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