Tag Archives: boot

Other FreeBSD Version in ZFS Boot Environment

The first FreeBSD 12.3-PRERELEASE snapshots are finally available. This means we can try them in a new ZFS Boot Environment without touching out currently running 13.0-RELEASE system. We can not take the usual path with creating new BE from our current one and upgrade it to newer version because 12.3 has older major version then the 13.0 one.

This is kinda a paradox in the FreeBSD release process that when released the 12.3-RELEASE will have some newer commits and features then older 13.0-RELEASE which was released earlier this year. Of course not all things that have been committed to HEAD goes into 12-STABLE or 13-STABLE automatically – but most of them do. Only the biggest changes will be limited only to 14.0-RELEASE – of course probably somewhere in the middle of 2022 when it will be having its release process.

One note about ZFS filesystem on FreeBSD. People often confuse ‘real’ ZFS Boot Environments with its trying-to-be substitutes like BTRFS snapshots or snapshots used by Ubuntu with zsysctl(8) command. Unfortunately they are only snapshots and are not full writable clones (or entire separate ZFS datasets). They can freeze your system in time so you will be able to get back to working configuration after updating packages for example – but You will not be able to install other separate version of a system as other ZFS dataset making it another independent ZFS Boot Environment.

Create New ZFS Dataset

host # beadm list
BE             Active Mountpoint  Space Created
13.0.w520      NR     /           12.8G 2021-09-14 17:27
13.0.w520.safe -      -            1.2G 2021-10-18 10:01

host # zfs list -r zroot/ROOT
NAME                        USED  AVAIL     REFER  MOUNTPOINT
zroot/ROOT                 12.8G  96.8G       88K  none
zroot/ROOT/13.0.w520       12.8G  96.8G     11.6G  /
zroot/ROOT/13.0.w520.safe     8K  96.8G     11.1G  /

host # zfs create -o mountpoint=/ -o canmount=off zroot/ROOT/12.3

host # beadm list
BE             Active Mountpoint  Space Created
13.0.w520      NR     /           12.8G 2021-09-14 17:27
13.0.w520.safe -      -            1.2G 2021-10-18 10:01
12.3           -      -           96.0K 2021-10-18 13:14

Install FreeBSD 12.3-PRERELEASE

host # beadm mount 12.3 /var/tmp/12.3
Mounted successfully on '/var/tmp/12.3'

host # beadm list
BE             Active Mountpoint     Space Created
13.0.w520      NR     /              12.8G 2021-09-14 17:27
13.0.w520.safe -      -               1.2G 2021-10-18 10:01
12.3           -      /var/tmp/12.3  96.0K 2021-10-18 13:14

host # curl -o - https://download.freebsd.org/ftp/snapshots/amd64/12.3-PRERELEASE/base.txz \
         | tar --unlink -xpf - -C /var/tmp/12.3
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  173M  100  173M    0     0  1889k      0  0:01:33  0:01:33 --:--:-- 2228k

host # exa -1 /var/tmp/12.3
bin
boot
dev
etc
lib
libexec
media
mnt
net
proc
rescue
root
sbin
tmp
usr
var
COPYRIGHT
sys

host # curl -o - https://download.freebsd.org/ftp/snapshots/amd64/12.3-PRERELEASE/kernel.txz \
         | tar --unlink -xpf - -C /var/tmp/12.3
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 43.3M  100 43.3M    0     0  1733k      0  0:00:25  0:00:25 --:--:-- 1663k

host # exa -lh /var/tmp/12.3/boot/kernel/kernel
Permissions Size User Date Modified    Name
.r-xr-xr-x   37M root 2021-10-14 06:31 /var/tmp/12.3/boot/kernel/kernel

host # curl -o - https://download.freebsd.org/ftp/snapshots/amd64/12.3-PRERELEASE/lib32.txz \
         | tar --unlink -xpf - -C /var/tmp/12.3

host # exa -ld /var/tmp/12.3/usr/lib32
drwxr-xr-x - root 2021-10-18 13:45 /var/tmp/12.3/usr/lib32

Install Same Packages as on Host

With the pkg prime-list we will get all installed by hand pkg(8)packages from our currently running system. You may omit this section or just install packages that you need instead all of them.

host # pkg prime-list > /var/tmp/12.3/pkg.prime-list

host # chroot /var/tmp/12.3 /bin/sh

(BE) # export PS1="BE # "

BE # mount -t devfs devfs /dev

BE # sed -i '' s/quarterly/latest/g /etc/pkg/FreeBSD.conf

BE # pkg install -y $( cat pkg.prime-list )
Bootstrapping pkg from pkg+http://pkg.FreeBSD.org/FreeBSD:12:amd64/latest, please wait...
Verifying signature with trusted certificate pkg.freebsd.org.2013102301... done
Installing pkg-1.17.2...
Extracting pkg-1.17.2: 100%
Updating FreeBSD repository catalogue...
Fetching meta.conf: 100%    163 B   0.2kB/s    00:01
Fetching packagesite.pkg: 100%    6 MiB   1.3MB/s    00:05
Processing entries: 100%
FreeBSD repository update completed. 31294 packages processed.
All repositories are up to date.
Updating database digests format: 100%
pkg: No packages available to install matching 'chromium' have been found in the repositories
pkg: No packages available to install matching 'drm-fbsd13-kmod' have been found in the repositories
pkg: No packages available to install matching 'geany-gtk2' have been found in the repositories
pkg: No packages available to install matching 'ramspeed' have been found in the repositories
pkg: No packages available to install matching 'vim-console' have been found in the repositories

As we can see some of the packages that we have installed in the FreeBSD 13.0-RELEASE system are not currently available in the ‘latestpkg(8) branch for the FreeBSD 12.3-PRERELEASE system. This sometimes happens when the build of such package will fail – but you may assume that such package will be available in a week or so as that is the period in which pkg(8) packages are (re)build in the ‘latest‘ branch.

We will now remove the missed packages and also rename some packages that may have different names for 12.x version of FreeBSD.

BE # sed -i '' \
         -e s/drm-fbsd13-kmod/drm-kmod/g \
         -e s/geany-gtk2/geany/g \
         -e s/vim-console/vim-tiny/g \
         pkg.prime-list

BE # pkg install -y $( cat pkg.prime-list | grep -v -e chromium -e ramspeed )
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
The following 1072 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
        (...)

Number of packages to be installed: 1072

The process will require 11 GiB more space.
2 GiB to be downloaded.
(...)

BE # rm pkg.prime-list

After hour or so later our packages have been installed.

BE # pkg stats
Local package database:
        Installed packages: 1073
        Disk space occupied: 11 GiB

Remote package database(s):
        Number of repositories: 1
        Packages available: 31294
        Unique packages: 31294
        Total size of packages: 96 GiB

Copy Configuration Files

You can now reboot to plain and unconfigured FreeBSD system but you may as well copy your configuration files from your current working installation. These are the files I have copied.

First files from the Base System /etc and /boot places.

host # for I in /boot/loader.conf \
                /etc/hosts \
                /etc/fstab \
                /etc/rc.conf \
                /etc/sysctl.conf \
                /etc/wpa_supplicant.conf \
                /etc/jail.conf \
                /etc/devfs.rules \
                /etc/resolv.conf
       do
         cp "${I}" /var/tmp/12.3/"${I}"
         echo "${I}"
       done
/boot/loader.conf
/etc/hosts
/etc/fstab
/etc/rc.conf
/etc/sysctl.conf
/etc/wpa_supplicant.conf
/etc/jail.conf
/etc/devfs.rules
/etc/resolv.conf

Now the files for installed packages under /usr/local/etc dir.

host # for I in /usr/local/etc/X11/xorg.conf.d/* \
                /usr/local/etc/X11/xdm/{Xresources,Xsetup_0} \
                /usr/local/etc/automount.conf \
                /usr/local/etc/sudoers \
                /usr/local/etc/doas.conf \
                /usr/local/etc/zshrc
       do
         cp "${I}" /var/tmp/12.3/"${I}"
         echo "${I}"
       done
/usr/local/etc/X11/xorg.conf.d/card.conf
/usr/local/etc/X11/xorg.conf.d/flags.conf
/usr/local/etc/X11/xorg.conf.d/keyboard.conf
/usr/local/etc/X11/xorg.conf.d/touchpad.conf
/usr/local/etc/X11/xdm/Xresources
/usr/local/etc/X11/xdm/Xsetup_0
/usr/local/etc/automount.conf
/usr/local/etc/sudoers
/usr/local/etc/doas.conf
/usr/local/etc/zshrc

Add Users and Set Passwords

You should now add your regular user and set passwords for both your user and root account.

BE # pw useradd vermaden -u 1000 -d /home/vermaden -G wheel,operator,video,network,webcamd,vboxusers

BE # passwd root

BE # passwd vermaden

Reboot Into New ZFS Boot Environment

You may now exit the chroot(8) of that ZFS Boot Environment and reboot. In the FreeBSD loader(8) menu select the 12.3 boot environment.

BE # exit

host # umount /var/tmp/12.3/dev

host # beadm unmount 12.3
Unmounted successfully

host # beadm list -D
BE             Active Mountpoint  Space Created
13.0.w520      NR     /           11.3G 2021-09-14 17:27
13.0.w520.safe -      -           11.1G 2021-10-18 10:01
12.3        -      -            9.5G 2021-10-18 13:14

host # shutdown -r now

Testing New System

The 12.3-PRERELEASE system started fine for me. I was able to login and use system as usual. One important thing to note … the ZFS pools. I have another newer ZFS pool with zstd compression enabled … and I was not able to import that ZFS pool as FreeBSD 12.3-PREELEASE does not use OpenZFS 2.0 but an older FreeBSD in-house ZFS version.

# zpool import data
This pool uses the following feature(s) not supported by this system:
        org.freebsd:zstd_compress (zstd compression algorithm support.)
        com.delphix:log_spacemap (Log metaslab changes on a single spacemap and flush them periodically.)
        org.zfsonlinux:project_quota (space/object accounting based on project ID.)
        org.zfsonlinux:userobj_accounting (User/Group object accounting.)
cannot import 'data': unsupported version or feature

Keep that in mind … but you can also install newer OpenZFS from the FreeBSD Ports and this is what we will now do.

# pkg install -y openzfs openzfs-kmod
Updating FreeBSD repository catalogue...
FreeBSD repository is up to date.
All repositories are up to date.
The following 2 package(s) will be affected (of 0 checked):

New packages to be INSTALLED:
        openzfs: 2021090800
        openzfs-kmod: 2021090800

Number of packages to be installed: 2

The process will require 22 MiB more space.
4 MiB to be downloaded.
[1/2] Fetching openzfs-2021090800.pkg: 100%    3 MiB 975.3kB/s    00:03
[2/2] Fetching openzfs-kmod-2021090800.pkg: 100%    1 MiB 591.2kB/s    00:02
Checking integrity... done (0 conflicting)
[1/2] Installing openzfs-kmod-2021090800...
[1/2] Extracting openzfs-kmod-2021090800: 100%
pkg: Cannot open /dev/null:No such file or directory
[2/2] Installing openzfs-2021090800...
[2/2] Extracting openzfs-2021090800: 100%
=====
Message from openzfs-kmod-2021090800:

--
Amend /boot/loader.conf as follows to use this module:

- change zfs_load="YES" to NO
- change opensolaris_load="YES" to NO
- add openzfs_load="YES"
- (for ARM64) add cryptodev_load="YES"
=====
Message from openzfs-2021090800:

--
Ensure that any zfs-related commands, such as zpool, zfs, as used in scripts
and in your terminal sessions, use the correct path of /usr/local/sbin/ and
not the /sbin/ commands provided by the FreeBSD base system.

Consider setting this in your shell profile defaults!

We will now have to modify our /boot/loader.conf file.

host # beadm mount 12.3 /var/tmp/12.3
Mounted successfully on '/var/tmp/12.3'

host # chroot /var/tmp/12.3

BE # cp /boot/loader.conf /boot/loader.conf.ZFS

BE # vi /boot/loader.conf

BE # diff -u /boot/loader.conf.ZFS /boot/loader.conf
--- /boot/loader.conf.ZFS       2021-10-19 10:57:04.180732000 +0000
+++ /boot/loader.conf   2021-10-19 10:57:23.992145000 +0000
@@ -12,7 +12,8 @@

 # MODULES - BOOT
   geom_eli_load=YES
-  zfs_load=YES
+  zfs_load=NO
+  openzfs_load=YES

 # DISABLE /dev/diskid/* ENTRIES FOR DISKS
   kern.geom.label.disk_ident.enable=0

BE # shutdown -r now

After reboot and trying again I was able to import that newer ZFS pool.

Hope that you will find that guide useful.

Feel free to add your suggestions.

UPDATE 1 – Notes When Installing Newer Version

This guide was written when I tried FreeBSD 12.3 on a previously used by FreeBSD 13.0 system so bootcode was not needed to be updated. I just tried 13.1 on the same 13.0 system and these two steps are needed to updated the bootcode.

UEFI

For UEFI partition you will need to copy /boot/loader.efi file from the 13.1 installation which means /var/tmp/13.1 dir. Here is the command to be used.

host # gpart show -p ada1
=>       40  250069600    ada1  GPT  (119G)
         40     409600  ada1p1  efi  (200M)          <== UEFI BOOT PARTITION
     409640       1024  ada1p2  freebsd-boot  (512K) <== BIOS BOOT PARTITION
     410664        984          - free -  (492K)
     411648    2097152  ada1p3  freebsd-swap  (1.0G)
    2508800  247560192  ada1p4  freebsd-zfs  (118G)
  250068992        648          - free -  (324K)

host # mount_msdosfs /dev/ada1p1 /mnt

host # cp /var/tmp/13.1/boot/loader.efi /mnt/efi/boot/bootx64.efi

BIOS

For the systems that boot in legacy/BIOS mode you will use this gpart(8) command instead.

host # cd /var/tmp/13.1/boot
host # pwd
/var/tmp/13.1/boot
host # gpart bootcode -b ./pmbr -p ./gptzfsboot -i 2 ada1
partcode written to ada1p2
bootcode written to ada1

As FreeBSD often is installed as BIOS+UEFI boot capable both of these steps would be needed.

EOF

UFS Boot Environments for ARM

Several days ago I introduced UFS Boot Environments that work great on AMD64 (or 64-bit PC if you prefer). I was interested it it will also work on less powerful devices that ZFS is not always the best idea – ARM based devices. After some testing I found out that after one simple modification the UFS Boot Environments work like a charm on ARM devices.

The Table of Contents is as follows.

  • ARM Testing
  • Setup UFS Boot Environments
  • Needed Fix to Make FreeBSD bootme Flags Work
  • Reboot into Other Boot Environment Test

There is not suitable TL;DR here – you will have to read it all or not at all this time πŸ™‚

ARM Testing

I currently do not own 64-bit ARM device … so I thought I will try the qemu(1) emulator and ready to download and use ARM images provided by the FreeBSD project.

First we will install needed packages and fetch the ARM64 (also known as aarch64) images.

host # pkg install -y qemu u-boot-qemu-arm64

host % fetch https://download.freebsd.org/ftp/releases/VM-IMAGES/13.0-RC4/aarch64/Latest/FreeBSD-13.0-RC4-arm64-aarch64.raw.xz

host % xz -d FreeBSD-13.0-RC4-arm64-aarch64.raw.xz

We will now increase the image size to add additional boot environment partition.

host % ls -lh FreeBSD-13.0-RC4-arm64-aarch64.raw 
-rw-r--r-- 1 vermaden vermaden 5.1G 2021-04-04 12:37 FreeBSD-13.0-RC4-arm64-aarch64.raw

host % truncate -s +9G FreeBSD-13.0-RC4-arm64-aarch64.raw

host % ls -lh FreeBSD-13.0-RC4-arm64-aarch64.raw
-rw-r--r-- 1 vermaden vermaden 15G 2021-04-04 12:38 FreeBSD-13.0-RC4-arm64-aarch64.raw

Using qemu(1) emulator we can boot using either UEFI or U-BOOT option. We will test both as some ARM devices use UEFI and some (like Raspberry Pi devices) use U-BOOT mode.

host % export VMDISK=FreeBSD-13.0-RC4-arm64-aarch64.raw

// UEFI
host % qemu-system-aarch64 \
         -m 4096M \
         -cpu cortex-a57 \
         -M virt \
         -bios edk2-aarch64-code.fd \
         -serial telnet::4444,server \
         -nographic \
         -drive if=none,file=${VMDISK},format=raw,id=hd0 \
         -device virtio-blk-device,drive=hd0 \
         -device virtio-net-device,netdev=net0 \
         -netdev user,id=net0

// U-BOOT
host % qemu-system-aarch64 \
         -m 4096M \
         -cpu cortex-a57 \
         -M virt \
         -bios /usr/local/share/u-boot/u-boot-qemu-arm64/u-boot.bin \
         -serial telnet::4444,server \
         -nographic \
         -drive if=none,file=${VMDISK},format=raw,id=hd0 \
         -device virtio-blk-device,drive=hd0 \
         -device virtio-net-device,netdev=net0 \
         -netdev user,id=net0

After starting the qemu(1) process it will display the following information.

(...)
QEMU 5.0.1 monitor - type 'help' for more information
(qemu) qemu-system-aarch64: -serial telnet::4444,server: info: QEMU waiting for connection on: disconnected:telnet::::4444,server

We can now use telnet(1) to connect to our serial console on emulated ARM64 system. We will add additional freebsd-ufs partition for our second boot environment.

host % telnet localhost 4444
(...)

login: root

ARM # pkg install -y lsblk

ARM # lsblk
DEVICE         MAJ:MIN SIZE TYPE                              LABEL MOUNT
vtbd0            0:62   14G GPT                                   - -
  vtbd0p1        0:63   33M efi                          gpt/efiesp /boot/efi
  vtbd0p2        0:64  1.0G freebsd-swap                 gpt/swapfs -
  vtbd0p3        0:65  4.0G freebsd-ufs                  ufs/rootfs /

ARM # gpart show
=>       3  10552344  vtbd0  GPT  (14G) [CORRUPT]
         3     66584      1  efi  (33M)
     66587   2097152      2  freebsd-swap  (1.0G)
   2163739   8388608      3  freebsd-ufs  (4.0G)

ARM # gpart recover vtbd0
vtbd0 recovered

ARM # gpart add -s 4G -t freebsd-ufs vtbd0
vtbd0p4 added

ARM # gpart show
=>       3  29426709  vtbd0  GPT  (14G)
         3     66584      1  efi  (33M)
     66587   2097152      2  freebsd-swap  (1.0G)
   2163739   8388608      3  freebsd-ufs  (4.0G)
  10552347   8388608      4  freebsd-ufs  (4.0G)
  18940955  10485757         - free -  (5.0G)

We will now make some manual preparations for ufsbe.sh to work.

For example the FreeBSD images come with GPT labels used in /etc/fstab file which are currently not supported by UFS Boot Environments so we will modify the /etc/fstab file to mount root filesystem from raw devices and partitions.

ARM # mkdir -p /ufsbe/3 /ufsbe/4

ARM # cat /etc/fstab
# Custom /etc/fstab for FreeBSD VM images
/dev/gpt/rootfs  /          ufs      rw  1 1
/dev/gpt/efiesp  /boot/efi  msdosfs  rw  2 2
/dev/gpt/swapfs  none       swap     sw  0 0

ARM # vi /etc/fstab

ARM # cat /etc/fstab
# Custom /etc/fstab for FreeBSD VM images
/dev/vtbd0p3     /          ufs      rw  1 1
/dev/vtbd0p4     /ufsbe/4   ufs      rw  1 1
/dev/gpt/efiesp  /boot/efi  msdosfs  rw  2 2
/dev/gpt/swapfs  none       swap     sw  0 0

ARM # newfs /dev/vtbd0p4
/dev/vtbd0p4: 4096.0MB (8388608 sectors) block size 32768, fragment size 4096
        using 7 cylinder groups of 625.22MB, 20007 blks, 80128 inodes.
super-block backups (for fsck_ffs -b #) at:
 192, 1280640, 2561088, 3841536, 5121984, 6402432, 7682880

We now have second boot environment ready and /etc/fstab file modified to boot from raw devices instead of GPT labels. We will now reboot(8) to make these changes apply.

ARM # reboot

Setup UFS Boot Environments

We will not fetch the ufsbe.sh command and finish the setup process.

ARM # fetch https://raw.githubusercontent.com/vermaden/ufsbe/main/ufsbe.sh

ARM # chmod +x ./ufsbe.sh

ARM # ./ufsbe.sh

NOPE: did not found boot environment setup with 'ufsbe' label

INFO: setup each boot environment partition with appropriate label

HELP: list all 'freebsd-ufs' partitions type:

  # gpart show -p | grep freebsd-ufs
      2098216   33554432  ada0p3  freebsd-ufs  [bootme]  (16G)
     35652648   33554432  ada0p4  freebsd-ufs  (16G)
     69207080   33554432  ada0p5  freebsd-ufs  (16G)

HELP: to setup partitions 3/4/5 as boot environments type:

  # gpart modify -i 3 -l ufsbe/3 ada0
  # gpart modify -i 4 -l ufsbe/4 ada0
  # gpart modify -i 5 -l ufsbe/5 ada0

ARM # gpart show
=>       3  29426709  vtbd0  GPT  (14G)
         3     66584      1  efi  (33M)
     66587   2097152      2  freebsd-swap  (1.0G)
   2163739   8388608      3  freebsd-ufs  (4.0G)
  10552347   8388608      4  freebsd-ufs  (4.0G)
  18940955  10485757         - free -  (5.0G)

ARM # gpart modify -i 3 -l ufsbe/3 vtbd0
vtbd0p3 modified

ARM # gpart modify -i 4 -l ufsbe/4 vtbd0
vtbd0p4 modified

ARM # ./ufsbe.sh 
INFO: flag 'bootme' successfully set on / filesystem
usage:
  ufsbe.sh (l)ist
  ufsbe.sh (a)ctivate
  ufsbe.sh (s)ync

The UFS Boot Environments are now properly deployed on this ARM64 test system.

Needed Fix to Make FreeBSD bootme Flags Work

At the first try I was not able to use UFS Boot Environments as the bootme flag was ignored.

I then submitted a FreeBSD bug – 254764 – GPT ‘bootme’ flag is not respected on AARCH64 – to make sure I am doing everything well on my side. As it turns out the bootme flag is a FreeBSD specific extension and nobody else uses it. The needed fix is to copy /boot/gptboot.efi in place of bootaa64.efi file.

Lets now make that fix.

ARM # cp /boot/gptboot.efi /boot/efi/EFI/BOOT/bootaa64.efi

Reboot into Other Boot Environment Test

We will now synchronize boot environments 3 and 4 and then reboot into the 4 boot environments.

ARM # ./ufsbe.sh list
PROVIDER LABEL        ACTIVE
vtbd0p3  ufsbe/3      NR  
vtbd0p4  ufsbe/4      -  

ARM # ./ufsbe.sh sync 3 4
INFO: syncing '3' (source) => '4' (target) boot environments ...
INFO: boot environments '3' (source) => '4' (target) synced

ARM # ./ufsbe.sh activate 4
INFO: boot environment '4' now activated

ARM # reboot

After the reboot the currently active boot environment is 4. It means that UFS Boot Environments work properly on ARM devices.

ARM # ./ufsbe.sh list
PROVIDER LABEL        ACTIVE
vtbd0p3  ufsbe/3      -   
vtbd0p4  ufsbe/4      NR  

ARM # df -h
Filesystem         Size    Used   Avail Capacity  Mounted on
/dev/vtbd0p4       3.9G    2.6G    935M    74%    /
devfs              1.0K    1.0K      0B   100%    /dev
/dev/vtbd0p3       3.9G    2.6G    932M    74%    /ufsbe/3
/dev/gpt/efiesp     32M    1.3M     31M     4%    /boot/efi

I have tested both U-BOOT and UEFI boot modes and they both allow to use UFS Boot Environments.

EOF

UFS Boot Environments

Yes you read it correctly. The fabulous ZFS Boot Environments – more about them here – https://is.gd/BECTL – if you are not familiar with this concept – are now also possible on UFS filesystems on FreeBSD. Of course in little different form and without using snapshots and clones but the idea and solution remains. You can now have bootable backups of your system before major changes and/or upgrades. This solution does not use UFS snapshots. All bootable UFS variants are supported with and without Soft Updates or Soft Updates Journaling. The idea behind UFS Boot Environments lays in several additional root (/) partitions that will be used as alternate boot environments.

If you are interested in ARM more then in X86 then also check UFS Boot Environments for ARM article.

Concept is similar to Solaris Live Upgrade mechanism which used lucreate/luupgrade/lustatus commands and also to AIX Alternate Disk Cloning and Install with alt_disk_copy/alt_disk_install commands.

In this article I will show you how to setup new FreeBSD system with 3 of such partitions. In my honest opinion its more then enough for most purposes. On my desktop/workstation I have more then 1000 packages installed. With FreeBSD Base System it takes about 11 GB of space with ZFS compression and 15 GB without it. Thus I propose 16 GB partitions. Your needs may of course be different. You may as well create 4 GB or 64 GB partitions.

The UFS Boot Environments would not exist without the inspiration from FreeBSD Upgrade Procedure Using GPT blog post by Mariusz Zaborski (also known as oshogbo) who describes the concept of bootme flags for GPT partitions. That is the heart of this solution. By selecting activate for boot environment the bootme flag is removed from all existing boot environments and set for the new desired one. The ufsbe(8) tool was tested on FreeBSD 12.x and 13.x currently.

FreeBSD Install for UFS Boot Environments

Generally only GPT partitioning is needed to use UFS Boot Environments. Below I will show example install process with 3 root partitions of 16 GB each.

In the FreeBSD Installer select Install.

The select Auto (UFS) option.

Then use Entire Disk option.

Then select GPT partition table.

The FreeBSD Installer will propose the following solution.

Change it into 3 partitions 16 GB each to make it look like that one below and hit Finish.

Then Commit your choice.

… and then the install process will continue as usual.

Besides these option you may select whatever you choose in the install process.

After the system reboots its gpart(8) will look like that one below.

root@fbsd13:~ # gpart show
=>       40  134217648  ada0  GPT  (64G)
         40       1024     1  freebsd-boot  (512K)
       1064    2097152     2  freebsd-swap  (1.0G)
    2098216   33554432     3  freebsd-ufs  (16G)
   35652648   33554432     4  freebsd-ufs  (16G)
   69207080   33554432     5  freebsd-ufs  (16G)
  102761512   31456176        - free -  (15G)

Now fetch(1) the ufsbe.sh script from its GitHub page.

# fetch https://raw.githubusercontent.com/vermaden/ufsbe/main/ufsbe.sh
# chmod +x ./ufsbe.sh
# ./ufsbe.sh

NOPE: did not found boot environment setup with 'ufsbe' label

INFO: setup each boot environment partition with appropriate label

HELP: list all 'freebsd-ufs' partitions type:

  # gpart show -p | grep freebsd-ufs
      2098216   33554432  ada0p3  freebsd-ufs  [bootme]  (16G)
     35652648   33554432  ada0p4  freebsd-ufs  (16G)
     69207080   33554432  ada0p5  freebsd-ufs  (16G)

HELP: to setup partitions 3/4/5 as boot environments type:

  # gpart modify -i 3 -l ufsbe/3 ada0
  # gpart modify -i 4 -l ufsbe/4 ada0
  # gpart modify -i 5 -l ufsbe/5 ada0

It will welcome you with information about needed setup steps.

We will now make these steps marking all boot environment partitions with appropriate ufsbe labels.

# gpart modify -i 3 -l ufsbe/3 ada0
ada0p3 modified
# gpart modify -i 4 -l ufsbe/4 ada0
ada0p4 modified
# gpart modify -i 5 -l ufsbe/5 ada0
ada0p5 modified

Now ufsbe.sh will setup bootme flag for currently used root (/) partition.

# ./ufsbe.sh
INFO: flag 'bootme' successfully set on / filesystem
usage:
  ufsbe.sh list
  ufsbe.sh activate
  ufsbe.sh sync  

Setup is complete.

All three root partitions have the ufsbe label. To make it more simple the /dev/ada0p3 device gets the ufsbe/3 label and /dev/ada0p4 device gets the ufsbe/4 … you see the pattern.

# gpart show -p -l
=>       40  134217648    ada0  GPT  (64G)
         40       1024  ada0p1  (null)  (512K)
       1064    2097152  ada0p2  swap  (1.0G)
    2098216   33554432  ada0p3  ufsbe/3  [bootme]  (16G)
   35652648   33554432  ada0p4  ufsbe/4  (16G)
   69207080   33554432  ada0p5  ufsbe/5  (16G)
  102761512   31456176          - free -  (15G)

You can now use our UFS Boot Environments on this system.

Using UFS Boot Environments

Lets list our boot environments with list command. The short ‘l‘ option also works.

# ./ufsbe.sh list
PROVIDER LABEL        ACTIVE
ada0p3   ufsbe/3      NR  
ada0p4   ufsbe/4      -   
ada0p5   ufsbe/5      -  

Its output is similar to mine ZFS Boot Environments tools beadm(8). The N flag shows that this is the boot environments we are using NOW. The R flag shows which one we will use after the reboot(8).

Currently only the 3 boot environments is populated (by FreeBSD Installer that is). The 4 and 5 boot environments are empty filesystems.

You can either extract your own FreeBSD version there with base.txz and kernel.txz or use the sync option of ufsbe.sh which will use rsync(1) for the process. Below is an example of syncing boot environment 3 (the one we installed) with currently empty boot environment 4.

# ./ufsbe.sh sync 3 4
NOPE: rsync(1) is not available in ${PATH}
INFO: install 'net/rsync' package or port

# pkg install net/rsync

# ./ufsbe.sh sync 3 4
INFO: syncing '3' (source) => '4' (target) boot environments ...
INFO: boot environments '3' (source) => '4' (target) synced

You can now see that boot environment 3 and 4 have same size.

# df -h
Filesystem     Size    Used   Avail Capacity  Mounted on
/dev/ada0p3     15G    1.3G     13G     9%    /
devfs          1.0K    1.0K      0B   100%    /dev
/dev/ada0p4     15G    1.2G     13G     9%    /ufsbe/4
/dev/ada0p5     15G     32M     14G     0%    /ufsbe/5

If we would like to activate an empty boot environment 5 then ufsbe.sh will not let us do that because that will make our system unbootable. Of course is quote fast/naive check but at least makes sure some files exists on the soon to be active boot environment. Currently these files are checked but this list may be increased in the future:

  • /boot/kernel/kernel
  • /boot/loader.conf
  • /etc/rc.conf
  • /rescue/ls
  • /bin/ls
  • /sbin/fsck
  • /usr/bin/su
  • /usr/sbin/chroot
  • /lib/libc.so.*
  • /usr/lib/libpam.so.*

Below this ‘protection’ in action.

# ./ufsbe.sh activate 5
NOPE: boot environment '5' is not complete
INFO: critical file '/ufsbe/5/boot/kernel/kernel' is missing
INFO: use 'sync' option or copy file manually

The boot environment 4 activation process works as desired as we populated it with files from boot environment 3 first.

# ./ufsbe.sh activate 4
INFO: boot environment '4' now activated

Same as with beadm(8) the ufsbe.sh also checks if boot environment is already activated.

# ./ufsbe.sh activate 4
INFO: boot environment '4' is already active

The list of our boot environments looks like that now.

# ./ufsbe.sh list
PROVIDER LABEL        ACTIVE
ada0p3   ufsbe/3      N   
ada0p4   ufsbe/4      R   
ada0p5   ufsbe/5      -   

… and that is how output of gpart(8) looks like.

# gpart show -p -l
=>       40  134217648    ada0  GPT  (64G)
         40       1024  ada0p1  (null)  (512K)
       1064    2097152  ada0p2  swap  (1.0G)
    2098216   33554432  ada0p3  ufsbe/3  (16G)
   35652648   33554432  ada0p4  ufsbe/4  [bootme]  (16G)
   69207080   33554432  ada0p5  ufsbe/5  (16G)
  102761512   31456176          - free -  (15G)

We will now reboot into the activated boot environment 4.

# shutdown -r now

After the reboot(8) we see that we are now booted from the 4 boot environment.

# ./ufsbe.sh list
PROVIDER LABEL        ACTIVE
ada0p3   ufsbe/3      -   
ada0p4   ufsbe/4      NR  
ada0p5   ufsbe/5      -   

Closing Notes

Keep in mind that this is only first 0.1 version of ufsbe.sh. Do not use it in production or important systems and make sure you have restorable backups. Like with beadm(8) in the past I plan to improve it with more useful options and also add it to the Ports tree in the future.

Feel free to share your thoughts about this tool.

I must wait till midnight to make it shown as posted on 2nd of April because if I would post it on 1st of April it would be taken as April Fool Joke which is definitely not.

Enjoy.

Updating or Upgrading

You may use the Upgrade FreeBSD with ZFS Boot Environments method with these UFS Boot Environments as well but now you will chroot(8) into /ufsbe/4 for example.

EOF

ZFS Boot Environments at PBUG

Today I was honored to give a talk about ZFS Boot Environments at the third (#3) Polish BSD User Group meeting.

You are invited to download the PDF Slides – https://is.gd/BEADM – here.

zfsbe-shot-256

As I just finished the talk the video from the talk is not yet available online, but I will update the post when it arises.

Back in 2012 I though that – then available solution – the manageBE script could be (re)written from scratch to ‘imitate’ the beadm command from Solaris/Illumos systems to make the use of Boot Environments easier and more natural. To do so I had written a small native FreeBSD beadm prototype in POSIX /bin/sh shell and shared the results of the work on the FreeBSD Forums in the HOWTO: FreeBSD ZFS Madness thread.

With the help of FreeBSD Community the beadm tool grown up into the complete native FreeBSD ZFS Boot Environment manager and later even the FreeBSD boot loader(8) has been modified/rewritten to support the selection of the ZFS Boot Environments created by the beadm script.

The attached PDF presentation explains following topics:

  • What ZFS Boot Environments are.
  • Why they are useful and what use cases it addresses.
  • What has been available in UNIX world before they were introduced.
  • What is available in the Linux world as alternative.
  • Practical examples in beadm usage.
  • History of the tools used for ZFS Boot Environments management.

If you will have the possibility and time to join the next Polish BSD User Group meeting, you will be impressed by the presence of lots BSD professionals with great attitude willing to share their ideas and experience … just like the whole FreeBSD Community. The next (#4) meeting will be organized on the 9th of August, same place as usual, Europe/Warsaw at Wheel Systems headquarters. The special guest of that meeting would be George Neville-Neil – a person that I do not have to introduce πŸ˜‰

UPDATE 1 – Video Available Online

The video from the talk has been uploaded online and its available here – https://youtu.be/t84s8DSgJRs – unfortunately its in Polish not English and subtitles are not available.

UPDATE 2

The ZFS Boot Environments at PBUG article was included in the BSD Now 258 – OS Foundations episode.

Thanks for mentioning!

EOF

FreeBSD Desktop – Part 1 – Simplified Boot

This is the first post in the FreeBSD Desktop series.

You may want to check other articles in the FreeBSD Desktop series on the FreeBSD Desktop – Global Page where you will find links to all episodes of the series along with table of contents for each episode’s contents.

The default FreeBSD boot process is quite verbose with a lot of debugging information along with kernel messages. We may divide that boot process into several β€˜screens’ or stages. First thing You see is the β€˜BIOS’ screen of the computer manufacturer. SecondΒ  thing is the FreeBSD BTX Loader. The third one is the FreeBSD Boot Menu with eventual ZFS Boot Environments if You use ZFS for root filesystem and other options to select like Single User Mode for example. The 4th one is the system boot along with kernel messages in non-native resolution. In the middle of that stage screen switches to native resolution and continues to display kernel messages and services leading to the text prompt with login: at the end. There comes optional fifth screen which may be graphically started (x11) login manager like slim or gdm.

This verbose information is usually useful for servers but not that much for laptops and/or desktop/workstation systems. The UNIX philosophy is to not β€˜say’ anything to stdout if everything is OK, so stdout/stderr should only be used when something is wrong … like on AMIGA, if anything is wrong then I want to see big red sign like [GURU MEDITAION] but if everything is ok, shut the … slience is golden πŸ™‚

guru-meditation

I really like Sun Solaris 10 approach here, that it boots with minimal information like its version and hostname into the login: prompt in less then 10 lines. The image below is from the first Sun Solaris 10 boot, so it includes additional OpenSSH server key generation information.

sun-solaris-10-boot-first

Unfortunately – despite what Oracle says – Oracle Solaris is dying, I gathered most of the information here – Oracle just killed Solaris/SPARC/ZFS teams – https://forums.freebsd.org/threads/62320/ – on FreeBSD Forums. The recent Oracle Solaris 11.4 release process along with public beta will not change that. Oracle Solaris will be kept in maintenance mode for the rest of its life, which is set by Oracle to 2034 currently. Pity because even BSD bits recently found its way into it Solaris, for example the OpenBSD PF firewall, there are some differences – Comparing PF in Oracle Solaris to IP Filter and to OpenBSD Packet Filter – https://docs.oracle.com/cd/E37838_01/html/E60993/pfovw-comparall.html – but there are differences between OpenBSD PF and FreeBSD PF too.

Back to FreeBSD – according to the project website – https://freebsd.org/ – β€œFreeBSD is an operating system used to power modern servers, desktops, and embedded platforms” so why not tune the boot process to be more appealing on laptops/desktops? Below are the stages of the default FreeBSD boot process up to the login: prompt.

stage0-BIOS.jpg

stage1-BTX-Loader.jpg

stage2-Boot-Menu.jpg

stage3-NOMOD-Non-Native-Boot.jpg

stage4a-NOMOD-Native-Boot-A.jpg.jpg

stage4b-NOMOD-Native-Boot-B.jpg

Not very lean to my standards. But with one parameter in /boot/loader.conf and 5 slightly silenced startup scripts its whole a lot better. Here are the modifications needed.

First add the boot_mute=YES option to the /boot/loader.conf file.

As we are here, You may as well add autoboot_delay=2 parameter to the /boot/loader.conf file to speed up boot process by 8 seconds. Default delay is 10 seconds.

% grep boot_mute /boot/loader.conf
boot_mute=YES
%

Next we will need to modify these startup scripts.

  • /etc/rc.d/ldconfig
  • /etc/rc.d/netif
  • /etc/rc.d/nfsclient
  • /etc/rc.d/random
  • /etc/rc.d/routing

Here is the summary of the changes. In most cases its just adding 1> /dev/null or 1> /dev/null 2> /dev/null to not display unneeded information at boot process.

% grep -n -E '(1|2)> /dev/null' /etc/rc.d/* | grep -E 'routing|netif|ldconfig'
/etc/rc.d/ldconfig:40: check_startmsgs && echo 'ELF ldconfig path:' ${_LDC} 1> /dev/null
/etc/rc.d/ldconfig:60: echo '32-bit compatibility ldconfig path:' ${_LDC} 1> /dev/null
/etc/rc.d/netif:260: /sbin/ifconfig ${ifn} 1> /dev/null 2> /dev/null
/etc/rc.d/routing:70: eval static_${_a} delete $_if 1> /dev/null 2> /dev/null
/etc/rc.d/routing:97: static_$2 add $3 1> /dev/null 2> /dev/null
/etc/rc.d/routing:104: static_$2 add $3 add $3 1> /dev/null 2> /dev/null

The only exception is the /etc/rc.d/random which requires little more love.

% grep -n -A 8 'random_start()' /etc/rc.d/random
45:random_start()
46-{
47-
48-   # if [ ${harvest_mask} -gt 0 ]; then
49-   #       echo -n 'Setting up harvesting: '
50-   #       ${SYSCTL} kern.random.harvest.mask=${harvest_mask} > /dev/null
51-   #       ${SYSCTL_N} kern.random.harvest.mask_symbolic
52-   # fi
53-

Here are diff(1) patches if that way will be easier for you.

% diff -rq ~/CLEAN-FreeBSD-11.1-RELEASE/etc/rc.d /etc/rc.d | column -t
Files  ~/CLEAN-FreeBSD-11.1-RELEASE/etc/rc.d/ldconfig   and  /etc/rc.d/ldconfig   differ
Files  ~/CLEAN-FreeBSD-11.1-RELEASE/etc/rc.d/netif      and  /etc/rc.d/netif      differ
Files  ~/CLEAN-FreeBSD-11.1-RELEASE/etc/rc.d/nfsclient  and  /etc/rc.d/nfsclient  differ
Files  ~/CLEAN-FreeBSD-11.1-RELEASE/etc/rc.d/random     and  /etc/rc.d/random     differ
Files  ~/CLEAN-FreeBSD-11.1-RELEASE/etc/rc.d/routing    and  /etc/rc.d/routing    differ
% diff -u ./rc.d/ldconfig /etc/rc.d/ldconfig
--- ./rc.d/ldconfig     2017-07-21 04:11:06.000000000 +0200
+++ /etc/rc.d/ldconfig  2017-12-18 09:12:18.190074000 +0100
@@ -37,7 +37,7 @@
                                _LDC="${_LDC} ${i}"
                        fi
                done
-               check_startmsgs && echo 'ELF ldconfig path:' ${_LDC}
+               check_startmsgs && echo 'ELF ldconfig path:' ${_LDC} 1> /dev/null
                ${ldconfig} -elf ${_ins} ${_LDC}
 
                case `sysctl -n hw.machine_arch` in
@@ -57,7 +57,7 @@
                                fi
                        done
                        check_startmsgs &&
-                           echo '32-bit compatibility ldconfig path:' ${_LDC}
+                           echo '32-bit compatibility ldconfig path:' ${_LDC} 1> /dev/null
                        ${ldconfig} -32 -m ${_ins} ${_LDC}
                        ;;
                esac

% diff -u ./rc.d/netif /etc/rc.d/netif
--- ./rc.d/netif        2017-07-21 04:11:06.000000000 +0200
+++ /etc/rc.d/netif     2017-11-30 17:32:11.394251000 +0100
@@ -257,7 +257,7 @@
                esac
                if check_startmsgs; then
                        for ifn in ${_ok}; do
-                               /sbin/ifconfig ${ifn}
+                               /sbin/ifconfig ${ifn} 1> /dev/null 2> /dev/null
                        done
                fi
        fi
% diff -u ./rc.d/nfsclient /etc/rc.d/nfsclient
--- ./rc.d/nfsclient    2017-07-21 04:11:06.000000000 +0200
+++ /etc/rc.d/nfsclient 2017-12-18 09:15:38.200376000 +0100
@@ -44,7 +44,7 @@
        # successfully notified about a previous client shutdown.
        # If there is no /var/db/mounttab, we do nothing.
        if [ -f /var/db/mounttab ]; then
-               rpc.umntall -k
+               rpc.umntall -k 2> /dev/null
        fi
 }
 load_rc_config $name
% diff -u ./rc.d/random /etc/rc.d/random
--- ./rc.d/random       2017-07-21 04:11:06.000000000 +0200
+++ /etc/rc.d/random    2018-01-09 13:32:18.439347000 +0100
@@ -45,13 +45,13 @@
 random_start()
 {
 
-       if [ ${harvest_mask} -gt 0 ]; then
-               echo -n 'Setting up harvesting: '
-               ${SYSCTL} kern.random.harvest.mask=${harvest_mask} > /dev/null
-               ${SYSCTL_N} kern.random.harvest.mask_symbolic
-       fi
+       # if [ ${harvest_mask} -gt 0 ]; then
+       #       echo -n 'Setting up harvesting: '
+       #       ${SYSCTL} kern.random.harvest.mask=${harvest_mask} > /dev/null
+       #       ${SYSCTL_N} kern.random.harvest.mask_symbolic
+       # fi
 
-       echo -n 'Feeding entropy: '
+       echo -n 'Feeding entropy:'
 
        if [ ! -w /dev/random ] ; then
                warn "/dev/random is not writeable"

% diff -u ./rc.d/routing /etc/rc.d/routing
--- ./rc.d/routing      2017-07-21 04:11:06.000000000 +0200
+++ /etc/rc.d/routing   2017-12-18 09:22:16.604428000 +0100
@@ -67,7 +67,7 @@
        ""|[Aa][Ll][Ll]|[Aa][Nn][Yy])
                for _a in inet inet6 atm; do
                        afexists $_a || continue
-                       eval static_${_a} delete $_if
+                       eval static_${_a} delete $_if 1> /dev/null 2> /dev/null
                        # When $_if is specified, do not flush routes.
                        if ! [ -n "$_if" ]; then
                                eval routing_stop_${_a}
@@ -94,14 +94,14 @@
        _ret=0
        case $1 in
        static)
-               static_$2 add $3
+               static_$2 add $3 1> /dev/null 2> /dev/null
                _ret=$?
                ;;
        options)
                options_$2
                ;;
        doall)
-               static_$2 add $3
+               static_$2 add $3 add $3 1> /dev/null 2> /dev/null
                _ret=$?
                options_$2
                ;;

Now lets see how FreeBSD boots now after the modifications.

stage0-BIOS.jpg

stage1-BTX-Loader.jpg

stage2-Boot-Menu.jpg

stage3-MOD-Non-Native-Boot.jpg.jpg

stage4a-MOD-Native-Boot-A.jpg.jpg

stage4b-MOD-Native-Boot-B.jpg

Its definitely not perfect, but a lot better in my taste.

Now lets login to desktop πŸ™‚

I prefer not to use a login manager so I have an alias named x to xinit command. This way after I login I type x press [ENTER] and x11 desktop is started.

% which x
x: aliased to xinit ~/.xinitrc -- -dpi 75 -nolisten tcp 1> /dev/null 2> /dev/null

stage4c-MOD-Native-Boot-C.jpg

stage5-X11.jpg

UPDATE 1 – FreeBSD 12.x

I recently tried FreeBSD 12.0-RC* versions and there is one ‘talkative’ script that also could be ‘silenced’ a little.

Its the /etc/rc.d/devmatch scrtipt.

Here is the needed patch to make it great again nice and clean again.

% diff -u /home/vermaden/rc-devmatch devmatch 
--- /home/vermaden/rc-devmatch        2018-11-27 17:49:53.573514000 +0100
+++ devmatch    2018-11-27 17:50:11.955342000 +0100
@@ -65,7 +65,7 @@
                case "#${x}#" in
                *"#${m}#"*) continue ;;
                esac
-               echo "Autoloading module: ${m}"
+               # echo "Autoloading module: ${m}"
                kldload -n ${m}
        done
        devctl thaw

UPDATE 2 – The drm-kmod Silencing

Recently to get support for newer GPUs the drm-kmod meta port/package is needed. The thing is that if you add the /boot/modules/i915kms.ko (for Intel GPUs) to the kld_list parameter it will display following error message from the kernel even with boot_mute=YES in the /boot/loader.conf file.

Loading kernel modules:
Dec 16 11:08:03 t420s kernel: Failed to add WC MTRR for [0xe0000000-0xefffffff]: -28; performance may suffer

The syslogd is guilty here with its default configuration in the /etc/syslog.conf file. To make it silent (not print pointless messages) make this change in the /etc/syslog.conf file.

% diff -u /root/syslog.conf /etc/syslog.conf
--- /root/syslog.conf   2018-12-18 11:49:48.204878000 +0100
+++ /etc/syslog.conf    2018-12-18 11:49:55.681504000 +0100
@@ -5,7 +5,7 @@
 #      separators. If you are sharing this file between systems, you
 #      may want to use only tabs as field separators here.
 #      Consult the syslog.conf(5) manpage.
-*.err;kern.warning;auth.notice;mail.crit                       /dev/console
+# *.err;kern.warning;auth.notice;mail.crit                       /dev/console
 *.notice;authpriv.none;kern.debug;lpr.info;mail.crit;news.err  /var/log/messages
 security.*                                                     /var/log/security
 auth.info;authpriv.info                                        /var/log/auth.log

Now it will not print these pointless messages.

This applies both to 11.2-RELEASE and 12.0-RELEASE versions.

UPDATE 3 – Silence the Services Starting Messages

Thanks to the vmisev suggestion we can silence the FreeBSD boot process even more.

Just add rc_startmsgs=NO to your /etc/rc.conf file and reboot to see effects.

Here is already silenced boot process by my earlier settings.

rc_startmsgs_YES.jpg

After adding rc_startmsgs=NO to the /etc/rc.conf file the boot messages are cut in half.

rc_startmsgs_NO.jpg

Now its very close to Solaris/Illumos provides πŸ™‚

EOF