From c4e8e653ace3cb2d3f7d846b1ac4ef9ca62cca44 Mon Sep 17 00:00:00 2001 From: Thomas Barrett Date: Fri, 8 Sep 2023 08:18:51 -0700 Subject: [PATCH] block: Add support for user specified ID_SERIAL Signed-off-by: Thomas Barrett --- block/src/lib.rs | 20 ++++++++++---------- fuzz/fuzz_targets/block.rs | 1 + vhost_user_block/src/lib.rs | 14 +++++++------- virtio-devices/src/block.rs | 14 +++++++++----- vmm/src/api/openapi/cloud-hypervisor.yaml | 2 ++ vmm/src/config.rs | 14 ++++++++++++-- vmm/src/device_manager.rs | 1 + vmm/src/vm_config.rs | 3 +++ 8 files changed, 45 insertions(+), 24 deletions(-) diff --git a/block/src/lib.rs b/block/src/lib.rs index 8c92a63b5..56a58168e 100644 --- a/block/src/lib.rs +++ b/block/src/lib.rs @@ -116,8 +116,8 @@ fn build_device_id(disk_path: &Path) -> result::Result { Ok(device_id) } -pub fn build_disk_image_id(disk_path: &Path) -> Vec { - let mut default_disk_image_id = vec![0; VIRTIO_BLK_ID_BYTES as usize]; +pub fn build_serial(disk_path: &Path) -> Vec { + let mut default_serial = vec![0; VIRTIO_BLK_ID_BYTES as usize]; match build_device_id(disk_path) { Err(_) => { warn!("Could not generate device id. We'll use a default."); @@ -127,10 +127,10 @@ pub fn build_disk_image_id(disk_path: &Path) -> Vec { // This will also zero out any leftover bytes. let disk_id = m.as_bytes(); let bytes_to_copy = cmp::min(disk_id.len(), VIRTIO_BLK_ID_BYTES as usize); - default_disk_image_id[..bytes_to_copy].clone_from_slice(&disk_id[..bytes_to_copy]) + default_serial[..bytes_to_copy].clone_from_slice(&disk_id[..bytes_to_copy]) } } - default_disk_image_id + default_serial } #[derive(Error, Debug)] @@ -330,7 +330,7 @@ impl Request { disk: &mut T, disk_nsectors: u64, mem: &GuestMemoryMmap, - disk_id: &[u8], + serial: &[u8], ) -> result::Result { disk.seek(SeekFrom::Start(self.sector << SECTOR_SHIFT)) .map_err(ExecuteError::Seek)?; @@ -362,10 +362,10 @@ impl Request { } RequestType::Flush => disk.flush().map_err(ExecuteError::Flush)?, RequestType::GetDeviceId => { - if (*data_len as usize) < disk_id.len() { + if (*data_len as usize) < serial.len() { return Err(ExecuteError::BadRequest(Error::InvalidOffset)); } - mem.write_slice(disk_id, *data_addr) + mem.write_slice(serial, *data_addr) .map_err(ExecuteError::Write)?; } RequestType::Unsupported(t) => return Err(ExecuteError::Unsupported(t)), @@ -379,7 +379,7 @@ impl Request { mem: &GuestMemoryMmap, disk_nsectors: u64, disk_image: &mut dyn AsyncIo, - disk_id: &[u8], + serial: &[u8], user_data: u64, ) -> result::Result { let sector = self.sector; @@ -481,10 +481,10 @@ impl Request { } else { return Err(ExecuteError::BadRequest(Error::TooManyDescriptors)); }; - if (data_len as usize) < disk_id.len() { + if (data_len as usize) < serial.len() { return Err(ExecuteError::BadRequest(Error::InvalidOffset)); } - mem.write_slice(disk_id, data_addr) + mem.write_slice(serial, data_addr) .map_err(ExecuteError::Write)?; return Ok(false); } diff --git a/fuzz/fuzz_targets/block.rs b/fuzz/fuzz_targets/block.rs index a184443b1..0514a2c00 100644 --- a/fuzz/fuzz_targets/block.rs +++ b/fuzz/fuzz_targets/block.rs @@ -57,6 +57,7 @@ fuzz_target!(|bytes| { false, 2, 256, + None, SeccompAction::Allow, None, EventFd::new(EFD_NONBLOCK).unwrap(), diff --git a/vhost_user_block/src/lib.rs b/vhost_user_block/src/lib.rs index ee43e5dd6..b50063b9a 100644 --- a/vhost_user_block/src/lib.rs +++ b/vhost_user_block/src/lib.rs @@ -9,7 +9,7 @@ // SPDX-License-Identifier: (Apache-2.0 AND BSD-3-Clause) use block::{ - build_disk_image_id, + build_serial, qcow::{self, ImageType, QcowFile}, Request, VirtioBlockConfig, }; @@ -90,7 +90,7 @@ impl convert::From for io::Error { struct VhostUserBlkThread { disk_image: Arc>, - disk_image_id: Vec, + serial: Vec, disk_nsectors: u64, event_idx: bool, kill_evt: EventFd, @@ -101,14 +101,14 @@ struct VhostUserBlkThread { impl VhostUserBlkThread { fn new( disk_image: Arc>, - disk_image_id: Vec, + serial: Vec, disk_nsectors: u64, writeback: Arc, mem: GuestMemoryAtomic, ) -> Result { Ok(VhostUserBlkThread { disk_image, - disk_image_id, + serial, disk_nsectors, event_idx: false, kill_evt: EventFd::new(EFD_NONBLOCK).map_err(Error::CreateKillEventFd)?, @@ -137,7 +137,7 @@ impl VhostUserBlkThread { &mut self.disk_image.lock().unwrap().deref_mut(), self.disk_nsectors, desc_chain.memory(), - &self.disk_image_id, + &self.serial, ) { Ok(l) => { len = l; @@ -222,7 +222,7 @@ impl VhostUserBlkBackend { let image: File = options.open(&image_path).unwrap(); let mut raw_img: qcow::RawFile = qcow::RawFile::new(image, direct); - let image_id = build_disk_image_id(&PathBuf::from(&image_path)); + let serial = build_serial(&PathBuf::from(&image_path)); let image_type = qcow::detect_image_type(&mut raw_img).unwrap(); let image = match image_type { ImageType::Raw => Arc::new(Mutex::new(raw_img)) as Arc>, @@ -250,7 +250,7 @@ impl VhostUserBlkBackend { for i in 0..num_queues { let thread = Mutex::new(VhostUserBlkThread::new( image.clone(), - image_id.clone(), + serial.clone(), nsectors, writeback.clone(), mem.clone(), diff --git a/virtio-devices/src/block.rs b/virtio-devices/src/block.rs index f4a250338..edf023186 100644 --- a/virtio-devices/src/block.rs +++ b/virtio-devices/src/block.rs @@ -20,7 +20,7 @@ use crate::GuestMemoryMmap; use crate::VirtioInterrupt; use anyhow::anyhow; use block::{ - async_io::AsyncIo, async_io::AsyncIoError, async_io::DiskFile, build_disk_image_id, Request, + async_io::AsyncIo, async_io::AsyncIoError, async_io::DiskFile, build_serial, Request, RequestType, VirtioBlockConfig, }; use rate_limiter::{RateLimiter, TokenType}; @@ -124,7 +124,7 @@ struct BlockEpollHandler { disk_image: Box, disk_nsectors: u64, interrupt_cb: Arc, - disk_image_id: Vec, + serial: Vec, kill_evt: EventFd, pause_evt: EventFd, writeback: Arc, @@ -205,7 +205,7 @@ impl BlockEpollHandler { desc_chain.memory(), self.disk_nsectors, self.disk_image.as_mut(), - &self.disk_image_id, + &self.serial, desc_chain.head_index() as u64, ) .map_err(Error::RequestExecuting)? @@ -504,6 +504,7 @@ pub struct Block { rate_limiter_config: Option, exit_evt: EventFd, read_only: bool, + serial: Vec, } #[derive(Versionize)] @@ -528,6 +529,7 @@ impl Block { iommu: bool, num_queues: usize, queue_size: u16, + serial: Option, seccomp_action: SeccompAction, rate_limiter_config: Option, exit_evt: EventFd, @@ -608,6 +610,8 @@ impl Block { (disk_nsectors, avail_features, 0, config, false) }; + let serial = serial.map(Vec::from).unwrap_or(build_serial(&disk_path)); + Ok(Block { common: VirtioCommon { device_type: VirtioDeviceType::Block as u32, @@ -630,6 +634,7 @@ impl Block { rate_limiter_config, exit_evt, read_only, + serial, }) } @@ -726,7 +731,6 @@ impl VirtioDevice for Block { ) -> ActivateResult { self.common.activate(&queues, &interrupt_cb)?; - let disk_image_id = build_disk_image_id(&self.disk_path); self.update_writeback(); let mut epoll_threads = Vec::new(); @@ -754,7 +758,7 @@ impl VirtioDevice for Block { })?, disk_nsectors: self.disk_nsectors, interrupt_cb: interrupt_cb.clone(), - disk_image_id: disk_image_id.clone(), + serial: self.serial.clone(), kill_evt, pause_evt, writeback: self.writeback.clone(), diff --git a/vmm/src/api/openapi/cloud-hypervisor.yaml b/vmm/src/api/openapi/cloud-hypervisor.yaml index 0300d4022..f29404fe5 100644 --- a/vmm/src/api/openapi/cloud-hypervisor.yaml +++ b/vmm/src/api/openapi/cloud-hypervisor.yaml @@ -820,6 +820,8 @@ components: format: int16 id: type: string + serial: + type: string NetConfig: type: object diff --git a/vmm/src/config.rs b/vmm/src/config.rs index 919478d68..a6836fc63 100644 --- a/vmm/src/config.rs +++ b/vmm/src/config.rs @@ -779,7 +779,8 @@ impl DiskConfig { .add("ops_refill_time") .add("id") .add("_disable_io_uring") - .add("pci_segment"); + .add("pci_segment") + .add("serial"); parser.parse(disk).map_err(Error::ParseDisk)?; let path = parser.get("path").map(PathBuf::from); @@ -846,6 +847,7 @@ impl DiskConfig { .convert("ops_refill_time") .map_err(Error::ParseDisk)? .unwrap_or_default(); + let serial = parser.get("serial"); let bw_tb_config = if bw_size != 0 && bw_refill_time != 0 { Some(TokenBucketConfig { size: bw_size, @@ -886,6 +888,7 @@ impl DiskConfig { id, disable_io_uring, pci_segment, + serial, }) } @@ -2462,7 +2465,14 @@ mod tests { ..Default::default() } ); - + assert_eq!( + DiskConfig::parse("path=/path/to_file,serial=test")?, + DiskConfig { + path: Some(PathBuf::from("/path/to_file")), + serial: Some(String::from("test")), + ..Default::default() + } + ); Ok(()) } diff --git a/vmm/src/device_manager.rs b/vmm/src/device_manager.rs index 80092e5ba..1f53390ca 100644 --- a/vmm/src/device_manager.rs +++ b/vmm/src/device_manager.rs @@ -2315,6 +2315,7 @@ impl DeviceManager { self.force_iommu | disk_cfg.iommu, disk_cfg.num_queues, disk_cfg.queue_size, + disk_cfg.serial.clone(), self.seccomp_action.clone(), disk_cfg.rate_limiter_config, self.exit_evt diff --git a/vmm/src/vm_config.rs b/vmm/src/vm_config.rs index c1b1de937..67ba0e126 100644 --- a/vmm/src/vm_config.rs +++ b/vmm/src/vm_config.rs @@ -220,6 +220,8 @@ pub struct DiskConfig { pub disable_io_uring: bool, #[serde(default)] pub pci_segment: u16, + #[serde(default)] + pub serial: Option, } pub const DEFAULT_DISK_NUM_QUEUES: usize = 1; @@ -249,6 +251,7 @@ impl Default for DiskConfig { disable_io_uring: false, rate_limiter_config: None, pci_segment: 0, + serial: None, } } }