Using GMirror as a rollback tool.

On Thunderflare, which predates affordable solid-state drives, the OS is run from two small laptop drives in RAID 1. The RAID 1 is there so that if one of them crashes, I won’t have to do a complete reinstall. I’m lazy, sue me. Besides, a reinstall would take a lot of time, while setting up the mirror is a few minutes work, so the time investment is validated, in my opinion.

To run the mirror, I’m using GMirror, a part of the GEOM kit that does most disk operations on FreeBSD. Setting one up is trivial. Let’s assume the current system disk is ada0 [1]:
Add this line to /boot/loader.conf:

geom_mirror_load="YES"

On the command line, type:

# sysctl kern.geom.debugflags=16
# gmirror label -v -b round-robin gm0 /dev/ada0
# gmirror insert gm0 /dev/ada1

The first line allows us to make changes to mounted drives. The second line creates a mirror called gm0, with disk ada0 as basis, and round-robin scheduling to determine which disk is read from. The last line adds ad1 as a second disk, since a one-disk mirror is pretty useless.
To make sure FreeBSD uses the mirror, and not the individual disks, change /etc/fstab to mount the mirror. To do this, replace each instance of /dev/ada0 with /dev/mirror/gm0. Since the fstab will generally refer to slices, not disks, you’ll have to replace just the /dev/ada0 part. An example:
If /etc/fstab reads:

/dev/ada0s1a  /     ufs   rw  1  1
/dev/ada0s1b  none  swap  sw  0  0

You replace that with:

/dev/mirror/gm0s1a  /     ufs   rw  1  1
/dev/mirror/gm0s1b  none  swap  sw  0  0

After inserting the second disk, you’ll have to wait a bit for the disks to synchronize, the progress of which you can watch by typing:

gmirror status

After the rebuild completes, reboot the system to make sure everything works, and presto, you are running your OS on RAID 1.

But what about using the mirror as a rollback tool?

As I already mentioned in the title, there’s another advantage of using a mirrored setup for your system. It allows you to do a rollback when a big change (such as an operating system update) goes wrong. To do this, you disconnect one drive from the mirror before doing the update. If the update goes as planned, you simply reconnect the disk, let the mirror rebuild, and you’re done. If it fails, you swap the connectors of the two drives, boot from the pre-update state, then create a new mirror and add the other disk to it.

Here’s how it works:

Disconnect the secondary disk from the mirror:

# gmirror remove gm0 ada1

Then, if the update succeeds, you simply re-add the ada1 back into the mirror:

# gmirror insert gm0 ada1

If the update fails, the process is slightly more complex. Easiest and most reliable is to physically swap the two drives. Mine are still running on old-fashioned PATA, so I just swap the master/slave jumpers, but for SATA drives you swap the cables.

Boot the machine. You’ll get an error that device gm0 can’t be found. It should ask you what slice to boot from, tell it to boot from /dev/ada0s1a.
This will give you access to your root folder, which is all you should need right now. By default however, it is mounted in read-only mode, so you’ll have to remount root for writing:

# mount -o rw /

After that, wipe the old mirror metadata from what is now /dev/ada1:

# gmirror remove gm0 ada1

You can then recreate the mirror as listed earlier in this article.

If you are fairly sure your update is going to fail, you can make your life easier by prepping the backup disk after disconnecting it from the mirror. To do this, mount /dev/ada1s1a in a location of your choice, and edit the /etc/fstab located on that drive to remove the references to gm0. Basically the reverse of what is done in step three when creating the mirror (see above). The advantage of this is that the system should boot successfully after you swap the drives around. The disadvantage is that you will have to edit /etc/fstab twice, giving more opportunities for mistakes.

  1. [1]Starting this post, I’ll be using the CAM-compatible device names in my FreeBSD posts, as used in FreeBSD 9.1 and newer. If you’re using an older version, replace each reference to adaX with adX.

No Comments

Leave a Reply

Your email is never shared.Required fields are marked *