virtio Drivers Explained
Introduction¶
When a VM uses an emulated device (e1000 NIC, IDE disk), every I/O operation traps to the hypervisor, which mimics real hardware register by register — slow. virtio is a standardised paravirtual interface: the guest knows it's virtualised and talks to the host through efficient shared-memory ring buffers.
The virtio device families¶
| Device | Replaces | Notes |
|---|---|---|
virtio-net |
e1000 / rtl8139 | paravirtual NIC; multi-queue capable |
virtio-blk |
IDE / SATA | simple fast block device (/dev/vda) |
virtio-scsi |
LSI SAS | SCSI stack: more LUNs, discard/TRIM, passthrough, hotplug |
virtio-balloon |
— | host reclaims guest RAM on demand |
virtio-rng |
— | feeds host entropy to the guest (avoids entropy starvation) |
virtio-gpu |
Cirrus / QXL | paravirtual graphics |
virtio-fs / 9p |
— | share a host directory into the guest |
virtio-vsock |
— | host↔guest socket channel |
For disks, prefer virtio-scsi over virtio-blk on anything non-trivial — it supports TRIM/discard (thin reclaim), more devices, and online resize.
libvirt XML¶
<disk type='file' device='disk'>
<driver name='qemu' type='qcow2' discard='unmap' queues='4'/>
<source file='/var/lib/libvirt/images/vm.qcow2'/>
<target dev='sda' bus='scsi'/>
</disk>
<controller type='scsi' model='virtio-scsi'/>
<interface type='network'>
<source network='default'/>
<model type='virtio'/>
<driver name='vhost' queues='4'/>
</interface>
<memballoon model='virtio'/>
<rng model='virtio'>
<backend model='random'>/dev/urandom</backend>
</rng>
<driver name='vhost'> moves the virtio-net datapath into the host kernel
(vhost-net) — much faster than QEMU userspace handling it.
Guest drivers¶
- Linux: virtio drivers are in the mainline kernel. Any modern distro just
works — you'll see
/dev/vdaorvirtio-scsi/dev/sda, andvirtio_net. Make sure the initramfs includes them if the root disk is virtio (it is by default on distro cloud images). - Windows: not built in. Install the virtio-win driver package (Fedora/RHEL ships an ISO). Attach the ISO, install the NetKVM (network), viostor/vioscsi (storage), balloon, and vioserial drivers. For a fresh Windows install onto a virtio disk, load vioscsi during setup ("Load driver"), or the installer won't see the disk.
Multi-queue¶
One queue = one CPU handles all I/O for that device. Multi-queue spreads it:
<driver name='vhost' queues='4'/> <!-- net: match vCPU count, up to 8-ish -->
<driver name='qemu' queues='4'/> <!-- virtio-scsi/blk -->
In the Linux guest, enable the net queues:
ethtool -L eth0 combined 4. Helps high-PPS or high-IOPS workloads; pointless
for a mostly-idle VM.
Verification and troubleshooting¶
# In the guest
lspci | grep -i virtio
lsmod | grep virtio
ethtool -i eth0 # driver: virtio_net
lsblk -d -o NAME,TRAN # TRAN = virtio
cat /sys/block/vda/queue/rotational # 0
- Windows VM: no network / no disk after migrating from another hypervisor — virtio-win drivers not installed. Boot with an e1000 NIC / SATA disk first, install virtio-win, then switch.
- Windows install "no drives found" — load
vioscsi/viostorfrom the virtio-win ISO during setup. - Guest slow disk despite virtio — cache mode (
cache='none'+io='native'orio='threads'for best throughput/safety), backing storage is slow, orqcow2on top of a network filesystem. Also checkdiscard='unmap'for thin volumes. - TRIM/
fstrimdoes nothing — virtio-blk without discard support, or missingdiscard='unmap'. Use virtio-scsi. - Entropy starvation in the guest (slow SSH/TLS on boot) — add
virtio-rng. - Balloon deflating unexpectedly / guest OOM — the host reclaimed too much via the balloon. Set a floor, or disable auto-ballooning and manage memory explicitly.
- Multi-queue set but only one CPU busy — guest side not enabled
(
ethtool -L), or the workload is single-threaded / single-flow.
Related tools and reading¶
- On-site: Linux commands reference.
- Related posts: KVM and libvirt: your first VM, libvirt networking: NAT vs bridged.
Stuck on something this site can't fix?Reach out to Prabath directly on LinkedIn.More in Virtualization
cloud-init for VM Templates
Build one generic image, then let cloud-init set the hostname, users, SSH keys, packages, and network per instance at first boot. Here's the NoCloud workflow for KVM.
October 24, 2026GPU Passthrough with VFIO
Passing a physical GPU to a VM needs IOMMU, a clean IOMMU group, vfio-pci binding, and often a vBIOS. Here's the path and the notorious failure modes.
October 24, 2026libvirt Networking: NAT vs Bridged vs Others
The default libvirt network NATs VMs behind the host — fine for a laptop, wrong for a server. Here's each mode and how to put VMs directly on your LAN.
October 24, 2026