Sun, 26 Jul 2009 17:34:23 GMT revised at: Sun, 26 Jul 2009 17:37:46 GMT
posted by Christian in General
This weekend I wanted to update my FreeBSD box and saw that the ZFS tools fundamentally changed. The UPDATING file has a corresponding note:
20090520:
Update ZFS to version 13. ZFS users will need to re-build
and install both kernel and world simultaneously in order
for the ZFS tools to work. Existing pools will continue to work
without upgrade. If a pool is upgraded it will no longer be
usable by older kernel revs. ZFS send / recv between
pool version 6 and pool version 13 is not supported.
Installing kernel and world simultaneously is scary. If something breaks you are left with a broken system, no way to roll back, and uncertain repair possibilities. Sure, you should have backups, but restoring a whole system is still something that takes a lot of time.
But is this not exactly one of ZFS' strength? ZFS provides easy snapshots and clones. When I search for "FreeBSD ZFS update" I stumbled of this Mail: Solaris live upgrade like FreeBSD ZFS-rootfs update, which gave me the idea to snapshot my root and usr file system. This should give me a reasonably easy rollback path.
Disclaimer
Here is what I did (with some minor tweaks). It might or might not work for you. You might loose all your data following my steps. I cannot be held reliable for that. I also probably made a few mistakes while writing this up. Back up your system!
Prerequistes
I have my FreeBSD with encrypted ZFS set-up like I described in my blog post FreeBSD: Encrypted ZFS Root with Geli. It should also work with a different encryption mechanism or without encryption.
Creating the Snapshots
Let us assume that the ZFS pool is called tank and that
the root file system is under tank/root and the usr file system
is under tank/usr.
First, let us create a snapshot of the usr file system and of the root file system:
$ sudo zfs snapshot tank/usr@pre_update $ sudo zfs snapshot tank/root@pre_update
A snapshot is not writable. So let us create clones:
$ sudo zfs clone tank/usr@pre_update tank/usr_pre_update $ sudo zfs clone tank/root@pre_update tank/root_pre_update
We need two versions of the root file system. The normal one
(tank/usr) where
usr points to the normal tank/usr and the
pre update one (tank/root_pre_update)
that points to the pre update snapshot tank/usr_pre_update.
We will use a symlink for this.
Unfortunately, you cannot change the mountpoint of your usr file system while the system is running. So let us first finalize and boot into the pre update set-up to see that it is working.
$ echo Temporary mounting the pre update root $ sudo mdkir -p /pre_update/root $ sudo zfs set mountpoint=/pre_update/root tank/root_pre_update $ echo Setting the mountpoint of the pre update usr file system $ sudo zfs set mountpoint=/usr_pre_update tank/usr_pre_update $ echo Symlinking usr to the pre update usr file system $ cd /pre_update/root $ sudo rmdir usr $ sudo ln -s usr_pre_update usr $ echo Setting the pre update root mountpoint to legacy $ sudo zfs set mountpoint=legacy tank/root_pre_update
We need a similar set-up in the normal root file system where the
symlink points to usr_post_update. In order to set
the mountpoint of tank/usr to /usr_post/update
we need to reboot into single user mode with ZFS disabled.
We go to the boot loader prompt (normally by choosing 6 in the boot menu).
# unset vfs.root.mountfrom # disable-module zfs # set boot_single # boot
Once we are in single user mode, we can import zpool and set the mountpoint.
# zpool import -d /boot/zfs # zpool import -f -R /tank tank # cd /tank/root # rmdir usr # ln -s usr_post_update usr # zfs set mountpoint=/usr_post_update tank/usr_post_update
Now we reboot the system into the pre update environment. We go to the boot loader prompt and change the root file system to the pre update root file system.
# set vfs.root.mountfrom=zfs:tank/root_pre_update # boot
If everything goes well, the machine boots up into the cloned environment.
We can verify this by looking that /usr points to
/usr_pre_update.
Let us reboot again into the normal environment (by doing nothing special
during boot-up). Now /usr should point to
/usr_post_update. With this system we can build and install
the world and the kernel as mentioned in the
Handbook - Rebuilding "world",
without the reboot into single user mode (which will not work, anyway).
Rollback
If anything goes wrong during the update, we can boot our pre update environment by going to the boot loader prompt, selecting the pre update root file system and booting the old kernel.
# set vfs.root.mountfrom=zfs:tank/root_pre_update # boot kernel.old
Here we can copy over the backup kernel to correct destination and roll back to the snapshot with the comfort of the system in a fully functional state that we know.
Should the update work out, we can destroy the pre update environment in order to safe disk space. Or we can leave it around to mitigate problems of the update we are not aware of just yet.
Resources
- How to install FreeBSD 7.0 under ZFS The section "Disaster recovery" is very helpful.
- ZFS entry in the FreeBSD wiki
- Working with ZFS Snapshots and Clones (from Solaris ZFS Administration Guide)

