I been using my Raspberry Pi 2 as my introduction to using FreeBSD and even an
introduction to BSDs. It has been of great help giving me perspectives and
experiences in package management, setting up DNS using unbound(8) and so on.
One of the tiny “gotchas” of using FreeBSD (as of the time of writing this) on
ARM is the fact that it is a Tier 2[1] for ARM 32-bit, but FreeBSD might be
seeing Tier 1 support as ARM 64-bit evolves. One of the issues of using Tier 2
support is there is no direct upgrade paths between FreeBSD release versions in
this specific scenario between 11.0-RELEASE vs 11.1-RELEASE. freebsd-update(1)
won’t work and the only way to do an in-place upgrade was to build the kernel
and do a make(1)
install of the world and kernel.
In general this is not much of an issue, but me being me and ignorant about the
warnings I was doing pkg-upgrade(8) to update the installed packages. Luckily I
did not restart the system before I noticed this error.
[fox@pi: ~]$ sudo -i
Password:
/usr/local/bin/sudo: Undefined symbol "memset_s"
[fox@pi: ~]$
I checked up on su(1), and su(1) worked as expected. But if sudo(8) was broken
from the upgrade, there might have been other programs installed via pkg(1)
might also be broken. Investigating a bit further I figure out that once the
11.1-RELEASE had gone through the newer packages are built against
11.1-RELEASE. With my RPi2 running on 11.0-RELEASE I was not expecting an ABI
breakage, and happily ignoring the message
ABI changed: 'freebsd:11:x86:64' -> 'freebsd:11:x86:64'
during the pkg-upgrade(8) did not help either. With a half broken RPi2 which
acts as my irc bouncer and a little web server which hosts this blog, I needed
to get fixed up before things start to get worse than it is.
The only viable solution to the above was to build the userland and kernel for
ARM (armv6 for RPi2) and then install them. Even though I had access to a
FreeBSD build machine where I could cross-compile the required binaries for
kernel and userland, mounting it over a NFS especially over a flaky internet
connection at my home to do make
install is quite a risky process if the
connectivity breaks for some reason. The fact that I was in Japan for a month
did not help either. Upgrading the RPi2 remotely was a risk, especially if any
of the install phases does not go right, at worst I might end up with a RPi2
with connectivity lost, which means I cannot bring back up the irc client or the
blog until I am back at my home.
Luckily Tod had a spare RPi2, so here is what I intend to do
- Download the FreeBSD 11.0-RELEASE image for RPi2.
dd(1)
the image onto my spare SD Cards (which I usually carry around).- Boot the RPi2, download the FreeBSD 11.0-RELEASE sources into the RPi2.
- Build the FreeBSD 11.1-RELEASE kernel and userland in the RPi2 (I know this is
going to burn the write cycles in the SD Card, but that is something that I
can replace if needed). - Compress the object directory of the build and clean out the build directory.
- Do a pkg-upgrade(8) to re-create the problem in FreeBSD-11.0-RELEASE.
- Uncompress the object directory into the right place.
- Do the
make
install of kernel and world in this local RPi2 viassh(1)
make
sure things go right. - Repeat the steps in my remote RPi2.
The basic setup!!
First things first check the disk space status (using a 16G SD Card).
root@rpi2:/home/freebsd # df -kh .
Filesystem Size Used Avail Capacity Mounted on
/dev/ufs/rootfs 14G 1.2G 12G 9% /
root@rpi2:/home/freebsd #
Using this well written article[3] I was able to initiate the build process
within RPi2. The kernel build went successfully, but the userland build failed
due to /tmp
not having enough space. Upon further inspection I found that the
/tmp
was mapped to the ramdisk and a simple umount(8)
on /tmp
fixed that
and I could proceed with the build.
root@rpi2:/usr/obj # df -kh .
Filesystem Size Used Avail Capacity Mounted on
/dev/ufs/rootfs 14G 6.8G 6.4G 52% /
root@rpi2:/usr/obj #
After this I managed to install the kernel and userland, rebooted the RPi2 and
sudo(8) started to work without issues. Now the challenge was to do the exact
same steps in my remote RPi2.
Next I compressed the src
and obj
directories, so that I can copy them over
to my RPi2 remotely, this would prevent me from re-building all the things from
scratch. rsync(1) was definitely useful to copy the files over to my RPi2 which
runs on a flakey connection. After this I just executed the usual make(1)
commands.
Before starting the upgrade.
[root@pi: /usr/src]# uname -a
FreeBSD pi 11.0-RELEASE-p1 FreeBSD 11.0-RELEASE-p1 #0 r306420: Thu Sep 29 13:01:42 UTC 2016 root@releng2.nyi.freebsd.org:/usr/obj/arm.armv6/usr/src/sys/RPI2 arm
[root@pi: /usr/src]#
Install the kernel and merge the configuration files.
[root@pi: /usr/src]# make TARGET_ARCH=armv6 KERNCONF=RPI2 installkernel
.
.
.
[root@pi: /usr/src]# mergemaster -p -A armv6
Install the world and merge the configuration files.
[root@pi: /usr/src]# make TARGET_ARCH=armv6 installworld
.
.
.
[root@pi: /usr/src]# mergemaster -iF -A armv6
Check for old files and delete the old files / library.
[root@pi: /usr/src]# make TARGET_ARCH=armv6 check-old
.
.
.
[root@pi: /usr/src]# make TARGET_ARCH=armv6 -DBATCH_DELETE_OLD_FILES delete-old
.
.
.
[root@pi: /usr/src]# make TARGET_ARCH=armv6 -DBATCH_DELETE_OLD_FILES delete-old-libs
After the upgrade :)
[fox@pi: ~]$ uname -a
FreeBSD pi 11.1-RELEASE-p9 FreeBSD 11.1-RELEASE-p9 #2 r332467: Mon Apr 16 21:11:04 UTC 2018 root@rpi2:/usr/obj/usr/src/sys/RPI2 arm
[fox@pi: ~]$
I think next time, doing a blind pkg-upgrade(8) may not be wise especially in
Tier 2 architecture. Also I should look into a better way to upgrade my RPi2
with updated version of FreeBSD without the need to dd(1) things over and losing
data. May be Crochet[4] with some customizations?, I am not sure about it.
References
- https://www.freebsd.org/platforms/arm.html
- https://www.freebsd.org/releases/11.1R/announce.html
- https://solence.de/2017/03/15/installing-and-updating-freebsd-11-0-release-on-a-raspberry-pi/
- https://github.com/freebsd/crochet