mirror of
https://chromium.googlesource.com/crosvm/crosvm
synced 2025-02-11 12:35:26 +00:00
devices: virtio: block: refactor status_writer setup
This consolidates the status byte manipulation in process_one_request() instead of requiring both that function and execute_request() to deal with it. The tests are modified to run the full process_one_request() function instead of just execute_request() to exercise the full descriptor parsing logic, and they are adapted to read the status of the request from the status byte in the buffer from the descriptor since process_one_request() returns successfully as long as the descriptor parsing succeeded, even if the requested I/O failed. BUG=None TEST=./build_test Change-Id: I17affabc2d3c30c810643ce260152cf34893b772 Signed-off-by: Daniel Verkamp <dverkamp@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1918479 Reviewed-by: Dylan Reid <dgreid@chromium.org> Reviewed-by: Chirantan Ekbote <chirantan@chromium.org> Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
parent
917b90e2a3
commit
e7c46cad41
1 changed files with 28 additions and 20 deletions
|
@ -261,25 +261,28 @@ impl Worker {
|
||||||
flush_timer_armed: &mut bool,
|
flush_timer_armed: &mut bool,
|
||||||
mem: &GuestMemory,
|
mem: &GuestMemory,
|
||||||
) -> result::Result<usize, ExecuteError> {
|
) -> result::Result<usize, ExecuteError> {
|
||||||
let mut status_writer =
|
let mut reader = Reader::new(mem, avail_desc.clone()).map_err(ExecuteError::Descriptor)?;
|
||||||
Writer::new(mem, avail_desc.clone()).map_err(ExecuteError::Descriptor)?;
|
let mut writer = Writer::new(mem, avail_desc).map_err(ExecuteError::Descriptor)?;
|
||||||
let available_bytes = status_writer.available_bytes();
|
|
||||||
|
// The last byte of the buffer is virtio_blk_req::status.
|
||||||
|
// Split it into a separate Writer so that status_writer is the final byte and
|
||||||
|
// the original writer is left with just the actual block I/O data.
|
||||||
|
let available_bytes = writer.available_bytes();
|
||||||
let status_offset = available_bytes
|
let status_offset = available_bytes
|
||||||
.checked_sub(1)
|
.checked_sub(1)
|
||||||
.ok_or(ExecuteError::MissingStatus)?;
|
.ok_or(ExecuteError::MissingStatus)?;
|
||||||
|
let mut status_writer = writer
|
||||||
status_writer = status_writer
|
|
||||||
.split_at(status_offset)
|
.split_at(status_offset)
|
||||||
.map_err(ExecuteError::Descriptor)?;
|
.map_err(ExecuteError::Descriptor)?;
|
||||||
|
|
||||||
let status = match Block::execute_request(
|
let status = match Block::execute_request(
|
||||||
avail_desc,
|
&mut reader,
|
||||||
|
&mut writer,
|
||||||
read_only,
|
read_only,
|
||||||
disk,
|
disk,
|
||||||
disk_size,
|
disk_size,
|
||||||
flush_timer,
|
flush_timer,
|
||||||
flush_timer_armed,
|
flush_timer_armed,
|
||||||
mem,
|
|
||||||
) {
|
) {
|
||||||
Ok(()) => VIRTIO_BLK_S_OK,
|
Ok(()) => VIRTIO_BLK_S_OK,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
@ -530,18 +533,19 @@ impl Block {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Execute a single block device request.
|
||||||
|
// `writer` includes the data region only; the status byte is not included.
|
||||||
|
// It is up to the caller to convert the result of this function into a status byte
|
||||||
|
// and write it to the expected location in guest memory.
|
||||||
fn execute_request(
|
fn execute_request(
|
||||||
avail_desc: DescriptorChain,
|
reader: &mut Reader,
|
||||||
|
writer: &mut Writer,
|
||||||
read_only: bool,
|
read_only: bool,
|
||||||
disk: &mut dyn DiskFile,
|
disk: &mut dyn DiskFile,
|
||||||
disk_size: u64,
|
disk_size: u64,
|
||||||
flush_timer: &mut TimerFd,
|
flush_timer: &mut TimerFd,
|
||||||
flush_timer_armed: &mut bool,
|
flush_timer_armed: &mut bool,
|
||||||
mem: &GuestMemory,
|
|
||||||
) -> result::Result<(), ExecuteError> {
|
) -> result::Result<(), ExecuteError> {
|
||||||
let mut reader = Reader::new(mem, avail_desc.clone()).map_err(ExecuteError::Descriptor)?;
|
|
||||||
let mut writer = Writer::new(mem, avail_desc).map_err(ExecuteError::Descriptor)?;
|
|
||||||
|
|
||||||
let req_header: virtio_blk_req_header = reader.read_obj().map_err(ExecuteError::Read)?;
|
let req_header: virtio_blk_req_header = reader.read_obj().map_err(ExecuteError::Read)?;
|
||||||
|
|
||||||
let req_type = req_header.req_type.to_native();
|
let req_type = req_header.req_type.to_native();
|
||||||
|
@ -574,11 +578,7 @@ impl Block {
|
||||||
|
|
||||||
match req_type {
|
match req_type {
|
||||||
VIRTIO_BLK_T_IN => {
|
VIRTIO_BLK_T_IN => {
|
||||||
// The last byte of writer is virtio_blk_req::status, so subtract it from data_len.
|
let data_len = writer.available_bytes();
|
||||||
let data_len = writer
|
|
||||||
.available_bytes()
|
|
||||||
.checked_sub(1)
|
|
||||||
.ok_or(ExecuteError::MissingStatus)?;
|
|
||||||
let offset = sector
|
let offset = sector
|
||||||
.checked_shl(u32::from(SECTOR_SHIFT))
|
.checked_shl(u32::from(SECTOR_SHIFT))
|
||||||
.ok_or(ExecuteError::OutOfRange)?;
|
.ok_or(ExecuteError::OutOfRange)?;
|
||||||
|
@ -881,7 +881,7 @@ mod tests {
|
||||||
let mut flush_timer = TimerFd::new().expect("failed to create flush_timer");
|
let mut flush_timer = TimerFd::new().expect("failed to create flush_timer");
|
||||||
let mut flush_timer_armed = false;
|
let mut flush_timer_armed = false;
|
||||||
|
|
||||||
Block::execute_request(
|
Worker::process_one_request(
|
||||||
avail_desc,
|
avail_desc,
|
||||||
false,
|
false,
|
||||||
&mut f,
|
&mut f,
|
||||||
|
@ -891,6 +891,10 @@ mod tests {
|
||||||
&mem,
|
&mem,
|
||||||
)
|
)
|
||||||
.expect("execute failed");
|
.expect("execute failed");
|
||||||
|
|
||||||
|
let status_offset = GuestAddress((0x1000 + size_of_val(&req_hdr) + 512) as u64);
|
||||||
|
let status = mem.read_obj_from_addr::<u8>(status_offset).unwrap();
|
||||||
|
assert_eq!(status, VIRTIO_BLK_S_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -937,7 +941,7 @@ mod tests {
|
||||||
let mut flush_timer = TimerFd::new().expect("failed to create flush_timer");
|
let mut flush_timer = TimerFd::new().expect("failed to create flush_timer");
|
||||||
let mut flush_timer_armed = false;
|
let mut flush_timer_armed = false;
|
||||||
|
|
||||||
Block::execute_request(
|
Worker::process_one_request(
|
||||||
avail_desc,
|
avail_desc,
|
||||||
false,
|
false,
|
||||||
&mut f,
|
&mut f,
|
||||||
|
@ -946,6 +950,10 @@ mod tests {
|
||||||
&mut flush_timer_armed,
|
&mut flush_timer_armed,
|
||||||
&mem,
|
&mem,
|
||||||
)
|
)
|
||||||
.expect_err("execute was supposed to fail");
|
.expect("execute failed");
|
||||||
|
|
||||||
|
let status_offset = GuestAddress((0x1000 + size_of_val(&req_hdr) + 512 * 2) as u64);
|
||||||
|
let status = mem.read_obj_from_addr::<u8>(status_offset).unwrap();
|
||||||
|
assert_eq!(status, VIRTIO_BLK_S_IOERR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue