]> git.scottworley.com Git - nixos-qemu-vm-isolation/commitdiff
Offer option of an erofs nix store image
authorScott Worley <scottworley@scottworley.com>
Fri, 21 Jul 2023 09:46:41 +0000 (02:46 -0700)
committerScott Worley <scottworley@scottworley.com>
Fri, 21 Jul 2023 09:49:17 +0000 (02:49 -0700)
Size of the simple test's nix store image:
 240M squashfs (no longer available)
 684M erofs
 1.3G ext4

checks/mount-grep.nix
modules/qemu-vm-isolation.nix

index f7eb3a327a367e2ec4d16dee8cf271f0308b0e03..5354d26c41492f7bb33e2539ef8fee989b9b3f69 100644 (file)
@@ -8,6 +8,10 @@ pkgs: {
   nodes = {
     shared = _: { };
     private = _: { imports = [ ../modules/qemu-vm-isolation.nix ]; };
   nodes = {
     shared = _: { };
     private = _: { imports = [ ../modules/qemu-vm-isolation.nix ]; };
+    privateErofs = _: {
+      imports = [ ../modules/qemu-vm-isolation.nix ];
+      virtualisation.qemu.isolation.nixStoreFilesystemType = "erofs";
+    };
     useNixStoreImage = {
       virtualisation = {
         sharedDirectories = pkgs.lib.mkForce { };
     useNixStoreImage = {
       virtualisation = {
         sharedDirectories = pkgs.lib.mkForce { };
@@ -18,13 +22,13 @@ pkgs: {
 
   testScript = ''
     start_all()
 
   testScript = ''
     start_all()
-    for machine in [shared, private, useNixStoreImage]:
+    for machine in [shared, private, privateErofs, useNixStoreImage]:
       machine.wait_for_unit("multi-user.target")
 
     shared.succeed("[[ $(mount | grep -c virt) -gt 0 ]]")
     shared.succeed("[[ -e ${pkgs.pv} ]]")
 
       machine.wait_for_unit("multi-user.target")
 
     shared.succeed("[[ $(mount | grep -c virt) -gt 0 ]]")
     shared.succeed("[[ -e ${pkgs.pv} ]]")
 
-    for machine in [private, useNixStoreImage]:
+    for machine in [private, privateErofs, useNixStoreImage]:
       machine.succeed("[[ $(mount | grep -c virt) -eq 0 ]]")
       machine.fail("[[ -e ${pkgs.pv} ]]")
   '';
       machine.succeed("[[ $(mount | grep -c virt) -eq 0 ]]")
       machine.fail("[[ -e ${pkgs.pv} ]]")
   '';
index 260e9fec7323c985a53c0fc1f197b13c765af525..bdf95e6d852f424ba6bc3264b421480769e1247a 100644 (file)
@@ -1,6 +1,10 @@
 { config, lib, modulesPath, pkgs, ... }:
 let
 { config, lib, modulesPath, pkgs, ... }:
 let
-  inherit (lib) findSingle mkForce mkIf mkMerge mkVMOverride;
+  inherit (lib)
+    escapeShellArg findSingle mkForce mkIf mkMerge mkOption mkVMOverride
+    optional;
+
+  cfg = config.virtualisation.qemu.isolation;
 
   lookupDriveDeviceName = driveName: driveList:
     (findSingle (drive: drive.name == driveName)
 
   lookupDriveDeviceName = driveName: driveList:
     (findSingle (drive: drive.name == driveName)
@@ -12,30 +16,15 @@ let
   else
     "/nix/store";
 
   else
     "/nix/store";
 
-in {
-
-  fileSystems = mkVMOverride {
-    "${storeMountPath}" = {
-      device =
-        lookupDriveDeviceName "nixstore" config.virtualisation.qemu.drives;
-      fsType = "ext4";
-      options = [ "ro" ];
-      neededForBoot = true;
-    };
-  };
+  hostPkgs = config.virtualisation.host.pkgs;
 
 
-  # We use this to disable fsck runs on the ext4 nix store image because stage-1
-  # fsck crashes (maybe because the device is read-only?), halting boot.
-  boot.initrd.checkJournalingFS = false;
+  storeContents =
+    hostPkgs.closureInfo { rootPaths = config.virtualisation.additionalPaths; };
 
 
-  system.build.nixStoreImage =
-    import (modulesPath + "/../lib/make-disk-image.nix") {
+  nixStoreImages = {
+    ext4 = import (modulesPath + "/../lib/make-disk-image.nix") {
       inherit pkgs config lib;
       inherit pkgs config lib;
-      additionalPaths = [
-        (config.virtualisation.host.pkgs.closureInfo {
-          rootPaths = config.virtualisation.additionalPaths;
-        })
-      ];
+      additionalPaths = [ storeContents ];
       onlyNixStore = true;
       label = "nix-store";
       partitionTableType = "none";
       onlyNixStore = true;
       label = "nix-store";
       partitionTableType = "none";
@@ -44,20 +33,78 @@ in {
       additionalSpace = "0M";
       copyChannel = false;
     };
       additionalSpace = "0M";
       copyChannel = false;
     };
+    erofs = hostPkgs.runCommand "nix-store-image" { } ''
+      mkdir $out
+      cd ${builtins.storeDir}
+      ${hostPkgs.erofs-utils}/bin/mkfs.erofs \
+        --force-uid=0 \
+        --force-gid=0 \
+        -L nix-store \
+        -U eb176051-bd15-49b7-9e6b-462e0b467019 \
+        -T 0 \
+        --exclude-regex="$(
+          <${storeContents}/store-paths \
+            sed -e 's^.*/^^g' \
+          | cut -c -10 \
+          | ${hostPkgs.python3}/bin/python -c ${
+            escapeShellArg (builtins.readFile
+              (modulesPath + "/virtualisation/includes-to-excludes.py"))
+          } )" \
+        $out/nixos.img \
+        .
+    '';
+  };
 
 
-  virtualisation = {
+in {
+  options = {
+    virtualisation.qemu.isolation.nixStoreFilesystemType = mkOption {
+      description = ''
+        What filesystem to use for the guest's Nix store.
 
 
-    sharedDirectories = mkForce { };
+        erofs is more compact than ext4, but less mature.
+      '';
+      type = lib.types.enum [ "ext4" "erofs" ];
+      default = "ext4";
+    };
+  };
+  config = mkMerge [
+    {
+      boot.initrd.kernelModules =
+        optional (cfg.nixStoreFilesystemType == "erofs") "erofs";
 
 
-    qemu.drives = [{
-      name = "nixstore";
-      file = "${config.system.build.nixStoreImage}/nixos.img";
-      driveExtraOpts = {
-        format = "raw";
-        read-only = "on";
-        werror = "report";
+      fileSystems = mkVMOverride {
+        "${storeMountPath}" = {
+          device =
+            lookupDriveDeviceName "nixstore" config.virtualisation.qemu.drives;
+          fsType = cfg.nixStoreFilesystemType;
+          options = [ "ro" ];
+          neededForBoot = true;
+        };
       };
       };
-    }];
 
 
-  };
+      system.build.nixStoreImage =
+        nixStoreImages."${cfg.nixStoreFilesystemType}";
+
+      virtualisation = {
+
+        sharedDirectories = mkForce { };
+
+        qemu.drives = [{
+          name = "nixstore";
+          file = "${config.system.build.nixStoreImage}/nixos.img";
+          driveExtraOpts = {
+            format = "raw";
+            read-only = "on";
+            werror = "report";
+          };
+        }];
+
+      };
+    }
+    (mkIf (cfg.nixStoreFilesystemType == "ext4") {
+      # We use this to disable fsck runs on the ext4 nix store image because stage-1
+      # fsck crashes (maybe because the device is read-only?), halting boot.
+      boot.initrd.checkJournalingFS = false;
+    })
+  ];
 }
 }