feat: add virtiofs support for Linux guests

Automatically use virtiofsd (vhost-user-fs-pci) instead of 9p when
virtiofsd is present on the host and the guest OS is Linux. Falls back
silently to 9p when virtiofsd is unavailable. Updates README to document
the new capability.
This commit is contained in:
Dino Korah 2026-03-22 16:37:20 +00:00
parent b541fe1c58
commit ff9f386399
2 changed files with 66 additions and 8 deletions

View File

@ -47,6 +47,7 @@ required to run the virtual machines.
- **Nearly 1000 operating system editions are supported!**
- Full SPICE support including host/guest clipboard sharing
- VirtIO-webdavd file sharing for Linux and Windows guests
- VirtIO-fs file sharing for Linux guests (*automatically preferred over 9p when `virtiofsd` is installed on the host*)
- VirtIO-9p file sharing for Linux and macOS guests
- [QEMU Guest Agent
support](https://wiki.qemu.org/Features/GuestAgent); provides access

View File

@ -1544,15 +1544,16 @@ function configure_file_sharing() {
*) echo " - WebDAV: On guest: dav://localhost:9843/";;
esac
# 9P
# virtiofs or 9p depending on host capability
if [ "${guest_os}" != "windows" ] || [ "${guest_os}" == "windows-server" ]; then
echo -n " - 9P: On guest: "
if [ "${guest_os}" == "linux" ]; then
echo "sudo mount -t 9p -o trans=virtio,version=9p2000.L,msize=104857600 ${PUBLIC_TAG} ~/$(basename "${PUBLIC}")"
if [ "${guest_os}" == "linux" ] && [ -n "${VIRTIOFSD}" ]; then
echo " - virtiofs: On guest: sudo mount -t virtiofs ${PUBLIC_TAG} ~/$(basename "${PUBLIC}")"
elif [ "${guest_os}" == "linux" ]; then
echo " - 9P: On guest: sudo mount -t 9p -o trans=virtio,version=9p2000.L,msize=104857600 ${PUBLIC_TAG} ~/$(basename "${PUBLIC}")"
elif [ "${guest_os}" == "macos" ]; then
# PUBLICSHARE needs to be world writeable for seamless integration with
# macOS. Test if it is world writeable, and prompt what to do if not.
echo "sudo mount_9p ${PUBLIC_TAG}"
echo " - 9P: On guest: sudo mount_9p ${PUBLIC_TAG}"
if [ "${PUBLIC_PERMS}" != "drwxrwxrwx" ]; then
echo " - 9P: On host: chmod 777 ${PUBLIC}"
echo " Required for macOS integration 👆"
@ -1616,6 +1617,37 @@ function configure_cpu_pinning() {
echo " - CPU Pinning: Bind guest cores to host cores (${GUEST_CPUS} -> ${CPU_PINNING})"
}
function start_virtiofsd() {
# Start virtiofsd as a background daemon and record its PID so it can be
# cleaned up when the VM exits. The socket path is placed alongside other
# VM runtime files in VMDIR.
if [ -z "${VIRTIOFSD}" ]; then
return
fi
VIRTIOFSD_SOCKET="${VMDIR}/${VMNAME}.virtiofsd-sock"
local virtiofsd_args=(
--socket-path="${VIRTIOFSD_SOCKET}"
--shared-dir="${PUBLIC}"
--announce-submounts
)
echo "${VIRTIOFSD} ${virtiofsd_args[*]} &" >> "${VMDIR}/${VMNAME}.sh"
${VIRTIOFSD} "${virtiofsd_args[@]}" >> "${VMDIR}/${VMNAME}.log" 2>&1 &
VIRTIOFSD_PID=$!
sleep 0.25
if ! kill -0 "${VIRTIOFSD_PID}" 2>/dev/null; then
echo " - WARNING! virtiofsd failed to start; falling back to 9p."
VIRTIOFSD=""
VIRTIOFSD_SOCKET=""
VIRTIOFSD_PID=""
return
fi
echo " - virtiofsd: ${VIRTIOFSD_SOCKET} (${VIRTIOFSD_PID})"
}
function vm_boot() {
AUDIO_DEV=""
BALLOON="-device virtio-balloon"
@ -2053,12 +2085,23 @@ function vm_boot() {
fi
fi
# File sharing: prefer virtiofs (shared memory, lower latency) over 9p when
# virtiofsd is available; virtiofsd must already be running at this point.
# https://wiki.qemu.org/Documentation/9psetup
# https://askubuntu.com/questions/772784/9p-libvirt-qemu-share-modes
if [ "${guest_os}" != "windows" ] || [ "${guest_os}" == "windows-server" ] && [ -n "${PUBLIC}" ]; then
# shellcheck disable=SC2054
args+=(-fsdev local,id=fsdev0,path="${PUBLIC}",security_model=mapped-xattr
-device virtio-9p-pci,fsdev=fsdev0,mount_tag="${PUBLIC_TAG}")
if [ -n "${VIRTIOFSD_SOCKET}" ]; then
# virtiofs requires a shared-memory backend; the size mirrors the VM RAM.
# shellcheck disable=SC2054
args+=(-object "memory-backend-file,id=mem,size=${RAM_VM},mem-path=/dev/shm,share=on"
-numa node,memdev=mem
-chardev "socket,id=char0,path=${VIRTIOFSD_SOCKET}"
-device "vhost-user-fs-pci,queue-size=1024,chardev=char0,tag=${PUBLIC_TAG}")
else
# shellcheck disable=SC2054
args+=(-fsdev local,id=fsdev0,path="${PUBLIC}",security_model=mapped-xattr
-device virtio-9p-pci,fsdev=fsdev0,mount_tag="${PUBLIC_TAG}")
fi
fi
if [ -n "${USB_PASSTHROUGH}" ]; then
@ -2469,6 +2512,16 @@ function fileshare_param_check() {
PUBLIC_PERMS=$(${STAT} -c "%A" "${PUBLIC}")
fi
fi
# Prefer virtiofs over 9p when virtiofsd is available and the guest is Linux.
# virtiofs uses shared memory rather than a transport protocol, giving much
# lower latency and higher throughput than 9p.
if [ -n "${PUBLIC}" ] && [ "${guest_os}" == "linux" ]; then
VIRTIOFSD=$(command -v virtiofsd 2>/dev/null || echo "/usr/lib/qemu/virtiofsd")
if [ ! -x "${VIRTIOFSD}" ]; then
VIRTIOFSD=""
fi
fi
}
function parse_ports_from_file {
@ -2579,6 +2632,9 @@ MONITOR_CMD=""
PUBLIC=""
PUBLIC_PERMS=""
PUBLIC_TAG=""
VIRTIOFSD=""
VIRTIOFSD_PID=""
VIRTIOFSD_SOCKET=""
SHORTCUT_OPTIONS=""
SNAPSHOT_ACTION=""
SNAPSHOT_TAG=""
@ -2903,6 +2959,7 @@ viewer_param_check
fileshare_param_check
if [ -z "${VM_PID}" ]; then
start_virtiofsd
vm_boot
start_viewer
# If the VM being started is an uninstalled Windows VM then auto-skip the press-any key prompt.