ZFS/rootfs

From Gentoo Wiki
< ZFS
Jump to:navigation Jump to:search
See also
For those looking to find general information on using ZFS on Linux then please see the ZFS page instead.

This article is focused on using ZFS as the rootfs on Gentoo and designed to be used with the Handbook. Over time more advanced setups will be added so please check the TODO section to see if there is something that can be added to improve this article.

Partitions

Layout

Follow the Handbook section on Preparing the disks returning at the creating file systems section.

This guide will be using the example below however it should be simple enough to adapt this to the user's needs.

/dev/sda1   | 1024 MiB      | EFI System Partition   | /efi
/dev/sda2   | 2048 MiB      | swap                   | swap
/dev/sda3   | Rest of Disk  | ZFS Partition          | /, /boot, /home, ...
Boot

Create a 1GB FAT32 filesystem:

root #mkfs.vfat -F 32 /dev/sda1
Swap

Swap performance on a ZFS partition is known to be poor and using a swapfile is not supported, instead it is recommended to use its own partition.

root #mkswap /dev/sda2
root #swapon /dev/sda2
Note
Alternatively, zram could be used on systems with a large amount of RAM but do note ZFS will cache data to RAM for speed.

ZFS Setup

Generate host ID

Randomly generate host ID into /etc/hostid allowing output overwrite.

root #zgenhostid -f

Alternatively, set a specific host ID, 0x00bab10c in this example.

root #zgenhostid -f 0x00bab10c
Create a ZFS pool

Load ZFS kernel module and create a ZFS pool tank on /dev/sda3.

root #modprobe zfs
root #zpool create -f \
-o ashift=12 \
-o autotrim=on \
-o compatibility=grub2 \
-O acltype=posixacl \
-O xattr=sa \
-O relatime=on \
-O compression=lz4 \
-m none tank /dev/sda3
Note
The option -o compatibility=grub2 makes sure that GRUB works. If you are using ZFSBootMenu, you can skip that option.
Warning
Use -o ashift=9 for disks with a 512 byte physical sector size or -o ashift=12 for disks with a 4096 byte physical sector size. See OpenZFS: ashift property definition
Alternative: Create a ZFS pool with LUKS encryption

Using LUKS involves creating an encrypted container on the physical partition first, then placing the ZFS pool inside that container.

Prepare the encrypted partition

First, initialize the physical partition (e.g., /dev/sda3) with LUKS. You will be prompted to set a password.

root #cryptsetup luksFormat /dev/sda3

Open the encrypted device. This creates a virtual block device at /dev/mapper/cryptroot.

root #cryptsetup luksOpen /dev/sda3 cryptroot

Create the ZFS pool on LUKS

Now, create the pool using the mapper device instead of the raw partition.

root #modprobe zfs
root #zpool create -f \
-o ashift=12 \
-o autotrim=on \
-o compatibility=grub2 \
-O acltype=posixacl \
-O xattr=sa \
-O relatime=on \
-O compression=lz4 \
-m none tank /dev/mapper/cryptroot

After this, proceed to Create ZFS file systems as usual. Note that you will need to unlock this partition every time you import the pool manually.

Update Dracut and Bootloader

For the system to boot, the initramfs must know how to unlock the LUKS device.

1. Find the UUID of your physical partition (e.g., /dev/sda3):

root #blkid /dev/sda3

2. Add the crypt module to your Dracut configuration in /etc/dracut.conf.d/zol.conf:

FILE /etc/dracut.conf.d/zol.confDracut config for LUKS + ZFS
nofsck="yes"
add_dracutmodules+=" zfs crypt "

3. Add the LUKS UUID to your kernel command line. For GRUB, edit /etc/default/grub:

FILE /etc/default/grubKernel parameters for unlocking LUKS
GRUB_CMDLINE_LINUX="rd.luks.uuid=YOUR-UUID-HERE"

Replace YOUR-UUID-HERE with the UUID from the blkid command. Finally, rebuild your initramfs and update your bootloader configuration.

Note
Check that you have the sys-fs/cryptsetup package installed in your world set before rebooting, as it's required for the initramfs to handle the LUKS container.
Alternative: Create a ZFS pool with native encryption
Note
Native encryption *used* to be unmaintained, but as of 2025 that is not the case anymore, see https://github.com/openzfs/zfs/issues/12014 https://github.com/openzfs/openzfs-docs/issues/494.


Native ZFS encryption can also be used by adding additional options when creating our zpool.

root #zpool create -f \
-o ashift=12 \
-o autotrim=on \
-o compatibility=openzfs-2.1-linux \
-O acltype=posixacl \
-O xattr=sa \
-O relatime=on \
-O compression=lz4 \
-O encryption=aes-256-gcm \
-O keylocation=prompt \
-O keyformat=passphrase \
-m none tank /dev/sda3
Note
It's also possible to set the keylocation property to point to a file, which is useful when using ZFSBootMenu as a bootloader, or when trying to reduce the number of passphrase prompts during boot. See the ZFSBootMenu documentation for more info on how it handles encrypted filesystems.
Create ZFS file systems

This guide will be only creating root and home file systems. However, the user is free to create additional file systems if desired.

root #zfs create -o mountpoint=none tank/os
root #zfs create -o mountpoint=/ -o canmount=noauto tank/os/gentoo
root #zfs create -o mountpoint=/home tank/home
Note
The property canmount=noauto should be set on any file systems with the root mountpoint. Omitting it can result in OS trying to automatically mount several file systems at / and failing.


If you intend to put /usr, /etc or any other system-critical folder on a different dataset, note that it has to be a child of the root dataset (e.g. tank/os/gentoo/usr), with canmount=on to be properly mounted by dracut-generated initramfs

Set the preferred boot file system of the pool.

root #zpool set bootfs=tank/os/gentoo tank
Export and re-import a pool, mount file systems

To export and re-import a pool with a specified mountpoint and without automatically mounting the file systems, run the following commands.

root #zpool export tank
root #zpool import -N -R /mnt/gentoo tank

It is then possible to mount root and home file systems.

Note
If you used native encryption, load zfs key with zfs load-key tank
root #zfs mount tank/os/gentoo
root #zfs mount tank/home

If you followed the example you can also mount your efi partition.

root #mount --mkdir /dev/sda1 /mnt/gentoo/efi

After mounting the file systems, it is advisable to verify mountpoints by checking the output of the command below.

root #mount -t zfs

Here is an example of the command output in case of successful mounting of file systems.

tank/os/gentoo /mnt/gentoo type zfs (rw,relatime,xattr,posixacl)
tank/home on /mnt/gentoo/home type zfs (rw,relatime,xattr,posixacl)

Update device symbolic links:

root #udevadm trigger

Return to the Handbook - EFI_system_partition_filesyste and return just before entering chroot command.

Copy host ID file
root #cp /etc/hostid /mnt/gentoo/etc

Return to Handbook - Installing Gentoo base system and return here at Kernel configuration and compilation.

Kernel

The user can choose between manually configured kernel or the distribution kernel.

Distribution kernel
Enabling USE flag

If using the distribution kernel then the dist-kernel USE flag will need to be enabled:

FILE /etc/portage/make.confEnabling dist-kernel USE flag in make.conf
USE="dist-kernel"
Installing distribution kernel
root #emerge -av sys-kernel/gentoo-kernel

Or, if you prefer using the pre-compiled binary,

root #emerge -av sys-kernel/gentoo-kernel-bin
Manual kernel config

configure the kernel as desired, save and build ( do not install yet )

root #make -j$(nproc) && make modules_install

install the zfs package ( if a kernel version error appears use the previous version )

root #emerge --ask zfs

then add zfs kernel module in dracut as shown previusly also write root=ZFS=tank/os/gentoo to /etc/cmdline or the initramfs will refuse to build now build and install, use installkernel for simplicity sake ( dracut and grub use flags enabled )

root #make -j$(nproc) && make modules_install && make install

everytime the gentoo-sources are emerged or the kernel config is changed you have to repeat this or it won't boot

ZFS userland utilities and kernel module

The sys-fs/zfs package is necessary to allow your system to interact with and manage your ZFS pools. Make sure the module flag is set

root #emerge -av sys-fs/zfs


Initramfs

Configure Dracut

Create a directory for Dracut configuration files if it does not exist.

root #mkdir -p /etc/dracut.conf.d

Then, create a file zol.conf with the following content in this directory:

root #nano /etc/dracut.conf.d/zol.conf
FILE /etc/dracut.conf.d/zol.confDracut configuration for ZFS
nofsck="yes"
add_dracutmodules+=" zfs "
Build the initramfs for the distribution kernel
root #emerge --config sys-kernel/gentoo-kernel

Or, if the binary version was installed,

root #emerge --config sys-kernel/gentoo-kernel-bin

You can return to the Handbook - Configuring the system and return here at Configuring the bootloader.


Bootloader

ZFSBootMenu

An overview of the ZFSBootMenu installation is given here, but a more in depth guide can be found at ZFS/ZFSBootMenu

Setting kernel command-line
root #zfs set org.zfsbootmenu:commandline="quiet loglevel=4" tank/os
Note
ZFS properties are inherited, therefore all children datasets of tank/os will inherit the command-line arguments. If necessary, the property can be overridden in specific child datasets.
Mounting the EFI System Partition
Note
The ZFSBootMenu documentation states that the kernel and initramfs must be located in the /boot directory of the ZFS root. However, the systemd installkernel will attempt to locate the mountpoint of your EFI partition and install the kernel-initramfs pair there instead, which in our case, is /efi Therefore, the -systemd USE flag must be added to sys-kernel/installkernel to prevent that from happening.

If the ESP was not mounted previously, it is necessary to do it now:

root #mkdir -p /efi
root #mount /dev/sda1 /efi
Installing ZFSBootMenu (from source)

ZFSBootMenu ebuild is available in the GURU repository, which has to be added first, if not done already:

root #emerge app-eselect/eselect-repository
root #eselect repository enable guru
root #emerge --sync

The package then needs to be unmasked.

FILE /etc/portage/package.accept_keywords/zfsbootmenuUnmasking zfsbootmenu for installation
sys-boot/zfsbootmenu ~amd64

sys-boot/zfsbootmenu can then be installed.

root #emerge --ask --verbose sys-boot/zfsbootmenu

After that, the ZFSBootMenu configuration needs to be adjusted in order to:

  • Enable automatic management of images: ManageImages:true
  • Point to the EFI mount point: BootMountPoint: /efi
  • Enable EFI binary generation: Enabled: true in the EFI section
FILE /etc/zfsbootmenu/config.yamlZFSBootMenu configuration
Global:
  ManageImages: true
  BootMountPoint: /efi
  DracutConfDir: /etc/zfsbootmenu/dracut.conf.d
  PreHooksDir: /etc/zfsbootmenu/generate-zbm.pre.d
  PostHooksDir: /etc/zfsbootmenu/generate-zbm.post.d
  InitCPIOConfig: /etc/zfsbootmenu/mkinitcpio.conf
Components:
  ImageDir: /efi/EFI/BOOT
  Versions: 3
  Enabled: true
EFI:
  ImageDir: /efi/EFI/BOOT
  Stub: /usr/lib/systemd/boot/efi/linuxx64.efi.stub
  Versions: false
  Enabled: true
Kernel:
  CommandLine: ro loglevel=0

Then the bootloader image needs to be generated:

root #generate-zbm

This will output an EFI image to /efi/EFI/BOOT/vmlinuz.EFI, which can then be copied to /efi/EFI/BOOT/BOOTX64.EFI, or sys-boot/efibootmgr can be used.

root #efibootmgr -c -d /dev/sdX -p 1 -L "ZFSBootMenu" -l '\EFI\BOOT\VMLINUZ.EFI'
Installing ZFSBootMenu (prebuilt)

Create a directory for the bootloader and download the EFI binary into it.

root #mkdir -p /efi/EFI/BOOT
root #wget -L https://get.zfsbootmenu.org/latest.EFI -O /efi/EFI/BOOT/BOOTX64.EFI
Creating an EFI boot entry

Install the package sys-boot/efibootmgr.

root #emerge -av sys-boot/efibootmgr

Then, an EFI boot entry can be created with the following command, if ZFSBootMenu was built from source:

root #efibootmgr -c -d /dev/sda -p 1 -L "ZFSBootMenu" -l \\EFI\\ZBM\\VMLINUZ.EFI

Otherwise, in case the prebuilt ZFSBootMenu binary is used:

root #efibootmgr -c -d /dev/sda -p 1 -L "ZFSBootMenu" -l \\EFI\\BOOT\\BOOTX64.EFI
Optional: Native Encryption

If you've opted for native encryption when you set up your zpool as described in Alternative: Create a ZFS pool with native encryption, it is possible to set up ZFSBootMenu to prompt for the passphrase once and have dracut have access to encryption keys at boot, or alternatively by setting the org.zfsbootmenu:keysource attribute and storing encryption keys on a separate dataset.

See the ZFSBootMenu documentation for info on how to properly set this up.

Limine

Limine is a modern, advanced, portable, multiprotocol bootloader and boot manager which also provides the reference implementation of the Limine boot protocol.

Follow the Limine article and making sure to follow the Limine#Using_Limine_With_ZFS_Root section.


Grand Unified Bootloader (GRUB)
Enable ZFS support for GRUB

Set the libzfs flag on the sys-boot/grub package to enable support for ZFS (by building sys-fs/zfs and sys-fs/zfs-kmod):

root #echo "sys-boot/grub libzfs" >> /etc/portage/package.use/grub
Build GRUB with ZFS support

Ensure the GRUB_PLATFORMS setting is properly configured for systems with EFI partition

root #echo 'GRUB_PLATFORMS="efi-64"' >> /etc/portage/make.conf

Build the sys-boot/grub package:

root #emerge --ask sys-boot/grub
Install GRUB to mounted EFI partition
root #grub-install --target=x86_64-efi --efi-directory=/efi --bootloader-id=gentoo
root #grub-mkconfig -o /boot/grub/grub.cfg

Add CMDLINE for first boot only

root #nano /etc/default/grub
root #GRUB_CMDLINE_LINUX="refresh"

execute "grub-mkconfig -o /boot/grub/grub.cfg" and when booting into gentoo remove it and reconfigure grub again with the command above

Finalize setup

Add the zfs-import and zfs-mount to boot service, otherwise the system will not boot.

OpenRC
root #rc-update add zfs-import sysinit && rc-update add zfs-mount sysinit

Rebooting the system

Exit the chrooted environment and unmount all mounted partitions, do not forget to export the pool. After that, the system can be rebooted.

root #exit
root #cd
root #umount -l /mnt/gentoo/dev{/shm,/pts,}
root #umount -n -R /mnt/gentoo
root #zpool export tank
root #reboot


Gentoo doesn't boot after reboot

Press E key in the grub entry and add "refresh" to the cmdline

TODO

Sections needed to be added for a more complete guide

  • Add instructions for alternative bootloaders
  • Add instructions for ZFSBootMenu installation via generate-zbm (likely requires using GURU)