nixos/filesystems: init erofs

Enable using an erofs filesystem as one of the filesystems needed to
boot the system. This is useful for example in image based deployments
where the Nix store is mounted read only.
[erofs](https://docs.kernel.org/filesystems/erofs.html) offers multiple
benefits over older filesystems like squashfs. Skip fsck.erofs because
it is still experimental.
This commit is contained in:
nikstur
2023-05-11 14:35:00 +02:00
parent b15daed965
commit fa09e0a3c7
4 changed files with 120 additions and 44 deletions

View File

@@ -1370,6 +1370,7 @@
./tasks/filesystems/cifs.nix ./tasks/filesystems/cifs.nix
./tasks/filesystems/ecryptfs.nix ./tasks/filesystems/ecryptfs.nix
./tasks/filesystems/envfs.nix ./tasks/filesystems/envfs.nix
./tasks/filesystems/erofs.nix
./tasks/filesystems/exfat.nix ./tasks/filesystems/exfat.nix
./tasks/filesystems/ext.nix ./tasks/filesystems/ext.nix
./tasks/filesystems/f2fs.nix ./tasks/filesystems/f2fs.nix

View File

@@ -293,6 +293,9 @@ checkFS() {
# Skip fsck for inherently readonly filesystems. # Skip fsck for inherently readonly filesystems.
if [ "$fsType" = squashfs ]; then return 0; fi if [ "$fsType" = squashfs ]; then return 0; fi
# Skip fsck.erofs because it is still experimental.
if [ "$fsType" = erofs ]; then return 0; fi
# If we couldn't figure out the FS type, then skip fsck. # If we couldn't figure out the FS type, then skip fsck.
if [ "$fsType" = auto ]; then if [ "$fsType" = auto ]; then
echo 'cannot check filesystem with type "auto"!' echo 'cannot check filesystem with type "auto"!'

View File

@@ -0,0 +1,21 @@
{ config, lib, pkgs, ... }:
let
inInitrd = lib.any (fs: fs == "erofs") config.boot.initrd.supportedFilesystems;
inSystem = lib.any (fs: fs == "erofs") config.boot.supportedFilesystems;
in
{
config = lib.mkIf (inInitrd || inSystem) {
system.fsPackages = [ pkgs.erofs-utils ];
boot.initrd.availableKernelModules = lib.mkIf inInitrd [ "erofs" ];
# fsck.erofs is currently experimental and should not be run as a
# privileged user. Thus, it is not included in the initrd.
};
}

View File

@@ -1,55 +1,106 @@
import ./make-test-python.nix ({ lib, pkgs, ... }: { system ? builtins.currentSystem
, config ? { }
, pkgs ? import ../.. { inherit system config; }
}:
with import ../lib/testing-python.nix { inherit system pkgs; };
with pkgs.lib;
{ {
name = "non-default-filesystems"; btrfs = makeTest
nodes.machine =
{ config, pkgs, lib, ... }:
let
disk = config.virtualisation.rootDevice;
in
{ {
virtualisation.rootDevice = "/dev/vda"; name = "non-default-filesystems-btrfs";
virtualisation.useDefaultFilesystems = false;
boot.initrd.availableKernelModules = [ "btrfs" ]; nodes.machine =
boot.supportedFilesystems = [ "btrfs" ]; { config, pkgs, lib, ... }:
let
disk = config.virtualisation.rootDevice;
in
{
virtualisation.rootDevice = "/dev/vda";
virtualisation.useDefaultFilesystems = false;
boot.initrd.postDeviceCommands = '' boot.initrd.availableKernelModules = [ "btrfs" ];
FSTYPE=$(blkid -o value -s TYPE ${disk} || true) boot.supportedFilesystems = [ "btrfs" ];
if test -z "$FSTYPE"; then
modprobe btrfs
${pkgs.btrfs-progs}/bin/mkfs.btrfs ${disk}
mkdir /nixos boot.initrd.postDeviceCommands = ''
mount -t btrfs ${disk} /nixos FSTYPE=$(blkid -o value -s TYPE ${disk} || true)
if test -z "$FSTYPE"; then
modprobe btrfs
${pkgs.btrfs-progs}/bin/mkfs.btrfs ${disk}
${pkgs.btrfs-progs}/bin/btrfs subvolume create /nixos/root mkdir /nixos
${pkgs.btrfs-progs}/bin/btrfs subvolume create /nixos/home mount -t btrfs ${disk} /nixos
umount /nixos ${pkgs.btrfs-progs}/bin/btrfs subvolume create /nixos/root
fi ${pkgs.btrfs-progs}/bin/btrfs subvolume create /nixos/home
umount /nixos
fi
'';
virtualisation.fileSystems = {
"/" = {
device = disk;
fsType = "btrfs";
options = [ "subvol=/root" ];
};
"/home" = {
device = disk;
fsType = "btrfs";
options = [ "subvol=/home" ];
};
};
};
testScript = ''
machine.wait_for_unit("multi-user.target")
with subtest("BTRFS filesystems are mounted correctly"):
machine.succeed("grep -E '/dev/vda / btrfs rw,relatime,space_cache=v2,subvolid=[0-9]+,subvol=/root 0 0' /proc/mounts")
machine.succeed("grep -E '/dev/vda /home btrfs rw,relatime,space_cache=v2,subvolid=[0-9]+,subvol=/home 0 0' /proc/mounts")
''; '';
virtualisation.fileSystems = {
"/" = {
device = disk;
fsType = "btrfs";
options = [ "subvol=/root" ];
};
"/home" = {
device = disk;
fsType = "btrfs";
options = [ "subvol=/home" ];
};
};
}; };
testScript = '' erofs =
machine.wait_for_unit("multi-user.target") let
fsImage = "/tmp/non-default-filesystem.img";
in
makeTest {
name = "non-default-filesystems-erofs";
with subtest("BTRFS filesystems are mounted correctly"): nodes.machine = _: {
machine.succeed("grep -E '/dev/vda / btrfs rw,relatime,space_cache=v2,subvolid=[0-9]+,subvol=/root 0 0' /proc/mounts") virtualisation.qemu.drives = [{
machine.succeed("grep -E '/dev/vda /home btrfs rw,relatime,space_cache=v2,subvolid=[0-9]+,subvol=/home 0 0' /proc/mounts") name = "non-default-filesystem";
''; file = fsImage;
}) }];
virtualisation.fileSystems."/non-default" = {
device = "/dev/vdb";
fsType = "erofs";
neededForBoot = true;
};
};
testScript = ''
import subprocess
import tempfile
with tempfile.TemporaryDirectory() as tmp_dir:
with open(f"{tmp_dir}/filesystem", "w") as f:
f.write("erofs")
subprocess.run([
"${pkgs.erofs-utils}/bin/mkfs.erofs",
"${fsImage}",
tmp_dir,
])
machine.start()
machine.wait_for_unit("default.target")
file_contents = machine.succeed("cat /non-default/filesystem")
assert "erofs" in file_contents
'';
};
}