2014-04-14 15:26:48 +01:00
|
|
|
|
{ config, lib, pkgs, utils, ... }:
|
2009-10-12 18:27:57 +01:00
|
|
|
|
|
2012-10-12 22:01:49 +01:00
|
|
|
|
with utils;
|
2014-05-05 19:58:51 +01:00
|
|
|
|
with lib;
|
2009-03-06 12:27:35 +00:00
|
|
|
|
|
2015-10-18 19:20:46 +01:00
|
|
|
|
let
|
|
|
|
|
|
|
|
|
|
swapCfg = {config, options, ...}: {
|
|
|
|
|
|
|
|
|
|
options = {
|
|
|
|
|
|
|
|
|
|
device = mkOption {
|
|
|
|
|
example = "/dev/sda3";
|
|
|
|
|
type = types.str;
|
|
|
|
|
description = "Path of the device.";
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
label = mkOption {
|
|
|
|
|
example = "swap";
|
|
|
|
|
type = types.str;
|
|
|
|
|
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
|
2016-07-06 12:41:40 +01:00
|
|
|
|
with the indicated size (in megabytes).
|
2015-10-18 19:20:46 +01:00
|
|
|
|
'';
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
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.
|
|
|
|
|
'';
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
randomEncryption = mkOption {
|
|
|
|
|
default = false;
|
|
|
|
|
type = types.bool;
|
|
|
|
|
description = ''
|
|
|
|
|
Encrypt swap device with a random key. This way you won't have a persistent swap device.
|
|
|
|
|
|
|
|
|
|
WARNING: Don't try to hibernate when you have at least one swap partition with
|
|
|
|
|
this option enabled! We have no way to set the partition into which hibernation image
|
|
|
|
|
is saved, so if your image ends up on an encrypted one you would lose it!
|
2016-08-31 14:34:08 +01:00
|
|
|
|
|
|
|
|
|
WARNING #2: Do not use /dev/disk/by-uuid/… or /dev/disk/by-label/… as your swap device
|
|
|
|
|
when using randomEncryption as the UUIDs and labels will get erased on every boot when
|
|
|
|
|
the partition is encrypted. Best to use /dev/disk/by-partuuid/…
|
2015-10-18 19:20:46 +01:00
|
|
|
|
'';
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
deviceName = mkOption {
|
|
|
|
|
type = types.str;
|
|
|
|
|
internal = true;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
realDevice = mkOption {
|
|
|
|
|
type = types.path;
|
|
|
|
|
internal = true;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
config = rec {
|
|
|
|
|
device = mkIf options.label.isDefined
|
|
|
|
|
"/dev/disk/by-label/${config.label}";
|
2016-08-31 14:34:08 +01:00
|
|
|
|
deviceName = lib.replaceChars ["\\"] [""] (escapeSystemdPath config.device);
|
2015-10-18 19:20:46 +01:00
|
|
|
|
realDevice = if config.randomEncryption then "/dev/mapper/${deviceName}" else config.device;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
in
|
|
|
|
|
|
2009-07-16 15:51:49 +01:00
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
###### interface
|
2011-09-14 19:20:50 +01:00
|
|
|
|
|
2009-05-28 00:14:38 +01:00
|
|
|
|
options = {
|
|
|
|
|
|
2009-07-16 15:51:49 +01:00
|
|
|
|
swapDevices = mkOption {
|
2009-05-28 00:14:38 +01:00
|
|
|
|
default = [];
|
|
|
|
|
example = [
|
|
|
|
|
{ device = "/dev/hda7"; }
|
|
|
|
|
{ device = "/var/swapfile"; }
|
|
|
|
|
{ label = "bigswap"; }
|
|
|
|
|
];
|
2009-07-16 15:51:49 +01:00
|
|
|
|
description = ''
|
2009-05-28 00:14:38 +01:00
|
|
|
|
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.
|
2009-07-16 15:51:49 +01:00
|
|
|
|
'';
|
|
|
|
|
|
2015-10-18 19:20:46 +01:00
|
|
|
|
type = types.listOf (types.submodule swapCfg);
|
2009-05-28 00:14:38 +01:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
};
|
2009-07-16 15:51:49 +01:00
|
|
|
|
|
2012-08-07 22:34:10 +01:00
|
|
|
|
config = mkIf ((length config.swapDevices) != 0) {
|
2012-10-12 21:47:11 +01:00
|
|
|
|
|
2012-08-07 22:34:10 +01:00
|
|
|
|
system.requiredKernelConfig = with config.lib.kernelConfig; [
|
|
|
|
|
(isYes "SWAP")
|
|
|
|
|
];
|
2012-10-12 21:47:11 +01:00
|
|
|
|
|
|
|
|
|
# Create missing swapfiles.
|
|
|
|
|
# FIXME: support changing the size of existing swapfiles.
|
2013-01-16 11:33:18 +00:00
|
|
|
|
systemd.services =
|
2012-10-12 21:47:11 +01:00
|
|
|
|
let
|
|
|
|
|
|
2012-10-12 22:01:49 +01:00
|
|
|
|
createSwapDevice = sw:
|
|
|
|
|
assert sw.device != "";
|
2016-08-31 15:29:11 +01:00
|
|
|
|
assert !(sw.randomEncryption && lib.hasPrefix "/dev/disk/by-uuid" sw.device);
|
|
|
|
|
assert !(sw.randomEncryption && lib.hasPrefix "/dev/disk/by-label" sw.device);
|
2015-10-18 19:20:46 +01:00
|
|
|
|
let realDevice' = escapeSystemdPath sw.realDevice;
|
|
|
|
|
in nameValuePair "mkswap-${sw.deviceName}"
|
|
|
|
|
{ description = "Initialisation of swap device ${sw.device}";
|
|
|
|
|
wantedBy = [ "${realDevice'}.swap" ];
|
|
|
|
|
before = [ "${realDevice'}.swap" ];
|
|
|
|
|
path = [ pkgs.utillinux ] ++ optional sw.randomEncryption pkgs.cryptsetup;
|
2016-01-12 14:27:21 +00:00
|
|
|
|
|
2012-10-12 21:47:11 +01:00
|
|
|
|
script =
|
|
|
|
|
''
|
2015-10-18 19:20:46 +01:00
|
|
|
|
${optionalString (sw.size != null) ''
|
2016-07-06 12:41:40 +01:00
|
|
|
|
currentSize=$(( $(stat -c "%s" "${sw.device}" 2>/dev/null || echo 0) / 1024 / 1024 ))
|
|
|
|
|
if [ "${toString sw.size}" != "$currentSize" ]; then
|
2015-10-18 19:20:46 +01:00
|
|
|
|
fallocate -l ${toString sw.size}M "${sw.device}" ||
|
|
|
|
|
dd if=/dev/zero of="${sw.device}" bs=1M count=${toString sw.size}
|
2016-07-06 12:41:40 +01:00
|
|
|
|
if [ "${toString sw.size}" -lt "$currentSize" ]; then
|
|
|
|
|
truncate --size "${toString sw.size}M" "${sw.device}"
|
|
|
|
|
fi
|
2015-10-18 19:20:46 +01:00
|
|
|
|
chmod 0600 ${sw.device}
|
|
|
|
|
${optionalString (!sw.randomEncryption) "mkswap ${sw.realDevice}"}
|
|
|
|
|
fi
|
|
|
|
|
''}
|
|
|
|
|
${optionalString sw.randomEncryption ''
|
|
|
|
|
echo "secretkey" | cryptsetup luksFormat --batch-mode ${sw.device}
|
|
|
|
|
echo "secretkey" | cryptsetup luksOpen ${sw.device} ${sw.deviceName}
|
|
|
|
|
cryptsetup luksErase --batch-mode ${sw.device}
|
|
|
|
|
mkswap ${sw.realDevice}
|
|
|
|
|
''}
|
2012-10-12 21:47:11 +01:00
|
|
|
|
'';
|
2016-01-12 14:27:21 +00:00
|
|
|
|
|
2012-10-12 22:32:36 +01:00
|
|
|
|
unitConfig.RequiresMountsFor = [ "${dirOf sw.device}" ];
|
2012-10-12 21:47:11 +01:00
|
|
|
|
unitConfig.DefaultDependencies = false; # needed to prevent a cycle
|
|
|
|
|
serviceConfig.Type = "oneshot";
|
2015-10-18 19:20:46 +01:00
|
|
|
|
serviceConfig.RemainAfterExit = sw.randomEncryption;
|
2016-01-05 18:23:04 +00:00
|
|
|
|
serviceConfig.ExecStop = optionalString sw.randomEncryption "${pkgs.cryptsetup}/bin/cryptsetup luksClose ${sw.deviceName}";
|
2016-01-12 14:27:21 +00:00
|
|
|
|
restartIfChanged = false;
|
2012-10-12 21:47:11 +01:00
|
|
|
|
};
|
|
|
|
|
|
2015-10-18 19:20:46 +01:00
|
|
|
|
in listToAttrs (map createSwapDevice (filter (sw: sw.size != null || sw.randomEncryption) config.swapDevices));
|
2012-10-12 21:47:11 +01:00
|
|
|
|
|
2012-08-07 22:34:10 +01:00
|
|
|
|
};
|
|
|
|
|
|
2006-12-21 01:07:23 +00:00
|
|
|
|
}
|