Difference between revisions of "SnapRAID / MergerFS"

From Briki
Jump to: navigation, search
(Identifying/Fixing a bad block)
(Identifying/Fixing a bad block)
Line 44: Line 44:
 
ddrescuelog -b B --list-blocks=- sdX.map
 
ddrescuelog -b B --list-blocks=- sdX.map
 
</pre>
 
</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.
+
* 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 –list-blocks=- sdX.map`
 +
do
 +
  dd if=/dev/sdX of=/dev/null count=1 bs=512 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 –list-blocks=- sdX.map`
 +
do
 +
  dd if=/dev/zero of=/dev/sdX count=1 bs=512 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):
 +
<pre>
 +
for block in `ddrescuelog –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. 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 –list-blocks=- sdX.map`
 +
do
 +
  hdparm –write-sector $block /dev/sdX
 +
done
 +
</pre>
  
 
More details:
 
More details:
 
* https://www.smartmontools.org/wiki/BadBlockHowto
 
* https://www.smartmontools.org/wiki/BadBlockHowto
 
* [[Mdadm#Repairing_failing_disk_on_degraded_array]]
 
* [[Mdadm#Repairing_failing_disk_on_degraded_array]]

Revision as of 09:45, 26 April 2022

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 –list-blocks=- sdX.map`
do
  dd if=/dev/sdX of=/dev/null count=1 bs=512 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 –list-blocks=- sdX.map`
do
  dd if=/dev/zero of=/dev/sdX count=1 bs=512 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):
for block in `ddrescuelog –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. 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 –list-blocks=- sdX.map`
do
  hdparm –write-sector $block /dev/sdX
done

More details: