summary refs log tree commit diff
path: root/nixos/modules/config/swap.nix
blob: fb171050d3e8e88b631ea5fe7d1cb333957a91d2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
{ config, pkgs, utils, ... }:

with pkgs.lib;
with utils;

{

  ###### interface

  options = {

    swapDevices = mkOption {
      default = [];
      example = [
        { device = "/dev/hda7"; }
        { device = "/var/swapfile"; }
        { label = "bigswap"; }
      ];
      description = ''
        The swap devices and swap files.  These must have been
        initialised using <command>mkswap</command>.  Each element
        should be an attribute set specifying either the path of the
        swap device or file (<literal>device</literal>) or the label
        of the swap device (<literal>label</literal>, see
        <command>mkswap -L</command>).  Using a label is
        recommended.
      '';

      type = types.listOf types.optionSet;

      options = {config, options, ...}: {

        options = {

          device = mkOption {
            example = "/dev/sda3";
            type = types.uniq types.string;
            description = "Path of the device.";
          };

          label = mkOption {
            example = "swap";
            type = types.uniq types.string;
            description = ''
              Label of the device.  Can be used instead of <varname>device</varname>.
            '';
          };

          size = mkOption {
            default = null;
            example = 2048;
            type = types.nullOr types.int;
            description = ''
              If this option is set, ‘device’ is interpreted as the
              path of a swapfile that will be created automatically
              with the indicated size (in megabytes) if it doesn't
              exist.
            '';
          };

          priority = mkOption {
            default = null;
            example = 2048;
            type = types.nullOr types.int;
            description = ''
              Specify the priority of the swap device. Priority is a value between 0 and 32767.
              Higher numbers indicate higher priority.
              null lets the kernel choose a priority, which will show up as a negative value.
            '';
          };

        };

        config = {
          device = mkIf options.label.isDefined
            "/dev/disk/by-label/${config.label}";
        };

      };

    };

  };

  config = mkIf ((length config.swapDevices) != 0) {

    system.requiredKernelConfig = with config.lib.kernelConfig; [
      (isYes "SWAP")
    ];

    # Create missing swapfiles.
    # FIXME: support changing the size of existing swapfiles.
    systemd.services =
      let

        createSwapDevice = sw:
          assert sw.device != "";
          let device' = escapeSystemdPath sw.device; in
          nameValuePair "mkswap-${escapeSystemdPath sw.device}"
          { description = "Initialisation of Swapfile ${sw.device}";
            wantedBy = [ "${device'}.swap" ];
            before = [ "${device'}.swap" ];
            path = [ pkgs.utillinux ];
            script =
              ''
                if [ ! -e "${sw.device}" ]; then
                  fallocate -l ${toString sw.size}M "${sw.device}" ||
                    dd if=/dev/zero of="${sw.device}" bs=1M count=${toString sw.size}
                  mkswap ${sw.device}
                fi
              '';
            unitConfig.RequiresMountsFor = [ "${dirOf sw.device}" ];
            unitConfig.DefaultDependencies = false; # needed to prevent a cycle
            serviceConfig.Type = "oneshot";
          };

      in listToAttrs (map createSwapDevice (filter (sw: sw.size != null) config.swapDevices));

  };

}