Using FreeBSD's re-root capability for fun and profit

# Task: I wanted to be able to reinstall a virtual machine that
# was installed with FreeBSD on UFS.  I wanted to have the machine
# run using ZFS filesystems.
# FreeBSD 11.0-RELEASE contains kernel and userland support allowing
# re-rooting of a running system.  The user component of the re-root
# support is provided by the reboot program.
# The basic strategy is to create a ram disk big enough to copy the
# entire UFS filesystem into, re-root into that filesystem.  Then
# repartition the disk, create ZFS filesystems, and copy all the data
# from the ramdisk into the ZFS filesystems.
# Original work by: Kurt Lidl  November, 2017

# '
# This procedure is inherently dangerous.  Any data on the machine could
# disappear without chance of recovery if something goes wrong during
# This procedure could easily render your machine unbootable,
# as it destroys the on-disk configuration while running from the
# created ramdisk.  A reboot, crash of the machine, or power outage
# during this procedure is likely to result in the machine being unable
# to reboot and total loss of all data.
# '

# First, cleanup the running machine, so that less data has to be
# copied into the ram disk.

# Note: It is assumed this is run inside a /bin/sh shell as the root user
rm -f /var/crash/*
rm -f /var/tmp/*
find /var/db/freebsd-update/files -type f -print | xargs rm -f

# Create 2GB ram disk - this needs to be big enough to hold all the data.
md=$(mdconfig -s 2g)

# Put a UFS filesystem on it, mount it:
newfs /dev/$md
mount /dev/$md /mnt

# This assumes there is a single filesystem to preserve.
# Dump the entire live filesystem, restore the dump into the ramdisk.
dump -0f - / | (cd /mnt; restore -rf -)

# Re-root the system.
kenv vfs.root.mountfrom=ufs:/dev/$md
reboot -r

# After re-rooting to the MFS device and rebooting, everything should
# come back up on the network, so login to the machine again and
# start a new /bin/sh session

exec /bin/sh

# On my host, there was an unforseen problem.  There was swap space
# added to the system via the /etc/fstab file, so even though the root
# filesystem was now entirely mfs-based, the swap space was added
# back to the running system, making the geom of the hard disk busy...

swapoff -a
gpart delete -i 2 ada0s1
gpart delete -i 1 ada0s1
gpart destroy -F ada0

# At this point, the hard disk (ada0) is completely unused
# and the system is entirely running from the ramdisk.
# A reboot or panic of the machine at this point would mean the
# system would not reboot, as there is no longer bootable media...

# Create ZFS partitions and make them bootable,
# Copy over data from the ramdisk.

sysctl kern.geom.label.disk_ident.enable=0
gpart create -s gpt ada0
gpart add -b 128 -s 448K -t freebsd-boot -l boot0 ada0
gpart add -s 4096M -t freebsd-swap -l swap0 ada0
gpart add -t freebsd-zfs -l sys0 ada0
gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 ada0

# Load zfs kernel module, make default blocksize be 4K.
kldload zfs
sysctl vfs.zfs.min_auto_ashift=12

# Set a few variables to make the following easier to update.
zpool create -f -o cachefile=none -O checksum=fletcher4 \
         -R $mnt -m none $P /dev/gpt/sys0
zfs create $P/ROOT
zfs create $P/ROOT/default
zpool set bootfs=$P/ROOT/default $P
zfs set mountpoint=/ $P/ROOT/default
zfs create $P/vartmp ; zfs set mountpoint=/var/tmp $P/vartmp
zfs create $P/home ; zfs set mountpoint=/usr/home $P/home
zfs mount -a

# Copy the mfs filesystem back to the ZFS pool.
dump -0f - / | (cd /mnt; restore -rf -)

# Fix mountpoint of the /home directory.
zfs set mountpoint=/home $P/home

# Fixup the system to be able to boot via zfs.
echo 'zfs_load="YES"' >> /mnt/boot/loader.conf
echo 'zfs_enable="YES"' >> /mnt/etc/rc.conf

# Site-specific settings you might want.  I find them useful.
echo 'clear_tmp_enable="YES"' >> /mnt/etc/rc.conf
echo 'ntpdate_enable="YES"' >> /mnt/etc/rc.conf
echo 'ntpd_enable="YES"' >> /mnt/etc/rc.conf

mv /mnt/etc/fstab /mnt/etc/fstab.hold

echo "/dev/gpt/swap0	none	swap	sw	0	0" > /mnt/etc/fstab
echo "tmpfs		/tmp	tmpfs	rw,mode=1777 0	0" >> /mnt/etc/fstab


# When the machine reboots, it should be running from ZFS.

Back to blog postings.