virtio-devices: pmem: Respond to unknown request types

Request::parse rejected unknown request types with an error, causing
process_queue to report the chain as used with no response written.
The device should write an error response so the driver knows the
request was handled. Move type validation out of parse into
process_queue where a proper response can be constructed.

Signed-off-by: Rob Bradford <rbradford@meta.com>
Assisted-by: Claude:claude-opus-4-6
This commit is contained in:
Rob Bradford
2026-05-06 16:09:22 +01:00
parent 56c18b51cc
commit cd3aca91d3

View File

@@ -15,7 +15,7 @@ use std::{io, result};
use anyhow::anyhow;
use event_monitor::event;
use log::{error, info};
use log::{error, info, warn};
use seccompiler::SeccompAction;
use serde::{Deserialize, Serialize};
use thiserror::Error;
@@ -97,6 +97,7 @@ enum Error {
#[derive(Debug, PartialEq, Eq)]
enum RequestType {
Flush,
Unknown(u32),
}
struct Request {
@@ -130,7 +131,7 @@ impl Request {
let request_type = match request.type_ {
VIRTIO_PMEM_REQ_TYPE_FLUSH => RequestType::Flush,
_ => return Err(Error::InvalidRequest),
t => RequestType::Unknown(t),
};
let status_desc = desc_chain.next().ok_or(Error::DescriptorChainTooShort)?;
@@ -170,11 +171,17 @@ impl PmemEpollHandler {
let mut used_descs = false;
while let Some(mut desc_chain) = self.queue.pop_descriptor_chain(self.mem.memory()) {
let len = match Request::parse(&mut desc_chain, self.access_platform.as_deref()) {
Ok(ref req) if (req.type_ == RequestType::Flush) => {
let status_code = match self.disk.sync_all() {
Ok(()) => VIRTIO_PMEM_RESP_TYPE_OK,
Err(e) => {
error!("failed flushing disk image: {e}");
Ok(ref req) => {
let status_code = match req.type_ {
RequestType::Flush => match self.disk.sync_all() {
Ok(()) => VIRTIO_PMEM_RESP_TYPE_OK,
Err(e) => {
error!("Failed flushing disk image: {e}");
VIRTIO_PMEM_RESP_TYPE_EIO
}
},
RequestType::Unknown(t) => {
warn!("Unknown request type: {t}");
VIRTIO_PMEM_RESP_TYPE_EIO
}
};
@@ -188,21 +195,6 @@ impl PmemEpollHandler {
}
}
}
Ok(ref req) => {
// Currently, there is only one virtio-pmem request, FLUSH.
error!("Invalid virtio request type {:?}", req.type_);
// The virtio spec requires a status response even on error.
let resp = VirtioPmemResp {
ret: VIRTIO_PMEM_RESP_TYPE_EIO,
};
match desc_chain.memory().write_obj(resp, req.status_addr) {
Ok(()) => size_of::<VirtioPmemResp>() as u32,
Err(e) => {
error!("Bad guest memory address: {e}");
0
}
}
}
Err(e) => {
error!("Failed to parse available descriptor chain: {e:?}");
0