nixos/modules/fileSystems/default.nix

248 lines
7.1 KiB
Nix
Raw Normal View History

2023-07-09 12:39:03 +08:00
inputs:
{
options.nixos.fileSystems = let inherit (inputs.lib) mkOption types; in
{
2023-07-09 12:50:30 +08:00
mount =
2023-07-09 12:39:03 +08:00
{
# device = mountPoint;
2023-07-28 20:15:49 +08:00
vfat = mkOption { type = types.attrsOf types.nonEmptyStr; default = {}; };
2023-07-09 12:39:03 +08:00
# device.subvol = mountPoint;
2023-07-28 20:15:49 +08:00
btrfs = mkOption { type = types.attrsOf (types.attrsOf types.nonEmptyStr); default = {}; };
2023-07-09 12:39:03 +08:00
};
2023-08-01 13:05:10 +08:00
decrypt =
2023-07-10 14:44:11 +08:00
{
2023-08-01 13:05:10 +08:00
auto = mkOption
{
type = types.attrsOf (types.submodule
{
options =
{
mapper = mkOption { type = types.nonEmptyStr; };
ssd = mkOption { type = types.bool; default = false; };
before = mkOption { type = types.nullOr (types.listOf types.nonEmptyStr); default = null; };
};
});
default = {};
};
manual =
{
enable = mkOption { type = types.bool; default = false; };
2023-08-02 14:24:25 +08:00
devices = mkOption
{
type = types.attrsOf (types.submodule
{
options =
{
mapper = mkOption { type = types.nonEmptyStr; };
ssd = mkOption { type = types.bool; default = false; };
};
});
default = {};
};
delayedMount = mkOption { type = types.listOf types.nonEmptyStr; default = []; };
};
2023-08-01 13:05:10 +08:00
};
2023-07-28 20:15:49 +08:00
mdadm = mkOption { type = types.nullOr types.str; default = null; };
swap = mkOption { type = types.listOf types.nonEmptyStr; default = []; };
resume = mkOption
2023-07-14 16:57:57 +08:00
{
2023-07-28 20:15:49 +08:00
type = types.nullOr (types.str or (types.submodule
{
options =
{
device = mkOption { type = types.nonEmptyStr; };
offset = mkOption { type = types.ints.unsigned; };
};
}));
default = null;
};
rollingRootfs = mkOption
{
type = types.nullOr (types.submodule { options =
{
device = mkOption { type = types.nonEmptyStr; };
path = mkOption { type = types.nonEmptyStr; };
}; });
default = null;
};
2023-07-09 12:39:03 +08:00
};
2023-07-26 23:36:12 +08:00
config =
let
inherit (builtins) listToAttrs map concatLists concatStringsSep;
2023-07-26 23:36:12 +08:00
inherit (inputs.lib) mkMerge mkIf;
inherit (inputs.localLib) stripeTabs attrsToList;
inherit (inputs.config.nixos) fileSystems;
in mkMerge
[
# mount.vfat
2023-07-21 13:52:04 +08:00
{
2023-07-26 23:36:12 +08:00
fileSystems = listToAttrs (map
(device: { name = device.value; value = { device = device.name; fsType = "vfat"; }; })
(attrsToList fileSystems.mount.vfat));
}
# mount.btrfs
{
fileSystems = listToAttrs (concatLists (map
(
device: map
(
subvol:
{
name = subvol.value;
value =
{
device = device.name;
fsType = "btrfs";
options = [ "compress-force=zstd" "subvol=${subvol.name}" ];
2023-07-26 23:36:12 +08:00
};
}
)
(attrsToList device.value)
)
(attrsToList fileSystems.mount.btrfs)));
}
# decrypt.auto
(
mkIf (fileSystems.decrypt.auto != null)
2023-07-22 18:25:26 +08:00
{
2023-07-26 23:36:12 +08:00
boot.initrd =
{
luks.devices = (listToAttrs (map
(
device:
2023-07-21 13:52:04 +08:00
{
2023-07-26 23:36:12 +08:00
name = device.value.mapper;
value =
{
device = device.name;
allowDiscards = device.value.ssd;
bypassWorkqueues = device.value.ssd;
crypttabExtraOpts = [ "fido2-device=auto" "x-initrd.attach" ];
};
}
)
(attrsToList fileSystems.decrypt.auto)));
systemd.services =
let
createService = device:
2023-07-22 18:25:26 +08:00
{
2023-07-26 23:36:12 +08:00
name = "systemd-cryptsetup@${device.value.mapper}";
value =
{
before = map (device: "systemd-cryptsetup@${device}.service") device.value.before;
overrideStrategy = "asDropin";
};
2023-07-22 18:25:26 +08:00
};
2023-07-26 23:36:12 +08:00
in
listToAttrs (map createService
(builtins.filter (device: device.value.before != null) (attrsToList fileSystems.decrypt.auto)));
};
}
)
2023-08-01 13:05:10 +08:00
# decrypt.manual
(
2023-08-01 14:49:03 +08:00
mkIf (fileSystems.decrypt.manual.enable)
{
boot.initrd =
{
luks.forceLuksSupportInInitrd = true;
systemd =
2023-08-01 14:49:03 +08:00
{
extraBin =
{
cryptsetup = "${inputs.pkgs.cryptsetup.bin}/bin/cryptsetup";
usbip = "${inputs.config.boot.kernelPackages.usbip}/bin/usbip";
2023-08-02 15:25:38 +08:00
sed = "${inputs.pkgs.gnused}/bin/sed";
awk = "${inputs.pkgs.gawk}/bin/awk";
2023-08-01 22:40:09 +08:00
decrypt = inputs.pkgs.writeShellScript "decrypt" (stripeTabs
"
modprobe vhci-hcd
busid=$(usbip list -r 127.0.0.1 | head -n4 | tail -n1 | awk '{print $1}' | sed 's/://')
usbip attach -r 127.0.0.1 -b $busid
2023-08-02 14:24:25 +08:00
${concatStringsSep "\n" (map
2023-08-02 14:42:02 +08:00
(device: ''systemd-cryptsetup attach ${device.value.mapper} ${device.name} "" fido2-device=auto''
+ (if device.value.ssd then ",discard" else ""))
2023-08-01 22:40:09 +08:00
(attrsToList fileSystems.decrypt.manual.devices))}
");
};
2023-08-02 14:42:02 +08:00
services.wait-manual-decrypt =
{
wantedBy = [ "initrd-root-fs.target" ];
2023-08-02 15:25:38 +08:00
before = [ "roll-rootfs.service" ];
2023-08-02 14:42:02 +08:00
unitConfig.DefaultDependencies = false;
serviceConfig.Type = "oneshot";
script = concatStringsSep "\n" (map
(device: "while [ ! -e /dev/mapper/${device.value.mapper} ]; do sleep 1; done")
(attrsToList fileSystems.decrypt.manual.devices));
};
2023-08-01 14:49:03 +08:00
};
};
2023-08-01 22:40:09 +08:00
fileSystems = listToAttrs (map
2023-08-02 14:24:25 +08:00
(mount: { name = mount; value.options = [ "x-systemd.device-timeout=15min" ]; })
fileSystems.decrypt.manual.delayedMount);
2023-08-01 14:49:03 +08:00
}
2023-08-01 13:05:10 +08:00
)
2023-07-26 23:36:12 +08:00
# mdadm
2023-07-21 13:52:04 +08:00
(
2023-07-26 23:36:12 +08:00
mkIf (fileSystems.mdadm != null)
2023-08-09 22:05:51 +08:00
{ boot.swraid = { enable = true; mdadmConf = fileSystems.mdadm; }; }
2023-07-26 23:36:12 +08:00
)
# swap
{ swapDevices = map (device: { device = device; }) fileSystems.swap; }
# resume
(
mkIf (fileSystems.resume != null) { boot =
(
if builtins.typeOf fileSystems.resume == "string" then
{ resumeDevice = fileSystems.resume; }
else
{
resumeDevice = fileSystems.resume.device;
kernelModules = [ "resume_offset=${fileSystems.resume.offset}" ];
}
);}
)
# rollingRootfs
(
mkIf (fileSystems.rollingRootfs != null)
2023-07-10 13:18:49 +08:00
{
2023-07-26 23:36:12 +08:00
boot.initrd.systemd.services.roll-rootfs =
{
2023-08-11 02:20:42 +08:00
wantedBy = [ "initrd.target" ];
2023-07-31 23:32:19 +08:00
after = [ "cryptsetup.target" "systemd-hibernate-resume.service" ];
before = [ "local-fs-pre.target" "sysroot.mount" ];
2023-07-26 23:36:12 +08:00
unitConfig.DefaultDependencies = false;
serviceConfig.Type = "oneshot";
script = let inherit (fileSystems.rollingRootfs) device path; in stripeTabs
"
mount ${device} /mnt -m
if [ -f /mnt${path}/current/.timestamp ]
then
mv /mnt${path}/current /mnt${path}/$(cat /mnt${path}/current/.timestamp)
fi
btrfs subvolume create /mnt${path}/current
echo $(date '+%Y%m%d%H%M%S') > /mnt${path}/current/.timestamp
umount /mnt
";
};
2023-07-10 13:18:49 +08:00
}
2023-07-26 23:36:12 +08:00
)
];
2023-07-09 12:39:03 +08:00
}
# Disable CoW for VM image and database:
# sudo chattr +C images
# zstd:15 cause sound stuttering
# From btrfs wiki: 1-3 are real-time, 4-8 slower with improved compression,
# 9-15 try even harder though the resulting size may not be significantly improved.
# https://btrfs.readthedocs.io/en/latest/Compression.html
# sudo btrfs filesystem resize -50G /nix
# sudo cryptsetup status root
# sudo cryptsetup -b 3787456512 resize root
# sudo cfdisk /dev/nvme1n1p3
# test on e20dae7d8b317f95718b5f4175bd4246c09735de mathematica ~15G
2023-08-21 20:57:15 +08:00
# zstd:15 5m33s 7.16G
# zstd:8 54s 7.32G
# zstd:3 17s 7.52G