summaryrefslogtreecommitdiffstats
path: root/nixos/modules/config/zram.nix
diff options
context:
space:
mode:
authordanbst <abcz2.uprola@gmail.com>2018-12-28 00:00:48 +0200
committerdanbst <abcz2.uprola@gmail.com>2019-01-17 15:58:53 +0200
commit8d8a7210e480ac122d55a7d36879b8f41ea6fc80 (patch)
treee703f5cf360f84cd6ad819c7ecd7237173c101fb /nixos/modules/config/zram.nix
parent872502aa56bd4d574fcfe9cfef9066c9e8ee2894 (diff)
zramSwap: allow configure compression algorithm + cleanups
- add `zramSwap.algorithm` option, which allows to change compressor declaratively. zstd as default - add `zramSwap.swapDevices` option, which allows to define how many zram devices will be used as swap. Rest devices can be managed freely - simpler floating calculations - fix udev race condition - some documentation changes - replaced `/sys/block/zram*` handling with `zramctl`, because I had occasional "Device is busy" error (looks like zram has to be configured in predefined order) - added `memoryPercent` and `algorithm` as restart triggers. I think, it was a bug that changing `memoryPercent` in configuration wasn't applied immediately. - removed a bind to .swap device. While it looks natural (when swap device goes off, so should zram device), it wasn't implemented properly. This caused problems with swapon/swapoff: ``` $ cat /proc/swaps Filename Type Size Used Priority /dev/zram0 partition 8166024 0 -2 /var/swapfile file 5119996 5120 1 $ sudo swapoff -a $ sudo swapon -a swapon: /dev/zram0: read swap header failed $ cat /proc/swaps Filename Type Size Used Priority /var/swapfile file 5119996 0 1 ```
Diffstat (limited to 'nixos/modules/config/zram.nix')
-rw-r--r--nixos/modules/config/zram.nix79
1 files changed, 65 insertions, 14 deletions
diff --git a/nixos/modules/config/zram.nix b/nixos/modules/config/zram.nix
index c1748812821e..f8ff926cd56d 100644
--- a/nixos/modules/config/zram.nix
+++ b/nixos/modules/config/zram.nix
@@ -6,10 +6,27 @@ let
cfg = config.zramSwap;
- devices = map (nr: "zram${toString nr}") (range 0 (cfg.numDevices - 1));
+ # 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.
+ '')
+ ];
+
in
{
@@ -24,9 +41,11 @@ in
default = false;
type = types.bool;
description = ''
- Enable in-memory compressed swap space provided by the zram kernel
- module.
- See https://www.kernel.org/doc/Documentation/blockdev/zram.txt
+ Enable in-memory compressed devices and swap space provided by the zram
+ kernel module.
+ See <link xlink:href="https://www.kernel.org/doc/Documentation/blockdev/zram.txt">
+ https://www.kernel.org/doc/Documentation/blockdev/zram.txt
+ </link>.
'';
};
@@ -34,7 +53,19 @@ in
default = 1;
type = types.int;
description = ''
- Number of zram swap devices to create.
+ Number of zram devices to create. See also
+ <literal>zramSwap.swapDevices</literal>
+ '';
+ };
+
+ swapDevices = mkOption {
+ default = null;
+ example = 1;
+ type = with types; nullOr int;
+ description = ''
+ Number of zram devices to be used as swap. Must be
+ <literal>&lt;= zramSwap.numDevices</literal>.
+ Default is same as <literal>zramSwap.numDevices</literal>, recommended is 1.
'';
};
@@ -44,7 +75,8 @@ in
description = ''
Maximum amount of memory that can be used by the zram swap devices
(as a percentage of your total memory). Defaults to 1/2 of your total
- RAM.
+ RAM. Run <literal>zramctl</literal> to check how good memory is
+ compressed.
'';
};
@@ -58,12 +90,26 @@ in
'';
};
+ algorithm = mkOption {
+ default = "zstd";
+ example = "lzo";
+ 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.
+ You can check what other algorithms are supported by your zram device with
+ <programlisting>cat /sys/class/block/zram*/comp_algorithm</programlisting>
+ '';
+ };
};
};
config = mkIf cfg.enable {
+ inherit warnings;
+
system.requiredKernelConfig = with config.lib.kernelConfig; [
(isModule "ZRAM")
];
@@ -85,7 +131,6 @@ in
createZramInitService = dev:
nameValuePair "zram-init-${dev}" {
description = "Init swap on zram-based device ${dev}";
- bindsTo = [ "dev-${dev}.swap" ];
after = [ "dev-${dev}.device" "zram-reloader.service" ];
requires = [ "dev-${dev}.device" "zram-reloader.service" ];
before = [ "dev-${dev}.swap" ];
@@ -96,14 +141,14 @@ in
ExecStop = "${pkgs.runtimeShell} -c 'echo 1 > /sys/class/block/${dev}/reset'";
};
script = ''
- set -u
- set -o pipefail
-
+ set -euo pipefail
+
# Calculate memory to use for zram
- totalmem=$(${pkgs.gnugrep}/bin/grep 'MemTotal: ' /proc/meminfo | ${pkgs.gawk}/bin/awk '{print $2}')
- mem=$(((totalmem * ${toString cfg.memoryPercent} / 100 / ${toString cfg.numDevices}) * 1024))
+ mem=$(${pkgs.gawk}/bin/awk '/MemTotal: / {
+ print int($2*${toString cfg.memoryPercent}/100.0/${toString devicesCount}*1024)
+ }' /proc/meminfo)
- echo $mem > /sys/class/block/${dev}/disksize
+ ${pkgs.utillinux}/sbin/zramctl --size $mem --algorithm ${cfg.algorithm} /dev/${dev}
${pkgs.utillinux}/sbin/mkswap /dev/${dev}
'';
restartIfChanged = false;
@@ -111,6 +156,8 @@ in
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" ];
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
@@ -118,7 +165,11 @@ in
ExecStart = "${modprobe} zram";
ExecStop = "${modprobe} -r zram";
};
- restartTriggers = [ cfg.numDevices ];
+ restartTriggers = [
+ cfg.numDevices
+ cfg.algorithm
+ cfg.memoryPercent
+ ];
restartIfChanged = true;
})]);