[PATCH v2 08/10] qsu: optional virtiofs share into the guest
Daniel Gomez <[email protected]> Fri, 12 Jun 2026 12:55:20 +0200
| Newsgroups | dev.linux.lists.kdevops |
|---|---|
| Message-ID | <[email protected]> |
From: Daniel Gomez <[email protected]> qsu's vars schema lets a VM declare any number of host->guest virtiofs shares (see scripts/qemu-system-units/docs/vars.md). The nixosfi backend already appends two role-owned entries to that list -- the /nix/store and /lib/modules shares the imageless boot path needs -- and the fstests workflow appends three more (data-configs, data-results, kdevops-fstests). Expose one operator-defined slot on top. Add a QSU_SHARES_S0 menu under "Virtiofs shares" that, when enabled, appends a single share entry to qsu_shares with operator-supplied dir, mount and tag (defaults $HOME -> $HOME, tag share-s0). The matching guest-side mount drops into nixosfi's per-VM default.nix via nixos-flake.nixosModules.mounts.shares. The slot is named S0 to reserve namespace for additional slots (S1, S2, ...) and dedicated wells (HOME) as future additive features, without forcing another rename. Production VM configurations that want permanent shares should still extend qsu's vars schema and the guest module directly. Generated-by: Claude AI Signed-off-by: Daniel Gomez <[email protected]> --- kconfigs/Kconfig.qsu | 89 ++++++++++++++++++++++++ playbooks/roles/nixosfi/templates/default.nix.j2 | 4 ++ playbooks/roles/qsu/tasks/render-per-vm.yml | 10 ++- playbooks/roles/qsu/vars/main.yml | 11 +-- 4 files changed, 108 insertions(+), 6 deletions(-) diff --git a/kconfigs/Kconfig.qsu b/kconfigs/Kconfig.qsu index 7d5d4cb5..4cbd4dbb 100644 --- a/kconfigs/Kconfig.qsu +++ b/kconfigs/Kconfig.qsu @@ -118,6 +118,95 @@ endchoice endmenu # SSH access +menu "Virtiofs shares" + +# qsu's vars schema accepts a list of shares (see +# scripts/qemu-system-units/docs/vars.md). The imageless backend's +# /nix/store + /lib/modules entries and the fstests workflow's +# data-configs/data-results/kdevops-fstests entries are appended to +# qsu_shares by playbooks/roles/qsu/tasks/render-per-vm.yml. This +# menu exposes one operator-defined entry on top of those. + +config QSU_SHARES_S0 + bool "Mount a controller directory into the guest via virtiofs" + depends on NIXOS_FLAKE_MOUNT_SHARES + output yaml + default n + help + Append one operator-defined entry to qsu_shares that + exposes an arbitrary controller directory to the guest at + bringup. The imageless backend already shares /nix/store + with the guest, so a binary built on the controller with + `nix build` (which produces a `result -> /nix/store/<hash>` + symlink) becomes immediately runnable inside the guest once + the directory holding that symlink is shared too. + + The canonical use case is mirroring $HOME so per-project + `result` symlinks resolve at the same absolute path on both + the controller and the guest. Useful for iterating on a tool + under ~/src/<project> and exercising it inside the VM + without going through the system-closure rebuild loop. + + Developer convenience knob. Production VM configurations + that want permanent shares should add them directly to qsu's + vars schema (host side) and the per-VM default.nix via + nixos-flake.nixosModules.mounts.shares (guest side). + + Takes effect at `make bringup` or `make nixosfi-rebuild-boot` + because the matching virtiofsd daemon is only spun up when + the qsu render path runs. `make nixosfi-rebuild-test` alone + is not enough; the guest would fail to mount a tag that no + virtiofsd is serving. + +if QSU_SHARES_S0 + +config QSU_SHARES_S0_DIR + string "Controller directory to share" + output yaml + default "$(HOME)" + help + Absolute path on the controller to expose to the guest. + Default is $HOME so per-project `result -> /nix/store/<hash>` + symlinks under ~/src/* resolve at the same path in the guest. + +config QSU_SHARES_S0_MOUNT + string "Guest mount point" + output yaml + default "$(HOME)" + help + Path at which the share appears inside the guest. Default + mirrors the controller path so absolute paths (including + /nix/store/<hash> symlink chains rooted under the shared + directory) resolve identically on both sides. + +config QSU_SHARES_S0_TAG + string "virtiofs tag" + output yaml + default "share-s0" + help + Tag the controller's virtiofsd announces for this share. + Must be unique across the guest's shares; the imageless + backend reserves `store` and `modules`, and the fstests + workflow reserves `data-configs`, `data-results`, and + `kdevops-fstests`. + +config QSU_SHARES_S0_READWRITE + bool "Mount the share read-write" + output yaml + default n + help + Default is read-only at the guest mount: the guest reads + controller files at the mount point but cannot modify them, + preventing operator typos in the guest from clobbering + controller source trees. Enable this only when the in-guest + workload must write back to the controller (forensics + capture, log shipping, result harvest). + +endif # QSU_SHARES_S0 + +endmenu # Virtiofs shares + + menu "NVMe storage" config QSU_NVME_DRIVE_COUNT diff --git a/playbooks/roles/nixosfi/templates/default.nix.j2 b/playbooks/roles/nixosfi/templates/default.nix.j2 index db8d3dc8..41b77444 100644 --- a/playbooks/roles/nixosfi/templates/default.nix.j2 +++ b/playbooks/roles/nixosfi/templates/default.nix.j2 @@ -72,6 +72,10 @@ options = [ "trans=virtio" "version=9p2000.L" "cache=loose" ]; }; {% endif %} +{% if qsu_shares_s0 is defined and qsu_shares_s0 %} + # CONFIG_QSU_SHARES_S0 — see nixos-flake docs/usage.md. + nixos-flake.shares."{{ qsu_shares_s0_mount }}" = { tag = "{{ qsu_shares_s0_tag }}";{% if not (qsu_shares_s0_readwrite | default(false)) %} options = [ "ro" ];{% endif %} }; +{% endif %} {% set override_pkgs = [ ('fio', nixos_flake_override_fio | default(false), nixos_flake_override_fio_src | default('')), ('xfstests', nixos_flake_override_xfstests | default(false), nixos_flake_override_xfstests_src | default('')), diff --git a/playbooks/roles/qsu/tasks/render-per-vm.yml b/playbooks/roles/qsu/tasks/render-per-vm.yml index 83895bda..a7e63829 100644 --- a/playbooks/roles/qsu/tasks/render-per-vm.yml +++ b/playbooks/roles/qsu/tasks/render-per-vm.yml @@ -152,7 +152,7 @@ - name: Compose per-VM virtiofs shares for {{ qsu_vm_name }} ansible.builtin.set_fact: - qsu_shares: "{{ qsu_shares_base + qsu_shares_fstests }}" + qsu_shares: "{{ qsu_shares_base + qsu_shares_fstests + qsu_shares_s0_entries }}" vars: qsu_shares_base: - tag: store @@ -177,6 +177,14 @@ if (kdevops_workflow_enable_fstests | default(false) | bool) else [] }} + qsu_shares_s0_entries: >- + {{ + [{'tag': qsu_shares_s0_tag, + 'dir': qsu_shares_s0_dir, + 'mount': qsu_shares_s0_mount}] + if (qsu_shares_s0 | default(false) | bool) + else [] + }} - name: Render vm.env for {{ qsu_vm_name }} ansible.builtin.template: diff --git a/playbooks/roles/qsu/vars/main.yml b/playbooks/roles/qsu/vars/main.yml index 5ac02375..037ecf76 100644 --- a/playbooks/roles/qsu/vars/main.yml +++ b/playbooks/roles/qsu/vars/main.yml @@ -7,20 +7,21 @@ # Superset of every virtiofsd share tag the role can render an # env file for. Active subset per inventory VM is computed in -# tasks/imageless-build-per-vm.yml as -# qsu_shares = qsu_shares_base + qsu_shares_fstests -# under the kdevops_workflow_enable_fstests gate. bringup.yml uses -# this list to validate that an env file +# tasks/render-per-vm.yml as +# qsu_shares = qsu_shares_base + qsu_shares_fstests + qsu_shares_s0_entries +# under the kdevops_workflow_enable_fstests and qsu_shares_s0 +# gates. bringup.yml uses this list to validate that an env file # in the host-shared ~/.config/systemd/virtiofsd/ directory really # belongs to the role (i.e. matches `<inventory-vm>-<tag>.env`) # before restarting its socket — without this filter, a global # *.env glob touches sockets owned by VMs in other kdevops trees # on the host. destroy.yml uses it to enumerate exactly which # per-share env files to remove. Keep in sync with the shares -# block in imageless-build-per-vm.yml whenever a share is added. +# block in render-per-vm.yml whenever a share is added. qsu_canonical_share_tags: - store - modules - data-configs - data-results - kdevops-fstests + - "{{ qsu_shares_s0_tag | default('share-s0') }}" -- 2.54.0