Replace the stored AccessPlatform reference with one to the
VirtioDevice. By doing this not only does it allow the code to be
simplified but also now makes it virtio spec compliant by only
translating via the access platform if the feature is acknowledged.
Signed-off-by: Rob Bradford <rbradford@meta.com>
This forwards through to the VirtioCommon implementation and can be used
to simplify the virtio PCI access code.
Signed-off-by: Rob Bradford <rbradford@meta.com>
Adding this method to the trait will allow the virtio PCI code to access
a feature conditional version of the access platform and simplify the
logic.
Signed-off-by: Rob Bradford <rbradford@meta.com>
Use the new virtio feature gated accessor when creating the handlers for
the virtio devices. This now means that the translations via the
accessor will only be applied if the feature is acked in accordance with
the spec.
Signed-off-by: Rob Bradford <rbradford@meta.com>
Add VirtioCommon::access_platform() method. The virtio spec requires
that only if the feature is acked should the accesses be transformed via
the access platform implementation. This will enable that filtering.
Signed-off-by: Rob Bradford <rbradford@meta.com>
Previously, calling pause() when already paused would wait on a barrier
for worker threads that were already parked, causing a deadlock.
This situation occurs when the VMM thread holds a device mutex while
calling an operation that triggers pause(), and a vCPU thread
simultaneously needs that same mutex for MMIO access. With slow I/O
backends (like RBD/Ceph), the timing window for this race is larger,
making the deadlock more likely to occur, see [0].
Make pause() idempotent by checking the paused state atomically and
returning early if already paused, avoiding the barrier wait.
[0] https://github.com/cloud-hypervisor/cloud-hypervisor/pull/7948#discussion_r305052509
Signed-off-by: Vincent Thomas <vincent@v-thomas.com>
Make it easier to chase down which vhost user socket failed and why in
systems that have many vhost user devices.
Signed-off-by: Dylan Reid <dgreid@fb.com>
The address that is passed from the guest should be treated as
untrusted. Currently an invalid address will panic the VMM. This only
allows the guest to hurt itself, but we shouldn't have the VMM crashing.
Instead let's return an error if possible or invalidate the queue if it
happen during setup.
The data flow from guest to translate_gva/translate_gpa is:
1. Guest writes a raw u64 address into a virtio descriptor in the
shared descriptor table (guest memory).
2. The virtio-queue crate reads this descriptor via read_obj() and
returns the addr field as-is in a GuestAddress — no validation.
3. Device code calls .translate_gva(access_platform, len) on the
GuestAddress.
4. With IOMMU (access_platform is Some): the address is an IOVA that
must be translated to a GPA via the IOMMU mapping table. If the
guest provides an unmapped IOVA, translation returns Err.
Previously, .unwrap() here panicked the VMM.
5. Without IOMMU (access_platform is None): translate_gva is a no-op
(returns self). The raw address flows to GuestMemory::read_obj()
which validates it — out-of-range addresses return
Err(InvalidGuestAddress), so no host memory corruption is possible.
Signed-off-by: Dylan Reid <dgreid@fb.com>
Now on the generic restore path the worker thread is notified on the
events and also the guest is notified via the interrupt. This avoids the
same "livelock" situation that required this "driver_awake" workaround
when restoring the net device.
Signed-off-by: Rob Bradford <rbradford@meta.com>
This will wake up the guest and avoid a livelock situation by ensuring
that it will process any pending queues on its side.
Signed-off-by: Rob Bradford <rbradford@meta.com>
A restored virtqueue can already contain pending descriptors when the VM
resumes. Before this change, the worker thread was unparked and then
waited for a fresh queue eventfd signal. That is normally fine, but not
when the queue was already non-empty at snapshot time. The virtqueue
state lives in guest memory and is restored, but the original host-side
queue eventfd signal is not persistent snapshot state. If the guest
already notified the queue before the snapshot, it may not notify it
again after resume.
That can leave the worker idle while the guest is still waiting for the
pending request to complete. In one observed case, this stalled a
virtio-blk flush during early boot after snapshot/restore.
We mitigate this in the shared `VirtioCommon` resume path.
`VirtioCommon` retains cloned queue eventfds for activated virtqueues
and signals each of them once on resume after unparking the worker
threads.
Keep virtio-net on its existing special-case path: it resumes worker
threads without signaling queue eventfds so the `driver_awake`
workaround remains intact until the guest performs a real notify.
On-behalf-of: SAP leander.kohler@sap.com
Signed-off-by: Leander Kohler <leander.kohler@cyberus-technology.de>
When BAR reprogramming is detected, detect_bar_reprogramming()
eagerly updates the BAR address in config space before the actual
MMIO remapping occurs. If the subsequent move_bar() fails (e.g.
the new address falls outside the allocator range), the config
register retains the new address while the MMIO bus still uses
the old one, leaving the device broken.
Add restore_bar_addr() to undo the config space update when
move_bar() fails, so the device remains functional at its
original address.
For 64-bit BARs, restore both the low and high BAR slots as well
as the corresponding config registers, mirroring the two-slot
update logic in detect_bar_reprogramming().
Implement restore_bar_addr() for all PciDevice implementations
(VirtioPciDevice, VfioPciDevice, VfioUserPciDevice, IvshmemDevice,
PvPanicDevice, and PvmemcontrolPciDevice) by delegating to their
respective PciConfiguration::restore_bar_addr().
Signed-off-by: CMGS <ilskdw@gmail.com>
It is desirable to be able to track the progress of memory hotplug.
Update the memory_actual_size field to query the current plugged size
from virtio-mem to enable this.
Signed-off-by: Jared White <git@jaredwhite.dev>
After a vDPA device reset, activate_vdpa() read avail_idx from guest
memory to pass as the vring base via VHOST_SET_VRING_BASE. However,
the guest memory still contained the stale avail_idx from the previous
session. For a 256-entry ring, this meant base=256, causing the
hardware to believe the entire RX ring was consumed with no available
buffers — RX silently stopped while TX continued to work.
QEMU handles this correctly by tracking last_avail_idx internally
(reset to 0 in virtio_reset()) and passing that value, rather than
reading from guest memory.
Fix by always passing base=0 to set_vring_base(). After a device
reset, both the guest driver and the vhost backend restart their rings
from index 0. For live migration, the correct base should come from
VHOST_GET_VRING_BASE (saved before the migration), not guest memory.
Tested with mlx5_vdpa (ConnectX-6 Dx) + Windows Server 2025 (netkvm).
Before: RX=0 after 3rd driver activation. After: full connectivity.
Signed-off-by: Max Makarov <maxpain@linux.com>
Virtio v1.2 says that if CONFIG_WCE is negotiated
but FLUSH is not, the device must initialize writeback to 0.
It also says that if CONFIG_WCE was not negotiated but FLUSH
was, the driver should assume presence of a writeback cache.
Introduce a pure is_writeback_enabled helper and a
set_writeback_mode helper. This makes the two call flows
explicit:
* write_config resolves the guest requested mode against the
negotiated features before storing it back
* activate starts from the default writeback preference and then
resolves it against the negotiated features
* reset restores the initial writeback state
This keeps the config space value and the runtime writeback flag
in sync and makes the spec driven fallback easier to follow.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Refactor PciDevice::allocate_bars trait and all implementations
to take &mut SystemAllocator instead of &Arc<Mutex<SystemAllocator>>,
removing double indirection.
The caller in device_manager.rs now acquires the lock before
calling allocate_bars.
Signed-off-by: Chinmoy <daschinmoyy21@gmail.com>
Now that the VhostUserCommon::shutdown implementation has been filled
out to support migration it can also be used for the drop
implementations in the vhost-user devices.
It's worth noting that the call to wait_for_epoll_threads() was a no-op
as those threads are only configured on conventional virtio devices.
Signed-off-by: Rob Bradford <rbradford@meta.com>
Advertising support for this virtio feature is required to enable
support for migration. (Along with the LOG_SHMFD protocol feature.)
Signed-off-by: Rob Bradford <rbradford@meta.com>
If the epoll thread is paused, which would be expected as a part of live
migration/snapshot-restore unpause the thread so that it can receive the
kill event. This mirrors the reset() behaviour of virtio devices. It is
important here so as to close the connection with the vhost-user-backend
to allow same host and --local migration and since after getting the
device state the vhost-user backend should no longer be used.
As a result of this change we can do --local and same-host migration
with virtio-fs.
Signed-off-by: Rob Bradford <rbradford@meta.com>
This is used by all devices so it can be part of the common state.
Moving it simplifies the code and simplifies some future improvements
around shutdown for migration.
Signed-off-by: Rob Bradford <rbradford@meta.com>
Since vhost-user devices are always virtio devices it makes sense to
structure this struct inside the VhostUserCommon struct. This then also
makes some of the methods on VhostUserCommon cleaner since they can now
act directly on the common virtio bits (e.g. for kill_evt)
Signed-off-by: Rob Bradford <rbradford@meta.com>
PR #7852 fixed the missing VirtioBlockConfig fields but did not
change the feature advertisement logic. The condition
`sparse || disk_image.supports_zero_flag()` causes qcow2 to
advertise DISCARD even with sparse=false, because qcow2 can
mark clusters as zero (supports_zero_flag() returns true).
Windows viostor BSODs (DRIVER_IRQL_NOT_LESS_OR_EQUAL) when
DISCARD is advertised on qcow2 backends, making sparse=off
ineffective as a workaround for qcow2 images.
Restrict DISCARD to explicit sparse=true only. WRITE_ZEROES
remains available for all sparse-capable backends.
Fixes#7849
Signed-off-by: CMGS <ilskdw@gmail.com>
The queue_msix_vector register (offset 0x1a in virtio PCI common
config) was indexed into the msix_queues Vec using the guest-controlled
queue_select value without bounds checking. A malicious guest can set
queue_select to any u16 value via offset 0x16, then read or write
offset 0x1a to trigger an out-of-bounds panic, crashing the VMM.
Replace direct Vec indexing with .get()/.get_mut() for bounds-checked
access, returning VIRTQ_MSI_NO_VECTOR (0xFFFF) on OOB reads to match
the virtio "no vector" sentinel. Add a regression test that sets
queue_select to 0xFFFF and exercises both the read and write paths.
AI/LLM disclosure: this patch was co-authored with Claude Code.
Fixes#7917
Signed-off-by: Tobias Kässer <t.kaesser@gmail.com>
The sync fallback path in process_queue_submit() hardcoded
VIRTIO_BLK_S_IOERR for all errors. This caused unsupported
request errors to report IOERR to the guest instead of the
correct VIRTIO_BLK_S_UNSUPP.
Use ExecuteError::status() to return the appropriate status
code for each error variant.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Enable the DEVICE_STATE protocol feature negotiation for all vhost-user
devices (block, fs, net, and generic). Restoring the state (including
the backend state if present) and vrings.
Signed-off-by: Rob Bradford <rbradford@meta.com>
Add a common method for validating the state (checking vrings &
device_state) and then restoring the backend state if present.
Signed-off-by: Rob Bradford <rbradford@meta.com>
Fetch the opaque device state from the backend and store it along with
the last vring used in the state used for the snapshot.
Signed-off-by: Rob Bradford <rbradford@meta.com>
The vhost-user protocol now has support for the backend to provide an
opaque blob of data (read or written through a pipe) that the VMM can
use to save/restore state after snapshot/restore or live migration.
It also adds a command for checking the backend accepts the uploaded
device state. One quirk of saving the state is that GET_VRING_BASE must
be used first to quiesce the state of the backend and flush any
in-flight requests. This then also requires saving that index for use on
the restore.
Signed-off-by: Rob Bradford <rbradford@meta.com>
Rename update_supports_migration() to update_supported_features() as
this method will be extended to track additional capability flags beyond
just migration support (e.g. DEVICE_STATE for snapshot/restore.)
Signed-off-by: Rob Bradford <rbradford@meta.com>
This is a refactoring step in preparation for fetching backend device
state via SET_DEVICE_STATE_FD which can fail.
Signed-off-by: Rob Bradford <rbradford@meta.com>
In GenericVhostUser's read_config and write_config, access
vu_common.acked_protocol_features directly instead of going through
the state() method which creates a struct. This removes creating the
struct just to access two fields that are already directly accessible.
Signed-off-by: Rob Bradford <rbradford@meta.com>
With a common state structure for all vhost-user devices the state()
methods can also be refactored for reuse. This will make it easier to
add new common fields in the future for snapshot/restore.
Signed-off-by: Rob Bradford <rbradford@meta.com>
Each vhost-user device type had near identical State structs.
Deduplicate those by introducing a new common struct (and parameterising
it when it needs to embed a config member.) This will make it easier to
reuse more code in the future and to add more struct members to handle
the requirements of snapshot/restore.
These changes have been designed to have no impact on the existing
snapshot/restore state.
Signed-off-by: Rob Bradford <rbradford@meta.com>
Use logical_size() instead of physical_size() for the byte-range
advisory lock. physical_size() returns st_blocks*512 which is the
actual host allocation and can be smaller than the guest visible
extent on sparse files, leaving part of the range unprotected.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Previously this code could lead to the device being trying to be
activated multiple times as the code to trigger the activation was based
on the state of the device (not yet activated and device being ready).
This could occur if anothe vCPU wrote to a PCI BAR on this device before
the device activation was completed by the VMM thread. Now we only
trigger the activation if the device readiness has changed as a result
of this BAR write (by checking that the readiness was originally
unready.)
Signed-off-by: Rob Bradford <rbradford@meta.com>
When configuring multiple queues for a virtio device, the guest can
activate between 1 and the configured amount of queues. The firmware,
for example, may activate only one queue, while a Linux guest would
likely activate all available queues.
The constructor of virtio-blk initializes the `paused_sync` barrier
using the configured queue count (plus one for the main thread). This
can be wrong if the guest enable a different number of queues at
activation time, which can make pause hang. Thus, we now recompute the
barrier size from the queues that are actually activated.
On-behalf-of: SAP sebastian.eydam@sap.com
Signed-off-by: Sebastian Eydam <sebastian.eydam@cyberus-technology.de>
When configuring multiple queues for a virtio device, the guest can
activate between 1 and the configured amout of queues. The firmware,
for example, may activate only one queue, while a Linux guest would
likely activate all available queues.
The constructor of virtio-net initializes the `paused_sync` barrier
using the configured queue count (plus one for the main thread). This
can be wrong if the guest enables a different number of queues at
activation time, which can make pause hang. Thus, we now recompute the
barrier size from the queues that are actually activated.
On-behalf-of: SAP sebastian.eydam@sap.com
Signed-off-by: Sebastian Eydam <sebastian.eydam@cyberus-technology.de>
Bump to the released versions that are compatible wherever possible but
for the vhost and vfio crates they are git hashes as no releases with
compatible versions have yet been made.
Signed-off-by: Rob Bradford <rbradford@meta.com>
This now required after Rust-VMM crate bumps. Also reorder some syscalls
so that they are now in alphabetical order.
Signed-off-by: Rob Bradford <rbradford@meta.com>
Split the data length check into two conditions:
- reject descriptors shorter than one
virtio_blk_discard_write_zeroes segment, and
- reject payloads exceeding MAX_DISCARD_WRITE_ZEROES_SEG segments
Previously only the minimum length was checked and extra segments
were silently dropped.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Change Block to hold DiskBackend instead of
Box<dyn async_io::DiskFile>. In device_manager, existing formats
(raw, vhd, vhdx) are wrapped in DiskBackend::Legacy while
QcowDiskSync uses DiskBackend::Next. The fuzz target is updated
accordingly.
The Error::DiskResize variant now carries BlockError instead of
DiskFileError, matching the BlockResult return type of
DiskBackend::resize().
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Set discard_sector_alignment from the logical block size
reported by the backend topology instead of hardcoding it
to 1 sector. This gives the guest accurate alignment hints
so it can avoid sub block discards that the filesystem
might silently ignore.
For example, on a 4K block filesystem the alignment is now
8 sectors (4096/512) instead of 1.
For image formats with their own allocation units (QCOW2
clusters, VHD/VHDX block sizes), the ideal alignment would
be derived from the format cluster/block size. This is
left for a followup that surfaces allocation granularity
through DiskTopology.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
The virtio vhost-user device backend prefers to use externally-provided
eventfds as irqfds. This allows the frontend VM to notify the backend
VM directly, without the need for a userspace proxy process. Since the
frontend can provide irqfds at any time, the backend needs to register
and unregister irqfds dynamically.
This is tricky because the functions that access the irqfd table all
take `&self`, not `&mut self`. The obvious solution to this problem is
to wrap the table in a mutex. Most of these functions are not called on
hot paths, but `.notifier()` is called whenever Cloud Hypervisor needs
to inject an interrupt into a guest. Most devices don't need to
register irqfds at runtime, and for them, slowing down interrupt
injection would be wasteful.
Instead, require devices to opt-in to irqfd registration. The irqfd
table now comes in two forms: one that contains a mutex and one that
does not. The one containing a mutex can be mutated freely, while
attempting to mutate the one that does not will panic.
Right now, no code registeres irqfds at runtime, but this will change in
subsequent commits.
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
It is currently left as unimplemented!().
No functional change intended as there are no callers.
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com>
Trigger the interrupts in the guest for the virtio device queues behind
the vhost-user devices when resuming. This avoids a situation where
interrupts from the backend get lost when they are dispatched from the
backend when then guest is paused leading to the guest/backend
effectively waiting for each other to move forward. This is more
reproducible with longer durations between pause and resume as there is
more opportunity for the backend to completely process it's queue and
fire all the interrupts.
It's perfectly safe and allowed by the virtio spec to generate these
interrupts and the performance impact is negligible and is a safe way to
ensure forward progress after a resume.
See: #7850
Signed-off-by: Rob Bradford <rbradford@meta.com>
When VIRTIO_BLK_F_DISCARD or VIRTIO_BLK_F_WRITE_ZEROES features
are advertised, the virtio spec v1.2, sections 5.2.4 and
5.2.6.1, requires the corresponding VirtioBlockConfig fields
to contain valid, non zero values. Leaving them at zero causes
strictly behaved drivers to either reject the features or crash.
Populate max_discard_sectors, max_discard_seg,
discard_sector_alignment, max_write_zeroes_sectors,
max_write_zeroes_seg and write_zeroes_may_unmap after
feature advertisement so drivers can safely negotiate
these features.
Fixes: #7849
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>