This page looks best with JavaScript enabled

FreeBSD update 13.0

 ·  🎃 kr0m

In this article we will explain how to migrate a FreeBSD 12.2 system to 13.0. The main features to highlight in version 13 are the incorporation of OpenZFS and TLS in the kernel itself. For more details, we can see the release notes at this link: https://www.freebsd.org/releases/13.0R/relnotes/

The migration will be carried out differently depending on whether it is a physical system or a virtualized jail, and there are also variations depending on the boot system used. On the other hand, we will also explain some aspects to take into account if we use FUSE, ZFS or Poudriere.


Operating system

We update the kernel and core tools to the latest version within 12.2:

freebsd-update fetch
freebsd-update install

We do the same with binary packages:

pkg upgrade
pkg autoremove

We check the current version:

freebsd-version

12.2-RELEASE-p6

We create a new boot environment (BE):

bectl create 13
bectl list

BE      Active Mountpoint Space Created
13      -      -          8K    2021-05-15 18:03
default NR     /          41.7G 2020-11-27 23:58

We mount the BE:

bectl mount 13 /var/tmp/BE-13

Successfully mounted 13 at /var/tmp/BE-13

We chroot to this directory:

chroot /var/tmp/BE-13
mount -t devfs devfs /dev
rm -rf /var/db/freebsd-update
mkdir /var/db/freebsd-update

We upgraded to 13.0:

freebsd-update upgrade -r 13.0

We installed kernel and modules:

freebsd-update install

We installed userspace/binaries/libraries:

freebsd-update install

The assistant informs us that we must reinstall all installed packages:

Completing this upgrade requires removing old shared object files.
Please rebuild all installed 3rd party software (e.g., programs
installed from the ports tree) and then run "/usr/sbin/freebsd-update install"
again to finish installing updates.

We reinstall according to whether we use binary packages or ports:

pkg upgrade
git -C /usr/ports pull
cd /usr/ports
make fetchindex
for PORT in $(pkg info|awk '{print$1}'); do PORT_PATH=$(pkg info $PORT|grep Origin|awk '{print$3}') && echo PORT: $PORT - $PORT_PATH && cd /usr/ports/$PORT_PATH && export BATCH="yes" && make clean reinstall clean; done

It will detect the ABI change and reinstall all installed packages.

We remove old libraries and files:

freebsd-update install

Exit the chroot:

exit

Unmount the BE:

umount /var/tmp/BE-13/dev

Activate the BE to be loaded on the next boot:

bectl activate 13


Another important aspect of the OS is the loader, to switch to version 13.0 we must also update it.

Loader update: EFI

Locate the EFI partition:

gpart show -p nvd0 | grep efi

          40      409600  nvd0p1  efi  (200M)

Mount the partition and display its contents:

mount_msdosfs /dev/nvd0p1 /mnt
find /mnt

/mnt
/mnt/efi
/mnt/efi/boot
/mnt/efi/boot/BOOTx64.efi
/mnt/efi/boot/startup.nsh
/mnt/System Volume Information

Update the loader:

cp /var/tmp/BE-13/boot/loader.efi /mnt/efi/boot/bootx64.efi

Unmount the EFI partition:

umount /mnt

In the following link, we can see the change in managing the EFI partition:
https://www.freebsd.org/releases/13.0R/relnotes/#boot

Prior releases had a complete ms-dos formatted filesystem packaged into boot1.efifat. Older versions of FreeBSD installed this filesystem image into a raw partition. However, uses of the ESP have proliferated, making this inflexible approach no longer desirable.
Users have varied needs for the size of this partition, and multiple booting setups require more detailed access.
To update old ESP partitions, users should stop using the gpart(8) utility. Instead, ESP partitions should be mounted as MS-DOS filesystems as /boot/efi, and /boot/loader.efi should be copied to /boot/efi/efi/boot/bootx64.efi if the default setup is use.
If the efibootmgr(8) utility is used to customize the boot environment, this file should be copied to the location set with the -l flag.

Previously, an image of the EFI partition was directly dumped to a partition:

gpart bootcode -p /boot/boot1.efifat -i 1 vtbd1

Now, mount the EFI partition and copy the file:

loader.efi

Loader update: BIOS

If we boot using BIOS, we need to locate the boot partition:

gpart show -p ada0 | grep freebsd-boot

         40       1024  ada0p1  freebsd-boot  (512K)

Dump the contents of the file /boot/pmbr to the MBR (first 512 bytes) of the disk and the contents of the file /boot/gptzfsboot to the boot partition:

gpart bootcode -b /var/tmp/BE-13/boot/pmbr -p /var/tmp/BE-13/boot/gptzfsboot -i 1 ada0

partcode written to ada0p1
bootcode written to ada0

Restart:

shutdown -r now

If something goes wrong, we can always boot into the other BE.

If, on the other hand, we lose the bootloader, we can restore it by booting a FreeBSD13 ISO and copying loader.efi to the EFI partition or rewriting the MBR and boot partition if using BIOS mode.

In EFI mode, we will see the new loader:

In BIOS mode, we will continue with the old one:

Check the version:

freebsd-version

13.0-RELEASE

When we are sure that the new version works fine, we can rename the BE:

bectl destroy default
bectl rename 13 default


ZFS update

When the ZFS code is updated, we need to update the system pools to enable the new functionalities:

zpool status

  pool: zroot
 state: ONLINE
status: Some supported features are not enabled on the pool. The pool can
	still be used, but some features are unavailable.
action: Enable all features using 'zpool upgrade'. Once this is done,
	the pool may no longer be accessible by software that does not support
	the features. See zpool-features(5) for details.
config:

	NAME        STATE     READ WRITE CKSUM
	zroot       ONLINE       0     0     0
	  nvd0p4    ONLINE       0     0     0

errors: No known data errors

Update the pool:

zpool upgrade zroot

zpool status
  pool: zroot
 state: ONLINE
config:

	NAME        STATE     READ WRITE CKSUM
	zroot       ONLINE       0     0     0
	  nvd0p4    ONLINE       0     0     0

errors: No known data errors

FUSE update

The name of the FUSE kernel module has been renamed, so we update the module list:

vi /etc/rc.conf
kld_list="nvidia-modeset fusefs vmm if_tap if_bridge nmdm linux linux64 linprocfs linsysfs fdescfs"

IOCAGE update

First, we update the parent to 13.0 following the previous steps in this same article.

The next step is to update both the OS and the packages to their latest version in each of the jails.

JAILNAME=….
iocage update $JAILNAME
iocage console $JAILNAME
pkg upgrade
pkg autoremove

Now we can update them to 13.0. We download the RELEASE from Iocage:

iocage fetch

[0] 11.2-RELEASE
[1] 11.3-RELEASE
[2] 11.4-RELEASE
[3] 12.0-RELEASE
[4] 12.1-RELEASE
[5] 12.2-RELEASE
[6] 13.0-RELEASE

Type the number of the desired RELEASE
Press [Enter] to fetch the default selection: (13.0)
Type EXIT to quit:  
Fetching: 13.0-RELEASE

We update each of the jails:

JAILNAME=….

iocage upgrade $JAILNAME -r 13.0-RELEASE
iocage update $JAILNAME
iocage console $JAILNAME

If we see the following error message, we need to change the shell to the default one before accessing the jail:

ld-elf.so.1: Shared object “libncursesw.so.8” not found, required by “bash”

iocage exec $JAILNAME "chsh -s /bin/sh"

Inside the jail
Depending on whether we use binary packages or ports, we will execute:

pkg-static upgrade -f
git -C /usr/ports pull
cd /usr/ports
make fetchindex
for PORT in $(pkg info|awk '{print$1}'); do PORT_PATH=$(pkg info $PORT|grep Origin|awk '{print$3}') && echo PORT: $PORT - $PORT_PATH && cd /usr/ports/$PORT_PATH && export BATCH="yes" && make clean reinstall clean; done

When we finish, we exit the jail.

exit

We revert the shell change:

iocage exec $JAILNAME "chsh -s /usr/local/bin/bash"

We finish the update:

iocage update $JAILNAME

NOTE: Updates using Iocage automatically create a snapshot with each update, so if something goes wrong, it can be easily reverted.

But we need to keep in mind that snapshots take up disk space:

zpool list

NAME      SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
storage   928G   822G   106G        -         -    34%    88%  1.00x    ONLINE  -
zroot     109G   104G  5.38G        -         -    87%    95%  1.00x    ONLINE  -
iocage df
+----------------+-------+------+------+-------+-------+
|      NAME      |  CRT  | RES  | QTA  |  USE  |  AVA  |
+================+=======+======+======+=======+=======+
| Andromeda      | 1.56x | none | none | 3.48G | 13.5G |
+----------------+-------+------+------+-------+-------+
| DrWho          | 1.74x | none | none | 7.33G | 13.5G |
+----------------+-------+------+------+-------+-------+
| HAProxy        | 1.59x | none | none | 4.71G | 13.5G |
+----------------+-------+------+------+-------+-------+
| Infinity       | 1.56x | none | none | 4.09G | 13.5G |
+----------------+-------+------+------+-------+-------+
| Lomax          | 1.42x | none | none | 5.82G | 13.5G |
+----------------+-------+------+------+-------+-------+
| Mistery        | 1.50x | none | none | 12.4G | 13.5G |
+----------------+-------+------+------+-------+-------+
| Potras         | 1.61x | none | none | 6.33G | 13.5G |
+----------------+-------+------+------+-------+-------+
| basic_template | 1.64x | none | none | 4.46G | 13.5G |
+----------------+-------+------+------+-------+-------+
| redis00        | 1.55x | none | none | 3.37G | 13.5G |
+----------------+-------+------+------+-------+-------+
| redis01        | 1.58x | none | none | 3.39G | 13.5G |
+----------------+-------+------+------+-------+-------+
| redis02        | 1.58x | none | none | 3.39G | 13.5G |
+----------------+-------+------+------+-------+-------+
| rxWod          | 1.75x | none | none | 10.1G | 13.5G |
+----------------+-------+------+------+-------+-------+

Once we are sure that the jail is working fine, we can clean up the snapshots:

JAIL=….

for SNAPTOREMOVE in $(iocage snaplist $JAIL|grep -v root|grep -v ‘+’|grep -v ‘NAME’|awk ‘{print$2}’); do
iocage snapremove -n $SNAPTOREMOVE $JAIL
done


Iocage - Template

To update templates, we first need to convert them to a jail, update them, and then convert them back to a template:

iocage list -t

+-----+----------------+-------+--------------+--------------+
| JID |      NAME      | STATE |   RELEASE    |     IP4      |
+=====+================+=======+==============+==============+
| -   | basic_template | down  | 12.2-RELEASE | 192.168.69.9 |
+-----+----------------+-------+--------------+--------------+
iocage set template=no $JAIL
iocage start $JAIL

Update it as if it were a regular jail:

iocage stop $JAIL

Delete the template snapshots:

JAIL=….

for SNAPTOREMOVE in $(iocage snaplist $JAIL|grep -v root|grep -v ‘+’|grep -v ‘NAME’|awk ‘{print$2}’); do
iocage snapremove -n $SNAPTOREMOVE $JAIL
done

Convert it back to a template:

iocage set template=yes $JAIL

iocage list -t

+-----+----------------+-------+--------------+--------------+
| JID |      NAME      | STATE |   RELEASE    |     IP4      |
+=====+================+=======+==============+==============+
| -   | basic_template | down  | 13.0-RELEASE | 192.168.69.9 |
+-----+----------------+-------+--------------+--------------+

Poudriere

We download the new RELEASE version:

poudriere jail -c -j freebsd_13-0x64 -v 13.0-RELEASE

poudriere jail -l
JAILNAME        VERSION         ARCH  METHOD TIMESTAMP           PATH
freebsd_12-2x64 12.2-RELEASE-p6 amd64 ftp    2021-05-10 23:36:10 /usr/local/poudriere/jails/freebsd_12-2x64
freebsd_13-0x64 13.0-RELEASE    amd64 ftp    2021-05-17 15:19:03 /usr/local/poudriere/jails/freebsd_13-0x64

We migrate the generic compilation options:

cp /usr/local/etc/poudriere.d/freebsd_12-2x64-make.conf /usr/local/etc/poudriere.d/freebsd_13-0x64-make.conf

The options by package:

cp -r /usr/local/etc/poudriere.d/freebsd_12-2x64-HEAD-options /usr/local/etc/poudriere.d/freebsd_13-0x64-HEAD-options

The configuration of compilation options:

poudriere options -c -j freebsd_13-0x64 -p HEAD -f /usr/local/etc/poudriere.d/port-list

We update the jail and ports:

poudriere jail -u -j freebsd_13-0x64
poudriere ports -u -p HEAD

We compile the ports:

poudriere bulk -j freebsd_13-0x64 -p HEAD -f /usr/local/etc/poudriere.d/port-list

The client part would be as follows:

vi /usr/local/etc/pkg/repos/poudriere.conf

poudriere: {
    url: "http://poudriere.alfaexploit.com/packages/freebsd_13-0x64-HEAD/",
    mirror_type: "http",
    signature_type: "pubkey",
    pubkey: "/usr/local/etc/ssl/certs/poudriere.cert",
    enabled: yes,
}

We check that the repository content is accessible:

<html>
<head><title>Index of /packages/</title></head>
<body>
<h1>Index of /packages/</h1><hr><pre><a href="../">../</a>
<a href="freebsd_12-2x64-HEAD/">freebsd_12-2x64-HEAD/</a>                              10-May-2021 21:37                   -
<a href="freebsd_13-0x64-HEAD/">freebsd_13-0x64-HEAD/</a>                              17-May-2021 17:54                   -
</pre><hr></body>
</html>

We recompile all the packages:

pkg-static upgrade -f

If we use an automatic script on the build server as indicated here , we must also modify it:

vi .scripts/updatePoudriere.sh

#!/usr/local/bin/bash
poudriere jail -u -j freebsd_13-0x64
poudriere ports -u -p HEAD
poudriere options -j freebsd_13-0x64 -p HEAD -f /usr/local/etc/poudriere.d/port-list
poudriere bulk -j freebsd_13-0x64 -p HEAD -f /usr/local/etc/poudriere.d/port-list

Poudriere - Cleaning

We remove the jail:

poudriere jail -d -j freebsd_12-2x64

We remove the source code of the packages:

poudriere distclean -a -p HEAD

We remove the logs:

poudriere logclean -a -j freebsd_12-2x64 -p HEAD

We remove the compiled packages:

poudriere pkgclean -A -j freebsd_12-2x64 -p HEAD

We remove some residual directories:

rm -rf /usr/local/poudriere/data/packages/freebsd_12-2x64-HEAD/
rm -rf /usr/local/etc/poudriere.d/freebsd_12-2x64-HEAD-options
rm /usr/local/etc/poudriere.d/freebsd_12-2x64-make.conf

We remove the old version of the data.json file:

vi /usr/local/poudriere/data/logs/bulk/.data.json

If you liked the article, you can treat me to a RedBull here