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