Alex headshot

AlBlue’s Blog

Macs, Modularity and More

Moving data from one ZFS pool to another on OSX

Howto Zfs Mac

If you've got a bunch of data on one ZFS system, and you want to move it to another system, then there's a few ways this can be accomplished. The easiest is probably to use a mirrored ZFS drive, since you can add a new mirror, take a snapshot of the data, then move it off elsewhere.

This doesn't work if (a) you don't have a mirror to start with, or (b) the destination you're moving to isn't same sized or bigger. Even if you've used less space than is available, ZFS mirrors operate on the size of the minimum disk in a set, and can't grow smaller again.

Fortunately, zfs send and zfs receive are really handy for moving the contents of one (or more) snapshots between systems. Unfortunately, it takes a bit more work on OSX because (a) we've not got to the point where recursive snapshot sending works, and (b) the zfs command can't deal with streams.

You can work around this with a set of steps, however. Let's say we have source and target pools on different systems. We can do:

  • target# mkfifo /var/tmp/in
  • target# nc -l 1234 > /var/tmp/in &
  • target# zfs receive -F TargetPool/Filesystem@SomeSnapshot < /var/tmp/in
  • source# mkfifo /var/tmp/out
  • source# cat /var/tmp/out | nc target 1234 &
  • source# zfs send SourcePool/Filesystem@SomeSnapshot > /var/tmp/out

This should send a single snapshot from the source system to the target system. If you have multiple snapshots, you can send them incrementally:

  • source$ zfs send -i SourcePool/Filesystem@SomeSnapshot SourcePool/Filesystem@NextSnapshot > /var/tmp/out

The only constraint is that the target system has to have the @SomeSnapshot and that @NextSnapshot is ahead of @SomeSnapshot.

Finally, note that this can be used to perform incremental backups as well as once-off sending of data, so it's good to know how to use them. Also note that netcat (nc) doesn't encrypt any data, so there's an assumption that this is over a trusted network (if not, use SSH to wrap). Finally, this assumes running as root since that will be needed for the send/receive parts to work.