Here are some notes of how I recovered most of the data after my btrfs disk got horribly corrupted by bad memory. Fortunately I had upgraded the disk 6 months ago so I was able to start from that image left behind on the old disk, copied over using the excellent btrfs-clone tool.
After that I could restore most of my files to the last backup (a month or two back) and git repositories from the main server. But I still had a number of documents and other bits that I needed to recover.
The first thing prior to formatting the disk (I don’t have another spare fast SSD lying around) was to take a backup of the entire btrfs disk. However it was quite a bit larger than I easily had spare on another disk. So, I stored it in squashfs which reduced size by 50%.
mkdir empty-dir mksquashfs empty-dir squash.img -p 'sdb3_backup.img f 444 root root dd if=/dev/sdb3 bs=4M'
After that I tested that it was mountable:
mount squash.img /mnt/tmp btrfs restore -l /mnt/tmp/sdb3_backup.img
And erased and cloned the old btrfs disk to it.
I then started using the btrfs restore
tool to try to recover the data. First you need to list the roots, usually the highest number will be the latest snapshot and it may have consistent data:
btrfs restore -l /mnt/tmp/sdb3_backup.img
Then you can get a listing of the files under that root and whether they may be recoverable using the -v -D
flags (-v
means list files, -D
means don’t actually try to restore any data. For example:
btrfs restore -r 290 -v -D sdb3_backup.img /laptop/restore/
If that looks good then you can run the command with a few extra flags to try to get the files back as much as possible:
btrfs restore -r 290 -x -m -i sdb3_backup.img /laptop/restore/
This can take a while but it seems to work well on smaller files. Unfortunately some virtual machine images (60gb or so each) didn’t recover because they had got corrupted in the middle.
If you want to recover only a particular point under the tree you can use the --path-regex
parameter to specify this, however writing the regexps is very difficult. Here is a short bit of code which will generate the path regex correctly:
perl -E 'for(@ARGV){ $p = () = m!/!g; s!/!(|/!g; $_.= "(|/.*))" . ")" x $p; say "--path-regex '\''^/(|$_\$'\''" }' 'mark/data/documents'
You can then restore just those files like:
btrfs restore -x -m -i -r 290 --path-regex '^/(|mark(|/data(|/documents(|/.*))))$' sdb3_backup.img /laptop/restore/