1{ config, lib, pkgs, ... }:
2
3with lib;
4let
5 cfg = config.services.lvm;
6in {
7 options.services.lvm = {
8 package = mkOption {
9 type = types.package;
10 default = pkgs.lvm2;
11 internal = true;
12 defaultText = literalExpression "pkgs.lvm2";
13 description = lib.mdDoc ''
14 This option allows you to override the LVM package that's used on the system
15 (udev rules, tmpfiles, systemd services).
16 Defaults to pkgs.lvm2, pkgs.lvm2_dmeventd if dmeventd or pkgs.lvm2_vdo if vdo is enabled.
17 '';
18 };
19 dmeventd.enable = mkEnableOption (lib.mdDoc "the LVM dmevent daemon");
20 boot.thin.enable = mkEnableOption (lib.mdDoc "support for booting from ThinLVs");
21 boot.vdo.enable = mkEnableOption (lib.mdDoc "support for booting from VDOLVs");
22 };
23
24 options.boot.initrd.services.lvm.enable = (mkEnableOption (lib.mdDoc "enable booting from LVM2 in the initrd")) // {
25 visible = false;
26 };
27
28 config = mkMerge [
29 ({
30 # minimal configuration file to make lvmconfig/lvm2-activation-generator happy
31 environment.etc."lvm/lvm.conf".text = "config {}";
32 })
33 (mkIf (!config.boot.isContainer) {
34 systemd.tmpfiles.packages = [ cfg.package.out ];
35 environment.systemPackages = [ cfg.package ];
36 systemd.packages = [ cfg.package ];
37
38 services.udev.packages = [ cfg.package.out ];
39
40 # We need lvm2 for the device-mapper rules
41 boot.initrd.services.udev.packages = lib.mkIf config.boot.initrd.services.lvm.enable [ cfg.package ];
42 # The device-mapper rules want to call tools from lvm2
43 boot.initrd.systemd.initrdBin = lib.mkIf config.boot.initrd.services.lvm.enable [ cfg.package ];
44 boot.initrd.services.udev.binPackages = lib.mkIf config.boot.initrd.services.lvm.enable [ cfg.package ];
45 })
46 (mkIf cfg.dmeventd.enable {
47 systemd.sockets."dm-event".wantedBy = [ "sockets.target" ];
48 systemd.services."lvm2-monitor".wantedBy = [ "sysinit.target" ];
49
50 environment.etc."lvm/lvm.conf".text = ''
51 dmeventd/executable = "${cfg.package}/bin/dmeventd"
52 '';
53 services.lvm.package = mkDefault pkgs.lvm2_dmeventd;
54 })
55 (mkIf cfg.boot.thin.enable {
56 boot.initrd = {
57 kernelModules = [ "dm-snapshot" "dm-thin-pool" ];
58
59 systemd.initrdBin = lib.mkIf config.boot.initrd.services.lvm.enable [ pkgs.thin-provisioning-tools ];
60
61 extraUtilsCommands = mkIf (!config.boot.initrd.systemd.enable) ''
62 for BIN in ${pkgs.thin-provisioning-tools}/bin/*; do
63 copy_bin_and_libs $BIN
64 done
65 '';
66
67 extraUtilsCommandsTest = mkIf (!config.boot.initrd.systemd.enable) ''
68 ls ${pkgs.thin-provisioning-tools}/bin/ | grep -v pdata_tools | while read BIN; do
69 $out/bin/$(basename $BIN) --help > /dev/null
70 done
71 '';
72 };
73
74 environment.etc."lvm/lvm.conf".text = concatMapStringsSep "\n"
75 (bin: "global/${bin}_executable = ${pkgs.thin-provisioning-tools}/bin/${bin}")
76 [ "thin_check" "thin_dump" "thin_repair" "cache_check" "cache_dump" "cache_repair" ];
77
78 environment.systemPackages = [ pkgs.thin-provisioning-tools ];
79 })
80 (mkIf cfg.boot.vdo.enable {
81 boot = {
82 initrd = {
83 kernelModules = [ "kvdo" ];
84
85 systemd.initrdBin = lib.mkIf config.boot.initrd.services.lvm.enable [ pkgs.vdo ];
86
87 extraUtilsCommands = mkIf (!config.boot.initrd.systemd.enable)''
88 ls ${pkgs.vdo}/bin/ | while read BIN; do
89 copy_bin_and_libs ${pkgs.vdo}/bin/$BIN
90 done
91 substituteInPlace $out/bin/vdorecover --replace "${pkgs.bash}/bin/bash" "/bin/sh"
92 substituteInPlace $out/bin/adaptLVMVDO.sh --replace "${pkgs.bash}/bin/bash" "/bin/sh"
93 '';
94
95 extraUtilsCommandsTest = mkIf (!config.boot.initrd.systemd.enable)''
96 ls ${pkgs.vdo}/bin/ | grep -vE '(adaptLVMVDO|vdorecover)' | while read BIN; do
97 $out/bin/$(basename $BIN) --help > /dev/null
98 done
99 '';
100 };
101 extraModulePackages = [ config.boot.kernelPackages.kvdo ];
102 };
103
104 services.lvm.package = mkOverride 999 pkgs.lvm2_vdo; # this overrides mkDefault
105
106 environment.systemPackages = [ pkgs.vdo ];
107 })
108 (mkIf (cfg.dmeventd.enable || cfg.boot.thin.enable) {
109 boot.initrd.systemd.contents."/etc/lvm/lvm.conf".text = optionalString (config.boot.initrd.services.lvm.enable && cfg.boot.thin.enable) (concatMapStringsSep "\n"
110 (bin: "global/${bin}_executable = /bin/${bin}")
111 [ "thin_check" "thin_dump" "thin_repair" "cache_check" "cache_dump" "cache_repair" ]
112 ) + "\n" + optionalString cfg.dmeventd.enable ''
113 dmeventd/executable = /bin/false
114 activation/monitoring = 0
115 '';
116
117 boot.initrd.preLVMCommands = mkIf (!config.boot.initrd.systemd.enable) ''
118 mkdir -p /etc/lvm
119 cat << EOF >> /etc/lvm/lvm.conf
120 ${optionalString cfg.boot.thin.enable (
121 concatMapStringsSep "\n"
122 (bin: "global/${bin}_executable = $(command -v ${bin})")
123 [ "thin_check" "thin_dump" "thin_repair" "cache_check" "cache_dump" "cache_repair" ]
124 )
125 }
126 ${optionalString cfg.dmeventd.enable ''
127 dmeventd/executable = "$(command -v false)"
128 activation/monitoring = 0
129 ''}
130 EOF
131 '';
132 })
133 ];
134
135}