1{
2 config,
3 lib,
4 pkgs,
5 ...
6}:
7
8let
9
10 cfg = config.zramSwap;
11 devices = map (nr: "zram${toString nr}") (lib.range 0 (cfg.swapDevices - 1));
12
13in
14
15{
16
17 imports = [
18 (lib.mkRemovedOptionModule [
19 "zramSwap"
20 "numDevices"
21 ] "Using ZRAM devices as general purpose ephemeral block devices is no longer supported")
22 ];
23
24 ###### interface
25
26 options = {
27
28 zramSwap = {
29
30 enable = lib.mkOption {
31 default = false;
32 type = lib.types.bool;
33 description = ''
34 Enable in-memory compressed devices and swap space provided by the zram
35 kernel module.
36 See [
37 https://www.kernel.org/doc/Documentation/blockdev/zram.txt
38 ](https://www.kernel.org/doc/Documentation/blockdev/zram.txt).
39 '';
40 };
41
42 swapDevices = lib.mkOption {
43 default = 1;
44 type = lib.types.int;
45 description = ''
46 Number of zram devices to be used as swap, recommended is 1.
47 '';
48 };
49
50 memoryPercent = lib.mkOption {
51 default = 50;
52 type = lib.types.int;
53 description = ''
54 Maximum total amount of memory that can be stored in the zram swap devices
55 (as a percentage of your total memory). Defaults to 1/2 of your total
56 RAM. Run `zramctl` to check how good memory is compressed.
57 This doesn't define how much memory will be used by the zram swap devices.
58 '';
59 };
60
61 memoryMax = lib.mkOption {
62 default = null;
63 type = with lib.types; nullOr int;
64 description = ''
65 Maximum total amount of memory (in bytes) that can be stored in the zram
66 swap devices.
67 This doesn't define how much memory will be used by the zram swap devices.
68 '';
69 };
70
71 priority = lib.mkOption {
72 default = 5;
73 type = lib.types.int;
74 description = ''
75 Priority of the zram swap devices. It should be a number higher than
76 the priority of your disk-based swap devices (so that the system will
77 fill the zram swap devices before falling back to disk swap).
78 '';
79 };
80
81 algorithm = lib.mkOption {
82 default = "zstd";
83 example = "lz4";
84 type =
85 with lib.types;
86 either (enum [
87 "842"
88 "lzo"
89 "lzo-rle"
90 "lz4"
91 "lz4hc"
92 "zstd"
93 ]) str;
94 description = ''
95 Compression algorithm. `lzo` has good compression,
96 but is slow. `lz4` has bad compression, but is fast.
97 `zstd` is both good compression and fast, but requires newer kernel.
98 You can check what other algorithms are supported by your zram device with
99 {command}`cat /sys/class/block/zram*/comp_algorithm`
100 '';
101 };
102
103 writebackDevice = lib.mkOption {
104 default = null;
105 example = "/dev/zvol/tarta-zoot/swap-writeback";
106 type = lib.types.nullOr lib.types.path;
107 description = ''
108 Write incompressible pages to this device,
109 as there's no gain from keeping them in RAM.
110 '';
111 };
112 };
113
114 };
115
116 config = lib.mkIf cfg.enable {
117
118 assertions = [
119 {
120 assertion = cfg.writebackDevice == null || cfg.swapDevices <= 1;
121 message = "A single writeback device cannot be shared among multiple zram devices";
122 }
123 ];
124
125 services.zram-generator.enable = true;
126
127 services.zram-generator.settings = lib.listToAttrs (
128 builtins.map (dev: {
129 name = dev;
130 value =
131 let
132 size = "${toString cfg.memoryPercent} / 100 * ram";
133 in
134 {
135 zram-size =
136 if cfg.memoryMax != null then "min(${size}, ${toString cfg.memoryMax} / 1024 / 1024)" else size;
137 compression-algorithm = cfg.algorithm;
138 swap-priority = cfg.priority;
139 }
140 // lib.optionalAttrs (cfg.writebackDevice != null) {
141 writeback-device = cfg.writebackDevice;
142 };
143 }) devices
144 );
145
146 };
147
148}