Skip to content

virtio: make VirtioDevice::enable return Result#2947

Open
jstarks wants to merge 3 commits intomicrosoft:mainfrom
jstarks:virtio-enable-result
Open

virtio: make VirtioDevice::enable return Result#2947
jstarks wants to merge 3 commits intomicrosoft:mainfrom
jstarks:virtio-enable-result

Conversation

@jstarks
Copy link
Member

@jstarks jstarks commented Mar 11, 2026

Change the VirtioDevice::enable trait method to return anyhow::Result<()> so that device activation errors are propagated to the transport layer instead of panicking.

Previously, several device implementations used .unwrap() or .expect() on fallible operations inside enable(), which could crash the VMM on malformed guest input (violating the trust boundary).

Change the VirtioDevice::enable trait method to return anyhow::Result<()>
so that device activation errors are propagated to the transport layer
instead of panicking.

Previously, several device implementations used .unwrap() or .expect()
on fallible operations inside enable(), which could crash the VMM on
malformed guest input (violating the trust boundary). Now:

- The trait method returns Result, allowing devices to use ? for error
  propagation.
- Both PCI and MMIO transports handle the error by logging it (rate
  limited) and leaving DRIVER_OK unset, so the device remains inert.
- virtio_blk: simplified from verbose match blocks to ? operators.
- virtio_net: replaced if-let-Err + unwrap pattern with ? operators.
- virtio_p9: replaced .expect() with .context()?.
- virtio_pmem: replaced .unwrap() on shared_memory_region and map()
  result with proper error propagation.
- virtiofs, tests: trivially updated (always return Ok(())).
@jstarks jstarks requested a review from a team as a code owner March 11, 2026 21:09
Copilot AI review requested due to automatic review settings March 11, 2026 21:09
@github-actions github-actions bot added the unsafe Related to unsafe code label Mar 11, 2026
@github-actions
Copy link

⚠️ Unsafe Code Detected

This PR modifies files containing unsafe Rust code. Extra scrutiny is required during review.

For more on why we check whole files, instead of just diffs, check out the Rustonomicon

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR changes the VirtioDevice::enable lifecycle hook to return anyhow::Result<()>, allowing virtio device activation failures to propagate to the MMIO/PCI transport layer instead of panicking across the guest trust boundary.

Changes:

  • Update VirtioDevice::enable trait signature to return anyhow::Result<()> and document expected transport behavior on failure.
  • Convert several virtio device implementations to return structured errors (replacing unwrap/expect/ignored results during activation).
  • Update MMIO/PCI transports to set DRIVER_OK only when enable() succeeds, and to log errors on failure.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
vm/devices/virtio/virtio/src/common.rs Change VirtioDevice::enable to return anyhow::Result<()> and document failure semantics.
vm/devices/virtio/virtio/src/transport/pci.rs Gate DRIVER_OK on successful enable() and log enable failures.
vm/devices/virtio/virtio/src/transport/mmio.rs Gate DRIVER_OK on successful enable() and log enable failures.
vm/devices/virtio/virtio/src/tests.rs Update TestDevice::enable to return Result to match the trait.
vm/devices/virtio/virtio_blk/src/lib.rs Propagate queue event/queue creation errors from enable() via Result.
vm/devices/virtio/virtio_net/src/lib.rs Propagate queue event/queue creation errors from enable() via Result.
vm/devices/virtio/virtio_p9/src/lib.rs Replace expect with anyhow::Context and return Result from enable().
vm/devices/virtio/virtio_pmem/src/lib.rs Require shared memory region and propagate mapping failures via Result.
vm/devices/virtio/virtiofs/src/virtio.rs Update enable() signature and return Ok(()).

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +495 to +514
match self.device.enable(Resources {
features: self.driver_feature.clone(),
queues,
shared_memory_region: self.shared_memory_region.clone(),
shared_memory_size: self.shared_memory_size,
});

self.device_status.set_driver_ok(true);
}) {
Ok(()) => {
self.device_status.set_driver_ok(true);
}
Err(err) => {
// FUTURE: consider setting DEVICE_NEEDS_RESET and
// delivering a config change interrupt so the guest
// can detect the failure proactively instead of
// waiting for IO timeouts.
tracelimit::error_ratelimited!(
error = &*err as &dyn std::error::Error,
"virtio device enable failed"
);
}
}
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the DRIVER_OK transition, doorbells are registered before calling device.enable(). If enable() returns Err, driver_ok is left unset, so the normal reset/disable paths that clear doorbells (which are gated on driver_ok/disabling) won’t run. This can leave stale/duplicate doorbell registrations and grow self.doorbells on repeated DRIVER_OK writes. Consider registering doorbells only after enable() succeeds, or clearing doorbells (and any other partial transport state) in the Err path.

Copilot uses AI. Check for mistakes.
Comment on lines +435 to +454
match self.device.enable(Resources {
features: self.driver_feature.clone(),
queues,
shared_memory_region: None,
shared_memory_size: 0,
});

self.device_status.set_driver_ok(true);
}) {
Ok(()) => {
self.device_status.set_driver_ok(true);
}
Err(err) => {
// FUTURE: consider setting DEVICE_NEEDS_RESET and
// delivering a config change interrupt so the guest
// can detect the failure proactively instead of
// waiting for IO timeouts.
tracelimit::error_ratelimited!(
error = &*err as &dyn std::error::Error,
"virtio device enable failed"
);
}
}
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the DRIVER_OK transition, doorbells are registered before calling device.enable(). If enable() returns Err, driver_ok is left unset, so guest reset/status=0 won’t clear doorbells (that path only clears when driver_ok was set). This can leak/duplicate doorbell registrations and cause self.doorbells to grow on repeated DRIVER_OK writes. Consider registering doorbells only after enable() succeeds, or clearing doorbells (and any other partial transport state) in the Err path.

Copilot uses AI. Check for mistakes.
Comment on lines 821 to +846
@@ -843,6 +843,7 @@ impl VirtioDevice for TestDevice {
))
})
.collect();
Ok(())
Copy link

Copilot AI Mar 11, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are tests covering the successful DRIVER_OK path, but none exercising the new failure path where VirtioDevice::enable() returns Err. Adding a test device whose enable() returns an error and asserting that the transport does not set DRIVER_OK (and remains inert) would prevent regressions in this error propagation behavior for both MMIO and PCI transports.

Copilot generated this review using guidance from repository custom instructions.
- Clear doorbells in Err arm of both MMIO and PCI transports to prevent
  stale/duplicate registrations on repeated DRIVER_OK writes when
  enable() fails.
- Add FailingTestDevice and tests verifying DRIVER_OK is not set when
  enable() returns an error, for both MMIO and PCI transports.
- Fix CI: apply rustfmt, remove unused tracing dep from virtio_blk.
Copilot AI review requested due to automatic review settings March 12, 2026 00:09
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 10 out of 11 changed files in this pull request and generated no new comments.


You can also share your feedback on Copilot code review. Take the survey.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

unsafe Related to unsafe code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants