Currently ejecting a device leaks its mapping keeping the container fd
open. Remove the mapping so the fd can be closed.
Assisted-by: Claude:Opus-4.8
Signed-off-by: Dylan Reid <dgreid@fb.com>
Query and save the dirty log before shutting down the vhost-user device.
This allows any final dirty memory ranges to be recorded before it
becomes impossible to do that as the vhost-user handle has been closed.
This is required to ensure that all memory writes have been correctly
recorded that may be triggered by inflight I/O drains from vhost-user
device state capture.
One small implementation wrinkle: with local migrations there is no
dirty logging (since we just pass the memory FD over the socket) so
calling dirty_log() would generate an error. As there is no clean way to
query if dirty logging has been started add a boolean to track if its
active.
Signed-off-by: Rob Bradford <rbradford@meta.com>
Rather than each device implementation holding a reference to the guest
memory move this to VhostUserCommon. This refactoring simplifies the
function signatures but also allows for methods that act on
VhostUserCommon that don't have the memory available to them.
Signed-off-by: Rob Bradford <rbradford@meta.com>
A confidential guest (e.g. SEV-SNP) requires every virtio device to
advertise VIRTIO_F_ACCESS_PLATFORM so the guest driver routes DMA
through the platform's bounce-buffer path; the driver refuses a device
that does not offer it.
Add VIRTIO_F_ACCESS_PLATFORM support to virtio-{watchdog,iommu} which
are exercised as part of the CVM integration tests.
Assisted-by: Claude:Opus-4.8
Signed-off-by: Ruben Hakobyan <hruben@meta.com>
eject_device calls shutdown, but Block doesn't implement it, so the
worker thread was never joined. Drop for Block does not help either,
VirtioPciDevice keeps an Arc<Mutex<Block>> past eject, so Drop never
runs. The async worker keeps completing in-flight I/O into the guest RAM
that backed it when issued.
Implement shutdown() to call wait_for_epoll_threads(), which drops the
WorkerThreads handle and ensures that worker's io completes.
Signed-off-by: Dylan Reid <dgreid@fb.com>
Feed Ok into VirtioPciDeviceActivator and assert that activate returns
Ok, device_activated becomes true, DEVICE_NEEDS_RESET is not set,
status is otherwise unchanged, no Config interrupt is delivered, and
the barrier waiter unblocks normally.
Assisted-by: Claude:Opus-4.7
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Feed BadActivate into VirtioPciDeviceActivator and assert that the
error propagates, device_activated stays false, DEVICE_NEEDS_RESET is
set in status, a single Config interrupt is delivered, and a thread
waiting on the activation barrier unblocks. The barrier release is
the deadlock fixed by the NEEDS_RESET on activation failure change.
Assisted-by: Claude:Opus-4.7
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add TestVirtioDevice with a controllable ActivateResult,
TestVirtioInterrupt that records delivered interrupt types, and a
make_activator helper that builds a complete VirtioPciDeviceActivator
with observable status, activated flag, interrupt log, and barrier.
Assisted-by: Claude:Opus-4.7
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
When the guest writes DRIVER_OK and the device fails to activate, the
VMM previously bubbled the error up via VirtioActivate and never
released the activation barrier, leaving the vCPU that wrote DRIVER_OK
blocked on the barrier and effectively deadlocking the guest.
Per virtio 1.3 section 2.1.2, a device that has experienced an error
it cannot recover from should set DEVICE_NEEDS_RESET in its status and
notify the driver via a configuration change interrupt. Do that on
activation failure through the existing mark_device_needs_reset
helper, then release the activation barrier so the vCPU can resume.
DeviceManager::activate_virtio_devices now logs and continues instead
of aborting the whole pending list, so one failing device does not
take down the VMM or block pause and migration. The activator has
already reported the failure with the device id.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
RX packet assembly checks descriptor capacity before the backend sees
the packet. The backend then updates hdr.len before the header is
written back.
Validate that final length before committing the header, so we never
tell the guest that more bytes were written than fit in the RX buffer.
Assisted-by: Codex:GPT-5
Signed-off-by: Dylan Reid <dgreid@fb.com>
Remove the need for unsafely materializing slices from guest memory
pointers which is, by definition, undefined behavior.
Achieved by introducing a TxBufSource trait that is implemented for both
types of sources (Guest Memory or local copy) and by using the volatile
read/write primities for moving data from a readable or writable to
guest memory.
Assisted-by: Codex:GPT-5
Signed-off-by: Dylan Reid <dgreid@fb.com>
Keep packet data as a checked guest memory range and add helpers for
volatile reads and writes. Arguably VsockPacket should hold a
VolatileSlice for the guest memory usecase, but the lifetime tracking
involved wasn't worth it.
Keep the old slice accessors for now so existing callers still build.
The next commit switches them over.
Assisted-by: Codex:GPT-5
Signed-off-by: Dylan Reid <dgreid@fb.com>
The helper only needs to update the packet len field. Use write_slice()
instead of rebuilding a mutable slice from a raw host pointer.
Assisted-by: Codex:GPT-5
Signed-off-by: Dylan Reid <dgreid@fb.com>
Take the recent thread refactor further. Bundle a device's worker
JoinHandles together with the kill event that stops them into a single
WorkerThreads value, owned by VirtioCommon. Its Drop signals the workers
to exit, unparks any parked for migration, and joins them.
This makes a detached/leaked worker unrepresentable. reset(),
wait_for_epoll_threads() and VhostUserCommon::shutdown() now happen when
dropping the WorkerThreads, and the unpark-before-join teardown now
lives in one place.
Assisted-by: Claude:Opus-4.8
Signed-off-by: Dylan Reid <dgreid@fb.com>
Signed-off-by: Rob Bradford <rbradford@meta.com>
Replace manual thread management with the use of
VhostUserCommon::spawn_worker() which is just a thin layer over
VirtioCommon::spawn_worker() but handling VhostUserCommon reset. This
removes some manual thread management and also triggers a reset upon
spawn failure.
Assisted-by: Claude:Opus-4.7
Signed-off-by: Rob Bradford <rbradford@meta.com>
Wrap VirtioCommon::spawn_worker() to also include vhost-user specific
backend cleanup.
Assisted-by: Claude:Opus-4.7
Signed-off-by: Rob Bradford <rbradford@meta.com>
Replace use of spawn_virtio_thread() helper with the new method on
VirtioCommon to handle thread management as well as spawning. As a
result this cleanly handles reset if it fails to spawn the thread.
Assisted-by: Claude:Opus-4.7
Signed-off-by: Rob Bradford <rbradford@meta.com>
Implement a method on VirtioCommon for spawning the worker thread. This
method also handles storing the handle to the thread and triggering a
reset on the device if thread spawning fails. The addition of this
helper replaces a repeated pattern across virtio and vhost-user devices
but also ensures correct cleanup when spawning multiple threads for a
device with multiple queues.
Assisted-by: Claude:Opus-4.7
Signed-off-by: Rob Bradford <rbradford@meta.com>
Rely on the vector of threads in VirtioCommon for storing all the
handles of the spawned threads rather than storing them in the devices
or in VhostUserCommon directly.
Assisted-by: Claude:Opus-4.7
Signed-off-by: Rob Bradford <rbradford@meta.com>
process_rx writes the packet header back into the descriptor chain
it is currently processing, so the write must go through that
chain's memory snapshot. Rederefing self.mem.memory() resolves to
the same snapshot today, but couples the write on the chain to the
device's atomic handle and obscures intent. Match the pattern used
by the rest of the device by writing through desc_chain.memory().
Suggested-by: Rob Bradford <rbradford@meta.com>
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Drop the local next_checked_desc helper and the inline
translate_gva calls in from_tx_virtq_head and from_rx_virtq_head.
Buffer ranges are now validated by the shared next_checked helper
in vm-virtio, and the validated guest address is read directly
from CheckedDescriptor::addr.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add check_range calls on request and status descriptor addresses to
reject buffers that extend past guest memory.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Add check_range calls on request and status descriptor addresses to
reject buffers that extend past guest memory.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Replace inline translate_gva and check_range with checked_iter, which
validates the descriptor buffer range against guest memory before
yielding each descriptor.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Replace manual translate_gva calls with checked_iter in both the
inflate/deflate and reporting queue handlers.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Replace raw desc.addr() usage with checked_iter which validates the
descriptor buffer range against guest memory before I/O.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Replace manual translate_gva calls in both input and output queue
handlers with checked_iter for centralized range validation.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Replace manual translate_gva call with checked_iter which validates
the descriptor buffer range against guest memory before I/O.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Verify that bar_access_params clamps the access length to cap.length
when the PCI config read buffer is larger.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
The VIRTIO_PCI_CAP_PCI_CFG indirect access mechanism was ignoring
the cap.length field written by the guest driver. PCI config register
reads always produce a 4 byte buffer, so when a driver set cap.length
to 1 for a byte wide access to device_status at common config offset
0x14, the VMM passed all 4 bytes to read_bar, dispatching to the
dword handler which does not cover that offset.
Use cap.length to determine the actual BAR access width per virtio
spec 4.1.4.9.1. Also replace the unsafe transmute with the safe
Le32::to_native() conversion.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Drop the borrowed iovec AsyncIo entry points now that all callers use
owned operations. Rename the transitional owned batch and completion
methods to the final trait names and remove the borrowed submission
helpers from the queue wrappers.
This removes a bunch of known safety foot-guns so future-us don't
accidentally use them.
Assisted-by: Codex:GPT-5.5
Signed-off-by: Dylan Reid <dgreid@fb.com>
Switch virtio-blk request construction and the users to the owned
AsyncIo data path added in the series. Read bounce buffers now return
through AsyncIoCompletion before being copied back to guest memory.
This makes the main virtio async block I/O path use retained request
memory. qcow still has raw-iovec fallback paths at this point; those
are removed in follow-up commits.
Leave the legacy borrowed iovec trait methods in place for a follow-up
cleanup commit to minimize single-commit churn.
Signed-off-by: Dylan Reid <dgreid@fb.com>
This change will allow us to get accurate time over ptp in guests
started from a MSHV-virtualized Linux host. Implementing it as a
virtio device is preferable to using the existing kvm_ptp because:
kvm_ptp relies on hypercalls that only exist on host kernels running
kvm. Virtio-rtc gives us more flexibility in what clock types we want
to provide. We can later extend the device to implement multiple clocks
(smeared UTC, TAI, monotonic, etc.). Virtio-rtc protocol supports
alarms. Alarms may later enable usecases where the guests can do their
own VM lifecycle management without relying on a host-side
orchestrator.
Implement device backend for virtio-rtc. Currently this implementation
encompasses:
1. CONFIG, CAP, READ, CROSSCAP (returns false)
2. One PTP clock is presented of type
VIRTIO_RTC_CLOCK_UTC_MAYBE_SMEARED with leap_second_smearing
VIRTIO_RTC_SMEAR_UNSPECIFIED
The device is disabled by default, requiring --rtc to be passed
Not implemented but theoretically supported by virtio-rtc is:
1. Cross-timestamping support
2. The alarm queue
Fixes#7730
Signed-off-by: Cameron Baird <cameronbaird@microsoft.com>
Windows 11 PnP rebalance rewrites peer BARs into the same range CH
packed the initial layout at, causing move_bar() failures and boot
deadlock. Pack Mmio64 BARs at 8 MiB stride. Mmio32 isn't wide enough
for the same stride, but its BARs don't participate in guest BAR
rebalancing.
On restore, pin the BAR to the snapshot address (alignment=None) so a
guest-relocated BAR with smaller alignment is accepted.
Signed-off-by: CMGS <ilskdw@gmail.com>
IommuEpollHandler::request_queue() can fail because the guest put in a
bad request or because of a fatal error. Handle those cases differently,
letting the guest continue, but see the error if it can.
This makes debugging from the guest easier as one mistake doesn't cause
a VM reset if it's avoidable.
Signed-off-by: Dylan Reid <dgreid@fb.com>
Assert VirtioPciNotifyCap and VirtioPciCap64 size cap_len from
their own type. Catches a future regression of the same shape as
the VirtioPciCfgCap one in any of the sibling capabilities.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Assert the emitted VirtioPciCfgCap carries cfg_type 5, the value
assigned to PciCapabilityType::Pci by virtio 1.2 section 4.1.4.1.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
Regression test for the cap_len fix. The emitted VirtioPciCfgCap
must report cap_len 20, covering the trailing pci_cfg_data window
per virtio 1.2 section 4.1.4.9.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
VirtioPciCfgCap::new built its inner header via VirtioPciCap::new,
which sized cap_len from the bare virtio_pci_cap layout, yielding
16. The emitted capability is VirtioPciCfgCap, which appends a four
byte pci_cfg_data window, so the correct value is 20.
The virtio 1.2 specification defines this cap as virtio_pci_cap
followed by pci_cfg_data[4] and requires cap_len to
cover the whole structure. Build the header inline so cap_len
reflects the actual emitted size, matching VirtioPciNotifyCap and
VirtioPciCap64.
Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
I started by looking at all `Option<Vec<T>>` values in config.rs and
vm_config.rs, and replaced them with `Option<Box<[T]>>`. This has the
advantage that one now can see at a glance if this field will ever
resize during operation or not, reducing cognitive load and increasing
maintainability. All fields that need the properties of a Ver or where
this change was not trivial are kept intact.
On-behalf-of: SAP philipp.schuster@sap.com
Signed-off-by: Philipp Schuster <philipp.schuster@cyberus-technology.de>
Some block devices (ZFS volume) may require BLKDISCARD and BLKZEROOUT
ioctls for discard and write_zeroes operations respectively.
There is no good way to probe whether fallocate is supported on a block
device. Arguably, punch_hole and write_zeroes are rare. Instead of
having a complex scheme for the IO uring backend, we force it to always
use ioctls. The code can be changed if the synchronized ioctls become a
performance issue.
Changes:
- Detect block devices at construction time
- Use BLKDISCARD ioctl for punch_hole (discard) on block devices
- Use BLKZEROOUT ioctl for write_zeroes on block devices
- Add BLKDISCARD/BLKZEROOUT to VirtioBlock seccomp whitelist
- Keep fallocate() path for regular files (no behavior change)
- Consolidate some helper functions to the new sparse module
Signed-off-by: Wei Liu <liuwe@microsoft.com>