Repository: tiiuae/ghaf
Pull request #1005: disko: use ext4 and btrfs for debug builds
Author: login: humaidq-tii
Labels: name: Tested on Orin AGX
description: This PR has been tested on NVIDIA Jetson AGX Orin
name: Tested on Orin NX
description: This PR has been tested on NVIDIA Jetson NX Orin
name: Tested on Lenovo X1 Carbon
description: This PR has been tested on Lenovo X1 Carbon
Created: 2025-02-10T10:07:39Z | Merged: 2025-03-06T10:01:16Z

<!--
    Copyright 2023 TII (SSRC) and the Ghaf contributors
    SPDX-License-Identifier: CC-BY-SA-4.0
-->

## Description of changes

This is the first phase to an image based disk installation for Ghaf. The disko image would only be used for debug systems in the future.

This PR removes the A/B partitioning scheme layout with a more simplified one that would match the image based Ghaf system.

- Only 1GB VM size needed instead of 18GB+
- ext4 will be used for the root
- btrfs will be used for the persistence partition (which includes storagevm)
- Removed other unused partitions
- Performance improvements expected (not measured)

A/B Partitioning scheme will be added in the next PR.


<!--
Summary of the proposed changes in the PR description in your own words. For dependency updates, please link to the changelog.
-->

## Checklist for things done

<!-- Please check, [X], to all that applies. Leave [ ] if an item does not apply but you have considered the check list item. Note that all of these are not hard requirements. They serve information to reviewers. When you fill the checklist, you indicate to reviewers you appreciate their work. -->

- [x] Summary of the proposed changes in the PR description
- [x] More detailed description in the commit message(s)
- [x] Commits are squashed into relevant entities - avoid a lot of minimal dev time commits in the PR
- [x] [Contribution guidelines](https://github.com/tiiuae/ghaf/blob/main/CONTRIBUTING.md) followed
- [ ] Ghaf documentation updated with the commit - https://tiiuae.github.io/ghaf/
- [ ] PR linked to architecture documentation and requirement(s) (ticket id)
- [ ] Test procedure described (or includes tests). Select one or more:
  - [x] Tested on Lenovo X1 `x86_64`
  - [ ] Tested on Jetson Orin NX or AGX `aarch64`
  - [ ] Tested on Polarfire `riscv64`
- [ ] Author has run `make-checks` and it passes
- [ ] All automatic Github Action checks pass - see [actions](https://github.com/tiiuae/ghaf/actions)
- [ ] Author has added reviewers and removed PR draft status
- [x] Change requires full re-installation
- [ ] Change can be updated with `nixos-rebuild ... switch`: NO

<!-- Additional description of omitted [ ] items if not obvious. -->

## Instructions for Testing

Fresh install needed. Build time should be faster.

- [x] List all targets that this applies to: lenovo, dell targets
- [ ] Is this a new feature: no
  - [ ] List the test steps to verify: Install system, persistence should work, system should be stable, persist partition in host should use full space.
- [x] If it is an improvement how does it impact existing functionality? No noticeable impact on user functionality.




Diff:
diff --git a/modules/common/users/desktop.nix b/modules/common/users/desktop.nix
index 48022829e1..efb8985117 100644
--- a/modules/common/users/desktop.nix
+++ b/modules/common/users/desktop.nix
@@ -204,6 +204,7 @@ in
                   --skel=/etc/skel \
                   --storage=luks \
                   --luks-pbkdf-type=argon2id \
+                  --fs-type=btrfs \
                   --enforce-password-policy=true \
                   --drop-caches=true \
                   --nosuid=true \
diff --git a/modules/disko/disko-ab-partitions.nix b/modules/disko/disko-ab-partitions.nix
deleted file mode 100644
index 8dc2801fa4..0000000000
--- a/modules/disko/disko-ab-partitions.nix
+++ /dev/null
@@ -1,166 +0,0 @@
-# Copyright 2022-2024 TII (SSRC) and the Ghaf contributors
-# SPDX-License-Identifier: Apache-2.0
-#
-# This partition scheme contains three common partitions and ZFS pool.
-# Some partitions are duplicated for the future AB SWupdate implementation.
-#
-# First two partitions are related to the boot process:
-# - boot : Bootloader partition
-# - ESP-A : (500M) Kernel and initrd
-#
-# ZFS datasets do not necessary need to have specified size and can be
-# allocated dynamically. Quotas only restrict the maximum size of
-# datasets, but do not reserve the space in the pool.
-# The ZFS pool contains next datasets:
-# - root : (30G) Root FS
-# - vm-storage : (30G) Possible standalone pre-built VM images are stored here
-# - reserved : (10G) Reserved dataset, no use
-# - gp-storage : (50G) General purpose storage for some common insecure cases
-# - recovery : (no quota) Recovery factory image is stored here
-# - storagevm: (no quota) Dataset is meant to be used for StorageVM
-{
-  pkgs,
-  lib,
-  config,
-  ...
-}:
-{
-
-  options = {
-    ghaf.imageBuilder.compression = lib.mkOption {
-      type = lib.types.enum [
-        "none"
-        "zstd"
-      ];
-      description = "Compression algorithm used for the install image";
-      default = "zstd";
-    };
-  };
-  config = {
-    # TODO Keep ZFS-related parts of the configuration here for now.
-    # This allows to have all config dependencies in one place and cleans
-    # other targets' configs from unnecessary components.
-    networking.hostId = "8425e349";
-    boot = {
-      initrd.availableKernelModules = [ "zfs" ];
-      supportedFilesystems = [ "zfs" ];
-    };
-    disko = {
-      # 8GB is the recommeneded minimum for ZFS, so we are using this for VMs to avoid `cp` oom errors.
-      memSize = 18432;
-      imageBuilder = {
-        extraPostVM = lib.mkIf (config.ghaf.imageBuilder.compression == "zstd") ''
-          ${pkgs.zstd}/bin/zstd --compress $out/*raw
-          rm $out/*raw
-        '';
-      };
-      devices = {
-        disk.disk1 = {
-          type = "disk";
-          imageSize = "60G";
-          content = {
-            type = "gpt";
-            partitions = {
-              boot = {
-                name = "boot";
-                size = "1M";
-                type = "EF02";
-                priority = 1; # Needs to be first partition
-              };
-              esp = {
-                name = "ESP";
-                size = "500M";
-                type = "EF00";
-                content = {
-                  type = "filesystem";
-                  format = "vfat";
-                  mountpoint = "/boot";
-                  mountOptions = [
-                    "umask=0077"
-                    "nofail"
-                  ];
-                };
-              };
-              swap = {
-                size = "38G";
-                type = "8200";
-                content = {
-                  type = "swap";
-                  resumeDevice = true; # resume from hiberation from this device
-                  # TODO: remove when LUKS is enabled
-                  #randomEncryption = true;
-                };
-              };
-              zfs_1 = {
-                size = "100%";
-                content = {
-                  type = "zfs";
-                  pool = "zfspool";
-                };
-              };
-            };
-          };
-        };
-        zpool = {
-          zfspool = {
-            type = "zpool";
-            rootFsOptions = {
-              mountpoint = "none";
-              acltype = "posixacl";
-              compression = "lz4";
-              xattr = "sa";
-            };
-            # `ashift=12` optimizes alignment for 4K sector size.
-            # Since this is an generic image and people might upgrade from one nvme device to another,
-            # we should make sure it runs well on these devices, also in theory 512B would work with less.
-            # This trades off some space overhead for overall better performance on 4k devices.
-            options.ashift = "12";
-            datasets = {
-              "root" = {
-                type = "zfs_fs";
-                mountpoint = "/";
-                options = {
-                  mountpoint = "/";
-                  quota = "30G";
-                };
-              };
-              "vm_storage" = {
-                type = "zfs_fs";
-                options = {
-                  mountpoint = "/vm_storage";
-                  quota = "30G";
-                };
-              };
-              "reserved" = {
-                type = "zfs_fs";
-                options = {
-                  mountpoint = "none";
-                  quota = "10G";
-                };
-              };
-              "gp_storage" = {
-                type = "zfs_fs";
-                options = {
-                  mountpoint = "/gp_storage";
-                  quota = "50G";
-                };
-              };
-              "recovery" = {
-                type = "zfs_fs";
-                options = {
-                  mountpoint = "none";
-                };
-              };
-              "storagevm" = {
-                type = "zfs_fs";
-                options = {
-                  mountpoint = "/storagevm";
-                };
-              };
-            };
-          };
-        };
-      };
-    };
-  };
-}
diff --git a/modules/disko/disko-basic-partition-v1.nix b/modules/disko/disko-basic-partition-v1.nix
deleted file mode 100644
index bedca85f8a..0000000000
--- a/modules/disko/disko-basic-partition-v1.nix
+++ /dev/null
@@ -1,71 +0,0 @@
-# Copyright 2022-2023 TII (SSRC) and the Ghaf contributors
-# SPDX-License-Identifier: Apache-2.0
-# Example to create a bios compatible gpt partition
-# To use this example, you will need to specify a device i.e.
-#   { disko.devices.disk1.device = "/dev/sda"; }
-{ pkgs, ... }:
-{
-  disko.devices = {
-    disk.disk1 = {
-      type = "disk";
-      #TODO: hardcoding the size for now until 544 is merged
-      #https://github.com/nix-community/disko/pull/544
-      imageSize = "15G";
-      content = {
-        type = "gpt";
-        partitions = {
-          boot = {
-            name = "boot";
-            size = "1M";
-            type = "EF02";
-          };
-          esp = {
-            name = "ESP";
-            size = "500M";
-            type = "EF00";
-            content = {
-              type = "filesystem";
-              format = "vfat";
-              mountpoint = "/boot";
-              mountOptions = [ "umask=0077" ];
-            };
-          };
-          root = {
-            name = "root";
-            size = "100%";
-            content = {
-              type = "lvm_pv";
-              vg = "pool";
-            };
-          };
-        };
-      };
-    };
-    lvm_vg = {
-      pool = {
-        type = "lvm_vg";
-        lvs = {
-          root = {
-            size = "100%FREE";
-            content = {
-              type = "filesystem";
-              format = "ext4";
-              mountpoint = "/";
-              mountOptions = [ "defaults" ];
-            };
-          };
-          #TODO has to add the /storagevm partition or a folder in order for the impermanence to work.
-        };
-      };
-    };
-  };
-  disko = {
-    memSize = 4096;
-    imageBuilder = {
-      extraPostVM = ''
-        ${pkgs.zstd}/bin/zstd --compress $out/*raw
-        rm $out/*raw
-      '';
-    };
-  };
-}
diff --git a/modules/disko/disko-basic-postboot.nix b/modules/disko/disko-basic-postboot.nix
deleted file mode 100644
index cb601b9d35..0000000000
--- a/modules/disko/disko-basic-postboot.nix
+++ /dev/null
@@ -1,64 +0,0 @@
-# Copyright 2022-2024 TII (SSRC) and the Ghaf contributors
-# SPDX-License-Identifier: Apache-2.0
-{ pkgs, ... }:
-let
-  postBootCmds = ''
-    set -xeuo pipefail
-
-    readarray -t partitions <<<"$(${pkgs.util-linux}/bin/lsblk -np -o PATH,MAJ:MIN,PKNAME,MOUNTPOINT)"
-
-    # Find out the root partition in a loop, and its LVM pool parent disk
-    for p in "''${partitions[@]}"
-    do
-            P_DEVPATH=$(echo "$p" | ${pkgs.gawk}/bin/awk '{print $1}')
-            P_PKNAME=$(echo "$p" | ${pkgs.gawk}/bin/awk '{print $3}')
-            P_MOUNTPOINT=$(echo "$p" | ${pkgs.gawk}/bin/awk '{print $4}')
-
-            [[ "$P_MOUNTPOINT" == "/" ]] && {
-                    FOUND=1
-                    DEVPATH="$P_DEVPATH"
-                    PKNAME="$P_PKNAME"
-            }
-    done
-
-    # If root partition was not found, exit at this point, but still return 0, so
-    # it won't stop device from booting.
-    [[ "$FOUND" != 1 ]] && echo "Did not find root partition" && exit 0
-
-    # Find parent device of the root partition
-    for p in "''${partitions[@]}"
-    do
-            P_DEVPATH=$(echo "$p" | ${pkgs.gawk}/bin/awk '{print $1}')
-            P_MAJMIN=$(echo "$p" | ${pkgs.gawk}/bin/awk '{print $2}')
-            P_PKNAME=$(echo "$p" | ${pkgs.gawk}/bin/awk '{print $3}')
-
-            [[ "$P_DEVPATH" == "$PKNAME" ]] && {
-                    FOUND_PARENT=1
-                    PARENT_DISK="$P_PKNAME"
-                    PARTNUM=$(echo "$P_MAJMIN" | ${pkgs.gawk}/bin/awk -F: '{print $2}')
-            }
-    done
-
-    # If boot device was not found, exit at this point, but still return 0, so it
-    # won't stop device from booting.
-    [[ "$FOUND_PARENT" != 1 ]] && echo "Did not find boot device" && exit 0
-
-    # First enlarge the physical volume on the disk
-    echo ",+," | ${pkgs.util-linux}/bin/sfdisk -N"$PARTNUM" --no-reread "$PARENT_DISK"
-
-    # Call partprobe to update kernel's partitions
-    ${pkgs.parted}/bin/partprobe
-
-    # Extend the phyiscal volume
-    ${pkgs.lvm2.bin}/bin/pvresize "$PKNAME"
-
-    # Extend the logical volume
-    ${pkgs.lvm2.bin}/bin/lvextend --noudevsync -l +100%FREE "$DEVPATH"
-
-    # Finally resize the filesystem inside the logical volume
-    ${pkgs.e2fsprogs}/bin/resize2fs "$DEVPATH"
-  '';
-in
-{
-  boot.postBootCommands = postBootCmds;
-}
diff --git a/modules/disko/disko-debug-partition.nix b/modules/disko/disko-debug-partition.nix
new file mode 100644
index 0000000000..9bfffb9018
--- /dev/null
+++ b/modules/disko/disko-debug-partition.nix
@@ -0,0 +1,110 @@
+# Copyright 2022-2024 TII (SSRC) and the Ghaf contributors
+# SPDX-License-Identifier: Apache-2.0
+#
+#
+# This partition scheme is used for development & debug systems. It contains
+# four partitions.
+#
+# First two partitions are related to the boot process:
+# - boot : Bootloader partition
+# - ESP-A : (500M) Kernel and initrd
+#
+# Which is followed by the data partitions:
+# - root : Root partition which contains the Nix store
+# - persist : Persistence partition for system & user data
+{
+  pkgs,
+  lib,
+  config,
+  ...
+}:
+{
+
+  options = {
+    ghaf.imageBuilder.compression = lib.mkOption {
+      type = lib.types.enum [
+        "none"
+        "zstd"
+      ];
+      description = "Compression algorithm used for the install image";
+      default = "zstd";
+    };
+  };
+  config = {
+    disko = {
+      imageBuilder = {
+        extraPostVM = lib.mkIf (config.ghaf.imageBuilder.compression == "zstd") ''
+          ${pkgs.zstd}/bin/zstd --compress $out/*raw
+          rm $out/*raw
+        '';
+      };
+      devices = {
+        disk.disk1 = {
+          type = "disk";
+          imageSize = "60G";
+          content = {
+            type = "gpt";
+            partitions = {
+              boot = {
+                name = "boot";
+                size = "1M";
+                type = "EF02";
+                priority = 1; # Needs to be first partition
+              };
+              esp = {
+                name = "ESP";
+                size = "500M";
+                type = "EF00";
+                content = {
+                  type = "filesystem";
+                  format = "vfat";
+                  mountpoint = "/boot";
+                  mountOptions = [
+                    "umask=0077"
+                    "nofail"
+                  ];
+                };
+                priority = 2;
+              };
+              swap = {
+                size = "12G";
+                type = "8200";
+                content = {
+                  type = "swap";
+                  resumeDevice = true; # resume from hiberation from this device
+                  randomEncryption = true;
+                };
+                priority = 3;
+              };
+              root = {
+                size = "40G";
+                content = {
+                  type = "filesystem";
+                  format = "ext4";
+                  mountpoint = "/";
+                  mountOptions = [
+                    "noatime"
+                    "nodiratime"
+                  ];
+                };
+                priority = 4;
+              };
+              persist = {
+                size = "100%";
+                content = {
+                  type = "filesystem";
+                  format = "btrfs";
+                  mountpoint = "/persist";
+                  mountOptions = [
+                    "noatime"
+                    "nodiratime"
+                  ];
+                };
+              };
+            };
+          };
+        };
+      };
+    };
+  };
+}
diff --git a/modules/disko/disko-postboot.nix b/modules/disko/disko-postboot.nix
new file mode 100644
index 0000000000..434a5295f9
--- /dev/null
+++ b/modules/disko/disko-postboot.nix
@@ -0,0 +1,63 @@
+# Copyright 2022-2024 TII (SSRC) and the Ghaf contributors
+# SPDX-License-Identifier: Apache-2.0
+{ pkgs, ... }:
+let
+  postBootCmds = ''
+    set -xeuo pipefail
+
+    # Check which physical disk is used by btrfs
+    # TODO use a label in case there are more than one btrfs partitions/subvolumes
+    BTRFS_LOCATION=$(${pkgs.btrfs-progs}/bin/btrfs fi show | ${pkgs.gnugrep}/bin/grep \/dev | ${pkgs.gawk}/bin/awk '{print $8}')
+
+    # Get the actual device path
+    P_DEVPATH=$(readlink -f "$BTRFS_LOCATION")
+
+    # Extract the partition number using regex
+    if [[ "$P_DEVPATH" =~ [0-9]+$ ]]; then
+      PARTNUM=$(echo "$P_DEVPATH" | ${pkgs.gnugrep}/bin/grep -o '[0-9]*$')
+      PARENT_DISK=/dev/$(${pkgs.util-linux}/bin/lsblk -no pkname "$P_DEVPATH")
+    else
+      echo "No partition number found in device path: $P_DEVPATH"
+    fi
+
+    # Fix GPT first
+    ${pkgs.gptfdisk}/bin/sgdisk "$PARENT_DISK" -e
+
+    # Call partprobe to update kernel's partitions
+    ${pkgs.parted}/bin/partprobe
+
+    # Extend the partition to use unallocated space
+    ${pkgs.parted}/bin/parted -s -a opt "$PARENT_DISK" "resizepart $PARTNUM 100%"
+  '';
+in
+{
+  # To debug postBootCommands, one may run
+  # journalctl -u initrd-nixos-activation.service
+  # inside the running Ghaf host.
+  boot.postBootCommands = postBootCmds;
+
+  systemd.services.extendbtrfs =
+    let
+      extendbtrfs = pkgs.writeShellApplication {
+        name = "extendbtrfs";
+        runtimeInputs = [ pkgs.btrfs-progs ];
+        text = ''
+          # Extend btrfs to use newly allocated space
+          ${pkgs.btrfs-progs}/bin/btrfs filesystem resize max /persist
+        '';
+      };
+    in
+    {
+      enable = true;
+      description = "Extend the persistence partition";
+      wantedBy = [ "multi-user.target" ];
+      serviceConfig = {
+        Type = "oneshot";
+        RemainAfterExit = true;
+        StandardOutput = "journal";
+        StandardError = "journal";
+        ExecStart = "${extendbtrfs}/bin/extendbtrfs";
+      };
+    };
+
+}
diff --git a/modules/disko/disko-zfs-postboot.nix b/modules/disko/disko-zfs-postboot.nix
deleted file mode 100644
index c7b8c0e5ce..0000000000
--- a/modules/disko/disko-zfs-postboot.nix
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright 2022-2024 TII (SSRC) and the Ghaf contributors
-# SPDX-License-Identifier: Apache-2.0
-{ pkgs, ... }:
-let
-  postBootCmds = ''
-    set -xeuo pipefail
-
-    # Check which physical disk is used by ZFS
-    ZFS_POOLNAME=$(${pkgs.zfs}/bin/zpool list | ${pkgs.gnugrep}/bin/grep -v NAME |  ${pkgs.gawk}/bin/awk '{print $1}')
-    ZFS_LOCATION=$(${pkgs.zfs}/bin/zpool status -P | ${pkgs.gnugrep}/bin/grep dev | ${pkgs.gawk}/bin/awk '{print $1}')
-
-    # Get the actual device path
-    P_DEVPATH=$(readlink -f "$ZFS_LOCATION")
-
-    # Extract the partition number using regex
-    if [[ "$P_DEVPATH" =~ [0-9]+$ ]]; then
-      PARTNUM=$(echo "$P_DEVPATH" | ${pkgs.gnugrep}/bin/grep -o '[0-9]*$')
-      PARENT_DISK=/dev/$(${pkgs.util-linux}/bin/lsblk -no pkname "$P_DEVPATH")
-    else
-      echo "No partition number found in device path: $P_DEVPATH"
-    fi
-
-    # Fix GPT first
-    ${pkgs.gptfdisk}/bin/sgdisk "$PARENT_DISK" -e
-
-    # Call partprobe to update kernel's partitions
-    ${pkgs.parted}/bin/partprobe
-
-    # Extend the partition to use unallocated space
-    ${pkgs.parted}/bin/parted -s -a opt "$PARENT_DISK" "resizepart $PARTNUM 100%"
-
-    # Extend ZFS pool to use newly allocated space
-    ${pkgs.zfs}/bin/zpool online -e "$ZFS_POOLNAME" "$ZFS_LOCATION"
-  '';
-in
-{
-  # To debug postBootCommands, one may run
-  # journalctl -u initrd-nixos-activation.service
-  # inside the running Ghaf host.
-  boot.postBootCommands = postBootCmds;
-}
diff --git a/modules/disko/flake-module.nix b/modules/disko/flake-module.nix
index 1b94ecdf5b..d3a397c5ea 100644
--- a/modules/disko/flake-module.nix
+++ b/modules/disko/flake-module.nix
@@ -3,16 +3,10 @@
 { inputs, ... }:
 {
   flake.nixosModules = {
-    disko-basic-partition-v1.imports = [
+    disko-debug-partition.imports = [
       inputs.disko.nixosModules.disko
-      ./disko-basic-partition-v1.nix
-      ./disko-basic-postboot.nix
-    ];
-
-    disko-ab-partitions-v1.imports = [
-      inputs.disko.nixosModules.disko
-      ./disko-ab-partitions.nix
-      ./disko-zfs-postboot.nix
+      ./disko-debug-partition.nix
+      ./disko-postboot.nix
     ];
   };
 }
diff --git a/modules/givc/host.nix b/modules/givc/host.nix
index 4e56421dae..e3817f2320 100644
--- a/modules/givc/host.nix
+++ b/modules/givc/host.nix
@@ -52,7 +52,7 @@ in
       adminTlsName = config.ghaf.givc.adminConfig.name;
       adminAddresses = config.ghaf.givc.adminConfig.addresses;
       generatorHostName = hostName;
-      storagePath = "/storagevm/givc";
+      storagePath = "/persist/storagevm/givc";
     };
   };
 }
diff --git a/modules/hardware/x86_64-generic/x86_64-linux.nix b/modules/hardware/x86_64-generic/x86_64-linux.nix
index 3074f205f4..f17a427ebe 100644
--- a/modules/hardware/x86_64-generic/x86_64-linux.nix
+++ b/modules/hardware/x86_64-generic/x86_64-linux.nix
@@ -46,9 +46,7 @@ in
         systemd-boot.enable = true;
       };
 
-      # TODO the kernel latest is currently broken for zfs.
-      # try to fix on the next update.
-      kernelPackages = pkgs.linuxPackages;
+      kernelPackages = pkgs.linuxPackages_latest;
     };
   };
 }
diff --git a/modules/microvm/virtualization/microvm/common/shared-directory.nix b/modules/microvm/virtualization/microvm/common/shared-directory.nix
index bb995d549d..c7dea3064f 100644
--- a/modules/microvm/virtualization/microvm/common/shared-directory.nix
+++ b/modules/microvm/virtualization/microvm/common/shared-directory.nix
@@ -18,7 +18,7 @@ in
         proto = "virtiofs";
         securityModel = "passthrough";
         # We want double dir to keep root permission for `shared` directory and `shares` will be allowed to view and change by user.
-        source = "/storagevm/shared/shares" + (if !isGuiVm then "/Unsafe\ ${name}\ share/" else "");
+        source = "/persist/storagevm/shared/shares" + (if !isGuiVm then "/Unsafe\ ${name}\ share/" else "");
         mountPoint = shared-mountPath;
       }
     ];
diff --git a/modules/microvm/virtualization/microvm/common/storagevm.nix b/modules/microvm/virtualization/microvm/common/storagevm.nix
index fb5e4dc363..4b17eadc29 100644
--- a/modules/microvm/virtualization/microvm/common/storagevm.nix
+++ b/modules/microvm/virtualization/microvm/common/storagevm.nix
@@ -97,16 +97,16 @@ in
           tag = "hostshare";
           proto = "virtiofs";
           securityModel = "passthrough";
-          source = "/storagevm/${cfg.name}";
+          source = "/persist/storagevm/${cfg.name}";
           mountPoint = cfg.mountPath;
         }
       ];
 
       microvm.volumes = lib.optionals config.ghaf.users.loginUser.enable [
         {
-          image = "/storagevm/homes/${cfg.name}-home.img";
+          image = "/persist/storagevm/homes/${cfg.name}-home.img";
           size = builtins.floor (config.ghaf.users.loginUser.homeSize * 1.15);
-          fsType = "ext4";
+          fsType = "btrfs";
           mountPoint = "/home";
         }
       ];
@@ -141,7 +141,7 @@ in
       };
       microvm.volumes = [
         {
-          image = "/storagevm/givc/${cfg.name}.img";
+          image = "/persist/storagevm/givc/${cfg.name}.img";
           readOnly = true;
           autoCreate = false;
           fsType = "ext4";
diff --git a/modules/microvm/virtualization/microvm/common/xdgitems.nix b/modules/microvm/virtualization/microvm/common/xdgitems.nix
index a16e6734c7..5a8f2d1f5b 100644
--- a/modules/microvm/virtualization/microvm/common/xdgitems.nix
+++ b/modules/microvm/virtualization/microvm/common/xdgitems.nix
@@ -75,7 +75,7 @@ in
     xdgHostRoot = lib.mkOption {
       description = "Path of the XDG root folder used for file sharing between VMs";
       type = lib.types.str;
-      default = "/storagevm/xdg";
+      default = "/persist/storagevm/xdg";
     };
 
     xdgHostPaths = lib.mkOption {
diff --git a/modules/microvm/virtualization/microvm/microvm-host.nix b/modules/microvm/virtualization/microvm/microvm-host.nix
index 3d0eb1e667..abf818571e 100644
--- a/modules/microvm/virtualization/microvm/microvm-host.nix
+++ b/modules/microvm/virtualization/microvm/microvm-host.nix
@@ -83,7 +83,7 @@ in
       # Create host directories for microvm shares
       systemd.tmpfiles.rules =
         let
-          vmRootDirs = map (vm: "d /storagevm/${vm} 0700 root root -") (
+          vmRootDirs = map (vm: "d /persist/storagevm/${vm} 0700 root root -") (
             builtins.attrNames config.microvm.vms
           );
           vmsWithXdg = lib.filter (
@@ -93,11 +93,11 @@ in
           xdgRules = map (path: "D ${path} 0700 ${toString config.ghaf.users.loginUser.uid} users -") xdgDirs;
         in
         [
-          "d /storagevm/homes 0700 microvm kvm -"
+          "d /persist/storagevm/homes 0700 microvm kvm -"
           "d ${config.ghaf.security.sshKeys.waypipeSshPublicKeyDir} 0700 root root -"
         ]
         ++ lib.optionals config.ghaf.givc.enable [
-          "d /storagevm/givc 0700 microvm kvm -"
+          "d /persist/storagevm/givc 0700 microvm kvm -"
         ]
         ++ vmRootDirs
         ++ xdgRules;
@@ -134,12 +134,12 @@ in
         let
           vmDirs = map (
             n:
-            "d /storagevm/shared/shares/Unsafe\\x20${n}\\x20share/ 0760 ${toString config.ghaf.users.loginUser.uid} users"
+            "d /persist/storagevm/shared/shares/Unsafe\\x20${n}\\x20share/ 0760 ${toString config.ghaf.users.loginUser.uid} users"
           ) cfg.sharedVmDirectory.vms;
         in
         [
-          "d /storagevm/shared 0755 root root"
-          "d /storagevm/shared/shares 0760 ${toString config.ghaf.users.loginUser.uid} users"
+          "d /persist/storagevm/shared 0755 root root"
+          "d /persist/storagevm/shared/shares 0760 ${toString config.ghaf.users.loginUser.uid} users"
         ]
         ++ vmDirs;
     })
@@ -154,8 +154,8 @@ in
             ];
             text = ''
               echo "Removing ghaf login user data"
-              rm -r /storagevm/homes/*
-              rm -r /storagevm/gui-vm/var/
+              rm -r /persist/storagevm/homes/*
+              rm -r /persist/storagevm/gui-vm/var/
               echo "All ghaf login user data removed"
             '';
           };
@@ -164,7 +164,7 @@ in
           description = "Remove ghaf login users";
           enable = true;
           path = [ userRemovalScript ];
-          unitConfig.ConditionPathExists = "/storagevm/gui-vm/var/lib/nixos/user.lock";
+          unitConfig.ConditionPathExists = "/persist/storagevm/gui-vm/var/lib/nixos/user.lock";
           serviceConfig = {
             Type = "oneshot";
             ExecStart = "${userRemovalScript}/bin/remove-users";
diff --git a/packages/flake-module.nix b/packages/flake-module.nix
index 74d64513c0..daad5086f2 100644
--- a/packages/flake-module.nix
+++ b/packages/flake-module.nix
@@ -36,7 +36,7 @@
                   self.nixosModules.laptop
                   inputs.lanzaboote.nixosModules.lanzaboote
                   self.nixosModules.microvm
-                  self.nixosModules.disko-ab-partitions-v1
+                  self.nixosModules.disko-debug-partition
                   {
                     nixpkgs.hostPlatform = "x86_64-linux";
                     ghaf.hardware.definition = import ../modules/reference/hardware/lenovo-x1/definitions/x1-gen11.nix;
diff --git a/targets/laptop/flake-module.nix b/targets/laptop/flake-module.nix
index 823fb66fed..a100b501fd 100644
--- a/targets/laptop/flake-module.nix
+++ b/targets/laptop/flake-module.nix
@@ -17,7 +17,7 @@ let
   target-configs = [
     # Laptop Debug configurations
     (laptop-configuration "lenovo-x1-carbon-gen10" "debug" [
-      self.nixosModules.disko-ab-partitions-v1
+      self.nixosModules.disko-debug-partition
       {
         ghaf = {
           hardware.definition = import ../../modules/reference/hardware/lenovo-x1/definitions/x1-gen10.nix;
@@ -26,7 +26,7 @@ let
       }
     ])
     (laptop-configuration "lenovo-x1-carbon-gen11" "debug" [
-      self.nixosModules.disko-ab-partitions-v1
+      self.nixosModules.disko-debug-partition
       {
         ghaf = {
           hardware.definition = import ../../modules/reference/hardware/lenovo-x1/definitions/x1-gen11.nix;
@@ -35,7 +35,7 @@ let
       }
     ])
     (laptop-configuration "lenovo-x1-carbon-gen12" "debug" [
-      self.nixosModules.disko-ab-partitions-v1
+      self.nixosModules.disko-debug-partition
       {
         ghaf = {
           hardware.definition = import ../../modules/reference/hardware/lenovo-x1/definitions/x1-gen12.nix;
@@ -44,7 +44,7 @@ let
       }
     ])
     (laptop-configuration "lenovo-x1-extras" "debug" [
-      self.nixosModules.disko-ab-partitions-v1
+      self.nixosModules.disko-debug-partition
       {
         ghaf = {
           hardware.definition = import ../../modules/reference/hardware/lenovo-x1/definitions/x1-gen11.nix;
@@ -53,7 +53,7 @@ let
       }
     ])
     (laptop-configuration "dell-latitude-7230" "debug" [
-      self.nixosModules.disko-ab-partitions-v1
+      self.nixosModules.disko-debug-partition
       {
         ghaf = {
           hardware.definition = import ../../modules/reference/hardware/dell-latitude/definitions/dell-latitude-7230.nix;
@@ -62,7 +62,7 @@ let
       }
     ])
     (laptop-configuration "dell-latitude-7330" "debug" [
-      self.nixosModules.disko-ab-partitions-v1
+      self.nixosModules.disko-debug-partition
       {
         ghaf = {
           hardware.definition = import ../../modules/reference/hardware/dell-latitude/definitions/dell-latitude-7330.nix;
@@ -71,7 +71,7 @@ let
       }
     ])
     (laptop-configuration "alienware-m18-R2" "debug" [
-      self.nixosModules.disko-ab-partitions-v1
+      self.nixosModules.disko-debug-partition
       {
         ghaf = {
           hardware.definition = import ../../modules/reference/hardware/alienware/alienware-m18.nix;
@@ -85,7 +85,7 @@ let
 
     # Laptop Release configurations
     (laptop-configuration "lenovo-x1-carbon-gen10" "release" [
-      self.nixosModules.disko-ab-partitions-v1
+      self.nixosModules.disko-debug-partition
       {
         ghaf = {
           hardware.definition = import ../../modules/reference/hardware/lenovo-x1/definitions/x1-gen10.nix;
@@ -94,7 +94,7 @@ let
       }
     ])
     (laptop-configuration "lenovo-x1-carbon-gen11" "release" [
-      self.nixosModules.disko-ab-partitions-v1
+      self.nixosModules.disko-debug-partition
       {
         ghaf = {
           hardware.definition = import ../../modules/reference/hardware/lenovo-x1/definitions/x1-gen11.nix;
@@ -103,7 +103,7 @@ let
       }
     ])
     (laptop-configuration "lenovo-x1-carbon-gen12" "release" [
-      self.nixosModules.disko-ab-partitions-v1
+      self.nixosModules.disko-debug-partition
       {
         ghaf = {
           hardware.definition = import ../../modules/reference/hardware/lenovo-x1/definitions/x1-gen12.nix;
@@ -112,7 +112,7 @@ let
       }
     ])
     (laptop-configuration "lenovo-x1-extras" "release" [
-      self.nixosModules.disko-ab-partitions-v1
+      self.nixosModules.disko-debug-partition
       {
         ghaf = {
           hardware.definition = import ../../modules/reference/hardware/lenovo-x1/definitions/x1-gen11.nix;
@@ -121,7 +121,7 @@ let
       }
     ])
     (laptop-configuration "dell-latitude-7230" "release" [
-      self.nixosModules.disko-ab-partitions-v1
+      self.nixosModules.disko-debug-partition
       {
         ghaf = {
           hardware.definition = import ../../modules/reference/hardware/dell-latitude/definitions/dell-latitude-7230.nix;
@@ -130,7 +130,7 @@ let
       }
     ])
     (laptop-configuration "dell-latitude-7330" "release" [
-      self.nixosModules.disko-ab-partitions-v1
+      self.nixosModules.disko-debug-partition
       {
         ghaf = {
           hardware.definition = import ../../modules/reference/hardware/dell-latitude/definitions/dell-latitude-7330.nix;
@@ -139,7 +139,7 @@ let
       }
     ])
     (laptop-configuration "alienware-m18-R2" "release" [
-      self.nixosModules.disko-ab-partitions-v1
+      self.nixosModules.disko-debug-partition
       {
         ghaf = {
           hardware.definition = import ../../modules/reference/hardware/alienware/alienware-m18.nix;
diff --git a/tests/installer/default.nix b/tests/installer/default.nix
index e728d6251f..92c28aa95b 100644
--- a/tests/installer/default.nix
+++ b/tests/installer/default.nix
@@ -24,9 +24,6 @@ let
       (_: {
         testing.initrdBackdoor = true;
         services.openssh.enable = true;
-        # https://github.com/nix-community/disko/blob/e55f9a8678adc02024a4877c2a403e3f6daf24fe/lib/interactive-vm.nix#L63
-        boot.zfs.devNodes = "/dev/disk/by-uuid"; # needed because /dev/disk/by-id is empty in qemu-vms
-        boot.zfs.forceImportAll = true;
       })
     ];
   };


Reviews:
user: login: brianmcgillion
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-03T13:02:42Z
user: login: mbssrc
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-05T07:12:33Z
user: login: humaidq-tii
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-05T07:16:37Z
user: login: mbssrc
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-05T07:24:02Z
user: login: humaidq-tii
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-05T07:32:25Z
user: login: mbssrc
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-05T07:41:36Z
user: login: humaidq-tii
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-03-05T08:12:22Z
user: login: mbssrc
state: COMMENTED
author_association: COLLABORATOR
submitted_at: 2025-03-05T08:29:02Z
user: login: mbssrc
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-05T08:29:24Z
user: login: brianmcgillion
state: APPROVED
author_association: COLLABORATOR
submitted_at: 2025-03-06T10:01:08Z

Review comments:
diff_hunk: @@ -52,7 +52,7 @@ in
       adminTlsName = config.ghaf.givc.adminConfig.name;
       adminAddresses = config.ghaf.givc.adminConfig.addresses;
       generatorHostName = hostName;
-      storagePath = "/storagevm/givc";
+      storagePath = "/persist/storagevm/givc";
path: modules/givc/host.nix
user: login: mbssrc
body: The `storagevm` in the path `/persist/storagevm` seems to be somewhat unnecessary?
created_at: 2025-03-05T07:12:33Z
author_association: COLLABORATOR
diff_hunk: @@ -52,7 +52,7 @@ in
       adminTlsName = config.ghaf.givc.adminConfig.name;
       adminAddresses = config.ghaf.givc.adminConfig.addresses;
       generatorHostName = hostName;
-      storagePath = "/storagevm/givc";
+      storagePath = "/persist/storagevm/givc";
path: modules/givc/host.nix
user: login: humaidq-tii
body: Is it required for givc to be under storagevm? Or is it okay to be stored separately?

I have kept paths mostly as is previously to avoid breaking other components with these changes.
created_at: 2025-03-05T07:16:37Z
author_association: MEMBER
diff_hunk: @@ -52,7 +52,7 @@ in
       adminTlsName = config.ghaf.givc.adminConfig.name;
       adminAddresses = config.ghaf.givc.adminConfig.addresses;
       generatorHostName = hostName;
-      storagePath = "/storagevm/givc";
+      storagePath = "/persist/storagevm/givc";
path: modules/givc/host.nix
user: login: mbssrc
body: I was generally referring to having the `storagevm` path instead of just `/persist`, unless we want to indicate some differences for types of vm storage? A minor style question
created_at: 2025-03-05T07:24:02Z
author_association: COLLABORATOR
diff_hunk: @@ -52,7 +52,7 @@ in
       adminTlsName = config.ghaf.givc.adminConfig.name;
       adminAddresses = config.ghaf.givc.adminConfig.addresses;
       generatorHostName = hostName;
-      storagePath = "/storagevm/givc";
+      storagePath = "/persist/storagevm/givc";
path: modules/givc/host.nix
user: login: humaidq-tii
body: My reasoning was that everything that needs persistence will be in a single place, where we previously had gp_storage, vm_storage, and recovery under separate partitions.

This way we can know all persistence on host is under a single mount point, any other service that needs persistence can use /persist such as system update images on host.

Subvolumes aren't used currently to avoid increasing complexity in this stage, but these can be in separate subvolumes without having to change references to the path.
created_at: 2025-03-05T07:32:25Z
author_association: MEMBER
diff_hunk: @@ -52,7 +52,7 @@ in
       adminTlsName = config.ghaf.givc.adminConfig.name;
       adminAddresses = config.ghaf.givc.adminConfig.addresses;
       generatorHostName = hostName;
-      storagePath = "/storagevm/givc";
+      storagePath = "/persist/storagevm/givc";
path: modules/givc/host.nix
user: login: mbssrc
body: So this is a preparation for the future where the root partition is not ext4 anymore? I was mostly wondering because at the moment there is no usage of `/persist` besides `/persist/storagevm`.
created_at: 2025-03-05T07:41:36Z
author_association: COLLABORATOR
diff_hunk: @@ -52,7 +52,7 @@ in
       adminTlsName = config.ghaf.givc.adminConfig.name;
       adminAddresses = config.ghaf.givc.adminConfig.addresses;
       generatorHostName = hostName;
-      storagePath = "/storagevm/givc";
+      storagePath = "/persist/storagevm/givc";
path: modules/givc/host.nix
user: login: humaidq-tii
body: Yes, for release builds it will use erofs for root and not ext4.
created_at: 2025-03-05T08:12:22Z
author_association: MEMBER
diff_hunk: @@ -52,7 +52,7 @@ in
       adminTlsName = config.ghaf.givc.adminConfig.name;
       adminAddresses = config.ghaf.givc.adminConfig.addresses;
       generatorHostName = hostName;
-      storagePath = "/storagevm/givc";
+      storagePath = "/persist/storagevm/givc";
path: modules/givc/host.nix
user: login: mbssrc
body: Cool. lgtm
created_at: 2025-03-05T08:29:02Z
author_association: COLLABORATOR

PR comments:
user: login: johannarautanen
created_at: 2025-03-04T07:17:51Z
body: **Just in case check the native Orin AGX and NX with commit 56294944401933c98fce350af4e5121c01201851**
Working:
- ghaf-screen visible in external display
- applications launched
- automation tests ok
- tested manual tests ok
author_association: NONE
user: login: milva-unikie
created_at: 2025-03-04T09:36:29Z
body: **Tested on Lenovo-X1** (installation with installer & new debug image)

More thorough check with 5629494, but also checked with 80f2bcc.

Issues:
- The maximum size of Shares-folder is only 7.5 G. That is where user is supposed to store all their files. When Shares became full I noticed strange issues including system freezes.

Working:
- Everything else seems to be working correctly.
- Test-automation has one memory related test case that we will need to update. Other than that all tests pass.

Question:
- Is there a way to ensure that Ghaf boots from SSD when there is also Ghaf installed in the internal memory? It seems to randomly decide where to mount the persistent storage from. Sometimes it works correctly and sometimes not.
```
[ghaf@ghaf-host:~]$ lsblk
NAME                                            MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINTS
sda                                               8:0    0 476.9G  0 disk  
├─sda1                                            8:1    0     1M  0 part  
├─sda2                                            8:2    0   500M  0 part  /boot
├─sda3                                            8:3    0    12G  0 part  
│ └─dev-disk-byx2dpartlabel-diskx2ddisk1x2dswap 254:0    0    12G  0 crypt [SWAP]
├─sda4                                            8:4    0    40G  0 part  /etc/shadow
│                                                                          /etc/passwd
│                                                                          /etc/group
│                                                                          /nix/store
│                                                                          /
└─sda5                                            8:5    0   7.5G  0 part  
nvme0n1                                         259:0    0 953.9G  0 disk  
├─nvme0n1p1                                     259:1    0     1M  0 part  
├─nvme0n1p2                                     259:2    0   500M  0 part  
├─nvme0n1p3                                     259:3    0    12G  0 part  
├─nvme0n1p4                                     259:4    0    40G  0 part  
└─nvme0n1p5                                     259:5    0 901.4G  0 part  /persist
```

author_association: NONE
user: login: humaidq-tii
created_at: 2025-03-05T06:28:22Z
body: > Is there a way to ensure that Ghaf boots from SSD when there is also Ghaf installed in the internal memory? It seems to randomly decide where to mount the persistent storage from. Sometimes it works correctly and sometimes not.

Ghaf currently doesn't support dual booting, so there might be unexpected behaviour when loading the persistence partition. For testing it is better to boot from either storage, while the other is erased. If booting external SSD, internal storage shouldn't contain an existing Ghaf install.
author_association: MEMBER
user: login: humaidq-tii
created_at: 2025-03-05T06:42:38Z
body: @milva-unikie Bug should be fixed
author_association: MEMBER
user: login: milva-unikie
created_at: 2025-03-06T08:28:26Z
body: **Tested on Lenovo-X1** (installation with installer & new debug image)

- Shares is now expanded correctly.
- Test-automation needs one change, [PR](https://github.com/tiiuae/ci-test-automation/pull/264) for that is open and should be merged right before this PR.



> Ghaf currently doesn't support dual booting, so there might be unexpected behaviour when loading the persistence partition. For testing it is better to boot from either storage, while the other is erased. If booting external SSD, internal storage shouldn't contain an existing Ghaf install.

Currently you can work around this by renaming `zfspool` to eg. `zfspool2` with one of the installations. It makes testing much easier and faster. 

I tried renaming `persist` since that was the one mounted incorrectly, but it did not fix the issue. If a solution could be found for this in the near future, I would very much appreciate it.
author_association: NONE