ZFS pools can be made with a single disk, then turned into a mirror after the fact by adding additional drives. This is especially useful for staging or homelabs, where you might not have the money upfront to buy both drives, or want to test it before spending time resilvering. There are a few small gotchas that often get me, which we’ll explore here.
For this example, I’ve got a drive with a single
gpart(8)-created partition labelled
drive01. This is encrypted with
geli(8), and a ZFS pool built on top called
swimming in a ghastly pun. This is shown below:
# zpool list pool: swimming state: ONLINE scan: none requested config: NAME STATE READ WRITE CKSUM swimming ONLINE 0 0 0 gpt/drive01.eli ONLINE 0 0 0
Now we want to turn this into a mirror using another drive that we’ve called
drive02 The temptation is to do the below:
# echo Don't do this, it's just an example! # zpool add swimming /dev/gpt/drive02.eli
It’s an easy mistake to make, but this will stripe the two disks together into a larger vdev, not create a mirror. I remember in my early days of using ZFS I had a larger pool in production for a year that I thought had redundant storage when it didn’t. Whoops.
Instead, you want to use
zpool attach. You supply the pool name, the existing drive, and the new drive to mirror to:
# zpool attach swimming /dev/gpt/drive02.eli /dev/gpt/drive01.eli invalid vdev specification use '-f' to override the following errors: /dev/gpt/drive01.eli is part of active pool 'swimming'
Wait a minute! Don’t we want
drive01 to be part of this pool? Doesn’t it need to be so we can mirror the data across?
No, this is ZFS protecting us from ourselves again. The order is for the first drive to be mirrored to the second, so what we really want is:
# zpool attach swimming /dev/gpt/drive01.eli /dev/gpt/drive02.eli
Now when we check, we can see the pool resilvering as we want:
# zpool status pool: swimming state: ONLINE status: One or more devices is currently being resilvered. The pool will continue to function, possibly in a degraded state. action: Wait for the resilver to complete. config: NAME STATE READ WRITE CKSUM swimming ONLINE 0 0 0 mirror-0 ONLINE 0 0 0 gpt/drive01.eli ONLINE 0 0 0 gpt/drive02.eli ONLINE 0 0 0