vm-virtio: Simplify virtio-blk configuration

This commit reuses the clear definition of the virtio-blk
configuration structure, allowing both vhost-user-blk and
virtio-blk devices to rely on it.

This makes the code more readable for developers.

Signed-off-by: Sebastien Boeuf <sebastien.boeuf@intel.com>
This commit is contained in:
Sebastien Boeuf 2020-01-27 18:12:58 +01:00 committed by Rob Bradford
parent 8946a09afd
commit 8e48fc445f

View File

@ -6,6 +6,7 @@ use super::handler::*;
use super::vu_common_ctrl::*; use super::vu_common_ctrl::*;
use super::Error as DeviceError; use super::Error as DeviceError;
use super::{Error, Result}; use super::{Error, Result};
use crate::block::VirtioBlockConfig;
use crate::VirtioInterrupt; use crate::VirtioInterrupt;
use arc_swap::ArcSwap; use arc_swap::ArcSwap;
use libc; use libc;
@ -13,7 +14,6 @@ use libc::EFD_NONBLOCK;
use std::cmp; use std::cmp;
use std::io::Write; use std::io::Write;
use std::mem; use std::mem;
use std::ptr::null;
use std::result; use std::result;
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc; use std::sync::Arc;
@ -25,15 +25,9 @@ use vhost_rs::vhost_user::{Master, VhostUserMaster, VhostUserMasterReqHandler};
use vhost_rs::VhostBackend; use vhost_rs::VhostBackend;
use virtio_bindings::bindings::virtio_blk::*; use virtio_bindings::bindings::virtio_blk::*;
use vm_device::{Migratable, MigratableError, Pausable, Snapshotable}; use vm_device::{Migratable, MigratableError, Pausable, Snapshotable};
use vm_memory::GuestMemoryMmap; use vm_memory::{ByteValued, GuestMemoryMmap};
use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::eventfd::EventFd;
macro_rules! offset_of {
($ty:ty, $field:ident) => {
unsafe { &(*(null() as *const $ty)).$field as *const _ as usize }
};
}
struct SlaveReqHandler {} struct SlaveReqHandler {}
impl VhostUserMasterReqHandler for SlaveReqHandler {} impl VhostUserMasterReqHandler for SlaveReqHandler {}
@ -43,7 +37,7 @@ pub struct Blk {
pause_evt: Option<EventFd>, pause_evt: Option<EventFd>,
avail_features: u64, avail_features: u64,
acked_features: u64, acked_features: u64,
config_space: Vec<u8>, config: VirtioBlockConfig,
queue_sizes: Vec<u16>, queue_sizes: Vec<u16>,
queue_evts: Option<Vec<EventFd>>, queue_evts: Option<Vec<EventFd>>,
interrupt_cb: Option<Arc<dyn VirtioInterrupt>>, interrupt_cb: Option<Arc<dyn VirtioInterrupt>>,
@ -102,10 +96,9 @@ impl Blk {
.map_err(Error::VhostUserSetProtocolFeatures)?; .map_err(Error::VhostUserSetProtocolFeatures)?;
} }
let config_len = mem::size_of::<virtio_blk_config>(); let config_len = mem::size_of::<VirtioBlockConfig>();
let config_space: Vec<u8> = vec![0u8; config_len as usize]; let config_space: Vec<u8> = vec![0u8; config_len as usize];
let (_, config_space) = vhost_user_blk
let (_, mut config_space) = vhost_user_blk
.get_config( .get_config(
0, 0,
config_len as u32, config_len as u32,
@ -113,12 +106,12 @@ impl Blk {
config_space.as_slice(), config_space.as_slice(),
) )
.unwrap(); .unwrap();
let mut config = VirtioBlockConfig::default();
let queue_num_offset = offset_of!(virtio_blk_config, num_queues); if let Some(backend_config) = VirtioBlockConfig::from_slice(config_space.as_slice()) {
// Only set num_queues value(u16). config = *backend_config;
let num_queues_slice = (vu_cfg.num_queues as u16).to_le_bytes(); // Only set num_queues value(u16).
config_space[queue_num_offset..queue_num_offset + mem::size_of::<u16>()] config.num_queues = vu_cfg.num_queues as u16;
.copy_from_slice(&num_queues_slice); }
Ok(Blk { Ok(Blk {
vhost_user_blk, vhost_user_blk,
@ -126,7 +119,7 @@ impl Blk {
pause_evt: None, pause_evt: None,
avail_features, avail_features,
acked_features, acked_features,
config_space, config,
queue_sizes: vec![vu_cfg.queue_size; vu_cfg.num_queues], queue_sizes: vec![vu_cfg.queue_size; vu_cfg.num_queues],
queue_evts: None, queue_evts: None,
interrupt_cb: None, interrupt_cb: None,
@ -187,34 +180,32 @@ impl VirtioDevice for Blk {
} }
fn read_config(&self, offset: u64, mut data: &mut [u8]) { fn read_config(&self, offset: u64, mut data: &mut [u8]) {
let config_len = self.config_space.len() as u64; let config_slice = self.config.as_slice();
let config_len = config_slice.len() as u64;
if offset >= config_len { if offset >= config_len {
error!("Failed to read config space"); error!("Failed to read config space");
return; return;
} }
if let Some(end) = offset.checked_add(data.len() as u64) { if let Some(end) = offset.checked_add(data.len() as u64) {
// This write can't fail, offset and end are checked against config_len. // This write can't fail, offset and end are checked against config_len.
data.write_all(&self.config_space[offset as usize..cmp::min(end, config_len) as usize]) data.write_all(&config_slice[offset as usize..cmp::min(end, config_len) as usize])
.unwrap(); .unwrap();
} }
} }
fn write_config(&mut self, offset: u64, data: &[u8]) { fn write_config(&mut self, offset: u64, data: &[u8]) {
let config_slice = self.config.as_mut_slice();
let data_len = data.len() as u64; let data_len = data.len() as u64;
let config_len = self.config_space.len() as u64; let config_len = config_slice.len() as u64;
if offset + data_len > config_len { if offset + data_len > config_len {
error!("Failed to write config space"); error!("Failed to write config space");
return; return;
} }
// In fact, write_config() only handle wce value in vhost-user-blk.
// so, we can only set wce value here.
if self.config_space[offset as usize] == data[0] {
return;
}
self.vhost_user_blk self.vhost_user_blk
.set_config(offset as u32, VhostUserConfigFlags::WRITABLE, data) .set_config(offset as u32, VhostUserConfigFlags::WRITABLE, data)
.expect("Failed to set config"); .expect("Failed to set config");
self.config_space[offset as usize] = data[0]; let (_, right) = config_slice.split_at_mut(offset as usize);
right.copy_from_slice(&data[..]);
} }
fn activate( fn activate(