Yes, I know that this is not the best way to build RPM packages but because I had to come up with possibly cleanest for the host computer solution buildah is what came into my mind. Of course, somebody could argue that this can be achieved by using docker and that is true but I’m one of those people who ban docker form their computers. Personally, I’m using podman and systemnd-nspawn to work with containers.

The goal of this whole exercise is to have ZFS build with kmod packages instead of dkms provided by the official repository. Reason for that is simple - dkms is unreliable from time to time and I’m using ZFS as my root partition file system so I have to have fully working kernel modules every time. Unfortunately, maintainers of the official repo don’t have enough resources to follow Fedora update process so they provide only dkms solution which, in a normal situation, is completely sufficient. In next post, I’ll show how to install Fedora using ZFS as a root partition but before that let’s start our build process.

To simplify the whole process we will declare a variable containing the version of ZFS we want to build:

ZFS_VERSION="0.7.9"

Let’s spin-up build container and prepare it a little bit by updating all installed packages. Fedora releases their official images pretty regularly but not each time some little package is updated in repository so it’s quite likely that some will be outdated when you will be following those steps.

CONTAINER=$(buildah from fedora:28)
buildah run $CONTAINER dnf clean all
buildah run $CONTAINER dnf -y update

Following official ZFS wiki, it’s time to install all dependencies required to build ZFS.

buildah run $CONTAINER dnf -y install \
  autoconf \
  automake \
  createrepo \
  elfutils-libelf-devel \
  kernel-devel \
  ksh \
  libattr-devel \
  libblkid-devel \
  libselinux-devel \
  libtirpc-devel \
  libtool \
  libudev-devel \
  libuuid-devel \
  lsscsi \
  make \
  openssl-devel \
  parted \
  rpm-build \
  wget \
  zlib-devel

Since we intend to build kmod packages it’s important to know which version of kernel we will be using to build zfs.

KERNEL_VERSION=$(buildah run $CONTAINER bash -c "rpm -q kernel-devel|sed 's/kernel-devel-//'")

In this scenario, dnf will install latest available kernel packages which, in general, is what we want and ZFS build process will detect them correctly since those will be the only one installed in the container. KERNEL_VERSION variable will be used later only to install spl packages but we can also build kmod packages for specific, older kernel version. In that case, we would declare that variable manually at the beginning and use it to install the kernel-devel package in a specific version.

Next, we need to download ZFS source code.

buildah run $CONTAINER wget -O /root/spl-$ZFS_VERSION.tar.gz https://github.com/zfsonlinux/zfs/releases/download/zfs-$ZFS_VERSION/spl-$ZFS_VERSION.tar.gz
buildah run $CONTAINER wget -O /root/zfs-$ZFS_VERSION.tar.gz https://github.com/zfsonlinux/zfs/releases/download/zfs-$ZFS_VERSION/zfs-$ZFS_VERSION.tar.gz

Time to unpack and build the first part of ZFS - spl.

buildah run $CONTAINER tar xf /root/spl-$ZFS_VERSION.tar.gz -C /root
buildah run $CONTAINER bash -c "cd /root/spl-$ZFS_VERSION; ./configure; make -s -j$(nproc)"
buildah run $CONTAINER bash -c "cd /root/spl-$ZFS_VERSION; make -j1 pkg-utils pkg-kmod"

To continue and build ZFS part we first need to install freshly build spl - it’s a build dependency for ZFS. During that installation you can notice that spl brings with itself few extra packages like kernel-core or darcut and that we can observer few errors - nothing to worry about, all we are interested in right now is a proper spl installation. For errors responsible is dracut because it’s unable to properly generate initramfs which is normal in a container that is unprepared to do such thing. We don’t need initramfs to properly build ZFS so we can dismiss that.

buildah run $CONTAINER dnf -y install \
  /root/spl-$ZFS_VERSION/spl-$ZFS_VERSION-1.fc28.x86_64.rpm \
  /root/spl-$ZFS_VERSION/kmod-spl-devel-$ZFS_VERSION-1.fc28.x86_64.rpm \
  /root/spl-$ZFS_VERSION/kmod-spl-$KERNEL_VERSION-$ZFS_VERSION-1.fc28.x86_64.rpm \
  /root/spl-$ZFS_VERSION/kmod-spl-devel-$KERNEL_VERSION-$ZFS_VERSION-1.fc28.x86_64.rpm

Finally we can unpack and build ZFS.

buildah run $CONTAINER tar xf /root/zfs-$ZFS_VERSION.tar.gz -C /root
buildah run $CONTAINER bash -c "cd /root/zfs-$ZFS_VERSION; ./configure; make -s -j$(nproc)"

At this moment, if you follow stderr your attention may be alerted by those three messages printed-out by our make process:

/root/zfs-0.7.9/module/icp/asm-x86_64/sha1/sha1-x86_64.o: warning: objtool: sha1_block_data_order()+0x11: unsupported stack pointer realignment
/root/zfs-0.7.9/module/icp/asm-x86_64/sha2/sha256_impl.o: warning: objtool: SHA256TransformBlocks()+0x19: unsupported stack pointer realignment
/root/zfs-0.7.9/module/icp/asm-x86_64/sha2/sha512_impl.o: warning: objtool: SHA512TransformBlocks()+0x1c: unsupported stack pointer realignment

Those are generated by outdated assembly code brought in from Illumos in which it appears as a copy-and-paste from old OpenSSL implementation of those hashing algorithms. There is an issue on GitHub for that if you want to take a look. Nothing to worry about for now. ;)

We can continue and build our packages.

buildah run $CONTAINER bash -c "cd /root/zfs-$ZFS_VERSION; make -j1 pkg-utils pkg-kmod"

Now it’s time to copy packages and clean after ourselves, simple container removal will do.

mkdir ~/zfs-rpms
MOUNTPOINT=$(buildah mount $CONTAINER)
mv $MOUNTPOINT/root/{spl,zfs}-$ZFS_VERSION/*.rpm ~/zfs-rpms
buildah rm $CONTAINER

After all of this, we have all build RPMs in ~/zfs-rpms directory ready to be installed. Enjoy.

This whole process can obviously be combined into a simple shell script and it was presented as one in this post only with some additionally commentary so just for your convenience here is a gist that will save you some time with copying parts of this post into the terminal. :)