at 15.09-beta 4.0 kB view raw
1{ config, lib, pkgs, ... }: 2 3with lib; 4 5let 6 7 cfg = config.zramSwap; 8 9 devices = map (nr: "zram${toString nr}") (range 0 (cfg.numDevices - 1)); 10 11 modprobe = "${config.system.sbin.modprobe}/sbin/modprobe"; 12 13in 14 15{ 16 17 ###### interface 18 19 options = { 20 21 zramSwap = { 22 23 enable = mkOption { 24 default = false; 25 type = types.bool; 26 description = '' 27 Enable in-memory compressed swap space provided by the zram kernel 28 module. It is recommended to enable only for kernel 3.14 or higher. 29 ''; 30 }; 31 32 numDevices = mkOption { 33 default = 4; 34 type = types.int; 35 description = '' 36 Number of zram swap devices to create. It should be equal to the 37 number of CPU cores your system has. 38 ''; 39 }; 40 41 memoryPercent = mkOption { 42 default = 50; 43 type = types.int; 44 description = '' 45 Maximum amount of memory that can be used by the zram swap devices 46 (as a percentage of your total memory). Defaults to 1/2 of your total 47 RAM. 48 ''; 49 }; 50 51 priority = mkOption { 52 default = 5; 53 type = types.int; 54 description = '' 55 Priority of the zram swap devices. It should be a number higher than 56 the priority of your disk-based swap devices (so that the system will 57 fill the zram swap devices before falling back to disk swap). 58 ''; 59 }; 60 61 }; 62 63 }; 64 65 config = mkIf cfg.enable { 66 67 system.requiredKernelConfig = with config.lib.kernelConfig; [ 68 (isModule "ZRAM") 69 ]; 70 71 # Disabling this for the moment, as it would create and mkswap devices twice, 72 # once in stage 2 boot, and again when the zram-reloader service starts. 73 # boot.kernelModules = [ "zram" ]; 74 75 boot.extraModprobeConfig = '' 76 options zram num_devices=${toString cfg.numDevices} 77 ''; 78 79 services.udev.extraRules = '' 80 KERNEL=="zram[0-9]*", ENV{SYSTEMD_WANTS}="zram-init-%k.service", TAG+="systemd" 81 ''; 82 83 systemd.services = 84 let 85 createZramInitService = dev: 86 nameValuePair "zram-init-${dev}" { 87 description = "Init swap on zram-based device ${dev}"; 88 bindsTo = [ "dev-${dev}.swap" ]; 89 after = [ "dev-${dev}.device" "zram-reloader.service" ]; 90 requires = [ "dev-${dev}.device" "zram-reloader.service" ]; 91 before = [ "dev-${dev}.swap" ]; 92 requiredBy = [ "dev-${dev}.swap" ]; 93 serviceConfig = { 94 Type = "oneshot"; 95 RemainAfterExit = true; 96 ExecStop = "${pkgs.stdenv.shell} -c 'echo 1 > /sys/class/block/${dev}/reset'"; 97 }; 98 script = '' 99 set -u 100 set -o pipefail 101 102 PATH=${pkgs.procps}/bin:${pkgs.gnugrep}/bin:${pkgs.gnused}/bin 103 104 # Calculate memory to use for zram 105 totalmem=$(free | grep -e "^Mem:" | sed -e 's/^Mem: *//' -e 's/ *.*//') 106 mem=$(((totalmem * ${toString cfg.memoryPercent} / 100 / ${toString cfg.numDevices}) * 1024)) 107 108 echo $mem > /sys/class/block/${dev}/disksize 109 ${pkgs.utillinux}/sbin/mkswap /dev/${dev} 110 ''; 111 restartIfChanged = false; 112 }; 113 in listToAttrs ((map createZramInitService devices) ++ [(nameValuePair "zram-reloader" 114 { 115 description = "Reload zram kernel module when number of devices changes"; 116 serviceConfig = { 117 Type = "oneshot"; 118 RemainAfterExit = true; 119 ExecStartPre = "${modprobe} -r zram"; 120 ExecStart = "${modprobe} zram"; 121 ExecStop = "${modprobe} -r zram"; 122 }; 123 restartTriggers = [ cfg.numDevices ]; 124 restartIfChanged = true; 125 })]); 126 127 swapDevices = 128 let 129 useZramSwap = dev: 130 { 131 device = "/dev/${dev}"; 132 priority = cfg.priority; 133 }; 134 in map useZramSwap devices; 135 136 }; 137 138}