Commit da718350 authored by Vitaly Lipatov's avatar Vitaly Lipatov

Add ZFS label tool for mirror disk recovery

Tool to read, parse, modify and write ZFS vdev labels. Allows recovering a detached disk back into a mirror by copying labels between devices. Co-Authored-By: 's avatarClaude Opus 4.6 (1M context) <noreply@anthropic.com>
parent ee8ba7ed
#!/bin/bash
# Test ZFS mirror label editing tool
# Scenario: 2-disk mirror → detach disk1 → write data → add disk3 →
# restore disk1 → get 3-way mirror with all data intact
#
# Run as root: bash test_zfs_mirror.sh
set -e
TOOL="$(cd "$(dirname "$0")" && pwd)/zfs_label_tool.py"
DIR="/tmp/zfs_label_test"
POOL="testlabeltool"
cleanup() {
echo "=== Cleanup ==="
zpool destroy "$POOL" 2>/dev/null || true
rm -rf "$DIR"
}
die() { echo "FAIL: $1" >&2; exit 1; }
# Clean up before start
cleanup
mkdir -p "$DIR"
echo "============================================================"
echo "Step 1: Create 2 files (256MB each) and a mirror"
echo "============================================================"
truncate -s 256M "$DIR/disk1"
truncate -s 256M "$DIR/disk2"
zpool create -f "$POOL" mirror "$DIR/disk1" "$DIR/disk2"
zpool status "$POOL"
echo ""
echo "============================================================"
echo "Step 2: Write initial data"
echo "============================================================"
echo "Initial data from 2-way mirror" > "/$POOL/testfile1"
dd if=/dev/urandom of="/$POOL/random1" bs=1M count=5 2>/dev/null
md5sum "/$POOL/random1" > "$DIR/md5_random1"
zpool sync "$POOL"
echo "Written: testfile1, random1"
echo ""
echo "============================================================"
echo "Step 3: Verify tool can parse and round-trip labels"
echo "============================================================"
python3 "$TOOL" verify "$DIR/disk1"
python3 "$TOOL" verify "$DIR/disk2"
echo ""
echo "============================================================"
echo "Step 4: Detach disk1"
echo "============================================================"
zpool detach "$POOL" "$DIR/disk1"
echo "disk1 detached"
zpool status "$POOL"
echo ""
echo "============================================================"
echo "Step 5: Write more data (disk1 is now behind)"
echo "============================================================"
echo "Data written after disk1 detach" > "/$POOL/testfile2"
dd if=/dev/urandom of="/$POOL/random2" bs=1M count=5 2>/dev/null
md5sum "/$POOL/random2" > "$DIR/md5_random2"
zpool sync "$POOL"
echo "Written: testfile2, random2"
echo ""
echo "============================================================"
echo "Step 6: Create disk3 and attach to mirror"
echo "============================================================"
truncate -s 256M "$DIR/disk3"
zpool attach "$POOL" "$DIR/disk2" "$DIR/disk3"
echo "disk3 attached, waiting for resilver..."
sleep 3
zpool wait "$POOL" 2>/dev/null || sleep 5
zpool status "$POOL"
echo ""
echo "============================================================"
echo "Step 7: Write even more data (disk1 is further behind)"
echo "============================================================"
echo "Data written with 3 disks (but disk1 detached)" > "/$POOL/testfile3"
zpool sync "$POOL"
echo ""
echo "============================================================"
echo "Step 8: Show disk1 labels (should be wiped after detach)"
echo "============================================================"
echo "--- disk1 label 0 ---"
python3 "$TOOL" show "$DIR/disk1" 2>&1 | head -5
echo ""
echo "--- Restoring uberblock with zhack ---"
zhack label repair -u "$DIR/disk1"
echo ""
echo "--- disk1 after zhack ---"
python3 "$TOOL" show "$DIR/disk1" 2>&1 | head -20
echo ""
echo "============================================================"
echo "Step 9: Export pool"
echo "============================================================"
zpool export "$POOL"
echo "Pool exported"
echo ""
echo "============================================================"
echo "Step 10: Verify round-trip on all disks"
echo "============================================================"
python3 "$TOOL" verify "$DIR/disk2"
python3 "$TOOL" verify "$DIR/disk3"
python3 "$TOOL" verify "$DIR/disk1"
echo ""
echo "============================================================"
echo "Step 11: Add disk1 back to disk2's labels"
echo "============================================================"
python3 "$TOOL" add-child "$DIR/disk2" "$DIR/disk1"
echo ""
echo "============================================================"
echo "Step 12: Add disk1 back to disk3's labels"
echo "============================================================"
python3 "$TOOL" add-child "$DIR/disk3" "$DIR/disk1"
echo ""
echo "============================================================"
echo "Step 13: Sync labels to disk1 (copy config from disk2)"
echo "============================================================"
python3 "$TOOL" sync-labels "$DIR/disk2" "$DIR/disk1"
echo ""
echo "============================================================"
echo "Step 14: Verify all labels after modification"
echo "============================================================"
python3 "$TOOL" verify "$DIR/disk2"
python3 "$TOOL" verify "$DIR/disk3"
python3 "$TOOL" verify "$DIR/disk1"
echo ""
echo "============================================================"
echo "Step 15: Show final label config (disk2)"
echo "============================================================"
python3 "$TOOL" show "$DIR/disk2" 2>&1 | head -60
echo ""
echo "============================================================"
echo "Step 16: Import pool"
echo "============================================================"
zpool import -d "$DIR" "$POOL" && echo "Import successful!" || die "Import failed!"
zpool status "$POOL"
echo ""
echo "============================================================"
echo "Step 17: Verify data integrity"
echo "============================================================"
echo "--- testfile1 ---"
cat "/$POOL/testfile1" || die "testfile1 missing"
echo "--- testfile2 ---"
cat "/$POOL/testfile2" || die "testfile2 missing"
echo "--- testfile3 ---"
cat "/$POOL/testfile3" || die "testfile3 missing"
echo "--- checksum random1 ---"
md5sum -c "$DIR/md5_random1" || die "random1 checksum mismatch"
echo "--- checksum random2 ---"
md5sum -c "$DIR/md5_random2" || die "random2 checksum mismatch"
echo ""
echo "============================================================"
echo "Step 18: Wait for resilver and final check"
echo "============================================================"
sleep 5
zpool status "$POOL"
echo ""
echo "============================================================"
echo "ALL TESTS PASSED!"
echo "============================================================"
# Cleanup
cleanup
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment