diff --git a/lib/types.nix b/lib/types.nix index ee1410127b1ae6..6c689b944be4d9 100644 --- a/lib/types.nix +++ b/lib/types.nix @@ -1180,6 +1180,13 @@ rec { nestedTypes.finalType = finalType; }; + # A list of attrnames is coerced into an attrset of bools by + # setting the values to true. + attrNamesToTrue = coercedTo + (types.listOf types.str) + (enabledList: lib.genAttrs enabledList (_attrName: true)) + (types.attrsOf types.bool); + # Augment the given type with an additional type check function. addCheck = elemType: check: elemType // { check = x: elemType.check x && check x; }; diff --git a/nixos/doc/manual/development/option-types.section.md b/nixos/doc/manual/development/option-types.section.md index f39472e2ba61c0..882c3ce7575e0b 100644 --- a/nixos/doc/manual/development/option-types.section.md +++ b/nixos/doc/manual/development/option-types.section.md @@ -135,6 +135,29 @@ merging is handled. problems. ::: +`types.attrNamesToTrue` + +: Either a list of attribute names, or an attribute set of + booleans. A list will be coerced into an attribute set with those + names, whose values are set to `true`. This is useful when it is + convenient to be able to write definitions as a simple list, but + still need to be able to override and disable individual values. + + ::: {#ex-types-attrNamesToTrue .example} + ### `types.attrNamesToTrue` + ``` + { + foo = [ "bar" ]; + } + ``` + + ``` + { + foo.bar = true; + } + ``` + ::: + `types.pkgs` : A type for the top level Nixpkgs package set. diff --git a/nixos/modules/system/boot/kernel.nix b/nixos/modules/system/boot/kernel.nix index d25a6e98497e77..2a7e5a7d764712 100644 --- a/nixos/modules/system/boot/kernel.nix +++ b/nixos/modules/system/boot/kernel.nix @@ -8,6 +8,14 @@ let inherit (config.boot.kernel) features randstructSeed; inherit (config.boot.kernelPackages) kernel; + modulesTypeDesc = '' + This can either be a list of modules, or an attrset. In an + attrset, names that are set to `true` represent modules that will + be included. Note that setting these names to `false` does not + prevent the module from being loaded. For that, use + {option}`boot.blacklistedKernelModules`. + ''; + kernelModulesConf = pkgs.writeText "nixos.conf" '' ${concatStringsSep "\n" config.boot.kernelModules} @@ -175,20 +183,23 @@ in }; boot.kernelModules = mkOption { - type = types.listOf types.str; - default = []; + type = types.attrNamesToTrue; + default = { }; description = '' The set of kernel modules to be loaded in the second stage of the boot process. Note that modules that are needed to mount the root file system should be added to {option}`boot.initrd.availableKernelModules` or {option}`boot.initrd.kernelModules`. + + ${modulesTypeDesc} ''; + apply = mods: lib.attrNames (lib.filterAttrs (_: v: v) mods); }; boot.initrd.availableKernelModules = mkOption { - type = types.listOf types.str; - default = []; + type = types.attrNamesToTrue; + default = { }; example = [ "sata_nv" "ext3" ]; description = '' The set of kernel modules in the initial ramdisk used during the @@ -204,13 +215,21 @@ in modules for PCI devices are loaded when they match the PCI ID of a device in your system). To force a module to be loaded, include it in {option}`boot.initrd.kernelModules`. + + ${modulesTypeDesc} ''; + apply = mods: lib.attrNames (lib.filterAttrs (_: v: v) mods); }; boot.initrd.kernelModules = mkOption { - type = types.listOf types.str; - default = []; - description = "List of modules that are always loaded by the initrd."; + type = types.attrNamesToTrue; + default = { }; + description = '' + Set of modules that are always loaded by the initrd. + + ${modulesTypeDesc} + ''; + apply = mods: lib.attrNames (lib.filterAttrs (_: v: v) mods); }; boot.initrd.includeDefaultModules = mkOption { @@ -223,6 +242,24 @@ in ''; }; + boot.initrd.allowMissingModules = mkOption { + type = types.bool; + default = false; + description = '' + Whether the initrd can be built even though modules listed in + {option}`boot.initrd.kernelModules` or + {option}`boot.initrd.availableKernelModules` are missing from + the kernel. This is useful when combining configurations that + include a lot of modules, such as + {option}`hardware.enableAllHardware`, with kernels that don't + provide as many modules as typical NixOS kernels. + + Note that enabling this is discouraged. Instead, try disabling + individual modules by setting e.g. + `boot.initrd.availableKernelModules.foo = lib.mkForce false;` + ''; + }; + system.modulesTree = mkOption { type = types.listOf types.path; internal = true; diff --git a/nixos/modules/system/boot/modprobe.nix b/nixos/modules/system/boot/modprobe.nix index df0d5d6679884a..b38e78c3222aab 100644 --- a/nixos/modules/system/boot/modprobe.nix +++ b/nixos/modules/system/boot/modprobe.nix @@ -25,16 +25,19 @@ with lib; }; boot.blacklistedKernelModules = mkOption { - type = types.listOf types.str; - default = [ ]; + type = types.attrNamesToTrue; + default = { }; example = [ "cirrusfb" "i2c_piix4" ]; description = '' - List of names of kernel modules that should not be loaded - automatically by the hardware probing code. + Set of names of kernel modules that should not be loaded + automatically by the hardware probing code. This can either be + a list of modules or an attrset. In an attrset, names that are + set to `true` represent modules that will be blacklisted. ''; + apply = mods: lib.attrNames (lib.filterAttrs (_: v: v) mods); }; boot.extraModprobeConfig = mkOption { diff --git a/nixos/modules/system/boot/stage-1.nix b/nixos/modules/system/boot/stage-1.nix index 1aab9548a59514..e505be94ae5204 100644 --- a/nixos/modules/system/boot/stage-1.nix +++ b/nixos/modules/system/boot/stage-1.nix @@ -18,7 +18,7 @@ let rootModules = config.boot.initrd.availableKernelModules ++ config.boot.initrd.kernelModules; kernel = config.system.modulesTree; firmware = config.hardware.firmware; - allowMissing = false; + allowMissing = config.boot.initrd.allowMissingModules; inherit (config.boot.initrd) extraFirmwarePaths; }; @@ -716,7 +716,7 @@ in ]; system.build = mkMerge [ - { inherit bootStage1 initialRamdiskSecretAppender extraUtils; } + { inherit bootStage1 initialRamdiskSecretAppender extraUtils modulesClosure; } # generated in nixos/modules/system/boot/systemd/initrd.nix (mkIf (!config.boot.initrd.systemd.enable) { inherit initialRamdisk; }) diff --git a/nixos/modules/system/boot/systemd/initrd.nix b/nixos/modules/system/boot/systemd/initrd.nix index 23b9e232c64df8..0a516cac9fff82 100644 --- a/nixos/modules/system/boot/systemd/initrd.nix +++ b/nixos/modules/system/boot/systemd/initrd.nix @@ -99,14 +99,6 @@ let }; kernel-name = config.boot.kernelPackages.kernel.name or "kernel"; - # Determine the set of modules that we need to mount the root FS. - modulesClosure = pkgs.makeModulesClosure { - rootModules = config.boot.initrd.availableKernelModules ++ config.boot.initrd.kernelModules; - kernel = config.system.modulesTree; - firmware = config.hardware.firmware; - allowMissing = false; - inherit (config.boot.initrd) extraFirmwarePaths; - }; initrdBinEnv = pkgs.buildEnv { name = "initrd-bin-env"; @@ -477,7 +469,7 @@ in } ''; - "/lib".source = "${modulesClosure}/lib"; + "/lib".source = "${config.system.build.modulesClosure}/lib"; "/etc/modules-load.d/nixos.conf".text = concatStringsSep "\n" config.boot.initrd.kernelModules; diff --git a/nixos/modules/tasks/filesystems.nix b/nixos/modules/tasks/filesystems.nix index 9afb2e45334f09..53cdbb63041a68 100644 --- a/nixos/modules/tasks/filesystems.nix +++ b/nixos/modules/tasks/filesystems.nix @@ -273,10 +273,7 @@ in zfs = lib.mkForce false; } ''; - type = types.coercedTo - (types.listOf types.str) - (enabled: lib.listToAttrs (map (fs: lib.nameValuePair fs true) enabled)) - (types.attrsOf types.bool); + type = types.attrNamesToTrue; description = '' Names of supported filesystem types, or an attribute set of file system types and their state. The set form may be used together with `lib.mkForce` to