Moving a ZFS mirror to a RAIDZ
While I’m no data hoarder, I’ve finally ran out of space on my 2 x 4TB ZFS mirror (effectively 4TB of available space). I already had a third 4TB drive; so I thought I would try to do an in place transfer using the existing drives to create a raidz.
Word of warning. I would not have tried this if I did not have really good backups. I recommend a 3-2-1 backup strategy for all important data!
I’m not the first to attempt this, I got some hints from unix44lyfe.org. Here’s the overall strategy:
- Break the mirror (detach one device)
- Create a raidz with 2 real disks (one new, one detached from mirror) and one fake disk
- Offline the fake disk
- Copy all the date over
- Delete the mirror
- Replace the offlined fack disk with the real one from the mirror
Tip of the day: when dong something crazy like this, it’s nice to be able to do a dry run. Since ZFS can use files as devices for pools, you can try everything here without touching your disks!
Here’s the specific commands I used for this procedure:
DISK1=/dev/disk/by-id/<disk id> # first disk in mirror
DISK1=/dev/disk/by-id/<disk id> # second disk in mirror
DISK1=/dev/disk/by-id/<disk id> # new disk
# Unmount all filesystems on the pool, in this case doing it the easy way
zpool export tank
zpool import -N tank
# Make a fake disk of the right size
# I grabbed the number of bytes of $DISK2 using `fdisk -l`
truncate -s 4000787030016 /fake.disk
# Remove one disk from the mirror
zpool detach tank $DISK2
# Create raidz including one fake disk
zpool create -f tank2 raidz $DISK2 $DISK3 /fake.disk
# Offline the fake disk
zpool offline tank2 /fake.disk
# snaptshot the data to be copied
zfs snapshot -r tank@move
# big data copy
zfs send -Rnv tank@move # dry run to get the size to pass to `pv`
zfs send -R tank@move | pv <-s SIZE> | zfs recv -F -d tank2
# Destroy the old mirror
zpool destroy tank
# export the new raidz pool
zpool export tank2
# The fake disk can be deleted at anytime after the `offline` command
rm /fake.disk
# Reimport the raidz pool with the name tank (the old mirror's name)
zpool import tank2 tank
# Replace the fake disk with the real one
# expect the resilver to take 1/2 - 2/3 as long as the data copy
zpool replace tank /fake.disk $DISK1
And that was all there was to the process. It went surprisingly smoothly and now I have 8TB of available storage in a raidz1 configuration.