diff options
Diffstat (limited to 'nixpkgs/nixos/modules/config/zram.nix')
-rw-r--r-- | nixpkgs/nixos/modules/config/zram.nix | 196 |
1 files changed, 67 insertions, 129 deletions
diff --git a/nixpkgs/nixos/modules/config/zram.nix b/nixpkgs/nixos/modules/config/zram.nix index 34e80df47a40..991387ea9b2b 100644 --- a/nixpkgs/nixos/modules/config/zram.nix +++ b/nixpkgs/nixos/modules/config/zram.nix @@ -1,45 +1,27 @@ { config, lib, pkgs, ... }: -with lib; - let cfg = config.zramSwap; - - # don't set swapDevices as mkDefault, so we can detect user had read our warning - # (see below) and made an action (or not) - devicesCount = if cfg.swapDevices != null then cfg.swapDevices else cfg.numDevices; - - devices = map (nr: "zram${toString nr}") (range 0 (devicesCount - 1)); - - modprobe = "${pkgs.kmod}/bin/modprobe"; - - warnings = - assert cfg.swapDevices != null -> cfg.numDevices >= cfg.swapDevices; - flatten [ - (optional (cfg.numDevices > 1 && cfg.swapDevices == null) '' - Using several small zram devices as swap is no better than using one large. - Set either zramSwap.numDevices = 1 or explicitly set zramSwap.swapDevices. - - Previously multiple zram devices were used to enable multithreaded - compression. Linux supports multithreaded compression for 1 device - since 3.15. See https://lkml.org/lkml/2014/2/28/404 for details. - '') - ]; + devices = map (nr: "zram${toString nr}") (lib.range 0 (cfg.swapDevices - 1)); in { + imports = [ + (lib.mkRemovedOptionModule [ "zramSwap" "numDevices" ] "Using ZRAM devices as general purpose ephemeral block devices is no longer supported") + ]; + ###### interface options = { zramSwap = { - enable = mkOption { + enable = lib.mkOption { default = false; - type = types.bool; + type = lib.types.bool; description = lib.mdDoc '' Enable in-memory compressed devices and swap space provided by the zram kernel module. @@ -49,49 +31,38 @@ in ''; }; - numDevices = mkOption { + swapDevices = lib.mkOption { default = 1; - type = types.int; - description = lib.mdDoc '' - Number of zram devices to create. See also - `zramSwap.swapDevices` - ''; - }; - - swapDevices = mkOption { - default = null; - example = 1; - type = with types; nullOr int; + type = lib.types.int; description = lib.mdDoc '' - Number of zram devices to be used as swap. Must be - `<= zramSwap.numDevices`. - Default is same as `zramSwap.numDevices`, recommended is 1. + Number of zram devices to be used as swap, recommended is 1. ''; }; - memoryPercent = mkOption { + memoryPercent = lib.mkOption { default = 50; - type = types.int; + type = lib.types.int; description = lib.mdDoc '' - Maximum amount of memory that can be used by the zram swap devices + Maximum total amount of memory that can be stored in the zram swap devices (as a percentage of your total memory). Defaults to 1/2 of your total - RAM. Run `zramctl` to check how good memory is - compressed. + RAM. Run `zramctl` to check how good memory is compressed. + This doesn't define how much memory will be used by the zram swap devices. ''; }; - memoryMax = mkOption { + memoryMax = lib.mkOption { default = null; - type = with types; nullOr int; + type = with lib.types; nullOr int; description = lib.mdDoc '' - Maximum total amount of memory (in bytes) that can be used by the zram + Maximum total amount of memory (in bytes) that can be stored in the zram swap devices. + This doesn't define how much memory will be used by the zram swap devices. ''; }; - priority = mkOption { + priority = lib.mkOption { default = 5; - type = types.int; + type = lib.types.int; description = lib.mdDoc '' Priority of the zram swap devices. It should be a number higher than the priority of your disk-based swap devices (so that the system will @@ -99,25 +70,41 @@ in ''; }; - algorithm = mkOption { + algorithm = lib.mkOption { default = "zstd"; example = "lz4"; - type = with types; either (enum [ "lzo" "lz4" "zstd" ]) str; - description = '' - Compression algorithm. <literal>lzo</literal> has good compression, - but is slow. <literal>lz4</literal> has bad compression, but is fast. - <literal>zstd</literal> is both good compression and fast, but requires newer kernel. + type = with lib.types; either (enum [ "lzo" "lz4" "zstd" ]) str; + description = lib.mdDoc '' + Compression algorithm. `lzo` has good compression, + but is slow. `lz4` has bad compression, but is fast. + `zstd` is both good compression and fast, but requires newer kernel. You can check what other algorithms are supported by your zram device with - <programlisting>cat /sys/class/block/zram*/comp_algorithm</programlisting> + {command}`cat /sys/class/block/zram*/comp_algorithm` + ''; + }; + + writebackDevice = lib.mkOption { + default = null; + example = "/dev/zvol/tarta-zoot/swap-writeback"; + type = lib.types.nullOr lib.types.path; + description = lib.mdDoc '' + Write incompressible pages to this device, + as there's no gain from keeping them in RAM. ''; }; }; }; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { + + assertions = [ + { + assertion = cfg.writebackDevice == null || cfg.swapDevices <= 1; + message = "A single writeback device cannot be shared among multiple zram devices"; + } + ]; - inherit warnings; system.requiredKernelConfig = with config.lib.kernelConfig; [ (isModule "ZRAM") @@ -127,76 +114,27 @@ in # once in stage 2 boot, and again when the zram-reloader service starts. # boot.kernelModules = [ "zram" ]; - boot.extraModprobeConfig = '' - options zram num_devices=${toString cfg.numDevices} - ''; - - services.udev.extraRules = '' - KERNEL=="zram[0-9]*", ENV{SYSTEMD_WANTS}="zram-init-%k.service", TAG+="systemd" - ''; - - systemd.services = - let - createZramInitService = dev: - nameValuePair "zram-init-${dev}" { - description = "Init swap on zram-based device ${dev}"; - after = [ "dev-${dev}.device" "zram-reloader.service" ]; - requires = [ "dev-${dev}.device" "zram-reloader.service" ]; - before = [ "dev-${dev}.swap" ]; - requiredBy = [ "dev-${dev}.swap" ]; - unitConfig.DefaultDependencies = false; # needed to prevent a cycle - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - ExecStop = "${pkgs.runtimeShell} -c 'echo 1 > /sys/class/block/${dev}/reset'"; - }; - script = '' - set -euo pipefail - - # Calculate memory to use for zram - mem=$(${pkgs.gawk}/bin/awk '/MemTotal: / { - value=int($2*${toString cfg.memoryPercent}/100.0/${toString devicesCount}*1024); - ${lib.optionalString (cfg.memoryMax != null) '' - memory_max=int(${toString cfg.memoryMax}/${toString devicesCount}); - if (value > memory_max) { value = memory_max } - ''} - print value - }' /proc/meminfo) - - ${pkgs.util-linux}/sbin/zramctl --size $mem --algorithm ${cfg.algorithm} /dev/${dev} - ${pkgs.util-linux}/sbin/mkswap /dev/${dev} - ''; - restartIfChanged = false; - }; - in listToAttrs ((map createZramInitService devices) ++ [(nameValuePair "zram-reloader" - { - description = "Reload zram kernel module when number of devices changes"; - wants = [ "systemd-udevd.service" ]; - after = [ "systemd-udevd.service" ]; - unitConfig.DefaultDependencies = false; # needed to prevent a cycle - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - ExecStartPre = "${modprobe} -r zram"; - ExecStart = "${modprobe} zram"; - ExecStop = "${modprobe} -r zram"; - }; - restartTriggers = [ - cfg.numDevices - cfg.algorithm - cfg.memoryPercent - ]; - restartIfChanged = true; - })]); - - swapDevices = - let - useZramSwap = dev: - { - device = "/dev/${dev}"; - priority = cfg.priority; - }; - in map useZramSwap devices; + systemd.packages = [ pkgs.zram-generator ]; + systemd.services."systemd-zram-setup@".path = [ pkgs.util-linux ]; # for mkswap + + environment.etc."systemd/zram-generator.conf".source = + (pkgs.formats.ini { }).generate "zram-generator.conf" (lib.listToAttrs + (builtins.map + (dev: { + name = dev; + value = + let + size = "${toString cfg.memoryPercent} / 100 * ram"; + in + { + zram-size = if cfg.memoryMax != null then "min(${size}, ${toString cfg.memoryMax} / 1024 / 1024)" else size; + compression-algorithm = cfg.algorithm; + swap-priority = cfg.priority; + } // lib.optionalAttrs (cfg.writebackDevice != null) { + writeback-device = cfg.writebackDevice; + }; + }) + devices)); }; |