Change:
Project description In the author says, In 2020 the zram-generator doesn't seem to have had any releases. In the meantime, it's gone from initial release version 0.2.0 up to the somewhat-mature version 1.1.2. It's probably a good time to port this to zram-generator. Metadata homepage URL: source URL: license: mit platforms: linux

Discussion:
</listitem> <listitem> <para> <ins> The <literal>zramSwap</literal> is now implemented with <literal>zram-generator</literal>, and the option <literal>zramSwap.numDevices</literal> for using ZRAM devices as general purpose ephemeral block devices has been removed. </para> </listitem> <listitem> <para> </ins> The <literal>unifi-poller</literal> package and corresponding NixOS module have been renamed to <literal>unpoller</literal> to match upstream.

- The `services.fwupd` module now allows arbitrary daemon settings to be configured in a structured manner ([`services.fwupd.daemonSettings`](#opt-services.fwupd.daemonSettings)). <ins> - The `zramSwap` is now implemented with `zram-generator`, and the option `zramSwap.numDevices` for using ZRAM devices as general purpose ephemeral block devices has been removed. </ins> - The `unifi-poller` package and corresponding NixOS module have been renamed to `unpoller` to match upstream. - The new option `services.tailscale.useRoutingFeatures` controls various settings for using Tailscale features like exit nodes and subnet routers. If you wish to use your machine as an exit node, you can set this setting to `server`, otherwise if you wish to use an exit node you can set this setting to `client`. The strict RPF warning has been removed as the RPF will be loosened automatically based on the value of this setting.

{ config, lib, pkgs, ... }: <del> with lib; </del> let cfg = config.zramSwap; <del> # 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. '') ]; </del> <ins> devices = map (nr: "zram${toString nr}") (lib.range 0 (cfg.swapDevices - 1)); </ins> in { <ins> imports = [ (lib.mkRemovedOptionModule [ "zramSwap" "numDevices" ] "Using ZRAM devices as general purpose ephemeral block devices is no longer supported") ]; </ins> ###### interface options = { zramSwap = { <del> enable = mkOption { </del> <ins> enable = lib.mkOption { </ins> default = false; <del> type = types.bool; </del> <ins> type = lib.types.bool; </ins> description = lib.mdDoc '' Enable in-memory compressed devices and swap space provided by the zram kernel module.

''; }; <del> numDevices = mkOption { default = 1; type = types.int; description = lib.mdDoc '' Number of zram devices to create. See also `zramSwap.swapDevices` ''; }; swapDevices = mkOption { default = null; </del> <ins> swapDevices = lib.mkOption { default = 0; </ins> example = 1; <del> type = with types; nullOr int; </del> <ins> type = lib.types.int; </ins> description = lib.mdDoc '' <del> Number of zram devices to be used as swap. Must be `<= zramSwap.numDevices`. Default is same as `zramSwap.numDevices`, recommended is 1. </del> <ins> Number of zram devices to be used as swap, recommended is 1. </ins> ''; }; <del> memoryPercent = mkOption { </del> <ins> memoryPercent = lib.mkOption { </ins> default = 50; <del> type = types.int; </del> <ins> type = lib.types.int; </ins> description = lib.mdDoc '' 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

''; }; <del> memoryMax = mkOption { </del> <ins> memoryMax = lib.mkOption { </ins> default = null; <del> type = with types; nullOr int; </del> <ins> type = with lib.types; nullOr int; </ins> description = lib.mdDoc '' Maximum total amount of memory (in bytes) that can be stored in the zram swap devices.

''; }; <del> priority = mkOption { </del> <ins> priority = lib.mkOption { </ins> default = 5; <del> type = types.int; </del> <ins> type = lib.types.int; </ins> 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

''; }; <del> algorithm = mkOption { </del> <ins> algorithm = lib.mkOption { </ins> default = "zstd"; example = "lz4"; <del> type = with types; either (enum [ "lzo" "lz4" "zstd" ]) str; </del> <ins> type = with lib.types; either (enum [ "lzo" "lz4" "zstd" ]) str; </ins> description = lib.mdDoc '' Compression algorithm. `lzo` has good compression, but is slow. `lz4` has bad compression, but is fast.

}; <del> config = mkIf cfg.enable { inherit warnings; </del> <ins> config = lib.mkIf cfg.enable { </ins> system.requiredKernelConfig = with config.lib.kernelConfig; [ (isModule "ZRAM")

# once in stage 2 boot, and again when the zram-reloader service starts. # boot.kernelModules = [ "zram" ]; <del> boot.extraModprobeConfig = '' options zram num_devices=${toString cfg.numDevices} ''; boot.kernelParams = ["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; </del> <ins> 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; }; }) devices)); </ins> };

import ./make-test-python.nix { name = "zram-generator"; <del> nodes.machine = { pkgs, ... }: { environment.etc."systemd/zram-generator.conf".text = '' [zram0] zram-size = ram / 2 ''; systemd.packages = [ pkgs.zram-generator ]; systemd.services."systemd-zram-setup@".path = [ pkgs.util-linux ]; # for mkswap </del> <ins> nodes.machine = { ... }: { zramSwap = { enable = true; priority = 10; algorithm = "lz4"; swapDevices = 2; memoryPercent = 30; memoryMax = 10 * 1024 * 1024; }; </ins> }; testScript = '' machine.wait_for_unit("systemd-zram-setup@zram0.service") <del> assert "zram0" in machine.succeed("zramctl -n") assert "zram0" in machine.succeed("swapon --show --noheadings") </del> <ins> machine.wait_for_unit("systemd-zram-setup@zram1.service") zram = machine.succeed("zramctl --noheadings --raw") swap = machine.succeed("swapon --show --noheadings") for i in range(2): assert f"/dev/zram{i} lz4 10M" in zram assert f"/dev/zram{i} partition  10M" in swap </ins> ''; }