Simple way to move btrfs subvolumes to a different btrfs filesystem

btrfsfilesystems

I have two separate btrfs filesystems which I would like to consolidate. The subvolume structure looks like this:

/ filesystemA
|- subvolume1
|- subvolume2
|- ...
|- subvolumeN

/ filesystemB
|- subvolume1
|- subvolume2
|- ...
|- subvolumeM

filesystemB is the target. I would like to move subvolumes 1 to N into filesystemB. N is more than 1000, as they are daily-snapshot subvolumes – also because of this the differences between them are minimal, i.e. there is a lot of shared data. filesystemA is 1TB, but a naive du on the path totals more than 300TB of files (actual space usage on the drive is less than 500GB).

Therefore I believe a straight mv or cp from filesystemA to filesystemB is infeasible, as it won't be aware of btrfs subvolumes or the shared nature of the data.

I've read the documentation on btrfs send and btrfs receive a couple of times and it looks like this might work, essentially rebuilding the whole subvolume structure on filesystemB incrementally. But I'm hoping there is a simpler way, as I'd have to script this (due to the large number of subvolumes) and I feel this may be error-prone.

(Additionally, send/receive requires the subvolumes to be read-only, and the version of btrfs-tools on Ubuntu 14.04 doesn't seem to have the btrfs property command that would allow me to set an existing subvolume to read-only. I could install a later version but would prefer not to for the sake of configuration management on this "production" machine.)

Best Answer

I am pretty sure, you won't get around btrfs-send/btrfs-receive. Another option would be, to copy the subvolumes and then deduplicate them on the destination, but this would take ages.

For the readonly problem: as these are daily snapshots, arent most of the volumes read-only anyway?

I would do a

$btrfs subvolume create /subvolumeA/source
$for i in /filesystemA/subvolume*; do btrfs subvolume snapshot -r $i /filesystemA/source/$i; done

Now you have all subvolumes under /filesystemA/source/ readonly.

Now you could send them in a loop incrementaly with btrfs-send with the parent statement to the destination.

If some of the snapshots should be writeable again, you can copy the content of these to a new writeable subvolume using cp --reflink.

Related Question