commit 1d45e34e6c98a489c76c37e5d58adca4a45fea32 parent 6286b198b052775c326002356f57229975970991 Author: vin <git@vineetk.net> Date: Tue, 9 Dec 2025 21:57:55 -0500 attempt adding root-on-zfs support via hako rosenthal patches Diffstat:
| M | epistemia/packages/zfs.scm | | | 2 | +- |
| M | epistemia/systems/demiurge.scm | | | 121 | ++++++++++++++++++++++++++++++++++++++++++++----------------------------------- |
| A | epistemia/systems/linux-initrd.scm | | | 241 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | epistemia/systems/zfs.scm | | | 30 | ++++++++++++++++++++++++++++++ |
4 files changed, 339 insertions(+), 55 deletions(-)
diff --git a/epistemia/packages/zfs.scm b/epistemia/packages/zfs.scm @@ -9,5 +9,5 @@ (package (inherit zfs) (arguments - (cons* #:linux linux-6.15 + (cons* #:linux linux-6.16 (package-arguments zfs))))) diff --git a/epistemia/systems/demiurge.scm b/epistemia/systems/demiurge.scm @@ -11,8 +11,9 @@ #:use-module (guix) #:use-module (guix utils) #:use-module (nongnu packages linux) - #:use-module (nongnu system linux-initrd) + #:use-module (nongnu system linux-initrd) ; for microcode #:use-module (epistemia systems base-system) + #:use-module (epistemia systems linux-initrd) ; for zfs-on-root #:use-module (epistemia services zfs) #:use-module (epistemia packages zfs)) @@ -20,62 +21,74 @@ (use-package-modules bootloaders emacs) (operating-system - (inherit base-system) - (host-name "demiurge") + (inherit base-system) + (host-name "demiurge") - (kernel linux-6.15) - (kernel-arguments (list "net.ifnames=0")) - (kernel-loadable-modules (list (list zfs-linux "module"))) + (kernel linux-6.16) + (kernel-arguments (list "net.ifnames=0")) + (kernel-loadable-modules (list (list zfs-linux "module"))) - (initrd microcode-initrd) - (firmware (cons* amdgpu-firmware %base-firmware)) + (initrd (lambda (file-systems . args) + (apply microcode-initrd file-systems + #:initrd epistemia-zfs-initrd + #:zfs-package zfs-linux + args))) + (firmware (cons* amdgpu-firmware %base-firmware)) - (bootloader (bootloader-configuration - (bootloader grub-efi-bootloader) - (targets '("/boot/efi")))) + (bootloader (bootloader-configuration + (bootloader grub-efi-bootloader) + (targets '("/boot/efi")))) - (file-systems (append - (list (file-system - (device (uuid "e2a1956c-51d1-4263-b8be-1961b6d24a46" 'f2fs)) - (mount-point "/") - (type "f2fs")) - (file-system - (device (uuid "EC1D-4A47" 'fat)) - (mount-point "/boot/efi") - (type "vfat"))) - %base-file-systems)) + (file-systems (append + (list (file-system + (device (file-system-label "zroot/root_crux")) + (mount-point "/") + (type "zfs") + (check? #f) + (needed-for-boot? #t)) + (file-system + (device (file-system-label "zroot/gnu")) + (mount-point "/gnu") + (type "zfs") + (check? #f) + (needed-for-boot? #t)) + (file-system + (device (uuid "EC1D-4A47" 'fat)) + (mount-point "/boot/efi") + (type "vfat"))) + %base-file-systems)) - (packages (append (list emacs-no-x podman-compose zfs-linux) - %base-packages)) + (packages (append (list dsp emacs-no-x podman-compose zfs-linux) + %base-packages)) - (services (append (list (simple-service 'zfs-loader - kernel-module-loader-service-type - '("zfs")) - (simple-service 'zfs-shepherd-services - shepherd-root-service-type - zfs-shepherd-services) - (simple-service 'zfs-shepherd-services-user-processes - user-processes-service-type - '(zfs-automount)) - (service seatd-service-type) - (service dbus-root-service-type) - (service iptables-service-type) - (service rootless-podman-service-type - (rootless-podman-configuration - (subgids - (list (subid-range (name "vin")))) - (subuids - (list (subid-range (name "vin")))))) - (service static-networking-service-type - (list (static-networking - (addresses - (list (network-address - (device "eth0") - (value "192.168.1.2/24")))) - (routes - (list (network-route - (destination "default") - (gateway "192.168.1.1")))) - (name-servers '("192.168.1.1"))))) - (service openssh-service-type)) - %base-services))) + (services (append (list (simple-service 'zfs-loader + kernel-module-loader-service-type + '("zfs")) + (simple-service 'zfs-shepherd-services + shepherd-root-service-type + zfs-shepherd-services) + (simple-service 'zfs-shepherd-services-user-processes + user-processes-service-type + '(zfs-automount)) + (service seatd-service-type) + (service dbus-root-service-type) + (service iptables-service-type) + (service rootless-podman-service-type + (rootless-podman-configuration + (subgids + (list (subid-range (name "vin")))) + (subuids + (list (subid-range (name "vin")))))) + (service static-networking-service-type + (list (static-networking + (addresses + (list (network-address + (device "eth0") + (value "192.168.1.2/24")))) + (routes + (list (network-route + (destination "default") + (gateway "192.168.1.1")))) + (name-servers '("192.168.1.1"))))) + (service openssh-service-type)) + %base-services))) diff --git a/epistemia/systems/linux-initrd.scm b/epistemia/systems/linux-initrd.scm @@ -0,0 +1,241 @@ +;;; SPDX-License-Identifier: GPL-3.0-or-later +;;; Adapted from GNU Guix gnu/system/linux-initrd.scm and Hako's Rosenthal zfs-on-root patches + +(define-module (epistemia system linux-initrd) + #:use-module (guix gexp) + #:use-module (guix utils) + #:use-module ((guix store) #:select (%store-prefix)) + #:use-module ((guix derivations) #:select (derivation->output-path)) + #:use-module (guix modules) + #:use-module (gnu packages compression) + #:use-module (gnu packages disk) + #:use-module (gnu packages linux) + #:use-module (gnu packages file-systems) + #:use-module (gnu system file-systems) + #:use-module (gnu system mapped-devices) + #:use-module (gnu system keyboard) + #:use-module (gnu system linux-initrd) ;; upstream module imported for reusing helpers + #:use-module (ice-9 match) + #:use-module (ice-9 regex) + #:use-module (ice-9 vlist) + #:use-module (srfi srfi-1) + #:use-module (srfi srfi-26) + #:export (epistemia-zfs-initrd)) + +;;; +;;; Custom Module Builder (Solves the "Out-of-Tree" problem) +;;; + +(define (flat-linux-module-directory* linux extra-packages modules) + "Return a flat directory containing the Linux kernel modules listed in +MODULES. Unlike the upstream version, this searches both LINUX and EXTRA-PACKAGES +for the requested modules." + (define imported-modules + (source-module-closure '((gnu build linux-modules) + (guix build utils)))) + + (define build-exp + (with-imported-modules imported-modules + (with-extensions (list guile-zlib guile-zstd) + #~(begin + (use-modules (gnu build linux-modules) + (guix build utils) + (rnrs io ports) + (srfi srfi-1) + (srfi srfi-26) + (ice-9 match)) + + ;; Define search paths: Kernel + Extra Packages (ZFS) + (define module-dirs + (map (lambda (pkg) (string-append pkg "/lib/modules")) + (cons #$linux '#$extra-packages))) + + ;; Helper to find the builtin modules in the main kernel + (define builtin-modules + (match (find-files (string-append #$linux "/lib/modules") + (lambda (file stat) + (string=? (basename file) "modules.builtin"))) + ((file . _) + (call-with-input-file file + (lambda (port) + (map file-name->module-name + (string-tokenize (get-string-all port)))))) + (_ '()))) + + (define modules-to-lookup + (lset-difference string=? '#$modules builtin-modules)) + + ;; Custom lookup function that iterates over all module-dirs + (define (lookup-in-dirs name) + (let loop ((dirs module-dirs)) + (match dirs + ((dir . rest) + (or (find-module-file dir name) + (loop rest))) + (() #f)))) + + (define modules + (let ((modules (map lookup-in-dirs modules-to-lookup))) + (append modules + (recursive-module-dependencies + modules + #:lookup-module lookup-in-dirs)))) + + (define (maybe-uncompress file) + (cond + ((string-contains file ".ko.gz") + (invoke #+(file-append gzip "/bin/gunzip") file)) + ((string-contains file ".ko.zst") + (invoke #+(file-append zstd "/bin/zstd") "-d" file)))) + + (mkdir #$output) + (for-each (lambda (module) + (when module ;; check if module was found + (let ((out-module + (string-append #$output "/" + (basename module)))) + (format #t "copying '~a'...~%" module) + (copy-file module out-module) + (maybe-uncompress out-module)))) + (delete-duplicates modules)) + + (write-module-name-database #$output))))) + + (computed-file "linux-modules-combined" build-exp)) + +;;; +;;; Custom Initrd Builder (Solves the "Import Pool" problem) +;;; + +(define* (zfs-raw-initrd file-systems + #:key + (linux linux-libre) + (zfs-package zfs) ;; New argument + (linux-modules '()) + (pre-mount #t) + (mapped-devices '()) + (keyboard-layout #f) + (helper-packages '()) + qemu-networking? + volatile-root? + (on-error 'debug)) + "A wrapper around expression->initrd that injects ZFS support." + + (define device-mapping-commands + (map (lambda (md) + (let* ((source (mapped-device-source md)) + (targets (mapped-device-targets md)) + (type (mapped-device-type md)) + (open (mapped-device-kind-open type))) + (apply open source targets + (mapped-device-arguments md)))) + mapped-devices)) + + (define file-system-scan-commands + (let ((file-system-types (map file-system-type file-systems))) + (if (member "btrfs" file-system-types) + #~((system* (string-append #$btrfs-progs/static "/bin/btrfs") + "device" "scan")) + #~()))) + + ;; Custom ZFS Import Logic + (define zfs-import-commands + #~(begin + (format #t "Epistemia: Importing ZFS pools...~%") + ;; We use the zpool binary from the provided package. + ;; -N: Do not mount (Guix handles mounting) + ;; -f: Force import (if previously not exported cleanly) + ;; -d: Look in /dev/disk/by-id for stable names + (system* (string-append #$zfs-package "/sbin/zpool") + "import" "-a" "-N" "-f" "-d" "/dev/disk/by-id") + ;; Sleep briefly to allow device nodes (like /dev/zvol/...) to settle + (sleep 2))) + + ;; Use our custom module directory builder + (define kodir + (flat-linux-module-directory* linux (list zfs-package) linux-modules)) + + (expression->initrd + (with-imported-modules (source-module-closure + '((gnu build linux-boot) + (guix build utils) + (guix build bournish) + (gnu system file-systems) + (gnu build file-systems))) + #~(begin + (use-modules (gnu build linux-boot) + (gnu system file-systems) + ((guix build utils) #:hide (delete)) + (guix build bournish) + (srfi srfi-1) + (srfi srfi-26)) + + (with-output-to-port (%make-void-port "w") + (lambda () + (set-path-environment-variable "PATH" '("bin" "sbin") + '#$helper-packages))) + + (parameterize ((current-warning-port (%make-void-port "w"))) + (boot-system #:mounts + (map spec->file-system + '#$(map file-system->spec file-systems)) + #:pre-mount (lambda () + (and #$pre-mount + #$@device-mapping-commands + #$@file-system-scan-commands + ;; INJECT ZFS HERE + #$zfs-import-commands)) + #:linux-modules '#$linux-modules + #:linux-module-directory '#$kodir + #:keymap-file #+(and=> keyboard-layout + keyboard-layout->console-keymap) + #:qemu-guest-networking? #$qemu-networking? + #:volatile-root? '#$volatile-root? + #:on-error '#$on-error)))) + #:name "zfs-initrd")) + +;;; +;;; The Public Interface +;;; + +(define* (epistemia-zfs-initrd file-systems + #:key + (linux linux-libre) + (zfs-package zfs) + (linux-modules '()) + (mapped-devices '()) + (keyboard-layout #f) + qemu-networking? + volatile-root? + (extra-modules '()) + (on-error 'debug) + #:allow-other-keys) + "Return a ZFS-capable initrd." + + (define linux-modules* + ;; Ensure ZFS is added to the module list + (cons "zfs" + `(,@linux-modules + ,@(file-system-modules file-systems) + ,@(if volatile-root? '("overlay") '()) + ,@extra-modules))) + + (define helper-packages + ;; Ensure zfs-package is available in the initrd (for zpool command) + (cons zfs-package + (append (file-system-packages file-systems + #:volatile-root? volatile-root?) + (if keyboard-layout + (list loadkeys-static) + '())))) + + (zfs-raw-initrd file-systems + #:linux linux + #:zfs-package zfs-package + #:linux-modules linux-modules* + #:mapped-devices mapped-devices + #:helper-packages helper-packages + #:keyboard-layout keyboard-layout + #:qemu-networking? qemu-networking? + #:volatile-root? volatile-root? + #:on-error on-error)) diff --git a/epistemia/systems/zfs.scm b/epistemia/systems/zfs.scm @@ -0,0 +1,30 @@ +(define-module (epistemia system zfs) + #:use-module (gnu system mapped-devices) + #:use-module (guix gexp) + #:use-module (epistemia packages zfs) + #:export (zfs-device-mapping)) + +(define* (open-zfs-device source targets #:key (root-dataset #f)) + "Import ZFS pool SOURCE and optionally mount ROOT-DATASET." + (with-imported-modules '((guix build utils)) + #~(let ((zpool #$(file-append zfs-linux "/sbin/zpool")) + (zfs #$(file-append zfs-linux "/sbin/zfs"))) + (format #t "Importing ZFS pool ~a...~%" #$source) + (system* zpool "import" "-N" "-f" "-d" "/dev/disk/by-id" #$source) + + #$@(if root-dataset + (list #~(begin + (format #t "Mounting ~a...~%" #$root-dataset) + (system* zfs "mount" #$root-dataset))) + '()) + #t))) + +(define (close-zfs-device source targets) + "Export ZFS pool SOURCE." + #~(zero? (system* #$(file-append zfs-linux "/sbin/zpool") "export" #$source))) + +(define zfs-device-mapping + (mapped-device-kind + (open open-zfs-device) + (close close-zfs-device) + (modules '((guix build utils)))))