Find oldest file on UNIX/BSD

If you wish to find the oldest file in a directory tree on a UNIX system, you might have found the following solution:

find . -type f -printf '%T+ %p\n' | sort | head -n 1

This is all good and nice, but it only works with the GNU version of findutils. Indeed other versions of find do not support the -printf option. A more compatible option goes something like that (it’s at the same time more generic (doesn’t use -printf) and more BSD specific (stat syntax) but you might adapt it to Linux easily):

find . -type f | xargs stat -f "%m %N" | sort | head -n 1

HiFiBerry on Debian ARM64

Long are gone the days of the ten thousands songs Winamp playlist, the modern way of listening to music consists solely of spotify blasting its (not-so-randomly) set of tracks and ads on random variants of laptop/phones/speakers.

But I will forever say no to that.
Spotify is bad for the artists, for you, our planet and it has as much a good impact on musical culture as Facebook has on our social life. Today, the common physical storage available locally (if you don’t depend uniquely on the cloud) has more than enough room to host all the music you’d ever want to listen to. Of course this means that you have to handle your music playlist manually. But that effort will refine your tastes as to what is genuinely good music to your ears, and what is just effective product placement.

To handle my music media center, I always had a RPi stucked to my HiFi system. This RPi would only handle playing music (mpd) and remote control (Cantata, MPDroid, ). This music would be stored remotely on my NAS and accessible in read-only from NFS (yup NFS not SAMBA/CIFS).

The music is played through a RPi HAT, the HiFiBerry DAC+ based on Texas Instruments PCM5102A DAC chip. This was done on a common Raspbian (the only viable solution back then), may be you could do the same easily on the new RaspberryPi OS. I did try to replicate the same setup on FreeBSD but neither the HiFiBerry nor the PCM5102 codec were supported. Attempts to play the music through a USB audio device instead of the HiFiBerry HAT were ultimately unsuccessful probably because of the USB DWC2 host driver. The same attempt on a FreeBSD running RPi4 with PCIe XHCI USB host ran the same USB audio devices perfectly well.

[Debian Diversity Logo -- https://gitlab.com/valessiobrito/artwork (GPLv3 -- https://gitlab.com/valessiobrito/artwork)]

But since I only had a single RPi4 that was already in use, and the fact that RPi4 are currently way overpriced and out-of-stock, I resolved to try a Linux based setup on a RPi3B. But you see, Raspbian is rather restricted by the fact that the RPi platforms ranges from ARMv6 to ARMv8 SoC. That’s 32 to 64-bit, so as a compromise Raspbian runs everything in 32-bit even on ARM64 capable SoC like the RPi3 or better (the new Raspberry Pi OS has some ARM64 images although it’s not widely advertised). The challenge was that it should run Debian ARM64 and play audio through the HiFiBerry DAC+.

The main problem is that the Debian ARM64 image runs a mainline/vanilla Linux kernel. Among other things this version of the kernel does not have support for the HiFiBerry. Instead I resolved to compile my own kernel with the appropriate driver included. Also to avoid the hurdle of porting everything HiFiBerry related and other RPi/BCM goodies to the mainline kernel, I used the Raspberry Pi Foundation kernel source tree.

As a starting point, I used the configuration of the RPi3B kernel from the Debian ARM64 image, which you can find in /boot/config-5.10.0-8-arm64. Crosscompiling the kernel for ARM64 was pretty straight forward:

# Mount the RPi image
mount /dev/sdf1 /mnt/rpi/fat32
mount /dev/sdf2 /mnt/rpi/ext4

# Install and clone the kernel
apt-get install crossbuild-essential-arm64
git clone git://github.com/raspberrypi/linux.git

# Setup some variable for cross-compiling.
cd linux
export KERNEL=kernel8
export ARCH=arm64
export CROSS_COMPILE=aarch64-linux-gnu-

# Kernel configuration
# (be sure to select the appropriate platform or the Device Tree Blob won't be compiled)
cp /mnt/rpi/ext4/boot/config-5.10.0-8-arm64 .config
make oldconfig
make menuconfig

# Compile!
make Image modules dtbs -j32

# Install
# (you might have to create the 'overlays' directory in the fat32 partition)
VMLINUZ=vmlinuz-5.10.74+
make INSTALL_MOD_PATH=/mnt/rpi/ext4 modules_install
cp arch/arm64/boot/dts/broadcom/*.dtb  /mnt/rpi/fat32
cp arch/arm64/boot/dts/overlays/*.dtb* /mnt/rpi/fat32/overlays/
cp arch/arm64/boot/Image "/mnt/rpi/fat32/${VMLINUZ}"
cp arch/arm64/boot/Image "/mnt/rpi/ext4/boot/${VMLINUZ}"

# Umount the RPi image and boot it still on the old working kernel.
umount /dev/sdf1
umount /dev/sdf2

# Connect to the RPi and create the initrd.
# This should also adapt the boot config. 
update-initramfs -c -k 5.10.74+

If you want to play with Device Tree overlays for example to use a RPi HAT like the HiFiBerry, you will have to compile the dtoverlay manipulation command from the RPi userland repository. Install libfdt-dev, compile and install libdtovl in helpers/dtoverlay, compile dtoverlay in host_applications/linux/apps/dtoverlay.

You need ConfigFS and the following kernel options for the dtoverlay command to work with dynamic DT:

CONFIG_DTC=y
CONFIG_OF=y
CONFIG_OF_UNITTEST=y
CONFIG_OF_DYNAMIC=y
CONFIG_OF_OVERLAY=y
CONFIG_OF_CONFIGFS=y

Also mount ConfigFS:

mkdir /config
mount -t configfs none /config

The command expects to find the overlays in /boot/overlays but on the Debian ARM64 image they will probably be in /boot/firmware/overlays. I fixed this with a symlink.

Next I had to fiddle a bit with the Device Tree sources. If you want some nice documentation about them, here’s a nice pdf from Freescale that explains a lot.

When I first tried to add the HiFiBerry overlay with dtoverlay hifiberry-dacplus, it could not apply because of “incompatible devices”. This was caused by discrepancies between the ARM and ARM64 DT sources for the RPi. This driver was made for the ARM arch than runs Raspbian, not ARM64. And the ARM arch DTS/DTSI exposes devices differently than ARM64. I added the missing devices on ARM64, recompiled and reinstalled the DTB on the RPi image. After that the DT overlay applied like a charm.

The HiFiBerry DAC+ is now happily playing music on Debian ARM64. The RPi3B runs at ~1.14W on idle and ~1.35W when playing music. I don’t how know much the fat-free low-power kernel config contributes to that, but it seems to run at ~1.25W on Debian’s vanilla kernel and I have some ideas to reduce the consumption even further.

AMD Renoir GPU on FreeBSD 13

UPDATE: github branch available (2022-03-12)

You if have a laptop running one of the latest AMD Ryzen 5 (such as the ThinkPad T14 AMD) with integrated Radeon graphic on FreeBSD 13, you probably struggled to get the GPU running and finally gave up to use the generic scfb frame buffer device instead. It is non accelerated, you cannot access any external port nor adjust the brightness, but it’s usable.

Now I’ve some good news for you! After randomly searching the FreeBSD forums I found a post that was referring to a work-in-progress branch of drm-kmod that should support the latest AMD Renoir GPU. This branch is now named 5.5-stable. After some modifications I was able to compile it on FreeBSD 13.0-RELEASE-p3 and got it to run on the GENERIC kernel.

Acceleration and the external ports work well. I even managed to get a 3 screen setup working through one of those USB-C docking station.

Only one cable connected to the laptop that carries the power supply, audio, external mouse, two screens, external HDD, floppy drive and more. Now, this is what I call “Universal Serial Bus”.

Patching the drm-kmod 5.5-stable branch to compile on 13.0-RELEASE was pretty straightforward too. A missing function here, a different signature there, some missing constants. A lot easier than other things I’ve been trying to port from 12 to 13.

Since I’ve also been able to install a modern TeX Live environment (the 2015 version from the port tree is getting rather outdated), I can now again use FreeBSD as my main working Operating System. Yahoo!

FreeBSD on RaspberryPi

RaspberryYou may have heard that ARM64 is now a tier-1 platform on FreeBSD 13. This basically means that this platform is now fully supported by the various FreeBSD teams. Seeing ARM supported as a tier 1 is really cool, since we can now play around with those ARM boards (RaspberryPi, BeagleBone, …) that were so far reserved to a selected set of Linux distributions. Being able to use an entirely different OS is refreshing.

In the last few weeks, I’ve devoted some of the very little free time that I have to try just that. I’ve installed FreeBSD on some RPi3 boards in the hope of replacing whatever they were doing before on Raspbian. If you insist you can use the video, but it’s very slow and totally unusable as a Kodi media-center. The reason being (as far as I understand) that the VideoCore drivers are a pain in the ass to port even from RPi Linux flavor to another, let alone on FreeBSD. So I wouldn’t expect improvement on that front for some time.

However as a network appliance or audio-only media-center, it works nicely. It’s just a matter of downloading the appropriate SD card image for your specific board (here and there), dd it to the SD card, boot with HDMI and USB keyboard, then configure your installation from there. Beware though, you should avoid editing the UFS partition of the image until it has been resized by growfs_enable=YES. In my case that triggered some naughty kernel panics (which I had no time to investigate thoroughly, oops).

I’ve also tried some unsupported platform such as the NanoPi R2S with mitigated success. I managed to boot on the serial interface and install some packages. But USB devices are not (or not always) showing, the driver for the second Ethernet interface is missing, and random kernel panics do happen. So I gave up for now and tried an RPi3 board instead.

I also tried running it on a RaspberryPi 1 B+ v1.2. The reason I’m trying that is to replace my media-center setup, especially the audio part. The RPi1 should consume less power, is perfectly capable for the task at hand and I’ve got a lot of them lying around. Since the device will be always on, it should be a perfect replacement for the RPi3 I used so far. For this I had to use the RPi-B image. Contrary to the RPi3 which runs ARMv8 64-bit, RPi1 B+ is still an ARMv6 32-bit architecture and a tier-2 platform on FreeBSD.

One of the problem with the RaspberryPi is that there are a lot of different version nowadays and they all share similar names. For instance if you say RPi B+, is it RPi3 B+ from 2018, RPi1 B+ from 2014, a confusion with the RPi2 B v1.2 from 2016 or the RPi2 B? All these run on different SoC with different flavor of ARM from ARMv6 to ARMv8. You must pay attention to choose the correct image for your board. Use the Wikipedia’s RaspberryPi page to tell them apart, it’s very complete, especially the Specifications and Connectors sections.

ioctl mem-alloc FAILED

If while trying to play a video on the RaspberryPi, in particular with Kodi, the video doesn’t play and you get this error on the terminal:

[CGPUMEM]: ioctl mem-alloc FAILED [-1]

Then hopefully this post will help you.

You may have read elsewhere that you should increase your GPU memory in /boot/config.txt, then add gpu_mem=256.

But that’s not enough. You also need to increase the limit of the contiguous memory allocator. In /boot/cmdline.txt add the option cma=256M. Then reboot and you should be fine.

App. freezing in i3

If you encounter some applications freezing or taking a long time to start while using i3, I think in particular about Skype, Discord, CMST (Connman QT GUI), Hexchat, … then may be here is a solution for you. Those app do not appreciate when the desktop does not have any notification daemon running. So you might just install and start one when i3 starts.

So I’ve just installed lxqt-notificationd. Then you can start it from i3’s config file:

exec --no-startup-id lxqt-notificationd

Now all my applications work like a charm, and I’ve no reason whatsoever to temporarily switch to XFCE4.

Clear zpool property

If you want to clear a zfs property, you will often be told to use inherit to instead just inherit the value from the parent dataset. But what if you want to clear a zpool property instead? The answer is simple but you got to know it.

Here I put the '' to emphasize the fact that it’s a pure empty space. that is, if you want to clear the property, there is nothing after ‘=’.

zpool set <property>='' <pool>

Replace USB boot key on FreeNAS

You don’t really install FreeNAS as you do with some other OS. Instead you have a device (often an USB key) that boots FreeNAS which itself manages your data storage. Indeed why wasting some precious SATA port for a boot device when all you need is a little USB key? Especially when thits boot device is less than 2GB in size.

The problem with USB keys is that they wear out over time. So it inevitably comes a time when it must be replaced. This is what happened to me a few days ago.

The freenas-boot pool switched to a DEGRADED state because checksum error happened too frequently. Fortunately a zpool scrub freenas-boot detected no error, and it seems that zfs was still able to correct those. So instead of reflashing a new USB key and restoring my config backup, I could from FreeNAS itself create a new bootable USB key and replace replace the faulty device in the freenas-boot pool.

Let’s login on FreeNAS and plug in your new USB key. We first find and verify what is the device name for the USB key, in my case it’s da2:

$ gpart part show da2
=>       1  60088319  da2  MBR  (29G)
         1        31       - free -  (16K)
        32  60088288    1  fat32lba  (29G)

You see that MBR table and a FAT32 partition, in my case it can only be the new USB key. We will replace that with GPT partitions. This will contain a boot partition (MBR boot or EFI boot), and a ZFS partition. As root:

# Clean that MBR and create GPT partition table
gpart destroy -F da2
gpart create -s GPT da2

# If you use MBR boot
gpart add -s 64K -t freebsd-boot da2
gpart bootcode -b /boot/pmbr -p /boot/gptzfsboot -i 1 da2

# If you use EFI boot
gpart add -s 128M -t efi da2
gpart bootcode -p /boot/boot1.efifat -i 1 da2

# Create the ZFS partition
gpart add -t freebsd-zfs da2

Now it’s time to replace the device:

$ zpool replace -f freenas-boot da1p2 da2p2
cannot replace da1p2 with da2p2: device is too small
# OOPS! :(

If you got the message device is too small, that is because you’ve been trying to replace a device with another one that is smaller than the original (in term of ZFS partition size I suppose). ZFS requires that you replace a device with another with a size greater or equal to the old one. This can be a problem especially if you have a ZFS partition along with others in the partition table like here, or if the vendor announces a certain disk size but only within a certain approximation. You could result in a disk announced to be the exact same size ending up to be very slighty shorter than your original disk. And as a result you won’t be able to use it to replace any disk in your ZFS pool/vdev. That’s why some recommend to create ZFS filesystems several percents less than the available disk size.

But since we messed up, instead we will create a pool on the other USB key and use ZFS send/recv to migrate the files.

# Create the pool on the new USB key.
# Note that we have to call it freenas-boot2
# because freenas-boot already exists.
zpool create freenas-boot2 da2p2 

# Create a recursive snapshot of the original pool
# that we will use to restore the backup. 
zfs snapshot -r freenas-boot@restore

# Send the snapshot from the old to the new USB key.
zfs send -R freenas-boot@restore | zfs recv -F freenas-boot2

We also need to save the original setting for bootfs because FreeNAS has its own way of managing the boot pool. We will set this value later on the new pool.

$ zpool get bootfs
NAME          PROPERTY  VALUE                        SOURCE
freenas-boot  bootfs    freenas-boot/ROOT/11.3-U4.1  local

We still have to change that name from freenas-boot2 to freenas-boot. However we cannot do so on the running instance of FreeNAS because it already has a pool named freenas-boot. So, we will import it on another ZFS capable machine and fix its name.

(but if anyone knows how to do this live, I’m interested)

# On some other ZFS capable host (FreeBSD for instance ;) )
# import the pool and change its name back to freenas-boot.
# The -f is required because it comes from another host.
zpool import -f freenas-boot2 freenas-boot

# Configure default boot filesystem.
# Remember the value of bootfs we found before on the original pool.
zpool set bootfs=freenas-boot/ROOT/11.3-U4.1 freenas-boot

# Export the pool again.
zpool export freenas-boot

Finally you can clear the old snapshot:

zfs destroy -R freebsd-boot@restore

Faster Intel graphics on FreeBSD

If you have a laptop with an Intel graphic card and architecture above Sandy Bridge (circa 2011), you can accelerate xorg significantly with this little hack. Create the file /usr/local/etc/X11/xorg.conf.d/intel.conf:

Section "Device"
  Identifier "Intel Graphics"
  Driver     "Intel"
  Option     "AccelMethod" "sna"
EndSection

See the manpage intel.4. It seems that the version of xf86-video-intel on FreeBSD falls back to the UXA acceleration method but forcing SNA provided good results on my ThinkPad X250.