File System Pass-Through in KVM/Qemu/libvirt

This post doesn’t cover fully setting up KVM/Qemu with virt-manager and creating virtual machine guests. See the Ubuntu KVM Installtion, VirtManager Guide, the Ubuntu Server Guide on libvirt, or HowtoForge for that.

Instead this blog post details the most relevant steps to get file system pass-through between a Linux host and Qemu guest working. The upstream Qemu docs provide a good starting point, as is the original IBM paper on VirtFS. For users of Ubuntu <= 13.04, watch out for the libvirt bug that I know many people run into, myself included.

First of all, I could never really master the beast called AppArmor in Ubuntu. Once I got the hang of the files to edit, the order to make changes and the syntax of its profile files I think I tried every possible permutation without any success. So I ended up disabling the profile(s) of my VM guests. The UUID in the filename can be found in the details of your VM, or in the process listing on the host: ps fax | grep guestname. Here is an example of how to disable one guest:

aa-complain /etc/apparmor.d/libvirt/libvirt-20b8c6c6-440c-bd76-254e-42fd475e6770

You need to install apparmor-utils to get the aa-complain tool. Where complain basically means ignore any hits from the given profile and just complain in the log. The default is aa-enforce. For more info on AppArmor, see the excellent upstream docs

Now, how to do it. I like virsh, but for most of the time the vmware like virt-manager is a lot more user friendly. In the VM’s Detailed view, click the “Add Hardware” button and select “Filesystem”. This is where the action happens.

  • Type: preset to Passthrough
  • Mode: change to Mapped This is the most important step in this blog, or you will not get read/write support!
  • Source path: select the path on your host that will be shared with this guest. I use /var/lib/libvirt/share but you can use any directory you want
  • Target path: enter magic string that you’ll use in the mount command in the guest. I use share, no slashes or anything. In reality this isn’t a path per se, it’s a tag that the guest sends to the kernel 9p driver via the mount command

Please note that 9P file systems simply pass-through the owner UID/GID and directory permissions from the host to the guest. This can be a bit confusing, but just make sure to use the same for all guests that share the same directory. I chowned it to my account on the host:

host# chown jocke:users /var/lib/libvirt/share

In my guest:/etc/modules I added the following modules, even though the kernel can probably load them itself on demand:

9p
9pnet
9pnet_virtio

The actual command to get the ball rolling on the guest:

guest# mount -t 9p -o trans=virtio,version=9p2000.L,rw share /mnt

To automatically mount this every time at boot, add the following to your guest:/etc/fstab:

share   /mnt    9p  trans=virtio,version=9p2000.L,rw    0   0

That’s it. Good Luck!