nixos/iosched: exclude loop devices by default

This commit is contained in:
Mikael Voss 2025-02-25 23:02:50 +01:00
parent b5dfb3feed
commit 54bd09a515
No known key found for this signature in database
2 changed files with 73 additions and 31 deletions

View file

@ -6,24 +6,53 @@
}: }:
let let
inherit (lib)
concatLines
concatStringsSep
mapAttrsToList
optional
optionals
mkIf
mkOption
types
;
cfg = config.hardware.block; cfg = config.hardware.block;
escape = lib.strings.escape [ ''"'' ]; escape = lib.strings.escape [ ''"'' ];
udevValue = types.addCheck types.nonEmptyStr (x: builtins.match "[^\n\r]*" x != null) // { udevValue = types.addCheck types.nonEmptyStr (x: builtins.match "[^\n\r]*" x != null) // {
name = "udevValue"; name = "udevValue";
description = "udev rule value"; description = "udev rule value";
descriptionClass = "noun"; descriptionClass = "noun";
}; };
inherit (lib) udevRule =
mkIf {
mkOption rotational ? null,
types include ? null,
exclude ? null,
concatLines scheduler,
concatStringsSep }:
mapAttrsToList concatStringsSep ", " (
optional [
; ''SUBSYSTEM=="block"''
''ACTION=="add|change"''
''TEST=="queue/scheduler"''
]
++ optionals (rotational != null) [
''ATTR{queue/rotational}=="${if rotational then "1" else "0"}"''
]
++ optionals (include != null) [
''KERNEL=="${escape include}"''
]
++ optionals (exclude != null) [
''KERNEL!="${escape exclude}"''
]
++ [
''ATTR{queue/scheduler}="${escape scheduler}"''
]
);
in in
{ {
options.hardware.block = { options.hardware.block = {
@ -54,6 +83,22 @@ in
example = "bfq"; example = "bfq";
}; };
defaultSchedulerExclude = mkOption {
type = types.nullOr udevValue;
default = "loop[0-9]*";
description = ''
Device name pattern to exclude from default scheduler assignment
through {option}`config.hardware.block.defaultScheduler` and
{option}`config.hardware.block.defaultSchedulerRotational`.
By default this excludes loop devices which generally do not benefit
from extra I/O scheduling in addition to the scheduling already
performed for their backing devices.
This setting does not affect {option}`config.hardware.block.scheduler`.
'';
};
scheduler = mkOption { scheduler = mkOption {
type = types.attrsOf udevValue; type = types.attrsOf udevValue;
default = { }; default = { };
@ -120,27 +165,21 @@ in
services.udev.packages = [ services.udev.packages = [
(pkgs.writeTextDir "etc/udev/rules.d/98-block-io-scheduler.rules" ( (pkgs.writeTextDir "etc/udev/rules.d/98-block-io-scheduler.rules" (
concatLines ( concatLines (
map (concatStringsSep ", ") ( optional (cfg.defaultScheduler != null) (udevRule {
optional (cfg.defaultScheduler != null) [ exclude = cfg.defaultSchedulerExclude;
''SUBSYSTEM=="block"'' scheduler = cfg.defaultScheduler;
''ACTION=="add|change"'' })
''TEST=="queue/scheduler"'' ++ optional (cfg.defaultSchedulerRotational != null) (udevRule {
''ATTR{queue/scheduler}="${escape cfg.defaultScheduler}"'' rotational = true;
] exclude = cfg.defaultSchedulerExclude;
++ optional (cfg.defaultSchedulerRotational != null) [ scheduler = cfg.defaultSchedulerRotational;
''SUBSYSTEM=="block"'' })
''ACTION=="add|change"'' ++ mapAttrsToList (
''ATTR{queue/rotational}=="1"'' include: scheduler:
''TEST=="queue/scheduler"'' udevRule {
''ATTR{queue/scheduler}="${escape cfg.defaultSchedulerRotational}"'' inherit include scheduler;
] }
++ mapAttrsToList (name: sched: [ ) cfg.scheduler
''SUBSYSTEM=="block"''
''ACTION=="add|change"''
''KERNEL=="${escape name}"''
''ATTR{queue/scheduler}="${escape sched}"''
]) cfg.scheduler
)
) )
)) ))
]; ];

View file

@ -63,6 +63,9 @@ import ./make-test-python.nix (
check_scheduler("sdb", "mq-deadline") check_scheduler("sdb", "mq-deadline")
check_scheduler("nvme0n1", "kyber") check_scheduler("nvme0n1", "kyber")
check_scheduler("mmcblk0", "bfq") check_scheduler("mmcblk0", "bfq")
machine.succeed("tmp=\"$(mktemp)\"; losetup /dev/loop0 \"$tmp\"")
check_scheduler("loop0", "none")
''; '';
} }
) )