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.ints.positive;
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. If set, the smaller one of this option and memoryPercent would
67 be used.
68 This doesn't define how much memory will be used by the zram swap devices.
69 '';
70 };
71
72 priority = lib.mkOption {
73 default = 5;
74 type = lib.types.int;
75 description = ''
76 Priority of the zram swap devices. It should be a number higher than
77 the priority of your disk-based swap devices (so that the system will
78 fill the zram swap devices before falling back to disk swap).
79 '';
80 };
81
82 algorithm = lib.mkOption {
83 default = "zstd";
84 example = "lz4";
85 type =
86 with lib.types;
87 either (enum [
88 "842"
89 "lzo"
90 "lzo-rle"
91 "lz4"
92 "lz4hc"
93 "zstd"
94 ]) str;
95 description = ''
96 Compression algorithm. `lzo` has good compression,
97 but is slow. `lz4` has bad compression, but is fast.
98 `zstd` is both good compression and fast, but requires newer kernel.
99 You can check what other algorithms are supported by your zram device with
100 {command}`cat /sys/class/block/zram*/comp_algorithm`
101 '';
102 };
103
104 writebackDevice = lib.mkOption {
105 default = null;
106 example = "/dev/zvol/tarta-zoot/swap-writeback";
107 type = lib.types.nullOr lib.types.path;
108 description = ''
109 Write incompressible pages to this device,
110 as there's no gain from keeping them in RAM.
111 '';
112 };
113 };
114
115 };
116
117 config = lib.mkIf cfg.enable {
118
119 assertions = [
120 {
121 assertion = cfg.writebackDevice == null || cfg.swapDevices <= 1;
122 message = "A single writeback device cannot be shared among multiple zram devices";
123 }
124 ];
125
126 services.zram-generator.enable = true;
127
128 services.zram-generator.settings = lib.listToAttrs (
129 builtins.map (dev: {
130 name = dev;
131 value =
132 let
133 size = "${toString cfg.memoryPercent} / 100 * ram";
134 in
135 {
136 zram-size =
137 if cfg.memoryMax != null then "min(${size}, ${toString cfg.memoryMax} / 1024 / 1024)" else size;
138 compression-algorithm = cfg.algorithm;
139 swap-priority = cfg.priority;
140 }
141 // lib.optionalAttrs (cfg.writebackDevice != null) {
142 writeback-device = cfg.writebackDevice;
143 };
144 }) devices
145 );
146
147 };
148
149}