Again, this is mostly for my own reference, but if you have the same problem that I had, this article may prove useful to you as well.
OpenSolaris (from which FreeBSD's ZFS codebase came from) has this limitation: The “root” pool (i.e. the one that contains a boot filesystem, specified in the bootfs pool property) can only be a simple pool or a mirrored pool, not a raidz or any other fancier type. The main problem seems to be the OpenSolaris ZFS boot loader having trouble reading from other disks than the “boot disk”: If anything required for booting (e.g. the kernel) resides on a non-boot disk, the system fails to boot. Yes, boo.
There is a safeguard against this in the zpool program: If you tell it to add another vdev to a root pool (that is, one with bootfs set) in a non-mirrored setup, it complains: “root pool cannot have multiple vdevs or separate logs”.
The thing is, the FreeBSD ZFS boot loader does not suffer from the same limitation as the OpenSolaris counterpart does, and the system can indeed boot from a pool with multiple top-level vdevs, or even from a raidz pool. The boot loader enumerates all hard drives visible through BIOS, examines metadata on ZFS partition(s) on each drive to figure out which partition belongs to what pool, then mixes-and-matches them as necessary to reconstruct a complete root pool from which to boot. In other words, it is safe to add more top-level vdevs to a FreeBSD boot pool.
Problem: The safeguard mentioned above is still present in the FreeBSD version of zpool. Because a root pool has the bootfs property, you cannot add another disk to a non-mirrored root pool, as long as the pool has the bootfs property set.
Well, the workaround is obvious now, isn't it? It is as simple as temporarily clearing the bootfs property, as shown in the example below where I create a new GUID partition labeled mail0-002 on the disk da1 then add it to the root pool named mail0:
# gpart create -s GPT da1
da1 created
# gpart bootcode -b /boot/pmbr da1
da1 has bootcode
# gpart add -t freebsd-zfs -l mail0-002 da1
da1p1 added
# zpool add mail0 gpt/mail0-002
cannot add to 'mail0': root pool cannot have multiple vdevs or separate logs
# zpool get bootfs mail0
NAME PROPERTY VALUE SOURCE
mail0 bootfs mail0 local
# zpool set bootfs="" mail0
# zpool get bootfs mail0
NAME PROPERTY VALUE SOURCE
mail0 bootfs - default
# zpool add mail0 gpt/mail0-002
# zpool status mail0
pool: mail0
state: ONLINE
scrub: none requested
config:
NAME STATE READ WRITE CKSUM
mail0
gpt/mail0-001 ONLINE 0 0 0
gpt/mail0-002 ONLINE 0 0 0
errors: No known data errors
# zpool set bootfs=mail0 mail0
# zpool get bootfs mail0
NAME PROPERTY VALUE SOURCE
mail0 bootfs mail0 local
Important: Do not forget to restore the bootfs property as shown in the last two commands (use the original value as returned by a previous zpool get command); the system will otherwise fail to boot.
Note that, even though you can add more disks to your root pool this way, you may still want to limit the number of devices in your root pool to a minimum. FreeBSD's ZFS boot loader-I use gptzfsboot-seems to take a long time to examine a disk. “mail0” shown above has 3 disks, and it already takes about 10-20 seconds for gptzfsboot to finish scanning the 3 disks for ZFS partitions and start loading the next-stage BTX loader (/boot/loader) from them.