summary refs log tree commit diff
diff options
context:
space:
mode:
authorJanne Heß <janne@hess.ooo>2022-04-11 19:28:09 +0100
committerJanne Heß <janne@hess.ooo>2022-04-13 23:00:19 +0100
commit2633e82e1a1cb73e83f7d8d6c70fbe125d182005 (patch)
treeadc1da2112c1b80b133474641550145b19cec7eb
parent65cc198539f7c78f13c6003339ed2928ce0ac6f0 (diff)
downloadnixpkgs-2633e82e1a1cb73e83f7d8d6c70fbe125d182005.tar
nixpkgs-2633e82e1a1cb73e83f7d8d6c70fbe125d182005.tar.gz
nixpkgs-2633e82e1a1cb73e83f7d8d6c70fbe125d182005.tar.bz2
nixpkgs-2633e82e1a1cb73e83f7d8d6c70fbe125d182005.tar.lz
nixpkgs-2633e82e1a1cb73e83f7d8d6c70fbe125d182005.tar.xz
nixpkgs-2633e82e1a1cb73e83f7d8d6c70fbe125d182005.tar.zst
nixpkgs-2633e82e1a1cb73e83f7d8d6c70fbe125d182005.zip
nixos/stage-1-systemd: Add LVM2 support
-rw-r--r--nixos/modules/tasks/lvm.nix33
-rw-r--r--nixos/tests/lvm2/default.nix20
-rw-r--r--nixos/tests/lvm2/systemd-stage-1.nix104
3 files changed, 150 insertions, 7 deletions
diff --git a/nixos/modules/tasks/lvm.nix b/nixos/modules/tasks/lvm.nix
index 59711f90dce..4108b482cce 100644
--- a/nixos/modules/tasks/lvm.nix
+++ b/nixos/modules/tasks/lvm.nix
@@ -21,6 +21,10 @@ in {
     boot.vdo.enable = mkEnableOption "support for booting from VDOLVs";
   };
 
+  options.boot.initrd.services.lvm.enable = (mkEnableOption "enable booting from LVM2 in the initrd") // {
+    visible = false;
+  };
+
   config = mkMerge [
     ({
       # minimal configuration file to make lvmconfig/lvm2-activation-generator happy
@@ -31,8 +35,13 @@ in {
       environment.systemPackages = [ cfg.package ];
       systemd.packages = [ cfg.package ];
 
-      # TODO: update once https://github.com/NixOS/nixpkgs/pull/93006 was merged
       services.udev.packages = [ cfg.package.out ];
+
+      # We need lvm2 for the device-mapper rules
+      boot.initrd.services.udev.packages = lib.mkIf config.boot.initrd.services.lvm.enable [ cfg.package ];
+      # The device-mapper rules want to call tools from lvm2
+      boot.initrd.systemd.initrdBin = lib.mkIf config.boot.initrd.services.lvm.enable [ cfg.package ];
+      boot.initrd.services.udev.binPackages = lib.mkIf config.boot.initrd.services.lvm.enable [ cfg.package ];
     })
     (mkIf cfg.dmeventd.enable {
       systemd.sockets."dm-event".wantedBy = [ "sockets.target" ];
@@ -47,13 +56,15 @@ in {
       boot.initrd = {
         kernelModules = [ "dm-snapshot" "dm-thin-pool" ];
 
-        extraUtilsCommands = ''
+        systemd.initrdBin = lib.mkIf config.boot.initrd.services.lvm.enable [ pkgs.thin-provisioning-tools ];
+
+        extraUtilsCommands = mkIf (!config.boot.initrd.systemd.enable) ''
           for BIN in ${pkgs.thin-provisioning-tools}/bin/*; do
             copy_bin_and_libs $BIN
           done
         '';
 
-        extraUtilsCommandsTest = ''
+        extraUtilsCommandsTest = mkIf (!config.boot.initrd.systemd.enable) ''
           ls ${pkgs.thin-provisioning-tools}/bin/ | grep -v pdata_tools | while read BIN; do
             $out/bin/$(basename $BIN) --help > /dev/null
           done
@@ -71,13 +82,15 @@ in {
         initrd = {
           kernelModules = [ "kvdo" ];
 
-          extraUtilsCommands = ''
+          systemd.initrdBin = lib.mkIf config.boot.initrd.services.lvm.enable [ pkgs.vdo ];
+
+          extraUtilsCommands = mkIf (!config.boot.initrd.systemd.enable)''
             ls ${pkgs.vdo}/bin/ | grep -v adaptLVMVDO | while read BIN; do
               copy_bin_and_libs ${pkgs.vdo}/bin/$BIN
             done
           '';
 
-          extraUtilsCommandsTest = ''
+          extraUtilsCommandsTest = mkIf (!config.boot.initrd.systemd.enable)''
             ls ${pkgs.vdo}/bin/ | grep -v adaptLVMVDO | while read BIN; do
               $out/bin/$(basename $BIN) --help > /dev/null
             done
@@ -91,7 +104,15 @@ in {
       environment.systemPackages = [ pkgs.vdo ];
     })
     (mkIf (cfg.dmeventd.enable || cfg.boot.thin.enable) {
-      boot.initrd.preLVMCommands = ''
+      boot.initrd.systemd.contents."/etc/lvm/lvm.conf".text = optionalString (config.boot.initrd.services.lvm.enable && cfg.boot.thin.enable) (concatMapStringsSep "\n"
+          (bin: "global/${bin}_executable = /bin/${bin}")
+          [ "thin_check" "thin_dump" "thin_repair" "cache_check" "cache_dump" "cache_repair" ]
+        ) + "\n" + optionalString cfg.dmeventd.enable ''
+          dmeventd/executable = /bin/false
+          activation/monitoring = 0
+        '';
+
+      boot.initrd.preLVMCommands = mkIf (!config.boot.initrd.systemd.enable) ''
           mkdir -p /etc/lvm
           cat << EOF >> /etc/lvm/lvm.conf
           ${optionalString cfg.boot.thin.enable (
diff --git a/nixos/tests/lvm2/default.nix b/nixos/tests/lvm2/default.nix
index 2ba17809569..1eb9f572a4d 100644
--- a/nixos/tests/lvm2/default.nix
+++ b/nixos/tests/lvm2/default.nix
@@ -11,6 +11,24 @@ let
     thinpool = { test = callTest ./thinpool.nix; kernelFilter = lib.id; };
     # we would like to test all versions, but the kernel module currently does not compile against the other versions
     vdo = { test = callTest ./vdo.nix; kernelFilter = lib.filter (v: v == "5.15"); };
+
+
+    # systemd in stage 1
+    raid-sd-stage-1 = {
+      test = callTest ./systemd-stage-1.nix;
+      kernelFilter = lib.id;
+      flavour = "raid";
+    };
+    thinpool-sd-stage-1 = {
+      test = callTest ./systemd-stage-1.nix;
+      kernelFilter = lib.id;
+      flavour = "thinpool";
+    };
+    vdo-sd-stage-1 = {
+      test = callTest ./systemd-stage-1.nix;
+      kernelFilter = lib.filter (v: v == "5.15");
+      flavour = "vdo";
+    };
   };
 in
 lib.listToAttrs (
@@ -20,7 +38,7 @@ lib.listToAttrs (
         v' = lib.replaceStrings [ "." ] [ "_" ] version;
       in
       lib.flip lib.mapAttrsToList tests (name: t:
-        lib.nameValuePair "lvm-${name}-linux-${v'}" (lib.optionalAttrs (builtins.elem version (t.kernelFilter kernelVersionsToTest)) (t.test { kernelPackages = pkgs."linuxPackages_${v'}"; }))
+        lib.nameValuePair "lvm-${name}-linux-${v'}" (lib.optionalAttrs (builtins.elem version (t.kernelFilter kernelVersionsToTest)) (t.test ({ kernelPackages = pkgs."linuxPackages_${v'}"; } // builtins.removeAttrs t [ "test" "kernelFilter" ])))
       )
     )
   )
diff --git a/nixos/tests/lvm2/systemd-stage-1.nix b/nixos/tests/lvm2/systemd-stage-1.nix
new file mode 100644
index 00000000000..617ba77b179
--- /dev/null
+++ b/nixos/tests/lvm2/systemd-stage-1.nix
@@ -0,0 +1,104 @@
+{ kernelPackages ? null, flavour }: let
+  preparationCode = {
+    raid = ''
+      machine.succeed("vgcreate test_vg /dev/vdc /dev/vdd")
+      machine.succeed("lvcreate -L 512M --type raid0 test_vg -n test_lv")
+    '';
+
+    thinpool = ''
+      machine.succeed("vgcreate test_vg /dev/vdc")
+      machine.succeed("lvcreate -L 512M -T test_vg/test_thin_pool")
+      machine.succeed("lvcreate -n test_lv -V 16G --thinpool test_thin_pool test_vg")
+    '';
+
+    vdo = ''
+      machine.succeed("vgcreate test_vg /dev/vdc")
+      machine.succeed("lvcreate --type vdo -n test_lv -L 6G -V 12G test_vg/vdo_pool_lv")
+    '';
+  }.${flavour};
+
+  extraConfig = {
+    raid = {
+      boot.initrd.kernelModules = [
+        "dm-raid"
+        "raid0"
+      ];
+    };
+
+    thinpool = {
+      services.lvm = {
+        boot.thin.enable = true;
+        dmeventd.enable = true;
+      };
+    };
+
+    vdo = {
+      services.lvm = {
+        boot.vdo.enable = true;
+        dmeventd.enable = true;
+      };
+    };
+  }.${flavour};
+
+  extraCheck = {
+    raid = ''
+      "test_lv" in machine.succeed("lvs --select segtype=raid0")
+    '';
+
+    thinpool = ''
+      "test_lv" in machine.succeed("lvs --select segtype=thin-pool")
+    '';
+
+    vdo = ''
+      "test_lv" in machine.succeed("lvs --select segtype=vdo")
+    '';
+  }.${flavour};
+
+in import ../make-test-python.nix ({ pkgs, ... }: {
+  name = "lvm2-${flavour}-systemd-stage-1";
+  meta.maintainers = with pkgs.lib.maintainers; [ das_j ];
+
+  nodes.machine = { pkgs, lib, ... }: {
+    imports = [ extraConfig ];
+    # Use systemd-boot
+    virtualisation = {
+      emptyDiskImages = [ 8192 8192 ];
+      useBootLoader = true;
+      useEFIBoot = true;
+    };
+    boot.loader.systemd-boot.enable = true;
+    boot.loader.efi.canTouchEfiVariables = true;
+
+    environment.systemPackages = with pkgs; [ e2fsprogs ]; # for mkfs.ext4
+    boot = {
+      initrd.systemd = {
+        enable = true;
+        emergencyAccess = true;
+      };
+      initrd.services.lvm.enable = true;
+      kernelPackages = lib.mkIf (kernelPackages != null) kernelPackages;
+    };
+
+    specialisation.boot-lvm.configuration.virtualisation.bootDevice = "/dev/test_vg/test_lv";
+  };
+
+  testScript = ''
+    machine.wait_for_unit("multi-user.target")
+    # Create a VG for the root
+    ${preparationCode}
+    machine.succeed("mkfs.ext4 /dev/test_vg/test_lv")
+    machine.succeed("mkdir -p /mnt && mount /dev/test_vg/test_lv /mnt && echo hello > /mnt/test && umount /mnt")
+
+    # Boot from LVM
+    machine.succeed("bootctl set-default nixos-generation-1-specialisation-boot-lvm.conf")
+    machine.succeed("sync")
+    machine.crash()
+    machine.wait_for_unit("multi-user.target")
+
+    # Ensure we have successfully booted from LVM
+    assert "(initrd)" in machine.succeed("systemd-analyze")  # booted with systemd in stage 1
+    assert "/dev/mapper/test_vg-test_lv on / type ext4" in machine.succeed("mount")
+    assert "hello" in machine.succeed("cat /test")
+    ${extraCheck}
+  '';
+})