Linux - ZFS as root Filesystem

This documentation contains instructions to use ZFS as the root filesystem under Linux-based operating systems. It is assumed that the respective ZFS kernel module and userspace tools are installed on the target operating system.

ZFS is arguably the most-resilient filesystem to ever exist, and contains many features to protect data and ease administration. A non-exhaustive list of ZFS features is as follows:

Within this documentation, # is used to denote running the command as the root user, and $ is used to denote running the command as an unprivileged user. The lowest-privileged user able to run the commands will be used for each command. Some shells may present different characters for privileged and unprivileged users than used in this documentation; the shell's documentation should be consulted if this is true for the system being used.

WARNING

As with any other filesystem, ZFS cannot guarantee that data is not corrupted before writing, or after reading, on a system without ECC-memory (error-correcting code) support; therefore, using a system with ECC-memory support is essential for any reliability guarantees. Any system without ECC-memory support is using broken memory, and both data corruption and undefined behaviour should be expected, regardless of use-case.

0. Create ZFS zpool

A ZFS zpool is a collection of 1 or more disks in a virtual device container. zpools control disk management for all disks contained within the their respective zpools.

To create a ZFS zpool containing a single disk, the following command can be run:

# zpool create <zpool name> <disk>

To create a ZFS zpool containing a multiple disks in a mirror configuration (RAID-1-like), the following command can be run:

# zpool create <zpool name> mirror <disk 0> <disk n>

More than 2 disks can be added to a multi-disk configuration.

For other types of multi-disk configurations, the OpenZFS official documentation should be consulted.

CAUTION

It is recommended that the World Wide Name (WWN) be used (found in /dev/disk/by-id/) for persistent disk naming, as the WWN is persistent even across different systems, storage types, and buses. Disk-discovery and mounting issues can occur if non-persistent naming is used.

CAUTION

Modern non-enterprise-grade disk-drives lie to the operating system regarding their sector-sizes, stating 512 B sector-sizes rather than their true 4 KiB sector-sizes. To force ZFS to create a 4 KiB-aligned zpool, add -o ashift=12 to the zpool-creation command, before specifying the zpool name. For other disk-drives and use-cases, set ashift to the correct value, where ashift is the sector-size as a power-of-two.

ashift cannot be modified without destroying and recreating the zpool.

1. Create ZFS Datasets

ZFS datasets are self-contained filesystems within a ZFS zpool. They can either inherit their properties from parent datasets, or have independent properties. Properties include record-sizes and compression algorithms. It is recommended that each set of files be namespaced into their own datasets, which allows for independent snapshotting, rollback, and other features, without affecting other datasets. Datasets must be descendents of a zpool, written in a path-like format.

To create a ZFS dataset, the following command can be run:

# zfs create <dataset name>

Without explicitly specifying a mountpoint, new datasets will automatically become a descendent of their parent dataset. This can be changed via explicitly specifying the mountpoint by adding -o mountpoint=<mountpoint> to the command, before the dataset name.

When creating a dataset for the root filesystem, the mountpoint must be set to not automatically mount. This can be achieved via the following command:

# zfs create -o mountpoint=/ -o canmount=noauto <dataset name>

For other available properties of ZFS datasets, the OpenZFS official documentation should be consulted.

WARNING

Failing to set canmount=noauto when creating the root-filesystem dataset will result in the operating system attempting to mount the new dataset over the currently-active root filesystem.

WARNING

If system directories, such as /usr/ and /var/, are to have their own datasets, they should be a descendent of the root-filesystem dataset in order to mount correctly. Failing to do so will likely result in an unbootable system as critical binaries such as init will not be found.

2. Set ZFS bootfs

The root-filesystem dataset must be set as the bootfs. This can be achieved via the following command:

# zpool set bootfs=<dataset> <zpool>

3. Set init Service

ZFS must be set to import the root-filesystem zpool on boot. This can be acheived on OpenRC-based systems via the following command:

# rc-update add <ZFS-import service> boot

On Gentoo Linux, this service is named zfs-import.

ZFS must be set to mount the root filesystem after importing the zpool. This can be acheived on OpenRC-based systems via the following command:

# rc-update add <ZFS-mount service> boot

On Gentoo Linux, this service is named zfs-mount.

4. Create initramfs

As ZFS is not a part of the kernel, it must be externally loaded as a module, and must be available before the root filesystem has been mounted.

To add ZFS support to dracut, the following must be added to either /etc/dracut.conf, or a file within /etc/dracut.conf.d/ with .conf as the filename extension:

nofsck="yes"
add_dracutmodules+=" zfs "

An initramfs must be created after adding the required module(s). To achieve this via dracut, the following command can be run:

# dracut --kver <kernel>

Sitemap