Difference between revisions of "SnapRAID / MergerFS"
From Briki
(→SnapRAID / MergerFS) |
(→Identifying/Fixing a bad block) |
||
(13 intermediate revisions by the same user not shown) | |||
Line 3: | Line 3: | ||
== Setup == | == Setup == | ||
https://zackreed.me/setting-up-snapraid-on-ubuntu/ | https://zackreed.me/setting-up-snapraid-on-ubuntu/ | ||
− | + | ||
+ | Note that if (like me) you use a dedicated snapraid content directory then you'll need to create that by hand for each disk with: | ||
+ | |||
+ | mkdir /mnt/data/disk1/.snapraid | ||
+ | |||
== Partitioning a new data disk == | == Partitioning a new data disk == | ||
Note: "-m 2" here reserves 2% of the filesystem for root-owned files (eg. .../.snapraid/content) | Note: "-m 2" here reserves 2% of the filesystem for root-owned files (eg. .../.snapraid/content) | ||
Line 26: | Line 30: | ||
sudo snapraid sync | sudo snapraid sync | ||
+ | |||
+ | == Identifying/Fixing a bad block == | ||
+ | * Run ddrescue to identify the failing bytes on the disk: | ||
+ | <pre> | ||
+ | ddrescue --ask --verbose --binary-prefixes --idirect --force /dev/sdX /dev/null sdX.map | ||
+ | </pre> | ||
+ | * ddrescue will write out a map file containing start positions and sizes (all in bytes) of good (+) and bad (-) byte ranges | ||
+ | * Get the block size for the volume with <code>tune2fs -l /dev/sdXY | grep "Block size"</code> (we'll call this '''B'''). In my case this is 4096. | ||
+ | * Get the sector size for the disk with <code>fdisk -l /dev/sdX | grep Units</code> (we'll call this '''S'''). In my case this is 512. | ||
+ | * Identify the starting sector for the /dev/sdXY volume (eg. /dev/sda1) with <code>fdisk -l /dev/sdX</code> (we'll call this '''T'''). In my case this is 2048. | ||
+ | * Run ddrescuelog to list out the bad block locations (using the block size B): | ||
+ | <pre> | ||
+ | ddrescuelog -b B --list-blocks=- sdX.map | ||
+ | </pre> | ||
+ | * For each of these, convert to a block location in the volume (rather than the disk) by subtracting <code>(T * S / B)</code>. In my case that's 256. Let's call each of these bad volume blocks '''BB''' | ||
+ | * Start debugfs for the volume with <code>debugfs /dev/sdXY</code> | ||
+ | * For each '''BB''' run: | ||
+ | <pre> | ||
+ | testb BB | ||
+ | </pre> | ||
+ | * If debugfs returns "Block BB not in use", then that block isn't part of a file and can safely be overwritten. If it returns an inode number (we'll call it '''I''') then you can convert that inode number to a file path with: | ||
+ | <pre> | ||
+ | ncheck I | ||
+ | </pre> | ||
+ | |||
+ | For any unused blocks, we need to do the following: | ||
+ | * Check with dd that we’ve got the right block IDs. For each one of these reads we expect to see an error (and “0+0 records in”): | ||
+ | <pre> | ||
+ | for block in `ddrescuelog -b B --list-blocks=- sdX.map` | ||
+ | do | ||
+ | dd if=/dev/sdX of=/dev/null count=1 bs=B skip=$block | ||
+ | done | ||
+ | </pre> | ||
+ | |||
+ | * For each of the bad blocks, write zeros over the block to force it to be reallocated from spare space on the drive. Be careful here – getting it wrong will destroy data! Also note that when reading, “skip” is used to position the input stream, but here “seek” is used to position the output stream: | ||
+ | <pre> | ||
+ | for block in `ddrescuelog -b B --list-blocks=- sdX.map` | ||
+ | do | ||
+ | dd if=/dev/zero of=/dev/sdX count=1 bs=B seek=$block | ||
+ | done | ||
+ | </pre> | ||
+ | |||
+ | * It’s possible that dd will fail to write to the block, in which case try again with hdparm: | ||
+ | |||
+ | ** First check that we’ve got the right sectors (we expect to see “SG_IO: bad/missing sense data” for each sector on stderr, so we pipe stdout to /dev/null to avoid noise). Note that we use '''S''' as the block size for ddrescuelog, since hdparm deals in sectors: | ||
+ | <pre> | ||
+ | for block in `ddrescuelog -b S --list-blocks=- sdX.map` | ||
+ | do | ||
+ | hdparm --read-sector $block /dev/sdX > /dev/null | ||
+ | done | ||
+ | </pre> | ||
+ | |||
+ | ** Assuming we’ve seen the expected errors, write zeros over each of the bad sectors. Note that we use '''S''' as the block size for ddrescuelog, since hdparm deals in sectors. Be careful here – getting it wrong will destroy data! You may be asked to add a “—yes-i-know-what-i-am-doing” flag. | ||
+ | <pre> | ||
+ | for block in `ddrescuelog -b S --list-blocks=- sdX.map` | ||
+ | do | ||
+ | hdparm --write-sector $block /dev/sdX | ||
+ | done | ||
+ | </pre> | ||
+ | |||
+ | * Check that the number of failing sectors has decreased: | ||
+ | <pre> | ||
+ | smartctl -a /dev/sdX | grep Pending | ||
+ | </pre> | ||
+ | |||
+ | For any files reported by `debugfs`: | ||
+ | * Write random data over the bad file, which should force the pending sector to be marked bad and reallocated from spare space on the disk: | ||
+ | <pre> | ||
+ | shred –v /path/to/bad/file | ||
+ | </pre> | ||
+ | |||
+ | * Check that the number of failing sectors has decreased: | ||
+ | <pre> | ||
+ | smartctl –a /dev/sdX | grep Pending | ||
+ | </pre> | ||
+ | |||
+ | * Assuming the number of pending sectors has decreased, it’s then ok to delete the bad file: | ||
+ | <pre> | ||
+ | rm /path/to/bad/file | ||
+ | </pre> | ||
+ | |||
+ | More details: | ||
+ | * https://www.smartmontools.org/wiki/BadBlockHowto | ||
+ | * [[Mdadm#Repairing_failing_disk_on_degraded_array]] |
Latest revision as of 09:00, 26 April 2022
Contents
SnapRAID / MergerFS
Setup
https://zackreed.me/setting-up-snapraid-on-ubuntu/
Note that if (like me) you use a dedicated snapraid content directory then you'll need to create that by hand for each disk with:
mkdir /mnt/data/disk1/.snapraid
Partitioning a new data disk
Note: "-m 2" here reserves 2% of the filesystem for root-owned files (eg. .../.snapraid/content)
sudo parted -a optimal -s /dev/sdX -- mklabel gpt mkpart primary 0% 100% sudo mkfs.ext4 -m 2 -T largefile4 /dev/sdX1
Partitioning a new parity disk
Note: "-m 0" here reserves 0% of the filesystem, ensuring that the parity disks are slightly larger than the data disks
sudo parted -a optimal -s /dev/sdX -- mklabel gpt mkpart primary 0% 100% sudo mkfs.ext4 -m 0 -T largefile4 /dev/sdX1
Adding a new data disk to mergerfs
From: https://zackreed.me/mergerfs-neat-tricks/ From within the root of the mergerfs filesystem (eg. /srv)
xattr -w user.mergerfs.srcmounts '+>/mnt/data/disk4/srv' .mergerfs
Removing a data disk from mergerfs
From within the root of the mergerfs filesystem (eg. /srv)
xattr -w user.mergerfs.srcmounts '-/mnt/data/disk4/srv' .mergerfs
Forcing a resync
sudo snapraid sync
Identifying/Fixing a bad block
- Run ddrescue to identify the failing bytes on the disk:
ddrescue --ask --verbose --binary-prefixes --idirect --force /dev/sdX /dev/null sdX.map
- ddrescue will write out a map file containing start positions and sizes (all in bytes) of good (+) and bad (-) byte ranges
- Get the block size for the volume with
tune2fs -l /dev/sdXY | grep "Block size"
(we'll call this B). In my case this is 4096. - Get the sector size for the disk with
fdisk -l /dev/sdX | grep Units
(we'll call this S). In my case this is 512. - Identify the starting sector for the /dev/sdXY volume (eg. /dev/sda1) with
fdisk -l /dev/sdX
(we'll call this T). In my case this is 2048. - Run ddrescuelog to list out the bad block locations (using the block size B):
ddrescuelog -b B --list-blocks=- sdX.map
- For each of these, convert to a block location in the volume (rather than the disk) by subtracting
(T * S / B)
. In my case that's 256. Let's call each of these bad volume blocks BB - Start debugfs for the volume with
debugfs /dev/sdXY
- For each BB run:
testb BB
- If debugfs returns "Block BB not in use", then that block isn't part of a file and can safely be overwritten. If it returns an inode number (we'll call it I) then you can convert that inode number to a file path with:
ncheck I
For any unused blocks, we need to do the following:
- Check with dd that we’ve got the right block IDs. For each one of these reads we expect to see an error (and “0+0 records in”):
for block in `ddrescuelog -b B --list-blocks=- sdX.map` do dd if=/dev/sdX of=/dev/null count=1 bs=B skip=$block done
- For each of the bad blocks, write zeros over the block to force it to be reallocated from spare space on the drive. Be careful here – getting it wrong will destroy data! Also note that when reading, “skip” is used to position the input stream, but here “seek” is used to position the output stream:
for block in `ddrescuelog -b B --list-blocks=- sdX.map` do dd if=/dev/zero of=/dev/sdX count=1 bs=B seek=$block done
- It’s possible that dd will fail to write to the block, in which case try again with hdparm:
- First check that we’ve got the right sectors (we expect to see “SG_IO: bad/missing sense data” for each sector on stderr, so we pipe stdout to /dev/null to avoid noise). Note that we use S as the block size for ddrescuelog, since hdparm deals in sectors:
for block in `ddrescuelog -b S --list-blocks=- sdX.map` do hdparm --read-sector $block /dev/sdX > /dev/null done
- Assuming we’ve seen the expected errors, write zeros over each of the bad sectors. Note that we use S as the block size for ddrescuelog, since hdparm deals in sectors. Be careful here – getting it wrong will destroy data! You may be asked to add a “—yes-i-know-what-i-am-doing” flag.
for block in `ddrescuelog -b S --list-blocks=- sdX.map` do hdparm --write-sector $block /dev/sdX done
- Check that the number of failing sectors has decreased:
smartctl -a /dev/sdX | grep Pending
For any files reported by `debugfs`:
- Write random data over the bad file, which should force the pending sector to be marked bad and reallocated from spare space on the disk:
shred –v /path/to/bad/file
- Check that the number of failing sectors has decreased:
smartctl –a /dev/sdX | grep Pending
- Assuming the number of pending sectors has decreased, it’s then ok to delete the bad file:
rm /path/to/bad/file
More details: