How to Share Files Between Host and Guest VMs on Fedora (virtiofs, shared folders)

Fedora's KVM/QEMU stack supports virtiofs, a high-performance shared filesystem that lets you mount host directories directly inside a guest VM with minimal overhead.

You just finished a clean Fedora install inside a KVM virtual machine

You have a project directory on the host that needs to be accessible from the guest. Dragging files through the clipboard fails. Copying over a virtual network adapter takes forever and wastes CPU cycles on packet processing. You need a direct, high-throughput shared folder that respects Linux permissions, preserves extended attributes, and survives reboots. The clipboard is for text. Network shares are for remote servers. For a local VM, you need a paravirtualized filesystem.

What is actually happening

virtiofs is not a network file system. It does not use TCP, UDP, or any routing stack. It uses a paravirtualized interface that connects the guest kernel directly to a host-side daemon called virtiofsd. When the guest opens a file, the request travels through a shared memory ring buffer to the daemon. The daemon performs the actual open(), read(), and stat() syscalls on the host filesystem, then returns the results to the guest. This bypasses network overhead and preserves hard links, POSIX permissions, and SELinux labels.

Older methods like 9pfs route everything through a slower, less capable protocol that struggles with modern Linux features. 9pfs was designed for early virtualization environments and lacks proper support for modern mount options, extended attributes, and high-concurrency I/O. virtiofs is the standard because it treats the shared directory as if it were locally mounted, just with a different backing store. The guest sees a regular filesystem. The host handles the actual disk access.

Mount the share by tag, not by path. The guest never sees the host directory tree.

The fix or how-to

Start with the host. Fedora ships the virtualization stack in modular groups. You need the base management tools and the virtiofs daemon package. The daemon is not installed by default on minimal server images.

sudo dnf install -y qemu-kvm libvirt virt-install virtiofsd # WHY: pulls the hypervisor, management daemon, and the virtiofsd translator
sudo systemctl enable --now libvirtd # WHY: starts the libvirt socket so virsh and virt-manager can talk to QEMU

Configure the shared folder through virsh edit. This command validates the XML schema before saving, which prevents malformed definitions from breaking your VM. Never edit the raw files in /etc/libvirt/qemu/ directly. Manual edits bypass validation and drift from libvirt's internal state.

virsh edit fedora-guest # WHY: opens the VM definition in your $EDITOR with automatic schema validation

Add the filesystem device inside the <devices> block. The target dir attribute becomes the mount tag the guest will use. The guest does not care about the host path. It only knows the tag.

<filesystem type="mount" accessmode="passthrough">
  <driver type="virtiofs"/> # WHY: tells QEMU to use the virtiofs paravirtualized driver instead of 9p or legacy scsi
  <source dir="/home/user/shared"/> # WHY: points to the actual host directory you want to expose
  <target dir="hostshare"/> # WHY: defines the mount tag the guest kernel will look for
</filesystem>

virtiofs requires shared memory backing to function. QEMU needs to map the ring buffer into a memory region that both the host daemon and the guest kernel can access simultaneously. Without this, the VM will refuse to start.

<memoryBacking>
  <source type="memfd"/> # WHY: creates an anonymous file descriptor for the shared memory region
  <access mode="shared"/> # WHY: allows multiple processes (QEMU and virtiofsd) to map the same pages
</memoryBacking>

Save the file and restart the VM. virsh destroy forces a clean shutdown if the guest is running. virsh start boots it with the new configuration.

virsh destroy fedora-guest # WHY: stops the running VM so the new XML definition can be applied
virsh start fedora-guest # WHY: boots the guest with the updated virtiofs device and memory backing

Inside the guest, create a mount point and attach the share. The mount command uses the tag you defined in the XML, not the host path.

sudo mkdir -p /mnt/hostshare # WHY: creates a stable directory for the mount point
sudo mount -t virtiofs hostshare /mnt/hostshare # WHY: binds the virtiofs device tagged 'hostshare' to the local directory

Make the mount persistent across reboots. Add an entry to the guest's /etc/fstab. The first field is the tag, not a device node or IP address.

hostshare  /mnt/hostshare  virtiofs  defaults  0  0 # WHY: tells the guest init system to mount this tag at boot using virtiofs

Run systemctl daemon-reload if you changed the fstab while the guest was running. The init system caches mount tables and will ignore new entries until you refresh it.

Mount the share by tag, not by path. The guest never sees the host directory tree.

Verify it worked

Check the mount table and filesystem type. The output should show virtiofs in the type column. If it shows 9p, tmpfs, or nfs, you configured the wrong driver or the daemon failed to start.

df -T /mnt/hostshare # WHY: displays the filesystem type and available space for the mount point
mount | grep virtiofs # WHY: confirms the kernel recognized the device and applied the correct driver

Create a test file from the host and verify it appears in the guest. Permissions and ownership should match the host user who created the file. virtiofs preserves the original UID and GID. If you see root or nobody instead of your actual user, check the host directory permissions and SELinux contexts.

touch /home/user/shared/testfile.txt # WHY: creates a marker file on the host to verify bidirectional visibility
ls -l /mnt/hostshare/testfile.txt # WHY: confirms the guest sees the file with correct ownership and permissions

Run df -T before you copy files. If the filesystem type says 9p or tmpfs, you configured the wrong driver.

Common pitfalls and what the error looks like

SELinux is the most frequent blocker. Fedora enforces mandatory access control on the host. The virtiofsd process runs in a confined domain and cannot read arbitrary directories without the correct label. If the guest shows Permission denied on every file, check the host audit log.

type=AVC msg=audit(1715423891.123:456): avc:  denied  { read } for  pid=1234 comm="virtiofsd" name="shared" dev="sda1" ino=789 scontext=system_u:system_r:virtiofsd_t:s0 tcontext=unconfined_u:object_r:home_root_t:s0 tclass=dir permissive=0

The denial shows virtiofsd_t trying to read a directory labeled home_root_t. Restore the correct context for the shared directory. The restorecon command applies the default policy label for that path.

sudo ausearch -m avc -ts recent # WHY: filters the audit log for recent SELinux denials so you can read the exact failure
sudo restorecon -Rv /home/user/shared # WHY: recursively resets the security context to match the host policy defaults

Missing shared memory backing causes a hard failure at boot. QEMU will refuse to launch the VM and print a clear error in the libvirt logs.

error: Failed to start domain fedora-guest
error: internal error: process exited while connecting to monitor: qemu-system-x86_64: -device virtio-9p-pci,fsdev=fsdev.0,mount_tag=hostshare: virtiofsd: shared memory not available

The error explicitly mentions shared memory. Add the <memoryBacking> block from the previous section and restart.

Mount tag mismatches cause the guest mount command to fail silently or throw a device-not-found error. The guest kernel only knows about tags exposed by the hypervisor. If you type the wrong tag, the kernel has nothing to bind.

mount: /mnt/hostshare: special device hostshare does not exist.

Double-check the <target dir> value in the VM XML. It must match the first argument to mount -t virtiofs exactly. Case sensitivity matters.

UID and GID mismatches cause confusing permission errors when files are created from the opposite side. virtiofs does not translate IDs. A file created by host user 1000 will appear as 1000 in the guest. If the guest does not have a user with that ID, the file shows as nobody or unknown. This is expected behavior. Align your user IDs across both systems or use idmap options if you need translation.

Check journalctl -xeu virtiofsd@<vm-name>.service before you blame the guest. The daemon logs the exact syscall that failed.

When to use this vs alternatives

Use virtiofs when you need high-throughput bidirectional file access between a local host and a KVM guest. Use 9pfs when you are maintaining legacy VMs that predate Fedora 33 and cannot upgrade the guest kernel. Use NFS or Samba when you need to share files with physical machines across a network or when the guest runs Windows. Use rsync or scp when you only need to transfer files occasionally and do not want a persistent mount. Stay on virtiofs if you are running development workloads, container builds, or media editing pipelines inside the VM.

Pick the tool that matches your I/O pattern. Shared memory beats network sockets every time.

Where to go next