feat: runtime hot-mount (limactl mount add|remove|list) for QEMU and VZ#5154
feat: runtime hot-mount (limactl mount add|remove|list) for QEMU and VZ#5154riccardosabatini wants to merge 18 commits into
Conversation
Adds the approved design for runtime hot-mount/unmount of host folders into a running QEMU/Linux VM. Primary transport is virtiofs (high-IO), with 9p and reverse-sshfs alternatives. Hot-mounts are ephemeral. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Riccardo Sabatini <riccardo.sab@gmail.com>
Adds the task-by-task implementation plan and records three planning-time refinements in the spec: optional FSHotPlugger capability interface (no macOS/Windows driver edits), Linux-gated memfd memory backing, and deferral of the external-driver gRPC proxy. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Riccardo Sabatini <riccardo.sab@gmail.com>
Extract the 9p/virtiofs/sshfs mount-option and fstype computation from cidata into pkg/mountutil so the runtime hot-mount path and the boot-time cloud-init path share one source of truth. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Riccardo Sabatini <riccardo.sab@gmail.com>
On Linux, back guest memory with memory-backend-memfd (share=on) so virtiofs devices can be hot-plugged at runtime, and reserve 8 spare pcie-root-port controllers on q35/virt as hot-plug slots. Non-Linux qemu hosts keep the existing /dev/shm backing for static virtiofs. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Riccardo Sabatini <riccardo.sab@gmail.com>
Add FSHotPlugger plus HotPlugFS/HotUnplugFS request/response types and ErrFSHotPlugUnsupported. ConfiguredDriver delegates to the wrapped driver when it implements the capability, so non-supporting drivers (VZ, WSL2, krunkit) need no changes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Riccardo Sabatini <riccardo.sab@gmail.com>
Add runtime attach/detach of virtio-9p-pci and vhost-user-fs-pci devices via QMP: PCIe slot allocator over the spare lima-hp-* root ports, virtiofsd lifecycle per virtiofs share, chardev-add/device_add (virtiofs) and fsdev_add/device_add (9p), and device_del waiting on DEVICE_DELETED before freeing the slot. virtiofsd leaks are reaped on Stop. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Riccardo Sabatini <riccardo.sab@gmail.com>
Add a runtime hot-mount registry to the host agent. reverse-sshfs reuses the existing setupMount; 9p/virtiofs attach a device via the driver's FSHotPlugger capability and mount it in the guest over SSH (with rollback on failure). Mounts are torn down on shutdown. guestExec is injected for testability. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Riccardo Sabatini <riccardo.sab@gmail.com>
Add POST/GET/DELETE /v1/mounts to the host agent HTTP API plus matching client methods and a httpclientutil.Delete helper. Backend now depends on a narrow Agent interface (satisfied by *HostAgent), which decouples the server from the hostagent package and enables handler tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Riccardo Sabatini <riccardo.sab@gmail.com>
Add 'limactl mount add|remove|list' to mount and unmount host directories into a running instance at runtime over the host agent /v1/mounts API. --type defaults to virtiofs; --writable controls write access. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Riccardo Sabatini <riccardo.sab@gmail.com>
Document 'limactl mount add|remove|list' in the mount docs (QEMU/Linux only, ephemeral, virtiofs default, 8-mount limit) and add a hack integration test exercising virtiofs, 9p, and reverse-sshfs hot-mounts host<->guest. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Riccardo Sabatini <riccardo.sab@gmail.com>
- shell-escape guest mount/umount paths (avoid injection/breakage on unusual mount points) - retry the guest mount to tolerate PCI hot-plug enumeration latency - reap virtiofsd in closeHotPlug (avoid zombies) via shared killProcess - reject 9p host paths containing spaces/commas that would corrupt the HMP fsdev_add command - do not fail/block host agent shutdown on hot-mount teardown errors - log chardev-remove rollback failures - set SSHFS defaults only for reverse-sshfs; reuse qemuConfig() in Start() Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Riccardo Sabatini <riccardo.sab@gmail.com>
VZ's Virtualization.framework has no device hot-plug API, so instead of adding a device per mount (as QEMU does), the VZ driver reserves 8 spare empty virtio-fs devices at boot and populates their share at runtime. - pkg/driver/vz/vm_darwin.go: reserve spare virtio-fs devices (tags lima-hotmount-0..7) on Linux guests, at directory-share indices 0..7. - pkg/driver/vz/hotplug_darwin.go: implement driver.FSHotPlugger by setting/clearing a spare device's share via a new binding method. - pkg/driver/driver.go: HotPlugFSResponse.Tag lets a driver with fixed pre-reserved device tags (VZ) tell the host agent which tag to mount. - third_party/Code-Hex-vz: vendored fork of Code-Hex/vz adding (*VirtualMachine).SetVirtioFileSystemDeviceShareAtIndex (runtime share mutation); isolated patch in hack/patches/, to be upstreamed. The host agent, /v1/mounts API, and limactl mount command are unchanged: VZ slots in purely by implementing the FSHotPlugger capability interface. Verified on native VZ (macOS 26, Apple silicon): hot-mount/unmount, two concurrent mounts, slot reuse, writable/read-only, ~5 GB/s read. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Riccardo Sabatini <riccardo.sab@gmail.com>
…t-mount Document the macOS/VZ build requirements for runtime hot-mount: Xcode CLT for the CGo VZ driver, the automatic virtualization-entitlement codesign, and the in-tree vendored Code-Hex/vz fork (with go.mod replace) that carries the runtime share-mutation method until it is upstreamed. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Riccardo Sabatini <riccardo.sab@gmail.com>
Cover the bin/share layout limactl expects relative to its binary, which guest agents and external deps (qemu, virtiofsd) to bundle per driver, macOS codesigning/entitlements and notarization for the embedded limactl, and runtime configuration (LIMA_HOME, PATH). Notes that the vendored Code-Hex/vz fork is compile-time only and that hot-mount works embedded. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Riccardo Sabatini <riccardo.sab@gmail.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Riccardo Sabatini <riccardo.sab@gmail.com>
These brainstorm spec/plan files are local workflow notes, not part of the Lima codebase. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Riccardo Sabatini <riccardo.sab@gmail.com>
- exclude vendored third_party/Code-Hex-vz from codespell, ls-lint, and editorconfig-checker (upstream code, not subject to our conventions) - fix golangci-lint findings in the hot-mount code: intrange, noctx, empty-block (revive), slices.Contains, unnecessary-format, unconvert, unnamedResult, forbidigo (t.Fatal*) and usetesting (t.Context) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Riccardo Sabatini <riccardo.sab@gmail.com>
…ndows - ltag: add third_party to -excludes (vendored fork carries upstream headers, not the Lima SPDX boilerplate) - validateHotMount: validate the guest mount point with path.IsAbs (Unix semantics) instead of filepath.IsAbs, which rejects /mnt/... on Windows hosts and broke the unit tests Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Signed-off-by: Riccardo Sabatini <riccardo.sab@gmail.com>
There was a problem hiding this comment.
Please send this patch to the upstream
There was a problem hiding this comment.
Hi @AkihiroSuda agree, this must go upstream, for now I copied the VZ code and added the batch in this branch not to rely on the release from VZ (so you guys can test it). I'll submit a PR to their repo, hopefully this will be fast. Once done I'll remove the patch and the VZ code from this PR (and other pieces managing the compilation, etc)
There was a problem hiding this comment.
New tests should be written in BATS
https://github.com/lima-vm/lima/tree/master/hack/bats
There was a problem hiding this comment.
Why fork the entire vz into third_party/Code-Hex-vz?
| > **Warning** | ||
| > Runtime hot-mount is experimental | ||
|
|
||
| | ⚡ Requirement | Lima >= 2.1.0; QEMU driver on a Linux host, or the VZ driver on macOS | |
| > `com.apple.security.virtualization` entitlement (from `vz.entitlements`). This signature is | ||
| > required for the VZ driver, including runtime [hot-mount](../../config/mount#runtime-hot-mounts). | ||
| > If you re-sign or strip the binary, re-apply the entitlement with | ||
| > `codesign -f --entitlements vz.entitlements -s - <binary>`. |
There was a problem hiding this comment.
Why does this need to be documented?
There was a problem hiding this comment.
Same thing, to remove once VZ accept the PR
| - `git` | ||
| - `go` | ||
| - `make` | ||
| - On **macOS**: the Xcode Command Line Tools (`xcode-select --install`), required to build |
There was a problem hiding this comment.
Not relevant to host-mounts
Not ready until unforking vz |
|
|
||
| // FSType returns the guest filesystem type string for a mount type and guest OS. | ||
| // It returns an empty string for unknown mount types. | ||
| func FSType(mountType limatype.MountType, os limatype.OS) string { |
There was a problem hiding this comment.
Why is this function needed?
| sudo mkdir -p %[1]s | ||
| i=0 | ||
| while [ "$i" -lt 30 ]; do | ||
| if sudo mount -t %[2]s -o %[3]s %[4]s %[1]s; then exit 0; fi |
There was a problem hiding this comment.
sudo is being discouraged
#5109 (comment)
The guestagent should have a proper API for this?
|
@AkihiroSuda let me know if this is something you guys would like to integrate, once polished - happy to work on the upstream VZ PR in case |
Yes
Does this PR work? |
Interesting, might be, I'll give a check tomorrow (getting late on my side) |
First off, thank you for Lima. It's become the backbone of how a lot of us run Linux on macOS, and digging through the codebase to build this, I came away genuinely impressed: the driver abstraction, the host-agent/guest-agent split, and the overall clarity made a fairly deep feature far more approachable than it had any right to be. The VsockEventEmitter optional-interface pattern in particular is lovely, and it's what this PR builds on.
Huge respect to the maintainers and contributors. 🙏
What this adds
A new command to mount/unmount host folders into a running instance, with no restart:
Mounts are ephemeral (not written to lima.yaml). The motivation: people currently reach for NFS/sshfs to get a folder into a live VM, and the throughput/memory behavior is rough. virtiofs is dramatically better: in testing here a hot-mounted folder reads at ~5 GB/s on VZ, identical to a statically-configured virtiofs mount.
How it works
It's exposed as a new optional driver.FSHotPlugger capability interface (modeled on VsockEventEmitter), so the CLI, the ha.sock /v1/mounts API, and the host-agent mount registry are all driver-agnostic, a driver opts in by implementing the interface, and everything else "just works."
memory (memory-backend-memfd,share=on) and 8 spare pcie-root-port controllers as hot-plug slots. The guest-side mount runs over the existing SSH connection.
addition to the Code-Hex/vz binding (see notes below).
The host-agent/guest-agent gRPC proto is untouched, guest mounts use the existing ssh.ExecuteScript helper.
Testing
Notes & deliberate tradeoffs
A few things are intentional choices that are really the maintainers' call, flagging them transparently so nothing's hidden:
For full transparency
This was developed with AI assistance (hence the Co-Authored-By trailers); all commits are DCO signed-off by me, and I've reviewed and tested everything on real hardware.
I'm offering the feature and the implementation here as a complete, working starting point. If it's of interest to the project, I'll happily defer to your senior maintainers on how you'd like to take it forward — splitting it,upstreaming the vz change first, gating the boot behavior, or reworking the packaging.
Thanks again for the project, and for taking the time to look. 🙇