Skip to content

Commit aa103e6

Browse files
committedMar 19, 2025
refactor: all the drive / storage and filesystem stuff
1 parent 7d3e605 commit aa103e6

20 files changed

+327
-298
lines changed
 

‎hosts/desktop/nixe/default.nix

-9
Original file line numberDiff line numberDiff line change
@@ -120,17 +120,8 @@
120120
};
121121

122122
host = {
123-
drive = {
124-
enable = true;
125-
126-
format = "btrfs";
127-
name = "Nix";
128-
};
129-
130123
persistence = {
131124
enable = true;
132-
type = "tmpfs";
133-
134125
directories = [
135126
"/var/lib/decky-loader"
136127
"/var/lib/private/ollama"

‎hosts/desktop/nixe/hardware.nix

+55-5
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
# TODO :: Auto subvolume setup
2-
{ inputs, pkgs, ... }:
1+
{
2+
inputs,
3+
pkgs,
4+
...
5+
}:
36
{
47
imports = [
58
inputs.nixos-hardware.nixosModules.common-cpu-amd
@@ -21,6 +24,19 @@
2124
productId = "0029";
2225
}
2326
];
27+
28+
storage = {
29+
enable = true;
30+
root = {
31+
label = "Nix";
32+
devPath = "/dev/disk/by-id/nvme-KINGSTON_SKC3000D2048G_50026B76857EB93E";
33+
ephemeral = {
34+
enable = true;
35+
type = "tmpfs";
36+
tmpfsSize = 16;
37+
};
38+
};
39+
};
2440
};
2541

2642
boot = rec {
@@ -57,8 +73,42 @@
5773
};
5874
};
5975

60-
fileSystems."/boot" = {
61-
device = "/dev/disk/by-partlabel/ESP";
62-
fsType = "vfat";
76+
fileSystems = {
77+
# "/boot" = {
78+
# device = "/dev/disk/by-partlabel/ESP";
79+
# fsType = "vfat";
80+
# };
81+
82+
# "/nix" = {
83+
# device = "/dev/disk/by-partlabel/Nix";
84+
# fsType = "btrfs";
85+
# options = [
86+
# "subvol=@store"
87+
# "noatime"
88+
# "compress=zstd"
89+
# ];
90+
# neededForBoot = true;
91+
# };
92+
93+
# "/persist" = {
94+
# device = "/dev/disk/by-partlabel/Nix";
95+
# fsType = "btrfs";
96+
# options = [
97+
# "subvol=@persist"
98+
# "compress=zstd"
99+
# ];
100+
# neededForBoot = true;
101+
# };
102+
103+
# "/" = {
104+
# device = "none";
105+
# fsType = "tmpfs";
106+
# options = [
107+
# "defaults"
108+
# "size=16G"
109+
# "mode=755"
110+
# ];
111+
# neededForBoot = false;
112+
# };
63113
};
64114
}

‎hosts/desktop/nixmi/default.nix

-10
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
{
88
imports = [
99
inputs.jovian.nixosModules.default
10-
inputs.disko.nixosModules.disko
1110

1211
./hardware.nix
1312

@@ -121,17 +120,8 @@
121120
};
122121

123122
host = {
124-
drive = {
125-
enable = true;
126-
127-
format = "btrfs";
128-
name = "Nix";
129-
};
130-
131123
persistence = {
132124
enable = true;
133-
type = "tmpfs";
134-
135125
directories = [
136126
"/var/lib/decky-loader"
137127
"/var/lib/private/ollama"

‎hosts/desktop/nixmi/hardware.nix

+12-6
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
{
2-
flake,
32
inputs,
43
pkgs,
54
...
@@ -10,17 +9,24 @@
109
inputs.nixos-hardware.nixosModules.common-cpu-amd-pstate
1110
inputs.nixos-hardware.nixosModules.common-pc-ssd
1211
inputs.nixos-hardware.nixosModules.common-hidpi
13-
14-
(import "${flake}/hosts/shared/disks/btrfs-luks-disk.nix" {
15-
disk = "/dev/nvme0n1"; # FIXME :: Placeholder, replace with /dev/disk/by-id/...
16-
withSwap = false;
17-
})
1812
];
1913

2014
hardware = {
2115
graphics.manufacturer = "nvidia";
2216
backlight.enable = true;
2317
cooling.enable = true;
18+
19+
storage = {
20+
enable = true;
21+
root = {
22+
devPath = "/dev/nvme0n1"; # FIXME :: Placeholder, replace with /dev/disk/by-id/...
23+
ephemeral = {
24+
enable = true;
25+
type = "tmpfs";
26+
tmpfsSize = 16;
27+
};
28+
};
29+
};
2430
};
2531

2632
boot = rec {

‎hosts/shared/disks/btrfs-disk.nix

-42
This file was deleted.

‎hosts/shared/disks/btrfs-luks-disk.nix

-65
This file was deleted.

‎hosts/shared/disks/neededForBoot.nix

-16
This file was deleted.

‎lib/builders/system/mkRaw.nix

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ rec {
2727
imports = [
2828
inputs.home-manager.nixosModules.default
2929
inputs.angrr.nixosModules.angrr
30+
inputs.disko.nixosModules.disko
3031
];
3132

3233
host = {

‎modules/nixos/hardware/default.nix

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ let
1010
in
1111
{
1212
imports = [
13+
./storage
1314
./backlight.nix
1415
./biometrics.nix
1516
./bluetooth.nix
+102
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
{ config, lib, ... }:
2+
let
3+
cfg = config.hardware.storage;
4+
in
5+
{
6+
imports = [
7+
./ephemeral.nix
8+
./luks.nix
9+
./maintenance.nix
10+
];
11+
12+
options.hardware.storage = {
13+
enable = lib.mkEnableOption "storage management";
14+
15+
root = lib.mkOption {
16+
default = { };
17+
type = lib.types.submodule {
18+
options = {
19+
enableLuks = lib.mkEnableOption "use LUKS encryption";
20+
21+
label = lib.mkOption {
22+
type = lib.types.str;
23+
default = "root";
24+
description = ''
25+
The label of the root partition.
26+
'';
27+
};
28+
29+
name = lib.mkOption {
30+
type = lib.types.str;
31+
default = config.networking.hostName;
32+
description = ''
33+
The name of the root device for usage within disko.
34+
'';
35+
};
36+
37+
devPath = lib.mkOption {
38+
type = lib.types.str;
39+
description = ''
40+
The path to the device to use as the root device.
41+
'';
42+
};
43+
44+
physicalSwap = lib.mkOption {
45+
default = { };
46+
type = lib.types.submodule {
47+
options = {
48+
enable = lib.mkEnableOption "physical swap";
49+
size = lib.mkOption {
50+
type = lib.types.int;
51+
default = 2;
52+
description = ''
53+
The size of the swap partition in GiB.
54+
'';
55+
};
56+
};
57+
};
58+
};
59+
};
60+
};
61+
};
62+
63+
withImpermanence = lib.mkOption {
64+
type = lib.types.bool;
65+
readOnly = true;
66+
default =
67+
config.environment.persistence ? "/persist" && config.environment.persistence."/persist".enable;
68+
};
69+
};
70+
71+
config = lib.mkIf cfg.enable {
72+
disko.devices = {
73+
disk."${cfg.root.name}" = {
74+
type = "disk";
75+
device = cfg.root.devPath;
76+
content = {
77+
type = "gpt";
78+
partitions = {
79+
ESP = import ./partitions/esp.nix;
80+
81+
root = lib.mkIf (!cfg.root.enableLuks) {
82+
size = "100%";
83+
inherit (cfg.root) label;
84+
content = import ./partitions/btrfs.nix { inherit config lib; };
85+
};
86+
87+
luks = lib.mkIf cfg.root.enableLuks {
88+
size = "100%";
89+
inherit (cfg.root) label;
90+
content = import ./partitions/luks.nix { inherit config lib; };
91+
};
92+
};
93+
};
94+
};
95+
};
96+
97+
fileSystems = {
98+
"/persist" = lib.mkIf cfg.withImpermanence { neededForBoot = true; };
99+
"/nix".neededForBoot = true;
100+
};
101+
};
102+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
{ config, lib, ... }:
2+
let
3+
cfg = config.hardware.storage.root;
4+
in
5+
{
6+
options.hardware.storage.root.ephemeral = {
7+
enable = lib.mkEnableOption "usage of an ephemeral root that is reset on boot";
8+
9+
type = lib.mkOption {
10+
type = lib.types.enum [
11+
"btrfs"
12+
"tmpfs"
13+
];
14+
description = ''
15+
The type of ephemeral root to use.
16+
'';
17+
};
18+
19+
tmpfsSize = lib.mkOption {
20+
type = lib.types.int;
21+
default = 4;
22+
description = ''
23+
The size of the tmpfs root in GiB.
24+
'';
25+
};
26+
27+
paritionLabel = lib.mkOption {
28+
type = lib.types.str;
29+
readOnly = true;
30+
default =
31+
let
32+
inherit (config.disko.devices.disk."${config.hardware.storage.root.name}".content) partitions;
33+
partition = if cfg.enableLuks then partitions.luks else partitions.root;
34+
in
35+
lib.stringAfter "/dev/disk/by-partlabel/" partition.label;
36+
};
37+
};
38+
39+
config = lib.mkIf cfg.ephemeral.enable {
40+
disko.devices = {
41+
nodev."/" = lib.mkIf (cfg.ephemeral.type == "tmpfs") (
42+
import ./partitions/tmpfs.nix { size = cfg.ephemeral.tmpfsSize; }
43+
);
44+
};
45+
46+
boot.initrd =
47+
let
48+
phase1Systemd = config.boot.initrd.systemd.enable;
49+
wipeScript = ''
50+
mkdir /tmp -p
51+
MNTPOINT=$(mktemp -d)
52+
(
53+
mount -t btrfs -o subvol=/ /dev/disk/by-partlabel/${cfg.ephemeral.paritionLabel} "$MNTPOINT"
54+
trap 'umount "$MNTPOINT"' EXIT
55+
56+
echo "Creating needed directories"
57+
mkdir -p "$MNTPOINT"/@persist/var/{log,lib/{nixos,systemd}}
58+
59+
echo "Cleaning root subvolume"
60+
btrfs subvolume list -o "$MNTPOINT/@root" | cut -f9 -d ' ' |
61+
while read -r subvolume; do
62+
btrfs subvolume delete "$MNTPOINT/$subvolume"
63+
done && btrfs subvolume delete "$MNTPOINT/@root"
64+
65+
echo "Restoring blank subvolume"
66+
btrfs subvolume snapshot "$MNTPOINT/@root-blank" "$MNTPOINT/@root"
67+
)
68+
'';
69+
in
70+
lib.mkIf (cfg.ephemeral.type == "btrfs") {
71+
supportedFilesystems = [ "btrfs" ];
72+
postDeviceCommands = lib.mkIf (!phase1Systemd) (lib.mkBefore wipeScript);
73+
systemd.services.restore-root = lib.mkIf phase1Systemd {
74+
description = "Rollback btrfs rootfs";
75+
wantedBy = [ "initrd.target" ];
76+
requires = [ "dev-disk-by\\x2dpartlabel-${cfg.ephemeral.paritionLabel}.device" ];
77+
after = [
78+
"dev-disk-by\\x2dpartlabel-${cfg.ephemeral.paritionLabel}.device"
79+
"systemd-cryptsetup@${cfg.ephemeral.paritionLabel}.service"
80+
];
81+
before = [ "sysroot.mount" ];
82+
unitConfig.DefaultDependencies = "no";
83+
serviceConfig.Type = "oneshot";
84+
script = wipeScript;
85+
};
86+
};
87+
};
88+
}
+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{ config, lib, ... }:
2+
let
3+
cfg = config.hardware.storage;
4+
in
5+
{
6+
options.hardware.storage.luks = {
7+
enable = lib.mkEnableOption "usage of LUKS encrypted storage";
8+
};
9+
10+
config = lib.mkIf cfg.luks.enable {
11+
disko.devices.disk.${cfg.root.name}.content.partitions.luks = {
12+
13+
};
14+
};
15+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{ config, lib, ... }:
2+
let
3+
cfg = config.hardware.storage;
4+
in
5+
{
6+
options.hardware.storage.maintenance = {
7+
enable = lib.mkEnableOption "storage device maintenance";
8+
};
9+
10+
config = lib.mkIf cfg.maintenance.enable {
11+
services.btrfs.autoScrub = {
12+
enable = true;
13+
fileSystems =
14+
builtins.attrNames
15+
config.disko.devices.disk.${cfg.root.name}.content.partitions.root.content.subvolumes;
16+
interval = "Wed *-*-* 02:00:00";
17+
};
18+
};
19+
}

‎hosts/shared/disks/partitions/btrfs.nix ‎modules/nixos/hardware/storage/partitions/btrfs.nix

+8-12
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,17 @@
11
{
22
config,
33
lib,
4-
5-
withSwap ? false,
6-
swapSize ? 0,
7-
8-
withImpermanence ?
9-
config.environment.persistence ? "/persist" && config.environment.persistence."/persist".enable,
10-
11-
...
124
}:
5+
let
6+
cfg = config.hardware.storage;
7+
in
138
{
149
type = "btrfs";
1510
extraArgs = [ "-f" ]; # force overwrite
1611
subvolumes =
1712
{
18-
"@root" = lib.mkIf (!withImpermanence) {
13+
# Only enable if not using ephemeral root or if using snapshotted root
14+
"@root" = lib.mkIf (!cfg.root.ephemeral.enable || cfg.root.ephemeral.type == "btrfs") {
1915
mountpoint = "/";
2016
mountOptions = [ "compress=zstd" ];
2117
};
@@ -28,12 +24,12 @@
2824
];
2925
};
3026

31-
"@swap" = lib.mkIf withSwap {
27+
"@swap" = lib.mkIf cfg.root.physicalSwap.enable {
3228
mountpoint = "/.swapvol";
33-
swap.swapfile.size = swapSize;
29+
swap.swapfile.size = "${cfg.root.physicalSwap.size}GiB";
3430
};
3531
}
36-
// (lib.optionalAttrs withImpermanence {
32+
// (lib.optionalAttrs cfg.withImpermanence {
3733
"@persist" = {
3834
mountpoint = "/persist";
3935
mountOptions = [ "compress=zstd" ];

‎hosts/shared/disks/partitions/esp.nix ‎modules/nixos/hardware/storage/partitions/esp.nix

-7
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
11
{
2-
name ? "ESP",
3-
4-
...
5-
}:
6-
{
7-
inherit name;
8-
92
priority = 1;
103
size = "512M";
114
type = "EF00";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
config,
3+
lib,
4+
}:
5+
{
6+
type = "luks";
7+
name = "encrypted-nixos";
8+
passwordFile = "/tmp/disko-password"; # this is populated by bootstrap-nixos.sh
9+
extraOpenArgs = [
10+
"--perf-no_read_workqueue"
11+
"--perf-no_write_workqueue"
12+
];
13+
settings = {
14+
allowDiscards = true;
15+
# https://github.com/hmajid2301/dotfiles/blob/a0b511c79b11d9b4afe2a5e2b7eedb2af23e288f/systems/x86_64-linux/framework/disks.nix#L36
16+
crypttabExtraOpts = [
17+
"fido2-device=auto"
18+
"token-timeout=10"
19+
];
20+
};
21+
22+
content = import ./btrfs.nix { inherit config lib; };
23+
}

‎hosts/shared/disks/partitions/tmpfs.nix ‎modules/nixos/hardware/storage/partitions/tmpfs.nix

+2-6
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,8 @@
1-
{
2-
size ? "2G",
3-
4-
...
5-
}:
1+
{ size }:
62
{
73
fsType = "tmpfs";
84
mountOptions = [
9-
"size=${size}"
5+
"size=${toString size}G"
106
"defaults"
117
"mode=755"
128
];

‎modules/nixos/host/default.nix

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ in
66
{
77
imports = [
88
./device.nix
9-
./drive.nix
109
./persistence.nix
1110
];
1211

‎modules/nixos/host/drive.nix

-32
This file was deleted.

‎modules/nixos/host/persistence.nix

+1-87
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ with lib;
88
with types;
99
let
1010
cfg = config.host.persistence;
11-
inherit (config.host) drive;
1211

1312
defaultPerms = {
1413
mode = "0755";
@@ -160,19 +159,12 @@ in
160159
root = mkOption {
161160
type = str;
162161
default = "/persist";
162+
readOnly = true;
163163
description = ''
164164
The root directory for the host's persistent state.
165165
'';
166166
};
167167

168-
type = mkOption {
169-
type = enum [
170-
"tmpfs"
171-
"snapshot"
172-
];
173-
default = "tmpfs";
174-
};
175-
176168
files = mkOption {
177169
type = listOf (coercedTo str (f: { file = f; }) rootFile);
178170
default = [ ];
@@ -250,84 +242,6 @@ in
250242
];
251243
};
252244

253-
fileSystems = {
254-
"/persist" = {
255-
device = "/dev/disk/by-partlabel/${drive.name}";
256-
fsType = drive.format;
257-
options = [
258-
"subvol=@persist"
259-
"compress=zstd"
260-
];
261-
neededForBoot = true;
262-
};
263-
264-
"/" = {
265-
device = if cfg.type == "tmpfs" then "none" else "/dev/disk/by-partlabel/${drive.name}";
266-
fsType = if cfg.type == "tmpfs" then "tmpfs" else drive.format;
267-
options =
268-
if cfg.type == "tmpfs" then
269-
[
270-
"defaults"
271-
"size=16G"
272-
"mode=755"
273-
]
274-
else
275-
[
276-
"subvol=@root"
277-
"compress=zstd"
278-
];
279-
neededForBoot = if cfg.type == "tmpfs" then false else true;
280-
};
281-
};
282-
283-
boot.initrd =
284-
let
285-
phase1Systemd = config.boot.initrd.systemd.enable;
286-
wipeScript = ''
287-
mkdir /tmp -p
288-
MNTPOINT=$(mktemp -d)
289-
(
290-
mount -t btrfs -o subvol=/ /dev/disk/by-partlabel/${drive.name} "$MNTPOINT"
291-
trap 'umount "$MNTPOINT"' EXIT
292-
293-
echo "Creating needed directories"
294-
mkdir -p "$MNTPOINT"/@persist/var/{log,lib/{nixos,systemd}}
295-
296-
echo "Cleaning root subvolume"
297-
btrfs subvolume list -o "$MNTPOINT/@root" | cut -f9 -d ' ' |
298-
while read -r subvolume; do
299-
btrfs subvolume delete "$MNTPOINT/$subvolume"
300-
done && btrfs subvolume delete "$MNTPOINT/@root"
301-
302-
echo "Restoring blank subvolume"
303-
btrfs subvolume snapshot "$MNTPOINT/@root-blank" "$MNTPOINT/@root"
304-
)
305-
'';
306-
in
307-
mkIf (drive.format == "btrfs" && cfg.type == "snapshot") {
308-
supportedFilesystems = [ "btrfs" ];
309-
postDeviceCommands = lib.mkIf (!phase1Systemd) (mkBefore wipeScript);
310-
systemd.services.restore-root = mkIf phase1Systemd {
311-
description = "Rollback btrfs rootfs";
312-
wantedBy = [ "initrd.target" ];
313-
requires = [ "dev-disk-by\\x2dpartlabel-${drive.name}.device" ];
314-
after = [
315-
"dev-disk-by\\x2dpartlabel-${drive.name}.device"
316-
"systemd-cryptsetup@${drive.name}.service"
317-
];
318-
before = [ "sysroot.mount" ];
319-
unitConfig.DefaultDependencies = "no";
320-
serviceConfig.Type = "oneshot";
321-
script = wipeScript;
322-
};
323-
};
324-
325-
services.btrfs.autoScrub = mkIf (drive.format == "btrfs") {
326-
enable = mkDefault false;
327-
fileSystems = [ "/persist" ];
328-
interval = "Wed *-*-* 02:00:00";
329-
};
330-
331245
# services.snapper.configs = mkIf (drive.format == "btrfs") (builtins.foldl' recursiveUpdate { }
332246
# ([{
333247
# persist = {

0 commit comments

Comments
 (0)
Please sign in to comment.