From 669ca49ae4b1355e569db99dd3182d48c98979d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kier=C3=A1n=20Meinhardt?= Date: Wed, 8 Apr 2026 08:51:20 +0200 Subject: [PATCH 1/2] disk-deactivate: wipe raid arrays before stopping them Previously, the `disk-deactivate` script stopped mdadm arrays before wiping the underlying physical disks. This caused filesystems with backup superblocks (like BTRFS at 64 MiB and 256 GiB offsets) to survive the wipe, as the backups were striped across the physical disks and missed by `wipefs` on the raw block devices. When the array was reassembled during reprovisioning, the filesystem superblocks realigned. `disko` would detect the old filesystem via `blkid` and silently skip the `mkfs` step, leaving stale data intact. This commit adds a `wipefs --all` command against the assembled RAID device *before* stopping it, ensuring all filesystem signatures and backup superblocks are cleanly destroyed. --- disk-deactivate/disk-deactivate.jq | 1 + 1 file changed, 1 insertion(+) diff --git a/disk-deactivate/disk-deactivate.jq b/disk-deactivate/disk-deactivate.jq index 3e37b74..6a30375 100644 --- a/disk-deactivate/disk-deactivate.jq +++ b/disk-deactivate/disk-deactivate.jq @@ -60,6 +60,7 @@ def deactivate: ] elif (.type | contains("raid")) then [ + "wipefs --all -f \(.path | shellquote)", "mdadm --stop \(.name | shellquote)" ] else From dffa2001ceebdc570f49d4e4a70f38636568458d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kier=C3=A1n=20Meinhardt?= Date: Wed, 8 Apr 2026 10:19:58 +0200 Subject: [PATCH 2/2] add canary test for btrfs on mdadm wipes Adds a NixOS integration test to verify that the `disk-deactivate` script properly destroys BTRFS filesystems residing on mdadm RAID arrays. --- tests/mdadm-btrfs-wipe.nix | 130 +++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) create mode 100644 tests/mdadm-btrfs-wipe.nix diff --git a/tests/mdadm-btrfs-wipe.nix b/tests/mdadm-btrfs-wipe.nix new file mode 100644 index 0000000..86b47fd --- /dev/null +++ b/tests/mdadm-btrfs-wipe.nix @@ -0,0 +1,130 @@ +{ + pkgs, + ... +}: +let + inherit (pkgs) lib; + + diskoModule = ../module.nix; + + diskoConfig = { + disko.devices.disk = { + main = { + device = "/dev/vdb"; + type = "disk"; + content = { + type = "gpt"; + partitions = { + ESP = { + type = "EF00"; + size = "500M"; + content = { + type = "filesystem"; + format = "vfat"; + mountpoint = "/boot"; + mountOptions = [ "umask=0077" ]; + }; + }; + encryptedSwap = { + size = "100%"; + content = { + type = "swap"; + randomEncryption = true; + }; + }; + }; + }; + }; + } + // (lib.genAttrs [ "pool1" "pool2" ] (name: { + type = "disk"; + device = + { + pool1 = "/dev/vdc"; + pool2 = "/dev/vdd"; + } + .${name}; + content = { + type = "gpt"; + partitions.mdadm = { + size = "100%"; + content = { + type = "mdraid"; + name = "raid0"; + }; + }; + }; + })); + + disko.devices.mdadm.raid0 = { + type = "mdadm"; + level = 0; + content = { + type = "btrfs"; + extraArgs = [ "-f" ]; + mountpoint = "/"; + }; + }; + }; +in +pkgs.testers.runNixOSTest { + name = "disko-btrfs-mdadm-resurrection"; + + nodes.machine = + { config, pkgs, ... }: + { + imports = [ + diskoModule + diskoConfig + ]; + + boot.loader.grub.devices = [ "/dev/null" ]; + + virtualisation.emptyDiskImages = [ + 4096 + 4096 + 4096 + ]; + boot.swraid.enable = true; + environment.systemPackages = with pkgs; [ + mdadm + btrfs-progs + cryptsetup + parted + ]; + }; + + testScript = + { nodes, ... }: + let + inherit (nodes.machine.system.build) destroyScript formatScript mountScript; + in + '' + machine.wait_for_unit("multi-user.target") + + print("Running initial format and mount...") + machine.succeed("${formatScript}") + machine.succeed("${mountScript}") + + print("Writing canary file...") + machine.succeed("echo 'I survived the wipe!' > /mnt/canary.txt") + machine.succeed("sync") + + machine.succeed("umount -R /mnt") + + print("Running the destroy script...") + machine.execute("${destroyScript}") + + print("Attempting to reformat and remount...") + machine.execute("${formatScript}") + machine.execute("${mountScript}") + + print("Checking if the canary file is still there...") + status, output = machine.execute("cat /mnt/canary.txt") + + if status == 0 and "I survived the wipe!" in output: + raise Exception("The canary file survived the Disko wipe process!") + else: + print("Test passed: Data was successfully destroyed.") + ''; +}