virtio-devices: Make reset() best-effort on backend failures

The virtio specification treats reset as the recovery operation and so
must take the device back to a fresh state, and the driver waits for the
status read-back to converge before continuing. There is no defined way
for the device to report a reset failure to the driver.

Previously the implementations of reset() would return early and not
complete all their cleanup leaving them in an inconsistent state. Now
log errors and continue through the execution.

Signed-off-by: Rob Bradford <rbradford@meta.com>
Assisted-by: Claude:claude-opus-4-7
This commit is contained in:
Rob Bradford
2026-04-26 13:11:47 +01:00
parent 733d1fe553
commit d573f1bf96
3 changed files with 16 additions and 8 deletions

View File

@@ -293,9 +293,13 @@ impl VirtioCommon {
pub fn reset(&mut self) -> Option<Arc<dyn VirtioInterrupt>> {
self.queue_evts.clear();
// We first must resume the virtio thread if it was paused.
if self.pause_evt.take().is_some() {
self.resume().ok()?;
// Resume the virtio thread if it was paused. Reset must always
// converge to fresh state, so a resume failure is logged but doesn't
// skip the rest of the teardown.
if self.pause_evt.take().is_some()
&& let Err(e) = self.resume()
{
error!("Failed to resume paused device during reset: {e:?}");
}
if let Some(kill_evt) = self.kill_evt.take() {

View File

@@ -451,9 +451,10 @@ impl VirtioDevice for Vdpa {
}
fn reset(&mut self) -> Option<Arc<dyn VirtioInterrupt>> {
// Backend reset failures are logged but don't skip local cleanup:
// reset must converge to fresh state regardless of backend state.
if let Err(e) = self.reset_vdpa() {
error!("Failed to reset vhost-vdpa: {e:?}");
return None;
}
event!("vdpa", "reset", "id", &self.id);

View File

@@ -429,9 +429,13 @@ impl VhostUserCommon {
}
pub fn reset(&mut self, id: &str) -> Option<Arc<dyn VirtioInterrupt>> {
// We first must resume the virtio thread if it was paused.
if self.virtio_common.pause_evt.take().is_some() {
self.virtio_common.resume().ok()?;
// Resume the virtio thread if it was paused. Reset must always
// converge to fresh state, so backend resume / reset failures are
// logged but don't skip the rest of the teardown.
if self.virtio_common.pause_evt.take().is_some()
&& let Err(e) = self.virtio_common.resume()
{
error!("Failed to resume paused device during reset: {e:?}");
}
if let Some(vu) = &self.vu
@@ -441,7 +445,6 @@ impl VhostUserCommon {
"Failed to reset vhost-user daemon for socket {}: {e:?}",
self.socket_path
);
return None;
}
if let Some(kill_evt) = self.virtio_common.kill_evt.take() {