Fedora, QEMU, and 9p Filesystem Passthrough

Previously I wrote an article about configuring NFS and autofs for use with a VM on Linux. The premise of that article is that you want to run a local VM, and you want to share files between the VM and the host machine. I described a mechanism for doing this by setting up an NFS server on the guest VM, and then using autofs on the host to automatically mount the guest filesystem as necessary. This does work, but I’ve since learned that it’s not at all the best way to configure things.

First, I’ve realized that it’s better to have the host OS also be the host for the filesystem. That is, the VM should mount the host filesystem, not the other way around. There are two reasons this is better:

The other thing I learned is that there’s this thing called 9p filesystem passthrough, which allows you to “directly” expose the host filesystem to the guest. I put “directly” in quotes here because the filesystem still needs to be mounted using a non-local driver, in this case using the 9p protocol. The difference here, compared to NFS, is that on Linux 9p has a native virtio driver which means that all of the filesystem operations are directly virtualized by the hypervisor. This means that everything is fast and there’s no weird network protocols (like NFS): everything is directly exposed by the kernel from the host to the guest.

Setting Up 9p Passthrough On Fedora

There are already a bunch of guides for configuring 9p passthrough on Linux, and I found that they all work except one step on Fedora, which is why I’m writing this post. The short version is that using virt-manager you expose a “filesystem” device and for the “source path” you point it at the directory on the host you want to share, and then for the “target path” you set up a unique tag like shared that you will be the name of the share. Then on the guest you mount the filesystem using the 9p mount type and using the options -o trans=virtio,version=9p2000.L,rw. I found this illustrated guide to be helpful; it even has pictures! If you don’t want to use virt-manager, just Googling “qemu 9p passthrough” should yield plenty of results explaining the relevant qemu command-line options.

Now once you do all of this, on Fedora you’ll run into a problem. If you did everything correctly you’ll find that while the guest can read files, it won’t be able to write to them, regardless of what fsdev security model you use. In other words, the mount will act like a read-only mount, even if you have it mounted read-write and have the right user ids and directory permissions and whatnot. More concretely, any system calls that open files for writing will fail with an EPERM error.

After a lot of head scratching I found this virt-users mailing list email about the issue. The issue is that by default on Fedora libvirt will arrange for the QEMU process to be run as a special, unprivileged user: the qemu user. The problem is that if you’re trying to mount files in your home directory, the qemu user won’t have the correct permissions to access those files. What you want, instead, is for the QEMU process to run as your own user id. This is easy to set up. Edit the file /etc/libvirt/qemu.conf and find the commented out lines for user and group, and make them look something like this:

user = "YOUR_USERNAME_HERE"
group = "YOUR_USERNAME_HERE"

Of course, the actual user and group on your system will probably be different (unless your Unix login happens to be YOUR_USERNAME_HERE).

After you make this change you’ll have to restart any active QEMU processes, e.g. by restarting any guests you have in virt-manager. Then confirm that in the process listing the QEMU process is running as the expected user id, e.g. by examining ps -ef | grep qemu. If that looks OK, you should be able to log into the guest and write to files!

I hope this article helps save a fellow Fedora user some time, since it took me quite a while to hunt this down.