nixpkgs/nixos/modules/hardware/iosched.nix

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

190 lines
5.5 KiB
Nix
Raw Permalink Normal View History

2024-06-09 20:09:25 +02:00
{
config,
lib,
pkgs,
...
}:
let
inherit (lib)
concatLines
concatStringsSep
mapAttrsToList
optional
optionals
mkIf
mkOption
types
;
2024-06-09 20:09:25 +02:00
cfg = config.hardware.block;
escape = lib.strings.escape [ ''"'' ];
2024-06-09 20:09:25 +02:00
udevValue = types.addCheck types.nonEmptyStr (x: builtins.match "[^\n\r]*" x != null) // {
name = "udevValue";
description = "udev rule value";
descriptionClass = "noun";
};
udevRule =
{
rotational ? null,
include ? null,
exclude ? null,
scheduler,
}:
concatStringsSep ", " (
[
''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}"''
]
);
2024-06-09 20:09:25 +02:00
in
{
options.hardware.block = {
defaultScheduler = mkOption {
type = types.nullOr udevValue;
default = null;
description = ''
Default block I/O scheduler.
Unless `null`, the value is assigned through a udev rule matching all
block devices.
'';
example = "kyber";
};
defaultSchedulerRotational = mkOption {
type = types.nullOr udevValue;
default = null;
description = ''
Default block I/O scheduler for rotational drives (e.g. hard disks).
Unless `null`, the value is assigned through a udev rule matching all
rotational block devices.
This option takes precedence over
{option}`config.hardware.block.defaultScheduler`.
'';
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`.
'';
};
2024-06-09 20:09:25 +02:00
scheduler = mkOption {
type = types.attrsOf udevValue;
default = { };
description = ''
Assign block I/O scheduler by device name pattern.
Names are matched using the {manpage}`udev(7)` pattern syntax:
`*`
: Matches zero or more characters.
`?`
: Matches any single character.
`[]`
: Matches any single character specified in the brackets. Ranges are
supported via the `-` character.
`|`
: Separates alternative patterns.
Please note that overlapping patterns may produce unexpected results.
More complex configurations requiring these should instead be specified
directly through custom udev rules, for example via
[{option}`config.services.udev.extraRules`](#opt-services.udev.extraRules),
to ensure correct ordering.
Available schedulers depend on the kernel configuration but modern
Linux systems typically support:
`none`
: Nooperation scheduler with no reordering of requests. Suitable
for devices with fast random I/O such as NVMe SSDs.
[`mq-deadline`](https://www.kernel.org/doc/html/latest/block/deadline-iosched.html)
: Simple latencyoriented generalpurpose scheduler.
[`kyber`](https://www.kernel.org/doc/html/latest/block/kyber-iosched.html)
: Simple latencyoriented scheduler for fast multiqueue devices
like NVMe SSDs.
[`bfq`](https://www.kernel.org/doc/html/latest/block/bfq-iosched.html)
: Complex fairnessoriented scheduler. Higher processing overhead,
but good interactive response, especially with slower devices.
Schedulers assigned through this option take precedence over
{option}`config.hardware.block.defaultScheduler` and
{option}`config.hardware.block.defaultSchedulerRotational` but may be
overridden by other udev rules.
'';
example = {
"mmcblk[0-9]*" = "bfq";
"nvme[0-9]*" = "kyber";
};
};
};
config =
mkIf
(cfg.defaultScheduler != null || cfg.defaultSchedulerRotational != null || cfg.scheduler != { })
{
services.udev.packages = [
(pkgs.writeTextDir "etc/udev/rules.d/98-block-io-scheduler.rules" (
concatLines (
optional (cfg.defaultScheduler != null) (udevRule {
exclude = cfg.defaultSchedulerExclude;
scheduler = cfg.defaultScheduler;
})
++ optional (cfg.defaultSchedulerRotational != null) (udevRule {
rotational = true;
exclude = cfg.defaultSchedulerExclude;
scheduler = cfg.defaultSchedulerRotational;
})
++ mapAttrsToList (
include: scheduler:
udevRule {
inherit include scheduler;
}
) cfg.scheduler
2024-06-09 20:09:25 +02:00
)
))
];
};
meta.maintainers = with lib.maintainers; [ mvs ];
}