July 11, 2023•526 words
Libvirt (and by extension, virt-manager) has supported filesystem passthrough to guest for a long time. This is implemented through one of two mechanisms: virtio-9p, or virtio-fs.
virtio-9p is basically the
virtio version of the famous Plan 9 filesystem protocol. With
virtio-fs, the host-side filesystem is passed through directly via a FUSE-like protocol running over the virtio transport, which promises high performance and native POSIX filesystem semantics.
Compared to file sharing with guests through NFS/SMB, both of these options tend to provide a much better experience. At the very least, one would not have to set up all the authentication and security measures associated with NFS or SMB. One limitation of
virtio-fs, however, is that it must be run as root on the host, because it also passes through all the POSIX attributes (
gid, etc.) as-is to the guest, and thus whatever is executing on the host must actually possess the permission to write as any user or group.
9p as a network protocol does not share this restriction, and works perfectly fine with Linux guests. However, the only supported filesystem sharing protocol for Windows guests is
virtio-fs, and having to use a system-wide (root) libvirtd session makes it really inconvenient, not to mention all the headaches with host-side file ownership when you have a VM running as root.
Fortunately, there seems to be a workaround. The host-side handling logic of
virtio-fs is executed as a separate process (which libvirtd will launch automatically) called virtiofsd. Instead of running this process as the actual
root user on the host, we can feasibly just isolate this process into a user namespace, with the
root user mapped to a normal, non-privileged user on the host (e.g. your regular user account). This is similar to how containerization tools like Podman work in rootless mode -- and the same containerization developers have kindly extracted all the namespace initialization code into a separate tool called RootlessKit. Any program wrapped with the
rootlesskit command would gain a "fake" rootful view into the filesystem, with the
root user actually mapped to the current user on host, perfect for running
With this tool, it is actually simple to bring up a rootless
rootlesskit virtiofsd --socket-path /path/to/virtiofsd.sock --shared-dir /path/to/shared/dir
and tell libvirtd (and QEMU) to use that instead of launching its own (by editing the XML definition of your libvirtd domain):
<filesystem type="mount" accessmode="passthrough"> <driver type="virtiofs" queue="1024"/> <source socket="/path/to/virtiofsd.sock"/> <target dir="your_dir_name"/> </filesystem>
Note that if you then try to edit this filesystem node in
virt-manager GUI, it would result in an error, but it is purely a UI bug and can be safely ignored. After saving the XML, you should then be able to launch the VM and mount the
your_dir_name share using the guest-side
To make launching
virtiofsd more convenient, I also came up with a systemd user service file (as
[Unit] Description=Virtio FS Daemon instance %i [Service] ExecStartPre=/usr/bin/mkdir -p %h/shared/%i ExecStart=/usr/bin/rootlesskit /usr/lib/virtiofsd --socket-path %t/virtiofsd-%i.sock --shared-dir %h/shared/%i Restart=always RestartSec=2s [Install] WantedBy=default.target
Using this unit, when you enable/launch, for example,
virtiofsd process will be launched that shares
$HOME/shared/windows, and listens on