From dae5132fd643e68fd4d77ea55847ee2043c2674b Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Mon, 20 Nov 2023 20:37:57 +0300 Subject: [PATCH 001/489] usb: Add cancel_packet() function to UsbDevice trait It's better to have the ability to cancel an incoming USB packet, e.g. when resetting the device. Signed-off-by: Goriainov Stanislav --- devices/src/usb/camera.rs | 2 ++ devices/src/usb/keyboard.rs | 2 ++ devices/src/usb/mod.rs | 4 ++++ devices/src/usb/storage.rs | 2 ++ devices/src/usb/tablet.rs | 2 ++ devices/src/usb/usbhost/mod.rs | 2 ++ 6 files changed, 14 insertions(+) diff --git a/devices/src/usb/camera.rs b/devices/src/usb/camera.rs index bd7ae9fb..12cbe6b2 100644 --- a/devices/src/usb/camera.rs +++ b/devices/src/usb/camera.rs @@ -783,6 +783,8 @@ impl UsbDevice for UsbCamera { Ok(()) } + fn cancel_packet(&mut self, _packet: &Arc>) {} + fn reset(&mut self) { info!("Camera {} device reset", self.device_id()); self.base.addr = 0; diff --git a/devices/src/usb/keyboard.rs b/devices/src/usb/keyboard.rs index 73dc8ed9..b6a01a4b 100644 --- a/devices/src/usb/keyboard.rs +++ b/devices/src/usb/keyboard.rs @@ -217,6 +217,8 @@ impl UsbDevice for UsbKeyboard { Ok(()) } + fn cancel_packet(&mut self, _packet: &Arc>) {} + fn reset(&mut self) { info!("Keyboard device reset"); self.base.remote_wakeup = 0; diff --git a/devices/src/usb/mod.rs b/devices/src/usb/mod.rs index f44d8b50..3fc1772f 100644 --- a/devices/src/usb/mod.rs +++ b/devices/src/usb/mod.rs @@ -349,6 +349,10 @@ pub trait UsbDevice: Send + Sync { fn unrealize(&mut self) -> Result<()> { Ok(()) } + + /// Cancel specified USB packet. + fn cancel_packet(&mut self, packet: &Arc>); + /// Handle the attach ops when attach device to controller. fn handle_attach(&mut self) -> Result<()> { let usb_dev = self.usb_device_base_mut(); diff --git a/devices/src/usb/storage.rs b/devices/src/usb/storage.rs index b227ecc0..1c34077e 100644 --- a/devices/src/usb/storage.rs +++ b/devices/src/usb/storage.rs @@ -542,6 +542,8 @@ impl UsbDevice for UsbStorage { Ok(storage) } + fn cancel_packet(&mut self, _packet: &Arc>) {} + fn reset(&mut self) { info!("Storage device reset"); self.base.remote_wakeup = 0; diff --git a/devices/src/usb/tablet.rs b/devices/src/usb/tablet.rs index 67a15139..a1171956 100644 --- a/devices/src/usb/tablet.rs +++ b/devices/src/usb/tablet.rs @@ -260,6 +260,8 @@ impl UsbDevice for UsbTablet { Ok(()) } + fn cancel_packet(&mut self, _packet: &Arc>) {} + fn reset(&mut self) { info!("Tablet device reset"); self.base.remote_wakeup = 0; diff --git a/devices/src/usb/usbhost/mod.rs b/devices/src/usb/usbhost/mod.rs index e34d1176..5abdb292 100644 --- a/devices/src/usb/usbhost/mod.rs +++ b/devices/src/usb/usbhost/mod.rs @@ -1045,6 +1045,8 @@ impl UsbDevice for UsbHost { Ok(()) } + fn cancel_packet(&mut self, _packet: &Arc>) {} + fn reset(&mut self) { info!("Usb Host device {} reset", self.device_id()); if self.handle.is_none() { -- Gitee From 958a0bfd461547c14443c6dab46c70c6461a8aae Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Fri, 24 Nov 2023 12:26:58 +0300 Subject: [PATCH 002/489] usb: Add target_dev to UsbPacket If one needs to cancel a USB packet, he has to know which device it is targeted at. Signed-off-by: Goriainov Stanislav --- devices/src/usb/mod.rs | 4 ++++ devices/src/usb/xhci/xhci_controller.rs | 18 +++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/devices/src/usb/mod.rs b/devices/src/usb/mod.rs index 3fc1772f..e461b757 100644 --- a/devices/src/usb/mod.rs +++ b/devices/src/usb/mod.rs @@ -511,6 +511,8 @@ pub struct UsbPacket { pub ep_number: u8, /// Transfer for complete packet. pub xfer_ops: Option>>, + /// Target USB device for this packet. + pub target_dev: Option>>, /// Stream id. pub stream: u32, } @@ -532,6 +534,7 @@ impl UsbPacket { ep_number: u8, iovecs: Vec, xfer_ops: Option>>, + target_dev: Option>>, ) -> Self { Self { packet_id, @@ -543,6 +546,7 @@ impl UsbPacket { actual_length: 0, ep_number, xfer_ops, + target_dev, stream: 0, } } diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index d15fef77..186b8d8b 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -1189,6 +1189,7 @@ impl XhciDevice { index: 0, length: 0, }; + let target_dev = Arc::downgrade(dev) as Weak>; let packet_id = self.generate_packet_id(); let p = Arc::new(Mutex::new(UsbPacket::new( packet_id, @@ -1196,6 +1197,7 @@ impl XhciDevice { 0, Vec::new(), None, + Some(target_dev), ))); trace::usb_handle_control(&locked_dev.usb_device_base().base.id, &device_req); locked_dev.handle_control(&p, &device_req); @@ -1939,10 +1941,24 @@ impl XhciDevice { } } + let target_dev = + if let Ok(target_dev) = self.get_usb_dev(locked_xfer.slotid, locked_xfer.epid) { + Some(Arc::downgrade(&target_dev) as Weak>) + } else { + None + }; + let packet_id = self.generate_packet_id(); let (_, ep_number) = endpoint_id_to_number(locked_xfer.epid as u8); let xfer_ops = Arc::downgrade(xfer) as Weak>; - let packet = UsbPacket::new(packet_id, dir as u32, ep_number, vec, Some(xfer_ops)); + let packet = UsbPacket::new( + packet_id, + dir as u32, + ep_number, + vec, + Some(xfer_ops), + target_dev, + ); Ok(Arc::new(Mutex::new(packet))) } -- Gitee From c39d52681c8b3ea93aaf9250ffc925118163675b Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Fri, 9 Feb 2024 11:50:00 +0300 Subject: [PATCH 003/489] xhci: Add USB Packet cancellation logic Add cancel_packet() calls when cancelling endpoint transfers. Signed-off-by: Stanislav Goriainov --- devices/src/usb/xhci/xhci_controller.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index 186b8d8b..3d90b9a2 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -2035,6 +2035,13 @@ impl XhciDevice { if report != TRBCCode::Invalid { xfer.status = report; xfer.submit_transfer()?; + + if let Some(usb_dev) = xfer.packet.lock().unwrap().target_dev.as_ref() { + if let Some(usb_dev) = usb_dev.clone().upgrade() { + let mut locked_usb_dev = usb_dev.lock().unwrap(); + locked_usb_dev.cancel_packet(&xfer.packet); + } + } } xfer.running_async = false; killed = 1; -- Gitee From c2bcf823bb00b46f05c846b4d5d8ba64fd8e2566 Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Fri, 24 Nov 2023 11:47:26 +0300 Subject: [PATCH 004/489] usb: Implement get_device_qualifier_descriptor properly device_qualifier_desc in get_device_qualifer_descriptor() used to always result to None. Signed-off-by: Goriainov Stanislav --- devices/src/usb/config.rs | 1 + devices/src/usb/descriptor.rs | 22 ++++++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/devices/src/usb/config.rs b/devices/src/usb/config.rs index 3dda38b4..a0ce8520 100644 --- a/devices/src/usb/config.rs +++ b/devices/src/usb/config.rs @@ -218,6 +218,7 @@ pub const USB_DT_DEVICE_SIZE: u8 = 18; pub const USB_DT_CONFIG_SIZE: u8 = 9; pub const USB_DT_INTERFACE_SIZE: u8 = 9; pub const USB_DT_ENDPOINT_SIZE: u8 = 7; +pub const USB_DT_DEVICE_QUALIFIER_SIZE: u8 = 10; pub const USB_DT_BOS_SIZE: u8 = 5; pub const USB_DT_SS_CAP_SIZE: u8 = 10; pub const USB_DT_SS_EP_COMP_SIZE: u8 = 6; diff --git a/devices/src/usb/descriptor.rs b/devices/src/usb/descriptor.rs index bdb30f77..ca4c51e7 100644 --- a/devices/src/usb/descriptor.rs +++ b/devices/src/usb/descriptor.rs @@ -349,11 +349,25 @@ impl UsbDescriptor { } fn get_device_qualifier_descriptor(&self) -> Result> { - if let Some(desc) = self.device_qualifier_desc.as_ref() { - Ok(desc.qualifier_desc.as_bytes().to_vec()) - } else { - bail!("Device qualifier descriptor not found"); + if self.device_desc.is_none() { + bail!("device qualifier descriptor not found"); } + + // SAFETY: device_desc has just been checked + let device_desc = &self.device_desc.as_ref().unwrap().device_desc; + let device_qualifier_desc = UsbDeviceQualifierDescriptor { + bLength: USB_DT_DEVICE_QUALIFIER_SIZE, + bDescriptorType: USB_DT_DEVICE_QUALIFIER, + bcdUSB: device_desc.bcdUSB, + bDeviceClass: device_desc.bDeviceClass, + bDeviceSubClass: device_desc.bDeviceSubClass, + bDeviceProtocol: device_desc.bDeviceProtocol, + bMaxPacketSize0: device_desc.bMaxPacketSize0, + bNumConfigurations: device_desc.bNumConfigurations, + bReserved: 0, + }; + + Ok(device_qualifier_desc.as_bytes().to_vec()) } fn get_debug_descriptor(&self) -> Result> { -- Gitee From 0c428c180ab8205cfaaeecff6866916304046423 Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Fri, 9 Feb 2024 12:08:00 +0300 Subject: [PATCH 005/489] scsi: Make some fucntions from scsi pub They will be needed in USB UASP device module. Signed-off-by: Stanislav Goriainov --- devices/src/scsi/bus.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/devices/src/scsi/bus.rs b/devices/src/scsi/bus.rs index 95467435..271c51a5 100644 --- a/devices/src/scsi/bus.rs +++ b/devices/src/scsi/bus.rs @@ -766,7 +766,7 @@ fn scsi_cdb_length(cdb: &[u8; SCSI_CMD_BUF_SIZE]) -> i32 { } } -fn scsi_cdb_xfer(cdb: &[u8; SCSI_CMD_BUF_SIZE], dev: Arc>) -> i32 { +pub fn scsi_cdb_xfer(cdb: &[u8; SCSI_CMD_BUF_SIZE], dev: Arc>) -> i32 { let dev_lock = dev.lock().unwrap(); let block_size = dev_lock.block_size as i32; drop(dev_lock); @@ -824,7 +824,7 @@ fn scsi_cdb_lba(cdb: &[u8; SCSI_CMD_BUF_SIZE]) -> i64 { } } -fn scsi_cdb_xfer_mode(cdb: &[u8; SCSI_CMD_BUF_SIZE]) -> ScsiXferMode { +pub fn scsi_cdb_xfer_mode(cdb: &[u8; SCSI_CMD_BUF_SIZE]) -> ScsiXferMode { match cdb[0] { WRITE_6 | WRITE_10 -- Gitee From ecec9265572f3b3a4d20433433e33e1eba0de4aa Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Fri, 24 Nov 2023 12:51:48 +0300 Subject: [PATCH 006/489] uas: Add support for USB UASP protocol Add USB Attached SCSI (UAS) device. Now it has support for both high and super speeds. High speed support will be gradually removed with introduction of streams support on the XHCI controller. Signed-off-by: Stanislav Goriainov --- devices/src/usb/mod.rs | 1 + devices/src/usb/uas.rs | 1268 +++++++++++++++++++++++++++++ machine/src/lib.rs | 11 +- machine_manager/src/config/usb.rs | 63 ++ trace/trace_info/usb.toml | 102 +++ 5 files changed, 1443 insertions(+), 2 deletions(-) create mode 100644 devices/src/usb/uas.rs diff --git a/devices/src/usb/mod.rs b/devices/src/usb/mod.rs index e461b757..44f5d88e 100644 --- a/devices/src/usb/mod.rs +++ b/devices/src/usb/mod.rs @@ -20,6 +20,7 @@ pub mod hid; pub mod keyboard; pub mod storage; pub mod tablet; +pub mod uas; #[cfg(feature = "usb_host")] pub mod usbhost; pub mod xhci; diff --git a/devices/src/usb/uas.rs b/devices/src/usb/uas.rs new file mode 100644 index 00000000..552fa15c --- /dev/null +++ b/devices/src/usb/uas.rs @@ -0,0 +1,1268 @@ +// Copyright (c) 2023 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::array; +use std::cmp::min; +use std::collections::{HashMap, VecDeque}; +use std::mem::size_of; +use std::sync::{Arc, Mutex, MutexGuard, Weak}; + +use anyhow::{anyhow, bail, Context, Result}; +use log::{debug, error, info, warn}; +use machine_manager::config::{DriveFile, UsbUasConfig}; +use once_cell::sync::Lazy; +use util::byte_code::ByteCode; + +use super::config::*; +use super::descriptor::{ + UsbConfigDescriptor, UsbDescConfig, UsbDescDevice, UsbDescEndpoint, UsbDescIface, + UsbDescriptorOps, UsbDeviceDescriptor, UsbEndpointDescriptor, UsbInterfaceDescriptor, + UsbSuperSpeedEndpointCompDescriptor, +}; +use super::xhci::xhci_controller::XhciDevice; +use super::{ + UsbDevice, UsbDeviceBase, UsbDeviceRequest, UsbEndpoint, UsbPacket, UsbPacketStatus, + USB_DEVICE_BUFFER_DEFAULT_LEN, +}; + +use crate::{ + ScsiBus::{ + scsi_cdb_xfer, scsi_cdb_xfer_mode, ScsiBus, ScsiRequest, ScsiRequestOps, ScsiSense, + ScsiXferMode, CHECK_CONDITION, EMULATE_SCSI_OPS, GOOD, SCSI_SENSE_INVALID_PARAM_VALUE, + SCSI_SENSE_INVALID_TAG, SCSI_SENSE_NO_SENSE, SCSI_SENSE_OVERLAPPED_COMMANDS, + }, + ScsiDisk::{ScsiDevice, SCSI_TYPE_DISK, SCSI_TYPE_ROM}, +}; + +// Size of UasIUBody +const UAS_IU_BODY_SIZE: usize = 30; + +// Size of cdb in UAS Command IU +const UAS_COMMAND_CDB_SIZE: usize = 16; + +// CRC16 of "STRATOVIRT" +const USB_UAS_VENDOR_ID: u16 = 0xB74C; + +// UAS Pipe IDs +const UAS_PIPE_ID_COMMAND: u8 = 0x01; +const UAS_PIPE_ID_STATUS: u8 = 0x02; +const UAS_PIPE_ID_DATA_IN: u8 = 0x03; +const UAS_PIPE_ID_DATA_OUT: u8 = 0x04; + +// UAS Streams Attributes +const UAS_MAX_STREAMS_BM_ATTR: u8 = 0; +const UAS_MAX_STREAMS: usize = 1 << UAS_MAX_STREAMS_BM_ATTR; + +// UAS IU IDs +const UAS_IU_ID_COMMAND: u8 = 0x01; +const UAS_IU_ID_SENSE: u8 = 0x03; +const UAS_IU_ID_RESPONSE: u8 = 0x04; +const UAS_IU_ID_TASK_MGMT: u8 = 0x05; +const UAS_IU_ID_READ_READY: u8 = 0x06; +const UAS_IU_ID_WRITE_READY: u8 = 0x07; + +// UAS Response Codes +const _UAS_RC_TMF_COMPLETE: u8 = 0x00; +const _UAS_RC_INVALID_IU: u8 = 0x02; +const UAS_RC_TMF_NOT_SUPPORTED: u8 = 0x04; +const _UAS_RC_TMF_FAILED: u8 = 0x05; +const _UAS_RC_TMF_SUCCEEDED: u8 = 0x08; +const _UAS_RC_INCORRECT_LUN: u8 = 0x09; +const _UAS_RC_OVERLAPPED_TAG: u8 = 0x0A; + +// UAS Task Management Functions +const _UAS_TMF_ABORT_TASK: u8 = 0x01; +const _UAS_TMF_ABORT_TASK_SET: u8 = 0x02; +const _UAS_TMF_CLEAR_TASK_SET: u8 = 0x04; +const _UAS_TMF_LOGICAL_UNIT_RESET: u8 = 0x08; +const _UAS_TMF_I_T_NEXUS_RESET: u8 = 0x10; +const _UAS_TMF_CLEAR_ACA: u8 = 0x40; +const _UAS_TMF_QUERY_TASK: u8 = 0x80; +const _UAS_TMF_QUERY_TASK_SET: u8 = 0x81; +const _UAS_TMF_QUERY_ASYNC_EVENT: u8 = 0x82; + +// USB Pipe Usage Descriptor +const USB_DT_PIPE_USAGE: u8 = 0x24; +const USB_DT_PIPE_USAGE_SIZE: u8 = 4; + +pub struct UsbUas { + base: UsbDeviceBase, + scsi_bus: Arc>, + scsi_device: Arc>, + commands_high: VecDeque, + statuses_high: VecDeque>>, + commands_super: [Option; UAS_MAX_STREAMS + 1], + statuses_super: [Option>>; UAS_MAX_STREAMS + 1], + data: [Option>>; UAS_MAX_STREAMS + 1], + data_ready_sent: bool, +} + +#[derive(Debug)] +enum UsbUasStringId { + #[allow(unused)] + Invalid = 0, + Manufacturer = 1, + Product = 2, + SerialNumber = 3, + ConfigHigh = 4, + ConfigSuper = 5, +} + +const UAS_DESC_STRINGS: [&str; 6] = [ + "", + "StratoVirt", + "StratoVirt USB Uas", + "5", + "High speed config (usb 2.0)", + "Super speed config (usb 3.0)", +]; + +struct UasRequest { + data: Option>>, + status: Arc>, + iu: UasIU, + completed: bool, +} + +impl ScsiRequestOps for UasRequest { + fn scsi_request_complete_cb( + &mut self, + scsi_status: u8, + scsi_sense: Option, + ) -> Result<()> { + let tag = u16::from_be(self.iu.header.tag); + let sense = scsi_sense.unwrap_or(SCSI_SENSE_NO_SENSE); + UsbUas::fill_sense(&mut self.status.lock().unwrap(), tag, scsi_status, &sense); + self.complete(); + Ok(()) + } +} + +#[derive(Debug, PartialEq, Eq)] +enum UasPacketStatus { + Completed = 0, + Pending = 1, +} + +impl From for UasPacketStatus { + fn from(status: bool) -> Self { + match status { + true => Self::Completed, + false => Self::Pending, + } + } +} + +#[allow(non_snake_case)] +#[repr(C, packed)] +#[derive(Copy, Clone, Debug, Default)] +struct UsbPipeUsageDescriptor { + bLength: u8, + bDescriptorType: u8, + bPipeId: u8, + bReserved: u8, +} + +impl ByteCode for UsbPipeUsageDescriptor {} + +#[repr(C, packed)] +#[derive(Default, Clone, Copy)] +struct UasIUHeader { + id: u8, + reserved: u8, + tag: u16, +} + +#[repr(C, packed)] +#[derive(Default, Clone, Copy)] +struct UasIUCommand { + prio_task_attr: u8, // 6:3 priority, 2:0 task attribute + reserved_1: u8, + add_cdb_len: u8, + reserved_2: u8, + lun: u64, + cdb: [u8; UAS_COMMAND_CDB_SIZE], + add_cdb: [u8; 1], // not supported by stratovirt +} + +#[repr(C, packed)] +#[derive(Default, Clone, Copy)] +struct UasIUSense { + status_qualifier: u16, + status: u8, + reserved: [u8; 7], + sense_length: u16, + sense_data: [u8; 18], +} + +#[repr(C, packed)] +#[derive(Default, Clone, Copy)] +struct UasIUResponse { + add_response_info: [u8; 3], + response_code: u8, +} + +#[repr(C, packed)] +#[derive(Default, Clone, Copy)] +struct UasIUTaskManagement { + function: u8, + reserved: u8, + task_tag: u16, + lun: u64, +} + +#[repr(C, packed)] +#[derive(Clone, Copy)] +union UasIUBody { + command: UasIUCommand, + sense: UasIUSense, + response: UasIUResponse, + task_management: UasIUTaskManagement, + raw_data: [u8; UAS_IU_BODY_SIZE], +} + +impl Default for UasIUBody { + fn default() -> Self { + Self { + raw_data: [0; UAS_IU_BODY_SIZE], + } + } +} + +#[repr(C, packed)] +#[derive(Default, Clone, Copy)] +struct UasIU { + header: UasIUHeader, + body: UasIUBody, +} + +impl ByteCode for UasIU {} + +static DESC_DEVICE_UAS_SUPER: Lazy> = Lazy::new(|| { + Arc::new(UsbDescDevice { + device_desc: UsbDeviceDescriptor { + bLength: USB_DT_DEVICE_SIZE, + bDescriptorType: USB_DT_DEVICE, + bcdUSB: 0x0300, + bDeviceClass: 0, + bDeviceSubClass: 0, + bDeviceProtocol: 0, + bMaxPacketSize0: 9, + idVendor: USB_UAS_VENDOR_ID, + idProduct: 0x0001, + bcdDevice: 0x0, + iManufacturer: UsbUasStringId::Manufacturer as u8, + iProduct: UsbUasStringId::Product as u8, + iSerialNumber: UsbUasStringId::SerialNumber as u8, + bNumConfigurations: 1, + }, + configs: vec![Arc::new(UsbDescConfig { + config_desc: UsbConfigDescriptor { + bLength: USB_DT_CONFIG_SIZE, + bDescriptorType: USB_DT_CONFIGURATION, + wTotalLength: 0, + bNumInterfaces: 1, + bConfigurationValue: 1, + iConfiguration: UsbUasStringId::ConfigSuper as u8, + bmAttributes: USB_CONFIGURATION_ATTR_ONE | USB_CONFIGURATION_ATTR_SELF_POWER, + bMaxPower: 50, + }, + iad_desc: vec![], + interfaces: vec![DESC_IFACE_UAS_SUPER.clone()], + })], + }) +}); + +static DESC_IFACE_UAS_SUPER: Lazy> = Lazy::new(|| { + Arc::new(UsbDescIface { + interface_desc: UsbInterfaceDescriptor { + bLength: USB_DT_INTERFACE_SIZE, + bDescriptorType: USB_DT_INTERFACE, + bInterfaceNumber: 0, + bAlternateSetting: 0, + bNumEndpoints: 4, + bInterfaceClass: USB_CLASS_MASS_STORAGE, + bInterfaceSubClass: 0x06, // SCSI + bInterfaceProtocol: 0x62, // UAS + iInterface: 0, + }, + other_desc: vec![], + endpoints: vec![ + Arc::new(UsbDescEndpoint { + endpoint_desc: UsbEndpointDescriptor { + bLength: USB_DT_ENDPOINT_SIZE, + bDescriptorType: USB_DT_ENDPOINT, + bEndpointAddress: USB_DIRECTION_HOST_TO_DEVICE | UAS_PIPE_ID_COMMAND, + bmAttributes: USB_ENDPOINT_ATTR_BULK, + wMaxPacketSize: 1024, + bInterval: 0, + }, + extra: [ + UsbSuperSpeedEndpointCompDescriptor { + bLength: USB_DT_SS_EP_COMP_SIZE, + bDescriptorType: USB_DT_ENDPOINT_COMPANION, + bMaxBurst: 15, + bmAttributes: 0, + wBytesPerInterval: 0, + } + .as_bytes(), + UsbPipeUsageDescriptor { + bLength: USB_DT_PIPE_USAGE_SIZE, + bDescriptorType: USB_DT_PIPE_USAGE, + bPipeId: UAS_PIPE_ID_COMMAND, + bReserved: 0, + } + .as_bytes(), + ] + .concat() + .to_vec(), + }), + Arc::new(UsbDescEndpoint { + endpoint_desc: UsbEndpointDescriptor { + bLength: USB_DT_ENDPOINT_SIZE, + bDescriptorType: USB_DT_ENDPOINT, + bEndpointAddress: USB_DIRECTION_DEVICE_TO_HOST | UAS_PIPE_ID_STATUS, + bmAttributes: USB_ENDPOINT_ATTR_BULK, + wMaxPacketSize: 1024, + bInterval: 0, + }, + extra: [ + UsbSuperSpeedEndpointCompDescriptor { + bLength: USB_DT_SS_EP_COMP_SIZE, + bDescriptorType: USB_DT_ENDPOINT_COMPANION, + bMaxBurst: 15, + bmAttributes: UAS_MAX_STREAMS_BM_ATTR, + wBytesPerInterval: 0, + } + .as_bytes(), + UsbPipeUsageDescriptor { + bLength: USB_DT_PIPE_USAGE_SIZE, + bDescriptorType: USB_DT_PIPE_USAGE, + bPipeId: UAS_PIPE_ID_STATUS, + bReserved: 0, + } + .as_bytes(), + ] + .concat() + .to_vec(), + }), + Arc::new(UsbDescEndpoint { + endpoint_desc: UsbEndpointDescriptor { + bLength: USB_DT_ENDPOINT_SIZE, + bDescriptorType: USB_DT_ENDPOINT, + bEndpointAddress: USB_DIRECTION_DEVICE_TO_HOST | UAS_PIPE_ID_DATA_IN, + bmAttributes: USB_ENDPOINT_ATTR_BULK, + wMaxPacketSize: 1024, + bInterval: 0, + }, + extra: [ + UsbSuperSpeedEndpointCompDescriptor { + bLength: USB_DT_SS_EP_COMP_SIZE, + bDescriptorType: USB_DT_ENDPOINT_COMPANION, + bMaxBurst: 15, + bmAttributes: UAS_MAX_STREAMS_BM_ATTR, + wBytesPerInterval: 0, + } + .as_bytes(), + UsbPipeUsageDescriptor { + bLength: USB_DT_PIPE_USAGE_SIZE, + bDescriptorType: USB_DT_PIPE_USAGE, + bPipeId: UAS_PIPE_ID_DATA_IN, + bReserved: 0, + } + .as_bytes(), + ] + .concat() + .to_vec(), + }), + Arc::new(UsbDescEndpoint { + endpoint_desc: UsbEndpointDescriptor { + bLength: USB_DT_ENDPOINT_SIZE, + bDescriptorType: USB_DT_ENDPOINT, + bEndpointAddress: USB_DIRECTION_HOST_TO_DEVICE | UAS_PIPE_ID_DATA_OUT, + bmAttributes: USB_ENDPOINT_ATTR_BULK, + wMaxPacketSize: 1024, + bInterval: 0, + }, + extra: [ + UsbSuperSpeedEndpointCompDescriptor { + bLength: USB_DT_SS_EP_COMP_SIZE, + bDescriptorType: USB_DT_ENDPOINT_COMPANION, + bMaxBurst: 15, + bmAttributes: UAS_MAX_STREAMS_BM_ATTR, + wBytesPerInterval: 0, + } + .as_bytes(), + UsbPipeUsageDescriptor { + bLength: USB_DT_PIPE_USAGE_SIZE, + bDescriptorType: USB_DT_PIPE_USAGE, + bPipeId: UAS_PIPE_ID_DATA_OUT, + bReserved: 0, + } + .as_bytes(), + ] + .concat() + .to_vec(), + }), + ], + }) +}); + +static DESC_DEVICE_UAS_HIGH: Lazy> = Lazy::new(|| { + Arc::new(UsbDescDevice { + device_desc: UsbDeviceDescriptor { + bLength: USB_DT_DEVICE_SIZE, + bDescriptorType: USB_DT_DEVICE, + bcdUSB: 0x0200, + bDeviceClass: 0, + bDeviceSubClass: 0, + bDeviceProtocol: 0, + bMaxPacketSize0: 64, + idVendor: USB_UAS_VENDOR_ID, + idProduct: 0x0002, + bcdDevice: 0x0001, + iManufacturer: UsbUasStringId::Manufacturer as u8, + iProduct: UsbUasStringId::Product as u8, + iSerialNumber: UsbUasStringId::SerialNumber as u8, + bNumConfigurations: 1, + }, + configs: vec![Arc::new(UsbDescConfig { + config_desc: UsbConfigDescriptor { + bLength: USB_DT_CONFIG_SIZE, + bDescriptorType: USB_DT_CONFIGURATION, + wTotalLength: 0, + bNumInterfaces: 1, + bConfigurationValue: 1, + iConfiguration: UsbUasStringId::ConfigHigh as u8, + bmAttributes: USB_CONFIGURATION_ATTR_ONE | USB_CONFIGURATION_ATTR_SELF_POWER, + bMaxPower: 0xFA, + }, + iad_desc: vec![], + interfaces: vec![DESC_IFACE_EMPTY.clone(), DESC_IFACE_UAS_HIGH.clone()], + })], + }) +}); + +static DESC_IFACE_UAS_HIGH: Lazy> = Lazy::new(|| { + Arc::new(UsbDescIface { + interface_desc: UsbInterfaceDescriptor { + bLength: USB_DT_INTERFACE_SIZE, + bDescriptorType: USB_DT_INTERFACE, + bInterfaceNumber: 0, + bAlternateSetting: 1, + bNumEndpoints: 4, + bInterfaceClass: USB_CLASS_MASS_STORAGE, + bInterfaceSubClass: 0x06, // SCSI + bInterfaceProtocol: 0x62, // UAS + iInterface: 0, + }, + other_desc: vec![], + endpoints: vec![ + Arc::new(UsbDescEndpoint { + endpoint_desc: UsbEndpointDescriptor { + bLength: USB_DT_ENDPOINT_SIZE, + bDescriptorType: USB_DT_ENDPOINT, + bEndpointAddress: USB_DIRECTION_HOST_TO_DEVICE | UAS_PIPE_ID_COMMAND, + bmAttributes: USB_ENDPOINT_ATTR_BULK, + wMaxPacketSize: 512, + bInterval: 0xFF, + }, + extra: UsbPipeUsageDescriptor { + bLength: USB_DT_PIPE_USAGE_SIZE, + bDescriptorType: USB_DT_PIPE_USAGE, + bPipeId: UAS_PIPE_ID_COMMAND, + bReserved: 0, + } + .as_bytes() + .to_vec(), + }), + Arc::new(UsbDescEndpoint { + endpoint_desc: UsbEndpointDescriptor { + bLength: USB_DT_ENDPOINT_SIZE, + bDescriptorType: USB_DT_ENDPOINT, + bEndpointAddress: USB_DIRECTION_DEVICE_TO_HOST | UAS_PIPE_ID_STATUS, + bmAttributes: USB_ENDPOINT_ATTR_BULK, + wMaxPacketSize: 512, + bInterval: 0xFF, + }, + extra: UsbPipeUsageDescriptor { + bLength: USB_DT_PIPE_USAGE_SIZE, + bDescriptorType: USB_DT_PIPE_USAGE, + bPipeId: UAS_PIPE_ID_STATUS, + bReserved: 0, + } + .as_bytes() + .to_vec(), + }), + Arc::new(UsbDescEndpoint { + endpoint_desc: UsbEndpointDescriptor { + bLength: USB_DT_ENDPOINT_SIZE, + bDescriptorType: USB_DT_ENDPOINT, + bEndpointAddress: USB_DIRECTION_DEVICE_TO_HOST | UAS_PIPE_ID_DATA_IN, + bmAttributes: USB_ENDPOINT_ATTR_BULK, + wMaxPacketSize: 512, + bInterval: 0xFF, + }, + extra: UsbPipeUsageDescriptor { + bLength: USB_DT_PIPE_USAGE_SIZE, + bDescriptorType: USB_DT_PIPE_USAGE, + bPipeId: UAS_PIPE_ID_DATA_IN, + bReserved: 0, + } + .as_bytes() + .to_vec(), + }), + Arc::new(UsbDescEndpoint { + endpoint_desc: UsbEndpointDescriptor { + bLength: USB_DT_ENDPOINT_SIZE, + bDescriptorType: USB_DT_ENDPOINT, + bEndpointAddress: USB_DIRECTION_HOST_TO_DEVICE | UAS_PIPE_ID_DATA_OUT, + bmAttributes: USB_ENDPOINT_ATTR_BULK, + wMaxPacketSize: 512, + bInterval: 0xFF, + }, + extra: UsbPipeUsageDescriptor { + bLength: USB_DT_PIPE_USAGE_SIZE, + bDescriptorType: USB_DT_PIPE_USAGE, + bPipeId: UAS_PIPE_ID_DATA_OUT, + bReserved: 0, + } + .as_bytes() + .to_vec(), + }), + ], + }) +}); + +// NOTE: Fake BOT interface descriptor is needed here since Windows UASP driver always expects two +// interfaces: both BOT and UASP. It also anticipates the UASP descriptor to be the second one. +// Therefore, the first one can be a BOT storage stub. +static DESC_IFACE_EMPTY: Lazy> = Lazy::new(|| { + Arc::new(UsbDescIface { + interface_desc: UsbInterfaceDescriptor { + bLength: USB_DT_INTERFACE_SIZE, + bDescriptorType: USB_DT_INTERFACE, + bInterfaceNumber: 0, + bAlternateSetting: 0, + bNumEndpoints: 0, + bInterfaceClass: USB_CLASS_MASS_STORAGE, + bInterfaceSubClass: 0x00, // SCSI + bInterfaceProtocol: 0x00, // BOT + iInterface: 0, + }, + other_desc: vec![], + endpoints: vec![], + }) +}); + +fn complete_async_packet(locked_packet: MutexGuard<'_, UsbPacket>) { + if let Some(xfer_ops) = locked_packet.xfer_ops.as_ref() { + if let Some(xfer_ops) = xfer_ops.clone().upgrade() { + drop(locked_packet); + xfer_ops.lock().unwrap().submit_transfer(); + } + } +} + +impl UsbUas { + pub fn new( + uas_config: UsbUasConfig, + drive_files: Arc>>, + ) -> Self { + let scsi_type = match &uas_config.media as &str { + "disk" => SCSI_TYPE_DISK, + _ => SCSI_TYPE_ROM, + }; + + let mut base = UsbDeviceBase::new( + uas_config.id.clone().unwrap(), + USB_DEVICE_BUFFER_DEFAULT_LEN, + ); + + base.speed = match uas_config.speed.as_deref() { + Some("super") => USB_SPEED_SUPER, + _ => USB_SPEED_HIGH, + }; + + Self { + base, + scsi_bus: Arc::new(Mutex::new(ScsiBus::new("".to_string()))), + scsi_device: Arc::new(Mutex::new(ScsiDevice::new( + uas_config.scsi_cfg, + scsi_type, + drive_files, + ))), + commands_high: VecDeque::new(), + commands_super: array::from_fn(|_| None), + statuses_high: VecDeque::new(), + statuses_super: array::from_fn(|_| None), + data: array::from_fn(|_| None), + data_ready_sent: false, + } + } + + fn streams_enabled(&self) -> bool { + self.base.speed == USB_SPEED_SUPER + } + + fn cancel_io(&mut self) { + self.commands_high = VecDeque::new(); + self.commands_super = array::from_fn(|_| None); + self.statuses_high = VecDeque::new(); + self.statuses_super = array::from_fn(|_| None); + self.data = array::from_fn(|_| None); + self.data_ready_sent = false; + } + + fn peek_next_status(&self, stream: usize) -> Option<&Arc>> { + match self.streams_enabled() { + true => self.statuses_super[stream].as_ref(), + false => self.statuses_high.front(), + } + } + + fn take_next_status(&mut self, stream: usize) -> Arc> { + match self.streams_enabled() { + true => self.statuses_super[stream].take().unwrap(), + false => self.statuses_high.pop_front().unwrap(), + } + } + + fn queue_status(&mut self, status: &Arc>, stream: usize) { + match self.streams_enabled() { + true => self.statuses_super[stream] = Some(Arc::clone(status)), + false => self.statuses_high.push_back(Arc::clone(status)), + }; + } + + fn peek_next_command(&self, stream: usize) -> Option<&UasIU> { + match self.streams_enabled() { + true => self.commands_super[stream].as_ref(), + false => self.commands_high.front(), + } + } + + fn take_next_command(&mut self, stream: usize) -> UasIU { + match self.streams_enabled() { + true => self.commands_super[stream].take().unwrap(), + false => self.commands_high.pop_front().unwrap(), + } + } + + fn queue_command(&mut self, command: UasIU, stream: usize) { + match self.streams_enabled() { + true => self.commands_super[stream] = Some(command), + false => self.commands_high.push_back(command), + } + } + + fn handle_iu_command( + &mut self, + iu: &UasIU, + mut uas_request: UasRequest, + ) -> Result { + // SAFETY: iu is guaranteed to be of type command + let add_cdb_len = unsafe { iu.body.command.add_cdb_len }; + let tag = u16::from_be(iu.header.tag); + + if add_cdb_len > 0 { + Self::fill_fake_sense( + &mut uas_request.status.lock().unwrap(), + tag, + &SCSI_SENSE_INVALID_PARAM_VALUE, + ); + uas_request.complete(); + bail!("additional cdb length is not supported"); + } + + if self.streams_enabled() && tag > UAS_MAX_STREAMS as u16 { + Self::fill_fake_sense( + &mut uas_request.status.lock().unwrap(), + tag, + &SCSI_SENSE_INVALID_TAG, + ); + uas_request.complete(); + bail!("invalid tag {}", tag); + } + + if self.streams_enabled() && self.commands_super[tag as usize].is_some() { + Self::fill_fake_sense( + &mut uas_request.status.lock().unwrap(), + tag, + &SCSI_SENSE_OVERLAPPED_COMMANDS, + ); + uas_request.complete(); + bail!("overlapped tag {}", tag); + } + + let (scsi_iovec, scsi_iovec_size) = match uas_request.data.as_ref() { + Some(data) => { + let mut locked_data = data.lock().unwrap(); + let iov_size = locked_data.get_iovecs_size() as u32; + locked_data.actual_length = iov_size; + (locked_data.iovecs.clone(), iov_size) + } + None => (Vec::new(), 0), + }; + + // SAFETY: iu is guaranteed to of type command + let cdb = unsafe { iu.body.command.cdb }; + // SAFETY: iu is guaranteed to of type command + let lun = unsafe { iu.body.command.lun } as u16; + trace::usb_uas_handle_iu_command(self.device_id(), cdb[0]); + let uas_request = Box::new(uas_request); + let scsi_request = ScsiRequest::new( + cdb, + lun, + scsi_iovec, + scsi_iovec_size, + Arc::clone(&self.scsi_device), + uas_request, + ) + .with_context(|| "Failed to create SCSI request.")?; + + if scsi_request.cmd.xfer > scsi_request.datalen + && scsi_request.cmd.mode != ScsiXferMode::ScsiXferNone + { + bail!( + "insufficient buffer provided (requested length {}, provided length {})", + scsi_request.cmd.xfer, + scsi_request.datalen + ); + } + + let scsi_request = match scsi_request.opstype { + EMULATE_SCSI_OPS => scsi_request.emulate_execute(), + _ => scsi_request.execute(), + } + .with_context(|| "Failed to execute SCSI request.")?; + + let upper_request = &mut scsi_request.lock().unwrap().upper_req; + let uas_request = upper_request + .as_mut() + .as_any_mut() + .downcast_mut::() + .unwrap(); + + Ok(uas_request.completed.into()) + } + + fn handle_iu_task_management( + &mut self, + iu: &UasIU, + mut uas_request: UasRequest, + ) -> Result { + let tag = u16::from_be(iu.header.tag); + + if self.streams_enabled() && tag > UAS_MAX_STREAMS as u16 { + Self::fill_fake_sense( + &mut uas_request.status.lock().unwrap(), + tag, + &SCSI_SENSE_INVALID_TAG, + ); + uas_request.complete(); + bail!("invalid tag {}", tag); + } + + if self.streams_enabled() && self.commands_super[tag as usize].is_some() { + Self::fill_fake_sense( + &mut uas_request.status.lock().unwrap(), + tag, + &SCSI_SENSE_OVERLAPPED_COMMANDS, + ); + uas_request.complete(); + bail!("overlapped tag {}", tag); + } + + // SAFETY: iu is guaranteed to be of type task management + let tmf = unsafe { iu.body.task_management.function }; + + #[allow(clippy::match_single_binding)] + match tmf { + _ => { + warn!("UAS {} device unsupported TMF {}.", self.device_id(), tmf); + Self::fill_response( + &mut uas_request.status.lock().unwrap(), + tag, + UAS_RC_TMF_NOT_SUPPORTED, + ); + } + }; + + uas_request.complete(); + Ok(UasPacketStatus::Completed) + } + + fn fill_response(packet: &mut UsbPacket, tag: u16, code: u8) { + let mut iu = UasIU::new(UAS_IU_ID_RESPONSE, tag); + iu.body.response.response_code = code; + let iu_len = size_of::() + size_of::(); + Self::fill_packet(packet, &mut iu, iu_len); + } + + fn fill_sense(packet: &mut UsbPacket, tag: u16, status: u8, sense: &ScsiSense) { + let mut iu = UasIU::new(UAS_IU_ID_SENSE, tag); + // SAFETY: iu is guaranteed to be of type status + let iu_sense = unsafe { &mut iu.body.sense }; + + iu_sense.status = status; + iu_sense.status_qualifier = 0_u16.to_be(); + iu_sense.sense_length = 0_u16.to_be(); + + if status != GOOD { + iu_sense.sense_length = 18_u16.to_be(); + iu_sense.sense_data[0] = 0x71; // Error code: deferred errors + iu_sense.sense_data[2] = sense.key; + iu_sense.sense_data[7] = 10; // Additional sense length: total length - 8 + iu_sense.sense_data[12] = sense.asc; + iu_sense.sense_data[13] = sense.ascq; + } + + let sense_len = iu_sense.sense_length as usize; + let real_sense_len = size_of::() - iu_sense.sense_data.len() + sense_len; + let iu_len = size_of::() + real_sense_len; + trace::usb_uas_fill_sense(status, iu_len, sense_len); + Self::fill_packet(packet, &mut iu, iu_len); + } + + fn fill_fake_sense(packet: &mut UsbPacket, tag: u16, sense: &ScsiSense) { + let mut iu = UasIU::new(UAS_IU_ID_SENSE, tag); + // SAFETY: iu is guaranteed to be of type status + let iu_sense = unsafe { &mut iu.body.sense }; + + iu_sense.status = CHECK_CONDITION; + iu_sense.status_qualifier = 0_u16.to_be(); + iu_sense.sense_length = 18_u16.to_be(); + iu_sense.sense_data[0] = 0x70; // Error code: current errors + iu_sense.sense_data[2] = sense.key; + iu_sense.sense_data[7] = 10; // Additional sense length: total length - 8 + iu_sense.sense_data[12] = sense.asc; + iu_sense.sense_data[13] = sense.ascq; + + let iu_len = size_of::() + size_of::(); + trace::usb_uas_fill_fake_sense(CHECK_CONDITION, iu_len, 18); + Self::fill_packet(packet, &mut iu, iu_len); + } + + fn fill_read_ready(packet: &mut UsbPacket, tag: u16) { + let mut iu = UasIU::new(UAS_IU_ID_READ_READY, tag); + let iu_len = size_of::(); + Self::fill_packet(packet, &mut iu, iu_len); + } + + fn fill_write_ready(packet: &mut UsbPacket, tag: u16) { + let mut iu = UasIU::new(UAS_IU_ID_WRITE_READY, tag); + let iu_len = size_of::(); + Self::fill_packet(packet, &mut iu, iu_len); + } + + fn fill_packet(packet: &mut UsbPacket, iu: &mut UasIU, iu_len: usize) { + let iov_size = packet.get_iovecs_size() as usize; + let iu_len = min(iov_size, iu_len); + trace::usb_uas_fill_packet(iov_size); + packet.transfer_packet(iu.as_mut_bytes(), iu_len); + } + + fn try_start_next_transfer(&mut self, stream: usize) -> UasPacketStatus { + let command = self.peek_next_command(stream); + + if let Some(command) = command { + // SAFETY: iu is guaranteed to be of type command + let cdb = unsafe { &command.body.command.cdb }; + let xfer_len = scsi_cdb_xfer(cdb, Arc::clone(&self.scsi_device)); + trace::usb_uas_try_start_next_transfer(self.device_id(), xfer_len); + + if xfer_len > 0 { + self.try_start_next_data(stream) + } else { + self.try_start_next_non_data(stream) + } + } else { + debug!( + "UAS {} device no inflight command when trying to start the next transfer.", + self.device_id() + ); + UasPacketStatus::Pending + } + } + + fn try_start_next_data(&mut self, stream: usize) -> UasPacketStatus { + let status = self.peek_next_status(stream); + + if status.is_none() { + debug!( + "UAS {} device no inflight status when trying to start the next data transfer.", + self.device_id() + ); + return UasPacketStatus::Pending; + } + + if !self.data_ready_sent { + return self.fill_data_ready(stream); + } + + if self.data[stream].is_some() { + self.start_next_transfer(stream) + } else { + debug!( + "UAS {} device no inflight data when trying to start the next data transfer.", + self.device_id() + ); + UasPacketStatus::Pending + } + } + + fn fill_data_ready(&mut self, stream: usize) -> UasPacketStatus { + // SAFETY: status must have been checked in try_start_next_data + let status = self.take_next_status(stream); + let mut locked_status = status.lock().unwrap(); + + // SAFETY: command must have been checked in try_start_next_transfer + let iu = self.peek_next_command(stream).unwrap(); + let tag = u16::from_be(iu.header.tag); + + // SAFETY: iu is guaranteed to be of type command + let cdb = unsafe { &iu.body.command.cdb }; + let xfer_mode = scsi_cdb_xfer_mode(cdb); + + match xfer_mode { + ScsiXferMode::ScsiXferFromDev => Self::fill_read_ready(&mut locked_status, tag), + ScsiXferMode::ScsiXferToDev => Self::fill_write_ready(&mut locked_status, tag), + ScsiXferMode::ScsiXferNone => { + warn!( + "UAS {} device cannot fill data ready, operation {} is not a data transfer.", + self.device_id(), + cdb[0] + ); + Self::fill_fake_sense(&mut locked_status, tag, &SCSI_SENSE_INVALID_PARAM_VALUE); + } + } + + if locked_status.is_async { + complete_async_packet(locked_status); + } + + self.data_ready_sent = true; + trace::usb_uas_fill_data_ready(self.device_id(), self.data_ready_sent); + UasPacketStatus::Completed + } + + fn try_start_next_non_data(&mut self, stream: usize) -> UasPacketStatus { + let status = self.peek_next_status(stream); + + if status.is_none() { + debug!( + "UAS {} device no inflight status when trying to start the next non-data transfer.", + self.device_id() + ); + return UasPacketStatus::Pending; + } + + self.start_next_transfer(stream) + } + + fn start_next_transfer(&mut self, stream: usize) -> UasPacketStatus { + trace::usb_uas_start_next_transfer(self.device_id(), stream); + + // SAFETY: status must have been checked in try_start_next_data or try_start_next_non_data + let status = self.take_next_status(stream); + + // SAFETY: command must have been checked in try_start_next_transfer + let command = self.take_next_command(stream); + + let mut uas_request = UasRequest::new(&status, &command); + uas_request.data = self.data[stream].take(); + + let result = match command.header.id { + UAS_IU_ID_COMMAND => self.handle_iu_command(&command, uas_request), + UAS_IU_ID_TASK_MGMT => self.handle_iu_task_management(&command, uas_request), + _ => Err(anyhow!("impossible command IU {}", command.header.id)), + }; + + self.data_ready_sent = false; + + if !self.streams_enabled() { + self.try_start_next_transfer(0); + } + + match result { + Ok(result) => result, + Err(err) => { + error!("UAS {} device error: {:#?}.", self.device_id(), err); + UasPacketStatus::Completed + } + } + } +} + +impl UsbDevice for UsbUas { + fn usb_device_base(&self) -> &UsbDeviceBase { + &self.base + } + + fn usb_device_base_mut(&mut self) -> &mut UsbDeviceBase { + &mut self.base + } + + fn realize(mut self) -> Result>> { + info!("UAS {} device realize.", self.device_id()); + self.base.reset_usb_endpoint(); + let mut desc_strings: Vec = + UAS_DESC_STRINGS.iter().map(|str| str.to_string()).collect(); + let prefix = &desc_strings[UsbUasStringId::SerialNumber as usize]; + desc_strings[UsbUasStringId::SerialNumber as usize] = + self.base.generate_serial_number(prefix); + + match self.base.speed { + USB_SPEED_HIGH => self + .base + .init_descriptor(DESC_DEVICE_UAS_HIGH.clone(), desc_strings)?, + USB_SPEED_SUPER => self + .base + .init_descriptor(DESC_DEVICE_UAS_SUPER.clone(), desc_strings)?, + _ => bail!("USB UAS unsupported device speed {}.", self.base.speed), + } + + // NOTE: "aio=off,direct=false" must be configured and other aio/direct values are not + // supported. + let mut locked_scsi_device = self.scsi_device.lock().unwrap(); + locked_scsi_device.realize(None)?; + locked_scsi_device.parent_bus = Arc::downgrade(&self.scsi_bus); + drop(locked_scsi_device); + self.scsi_bus + .lock() + .unwrap() + .devices + .insert((0, 0), Arc::clone(&self.scsi_device)); + + let uas = Arc::new(Mutex::new(self)); + Ok(uas) + } + + fn cancel_packet(&mut self, _packet: &Arc>) { + self.cancel_io(); + } + + fn reset(&mut self) { + info!("UAS {} device reset.", self.device_id()); + self.base.remote_wakeup = 0; + self.base.addr = 0; + self.cancel_io(); + } + + fn handle_control(&mut self, packet: &Arc>, device_req: &UsbDeviceRequest) { + let mut locked_packet = packet.lock().unwrap(); + trace::usb_uas_handle_control( + locked_packet.packet_id, + self.device_id(), + device_req.as_bytes(), + ); + + match self + .base + .handle_control_for_descriptor(&mut locked_packet, device_req) + { + Ok(handled) => { + if handled { + debug!( + "UAS {} device control handled by descriptor, return directly.", + self.device_id() + ); + return; + } + + error!( + "UAS {} device unhandled control request {:?}.", + self.device_id(), + device_req + ); + locked_packet.status = UsbPacketStatus::Stall; + } + Err(err) => { + error!( + "UAS {} device descriptor error {:?}.", + self.device_id(), + err + ); + locked_packet.status = UsbPacketStatus::Stall; + } + } + } + + fn handle_data(&mut self, packet: &Arc>) { + let locked_packet = packet.lock().unwrap(); + let stream = locked_packet.stream as usize; + let ep_number = locked_packet.ep_number; + let packet_id = locked_packet.packet_id; + trace::usb_uas_handle_data(self.device_id(), ep_number, stream); + drop(locked_packet); + + if self.streams_enabled() && stream > UAS_MAX_STREAMS { + warn!("UAS {} device invalid stream {}.", self.device_id(), stream); + packet.lock().unwrap().status = UsbPacketStatus::Stall; + return; + } + + // NOTE: The architecture of this device is rather simple: it first waits for all of the + // required USB packets to arrive, and only then creates and sends an actual UAS request. + // The number of USB packets differs from 2 to 4 and depends on whether the command involves + // data transfers or not. Since the packets arrive in arbitrary order, some of them may be + // queued asynchronously. Note that the command packet is always completed right away. For + // all the other types of packets, their asynchronous status is determined by the return + // value of try_start_next_transfer(). All the asynchronously queued packets will be + // completed in scsi_request_complete_cb() callback. + match ep_number { + UAS_PIPE_ID_COMMAND => { + if self.streams_enabled() && self.commands_super[stream].is_some() { + warn!( + "UAS {} device multiple command packets on stream {}.", + self.device_id(), + stream + ); + packet.lock().unwrap().status = UsbPacketStatus::Stall; + return; + } + + let mut locked_packet = packet.lock().unwrap(); + let mut iu = UasIU::default(); + let iov_size = locked_packet.get_iovecs_size() as usize; + let iu_len = min(iov_size, size_of::()); + locked_packet.transfer_packet(iu.as_mut_bytes(), iu_len); + + trace::usb_uas_command_received(packet_id, self.device_id()); + self.queue_command(iu, stream); + self.try_start_next_transfer(stream); + trace::usb_uas_command_completed(packet_id, self.device_id()); + } + UAS_PIPE_ID_STATUS => { + if self.streams_enabled() && self.statuses_super[stream].is_some() { + warn!( + "UAS {} device multiple status packets on stream {}.", + self.device_id(), + stream + ); + packet.lock().unwrap().status = UsbPacketStatus::Stall; + return; + } + + trace::usb_uas_status_received(packet_id, self.device_id()); + self.queue_status(packet, stream); + let result = self.try_start_next_transfer(stream); + + match result { + UasPacketStatus::Completed => { + trace::usb_uas_status_completed(packet_id, self.device_id()) + } + UasPacketStatus::Pending => { + packet.lock().unwrap().is_async = true; + trace::usb_uas_status_queued_async(packet_id, self.device_id()); + } + } + } + UAS_PIPE_ID_DATA_OUT | UAS_PIPE_ID_DATA_IN => { + if self.data[stream].is_some() { + warn!( + "UAS {} device multiple data packets on stream {}.", + self.device_id(), + stream + ); + packet.lock().unwrap().status = UsbPacketStatus::Stall; + return; + } + + trace::usb_uas_data_received(packet_id, self.device_id()); + self.data[stream] = Some(Arc::clone(packet)); + let result = self.try_start_next_transfer(stream); + + match result { + UasPacketStatus::Completed => { + trace::usb_uas_data_completed(packet_id, self.device_id()) + } + UasPacketStatus::Pending => { + packet.lock().unwrap().is_async = true; + trace::usb_uas_data_queued_async(packet_id, self.device_id()); + } + } + } + _ => { + error!( + "UAS {} device bad endpoint number {}.", + self.device_id(), + ep_number + ); + } + } + } + + fn set_controller(&mut self, _controller: std::sync::Weak>) {} + + fn get_controller(&self) -> Option>> { + None + } + + fn get_wakeup_endpoint(&self) -> &UsbEndpoint { + self.base.get_endpoint(true, 1) + } +} + +impl UasRequest { + fn new(status: &Arc>, iu: &UasIU) -> Self { + Self { + data: None, + status: Arc::clone(status), + iu: *iu, + completed: false, + } + } + + fn complete(&mut self) { + let locked_status = self.status.lock().unwrap(); + + // NOTE: Due to the specifics of this device, it waits for all of the required USB packets + // to arrive before starting an actual transfer. Therefore, some packets may arrive earlier + // than others, and they won't be completed right away (except for command packets) but + // rather queued asynchronously. A certain packet may also be async if it was the last to + // arrive and UasRequest didn't complete right away. + if locked_status.is_async { + complete_async_packet(locked_status); + } + + if let Some(data) = &self.data { + let locked_data = data.lock().unwrap(); + + if locked_data.is_async { + complete_async_packet(locked_data); + } + } + + self.completed = true; + } +} + +impl UasIUHeader { + fn new(id: u8, tag: u16) -> Self { + UasIUHeader { + id, + reserved: 0, + tag: tag.to_be(), + } + } +} + +impl UasIU { + fn new(id: u8, tag: u16) -> Self { + Self { + header: UasIUHeader::new(id, tag), + body: UasIUBody::default(), + } + } +} diff --git a/machine/src/lib.rs b/machine/src/lib.rs index ceeb39fb..895551ee 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -63,7 +63,7 @@ use devices::usb::tablet::{UsbTablet, UsbTabletConfig}; #[cfg(feature = "usb_host")] use devices::usb::usbhost::{UsbHost, UsbHostConfig}; use devices::usb::xhci::xhci_pci::{XhciConfig, XhciPciDevice}; -use devices::usb::{storage::UsbStorage, UsbDevice}; +use devices::usb::{storage::UsbStorage, uas::UsbUas, UsbDevice}; #[cfg(target_arch = "aarch64")] use devices::InterruptController; use devices::ScsiDisk::{ScsiDevice, SCSI_TYPE_DISK, SCSI_TYPE_ROM}; @@ -77,6 +77,7 @@ use machine_manager::config::parse_gpu; #[cfg(feature = "pvpanic")] use machine_manager::config::parse_pvpanic; use machine_manager::config::parse_usb_storage; +use machine_manager::config::parse_usb_uas; use machine_manager::config::{ complete_numa_node, get_multi_function, get_pci_bdf, parse_blk, parse_device_id, parse_device_type, parse_fs, parse_net, parse_numa_distance, parse_numa_mem, parse_rng_dev, @@ -1724,6 +1725,12 @@ pub trait MachineOps { .realize() .with_context(|| "Failed to realize usb storage device")? } + "usb-uas" => { + let device_cfg = parse_usb_uas(vm_config, cfg_args)?; + let uas = UsbUas::new(device_cfg, self.get_drive_files()); + uas.realize() + .with_context(|| "Failed to realize usb uas device")? + } #[cfg(feature = "usb_host")] "usb-host" => { let config = UsbHostConfig::try_parse_from(str_slip_to_clap(cfg_args))?; @@ -1793,7 +1800,7 @@ pub trait MachineOps { ("vhost-user-blk-pci",add_vhost_user_blk_pci, vm_config, cfg_args, false), ("vhost-user-fs-pci" | "vhost-user-fs-device", add_virtio_fs, vm_config, cfg_args), ("nec-usb-xhci", add_usb_xhci, cfg_args), - ("usb-kbd" | "usb-storage" | "usb-tablet" | "usb-camera" | "usb-host", add_usb_device, vm_config, cfg_args); + ("usb-kbd" | "usb-storage" | "usb-uas" | "usb-tablet" | "usb-camera" | "usb-host", add_usb_device, vm_config, cfg_args); #[cfg(feature = "virtio_gpu")] ("virtio-gpu-pci", add_virtio_pci_gpu, cfg_args), #[cfg(feature = "ramfb")] diff --git a/machine_manager/src/config/usb.rs b/machine_manager/src/config/usb.rs index da363b7e..1b0e492c 100644 --- a/machine_manager/src/config/usb.rs +++ b/machine_manager/src/config/usb.rs @@ -97,3 +97,66 @@ pub fn parse_usb_storage(vm_config: &mut VmConfig, drive_config: &str) -> Result dev.check()?; Ok(dev) } + +#[derive(Clone, Debug, Default)] +pub struct UsbUasConfig { + pub id: Option, + pub speed: Option, + pub scsi_cfg: ScsiDevConfig, + pub media: String, +} + +impl UsbUasConfig { + fn new() -> Self { + Self::default() + } +} + +impl ConfigCheck for UsbUasConfig { + fn check(&self) -> Result<()> { + check_id(self.id.clone(), "usb-uas")?; + + if self.scsi_cfg.aio_type != AioEngine::Off || self.scsi_cfg.direct { + bail!("USB UAS: \"aio=off,direct=false\" must be configured."); + } + + Ok(()) + } +} + +pub fn parse_usb_uas(vm_config: &mut VmConfig, drive_config: &str) -> Result { + let mut cmd_parser = CmdParser::new("usb-uas"); + cmd_parser + .push("") + .push("id") + .push("bus") + .push("port") + .push("drive") + .push("speed"); + + cmd_parser.parse(drive_config)?; + + let mut dev = UsbUasConfig::new(); + dev.id = cmd_parser.get_value::("id")?; + dev.speed = cmd_parser.get_value::("speed")?; + + let uas_drive = cmd_parser.get_value::("drive")?.with_context(|| { + ConfigError::FieldIsMissing("drive".to_string(), "usb uas device".to_string()) + })?; + + let drive_arg = &vm_config + .drives + .remove(&uas_drive) + .with_context(|| "No drive configured matched for usb uas device.")?; + dev.scsi_cfg.path_on_host = drive_arg.path_on_host.clone(); + dev.scsi_cfg.read_only = drive_arg.read_only; + dev.scsi_cfg.aio_type = drive_arg.aio; + dev.scsi_cfg.direct = drive_arg.direct; + dev.scsi_cfg.format = drive_arg.format; + dev.scsi_cfg.l2_cache_size = drive_arg.l2_cache_size; + dev.scsi_cfg.refcount_cache_size = drive_arg.refcount_cache_size; + dev.media = drive_arg.media.clone(); + + dev.check()?; + Ok(dev) +} diff --git a/trace/trace_info/usb.toml b/trace/trace_info/usb.toml index fa5b9454..d94588e6 100644 --- a/trace/trace_info/usb.toml +++ b/trace/trace_info/usb.toml @@ -465,3 +465,105 @@ name = "usb_host_req_complete" args = "bus_num: u8, addr: u8, packet: u64, status: &dyn fmt::Debug, actual_length: usize" message = "dev bus 0x{:X} addr 0x{:X}, packet 0x{:#X}, status {:?} actual length {}" enabled = true + +[[events]] +name = "usb_uas_handle_control" +args = "packet_id: u32, device_id: &str, req: &[u8]" +message = "USB {} packet received on UAS {} device, the request is {:?}." +enabled = true + +[[events]] +name = "usb_uas_handle_iu_command" +args = "device_id: &str, cdb: u8" +message = "UAS {} device handling IU with cdb[0] {}." +enabled = true + +[[events]] +name = "usb_uas_fill_sense" +args = "status: u8, iu_len: usize, sense_len: usize" +message = "UAS device is filling sense with status {:02} URB length {} sense length {}." +enabled = true + +[[events]] +name = "usb_uas_fill_fake_sense" +args = "status: u8, iu_len: usize, sense_len: usize" +message = "UAS device is filling fake sense with status {:02} URB length {} sense length {}." +enabled = true + +[[events]] +name = "usb_uas_fill_packet" +args = "iovec_size: usize" +message = "UAS device is filling USB packet with iovec of size {}." +enabled = true + +[[events]] +name = "usb_uas_try_start_next_transfer" +args = "device_id: &str, xfer_len: i32" +message = "UAS {} device is trying to start next transfer of length {}." +enabled = true + +[[events]] +name = "usb_uas_fill_data_ready" +args = "device_id: &str, data_ready_sent: bool" +message = "UAS {} device set data_ready_sent to {}." +enabled = true + +[[events]] +name = "usb_uas_start_next_transfer" +args = "device_id: &str, stream: usize" +message = "UAS {} device starting a transfer on stream {}." +enabled = true + +[[events]] +name = "usb_uas_handle_data" +args = "device_id: &str, endpoint: u8, stream: usize" +message = "UAS {} device handling data on endpoint {} and stream {}." +enabled = true + +[[events]] +name = "usb_uas_command_received" +args = "packet_id: u32, device_id: &str" +message = "USB {} command packet received on UAS {} device." +enabled = true + +[[events]] +name = "usb_uas_command_completed" +args = "packet_id: u32, device_id: &str" +message = "USB {} command packet completed on UAS {} device." +enabled = true + +[[events]] +name = "usb_uas_status_received" +args = "packet_id: u32, device_id: &str" +message = "USB {} status packet received on UAS {} device." +enabled = true + +[[events]] +name = "usb_uas_status_completed" +args = "packet_id: u32, device_id: &str" +message = "USB {} status packet completed on UAS {} device." +enabled = true + +[[events]] +name = "usb_uas_status_queued_async" +args = "packet_id: u32, device_id: &str" +message = "USB {} status packet queued async on UAS {} device." +enabled = true + +[[events]] +name = "usb_uas_data_received" +args = "packet_id: u32, device_id: &str" +message = "USB {} data packet received on UAS {} device." +enabled = true + +[[events]] +name = "usb_uas_data_completed" +args = "packet_id: u32, device_id: &str" +message = "USB {} data packet completed on UAS {} device." +enabled = true + +[[events]] +name = "usb_uas_data_queued_async" +args = "packet_id: u32, device_id: &str" +message = "USB {} data packet queued async on UAS {} device." +enabled = true -- Gitee From fa7fe743b1aff934ff75f3ea8903cf373168d3fd Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Tue, 13 Feb 2024 15:25:47 +0300 Subject: [PATCH 007/489] uas: Use strum EnumCount macro for convenience Add strum and strum_macro to the dependecies list. Use strum EnumCount macro instead of the magic const to determine the size of the enum. Signed-off-by: Stanislav Goriainov --- Cargo.lock | 2 ++ devices/Cargo.toml | 2 ++ devices/src/usb/uas.rs | 6 ++++-- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index f4c523c6..b53bd7ae 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -381,6 +381,8 @@ dependencies = [ "rusb", "serde", "serde_json", + "strum", + "strum_macros", "thiserror", "trace", "ui", diff --git a/devices/Cargo.toml b/devices/Cargo.toml index e19dea9b..5d54eabf 100644 --- a/devices/Cargo.toml +++ b/devices/Cargo.toml @@ -12,6 +12,8 @@ anyhow = "1.0" libc = "0.2" log = "0.4" serde = { version = "1.0", features = ["derive"] } +strum = "0.24.1" +strum_macros = "0.24.3" vmm-sys-util = "0.11.1" byteorder = "1.4.3" drm-fourcc = ">=2.2.0" diff --git a/devices/src/usb/uas.rs b/devices/src/usb/uas.rs index 552fa15c..ef7e90c4 100644 --- a/devices/src/usb/uas.rs +++ b/devices/src/usb/uas.rs @@ -20,6 +20,8 @@ use anyhow::{anyhow, bail, Context, Result}; use log::{debug, error, info, warn}; use machine_manager::config::{DriveFile, UsbUasConfig}; use once_cell::sync::Lazy; +use strum::EnumCount; +use strum_macros::EnumCount; use util::byte_code::ByteCode; use super::config::*; @@ -106,7 +108,7 @@ pub struct UsbUas { data_ready_sent: bool, } -#[derive(Debug)] +#[derive(Debug, EnumCount)] enum UsbUasStringId { #[allow(unused)] Invalid = 0, @@ -117,7 +119,7 @@ enum UsbUasStringId { ConfigSuper = 5, } -const UAS_DESC_STRINGS: [&str; 6] = [ +const UAS_DESC_STRINGS: [&str; UsbUasStringId::COUNT] = [ "", "StratoVirt", "StratoVirt USB Uas", -- Gitee From c701065030711798affe0eefec9f60c432c849f6 Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Tue, 13 Feb 2024 17:04:24 +0300 Subject: [PATCH 008/489] usb: Move common USB constants to config.rs Move some common USB descriptor-related values to config.rs. Also move vendor and device ids there, so that it would be easier to track ids and ensure that they are unique. Signed-off-by: Stanislav Goriainov --- devices/src/usb/camera.rs | 9 ++------- devices/src/usb/config.rs | 23 +++++++++++++++++++++- devices/src/usb/keyboard.rs | 6 +++--- devices/src/usb/storage.rs | 6 +++--- devices/src/usb/tablet.rs | 2 +- devices/src/usb/uas.rs | 39 ++++++++++++++----------------------- 6 files changed, 46 insertions(+), 39 deletions(-) diff --git a/devices/src/usb/camera.rs b/devices/src/usb/camera.rs index 12cbe6b2..cedf8cdc 100644 --- a/devices/src/usb/camera.rs +++ b/devices/src/usb/camera.rs @@ -44,11 +44,6 @@ use util::loop_context::{ read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, }; -// CRC16 of "STRATOVIRT" -const UVC_VENDOR_ID: u16 = 0xB74C; -// The first 4 chars of "VIDEO", 5 substitutes V. -const UVC_PRODUCT_ID: u16 = 0x51DE; - const INTERFACE_ID_CONTROL: u8 = 0; const INTERFACE_ID_STREAMING: u8 = 1; @@ -433,8 +428,8 @@ fn gen_desc_device_camera(fmt_list: Vec) -> Result> = Lazy::new(|| { bLength: USB_DT_DEVICE_SIZE, bDescriptorType: USB_DT_DEVICE, idVendor: 0x0627, - idProduct: 0x0001, + idProduct: USB_PRODUCT_ID_KEYBOARD, bcdDevice: 0, iManufacturer: STR_MANUFACTURER_INDEX, iProduct: STR_PRODUCT_KEYBOARD_INDEX, @@ -76,8 +76,8 @@ static DESC_IFACE_KEYBOARD: Lazy> = Lazy::new(|| { bAlternateSetting: 0, bNumEndpoints: 1, bInterfaceClass: USB_CLASS_HID, - bInterfaceSubClass: 1, - bInterfaceProtocol: 1, + bInterfaceSubClass: USB_SUBCLASS_BOOT, + bInterfaceProtocol: USB_IFACE_PROTOCOL_KEYBOARD, iInterface: 0, }, other_desc: vec![Arc::new(UsbDescOther { diff --git a/devices/src/usb/storage.rs b/devices/src/usb/storage.rs index 1c34077e..4bb44e0e 100644 --- a/devices/src/usb/storage.rs +++ b/devices/src/usb/storage.rs @@ -43,7 +43,7 @@ static DESC_DEVICE_STORAGE: Lazy> = Lazy::new(|| { bLength: USB_DT_DEVICE_SIZE, bDescriptorType: USB_DT_DEVICE, idVendor: USB_STORAGE_VENDOR_ID, - idProduct: 0x0001, + idProduct: USB_PRODUCT_ID_STORAGE, bcdDevice: 0, iManufacturer: STR_MANUFACTURER_INDEX, iProduct: STR_PRODUCT_STORAGE_INDEX, @@ -82,8 +82,8 @@ static DESC_IFACE_STORAGE: Lazy> = Lazy::new(|| { bAlternateSetting: 0, bNumEndpoints: 2, bInterfaceClass: USB_CLASS_MASS_STORAGE, - bInterfaceSubClass: 0x06, // SCSI - bInterfaceProtocol: 0x50, // Bulk-only + bInterfaceSubClass: USB_SUBCLASS_SCSI, + bInterfaceProtocol: USB_IFACE_PROTOCOL_BOT, iInterface: 0, }, other_desc: vec![], diff --git a/devices/src/usb/tablet.rs b/devices/src/usb/tablet.rs index a1171956..af3ab297 100644 --- a/devices/src/usb/tablet.rs +++ b/devices/src/usb/tablet.rs @@ -44,7 +44,7 @@ static DESC_DEVICE_TABLET: Lazy> = Lazy::new(|| { bLength: USB_DT_DEVICE_SIZE, bDescriptorType: USB_DT_DEVICE, idVendor: 0x0627, - idProduct: 0x0001, + idProduct: USB_PRODUCT_ID_TABLET, bcdDevice: 0, iManufacturer: STR_MANUFACTURER_INDEX, iProduct: STR_PRODUCT_TABLET_INDEX, diff --git a/devices/src/usb/uas.rs b/devices/src/usb/uas.rs index ef7e90c4..95944ee1 100644 --- a/devices/src/usb/uas.rs +++ b/devices/src/usb/uas.rs @@ -51,9 +51,6 @@ const UAS_IU_BODY_SIZE: usize = 30; // Size of cdb in UAS Command IU const UAS_COMMAND_CDB_SIZE: usize = 16; -// CRC16 of "STRATOVIRT" -const USB_UAS_VENDOR_ID: u16 = 0xB74C; - // UAS Pipe IDs const UAS_PIPE_ID_COMMAND: u8 = 0x01; const UAS_PIPE_ID_STATUS: u8 = 0x02; @@ -92,10 +89,6 @@ const _UAS_TMF_QUERY_TASK: u8 = 0x80; const _UAS_TMF_QUERY_TASK_SET: u8 = 0x81; const _UAS_TMF_QUERY_ASYNC_EVENT: u8 = 0x82; -// USB Pipe Usage Descriptor -const USB_DT_PIPE_USAGE: u8 = 0x24; -const USB_DT_PIPE_USAGE_SIZE: u8 = 4; - pub struct UsbUas { base: UsbDeviceBase, scsi_bus: Arc>, @@ -259,9 +252,9 @@ static DESC_DEVICE_UAS_SUPER: Lazy> = Lazy::new(|| { bDeviceSubClass: 0, bDeviceProtocol: 0, bMaxPacketSize0: 9, - idVendor: USB_UAS_VENDOR_ID, - idProduct: 0x0001, - bcdDevice: 0x0, + idVendor: USB_VENDOR_ID_STRATOVIRT, + idProduct: USB_PRODUCT_ID_UAS, + bcdDevice: 0, iManufacturer: UsbUasStringId::Manufacturer as u8, iProduct: UsbUasStringId::Product as u8, iSerialNumber: UsbUasStringId::SerialNumber as u8, @@ -293,8 +286,8 @@ static DESC_IFACE_UAS_SUPER: Lazy> = Lazy::new(|| { bAlternateSetting: 0, bNumEndpoints: 4, bInterfaceClass: USB_CLASS_MASS_STORAGE, - bInterfaceSubClass: 0x06, // SCSI - bInterfaceProtocol: 0x62, // UAS + bInterfaceSubClass: USB_SUBCLASS_SCSI, + bInterfaceProtocol: USB_IFACE_PROTOCOL_UAS, iInterface: 0, }, other_desc: vec![], @@ -429,9 +422,9 @@ static DESC_DEVICE_UAS_HIGH: Lazy> = Lazy::new(|| { bDeviceSubClass: 0, bDeviceProtocol: 0, bMaxPacketSize0: 64, - idVendor: USB_UAS_VENDOR_ID, - idProduct: 0x0002, - bcdDevice: 0x0001, + idVendor: USB_VENDOR_ID_STRATOVIRT, + idProduct: USB_PRODUCT_ID_UAS, + bcdDevice: 0, iManufacturer: UsbUasStringId::Manufacturer as u8, iProduct: UsbUasStringId::Product as u8, iSerialNumber: UsbUasStringId::SerialNumber as u8, @@ -463,8 +456,8 @@ static DESC_IFACE_UAS_HIGH: Lazy> = Lazy::new(|| { bAlternateSetting: 1, bNumEndpoints: 4, bInterfaceClass: USB_CLASS_MASS_STORAGE, - bInterfaceSubClass: 0x06, // SCSI - bInterfaceProtocol: 0x62, // UAS + bInterfaceSubClass: USB_SUBCLASS_SCSI, + bInterfaceProtocol: USB_IFACE_PROTOCOL_UAS, iInterface: 0, }, other_desc: vec![], @@ -476,7 +469,7 @@ static DESC_IFACE_UAS_HIGH: Lazy> = Lazy::new(|| { bEndpointAddress: USB_DIRECTION_HOST_TO_DEVICE | UAS_PIPE_ID_COMMAND, bmAttributes: USB_ENDPOINT_ATTR_BULK, wMaxPacketSize: 512, - bInterval: 0xFF, + bInterval: 0, }, extra: UsbPipeUsageDescriptor { bLength: USB_DT_PIPE_USAGE_SIZE, @@ -494,7 +487,7 @@ static DESC_IFACE_UAS_HIGH: Lazy> = Lazy::new(|| { bEndpointAddress: USB_DIRECTION_DEVICE_TO_HOST | UAS_PIPE_ID_STATUS, bmAttributes: USB_ENDPOINT_ATTR_BULK, wMaxPacketSize: 512, - bInterval: 0xFF, + bInterval: 0, }, extra: UsbPipeUsageDescriptor { bLength: USB_DT_PIPE_USAGE_SIZE, @@ -512,7 +505,7 @@ static DESC_IFACE_UAS_HIGH: Lazy> = Lazy::new(|| { bEndpointAddress: USB_DIRECTION_DEVICE_TO_HOST | UAS_PIPE_ID_DATA_IN, bmAttributes: USB_ENDPOINT_ATTR_BULK, wMaxPacketSize: 512, - bInterval: 0xFF, + bInterval: 0, }, extra: UsbPipeUsageDescriptor { bLength: USB_DT_PIPE_USAGE_SIZE, @@ -530,7 +523,7 @@ static DESC_IFACE_UAS_HIGH: Lazy> = Lazy::new(|| { bEndpointAddress: USB_DIRECTION_HOST_TO_DEVICE | UAS_PIPE_ID_DATA_OUT, bmAttributes: USB_ENDPOINT_ATTR_BULK, wMaxPacketSize: 512, - bInterval: 0xFF, + bInterval: 0, }, extra: UsbPipeUsageDescriptor { bLength: USB_DT_PIPE_USAGE_SIZE, @@ -557,9 +550,7 @@ static DESC_IFACE_EMPTY: Lazy> = Lazy::new(|| { bAlternateSetting: 0, bNumEndpoints: 0, bInterfaceClass: USB_CLASS_MASS_STORAGE, - bInterfaceSubClass: 0x00, // SCSI - bInterfaceProtocol: 0x00, // BOT - iInterface: 0, + ..Default::default() }, other_desc: vec![], endpoints: vec![], -- Gitee From 716b26ae8b061bb9f8e13fc3781c8bb1fb46167e Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Tue, 12 Mar 2024 15:22:40 +0300 Subject: [PATCH 009/489] uas: Fix some logical code issues Many small fixes including: applying stub BOT Descriptor hack for Super Speed, improving readability etc. Signed-off-by: goriainovstanislav --- devices/src/usb/uas.rs | 43 ++++++++++++++----------- devices/src/usb/xhci/xhci_controller.rs | 4 ++- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/devices/src/usb/uas.rs b/devices/src/usb/uas.rs index 95944ee1..3768b8bb 100644 --- a/devices/src/usb/uas.rs +++ b/devices/src/usb/uas.rs @@ -14,7 +14,7 @@ use std::array; use std::cmp::min; use std::collections::{HashMap, VecDeque}; use std::mem::size_of; -use std::sync::{Arc, Mutex, MutexGuard, Weak}; +use std::sync::{Arc, Mutex, Weak}; use anyhow::{anyhow, bail, Context, Result}; use log::{debug, error, info, warn}; @@ -272,7 +272,7 @@ static DESC_DEVICE_UAS_SUPER: Lazy> = Lazy::new(|| { bMaxPower: 50, }, iad_desc: vec![], - interfaces: vec![DESC_IFACE_UAS_SUPER.clone()], + interfaces: vec![DESC_IFACE_EMPTY.clone(), DESC_IFACE_UAS_SUPER.clone()], })], }) }); @@ -283,7 +283,7 @@ static DESC_IFACE_UAS_SUPER: Lazy> = Lazy::new(|| { bLength: USB_DT_INTERFACE_SIZE, bDescriptorType: USB_DT_INTERFACE, bInterfaceNumber: 0, - bAlternateSetting: 0, + bAlternateSetting: 1, bNumEndpoints: 4, bInterfaceClass: USB_CLASS_MASS_STORAGE, bInterfaceSubClass: USB_SUBCLASS_SCSI, @@ -439,7 +439,7 @@ static DESC_DEVICE_UAS_HIGH: Lazy> = Lazy::new(|| { bConfigurationValue: 1, iConfiguration: UsbUasStringId::ConfigHigh as u8, bmAttributes: USB_CONFIGURATION_ATTR_ONE | USB_CONFIGURATION_ATTR_SELF_POWER, - bMaxPower: 0xFA, + bMaxPower: 50, }, iad_desc: vec![], interfaces: vec![DESC_IFACE_EMPTY.clone(), DESC_IFACE_UAS_HIGH.clone()], @@ -550,14 +550,18 @@ static DESC_IFACE_EMPTY: Lazy> = Lazy::new(|| { bAlternateSetting: 0, bNumEndpoints: 0, bInterfaceClass: USB_CLASS_MASS_STORAGE, - ..Default::default() + bInterfaceSubClass: USB_SUBCLASS_SCSI, + bInterfaceProtocol: USB_IFACE_PROTOCOL_BOT, + iInterface: 0, }, other_desc: vec![], endpoints: vec![], }) }); -fn complete_async_packet(locked_packet: MutexGuard<'_, UsbPacket>) { +fn complete_async_packet(packet: &Arc>) { + let locked_packet = packet.lock().unwrap(); + if let Some(xfer_ops) = locked_packet.xfer_ops.as_ref() { if let Some(xfer_ops) = xfer_ops.clone().upgrade() { drop(locked_packet); @@ -940,8 +944,11 @@ impl UsbUas { } } - if locked_status.is_async { - complete_async_packet(locked_status); + let status_async = locked_status.is_async; + drop(locked_status); + + if status_async { + complete_async_packet(&status); } self.data_ready_sent = true; @@ -982,10 +989,7 @@ impl UsbUas { }; self.data_ready_sent = false; - - if !self.streams_enabled() { - self.try_start_next_transfer(0); - } + self.try_start_next_transfer(stream); match result { Ok(result) => result, @@ -1099,7 +1103,7 @@ impl UsbDevice for UsbUas { trace::usb_uas_handle_data(self.device_id(), ep_number, stream); drop(locked_packet); - if self.streams_enabled() && stream > UAS_MAX_STREAMS { + if self.streams_enabled() && (stream > UAS_MAX_STREAMS || stream == 0) { warn!("UAS {} device invalid stream {}.", self.device_id(), stream); packet.lock().unwrap().status = UsbPacketStatus::Stall; return; @@ -1218,22 +1222,23 @@ impl UasRequest { } fn complete(&mut self) { - let locked_status = self.status.lock().unwrap(); + let status = &self.status; + let status_async = status.lock().unwrap().is_async; // NOTE: Due to the specifics of this device, it waits for all of the required USB packets // to arrive before starting an actual transfer. Therefore, some packets may arrive earlier // than others, and they won't be completed right away (except for command packets) but // rather queued asynchronously. A certain packet may also be async if it was the last to // arrive and UasRequest didn't complete right away. - if locked_status.is_async { - complete_async_packet(locked_status); + if status_async { + complete_async_packet(status); } if let Some(data) = &self.data { - let locked_data = data.lock().unwrap(); + let data_async = data.lock().unwrap().is_async; - if locked_data.is_async { - complete_async_packet(locked_data); + if data_async { + complete_async_packet(data); } } diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index 3d90b9a2..ba2e1385 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -2035,9 +2035,11 @@ impl XhciDevice { if report != TRBCCode::Invalid { xfer.status = report; xfer.submit_transfer()?; + let locked_packet = xfer.packet.lock().unwrap(); - if let Some(usb_dev) = xfer.packet.lock().unwrap().target_dev.as_ref() { + if let Some(usb_dev) = locked_packet.target_dev.as_ref() { if let Some(usb_dev) = usb_dev.clone().upgrade() { + drop(locked_packet); let mut locked_usb_dev = usb_dev.lock().unwrap(); locked_usb_dev.cancel_packet(&xfer.packet); } -- Gitee From 013e63e8916890b7e141adb54f0db9188d8f6daa Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sun, 28 Apr 2024 09:18:09 +0800 Subject: [PATCH 010/489] virtio-fs: don't trigger irq of the virtio-fs device in test hypervisor Commit 4f0623f96f(Config: Support test as a hypervisor type) introduce test hypervisor and it doesn't support irqfd. As a result, virtio-fs device cannot be created successfully in MST. The virtio-fs device needs to determine whether to use irqfd based on the kernel support. Fix: 4f0623f96f(Config: Support test as a hypervisor type) part cherry-pick from 074e684648a34f9b88a7785300acc1abcec97bfa ([Huawei]vhost-user-fs: Fix the bug of triggering irq of the vhost-user-fs device) Signed-off-by: Jinhao Gao Signed-off-by: liuxiangdong --- devices/src/interrupt_controller/mod.rs | 2 ++ hypervisor/src/kvm/mod.rs | 4 ++++ hypervisor/src/test/mod.rs | 4 ++++ machine/src/lib.rs | 5 ++++- 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/devices/src/interrupt_controller/mod.rs b/devices/src/interrupt_controller/mod.rs index 4a0453c8..a1fb65d2 100644 --- a/devices/src/interrupt_controller/mod.rs +++ b/devices/src/interrupt_controller/mod.rs @@ -81,6 +81,8 @@ pub trait LineIrqManager: Send + Sync { } pub trait MsiIrqManager: Send + Sync { + fn irqfd_enable(&self) -> bool; + fn allocate_irq(&self, _vector: MsiVector) -> Result { Ok(0) } diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs index 8648b9c2..3e03a2a9 100644 --- a/hypervisor/src/kvm/mod.rs +++ b/hypervisor/src/kvm/mod.rs @@ -816,6 +816,10 @@ impl LineIrqManager for KVMInterruptManager { } impl MsiIrqManager for KVMInterruptManager { + fn irqfd_enable(&self) -> bool { + self.irqfd_cap + } + fn allocate_irq(&self, vector: MsiVector) -> Result { let mut locked_irq_route_table = self.irq_route_table.lock().unwrap(); let gsi = locked_irq_route_table.allocate_gsi().map_err(|e| { diff --git a/hypervisor/src/test/mod.rs b/hypervisor/src/test/mod.rs index 8fce37ee..8e4697ae 100644 --- a/hypervisor/src/test/mod.rs +++ b/hypervisor/src/test/mod.rs @@ -368,6 +368,10 @@ impl LineIrqManager for TestInterruptManager { } impl MsiIrqManager for TestInterruptManager { + fn irqfd_enable(&self) -> bool { + false + } + fn allocate_irq(&self, _vector: MsiVector) -> Result { Err(anyhow!( "Failed to allocate irq, mst doesn't support irq routing feature." diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 895551ee..fd21da8b 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -869,7 +869,10 @@ pub trait MachineOps { let device = Arc::new(Mutex::new(vhost::user::Fs::new(dev_cfg, sys_mem))); let bdf = get_pci_bdf(cfg_args)?; let multi_func = get_multi_function(cfg_args)?; - self.add_virtio_pci_device(&id_clone, &bdf, device, multi_func, true) + let root_bus = self.get_pci_host()?.lock().unwrap().root_bus.clone(); + let msi_irq_manager = &root_bus.lock().unwrap().msi_irq_manager; + let need_irqfd = msi_irq_manager.as_ref().unwrap().irqfd_enable(); + self.add_virtio_pci_device(&id_clone, &bdf, device, multi_func, need_irqfd) .with_context(|| "Failed to add pci fs device")?; } } -- Gitee From a1376d19f0746f5f2ae4456a4214ada7d86cb729 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sun, 28 Apr 2024 12:18:51 +0800 Subject: [PATCH 011/489] virtio-fs: use clone instead of reference to avoid deadlock `root_bus` will be locked for using its reference and then deadlock will occur in `add_virtio_pci_device`->`get_devfn_and_parent_bus`. (gdb) bt #0 syscall () at ../sysdeps/unix/sysv/linux/aarch64/syscall.S:38 #1 0x0000aaaabb7588f4 in std::sys::unix::futex::futex_wait () at library/std/src/sys/unix/futex.rs:62 #2 0x0000aaaababc3d44 in std::sys::unix::locks::futex_mutex::Mutex::lock_contended () at library/std/src/sys/unix/locks/futex_mutex.rs:61 #3 0x0000aaaabb048420 in std::sys::unix::locks::futex_mutex::Mutex::lock (self=0xaaaac1825080) at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/sys/unix/locks/futex_mutex.rs:33 #4 0x0000aaaabaf9b910 in std::sys_common::mutex::MovableMutex::raw_lock (self=0xaaaac1825080) at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/sys_common/mutex.rs:75 #5 0x0000aaaabaf1c9a8 in std::sync::mutex::Mutexdevices::pci::bus::PciBus::lockdevices::pci::bus::PciBus (self=0xaaaac1825080) at /rustc/a55dd71d5fb0ec5a6a3a9e8c27b2127ba491ce52/library/std/src/sync/mutex.rs:266 #6 0x0000aaaabaed0c90 in devices::pci::bus::PciBus::find_bus_by_name (bus=0xffffe9972688, bus_name=...) at devices/src/pci/bus.rs:147 #7 0x0000aaaabac13dd8 in machine::MachineOps::get_devfn_and_parent_busmachine::aarch64::standard::StdMachine (self=0xaaaac1828fe8, bdf=0xffffe9973670) at machine/src/lib.rs:1357 #8 0x0000aaaabac14494 in machine::MachineOps::add_virtio_pci_devicemachine::aarch64::standard::StdMachine (self=0xaaaac1828fe8, id=..., bdf=0xffffe9973670, device=..., multi_func=false, need_irqfd=false) at machine/src/lib.rs:1396 #9 0x0000aaaabac0fa58 in machine::MachineOps::add_virtio_fsmachine::aarch64::standard::StdMachine (self=0xaaaac1828fe8, vm_config=0xffffe9977658, cfg_args=...) at machine/src/lib.rs:875 #10 0x0000aaaabac184a4 in machine::MachineOps::add_devicesmachine::aarch64::standard::StdMachine (self=0xaaaac1828fe8, vm_config=0xffffe9977658) at machine/src/lib.rs:1787 #11 0x0000aaaababf4618 in machine::aarch64::standard::{impl#2}::realize (vm=0xffffe9975bf0, vm_config=0xffffe9977658) at machine/src/aarch64/standard.rs:631 #12 0x0000aaaababdff80 in stratovirt::real_main (cmd_args=0xffffe9977430, vm_config=0xffffe9977658) at src/main.rs:174 #13 0x0000aaaababdf4a4 in stratovirt::run () at src/main.rs:107 #14 0x0000aaaababdeefc in stratovirt::main () at src/main.rs:62 Fix: 6079887d8c4b(virtio-fs: don't trigger irq of the virtio-fs device in test hypervisor) Signed-off-by: liuxiangdong --- machine/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/machine/src/lib.rs b/machine/src/lib.rs index fd21da8b..7b4b7a01 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -870,7 +870,7 @@ pub trait MachineOps { let bdf = get_pci_bdf(cfg_args)?; let multi_func = get_multi_function(cfg_args)?; let root_bus = self.get_pci_host()?.lock().unwrap().root_bus.clone(); - let msi_irq_manager = &root_bus.lock().unwrap().msi_irq_manager; + let msi_irq_manager = root_bus.lock().unwrap().msi_irq_manager.clone(); let need_irqfd = msi_irq_manager.as_ref().unwrap().irqfd_enable(); self.add_virtio_pci_device(&id_clone, &bdf, device, multi_func, need_irqfd) .with_context(|| "Failed to add pci fs device")?; -- Gitee From b2c9ff950aeb3490e478fe05d27ae437c97c3507 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 22 Feb 2024 23:37:42 +0800 Subject: [PATCH 012/489] machine: report device type when adding device failed Report device type when adding device failed. Signed-off-by: liuxiangdong --- machine/src/lib.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 7b4b7a01..587dbc06 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -283,13 +283,13 @@ macro_rules! create_device_add_matches { match $command { $( $($driver_name)|+ => { - $controller.$function_name($($arg),*)?; + $controller.$function_name($($arg),*).with_context(|| format!("add {} fail.", $command))?; }, )* $( #[cfg($($features)*)] $driver_name1 => { - $controller.$function_name1($($arg1),*)?; + $controller.$function_name1($($arg1),*).with_context(|| format!("add {} fail.", $command))?; }, )* _ => bail!("Unsupported device: {:?}", $command), -- Gitee From 5192b569a81b3afca83ba50e05d7653b592b7830 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 22 Feb 2024 23:44:57 +0800 Subject: [PATCH 013/489] machine_manager: refactor str_slip_to_clap to support different types of first parameters The first parameter will be parsed as the `binary name` unless Command::no_binary_name is used when using `clap`. Stratovirt command line may use the first parameter as class type. Eg: 1. drive config: "-drive file=,if=pflash,unit=0" This cmdline has no class type. 2. device config: "-device virtio-balloon-pci,id=,bus=,addr=<0x4>" This cmdline sets device type `virtio-balloon-pci` as the first parameter. Use first_pos_is_type to indicate whether the first parameter is a type class which needs a separate analysis. Eg: 1. drive config: "-drive file=,if=pflash,unit=0" Set first_pos_is_type false for this cmdline has no class type. 2. device config: "-device virtio-balloon-pci,id=,bus=,addr=<0x4>" Set first_pos_is_type true for this cmdline has device type "virtio-balloon-pci" as the first parameter. Use first_pos_is_subcommand to indicate whether the first parameter is a subclass. Eg: Chardev has stdio/unix-socket/tcp-socket/pty/file classes. These classes have different configurations but will be stored in the same `ChardevConfig` structure by using `enum`. So, we will use class type as a subcommand to indicate which subtype will be used to store the configuration in enumeration type. Subcommand in `clap` doesn't need `--` in parameter. 1. -serial file,path= `file` is subcommand for socket. Set first_pos_is_subcommand true for first parameter `file` is the subclass type for chardev. Allow single parameter. Eg: -serial socket,path=,server,nowait `server` and `nowait` are single parameters. Signed-off-by: liuxiangdong --- devices/src/misc/scream/mod.rs | 4 +- devices/src/usb/camera.rs | 4 +- devices/src/usb/keyboard.rs | 4 +- devices/src/usb/tablet.rs | 4 +- devices/src/usb/usbhost/mod.rs | 4 +- devices/src/usb/xhci/xhci_pci.rs | 4 +- machine/src/lib.rs | 20 ++++++---- machine_manager/src/config/camera.rs | 7 +++- machine_manager/src/config/mod.rs | 58 ++++++++++++++++++++++++---- virtio/src/device/balloon.rs | 4 +- 10 files changed, 88 insertions(+), 25 deletions(-) diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index 13659f4b..ed089011 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -402,8 +402,10 @@ impl FromStr for ScreamInterface { } #[derive(Parser, Debug, Clone)] -#[command(name = "ivshmem_scream")] +#[command(no_binary_name(true))] pub struct ScreamConfig { + #[arg(long)] + pub classtype: String, #[arg(long, value_parser = valid_id)] id: String, #[arg(long)] diff --git a/devices/src/usb/camera.rs b/devices/src/usb/camera.rs index cedf8cdc..f687d455 100644 --- a/devices/src/usb/camera.rs +++ b/devices/src/usb/camera.rs @@ -90,8 +90,10 @@ const FRAME_SIZE_1280_720: u32 = 1280 * 720 * 2; const USB_CAMERA_BUFFER_LEN: usize = 12 * 1024; #[derive(Parser, Debug, Clone)] -#[command(name = "usb_camera")] +#[command(no_binary_name(true))] pub struct UsbCameraConfig { + #[arg(long)] + pub classtype: String, #[arg(long, value_parser = valid_id)] pub id: String, #[arg(long)] diff --git a/devices/src/usb/keyboard.rs b/devices/src/usb/keyboard.rs index 9ad3865d..71685603 100644 --- a/devices/src/usb/keyboard.rs +++ b/devices/src/usb/keyboard.rs @@ -121,8 +121,10 @@ const DESC_STRINGS: [&str; 5] = [ ]; #[derive(Parser, Clone, Debug, Default)] -#[command(name = "usb_keyboard")] +#[command(no_binary_name(true))] pub struct UsbKeyboardConfig { + #[arg(long)] + pub classtype: String, #[arg(long, value_parser = valid_id)] id: String, #[arg(long)] diff --git a/devices/src/usb/tablet.rs b/devices/src/usb/tablet.rs index af3ab297..fffb4df4 100644 --- a/devices/src/usb/tablet.rs +++ b/devices/src/usb/tablet.rs @@ -114,8 +114,10 @@ const STR_SERIAL_TABLET_INDEX: u8 = 4; const DESC_STRINGS: [&str; 5] = ["", "StratoVirt", "StratoVirt USB Tablet", "HID Tablet", "2"]; #[derive(Parser, Clone, Debug, Default)] -#[command(name = "usb_tablet")] +#[command(no_binary_name(true))] pub struct UsbTabletConfig { + #[arg(long)] + pub classtype: String, #[arg(long, value_parser = valid_id)] id: String, #[arg(long)] diff --git a/devices/src/usb/usbhost/mod.rs b/devices/src/usb/usbhost/mod.rs index 5abdb292..40d7c8af 100644 --- a/devices/src/usb/usbhost/mod.rs +++ b/devices/src/usb/usbhost/mod.rs @@ -357,8 +357,10 @@ impl IsoQueue { } #[derive(Parser, Clone, Debug, Default)] -#[command(name = "usb_host")] +#[command(no_binary_name(true))] pub struct UsbHostConfig { + #[arg(long)] + pub classtype: String, #[arg(long, value_parser = valid_id)] id: String, #[arg(long, default_value = "0")] diff --git a/devices/src/usb/xhci/xhci_pci.rs b/devices/src/usb/xhci/xhci_pci.rs index 0b3373cd..09c24f46 100644 --- a/devices/src/usb/xhci/xhci_pci.rs +++ b/devices/src/usb/xhci/xhci_pci.rs @@ -67,8 +67,10 @@ const XHCI_MSIX_PBA_OFFSET: u32 = 0x3800; /// XHCI controller configuration. #[derive(Parser, Clone, Debug, Default)] -#[command(name = "nec-usb-xhci")] +#[command(no_binary_name(true))] pub struct XhciConfig { + #[arg(long)] + pub classtype: String, #[arg(long, value_parser = valid_id)] id: Option, #[arg(long)] diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 587dbc06..249a3f5f 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -666,13 +666,13 @@ pub trait MachineOps { if vm_config.dev_name.get("balloon").is_some() { bail!("Only one balloon device is supported for each vm."); } - let config = BalloonConfig::try_parse_from(str_slip_to_clap(cfg_args))?; + let config = BalloonConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; vm_config.dev_name.insert("balloon".to_string(), 1); let sys_mem = self.get_sys_mem(); let balloon = Arc::new(Mutex::new(Balloon::new(config.clone(), sys_mem.clone()))); Balloon::object_init(balloon.clone()); - match parse_device_type(cfg_args)?.as_str() { + match config.classtype.as_str() { "virtio-balloon-device" => { if config.addr.is_some() || config.bus.is_some() || config.multifunction.is_some() { bail!("virtio balloon device config is error!"); @@ -1545,7 +1545,7 @@ pub trait MachineOps { /// /// * `cfg_args` - XHCI Configuration. fn add_usb_xhci(&mut self, cfg_args: &str) -> Result<()> { - let device_cfg = XhciConfig::try_parse_from(str_slip_to_clap(cfg_args))?; + let device_cfg = XhciConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; let bdf = PciBdf::new(device_cfg.bus.clone(), device_cfg.addr); let (devfn, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?; @@ -1569,7 +1569,7 @@ pub trait MachineOps { cfg_args: &str, token_id: Option>>, ) -> Result<()> { - let config = ScreamConfig::try_parse_from(str_slip_to_clap(cfg_args))?; + let config = ScreamConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; let bdf = PciBdf { bus: config.bus.clone(), addr: config.addr, @@ -1692,14 +1692,16 @@ pub trait MachineOps { fn add_usb_device(&mut self, vm_config: &mut VmConfig, cfg_args: &str) -> Result<()> { let usb_device = match parse_device_type(cfg_args)?.as_str() { "usb-kbd" => { - let config = UsbKeyboardConfig::try_parse_from(str_slip_to_clap(cfg_args))?; + let config = + UsbKeyboardConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; let keyboard = UsbKeyboard::new(config); keyboard .realize() .with_context(|| "Failed to realize usb keyboard device")? } "usb-tablet" => { - let config = UsbTabletConfig::try_parse_from(str_slip_to_clap(cfg_args))?; + let config = + UsbTabletConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; let tablet = UsbTablet::new(config); tablet .realize() @@ -1707,7 +1709,8 @@ pub trait MachineOps { } #[cfg(feature = "usb_camera")] "usb-camera" => { - let config = UsbCameraConfig::try_parse_from(str_slip_to_clap(cfg_args))?; + let config = + UsbCameraConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; let cameradev = get_cameradev_by_id(vm_config, config.cameradev.clone()) .with_context(|| { format!( @@ -1736,7 +1739,8 @@ pub trait MachineOps { } #[cfg(feature = "usb_host")] "usb-host" => { - let config = UsbHostConfig::try_parse_from(str_slip_to_clap(cfg_args))?; + let config = + UsbHostConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; let usbhost = UsbHost::new(config)?; usbhost .realize() diff --git a/machine_manager/src/config/camera.rs b/machine_manager/src/config/camera.rs index a5ed0702..43af312c 100644 --- a/machine_manager/src/config/camera.rs +++ b/machine_manager/src/config/camera.rs @@ -22,8 +22,10 @@ use crate::{ }; #[derive(Parser, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -#[command(name = "camera device")] +#[command(no_binary_name(true))] pub struct CameraDevConfig { + #[arg(long)] + pub classtype: String, #[arg(long, value_parser = valid_id)] pub id: String, #[arg(long)] @@ -59,7 +61,7 @@ impl FromStr for CamBackendType { impl VmConfig { pub fn add_camera_backend(&mut self, camera_config: &str) -> Result<()> { let cfg = format!("cameradev,backend={}", camera_config); - let config = CameraDevConfig::try_parse_from(str_slip_to_clap(&cfg))?; + let config = CameraDevConfig::try_parse_from(str_slip_to_clap(&cfg, true, false))?; self.add_cameradev_with_config(config) } @@ -103,6 +105,7 @@ impl VmConfig { pub fn get_cameradev_config(args: qmp_schema::CameraDevAddArgument) -> Result { let path = args.path.with_context(|| "cameradev config path is null")?; let config = CameraDevConfig { + classtype: "cameradev".to_string(), id: args.id, path, backend: CamBackendType::from_str(&args.driver)?, diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index 8b2944d8..985c1b78 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -737,14 +737,56 @@ pub fn check_arg_nonexist(arg: Option, name: &str, device: &str) -> Resu } /// Configure StratoVirt parameters in clap format. -pub fn str_slip_to_clap(args: &str) -> Vec { - let args_vecs = args.split([',', '=']).collect::>(); - let mut itr: Vec = Vec::with_capacity(args_vecs.len()); - for (cnt, param) in args_vecs.iter().enumerate() { - if cnt % 2 == 1 { - itr.push(format!("--{}", param)); - } else { - itr.push(param.to_string()); +/// +/// The first parameter will be parsed as the `binary name` unless Command::no_binary_name is used when using `clap`. +/// Stratovirt command line may use the first parameter as class type. +/// Eg: +/// 1. drive config: "-drive file=,if=pflash,unit=0" +/// This cmdline has no class type. +/// 2. device config: "-device virtio-balloon-pci,id=,bus=,addr=<0x4>" +/// This cmdline sets device type `virtio-balloon-pci` as the first parameter. +/// +/// Use first_pos_is_type to indicate whether the first parameter is a type class which needs a separate analysis. +/// Eg: +/// 1. drive config: "-drive file=,if=pflash,unit=0" +/// Set first_pos_is_type false for this cmdline has no class type. +/// 2. device config: "-device virtio-balloon-pci,id=,bus=,addr=<0x4>" +/// Set first_pos_is_type true for this cmdline has device type "virtio-balloon-pci" as the first parameter. +/// +/// Use first_pos_is_subcommand to indicate whether the first parameter is a subclass. +/// Eg: +/// Chardev has stdio/unix-socket/tcp-socket/pty/file classes. These classes have different configurations but will be stored +/// in the same `ChardevConfig` structure by using `enum`. So, we will use class type as a subcommand to indicate which subtype +/// will be used to store the configuration in enumeration type. Subcommand in `clap` doesn't need `--` in parameter. +/// 1. -serial file,path= +/// Set first_pos_is_subcommand true for first parameter `file` is the subclass type for chardev. +pub fn str_slip_to_clap( + args: &str, + first_pos_is_type: bool, + mut first_pos_is_subcommand: bool, +) -> Vec { + let args_str = if first_pos_is_type && !first_pos_is_subcommand { + format!("classtype={}", args) + } else { + args.to_string() + }; + let args_vecs = args_str.split([',']).collect::>(); + let mut itr: Vec = Vec::with_capacity(args_vecs.len() * 2); + for params in args_vecs { + let key_value = params.split(['=']).collect::>(); + // Command line like "key=value" will be converted to "--key value". + // Command line like "key" will be converted to "--key". + for (cnt, param) in key_value.iter().enumerate() { + if cnt % 2 == 0 { + if first_pos_is_subcommand { + itr.push(param.to_string()); + first_pos_is_subcommand = false; + } else { + itr.push(format!("--{}", param)); + } + } else { + itr.push(param.to_string()); + } } } itr diff --git a/virtio/src/device/balloon.rs b/virtio/src/device/balloon.rs index fd6347a2..6e6095f9 100644 --- a/virtio/src/device/balloon.rs +++ b/virtio/src/device/balloon.rs @@ -882,8 +882,10 @@ impl EventNotifierHelper for BalloonIoHandler { } #[derive(Parser, Debug, Clone, Default)] -#[command(name = "balloon")] +#[command(no_binary_name(true))] pub struct BalloonConfig { + #[arg(long)] + pub classtype: String, #[arg(long, value_parser = valid_id)] pub id: String, #[arg(long)] -- Gitee From ae17a0e1b5cb65122f6e4ccd3dafd637ad99db95 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 22 Feb 2024 23:50:26 +0800 Subject: [PATCH 014/489] drive: use clap to parse the parameters of the drive config Use clap to parse the parameters of the drive config, including pflash drive and block drive. Signed-off-by: liuxiangdong --- machine/src/aarch64/standard.rs | 8 +- machine/src/lib.rs | 6 +- machine/src/standard_common/mod.rs | 15 +- machine/src/x86_64/standard.rs | 10 +- machine_manager/src/config/drive.rs | 533 +++++++++++++--------------- machine_manager/src/config/mod.rs | 10 +- machine_manager/src/config/scsi.rs | 2 +- machine_manager/src/config/usb.rs | 2 +- util/src/aio/mod.rs | 7 +- 9 files changed, 272 insertions(+), 321 deletions(-) diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index 8d38c444..56a3a3a2 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -61,7 +61,7 @@ use machine_manager::config::ShutdownAction; #[cfg(feature = "gtk")] use machine_manager::config::UiContext; use machine_manager::config::{ - parse_incoming_uri, BootIndexInfo, MigrateMode, NumaNode, PFlashConfig, SerialConfig, VmConfig, + parse_incoming_uri, BootIndexInfo, DriveConfig, MigrateMode, NumaNode, SerialConfig, VmConfig, }; use machine_manager::event; use machine_manager::machine::{ @@ -685,16 +685,16 @@ impl MachineOps for StdMachine { Ok(()) } - fn add_pflash_device(&mut self, configs: &[PFlashConfig]) -> Result<()> { + fn add_pflash_device(&mut self, configs: &[DriveConfig]) -> Result<()> { let mut configs_vec = configs.to_vec(); - configs_vec.sort_by_key(|c| c.unit); + configs_vec.sort_by_key(|c| c.unit.unwrap()); let sector_len: u32 = 1024 * 256; let mut flash_base: u64 = MEM_LAYOUT[LayoutEntryType::Flash as usize].0; let flash_size: u64 = MEM_LAYOUT[LayoutEntryType::Flash as usize].1 / 2; for i in 0..=1 { let (fd, read_only) = if i < configs_vec.len() { let path = &configs_vec[i].path_on_host; - let read_only = configs_vec[i].read_only; + let read_only = configs_vec[i].readonly; let fd = self.fetch_drive_file(path)?; (Some(fd), read_only) } else { diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 249a3f5f..fb0256d2 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -83,8 +83,8 @@ use machine_manager::config::{ parse_device_type, parse_fs, parse_net, parse_numa_distance, parse_numa_mem, parse_rng_dev, parse_root_port, parse_scsi_controller, parse_scsi_device, parse_vfio, parse_vhost_user_blk, parse_virtio_serial, parse_virtserialport, parse_vsock, str_slip_to_clap, BootIndexInfo, - BootSource, DriveFile, Incoming, MachineMemConfig, MigrateMode, NumaConfig, NumaDistance, - NumaNode, NumaNodes, PFlashConfig, PciBdf, SerialConfig, VfioConfig, VmConfig, FAST_UNPLUG_ON, + BootSource, DriveConfig, DriveFile, Incoming, MachineMemConfig, MigrateMode, NumaConfig, + NumaDistance, NumaNode, NumaNodes, PciBdf, SerialConfig, VfioConfig, VmConfig, FAST_UNPLUG_ON, MAX_VIRTIO_QUEUE, }; use machine_manager::event_loop::EventLoop; @@ -1828,7 +1828,7 @@ pub trait MachineOps { None } - fn add_pflash_device(&mut self, _configs: &[PFlashConfig]) -> Result<()> { + fn add_pflash_device(&mut self, _configs: &[DriveConfig]) -> Result<()> { bail!("Pflash device is not supported!"); } diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index 1ab0be07..67ab3e22 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -1272,7 +1272,7 @@ impl DeviceInterface for StdMachine { if let Err(e) = self.register_drive_file( &config.id, &args.file.filename, - config.read_only, + config.readonly, config.direct, ) { error!("{:?}", e); @@ -1672,12 +1672,7 @@ impl DeviceInterface for StdMachine { None, ); } - let drive_cfg = match self - .get_vm_config() - .lock() - .unwrap() - .add_block_drive(cmd_args[2]) - { + let drive_cfg = match self.get_vm_config().lock().unwrap().add_drive(cmd_args[2]) { Ok(cfg) => cfg, Err(ref e) => { return Response::create_error_response( @@ -1689,7 +1684,7 @@ impl DeviceInterface for StdMachine { if let Err(e) = self.register_drive_file( &drive_cfg.id, &drive_cfg.path_on_host, - drive_cfg.read_only, + drive_cfg.readonly, drive_cfg.direct, ) { error!("{:?}", e); @@ -1915,8 +1910,10 @@ impl DeviceInterface for StdMachine { fn parse_blockdev(args: &BlockDevAddArgument) -> Result { let mut config = DriveConfig { id: args.node_name.clone(), + drive_type: "none".to_string(), + unit: None, path_on_host: args.file.filename.clone(), - read_only: args.read_only.unwrap_or(false), + readonly: args.read_only.unwrap_or(false), direct: true, iops: args.iops, aio: args.file.aio, diff --git a/machine/src/x86_64/standard.rs b/machine/src/x86_64/standard.rs index 6499151b..fdb88d1e 100644 --- a/machine/src/x86_64/standard.rs +++ b/machine/src/x86_64/standard.rs @@ -45,7 +45,7 @@ use hypervisor::kvm::*; #[cfg(feature = "gtk")] use machine_manager::config::UiContext; use machine_manager::config::{ - parse_incoming_uri, BootIndexInfo, MigrateMode, NumaNode, PFlashConfig, SerialConfig, VmConfig, + parse_incoming_uri, BootIndexInfo, DriveConfig, MigrateMode, NumaNode, SerialConfig, VmConfig, }; use machine_manager::event; use machine_manager::machine::{ @@ -628,9 +628,9 @@ impl MachineOps for StdMachine { Ok(()) } - fn add_pflash_device(&mut self, configs: &[PFlashConfig]) -> Result<()> { + fn add_pflash_device(&mut self, configs: &[DriveConfig]) -> Result<()> { let mut configs_vec = configs.to_vec(); - configs_vec.sort_by_key(|c| c.unit); + configs_vec.sort_by_key(|c| c.unit.unwrap()); // The two PFlash devices locates below 4GB, this variable represents the end address // of current PFlash device. let mut flash_end: u64 = MEM_LAYOUT[LayoutEntryType::MemAbove4g as usize].0; @@ -638,7 +638,7 @@ impl MachineOps for StdMachine { let mut fd = self.fetch_drive_file(&config.path_on_host)?; let pfl_size = fd.metadata().unwrap().len(); - if config.unit == 0 { + if config.unit.unwrap() == 0 { // According to the Linux/x86 boot protocol, the memory region of // 0x000000 - 0x100000 (1 MiB) is for BIOS usage. And the top 128 // KiB is for BIOS code which is stored in the first PFlash. @@ -674,7 +674,7 @@ impl MachineOps for StdMachine { sector_len, 4_u32, 1_u32, - config.read_only, + config.readonly, ) .with_context(|| MachineError::InitPflashErr)?; PFlash::realize( diff --git a/machine_manager/src/config/drive.rs b/machine_manager/src/config/drive.rs index e88826a5..3e787c0c 100644 --- a/machine_manager/src/config/drive.rs +++ b/machine_manager/src/config/drive.rs @@ -16,13 +16,16 @@ use std::path::Path; use std::str::FromStr; use anyhow::{anyhow, bail, Context, Result}; +use clap::{ArgAction, Parser}; use log::error; use serde::{Deserialize, Serialize}; +use super::valid_id; use super::{error::ConfigError, pci_args_check, M}; use crate::config::{ - check_arg_too_long, get_chardev_socket_path, memory_unit_conversion, CmdParser, ConfigCheck, - ExBool, VmConfig, DEFAULT_VIRTQUEUE_SIZE, MAX_PATH_LENGTH, MAX_STRING_LENGTH, MAX_VIRTIO_QUEUE, + check_arg_too_long, get_chardev_socket_path, memory_unit_conversion, parse_bool, + str_slip_to_clap, CmdParser, ConfigCheck, VmConfig, DEFAULT_VIRTQUEUE_SIZE, MAX_PATH_LENGTH, + MAX_STRING_LENGTH, MAX_VIRTIO_QUEUE, }; use util::aio::{aio_probe, AioEngine, WriteZeroesState}; @@ -115,8 +118,9 @@ impl Default for BlkDevConfig { } } -#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] pub enum DiskFormat { + #[default] Raw, Qcow2, } @@ -142,44 +146,88 @@ impl ToString for DiskFormat { } } -/// Config struct for `drive`. -/// Contains block device's attr. -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] +fn parse_size(s: &str) -> Result { + let size = memory_unit_conversion(s, M).with_context(|| format!("Invalid size: {}", s))?; + Ok(size) +} + +fn valid_l2_cache_size(s: &str) -> Result { + let size = parse_size(s)?; + if size > MAX_L2_CACHE_SIZE { + return Err(anyhow!(ConfigError::IllegalValue( + "l2-cache-size".to_string(), + 0, + true, + MAX_L2_CACHE_SIZE, + true + ))); + } + Ok(size) +} + +fn valid_refcount_cache_size(s: &str) -> Result { + let size = parse_size(s)?; + if size > MAX_REFTABLE_CACHE_SIZE { + return Err(anyhow!(ConfigError::IllegalValue( + "refcount-cache-size".to_string(), + 0, + true, + MAX_REFTABLE_CACHE_SIZE, + true + ))); + } + Ok(size) +} + +fn valid_path(path: &str) -> Result { + if path.len() > MAX_PATH_LENGTH { + return Err(anyhow!(ConfigError::StringLengthTooLong( + "Drive device path".to_string(), + MAX_PATH_LENGTH, + ))); + } + Ok(path.to_string()) +} + +/// Config struct for `drive`, including `block drive` and `pflash drive`. +#[derive(Parser, Debug, Clone, Default, Serialize, Deserialize)] +#[command(no_binary_name(true))] pub struct DriveConfig { + #[arg(long, default_value = "")] pub id: String, + #[arg(long, alias = "if", default_value = "none", value_parser = ["none", "pflash"])] + pub drive_type: String, + #[arg(long, value_parser = clap::value_parser!(u8).range(..MAX_UNIT_ID as i64))] + pub unit: Option, + #[arg(long, alias = "file", value_parser = valid_path)] pub path_on_host: String, - pub read_only: bool, + #[arg(long, default_value = "off", value_parser = parse_bool, action = ArgAction::Append)] + pub readonly: bool, + #[arg(long, default_value = "true", value_parser = parse_bool, action = ArgAction::Append)] pub direct: bool, + #[arg(long, alias = "throttling.iops-total", value_parser = clap::value_parser!(u64).range(..=MAX_IOPS as u64))] pub iops: Option, + #[arg( + long, + default_value = "native", + default_value_if("direct", "false", "off"), + default_value_if("direct", "off", "off") + )] pub aio: AioEngine, + #[arg(long, default_value = "disk", value_parser = ["disk", "cdrom"])] pub media: String, + #[arg(long, default_value = "ignore", value_parser = parse_bool, action = ArgAction::Append)] pub discard: bool, + #[arg(long, alias = "detect-zeroes", default_value = "off")] pub write_zeroes: WriteZeroesState, + #[arg(long, default_value = "raw")] pub format: DiskFormat, + #[arg(long, value_parser = valid_l2_cache_size)] pub l2_cache_size: Option, + #[arg(long, value_parser = valid_refcount_cache_size)] pub refcount_cache_size: Option, } -impl Default for DriveConfig { - fn default() -> Self { - DriveConfig { - id: "".to_string(), - path_on_host: "".to_string(), - read_only: false, - direct: true, - iops: None, - aio: AioEngine::Native, - media: "disk".to_string(), - discard: false, - write_zeroes: WriteZeroesState::Off, - format: DiskFormat::Raw, - l2_cache_size: None, - refcount_cache_size: None, - } - } -} - impl DriveConfig { /// Check whether the drive file path on the host is valid. pub fn check_path(&self) -> Result<()> { @@ -222,63 +270,68 @@ impl DriveConfig { impl ConfigCheck for DriveConfig { fn check(&self) -> Result<()> { - check_arg_too_long(&self.id, "Drive id")?; + if self.drive_type == "pflash" { + self.unit.with_context(|| { + ConfigError::FieldIsMissing("unit".to_string(), "pflash".to_string()) + })?; + if self.format.to_string() != "raw" { + bail!("Only \'raw\' type of pflash is supported"); + } + } else { + if self.id.is_empty() { + return Err(anyhow!(ConfigError::FieldIsMissing( + "id".to_string(), + "blk".to_string() + ))); + } + valid_id(&self.id)?; + valid_path(&self.path_on_host)?; + if self.iops > Some(MAX_IOPS) { + return Err(anyhow!(ConfigError::IllegalValue( + "iops of block device".to_string(), + 0, + true, + MAX_IOPS, + true, + ))); + } + if self.l2_cache_size > Some(MAX_L2_CACHE_SIZE) { + return Err(anyhow!(ConfigError::IllegalValue( + "l2-cache-size".to_string(), + 0, + true, + MAX_L2_CACHE_SIZE, + true + ))); + } + if self.refcount_cache_size > Some(MAX_REFTABLE_CACHE_SIZE) { + return Err(anyhow!(ConfigError::IllegalValue( + "refcount-cache-size".to_string(), + 0, + true, + MAX_REFTABLE_CACHE_SIZE, + true + ))); + } - if self.path_on_host.len() > MAX_PATH_LENGTH { - return Err(anyhow!(ConfigError::StringLengthTooLong( - "Drive device path".to_string(), - MAX_PATH_LENGTH, - ))); - } - if self.iops > Some(MAX_IOPS) { - return Err(anyhow!(ConfigError::IllegalValue( - "iops of block device".to_string(), - 0, - true, - MAX_IOPS, - true, - ))); - } - if self.aio != AioEngine::Off { - if self.aio == AioEngine::Native && !self.direct { + if self.aio != AioEngine::Off { + if self.aio == AioEngine::Native && !self.direct { + return Err(anyhow!(ConfigError::InvalidParam( + "aio".to_string(), + "native aio type should be used with \"direct\" on".to_string(), + ))); + } + aio_probe(self.aio)?; + } else if self.direct { return Err(anyhow!(ConfigError::InvalidParam( "aio".to_string(), - "native aio type should be used with \"direct\" on".to_string(), + "low performance expected when use sync io with \"direct\" on".to_string(), ))); } - aio_probe(self.aio)?; - } else if self.direct { - return Err(anyhow!(ConfigError::InvalidParam( - "aio".to_string(), - "low performance expected when use sync io with \"direct\" on".to_string(), - ))); - } - - if !["disk", "cdrom"].contains(&self.media.as_str()) { - return Err(anyhow!(ConfigError::InvalidParam( - "media".to_string(), - "media should be \"disk\" or \"cdrom\"".to_string(), - ))); } - if self.l2_cache_size > Some(MAX_L2_CACHE_SIZE) { - return Err(anyhow!(ConfigError::IllegalValue( - "l2-cache-size".to_string(), - 0, - true, - MAX_L2_CACHE_SIZE, - true - ))); - } - if self.refcount_cache_size > Some(MAX_REFTABLE_CACHE_SIZE) { - return Err(anyhow!(ConfigError::IllegalValue( - "refcount-cache-size".to_string(), - 0, - true, - MAX_REFTABLE_CACHE_SIZE, - true - ))); - } + #[cfg(not(test))] + self.check_path()?; Ok(()) } @@ -326,10 +379,12 @@ impl ConfigCheck for BlkDevConfig { } let fake_drive = DriveConfig { + id: self.id.clone(), path_on_host: self.path_on_host.clone(), direct: self.direct, iops: self.iops, aio: self.aio, + media: "disk".to_string(), ..Default::default() }; fake_drive.check()?; @@ -342,60 +397,6 @@ impl ConfigCheck for BlkDevConfig { } } -fn parse_drive(cmd_parser: CmdParser) -> Result { - let mut drive = DriveConfig::default(); - if let Some(fmt) = cmd_parser.get_value::("format")? { - drive.format = fmt; - } - - drive.id = cmd_parser - .get_value::("id")? - .with_context(|| ConfigError::FieldIsMissing("id".to_string(), "blk".to_string()))?; - drive.path_on_host = cmd_parser - .get_value::("file")? - .with_context(|| ConfigError::FieldIsMissing("file".to_string(), "blk".to_string()))?; - - if let Some(read_only) = cmd_parser.get_value::("readonly")? { - drive.read_only = read_only.into(); - } - if let Some(direct) = cmd_parser.get_value::("direct")? { - drive.direct = direct.into(); - } - drive.iops = cmd_parser.get_value::("throttling.iops-total")?; - drive.aio = cmd_parser.get_value::("aio")?.unwrap_or({ - if drive.direct { - AioEngine::Native - } else { - AioEngine::Off - } - }); - drive.media = cmd_parser - .get_value::("media")? - .unwrap_or_else(|| "disk".to_string()); - if let Some(discard) = cmd_parser.get_value::("discard")? { - drive.discard = discard.into(); - } - drive.write_zeroes = cmd_parser - .get_value::("detect-zeroes")? - .unwrap_or(WriteZeroesState::Off); - - if let Some(l2_cache) = cmd_parser.get_value::("l2-cache-size")? { - let sz = memory_unit_conversion(&l2_cache, M) - .with_context(|| format!("Invalid l2 cache size: {}", l2_cache))?; - drive.l2_cache_size = Some(sz); - } - if let Some(rc_cache) = cmd_parser.get_value::("refcount-cache-size")? { - let sz = memory_unit_conversion(&rc_cache, M) - .with_context(|| format!("Invalid refcount cache size: {}", rc_cache))?; - drive.refcount_cache_size = Some(sz); - } - - drive.check()?; - #[cfg(not(test))] - drive.check_path()?; - Ok(drive) -} - pub fn parse_blk( vm_config: &mut VmConfig, drive_config: &str, @@ -455,7 +456,7 @@ pub fn parse_blk( .remove(&blkdrive) .with_context(|| "No drive configured matched for blk device")?; blkdevcfg.path_on_host = drive_arg.path_on_host.clone(); - blkdevcfg.read_only = drive_arg.read_only; + blkdevcfg.read_only = drive_arg.readonly; blkdevcfg.direct = drive_arg.direct; blkdevcfg.iops = drive_arg.iops; blkdevcfg.aio = drive_arg.aio; @@ -522,83 +523,23 @@ pub fn parse_vhost_user_blk( Ok(blkdevcfg) } -/// Config struct for `pflash`. -/// Contains pflash device's attr. -#[derive(Debug, Clone, Serialize, Deserialize, Default)] -#[serde(deny_unknown_fields)] -pub struct PFlashConfig { - pub path_on_host: String, - pub read_only: bool, - pub unit: usize, -} - -impl ConfigCheck for PFlashConfig { - fn check(&self) -> Result<()> { - if self.path_on_host.len() > MAX_PATH_LENGTH { - return Err(anyhow!(ConfigError::StringLengthTooLong( - "drive device path".to_string(), - MAX_PATH_LENGTH, - ))); - } - - if self.unit >= MAX_UNIT_ID { - return Err(anyhow!(ConfigError::UnitIdError( - "PFlash unit id".to_string(), - self.unit, - MAX_UNIT_ID - 1 - ))); - } - Ok(()) - } -} - impl VmConfig { - /// Add '-drive ...' drive config to `VmConfig`. - pub fn add_drive(&mut self, drive_config: &str) -> Result<()> { - let mut cmd_parser = CmdParser::new("drive"); - cmd_parser.push("if"); - - cmd_parser.get_parameters(drive_config)?; - let drive_type = cmd_parser - .get_value::("if")? - .unwrap_or_else(|| "none".to_string()); - match drive_type.as_str() { + /// Add '-drive ...' drive config to `VmConfig`, including `block drive` and `pflash drive`. + pub fn add_drive(&mut self, drive_config: &str) -> Result { + let drive_cfg = DriveConfig::try_parse_from(str_slip_to_clap(drive_config, false, false))?; + drive_cfg.check()?; + match drive_cfg.drive_type.as_str() { "none" => { - self.add_block_drive(drive_config)?; + self.add_drive_with_config(drive_cfg.clone())?; } "pflash" => { - self.add_pflash(drive_config)?; + self.add_flashdev(drive_cfg.clone())?; } _ => { - bail!("Unknow 'if' argument: {:?}", drive_type.as_str()); + bail!("Unknow 'if' argument: {:?}", &drive_cfg.drive_type); } } - Ok(()) - } - - /// Add block drive config to vm and return the added drive config. - pub fn add_block_drive(&mut self, block_config: &str) -> Result { - let mut cmd_parser = CmdParser::new("drive"); - cmd_parser - .push("file") - .push("id") - .push("readonly") - .push("direct") - .push("format") - .push("if") - .push("throttling.iops-total") - .push("aio") - .push("media") - .push("discard") - .push("detect-zeroes") - .push("format") - .push("l2-cache-size") - .push("refcount-cache-size"); - - cmd_parser.parse(block_config)?; - let drive_cfg = parse_drive(cmd_parser)?; - self.add_drive_with_config(drive_cfg.clone())?; Ok(drive_cfg) } @@ -609,11 +550,10 @@ impl VmConfig { /// * `drive_conf` - The drive config to be added to the vm. pub fn add_drive_with_config(&mut self, drive_conf: DriveConfig) -> Result<()> { let drive_id = drive_conf.id.clone(); - if self.drives.get(&drive_id).is_none() { - self.drives.insert(drive_id, drive_conf); - } else { + if self.drives.get(&drive_id).is_some() { bail!("Drive {} has been added", drive_id); } + self.drives.insert(drive_id, drive_conf); Ok(()) } @@ -631,13 +571,13 @@ impl VmConfig { } /// Add new flash device to `VmConfig`. - fn add_flashdev(&mut self, pflash: PFlashConfig) -> Result<()> { + fn add_flashdev(&mut self, pflash: DriveConfig) -> Result<()> { if self.pflashs.is_some() { for pf in self.pflashs.as_ref().unwrap() { - if pf.unit == pflash.unit { + if pf.unit.unwrap() == pflash.unit.unwrap() { return Err(anyhow!(ConfigError::IdRepeat( "pflash".to_string(), - pf.unit.to_string() + pf.unit.unwrap().to_string() ))); } } @@ -647,41 +587,6 @@ impl VmConfig { } Ok(()) } - - /// Add '-pflash ...' pflash config to `VmConfig`. - pub fn add_pflash(&mut self, pflash_config: &str) -> Result<()> { - let mut cmd_parser = CmdParser::new("pflash"); - cmd_parser - .push("if") - .push("file") - .push("format") - .push("readonly") - .push("unit"); - - cmd_parser.parse(pflash_config)?; - - let mut pflash = PFlashConfig::default(); - - if let Some(format) = cmd_parser.get_value::("format")? { - if format.ne("raw") { - bail!("Only \'raw\' type of pflash is supported"); - } - } - pflash.path_on_host = cmd_parser.get_value::("file")?.with_context(|| { - ConfigError::FieldIsMissing("file".to_string(), "pflash".to_string()) - })?; - - if let Some(read_only) = cmd_parser.get_value::("readonly")? { - pflash.read_only = read_only.into(); - } - - pflash.unit = cmd_parser.get_value::("unit")?.with_context(|| { - ConfigError::FieldIsMissing("unit".to_string(), "pflash".to_string()) - })? as usize; - - pflash.check()?; - self.add_flashdev(pflash) - } } #[cfg(test)] @@ -760,34 +665,31 @@ mod tests { } #[test] - fn test_pflash_config_cmdline_parser() { + fn test_pflash_drive_config_cmdline_parser() { + // Test1: Right. let mut vm_config = VmConfig::default(); assert!(vm_config - .add_drive("if=pflash,readonly=on,file=flash0.fd,unit=0") + .add_drive("if=pflash,readonly=on,file=flash0.fd,unit=0,format=raw") .is_ok()); assert!(vm_config.pflashs.is_some()); let pflash = vm_config.pflashs.unwrap(); assert!(pflash.len() == 1); let pflash_cfg = &pflash[0]; - assert_eq!(pflash_cfg.unit, 0); + assert_eq!(pflash_cfg.unit.unwrap(), 0); assert_eq!(pflash_cfg.path_on_host, "flash0.fd".to_string()); - assert_eq!(pflash_cfg.read_only, true); + assert_eq!(pflash_cfg.readonly, true); + // Test2: Change parameters sequence. let mut vm_config = VmConfig::default(); assert!(vm_config .add_drive("readonly=on,file=flash0.fd,unit=0,if=pflash") .is_ok()); - let mut vm_config = VmConfig::default(); assert!(vm_config .add_drive("readonly=on,if=pflash,file=flash0.fd,unit=0") .is_ok()); - let mut vm_config = VmConfig::default(); - assert!(vm_config - .add_drive("if=pflash,readonly=on,file=flash0.fd,unit=2") - .is_err()); - + // Test3: Add duplicate pflash. let mut vm_config = VmConfig::default(); assert!(vm_config .add_drive("if=pflash,readonly=on,file=flash0.fd,unit=0") @@ -795,52 +697,103 @@ mod tests { assert!(vm_config .add_drive("if=pflash,file=flash1.fd,unit=1") .is_ok()); + assert!(vm_config + .add_drive("if=pflash,file=flash1.fd,unit=1") + .is_err()); assert!(vm_config.pflashs.is_some()); let pflash = vm_config.pflashs.unwrap(); assert!(pflash.len() == 2); let pflash_cfg = &pflash[0]; - assert_eq!(pflash_cfg.unit, 0); + assert_eq!(pflash_cfg.unit.unwrap(), 0); assert_eq!(pflash_cfg.path_on_host, "flash0.fd".to_string()); - assert_eq!(pflash_cfg.read_only, true); + assert_eq!(pflash_cfg.readonly, true); let pflash_cfg = &pflash[1]; - assert_eq!(pflash_cfg.unit, 1); + assert_eq!(pflash_cfg.unit.unwrap(), 1); assert_eq!(pflash_cfg.path_on_host, "flash1.fd".to_string()); - assert_eq!(pflash_cfg.read_only, false); - } + assert_eq!(pflash_cfg.readonly, false); - #[test] - fn test_drive_config_check() { - let mut drive_conf = DriveConfig::default(); - for _ in 0..MAX_STRING_LENGTH { - drive_conf.id += "A"; - } - assert!(drive_conf.check().is_ok()); + // Test4: Illegal parameters unit/format. + let mut vm_config = VmConfig::default(); + assert!(vm_config + .add_drive("if=pflash,readonly=on,file=flash0.fd,unit=2") + .is_err()); + assert!(vm_config + .add_drive("if=pflash,readonly=on,file=flash0.fd,unit=0,format=qcow2") + .is_err()); - // Overflow - drive_conf.id += "A"; - assert!(drive_conf.check().is_err()); + // Test5: Missing parameters file/unit. + let mut vm_config = VmConfig::default(); + assert!(vm_config.add_drive("if=pflash,readonly=on,unit=2").is_err()); + assert!(vm_config + .add_drive("if=pflash,readonly=on,file=flash0.fd") + .is_err()); + } - let mut drive_conf = DriveConfig::default(); - for _ in 0..MAX_PATH_LENGTH { - drive_conf.path_on_host += "A"; - } - assert!(drive_conf.check().is_ok()); + #[test] + fn test_block_drive_config_cmdline_parser() { + // Test1: Right. + let mut vm_config = VmConfig::default(); + assert!(vm_config + .add_drive("id=rootfs,file=/path/to/rootfs,format=qcow2,readonly=off,direct=on,throttling.iops-total=200,discard=unmap,detect-zeroes=unmap") + .is_ok()); + assert!(vm_config.drives.len() == 1); + let drive_cfg = &vm_config.drives.remove("rootfs").unwrap(); + + assert_eq!(drive_cfg.id, "rootfs"); + assert_eq!(drive_cfg.path_on_host, "/path/to/rootfs"); + assert_eq!(drive_cfg.format.to_string(), "qcow2"); + assert_eq!(drive_cfg.readonly, false); + assert_eq!(drive_cfg.direct, true); + assert_eq!(drive_cfg.iops.unwrap(), 200); + assert_eq!(drive_cfg.discard, true); + assert_eq!( + drive_cfg.write_zeroes, + WriteZeroesState::from_str("unmap").unwrap() + ); - // Overflow - drive_conf.path_on_host += "A"; - assert!(drive_conf.check().is_err()); + // Test2: Change parameters sequence. + let mut vm_config = VmConfig::default(); + assert!(vm_config + .add_drive("throttling.iops-total=200,file=/path/to/rootfs,format=qcow2,id=rootfs,readonly=off,direct=on,discard=unmap,detect-zeroes=unmap") + .is_ok()); - let mut drive_conf = DriveConfig::default(); - drive_conf.iops = Some(MAX_IOPS); - assert!(drive_conf.check().is_ok()); + // Test3: Add duplicate block drive config. + let mut vm_config = VmConfig::default(); + assert!(vm_config + .add_drive("id=rootfs,file=/path/to/rootfs,format=qcow2,readonly=off,direct=on") + .is_ok()); + assert!(vm_config + .add_drive("id=rootfs,file=/path/to/rootfs,format=qcow2,readonly=off,direct=on") + .is_err()); + let drive_cfg = &vm_config.drives.remove("rootfs"); + assert!(drive_cfg.is_some()); - let mut drive_conf = DriveConfig::default(); - drive_conf.iops = None; - assert!(drive_conf.check().is_ok()); + // Test4: Illegal parameters. + let mut vm_config = VmConfig::default(); + assert!(vm_config + .add_drive("id=rootfs,file=/path/to/rootfs,format=vhdx") + .is_err()); + assert!(vm_config + .add_drive("id=rootfs,if=illegal,file=/path/to/rootfs,format=vhdx") + .is_err()); + assert!(vm_config + .add_drive("id=rootfs,file=/path/to/rootfs,format=raw,throttling.iops-total=1000001") + .is_err()); + assert!(vm_config + .add_drive("id=rootfs,file=/path/to/rootfs,format=raw,media=illegal") + .is_err()); + assert!(vm_config + .add_drive("id=rootfs,file=/path/to/rootfs,format=raw,detect-zeroes=illegal") + .is_err()); - // Overflow - drive_conf.iops = Some(MAX_IOPS + 1); - assert!(drive_conf.check().is_err()); + // Test5: Missing parameters id/file. + let mut vm_config = VmConfig::default(); + assert!(vm_config + .add_drive("file=/path/to/rootfs,format=qcow2,readonly=off,direct=on,throttling.iops-total=200") + .is_err()); + assert!(vm_config + .add_drive("id=rootfs,format=qcow2,readonly=off,direct=on,throttling.iops-total=200") + .is_err()); } #[test] @@ -888,19 +841,19 @@ mod tests { fn test_drive_config_discard() { let mut vm_config = VmConfig::default(); let drive_conf = vm_config - .add_block_drive("id=rootfs,file=/path/to/rootfs,discard=ignore") + .add_drive("id=rootfs,file=/path/to/rootfs,discard=ignore") .unwrap(); assert_eq!(drive_conf.discard, false); let mut vm_config = VmConfig::default(); let drive_conf = vm_config - .add_block_drive("id=rootfs,file=/path/to/rootfs,discard=unmap") + .add_drive("id=rootfs,file=/path/to/rootfs,discard=unmap") .unwrap(); assert_eq!(drive_conf.discard, true); let mut vm_config = VmConfig::default(); let ret = vm_config - .add_block_drive("id=rootfs,file=/path/to/rootfs,discard=invalid") + .add_drive("id=rootfs,file=/path/to/rootfs,discard=invalid") .is_err(); assert_eq!(ret, true); } @@ -909,25 +862,25 @@ mod tests { fn test_drive_config_write_zeroes() { let mut vm_config = VmConfig::default(); let drive_conf = vm_config - .add_block_drive("id=rootfs,file=/path/to/rootfs,detect-zeroes=off") + .add_drive("id=rootfs,file=/path/to/rootfs,detect-zeroes=off") .unwrap(); assert_eq!(drive_conf.write_zeroes, WriteZeroesState::Off); let mut vm_config = VmConfig::default(); let drive_conf = vm_config - .add_block_drive("id=rootfs,file=/path/to/rootfs,detect-zeroes=on") + .add_drive("id=rootfs,file=/path/to/rootfs,detect-zeroes=on") .unwrap(); assert_eq!(drive_conf.write_zeroes, WriteZeroesState::On); let mut vm_config = VmConfig::default(); let drive_conf = vm_config - .add_block_drive("id=rootfs,file=/path/to/rootfs,detect-zeroes=unmap") + .add_drive("id=rootfs,file=/path/to/rootfs,detect-zeroes=unmap") .unwrap(); assert_eq!(drive_conf.write_zeroes, WriteZeroesState::Unmap); let mut vm_config = VmConfig::default(); let ret = vm_config - .add_block_drive("id=rootfs,file=/path/to/rootfs,detect-zeroes=invalid") + .add_drive("id=rootfs,file=/path/to/rootfs,detect-zeroes=invalid") .is_err(); assert_eq!(ret, true); } diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index 985c1b78..8f4d72e7 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -139,7 +139,7 @@ pub struct VmConfig { pub serial: Option, pub iothreads: Option>, pub object: ObjectConfig, - pub pflashs: Option>, + pub pflashs: Option>, pub dev_name: HashMap, pub global_config: HashMap, pub numa_nodes: Vec<(String, String)>, @@ -395,7 +395,7 @@ impl VmConfig { &mut drive_files, &drive.id, &drive.path_on_host, - drive.read_only, + drive.readonly, drive.direct, )?; } @@ -405,7 +405,7 @@ impl VmConfig { &mut drive_files, "", &pflash.path_on_host, - pflash.read_only, + pflash.readonly, false, )?; } @@ -619,8 +619,8 @@ impl From for bool { pub fn parse_bool(s: &str) -> Result { match s { - "on" => Ok(true), - "off" => Ok(false), + "true" | "on" | "yes" | "unmap" => Ok(true), + "false" | "off" | "no" | "ignore" => Ok(false), _ => Err(anyhow!("Unknow bool value {s}")), } } diff --git a/machine_manager/src/config/scsi.rs b/machine_manager/src/config/scsi.rs index b73833bc..d2fb48f7 100644 --- a/machine_manager/src/config/scsi.rs +++ b/machine_manager/src/config/scsi.rs @@ -268,7 +268,7 @@ pub fn parse_scsi_device(vm_config: &mut VmConfig, drive_config: &str) -> Result .remove(&scsi_drive) .with_context(|| "No drive configured matched for scsi device")?; scsi_dev_cfg.path_on_host = drive_arg.path_on_host.clone(); - scsi_dev_cfg.read_only = drive_arg.read_only; + scsi_dev_cfg.read_only = drive_arg.readonly; scsi_dev_cfg.direct = drive_arg.direct; scsi_dev_cfg.aio_type = drive_arg.aio; scsi_dev_cfg.format = drive_arg.format; diff --git a/machine_manager/src/config/usb.rs b/machine_manager/src/config/usb.rs index 1b0e492c..67917924 100644 --- a/machine_manager/src/config/usb.rs +++ b/machine_manager/src/config/usb.rs @@ -86,7 +86,7 @@ pub fn parse_usb_storage(vm_config: &mut VmConfig, drive_config: &str) -> Result .remove(&storage_drive) .with_context(|| "No drive configured matched for usb storage device.")?; dev.scsi_cfg.path_on_host = drive_arg.path_on_host.clone(); - dev.scsi_cfg.read_only = drive_arg.read_only; + dev.scsi_cfg.read_only = drive_arg.readonly; dev.scsi_cfg.aio_type = drive_arg.aio; dev.scsi_cfg.direct = drive_arg.direct; dev.scsi_cfg.format = drive_arg.format; diff --git a/util/src/aio/mod.rs b/util/src/aio/mod.rs index d8d733da..0b117b85 100644 --- a/util/src/aio/mod.rs +++ b/util/src/aio/mod.rs @@ -66,7 +66,7 @@ pub enum AioEngine { } impl FromStr for AioEngine { - type Err = (); + type Err = anyhow::Error; fn from_str(s: &str) -> std::result::Result { match s { @@ -74,7 +74,7 @@ impl FromStr for AioEngine { AIO_NATIVE => Ok(AioEngine::Native), AIO_IOURING => Ok(AioEngine::IoUring), AIO_THREADS => Ok(AioEngine::Threads), - _ => Err(()), + _ => Err(anyhow!("Unknown aio type")), } } } @@ -90,8 +90,9 @@ impl ToString for AioEngine { } } -#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] +#[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] pub enum WriteZeroesState { + #[default] Off, On, Unmap, -- Gitee From 4ecbe67dceb473fa2c30a5d4519a39a92cb91fe0 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Fri, 23 Feb 2024 10:50:25 +0800 Subject: [PATCH 015/489] scsi: use clap to parse the parameters of the scsi-device/usb-storage config Usb-storage has a scsi device as its backend. Use clap to parse the parameters of the scsi-device/usb-storage config simultaneously. Signed-off-by: liuxiangdong --- devices/src/scsi/bus.rs | 16 +-- devices/src/scsi/disk.rs | 141 ++++++++++++++++++++++--- devices/src/usb/storage.rs | 58 ++++++++--- devices/src/usb/uas.rs | 41 ++++++-- machine/src/lib.rs | 63 ++++++----- machine_manager/src/config/mod.rs | 2 - machine_manager/src/config/scsi.rs | 154 +-------------------------- machine_manager/src/config/usb.rs | 162 ----------------------------- virtio/src/device/scsi_cntlr.rs | 14 ++- 9 files changed, 255 insertions(+), 396 deletions(-) delete mode 100644 machine_manager/src/config/usb.rs diff --git a/devices/src/scsi/bus.rs b/devices/src/scsi/bus.rs index 271c51a5..0b018c65 100644 --- a/devices/src/scsi/bus.rs +++ b/devices/src/scsi/bus.rs @@ -666,7 +666,7 @@ impl ScsiRequest { let mut not_supported_flag = false; let mut sense = None; let mut status = GOOD; - let found_lun = self.dev.lock().unwrap().config.lun; + let found_lun = self.dev.lock().unwrap().dev_cfg.lun; // Requested lun id is not equal to found device id means it may be a target request. // REPORT LUNS is also a target request command. @@ -1174,7 +1174,7 @@ fn scsi_command_emulate_mode_sense( if dev_lock.state.features & (1 << SCSI_DISK_F_DPOFUA) != 0 { dev_specific_parameter = 0x10; } - if dev_lock.config.read_only { + if dev_lock.drive_cfg.readonly { // Readonly. dev_specific_parameter |= 0x80; } @@ -1362,7 +1362,7 @@ fn scsi_command_emulate_report_luns( let dev_lock = dev.lock().unwrap(); // Byte 0-3: Lun List Length. Byte 4-7: Reserved. let mut outbuf: Vec = vec![0; 8]; - let target = dev_lock.config.target; + let target = dev_lock.dev_cfg.target; if cmd.xfer < 16 { bail!("scsi REPORT LUNS xfer {} too short!", cmd.xfer); @@ -1383,17 +1383,17 @@ fn scsi_command_emulate_report_luns( for (_pos, device) in scsi_bus_clone.devices.iter() { let device_lock = device.lock().unwrap(); - if device_lock.config.target != target { + if device_lock.dev_cfg.target != target { drop(device_lock); continue; } let len = outbuf.len(); - if device_lock.config.lun < 256 { + if device_lock.dev_cfg.lun < 256 { outbuf.push(0); - outbuf.push(device_lock.config.lun as u8); + outbuf.push(device_lock.dev_cfg.lun as u8); } else { - outbuf.push(0x40 | ((device_lock.config.lun >> 8) & 0xff) as u8); - outbuf.push((device_lock.config.lun & 0xff) as u8); + outbuf.push(0x40 | ((device_lock.dev_cfg.lun >> 8) & 0xff) as u8); + outbuf.push((device_lock.dev_cfg.lun & 0xff) as u8); } outbuf.resize(len + 8, 0); drop(device_lock); diff --git a/devices/src/scsi/disk.rs b/devices/src/scsi/disk.rs index 6c4652ed..7edccdeb 100644 --- a/devices/src/scsi/disk.rs +++ b/devices/src/scsi/disk.rs @@ -14,11 +14,12 @@ use std::collections::HashMap; use std::sync::{Arc, Mutex, Weak}; use anyhow::{bail, Result}; +use clap::Parser; use crate::ScsiBus::{aio_complete_cb, ScsiBus, ScsiCompleteCb}; use crate::{Device, DeviceBase}; use block_backend::{create_block_backend, BlockDriverOps, BlockProperty}; -use machine_manager::config::{DriveFile, ScsiDevConfig, VmConfig}; +use machine_manager::config::{valid_id, DriveConfig, DriveFile, VmConfig}; use machine_manager::event_loop::EventLoop; use util::aio::{Aio, AioEngine, WriteZeroesState}; @@ -57,6 +58,49 @@ pub const SCSI_DISK_DEFAULT_BLOCK_SIZE: u32 = 1 << SCSI_DISK_DEFAULT_BLOCK_SIZE_ pub const SCSI_CDROM_DEFAULT_BLOCK_SIZE_SHIFT: u32 = 11; pub const SCSI_CDROM_DEFAULT_BLOCK_SIZE: u32 = 1 << SCSI_CDROM_DEFAULT_BLOCK_SIZE_SHIFT; +// Stratovirt uses scsi mod in only virtio-scsi and usb-storage. Scsi's channel/target/lun +// of usb-storage are both 0. Scsi's channel/target/lun of virtio-scsi is no more than 0/255/16383. +// Set valid range of channel/target according to the range of virtio-scsi as 0/255. +// +// For stratovirt doesn't support `Flat space addressing format`(14 bits for lun) and only supports +// `peripheral device addressing format`(8 bits for lun) now, lun should be less than 255(2^8 - 1) temporarily. +const SCSI_MAX_CHANNEL: i64 = 0; +const SCSI_MAX_TARGET: i64 = 255; +const SUPPORT_SCSI_MAX_LUN: i64 = 255; + +#[derive(Parser, Clone, Debug, Default)] +#[command(no_binary_name(true))] +pub struct ScsiDevConfig { + #[arg(long, value_parser = ["scsi-cd", "scsi-hd"])] + pub classtype: String, + #[arg(long, value_parser = valid_id)] + pub id: String, + #[arg(long, value_parser = valid_scsi_bus)] + pub bus: String, + /// Scsi four level hierarchical address(host, channel, target, lun). + #[arg(long, default_value = "0", value_parser = clap::value_parser!(u8).range(..=SCSI_MAX_CHANNEL))] + pub channel: u8, + #[arg(long, alias = "scsi-id", value_parser = clap::value_parser!(u8).range(..=SCSI_MAX_TARGET))] + pub target: u8, + #[arg(long, value_parser = clap::value_parser!(u16).range(..=SUPPORT_SCSI_MAX_LUN))] + pub lun: u16, + #[arg(long)] + pub drive: String, + #[arg(long)] + pub serial: Option, + #[arg(long)] + pub bootindex: Option, +} + +// Scsi device should has bus named as "$parent_cntlr_name.0". +fn valid_scsi_bus(bus: &str) -> Result { + let strs = bus.split('.').collect::>(); + if strs.len() != 2 || strs[1] != "0" { + bail!("Invalid scsi bus {}", bus); + } + Ok(bus.to_string()) +} + #[derive(Clone, Default)] pub struct ScsiDevState { /// Features which the scsi device supports. @@ -99,7 +143,9 @@ impl Device for ScsiDevice { pub struct ScsiDevice { pub base: DeviceBase, /// Configuration of the scsi device. - pub config: ScsiDevConfig, + pub dev_cfg: ScsiDevConfig, + /// Configuration of the scsi device's drive. + pub drive_cfg: DriveConfig, /// State of the scsi device. pub state: ScsiDevState, /// Block backend opened by scsi device. @@ -129,13 +175,19 @@ unsafe impl Sync for ScsiDevice {} impl ScsiDevice { pub fn new( - config: ScsiDevConfig, - scsi_type: u32, + dev_cfg: ScsiDevConfig, + drive_cfg: DriveConfig, drive_files: Arc>>, ) -> ScsiDevice { + let scsi_type = match dev_cfg.classtype.as_str() { + "scsi-hd" => SCSI_TYPE_DISK, + _ => SCSI_TYPE_ROM, + }; + ScsiDevice { - base: DeviceBase::new(config.id.clone(), false), - config, + base: DeviceBase::new(dev_cfg.id.clone(), false), + dev_cfg, + drive_cfg, state: ScsiDevState::new(), block_backend: None, req_align: 1, @@ -164,35 +216,35 @@ impl ScsiDevice { } } - if let Some(serial) = &self.config.serial { + if let Some(serial) = &self.dev_cfg.serial { self.state.serial = serial.clone(); } let drive_files = self.drive_files.lock().unwrap(); // File path can not be empty string. And it has also been checked in CmdParser::parse. - let file = VmConfig::fetch_drive_file(&drive_files, &self.config.path_on_host)?; + let file = VmConfig::fetch_drive_file(&drive_files, &self.drive_cfg.path_on_host)?; - let alignments = VmConfig::fetch_drive_align(&drive_files, &self.config.path_on_host)?; + let alignments = VmConfig::fetch_drive_align(&drive_files, &self.drive_cfg.path_on_host)?; self.req_align = alignments.0; self.buf_align = alignments.1; - let drive_id = VmConfig::get_drive_id(&drive_files, &self.config.path_on_host)?; + let drive_id = VmConfig::get_drive_id(&drive_files, &self.drive_cfg.path_on_host)?; let mut thread_pool = None; - if self.config.aio_type != AioEngine::Off { + if self.drive_cfg.aio != AioEngine::Off { thread_pool = Some(EventLoop::get_ctx(None).unwrap().thread_pool.clone()); } - let aio = Aio::new(Arc::new(aio_complete_cb), self.config.aio_type, thread_pool)?; + let aio = Aio::new(Arc::new(aio_complete_cb), self.drive_cfg.aio, thread_pool)?; let conf = BlockProperty { id: drive_id, - format: self.config.format, + format: self.drive_cfg.format, iothread, - direct: self.config.direct, + direct: self.drive_cfg.direct, req_align: self.req_align, buf_align: self.buf_align, discard: false, write_zeroes: WriteZeroesState::Off, - l2_cache_size: self.config.l2_cache_size, - refcount_cache_size: self.config.refcount_cache_size, + l2_cache_size: self.drive_cfg.l2_cache_size, + refcount_cache_size: self.drive_cfg.refcount_cache_size, }; let backend = create_block_backend(file, aio, conf)?; let disk_size = backend.lock().unwrap().disk_size()?; @@ -202,3 +254,60 @@ impl ScsiDevice { Ok(()) } } + +#[cfg(test)] +mod tests { + use super::*; + use machine_manager::config::str_slip_to_clap; + + #[test] + fn test_scsi_device_cmdline_parser() { + // Test1: Right. + let cmdline1 = "scsi-hd,bus=scsi0.0,scsi-id=0,lun=0,drive=drive-0-0-0-0,id=scsi0-0-0-0,serial=123456,bootindex=1"; + let config = + ScsiDevConfig::try_parse_from(str_slip_to_clap(cmdline1, true, false)).unwrap(); + assert_eq!(config.id, "scsi0-0-0-0"); + assert_eq!(config.bus, "scsi0.0"); + assert_eq!(config.target, 0); + assert_eq!(config.lun, 0); + assert_eq!(config.drive, "drive-0-0-0-0"); + assert_eq!(config.serial.unwrap(), "123456"); + assert_eq!(config.bootindex.unwrap(), 1); + + // Test2: Default value. + let cmdline2 = "scsi-cd,bus=scsi0.0,scsi-id=0,lun=0,drive=drive-0-0-0-0,id=scsi0-0-0-0"; + let config = + ScsiDevConfig::try_parse_from(str_slip_to_clap(cmdline2, true, false)).unwrap(); + assert_eq!(config.channel, 0); + assert_eq!(config.serial, None); + assert_eq!(config.bootindex, None); + + // Test3: Illegal value. + let cmdline3 = "scsi-hd,bus=scsi0.0,scsi-id=256,lun=0,drive=drive-0-0-0-0,id=scsi0-0-0-0"; + let result = ScsiDevConfig::try_parse_from(str_slip_to_clap(cmdline3, true, false)); + assert!(result.is_err()); + let cmdline3 = "scsi-hd,bus=scsi0.0,scsi-id=0,lun=256,drive=drive-0-0-0-0,id=scsi0-0-0-0"; + let result = ScsiDevConfig::try_parse_from(str_slip_to_clap(cmdline3, true, false)); + assert!(result.is_err()); + let cmdline3 = "illegal,bus=scsi0.0,scsi-id=0,lun=0,drive=drive-0-0-0-0,id=scsi0-0-0-0"; + let result = ScsiDevConfig::try_parse_from(str_slip_to_clap(cmdline3, true, false)); + assert!(result.is_err()); + + // Test4: Missing necessary parameters. + let cmdline4 = "scsi-hd,scsi-id=0,lun=0,drive=drive-0-0-0-0,id=scsi0-0-0-0"; + let result = ScsiDevConfig::try_parse_from(str_slip_to_clap(cmdline4, true, false)); + assert!(result.is_err()); + let cmdline4 = "scsi-hd,bus=scsi0.0,lun=0,drive=drive-0-0-0-0,id=scsi0-0-0-0"; + let result = ScsiDevConfig::try_parse_from(str_slip_to_clap(cmdline4, true, false)); + assert!(result.is_err()); + let cmdline4 = "scsi-hd,bus=scsi0.0,scsi-id=0,drive=drive-0-0-0-0,id=scsi0-0-0-0"; + let result = ScsiDevConfig::try_parse_from(str_slip_to_clap(cmdline4, true, false)); + assert!(result.is_err()); + let cmdline4 = "scsi-hd,bus=scsi0.0,scsi-id=0,lun=0,id=scsi0-0-0-0"; + let result = ScsiDevConfig::try_parse_from(str_slip_to_clap(cmdline4, true, false)); + assert!(result.is_err()); + let cmdline4 = "scsi-hd,bus=scsi0.0,scsi-id=0,lun=0,drive=drive-0-0-0-0"; + let result = ScsiDevConfig::try_parse_from(str_slip_to_clap(cmdline4, true, false)); + assert!(result.is_err()); + } +} diff --git a/devices/src/usb/storage.rs b/devices/src/usb/storage.rs index 4bb44e0e..2f9d4c96 100644 --- a/devices/src/usb/storage.rs +++ b/devices/src/usb/storage.rs @@ -17,6 +17,7 @@ use std::{ use anyhow::{anyhow, bail, Context, Result}; use byteorder::{ByteOrder, LittleEndian}; +use clap::Parser; use log::{error, info, warn}; use once_cell::sync::Lazy; @@ -32,9 +33,10 @@ use crate::{ ScsiBus, ScsiRequest, ScsiRequestOps, ScsiSense, ScsiXferMode, EMULATE_SCSI_OPS, GOOD, SCSI_CMD_BUF_SIZE, }, - ScsiDisk::{ScsiDevice, SCSI_TYPE_DISK, SCSI_TYPE_ROM}, + ScsiDisk::{ScsiDevConfig, ScsiDevice}, }; -use machine_manager::config::{DriveFile, UsbStorageConfig}; +use machine_manager::config::{DriveConfig, DriveFile}; +use util::aio::AioEngine; // Storage device descriptor static DESC_DEVICE_STORAGE: Lazy> = Lazy::new(|| { @@ -221,6 +223,21 @@ impl UsbStorageState { } } +#[derive(Parser, Clone, Debug)] +#[command(no_binary_name(true))] +pub struct UsbStorageConfig { + #[arg(long, value_parser = ["usb-storage"])] + pub classtype: String, + #[arg(long)] + pub id: String, + #[arg(long)] + pub drive: String, + #[arg(long)] + bus: Option, + #[arg(long)] + port: Option, +} + /// USB storage device. pub struct UsbStorage { base: UsbDeviceBase, @@ -228,7 +245,9 @@ pub struct UsbStorage { /// USB controller used to notify controller to transfer data. cntlr: Option>>, /// Configuration of the USB storage device. - pub config: UsbStorageConfig, + pub dev_cfg: UsbStorageConfig, + /// Configuration of the USB storage device's drive. + pub drive_cfg: DriveConfig, /// Scsi bus attached to this usb-storage device. scsi_bus: Arc>, /// Effective scsi backend. @@ -305,26 +324,37 @@ impl UsbMsdCsw { impl UsbStorage { pub fn new( - config: UsbStorageConfig, + dev_cfg: UsbStorageConfig, + drive_cfg: DriveConfig, drive_files: Arc>>, - ) -> Self { - let scsi_type = match &config.media as &str { - "disk" => SCSI_TYPE_DISK, - _ => SCSI_TYPE_ROM, + ) -> Result { + if drive_cfg.aio != AioEngine::Off || drive_cfg.direct { + bail!("USB-storage: \"aio=off,direct=false\" must be configured."); + } + + let scsidev_classtype = match &drive_cfg.media as &str { + "disk" => "scsi-hd".to_string(), + _ => "scsi-cd".to_string(), + }; + let scsi_dev_cfg = ScsiDevConfig { + classtype: scsidev_classtype, + drive: dev_cfg.drive.clone(), + ..Default::default() }; - Self { - base: UsbDeviceBase::new(config.id.clone().unwrap(), USB_DEVICE_BUFFER_DEFAULT_LEN), + Ok(Self { + base: UsbDeviceBase::new(dev_cfg.id.clone(), USB_DEVICE_BUFFER_DEFAULT_LEN), state: UsbStorageState::new(), cntlr: None, - config: config.clone(), + dev_cfg, + drive_cfg: drive_cfg.clone(), scsi_bus: Arc::new(Mutex::new(ScsiBus::new("".to_string()))), scsi_dev: Arc::new(Mutex::new(ScsiDevice::new( - config.scsi_cfg, - scsi_type, + scsi_dev_cfg, + drive_cfg, drive_files, ))), - } + }) } fn handle_control_packet(&mut self, packet: &mut UsbPacket, device_req: &UsbDeviceRequest) { diff --git a/devices/src/usb/uas.rs b/devices/src/usb/uas.rs index 3768b8bb..9ba134cd 100644 --- a/devices/src/usb/uas.rs +++ b/devices/src/usb/uas.rs @@ -17,12 +17,11 @@ use std::mem::size_of; use std::sync::{Arc, Mutex, Weak}; use anyhow::{anyhow, bail, Context, Result}; +use clap::Parser; use log::{debug, error, info, warn}; -use machine_manager::config::{DriveFile, UsbUasConfig}; use once_cell::sync::Lazy; use strum::EnumCount; use strum_macros::EnumCount; -use util::byte_code::ByteCode; use super::config::*; use super::descriptor::{ @@ -35,15 +34,16 @@ use super::{ UsbDevice, UsbDeviceBase, UsbDeviceRequest, UsbEndpoint, UsbPacket, UsbPacketStatus, USB_DEVICE_BUFFER_DEFAULT_LEN, }; - use crate::{ ScsiBus::{ scsi_cdb_xfer, scsi_cdb_xfer_mode, ScsiBus, ScsiRequest, ScsiRequestOps, ScsiSense, ScsiXferMode, CHECK_CONDITION, EMULATE_SCSI_OPS, GOOD, SCSI_SENSE_INVALID_PARAM_VALUE, SCSI_SENSE_INVALID_TAG, SCSI_SENSE_NO_SENSE, SCSI_SENSE_OVERLAPPED_COMMANDS, }, - ScsiDisk::{ScsiDevice, SCSI_TYPE_DISK, SCSI_TYPE_ROM}, + ScsiDisk::{ScsiDevConfig, ScsiDevice}, }; +use machine_manager::config::{DriveConfig, DriveFile}; +use util::byte_code::ByteCode; // Size of UasIUBody const UAS_IU_BODY_SIZE: usize = 30; @@ -89,6 +89,23 @@ const _UAS_TMF_QUERY_TASK: u8 = 0x80; const _UAS_TMF_QUERY_TASK_SET: u8 = 0x81; const _UAS_TMF_QUERY_ASYNC_EVENT: u8 = 0x82; +#[derive(Parser, Clone, Debug)] +#[command(no_binary_name(true))] +pub struct UsbUasConfig { + #[arg(long, value_parser = ["usb-uas"])] + pub classtype: String, + #[arg(long)] + pub drive: String, + #[arg(long)] + pub id: Option, + #[arg(long)] + pub speed: Option, + #[arg(long)] + bus: Option, + #[arg(long)] + port: Option, +} + pub struct UsbUas { base: UsbDeviceBase, scsi_bus: Arc>, @@ -573,11 +590,17 @@ fn complete_async_packet(packet: &Arc>) { impl UsbUas { pub fn new( uas_config: UsbUasConfig, + drive_cfg: DriveConfig, drive_files: Arc>>, ) -> Self { - let scsi_type = match &uas_config.media as &str { - "disk" => SCSI_TYPE_DISK, - _ => SCSI_TYPE_ROM, + let scsidev_classtype = match &drive_cfg.media as &str { + "disk" => "scsi-hd".to_string(), + _ => "scsi-cd".to_string(), + }; + let scsi_dev_cfg = ScsiDevConfig { + classtype: scsidev_classtype, + drive: uas_config.drive.clone(), + ..Default::default() }; let mut base = UsbDeviceBase::new( @@ -594,8 +617,8 @@ impl UsbUas { base, scsi_bus: Arc::new(Mutex::new(ScsiBus::new("".to_string()))), scsi_device: Arc::new(Mutex::new(ScsiDevice::new( - uas_config.scsi_cfg, - scsi_type, + scsi_dev_cfg, + drive_cfg, drive_files, ))), commands_high: VecDeque::new(), diff --git a/machine/src/lib.rs b/machine/src/lib.rs index fb0256d2..031f1697 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -59,14 +59,16 @@ use devices::sysbus::{SysBus, SysBusDevOps, SysBusDevType}; #[cfg(feature = "usb_camera")] use devices::usb::camera::{UsbCamera, UsbCameraConfig}; use devices::usb::keyboard::{UsbKeyboard, UsbKeyboardConfig}; +use devices::usb::storage::{UsbStorage, UsbStorageConfig}; use devices::usb::tablet::{UsbTablet, UsbTabletConfig}; +use devices::usb::uas::{UsbUas, UsbUasConfig}; #[cfg(feature = "usb_host")] use devices::usb::usbhost::{UsbHost, UsbHostConfig}; use devices::usb::xhci::xhci_pci::{XhciConfig, XhciPciDevice}; -use devices::usb::{storage::UsbStorage, uas::UsbUas, UsbDevice}; +use devices::usb::UsbDevice; #[cfg(target_arch = "aarch64")] use devices::InterruptController; -use devices::ScsiDisk::{ScsiDevice, SCSI_TYPE_DISK, SCSI_TYPE_ROM}; +use devices::ScsiDisk::{ScsiDevConfig, ScsiDevice}; use hypervisor::{kvm::KvmHypervisor, test::TestHypervisor, HypervisorOps}; #[cfg(feature = "usb_camera")] use machine_manager::config::get_cameradev_by_id; @@ -76,16 +78,13 @@ use machine_manager::config::parse_demo_dev; use machine_manager::config::parse_gpu; #[cfg(feature = "pvpanic")] use machine_manager::config::parse_pvpanic; -use machine_manager::config::parse_usb_storage; -use machine_manager::config::parse_usb_uas; use machine_manager::config::{ complete_numa_node, get_multi_function, get_pci_bdf, parse_blk, parse_device_id, parse_device_type, parse_fs, parse_net, parse_numa_distance, parse_numa_mem, parse_rng_dev, - parse_root_port, parse_scsi_controller, parse_scsi_device, parse_vfio, parse_vhost_user_blk, - parse_virtio_serial, parse_virtserialport, parse_vsock, str_slip_to_clap, BootIndexInfo, - BootSource, DriveConfig, DriveFile, Incoming, MachineMemConfig, MigrateMode, NumaConfig, - NumaDistance, NumaNode, NumaNodes, PciBdf, SerialConfig, VfioConfig, VmConfig, FAST_UNPLUG_ON, - MAX_VIRTIO_QUEUE, + parse_root_port, parse_scsi_controller, parse_vfio, parse_vhost_user_blk, parse_virtio_serial, + parse_virtserialport, parse_vsock, str_slip_to_clap, BootIndexInfo, BootSource, DriveConfig, + DriveFile, Incoming, MachineMemConfig, MigrateMode, NumaConfig, NumaDistance, NumaNode, + NumaNodes, PciBdf, SerialConfig, VfioConfig, VmConfig, FAST_UNPLUG_ON, MAX_VIRTIO_QUEUE, }; use machine_manager::event_loop::EventLoop; use machine_manager::machine::{HypervisorType, MachineInterface, VmState}; @@ -1119,29 +1118,27 @@ pub trait MachineOps { } fn add_scsi_device(&mut self, vm_config: &mut VmConfig, cfg_args: &str) -> Result<()> { - let device_cfg = parse_scsi_device(vm_config, cfg_args)?; - let scsi_type = match parse_device_type(cfg_args)?.as_str() { - "scsi-hd" => SCSI_TYPE_DISK, - _ => SCSI_TYPE_ROM, - }; - if let Some(bootindex) = device_cfg.boot_index { + let device_cfg = ScsiDevConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + let drive_arg = vm_config + .drives + .remove(&device_cfg.drive) + .with_context(|| "No drive configured matched for scsi device")?; + + if let Some(bootindex) = device_cfg.bootindex { self.check_bootindex(bootindex) .with_context(|| "Failed to add scsi device for invalid bootindex")?; } let device = Arc::new(Mutex::new(ScsiDevice::new( device_cfg.clone(), - scsi_type, + drive_arg, self.get_drive_files(), ))); + // Bus name `$parent_cntlr_name.0` is checked when parsing by clap. + let cntlr = device_cfg.bus.split('.').collect::>()[0].to_string(); let pci_dev = self - .get_pci_dev_by_id_and_type(vm_config, Some(&device_cfg.cntlr), "virtio-scsi-pci") - .with_context(|| { - format!( - "Can not find scsi controller from pci bus {}", - device_cfg.cntlr - ) - })?; + .get_pci_dev_by_id_and_type(vm_config, Some(&cntlr), "virtio-scsi-pci") + .with_context(|| format!("Can not find scsi controller from pci bus {}", cntlr))?; let locked_pcidev = pci_dev.lock().unwrap(); let virtio_pcidev = locked_pcidev .as_any() @@ -1167,7 +1164,7 @@ pub trait MachineOps { .insert((device_cfg.target, device_cfg.lun), device.clone()); device.lock().unwrap().parent_bus = Arc::downgrade(bus); - if let Some(bootindex) = device_cfg.boot_index { + if let Some(bootindex) = device_cfg.bootindex { // Eg: OpenFirmware device path(virtio-scsi disk): // /pci@i0cf8/scsi@7[,3]/channel@0/disk@2,3 // | | | | | | @@ -1725,15 +1722,25 @@ pub trait MachineOps { .with_context(|| "Failed to realize usb camera device")? } "usb-storage" => { - let device_cfg = parse_usb_storage(vm_config, cfg_args)?; - let storage = UsbStorage::new(device_cfg, self.get_drive_files()); + let device_cfg = + UsbStorageConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + let drive_cfg = vm_config + .drives + .remove(&device_cfg.drive) + .with_context(|| "No drive configured matched for usb storage device.")?; + let storage = UsbStorage::new(device_cfg, drive_cfg, self.get_drive_files())?; storage .realize() .with_context(|| "Failed to realize usb storage device")? } "usb-uas" => { - let device_cfg = parse_usb_uas(vm_config, cfg_args)?; - let uas = UsbUas::new(device_cfg, self.get_drive_files()); + let device_cfg = + UsbUasConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + let drive_cfg = vm_config + .drives + .remove(&device_cfg.drive) + .with_context(|| "No drive configured matched for usb uas device.")?; + let uas = UsbUas::new(device_cfg, drive_cfg, self.get_drive_files()); uas.realize() .with_context(|| "Failed to realize usb uas device")? } diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index 8f4d72e7..fd761414 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -44,7 +44,6 @@ mod scsi; mod smbios; #[cfg(feature = "vnc_auth")] mod tls_creds; -mod usb; mod vfio; pub use boot_source::*; @@ -78,7 +77,6 @@ pub use scsi::*; pub use smbios::*; #[cfg(feature = "vnc_auth")] pub use tls_creds::*; -pub use usb::*; pub use vfio::*; #[cfg(feature = "vnc")] pub use vnc::*; diff --git a/machine_manager/src/config/scsi.rs b/machine_manager/src/config/scsi.rs index d2fb48f7..da3d1dbb 100644 --- a/machine_manager/src/config/scsi.rs +++ b/machine_manager/src/config/scsi.rs @@ -12,22 +12,10 @@ use anyhow::{anyhow, bail, Context, Result}; -use super::{error::ConfigError, pci_args_check, DiskFormat}; +use super::{error::ConfigError, pci_args_check}; use crate::config::{ - check_arg_too_long, CmdParser, ConfigCheck, VmConfig, DEFAULT_VIRTQUEUE_SIZE, MAX_VIRTIO_QUEUE, + check_arg_too_long, CmdParser, ConfigCheck, DEFAULT_VIRTQUEUE_SIZE, MAX_VIRTIO_QUEUE, }; -use util::aio::AioEngine; - -/// According to Virtio Spec. -/// Max_channel should be 0. -/// Max_target should be less than or equal to 255. -pub const VIRTIO_SCSI_MAX_TARGET: u16 = 255; -/// Max_lun should be less than or equal to 16383 (2^14 - 1). -pub const VIRTIO_SCSI_MAX_LUN: u16 = 16383; - -/// Only support peripheral device addressing format(8 bits for lun) in stratovirt now. -/// So, max lun id supported is 255 (2^8 - 1). -const SUPPORT_SCSI_MAX_LUN: u16 = 255; // Seg_max = queue_size - 2. So, size of each virtqueue for virtio-scsi should be larger than 2. const MIN_QUEUE_SIZE_SCSI: u16 = 2; @@ -139,141 +127,3 @@ pub fn parse_scsi_controller( cntlr_cfg.check()?; Ok(cntlr_cfg) } - -#[derive(Clone, Debug)] -pub struct ScsiDevConfig { - /// Scsi Device id. - pub id: String, - /// The image file path. - pub path_on_host: String, - /// Serial number of the scsi device. - pub serial: Option, - /// Scsi controller which the scsi device attaches to. - pub cntlr: String, - /// Scsi device can not do write operation. - pub read_only: bool, - /// If true, use direct access io. - pub direct: bool, - /// Async IO type. - pub aio_type: AioEngine, - /// Boot order. - pub boot_index: Option, - /// Scsi four level hierarchical address(host, channel, target, lun). - pub channel: u8, - pub target: u8, - pub lun: u16, - pub format: DiskFormat, - pub l2_cache_size: Option, - pub refcount_cache_size: Option, -} - -impl Default for ScsiDevConfig { - fn default() -> Self { - ScsiDevConfig { - id: "".to_string(), - path_on_host: "".to_string(), - serial: None, - cntlr: "".to_string(), - read_only: false, - direct: true, - aio_type: AioEngine::Native, - boot_index: None, - channel: 0, - target: 0, - lun: 0, - format: DiskFormat::Raw, - l2_cache_size: None, - refcount_cache_size: None, - } - } -} - -pub fn parse_scsi_device(vm_config: &mut VmConfig, drive_config: &str) -> Result { - let mut cmd_parser = CmdParser::new("scsi-device"); - cmd_parser - .push("") - .push("id") - .push("bus") - .push("scsi-id") - .push("lun") - .push("serial") - .push("bootindex") - .push("drive"); - - cmd_parser.parse(drive_config)?; - - let mut scsi_dev_cfg = ScsiDevConfig::default(); - - let scsi_drive = cmd_parser.get_value::("drive")?.with_context(|| { - ConfigError::FieldIsMissing("drive".to_string(), "scsi device".to_string()) - })?; - - if let Some(boot_index) = cmd_parser.get_value::("bootindex")? { - scsi_dev_cfg.boot_index = Some(boot_index); - } - - if let Some(serial) = cmd_parser.get_value::("serial")? { - scsi_dev_cfg.serial = Some(serial); - } - - scsi_dev_cfg.id = cmd_parser.get_value::("id")?.with_context(|| { - ConfigError::FieldIsMissing("id".to_string(), "scsi device".to_string()) - })?; - - if let Some(bus) = cmd_parser.get_value::("bus")? { - // Format "$parent_cntlr_name.0" is required by scsi bus. - let strs = bus.split('.').collect::>(); - if strs.len() != 2 || strs[1] != "0" { - bail!("Invalid scsi bus {}", bus); - } - scsi_dev_cfg.cntlr = strs[0].to_string(); - } else { - return Err(anyhow!(ConfigError::FieldIsMissing( - "bus".to_string(), - "scsi device".to_string() - ))); - } - - if let Some(target) = cmd_parser.get_value::("scsi-id")? { - if target > VIRTIO_SCSI_MAX_TARGET as u8 { - return Err(anyhow!(ConfigError::IllegalValue( - "scsi-id of scsi device".to_string(), - 0, - true, - VIRTIO_SCSI_MAX_TARGET as u64, - true, - ))); - } - scsi_dev_cfg.target = target; - } - - if let Some(lun) = cmd_parser.get_value::("lun")? { - // Do not support Flat space addressing format(14 bits for lun) in stratovirt now. - // We now support peripheral device addressing format(8 bits for lun). - // So, MAX_LUN should be less than 255(2^8 - 1) temporarily. - if lun > SUPPORT_SCSI_MAX_LUN { - return Err(anyhow!(ConfigError::IllegalValue( - "lun of scsi device".to_string(), - 0, - true, - SUPPORT_SCSI_MAX_LUN as u64, - true, - ))); - } - scsi_dev_cfg.lun = lun; - } - - let drive_arg = &vm_config - .drives - .remove(&scsi_drive) - .with_context(|| "No drive configured matched for scsi device")?; - scsi_dev_cfg.path_on_host = drive_arg.path_on_host.clone(); - scsi_dev_cfg.read_only = drive_arg.readonly; - scsi_dev_cfg.direct = drive_arg.direct; - scsi_dev_cfg.aio_type = drive_arg.aio; - scsi_dev_cfg.format = drive_arg.format; - scsi_dev_cfg.l2_cache_size = drive_arg.l2_cache_size; - scsi_dev_cfg.refcount_cache_size = drive_arg.refcount_cache_size; - - Ok(scsi_dev_cfg) -} diff --git a/machine_manager/src/config/usb.rs b/machine_manager/src/config/usb.rs deleted file mode 100644 index 67917924..00000000 --- a/machine_manager/src/config/usb.rs +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) 2022 Huawei Technologies Co.,Ltd. All rights reserved. -// -// StratoVirt is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan -// PSL v2. -// You may obtain a copy of Mulan PSL v2 at: -// http://license.coscl.org.cn/MulanPSL2 -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY -// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -// See the Mulan PSL v2 for more details. - -use anyhow::{bail, Context, Result}; - -use super::error::ConfigError; -use crate::config::{ - check_arg_nonexist, check_arg_too_long, CmdParser, ConfigCheck, ScsiDevConfig, VmConfig, -}; -use util::aio::AioEngine; - -pub fn check_id(id: Option, device: &str) -> Result<()> { - check_arg_nonexist(id.clone(), "id", device)?; - check_arg_too_long(&id.unwrap(), "id")?; - - Ok(()) -} - -#[derive(Clone, Debug)] -pub struct UsbStorageConfig { - /// USB Storage device id. - pub id: Option, - /// The scsi backend config. - pub scsi_cfg: ScsiDevConfig, - /// The backend scsi device type(Disk or CD-ROM). - pub media: String, -} - -impl UsbStorageConfig { - fn new() -> Self { - Self { - id: None, - scsi_cfg: ScsiDevConfig::default(), - media: "".to_string(), - } - } -} - -impl Default for UsbStorageConfig { - fn default() -> Self { - Self::new() - } -} - -impl ConfigCheck for UsbStorageConfig { - fn check(&self) -> Result<()> { - check_id(self.id.clone(), "usb-storage")?; - - if self.scsi_cfg.aio_type != AioEngine::Off || self.scsi_cfg.direct { - bail!("USB-storage: \"aio=off,direct=false\" must be configured."); - } - - Ok(()) - } -} - -pub fn parse_usb_storage(vm_config: &mut VmConfig, drive_config: &str) -> Result { - let mut cmd_parser = CmdParser::new("usb-storage"); - cmd_parser - .push("") - .push("id") - .push("bus") - .push("port") - .push("drive"); - - cmd_parser.parse(drive_config)?; - - let mut dev = UsbStorageConfig::new(); - dev.id = cmd_parser.get_value::("id")?; - - let storage_drive = cmd_parser.get_value::("drive")?.with_context(|| { - ConfigError::FieldIsMissing("drive".to_string(), "usb storage device".to_string()) - })?; - - let drive_arg = &vm_config - .drives - .remove(&storage_drive) - .with_context(|| "No drive configured matched for usb storage device.")?; - dev.scsi_cfg.path_on_host = drive_arg.path_on_host.clone(); - dev.scsi_cfg.read_only = drive_arg.readonly; - dev.scsi_cfg.aio_type = drive_arg.aio; - dev.scsi_cfg.direct = drive_arg.direct; - dev.scsi_cfg.format = drive_arg.format; - dev.scsi_cfg.l2_cache_size = drive_arg.l2_cache_size; - dev.scsi_cfg.refcount_cache_size = drive_arg.refcount_cache_size; - dev.media = drive_arg.media.clone(); - - dev.check()?; - Ok(dev) -} - -#[derive(Clone, Debug, Default)] -pub struct UsbUasConfig { - pub id: Option, - pub speed: Option, - pub scsi_cfg: ScsiDevConfig, - pub media: String, -} - -impl UsbUasConfig { - fn new() -> Self { - Self::default() - } -} - -impl ConfigCheck for UsbUasConfig { - fn check(&self) -> Result<()> { - check_id(self.id.clone(), "usb-uas")?; - - if self.scsi_cfg.aio_type != AioEngine::Off || self.scsi_cfg.direct { - bail!("USB UAS: \"aio=off,direct=false\" must be configured."); - } - - Ok(()) - } -} - -pub fn parse_usb_uas(vm_config: &mut VmConfig, drive_config: &str) -> Result { - let mut cmd_parser = CmdParser::new("usb-uas"); - cmd_parser - .push("") - .push("id") - .push("bus") - .push("port") - .push("drive") - .push("speed"); - - cmd_parser.parse(drive_config)?; - - let mut dev = UsbUasConfig::new(); - dev.id = cmd_parser.get_value::("id")?; - dev.speed = cmd_parser.get_value::("speed")?; - - let uas_drive = cmd_parser.get_value::("drive")?.with_context(|| { - ConfigError::FieldIsMissing("drive".to_string(), "usb uas device".to_string()) - })?; - - let drive_arg = &vm_config - .drives - .remove(&uas_drive) - .with_context(|| "No drive configured matched for usb uas device.")?; - dev.scsi_cfg.path_on_host = drive_arg.path_on_host.clone(); - dev.scsi_cfg.read_only = drive_arg.read_only; - dev.scsi_cfg.aio_type = drive_arg.aio; - dev.scsi_cfg.direct = drive_arg.direct; - dev.scsi_cfg.format = drive_arg.format; - dev.scsi_cfg.l2_cache_size = drive_arg.l2_cache_size; - dev.scsi_cfg.refcount_cache_size = drive_arg.refcount_cache_size; - dev.media = drive_arg.media.clone(); - - dev.check()?; - Ok(dev) -} diff --git a/virtio/src/device/scsi_cntlr.rs b/virtio/src/device/scsi_cntlr.rs index d3d6cf42..2cc15bcc 100644 --- a/virtio/src/device/scsi_cntlr.rs +++ b/virtio/src/device/scsi_cntlr.rs @@ -33,16 +33,20 @@ use devices::ScsiBus::{ EMULATE_SCSI_OPS, SCSI_CMD_BUF_SIZE, SCSI_SENSE_INVALID_OPCODE, }; use machine_manager::event_loop::{register_event_helper, unregister_event_helper}; -use machine_manager::{ - config::{ScsiCntlrConfig, VIRTIO_SCSI_MAX_LUN, VIRTIO_SCSI_MAX_TARGET}, - event_loop::EventLoop, -}; +use machine_manager::{config::ScsiCntlrConfig, event_loop::EventLoop}; use util::aio::Iovec; use util::byte_code::ByteCode; use util::loop_context::{ read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, }; +/// According to Virtio Spec. +/// Max_channel should be 0. +/// Max_target should be less than or equal to 255. +const VIRTIO_SCSI_MAX_TARGET: u16 = 255; +/// Max_lun should be less than or equal to 16383 (2^14 - 1). +const VIRTIO_SCSI_MAX_LUN: u32 = 16383; + /// Virtio Scsi Controller has 1 ctrl queue, 1 event queue and at least 1 cmd queue. const SCSI_CTRL_QUEUE_NUM: usize = 1; const SCSI_EVENT_QUEUE_NUM: usize = 1; @@ -171,7 +175,7 @@ impl VirtioDevice for ScsiCntlr { // seg_max: queue size - 2, 32 bit. self.config_space.seg_max = self.queue_size_max() as u32 - 2; self.config_space.max_target = VIRTIO_SCSI_MAX_TARGET; - self.config_space.max_lun = VIRTIO_SCSI_MAX_LUN as u32; + self.config_space.max_lun = VIRTIO_SCSI_MAX_LUN; // num_queues: request queues number. self.config_space.num_queues = self.config.queues; -- Gitee From 81b1bb63c09d3bb403d681aad9fe34947f05b49d Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Wed, 13 Mar 2024 17:33:38 +0800 Subject: [PATCH 016/489] scsicntlr: use clap to parse the parameters of the virtio-scsi-pci config Use clap to parse the parameters of the virtio-scsi-pci config. Signed-off-by: liuxiangdong --- docs/config_guidebook.md | 2 +- machine/src/lib.rs | 36 ++++---- machine_manager/src/config/mod.rs | 25 +++++- machine_manager/src/config/scsi.rs | 129 ----------------------------- virtio/src/device/scsi_cntlr.rs | 94 +++++++++++++++++++-- 5 files changed, 132 insertions(+), 154 deletions(-) delete mode 100644 machine_manager/src/config/scsi.rs diff --git a/docs/config_guidebook.md b/docs/config_guidebook.md index bf205fc1..16195406 100644 --- a/docs/config_guidebook.md +++ b/docs/config_guidebook.md @@ -938,7 +938,7 @@ Six properties can be set for Virtio-Scsi controller. * bus: bus number of the device. * addr: including slot number and function number. * iothread: indicate which iothread will be used, if not specified the main thread will be used. (optional) -* num-queues: the optional num-queues attribute controls the number of request queues to be used for the scsi controller. If not set, the default block queue number is 1. The max queues number supported is no more than 32. (optional) +* num-queues: the optional num-queues attribute controls the number of request queues to be used for the scsi controller. If not set, the default queue number is the smaller one of vCPU count and the max queues number (e.g, min(vcpu_count, 32)). The max queues number supported is no more than 32. (optional) * queue-size: the optional virtqueue size for all the queues. Configuration range is (2, 1024] and queue size must be power of 2. Default queue size is 256. ```shell -device virtio-scsi-pci,id=,bus=,addr=<0x3>[,multifunction={on|off}][,iothread=][,num-queues=][,queue-size=] diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 031f1697..6b0be7df 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -81,10 +81,10 @@ use machine_manager::config::parse_pvpanic; use machine_manager::config::{ complete_numa_node, get_multi_function, get_pci_bdf, parse_blk, parse_device_id, parse_device_type, parse_fs, parse_net, parse_numa_distance, parse_numa_mem, parse_rng_dev, - parse_root_port, parse_scsi_controller, parse_vfio, parse_vhost_user_blk, parse_virtio_serial, - parse_virtserialport, parse_vsock, str_slip_to_clap, BootIndexInfo, BootSource, DriveConfig, - DriveFile, Incoming, MachineMemConfig, MigrateMode, NumaConfig, NumaDistance, NumaNode, - NumaNodes, PciBdf, SerialConfig, VfioConfig, VmConfig, FAST_UNPLUG_ON, MAX_VIRTIO_QUEUE, + parse_root_port, parse_vfio, parse_vhost_user_blk, parse_virtio_serial, parse_virtserialport, + parse_vsock, str_slip_to_clap, BootIndexInfo, BootSource, DriveConfig, DriveFile, Incoming, + MachineMemConfig, MigrateMode, NumaConfig, NumaDistance, NumaNode, NumaNodes, PciBdf, + SerialConfig, VfioConfig, VmConfig, FAST_UNPLUG_ON, MAX_VIRTIO_QUEUE, }; use machine_manager::event_loop::EventLoop; use machine_manager::machine::{HypervisorType, MachineInterface, VmState}; @@ -104,7 +104,7 @@ use virtio::VirtioDeviceQuirk; use virtio::{ balloon_allow_list, find_port_by_nr, get_max_nr, vhost, Balloon, BalloonConfig, Block, BlockState, Rng, RngState, - ScsiCntlr::{scsi_cntlr_create_scsi_bus, ScsiCntlr}, + ScsiCntlr::{scsi_cntlr_create_scsi_bus, ScsiCntlr, ScsiCntlrConfig}, Serial, SerialPort, VhostKern, VhostUser, VirtioDevice, VirtioMmioDevice, VirtioMmioState, VirtioNetState, VirtioPciDevice, VirtioSerialState, VIRTIO_TYPE_CONSOLE, }; @@ -1094,26 +1094,28 @@ pub trait MachineOps { cfg_args: &str, hotplug: bool, ) -> Result<()> { - let bdf = get_pci_bdf(cfg_args)?; - let multi_func = get_multi_function(cfg_args)?; - let queues_auto = Some(VirtioPciDevice::virtio_pci_auto_queues_num( - 0, - vm_config.machine_config.nr_cpus, - MAX_VIRTIO_QUEUE, - )); - let device_cfg = parse_scsi_controller(cfg_args, queues_auto)?; + let mut device_cfg = + ScsiCntlrConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + let bdf = PciBdf::new(device_cfg.bus.clone(), device_cfg.addr); + let multi_func = device_cfg.multifunction.unwrap_or_default(); + if device_cfg.num_queues.is_none() { + let queues_auto = VirtioPciDevice::virtio_pci_auto_queues_num( + 0, + vm_config.machine_config.nr_cpus, + MAX_VIRTIO_QUEUE, + ); + device_cfg.num_queues = Some(queues_auto as u32); + } let device = Arc::new(Mutex::new(ScsiCntlr::new(device_cfg.clone()))); let bus_name = format!("{}.0", device_cfg.id); scsi_cntlr_create_scsi_bus(&bus_name, &device)?; - let pci_dev = self - .add_virtio_pci_device(&device_cfg.id, &bdf, device.clone(), multi_func, false) + self.add_virtio_pci_device(&device_cfg.id, &bdf, device, multi_func, false) .with_context(|| "Failed to add virtio scsi controller")?; if !hotplug { self.reset_bus(&device_cfg.id)?; } - device.lock().unwrap().config.boot_prefix = pci_dev.lock().unwrap().get_dev_path(); Ok(()) } @@ -1140,6 +1142,7 @@ pub trait MachineOps { .get_pci_dev_by_id_and_type(vm_config, Some(&cntlr), "virtio-scsi-pci") .with_context(|| format!("Can not find scsi controller from pci bus {}", cntlr))?; let locked_pcidev = pci_dev.lock().unwrap(); + let prefix = locked_pcidev.get_dev_path().unwrap(); let virtio_pcidev = locked_pcidev .as_any() .downcast_ref::() @@ -1172,7 +1175,6 @@ pub trait MachineOps { // | | | channel(unused, fixed 0). // | PCI slot,[function] holding SCSI controller. // PCI root as system bus port. - let prefix = cntlr.config.boot_prefix.as_ref().unwrap(); let dev_path = format! {"{}/channel@0/disk@{:x},{:x}", prefix, device_cfg.target, device_cfg.lun}; self.add_bootindex_devices(bootindex, &dev_path, &device_cfg.id); diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index fd761414..b34540cb 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -40,7 +40,6 @@ mod ramfb; mod rng; #[cfg(feature = "vnc_auth")] mod sasl_auth; -mod scsi; mod smbios; #[cfg(feature = "vnc_auth")] mod tls_creds; @@ -73,7 +72,6 @@ pub use ramfb::*; pub use rng::*; #[cfg(feature = "vnc_auth")] pub use sasl_auth::*; -pub use scsi::*; pub use smbios::*; #[cfg(feature = "vnc_auth")] pub use tls_creds::*; @@ -112,6 +110,10 @@ pub const MAX_TAG_LENGTH: usize = 36; pub const MAX_NODES: u32 = 128; /// Default virtqueue size for virtio devices excepts virtio-fs. pub const DEFAULT_VIRTQUEUE_SIZE: u16 = 256; +// Seg_max = queue_size - 2. So, size of each virtqueue for virtio-scsi should be larger than 2. +pub const MIN_QUEUE_SIZE_SCSI: u64 = 2; +// Max size of each virtqueue for virtio-scsi. +pub const MAX_QUEUE_SIZE_SCSI: u64 = 1024; #[derive(Clone, Default, Debug, Serialize, Deserialize)] pub struct ObjectConfig { @@ -795,6 +797,25 @@ pub fn valid_id(id: &str) -> Result { Ok(id.to_string()) } +// Virtio queue size must be power of 2 and in range [min_size, max_size]. +pub fn valid_virtqueue_size(size: u64, min_size: u64, max_size: u64) -> Result<()> { + if size < min_size || size > max_size { + return Err(anyhow!(ConfigError::IllegalValue( + "virtqueue size".to_string(), + min_size, + true, + max_size, + true + ))); + } + + if size & (size - 1) != 0 { + bail!("Virtqueue size should be power of 2!"); + } + + Ok(()) +} + #[cfg(test)] mod tests { use super::*; diff --git a/machine_manager/src/config/scsi.rs b/machine_manager/src/config/scsi.rs deleted file mode 100644 index da3d1dbb..00000000 --- a/machine_manager/src/config/scsi.rs +++ /dev/null @@ -1,129 +0,0 @@ -// Copyright (c) 2022 Huawei Technologies Co.,Ltd. All rights reserved. -// -// StratoVirt is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan -// PSL v2. -// You may obtain a copy of Mulan PSL v2 at: -// http://license.coscl.org.cn/MulanPSL2 -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY -// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -// See the Mulan PSL v2 for more details. - -use anyhow::{anyhow, bail, Context, Result}; - -use super::{error::ConfigError, pci_args_check}; -use crate::config::{ - check_arg_too_long, CmdParser, ConfigCheck, DEFAULT_VIRTQUEUE_SIZE, MAX_VIRTIO_QUEUE, -}; - -// Seg_max = queue_size - 2. So, size of each virtqueue for virtio-scsi should be larger than 2. -const MIN_QUEUE_SIZE_SCSI: u16 = 2; -// Max size of each virtqueue for virtio-scsi. -const MAX_QUEUE_SIZE_SCSI: u16 = 1024; - -#[derive(Debug, Clone)] -pub struct ScsiCntlrConfig { - /// Virtio-scsi-pci device id. - pub id: String, - /// Thread name of io handler. - pub iothread: Option, - /// Number of scsi cmd queues. - pub queues: u32, - /// Boot path of this scsi controller. It's prefix of scsi device's boot path. - pub boot_prefix: Option, - /// Virtqueue size for all queues. - pub queue_size: u16, -} - -impl Default for ScsiCntlrConfig { - fn default() -> Self { - ScsiCntlrConfig { - id: "".to_string(), - iothread: None, - // At least 1 cmd queue. - queues: 1, - boot_prefix: None, - queue_size: DEFAULT_VIRTQUEUE_SIZE, - } - } -} - -impl ConfigCheck for ScsiCntlrConfig { - fn check(&self) -> Result<()> { - check_arg_too_long(&self.id, "virtio-scsi-pci device id")?; - - if self.iothread.is_some() { - check_arg_too_long(self.iothread.as_ref().unwrap(), "iothread name")?; - } - - if self.queues < 1 || self.queues > MAX_VIRTIO_QUEUE as u32 { - return Err(anyhow!(ConfigError::IllegalValue( - "queues number of scsi controller".to_string(), - 1, - true, - MAX_VIRTIO_QUEUE as u64, - true, - ))); - } - - if self.queue_size <= MIN_QUEUE_SIZE_SCSI || self.queue_size > MAX_QUEUE_SIZE_SCSI { - return Err(anyhow!(ConfigError::IllegalValue( - "virtqueue size of scsi controller".to_string(), - MIN_QUEUE_SIZE_SCSI as u64, - false, - MAX_QUEUE_SIZE_SCSI as u64, - true - ))); - } - - if self.queue_size & (self.queue_size - 1) != 0 { - bail!("Virtqueue size should be power of 2!"); - } - - Ok(()) - } -} - -pub fn parse_scsi_controller( - drive_config: &str, - queues_auto: Option, -) -> Result { - let mut cmd_parser = CmdParser::new("virtio-scsi-pci"); - cmd_parser - .push("") - .push("id") - .push("bus") - .push("addr") - .push("multifunction") - .push("iothread") - .push("num-queues") - .push("queue-size"); - - cmd_parser.parse(drive_config)?; - - pci_args_check(&cmd_parser)?; - - let mut cntlr_cfg = ScsiCntlrConfig::default(); - - if let Some(iothread) = cmd_parser.get_value::("iothread")? { - cntlr_cfg.iothread = Some(iothread); - } - - cntlr_cfg.id = cmd_parser.get_value::("id")?.with_context(|| { - ConfigError::FieldIsMissing("id".to_string(), "virtio scsi pci".to_string()) - })?; - - if let Some(queues) = cmd_parser.get_value::("num-queues")? { - cntlr_cfg.queues = queues; - } else if let Some(queues) = queues_auto { - cntlr_cfg.queues = queues as u32; - } - - if let Some(size) = cmd_parser.get_value::("queue-size")? { - cntlr_cfg.queue_size = size; - } - - cntlr_cfg.check()?; - Ok(cntlr_cfg) -} diff --git a/virtio/src/device/scsi_cntlr.rs b/virtio/src/device/scsi_cntlr.rs index 2cc15bcc..dc2d8f51 100644 --- a/virtio/src/device/scsi_cntlr.rs +++ b/virtio/src/device/scsi_cntlr.rs @@ -17,6 +17,7 @@ use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex}; use anyhow::{bail, Context, Result}; +use clap::Parser; use log::{error, info, warn}; use vmm_sys_util::{epoll::EventSet, eventfd::EventFd}; @@ -32,8 +33,11 @@ use devices::ScsiBus::{ ScsiBus, ScsiRequest, ScsiRequestOps, ScsiSense, ScsiXferMode, CHECK_CONDITION, EMULATE_SCSI_OPS, SCSI_CMD_BUF_SIZE, SCSI_SENSE_INVALID_OPCODE, }; -use machine_manager::event_loop::{register_event_helper, unregister_event_helper}; -use machine_manager::{config::ScsiCntlrConfig, event_loop::EventLoop}; +use machine_manager::config::{ + get_pci_df, parse_bool, valid_id, valid_virtqueue_size, MAX_QUEUE_SIZE_SCSI, MAX_VIRTIO_QUEUE, + MIN_QUEUE_SIZE_SCSI, +}; +use machine_manager::event_loop::{register_event_helper, unregister_event_helper, EventLoop}; use util::aio::Iovec; use util::byte_code::ByteCode; use util::loop_context::{ @@ -92,6 +96,34 @@ const VIRTIO_SCSI_S_BAD_TARGET: u8 = 3; /// with a response equal to VIRTIO_SCSI_S_FAILURE. const VIRTIO_SCSI_S_FAILURE: u8 = 9; +#[derive(Parser, Debug, Clone, Default)] +#[command(no_binary_name(true))] +pub struct ScsiCntlrConfig { + #[arg(long, value_parser = ["virtio-scsi-pci"])] + pub classtype: String, + #[arg(long, value_parser = valid_id)] + pub id: String, + #[arg(long)] + pub bus: String, + #[arg(long, value_parser = get_pci_df)] + pub addr: (u8, u8), + #[arg(long, value_parser = parse_bool)] + pub multifunction: Option, + #[arg(long, alias = "num-queues", value_parser = clap::value_parser!(u32).range(1..=MAX_VIRTIO_QUEUE as i64))] + pub num_queues: Option, + #[arg(long)] + pub iothread: Option, + #[arg(long, alias = "queue-size", default_value = "256", value_parser = valid_scsi_cntlr_queue_size)] + pub queue_size: u16, +} + +fn valid_scsi_cntlr_queue_size(s: &str) -> Result { + let size: u64 = s.parse()?; + valid_virtqueue_size(size, MIN_QUEUE_SIZE_SCSI + 1, MAX_QUEUE_SIZE_SCSI)?; + + Ok(size as u16) +} + #[repr(C, packed)] #[derive(Copy, Clone, Debug, Default)] struct VirtioScsiConfig { @@ -125,7 +157,8 @@ pub struct ScsiCntlr { impl ScsiCntlr { pub fn new(config: ScsiCntlrConfig) -> ScsiCntlr { // Note: config.queues <= MAX_VIRTIO_QUEUE(32). - let queue_num = config.queues as usize + SCSI_CTRL_QUEUE_NUM + SCSI_EVENT_QUEUE_NUM; + let queue_num = + config.num_queues.unwrap() as usize + SCSI_CTRL_QUEUE_NUM + SCSI_EVENT_QUEUE_NUM; let queue_size = config.queue_size; Self { @@ -168,7 +201,6 @@ impl VirtioDevice for ScsiCntlr { } fn init_config_features(&mut self) -> Result<()> { - self.config_space.num_queues = self.config.queues; self.config_space.max_sectors = 0xFFFF_u32; // cmd_per_lun: maximum number of linked commands can be sent to one LUN. 32bit. self.config_space.cmd_per_lun = 128; @@ -177,7 +209,7 @@ impl VirtioDevice for ScsiCntlr { self.config_space.max_target = VIRTIO_SCSI_MAX_TARGET; self.config_space.max_lun = VIRTIO_SCSI_MAX_LUN; // num_queues: request queues number. - self.config_space.num_queues = self.config.queues; + self.config_space.num_queues = self.config.num_queues.unwrap(); self.base.device_features |= (1_u64 << VIRTIO_F_VERSION_1) | (1_u64 << VIRTIO_F_RING_EVENT_IDX) @@ -969,3 +1001,55 @@ pub fn scsi_cntlr_create_scsi_bus( locked_scsi_cntlr.bus = Some(Arc::new(Mutex::new(bus))); Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + use machine_manager::config::str_slip_to_clap; + + #[test] + fn test_scsi_cntlr_config_cmdline_parser() { + // Test1: Right. + let cmdline1 = "virtio-scsi-pci,id=scsi0,bus=pcie.0,addr=0x3,multifunction=on,iothread=iothread1,num-queues=3,queue-size=128"; + let device_cfg = + ScsiCntlrConfig::try_parse_from(str_slip_to_clap(cmdline1, true, false)).unwrap(); + assert_eq!(device_cfg.id, "scsi0"); + assert_eq!(device_cfg.bus, "pcie.0"); + assert_eq!(device_cfg.addr, (3, 0)); + assert_eq!(device_cfg.multifunction, Some(true)); + assert_eq!(device_cfg.iothread.unwrap(), "iothread1"); + assert_eq!(device_cfg.num_queues.unwrap(), 3); + assert_eq!(device_cfg.queue_size, 128); + + // Test2: Default value. + let cmdline2 = "virtio-scsi-pci,id=scsi0,bus=pcie.0,addr=0x3.0x1"; + let device_cfg = + ScsiCntlrConfig::try_parse_from(str_slip_to_clap(cmdline2, true, false)).unwrap(); + assert_eq!(device_cfg.addr, (3, 1)); + assert_eq!(device_cfg.multifunction, None); + assert_eq!(device_cfg.num_queues, None); + assert_eq!(device_cfg.queue_size, 256); + + // Test3: Illegal value. + let cmdline3 = "virtio-scsi-pci,id=scsi0,bus=pcie.0,addr=0x3.0x1,num-queues=33"; + let result = ScsiCntlrConfig::try_parse_from(str_slip_to_clap(cmdline3, true, false)); + assert!(result.is_err()); + let cmdline3 = "virtio-scsi-pci,id=scsi0,bus=pcie.0,addr=0x3.0x1,queue-size=1025"; + let result = ScsiCntlrConfig::try_parse_from(str_slip_to_clap(cmdline3, true, false)); + assert!(result.is_err()); + let cmdline3 = "virtio-scsi-pci,id=scsi0,bus=pcie.0,addr=0x3.0x1,queue-size=65"; + let result = ScsiCntlrConfig::try_parse_from(str_slip_to_clap(cmdline3, true, false)); + assert!(result.is_err()); + + // Test4: Missing necessary parameters. + let cmdline4 = "virtio-scsi-pci,id=scsi0"; + let result = ScsiCntlrConfig::try_parse_from(str_slip_to_clap(cmdline4, true, false)); + assert!(result.is_err()); + let cmdline4 = "virtio-scsi-pci,bus=pcie.0,addr=0x3.0x1"; + let result = ScsiCntlrConfig::try_parse_from(str_slip_to_clap(cmdline4, true, false)); + assert!(result.is_err()); + let cmdline4 = "virtio-scsi-pci,id=scsi0,addr=0x3.0x1"; + let result = ScsiCntlrConfig::try_parse_from(str_slip_to_clap(cmdline4, true, false)); + assert!(result.is_err()); + } +} -- Gitee From d75edd31996612bacd7a8514f2fa8d0d65421362 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sun, 17 Mar 2024 23:18:50 +0800 Subject: [PATCH 017/489] chardev: use clap to parse the parameters of the chardev config Use clap to parse the parameters of the chardev config. Signed-off-by: liuxiangdong --- chardev_backend/src/chardev.rs | 92 +++--- devices/src/legacy/pl011.rs | 5 +- devices/src/legacy/serial.rs | 10 +- machine_manager/src/cmdline.rs | 64 ++-- machine_manager/src/config/chardev.rs | 430 ++++++++++---------------- machine_manager/src/config/drive.rs | 16 +- machine_manager/src/config/fs.rs | 40 ++- machine_manager/src/config/mod.rs | 31 +- virtio/src/device/serial.rs | 5 +- 9 files changed, 295 insertions(+), 398 deletions(-) diff --git a/chardev_backend/src/chardev.rs b/chardev_backend/src/chardev.rs index 7a07a78a..3f34fc61 100644 --- a/chardev_backend/src/chardev.rs +++ b/chardev_backend/src/chardev.rs @@ -28,7 +28,7 @@ use vmm_sys_util::epoll::EventSet; use machine_manager::event_loop::EventLoop; use machine_manager::machine::{PathInfo, PTY_PATH}; use machine_manager::{ - config::{ChardevConfig, ChardevType}, + config::{ChardevConfig, ChardevType, SocketType}, temp_cleaner::TempCleaner, }; use util::file::clear_file; @@ -90,8 +90,8 @@ pub struct Chardev { impl Chardev { pub fn new(chardev_cfg: ChardevConfig) -> Self { Chardev { - id: chardev_cfg.id, - backend: chardev_cfg.backend, + id: chardev_cfg.id(), + backend: chardev_cfg.classtype, listener: None, input: None, output: None, @@ -105,12 +105,12 @@ impl Chardev { pub fn realize(&mut self) -> Result<()> { match &self.backend { - ChardevType::Stdio => { + ChardevType::Stdio { .. } => { set_termi_raw_mode().with_context(|| "Failed to set terminal to raw mode")?; self.input = Some(Arc::new(Mutex::new(std::io::stdin()))); self.output = Some(Arc::new(Mutex::new(std::io::stdout()))); } - ChardevType::Pty => { + ChardevType::Pty { .. } => { let (master, path) = set_pty_raw_mode().with_context(|| "Failed to set pty to raw mode")?; info!("Pty path is: {:?}", path); @@ -125,58 +125,43 @@ impl Chardev { self.input = Some(master_arc.clone()); self.output = Some(master_arc); } - ChardevType::UnixSocket { - path, - server, - nowait, - } => { + ChardevType::Socket { server, nowait, .. } => { if !*server || !*nowait { bail!( "Argument \'server\' and \'nowait\' are both required for chardev \'{}\'", &self.id ); } - - clear_file(path.clone())?; - let listener = SocketListener::bind_by_uds(path).with_context(|| { - format!( - "Failed to bind socket for chardev \'{}\', path: {}", - &self.id, path - ) - })?; - self.listener = Some(listener); - - // add file to temporary pool, so it could be cleaned when vm exit. - TempCleaner::add_path(path.clone()); - limit_permission(path).with_context(|| { - format!( - "Failed to change file permission for chardev \'{}\', path: {}", - &self.id, path - ) - })?; - } - ChardevType::TcpSocket { - host, - port, - server, - nowait, - } => { - if !*server || !*nowait { - bail!( - "Argument \'server\' and \'nowait\' are both required for chardev \'{}\'", - &self.id - ); + let socket_type = self.backend.socket_type()?; + if let SocketType::Tcp { host, port } = socket_type { + let listener = SocketListener::bind_by_tcp(&host, port).with_context(|| { + format!( + "Failed to bind socket for chardev \'{}\', address: {}:{}", + &self.id, host, port + ) + })?; + self.listener = Some(listener); + } else if let SocketType::Unix { path } = socket_type { + clear_file(path.clone())?; + let listener = SocketListener::bind_by_uds(&path).with_context(|| { + format!( + "Failed to bind socket for chardev \'{}\', path: {}", + &self.id, path + ) + })?; + self.listener = Some(listener); + + // add file to temporary pool, so it could be cleaned when vm exit. + TempCleaner::add_path(path.clone()); + limit_permission(&path).with_context(|| { + format!( + "Failed to change file permission for chardev \'{}\', path: {}", + &self.id, path + ) + })?; } - - let listener = SocketListener::bind_by_tcp(host, *port).with_context(|| { - format!( - "Failed to bind socket for chardev \'{}\', address: {}:{}", - &self.id, host, port - ) - })?; - self.listener = Some(listener); } - ChardevType::File(path) => { + ChardevType::File { path, .. } => { let file = Arc::new(Mutex::new( OpenOptions::new() .read(true) @@ -510,11 +495,10 @@ impl EventNotifierHelper for Chardev { let notifier = { let backend = chardev.lock().unwrap().backend.clone(); match backend { - ChardevType::Stdio => get_terminal_notifier(chardev), - ChardevType::Pty => get_terminal_notifier(chardev), - ChardevType::UnixSocket { .. } => get_socket_notifier(chardev), - ChardevType::TcpSocket { .. } => get_socket_notifier(chardev), - ChardevType::File(_) => None, + ChardevType::Stdio { .. } => get_terminal_notifier(chardev), + ChardevType::Pty { .. } => get_terminal_notifier(chardev), + ChardevType::Socket { .. } => get_socket_notifier(chardev), + ChardevType::File { .. } => None, } }; notifier.map_or(Vec::new(), |value| vec![value]) diff --git a/devices/src/legacy/pl011.rs b/devices/src/legacy/pl011.rs index 24a34ef8..afe1e540 100644 --- a/devices/src/legacy/pl011.rs +++ b/devices/src/legacy/pl011.rs @@ -486,8 +486,9 @@ mod test { #[test] fn test_receive() { let chardev_cfg = ChardevConfig { - id: "chardev".to_string(), - backend: ChardevType::Stdio, + classtype: ChardevType::Stdio { + id: "chardev".to_string(), + }, }; let mut pl011_dev = PL011::new(SerialConfig { chardev: chardev_cfg, diff --git a/devices/src/legacy/serial.rs b/devices/src/legacy/serial.rs index 7c5b9072..8b096f09 100644 --- a/devices/src/legacy/serial.rs +++ b/devices/src/legacy/serial.rs @@ -490,8 +490,9 @@ mod test { fn test_methods_of_serial() { // test new method let chardev_cfg = ChardevConfig { - id: "chardev".to_string(), - backend: ChardevType::Stdio, + classtype: ChardevType::Stdio { + id: "chardev".to_string(), + }, }; let mut usart = Serial::new(SerialConfig { chardev: chardev_cfg.clone(), @@ -545,8 +546,9 @@ mod test { #[test] fn test_serial_migration_interface() { let chardev_cfg = ChardevConfig { - id: "chardev".to_string(), - backend: ChardevType::Stdio, + classtype: ChardevType::Stdio { + id: "chardev".to_string(), + }, }; let mut usart = Serial::new(SerialConfig { chardev: chardev_cfg, diff --git a/machine_manager/src/cmdline.rs b/machine_manager/src/cmdline.rs index 5b0d2751..65907018 100644 --- a/machine_manager/src/cmdline.rs +++ b/machine_manager/src/cmdline.rs @@ -13,7 +13,7 @@ use anyhow::{bail, Context, Result}; use crate::{ - config::{parse_trace_options, ChardevType, CmdParser, MachineType, VmConfig}, + config::{parse_trace_options, ChardevType, CmdParser, MachineType, SocketType, VmConfig}, qmp::qmp_socket::QmpSocketPath, temp_cleaner::TempCleaner, }; @@ -641,47 +641,33 @@ pub fn check_api_channel( .get_value::("chardev")? .with_context(|| "Argument \'chardev\' is missing for \'mon\'")?; - if let Some(mode) = cmd_parser.get_value::("mode")? { - if mode != *"control" { - bail!("Invalid \'mode\' parameter: {:?} for monitor", &mode); - } - } else { - bail!("Argument \'mode\' of \'mon\' should be set to \'control\'."); + let mode = cmd_parser + .get_value::("mode")? + .with_context(|| "Argument \'mode\' of \'mon\' should be set to \'control\'.")?; + if mode != "control" { + bail!("Invalid \'mode\' parameter: {:?} for monitor", &mode); } - if let Some(cfg) = vm_config.chardev.remove(&chardev) { - if let ChardevType::UnixSocket { - path, - server, - nowait, - } = cfg.backend - { - if !server || !nowait { - bail!( - "Argument \'server\' and \'nowait\' are both required for chardev \'{}\'", - path - ); - } - sock_paths.push(QmpSocketPath::Unix { path }); - } else if let ChardevType::TcpSocket { - host, - port, - server, - nowait, - } = cfg.backend - { - if !server || !nowait { - bail!( - "Argument \'server\' and \'nowait\' are both required for chardev \'{}:{}\'", - host, port - ); - } - sock_paths.push(QmpSocketPath::Tcp { host, port }); - } else { - bail!("Only chardev of unix-socket type can be used for monitor"); + let cfg = vm_config + .chardev + .remove(&chardev) + .with_context(|| format!("No chardev found: {}", &chardev))?; + let socket = cfg + .classtype + .socket_type() + .with_context(|| "Only chardev of unix-socket type can be used for monitor")?; + if let ChardevType::Socket { server, nowait, .. } = cfg.classtype { + if !server || !nowait { + bail!( + "Argument \'server\' and \'nowait\' are both required for chardev \'{}\'", + cfg.id() + ); } - } else { - bail!("No chardev found: {}", &chardev); + } + if let SocketType::Tcp { host, port } = socket { + sock_paths.push(QmpSocketPath::Tcp { host, port }); + } else if let SocketType::Unix { path } = socket { + sock_paths.push(QmpSocketPath::Unix { path }); } } diff --git a/machine_manager/src/config/chardev.rs b/machine_manager/src/config/chardev.rs index 943de721..f5ea6067 100644 --- a/machine_manager/src/config/chardev.rs +++ b/machine_manager/src/config/chardev.rs @@ -14,12 +14,14 @@ use std::net::IpAddr; use std::str::FromStr; use anyhow::{anyhow, bail, Context, Result}; +use clap::{ArgAction, Parser, Subcommand}; use log::error; use serde::{Deserialize, Serialize}; -use super::{error::ConfigError, get_pci_bdf, pci_args_check, PciBdf}; +use super::{error::ConfigError, get_pci_bdf, pci_args_check, str_slip_to_clap, PciBdf}; use crate::config::{ - check_arg_too_long, CmdParser, ConfigCheck, ExBool, VmConfig, MAX_PATH_LENGTH, + check_arg_too_long, valid_id, valid_path, valid_socket_path, CmdParser, ConfigCheck, ExBool, + VmConfig, }; use crate::qmp::qmp_schema; @@ -29,25 +31,6 @@ const MIN_GUEST_CID: u64 = 3; /// Default value of max ports for virtio-serial. const DEFAULT_SERIAL_PORTS_NUMBER: u32 = 31; -/// Character device options. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] -pub enum ChardevType { - Stdio, - Pty, - UnixSocket { - path: String, - server: bool, - nowait: bool, - }, - TcpSocket { - host: String, - port: u16, - server: bool, - nowait: bool, - }, - File(String), -} - /// Config structure for virtio-serial-port. #[derive(Debug, Clone)] pub struct VirtioSerialPort { @@ -64,198 +47,107 @@ impl ConfigCheck for VirtioSerialPort { } /// Config structure for character device. -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Parser, Debug, Clone, Serialize, Deserialize)] +#[command(no_binary_name(true))] pub struct ChardevConfig { - pub id: String, - pub backend: ChardevType, + #[command(subcommand)] + pub classtype: ChardevType, } -impl ConfigCheck for ChardevConfig { - fn check(&self) -> Result<()> { - check_arg_too_long(&self.id, "chardev id")?; - match &self.backend { - ChardevType::UnixSocket { path, .. } => { - if path.len() > MAX_PATH_LENGTH { - return Err(anyhow!(ConfigError::StringLengthTooLong( - "unix-socket path".to_string(), - MAX_PATH_LENGTH - ))); - } - Ok(()) - } - ChardevType::TcpSocket { host, port, .. } => { - if *port == 0u16 { - return Err(anyhow!(ConfigError::InvalidParam( - "port".to_string(), - "tcp-socket".to_string() - ))); - } - let ip_address = IpAddr::from_str(host); - if ip_address.is_err() { - return Err(anyhow!(ConfigError::InvalidParam( - "host".to_string(), - "tcp-socket".to_string() - ))); - } - Ok(()) - } - ChardevType::File(path) => { - if path.len() > MAX_PATH_LENGTH { - return Err(anyhow!(ConfigError::StringLengthTooLong( - "file path".to_string(), - MAX_PATH_LENGTH - ))); - } - Ok(()) - } - _ => Ok(()), +impl ChardevConfig { + pub fn id(&self) -> String { + match &self.classtype { + ChardevType::Stdio { id } => id, + ChardevType::Pty { id } => id, + ChardevType::Socket { id, .. } => id, + ChardevType::File { id, .. } => id, } + .clone() } } -fn check_chardev_fields( - dev_type: &str, - cmd_parser: &CmdParser, - supported_fields: &[&str], -) -> Result<()> { - for (field, value) in &cmd_parser.params { - let supported_field = supported_fields.contains(&field.as_str()); - if !supported_field && value.is_some() { - bail!( - "Chardev of type {} does not support \'{}\' argument", - dev_type, - field - ); +impl ConfigCheck for ChardevConfig { + fn check(&self) -> Result<()> { + if let ChardevType::Socket { .. } = self.classtype { + self.classtype.socket_type()?; } - } - Ok(()) -} - -fn parse_stdio_chardev(chardev_id: String, cmd_parser: CmdParser) -> Result { - let supported_fields = ["", "id"]; - check_chardev_fields("stdio", &cmd_parser, &supported_fields)?; - Ok(ChardevConfig { - id: chardev_id, - backend: ChardevType::Stdio, - }) -} -fn parse_pty_chardev(chardev_id: String, cmd_parser: CmdParser) -> Result { - let supported_fields = ["", "id"]; - check_chardev_fields("pty", &cmd_parser, &supported_fields)?; - Ok(ChardevConfig { - id: chardev_id, - backend: ChardevType::Pty, - }) + Ok(()) + } } -fn parse_file_chardev(chardev_id: String, cmd_parser: CmdParser) -> Result { - let supported_fields = ["", "id", "path"]; - check_chardev_fields("file", &cmd_parser, &supported_fields)?; - - let path = cmd_parser - .get_value::("path")? - .with_context(|| ConfigError::FieldIsMissing("path".to_string(), "chardev".to_string()))?; - - let default_value = path.clone(); - let file_path = std::fs::canonicalize(path).map_or(default_value, |canonical_path| { - String::from(canonical_path.to_str().unwrap()) - }); - - Ok(ChardevConfig { - id: chardev_id, - backend: ChardevType::File(file_path), - }) +/// Character device options. +#[derive(Subcommand, Debug, Clone, PartialEq, Eq, Serialize, Deserialize)] +pub enum ChardevType { + Stdio { + #[arg(long, value_parser = valid_id)] + id: String, + }, + Pty { + #[arg(long, value_parser = valid_id)] + id: String, + }, + // Unix Socket: use `path`. + // Tcp Socket: use `host` and `port`. + #[clap(group = clap::ArgGroup::new("unix-socket").args(&["host", "port"]).requires("port").multiple(true).conflicts_with("tcp-socket"))] + #[clap(group = clap::ArgGroup::new("tcp-socket").arg("path").conflicts_with("unix-socket"))] + Socket { + #[arg(long, value_parser = valid_id)] + id: String, + #[arg(long, value_parser = valid_socket_path)] + path: Option, + #[arg(long, value_parser = valid_host, default_value = "0.0.0.0")] + host: String, + #[arg(long, value_parser = clap::value_parser!(u16).range(1..))] + port: Option, + #[arg(long, action = ArgAction::SetTrue)] + server: bool, + #[arg(long, action = ArgAction::SetTrue)] + nowait: bool, + }, + File { + #[arg(long, value_parser = valid_id)] + id: String, + #[arg(long, value_parser = valid_path)] + path: String, + }, } -fn parse_socket_chardev(chardev_id: String, cmd_parser: CmdParser) -> Result { - let mut server_enabled = false; - let server = cmd_parser.get_value::("server")?; - if let Some(server) = server { - if server.ne("") { - bail!("No parameter needed for server"); - } - server_enabled = true; - } - - let mut nowait_enabled = false; - let nowait = cmd_parser.get_value::("nowait")?; - if let Some(nowait) = nowait { - if nowait.ne("") { - bail!("No parameter needed for nowait"); +impl ChardevType { + pub fn socket_type(&self) -> Result { + if let ChardevType::Socket { + path, host, port, .. + } = self + { + if path.is_some() && port.is_none() { + return Ok(SocketType::Unix { + path: path.clone().unwrap(), + }); + } else if port.is_some() && path.is_none() { + return Ok(SocketType::Tcp { + host: host.clone(), + port: (*port).unwrap(), + }); + } } - nowait_enabled = true; - } - - let path = cmd_parser.get_value::("path")?; - if let Some(path) = path { - let supported_fields = ["", "id", "path", "server", "nowait"]; - check_chardev_fields("unix-socket", &cmd_parser, &supported_fields)?; - - let default_value = path.clone(); - let socket_path = std::fs::canonicalize(path).map_or(default_value, |canonical_path| { - String::from(canonical_path.to_str().unwrap()) - }); - - return Ok(ChardevConfig { - id: chardev_id, - backend: ChardevType::UnixSocket { - path: socket_path, - server: server_enabled, - nowait: nowait_enabled, - }, - }); - } - - let port = cmd_parser.get_value::("port")?; - if let Some(port) = port { - let supported_fields = ["", "id", "host", "port", "server", "nowait"]; - check_chardev_fields("tcp-socket", &cmd_parser, &supported_fields)?; - - let host = cmd_parser.get_value::("host")?; - return Ok(ChardevConfig { - id: chardev_id, - backend: ChardevType::TcpSocket { - host: host.unwrap_or_else(|| String::from("0.0.0.0")), - port, - server: server_enabled, - nowait: nowait_enabled, - }, - }); + bail!("Not socket type or invalid socket type"); } - - Err(anyhow!(ConfigError::InvalidParam( - "backend".to_string(), - "chardev".to_string() - ))) } -pub fn parse_chardev(chardev_config: &str) -> Result { - let mut cmd_parser = CmdParser::new("chardev"); - for field in ["", "id", "path", "host", "port", "server", "nowait"] { - cmd_parser.push(field); - } - - cmd_parser.parse(chardev_config)?; +pub enum SocketType { + Unix { path: String }, + Tcp { host: String, port: u16 }, +} - let chardev_id = cmd_parser - .get_value::("id")? - .with_context(|| ConfigError::FieldIsMissing("id".to_string(), "chardev".to_string()))?; - - let backend = cmd_parser - .get_value::("")? - .with_context(|| ConfigError::InvalidParam("backend".to_string(), "chardev".to_string()))?; - - match backend.as_str() { - "stdio" => parse_stdio_chardev(chardev_id, cmd_parser), - "pty" => parse_pty_chardev(chardev_id, cmd_parser), - "file" => parse_file_chardev(chardev_id, cmd_parser), - "socket" => parse_socket_chardev(chardev_id, cmd_parser), - _ => Err(anyhow!(ConfigError::InvalidParam( - backend, - "chardev".to_string() - ))), +fn valid_host(host: &str) -> Result { + let ip_address = IpAddr::from_str(host); + if ip_address.is_err() { + return Err(anyhow!(ConfigError::InvalidParam( + "host".to_string(), + "tcp-socket".to_string() + ))); } + Ok(host.to_string()) } /// Get chardev config from qmp arguments. @@ -291,9 +183,11 @@ pub fn get_chardev_config(args: qmp_schema::CharDevAddArgument) -> Result Result Result { - if let Some(char_dev) = vm_config.chardev.remove(chardev) { - match char_dev.backend.clone() { - ChardevType::UnixSocket { - path, - server, - nowait, - } => { - if server || nowait { - bail!( - "Argument \'server\' or \'nowait\' is not need for chardev \'{}\'", - path - ); - } - Ok(path) - } - _ => { - bail!( - "Chardev {:?} backend should be unix-socket type.", - &char_dev.id - ); - } + let char_dev = vm_config + .chardev + .remove(chardev) + .with_context(|| format!("Chardev: {:?} not found for character device", chardev))?; + if let ChardevType::Socket { + path, + server, + nowait, + .. + } = char_dev.classtype + { + path.clone().with_context(|| { + format!("Chardev {:?} backend should be unix-socket type.", chardev) + })?; + if server || nowait { + bail!( + "Argument \'server\' or \'nowait\' is not need for chardev \'{}\'", + path.unwrap() + ); } - } else { - bail!("Chardev: {:?} not found for character device", &chardev); + return Ok(path.unwrap()); } + bail!("Chardev {:?} backend should be unix-socket type.", chardev); } pub fn parse_virtserialport( @@ -378,14 +270,9 @@ pub fn parse_virtserialport( impl VmConfig { /// Add chardev config to `VmConfig`. pub fn add_chardev(&mut self, chardev_config: &str) -> Result<()> { - let chardev = parse_chardev(chardev_config)?; + let chardev = ChardevConfig::try_parse_from(str_slip_to_clap(chardev_config, true, true))?; chardev.check()?; - let chardev_id = chardev.id.clone(); - if self.chardev.get(&chardev_id).is_none() { - self.chardev.insert(chardev_id, chardev); - } else { - bail!("Chardev {:?} has been added", &chardev_id); - } + self.add_chardev_with_config(chardev)?; Ok(()) } @@ -395,16 +282,11 @@ impl VmConfig { /// /// * `conf` - The chardev config to be added to the vm. pub fn add_chardev_with_config(&mut self, conf: ChardevConfig) -> Result<()> { - if let Err(e) = conf.check() { - bail!("Chardev config checking failed, {}", e.to_string()); - } - - let chardev_id = conf.id.clone(); - if self.chardev.get(&chardev_id).is_none() { - self.chardev.insert(chardev_id, conf); - } else { + let chardev_id = conf.id(); + if self.chardev.get(&chardev_id).is_some() { bail!("Chardev {:?} has been added", chardev_id); } + self.chardev.insert(chardev_id, conf); Ok(()) } @@ -414,11 +296,9 @@ impl VmConfig { /// /// * `id` - The chardev id which is used to delete chardev config. pub fn del_chardev_by_id(&mut self, id: &str) -> Result<()> { - if self.chardev.get(id).is_some() { - self.chardev.remove(id); - } else { - bail!("Chardev {} not found", id); - } + self.chardev + .remove(id) + .with_context(|| format!("Chardev {} not found", id))?; Ok(()) } } @@ -609,7 +489,7 @@ mod tests { let console_cfg = virt_console.unwrap(); assert_eq!(console_cfg.id, "console1"); - assert_eq!(console_cfg.chardev.backend, expected_chardev); + assert_eq!(console_cfg.chardev.classtype, expected_chardev); let mut vm_config = VmConfig::default(); assert!( @@ -639,8 +519,11 @@ mod tests { #[test] fn test_mmio_console_config_cmdline_parser_1() { let chardev_cfg = "socket,id=test_console,path=/path/to/socket,server,nowait"; - let expected_chardev = ChardevType::UnixSocket { - path: "/path/to/socket".to_string(), + let expected_chardev = ChardevType::Socket { + id: "test_console".to_string(), + path: Some("/path/to/socket".to_string()), + host: "0.0.0.0".to_string(), + port: None, server: true, nowait: true, }; @@ -650,9 +533,11 @@ mod tests { #[test] fn test_mmio_console_config_cmdline_parser_2() { let chardev_cfg = "socket,id=test_console,host=127.0.0.1,port=9090,server,nowait"; - let expected_chardev = ChardevType::TcpSocket { + let expected_chardev = ChardevType::Socket { + id: "test_console".to_string(), + path: None, host: "127.0.0.1".to_string(), - port: 9090, + port: Some(9090), server: true, nowait: true, }; @@ -681,7 +566,7 @@ mod tests { let bdf = serial_info.pci_bdf.unwrap(); assert_eq!(bdf.bus, "pcie.0"); assert_eq!(bdf.addr, (1, 2)); - assert_eq!(console_cfg.chardev.backend, expected_chardev); + assert_eq!(console_cfg.chardev.classtype, expected_chardev); let mut vm_config = VmConfig::default(); assert!(parse_virtio_serial( @@ -694,8 +579,11 @@ mod tests { #[test] fn test_pci_console_config_cmdline_parser_1() { let chardev_cfg = "socket,id=test_console,path=/path/to/socket,server,nowait"; - let expected_chardev = ChardevType::UnixSocket { - path: "/path/to/socket".to_string(), + let expected_chardev = ChardevType::Socket { + id: "test_console".to_string(), + path: Some("/path/to/socket".to_string()), + host: "0.0.0.0".to_string(), + port: None, server: true, nowait: true, }; @@ -705,9 +593,11 @@ mod tests { #[test] fn test_pci_console_config_cmdline_parser_2() { let chardev_cfg = "socket,id=test_console,host=127.0.0.1,port=9090,server,nowait"; - let expected_chardev = ChardevType::TcpSocket { + let expected_chardev = ChardevType::Socket { + id: "test_console".to_string(), + path: None, host: "127.0.0.1".to_string(), - port: 9090, + port: Some(9090), server: true, nowait: true, }; @@ -744,17 +634,30 @@ mod tests { let device_id = "test_id"; if let Some(char_dev) = vm_config.chardev.remove(device_id) { - assert_eq!(char_dev.backend, expect); + assert_eq!(char_dev.classtype, expect); } else { assert!(false); } }; - check_argument("stdio,id=test_id".to_string(), ChardevType::Stdio); - check_argument("pty,id=test_id".to_string(), ChardevType::Pty); + check_argument( + "stdio,id=test_id".to_string(), + ChardevType::Stdio { + id: "test_id".to_string(), + }, + ); + check_argument( + "pty,id=test_id".to_string(), + ChardevType::Pty { + id: "test_id".to_string(), + }, + ); check_argument( "file,id=test_id,path=/some/file".to_string(), - ChardevType::File("/some/file".to_string()), + ChardevType::File { + id: "test_id".to_string(), + path: "/some/file".to_string(), + }, ); let extra_params = [ @@ -767,17 +670,22 @@ mod tests { for (param, server_state, nowait_state) in extra_params { check_argument( format!("{}{}", "socket,id=test_id,path=/path/to/socket", param), - ChardevType::UnixSocket { - path: "/path/to/socket".to_string(), + ChardevType::Socket { + id: "test_id".to_string(), + path: Some("/path/to/socket".to_string()), + host: "0.0.0.0".to_string(), + port: None, server: server_state, nowait: nowait_state, }, ); check_argument( format!("{}{}", "socket,id=test_id,port=9090", param), - ChardevType::TcpSocket { + ChardevType::Socket { + id: "test_id".to_string(), + path: None, host: "0.0.0.0".to_string(), - port: 9090, + port: Some(9090), server: server_state, nowait: nowait_state, }, @@ -787,9 +695,11 @@ mod tests { "{}{}", "socket,id=test_id,host=172.56.16.12,port=7070", param ), - ChardevType::TcpSocket { + ChardevType::Socket { + id: "test_id".to_string(), + path: None, host: "172.56.16.12".to_string(), - port: 7070, + port: Some(7070), server: server_state, nowait: nowait_state, }, diff --git a/machine_manager/src/config/drive.rs b/machine_manager/src/config/drive.rs index 3e787c0c..a58d0012 100644 --- a/machine_manager/src/config/drive.rs +++ b/machine_manager/src/config/drive.rs @@ -20,12 +20,12 @@ use clap::{ArgAction, Parser}; use log::error; use serde::{Deserialize, Serialize}; -use super::valid_id; use super::{error::ConfigError, pci_args_check, M}; +use super::{valid_id, valid_path}; use crate::config::{ check_arg_too_long, get_chardev_socket_path, memory_unit_conversion, parse_bool, - str_slip_to_clap, CmdParser, ConfigCheck, VmConfig, DEFAULT_VIRTQUEUE_SIZE, MAX_PATH_LENGTH, - MAX_STRING_LENGTH, MAX_VIRTIO_QUEUE, + str_slip_to_clap, CmdParser, ConfigCheck, VmConfig, DEFAULT_VIRTQUEUE_SIZE, MAX_STRING_LENGTH, + MAX_VIRTIO_QUEUE, }; use util::aio::{aio_probe, AioEngine, WriteZeroesState}; @@ -179,16 +179,6 @@ fn valid_refcount_cache_size(s: &str) -> Result { Ok(size) } -fn valid_path(path: &str) -> Result { - if path.len() > MAX_PATH_LENGTH { - return Err(anyhow!(ConfigError::StringLengthTooLong( - "Drive device path".to_string(), - MAX_PATH_LENGTH, - ))); - } - Ok(path.to_string()) -} - /// Config struct for `drive`, including `block drive` and `pflash drive`. #[derive(Parser, Debug, Clone, Default, Serialize, Deserialize)] #[command(no_binary_name(true))] diff --git a/machine_manager/src/config/fs.rs b/machine_manager/src/config/fs.rs index e1a16ab3..6900888f 100644 --- a/machine_manager/src/config/fs.rs +++ b/machine_manager/src/config/fs.rs @@ -12,10 +12,10 @@ use anyhow::{anyhow, bail, Context, Result}; -use super::error::ConfigError; +use super::{error::ConfigError, SocketType}; use crate::config::{ - pci_args_check, ChardevType, CmdParser, ConfigCheck, VmConfig, MAX_SOCK_PATH_LENGTH, - MAX_STRING_LENGTH, MAX_TAG_LENGTH, + pci_args_check, CmdParser, ConfigCheck, VmConfig, MAX_SOCK_PATH_LENGTH, MAX_STRING_LENGTH, + MAX_TAG_LENGTH, }; /// Config struct for `fs`. @@ -90,26 +90,22 @@ pub fn parse_fs(vm_config: &mut VmConfig, fs_config: &str) -> Result { ..Default::default() }; - if let Some(name) = cmd_parser.get_value::("chardev")? { - if let Some(char_dev) = vm_config.chardev.remove(&name) { - match &char_dev.backend { - ChardevType::UnixSocket { path, .. } => { - fs_cfg.sock = path.clone(); - } - _ => { - bail!("Chardev {:?} backend should be unix-socket type.", &name); - } - } - } else { - bail!("Chardev {:?} not found or is in use", &name); + let name = cmd_parser + .get_value::("chardev")? + .with_context(|| { + ConfigError::FieldIsMissing("chardev".to_string(), "virtio-fs".to_string()) + })?; + let char_dev = vm_config + .chardev + .remove(&name) + .with_context(|| format!("Chardev {:?} not found or is in use", &name))?; + match char_dev.classtype.socket_type()? { + SocketType::Unix { path } => { + fs_cfg.sock = path; } - } else { - return Err(anyhow!(ConfigError::FieldIsMissing( - "chardev".to_string(), - "virtio-fs".to_string() - ))); - } - fs_cfg.check()?; + _ => bail!("Chardev {:?} backend should be unix-socket type.", &name), + }; + fs_cfg.check()?; Ok(fs_cfg) } diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index b34540cb..411dc3ff 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -80,7 +80,7 @@ pub use vfio::*; pub use vnc::*; use std::collections::HashMap; -use std::fs::File; +use std::fs::{canonicalize, File}; use std::io::Read; use std::str::FromStr; @@ -179,12 +179,12 @@ impl VmConfig { let mut stdio_count = 0; if let Some(serial) = self.serial.as_ref() { - if serial.chardev.backend == ChardevType::Stdio { + if let ChardevType::Stdio { .. } = serial.chardev.classtype { stdio_count += 1; } } for (_, char_dev) in self.chardev.clone() { - if char_dev.backend == ChardevType::Stdio { + if let ChardevType::Stdio { .. } = char_dev.classtype { stdio_count += 1; } } @@ -816,6 +816,31 @@ pub fn valid_virtqueue_size(size: u64, min_size: u64, max_size: u64) -> Result<( Ok(()) } +pub fn valid_path(path: &str) -> Result { + if path.len() > MAX_PATH_LENGTH { + return Err(anyhow!(ConfigError::StringLengthTooLong( + "path".to_string(), + MAX_PATH_LENGTH, + ))); + } + + let canonical_path = canonicalize(path).map_or(path.to_string(), |pathbuf| { + String::from(pathbuf.to_str().unwrap()) + }); + + Ok(canonical_path) +} + +pub fn valid_socket_path(sock_path: &str) -> Result { + if sock_path.len() > MAX_SOCK_PATH_LENGTH { + return Err(anyhow!(ConfigError::StringLengthTooLong( + "socket path".to_string(), + MAX_SOCK_PATH_LENGTH, + ))); + } + valid_path(sock_path) +} + #[cfg(test)] mod tests { use super::*; diff --git a/virtio/src/device/serial.rs b/virtio/src/device/serial.rs index 5bf1c101..57955619 100644 --- a/virtio/src/device/serial.rs +++ b/virtio/src/device/serial.rs @@ -357,7 +357,10 @@ impl SerialPort { pub fn new(port_cfg: VirtioSerialPort) -> Self { // Console is default host connected. And pty chardev has opened by default in realize() // function. - let host_connected = port_cfg.is_console || port_cfg.chardev.backend == ChardevType::Pty; + let mut host_connected = port_cfg.is_console; + if let ChardevType::Pty { .. } = port_cfg.chardev.classtype { + host_connected = true; + } SerialPort { name: Some(port_cfg.id), -- Gitee From 877cda59d3869dcdcab3f93addc72e3c7582184a Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 21 Mar 2024 12:45:15 +0800 Subject: [PATCH 018/489] vfio: use clap to parse the parameters of the vfio config Use clap to parse the parameters of the vfio config. Signed-off-by: liuxiangdong --- Cargo.lock | 1 + machine/src/lib.rs | 53 ++++-------- machine_manager/src/config/mod.rs | 2 - machine_manager/src/config/vfio.rs | 134 ----------------------------- vfio/Cargo.toml | 1 + vfio/src/lib.rs | 2 +- vfio/src/vfio_pci.rs | 57 ++++++++++++ 7 files changed, 78 insertions(+), 172 deletions(-) delete mode 100644 machine_manager/src/config/vfio.rs diff --git a/Cargo.lock b/Cargo.lock index b53bd7ae..dfcfbe29 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1855,6 +1855,7 @@ dependencies = [ "address_space", "anyhow", "byteorder", + "clap", "devices", "hypervisor", "kvm-bindings", diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 6b0be7df..86ae94e4 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -81,10 +81,10 @@ use machine_manager::config::parse_pvpanic; use machine_manager::config::{ complete_numa_node, get_multi_function, get_pci_bdf, parse_blk, parse_device_id, parse_device_type, parse_fs, parse_net, parse_numa_distance, parse_numa_mem, parse_rng_dev, - parse_root_port, parse_vfio, parse_vhost_user_blk, parse_virtio_serial, parse_virtserialport, - parse_vsock, str_slip_to_clap, BootIndexInfo, BootSource, DriveConfig, DriveFile, Incoming, + parse_root_port, parse_vhost_user_blk, parse_virtio_serial, parse_virtserialport, parse_vsock, + str_slip_to_clap, BootIndexInfo, BootSource, DriveConfig, DriveFile, Incoming, MachineMemConfig, MigrateMode, NumaConfig, NumaDistance, NumaNode, NumaNodes, PciBdf, - SerialConfig, VfioConfig, VmConfig, FAST_UNPLUG_ON, MAX_VIRTIO_QUEUE, + SerialConfig, VmConfig, FAST_UNPLUG_ON, MAX_VIRTIO_QUEUE, }; use machine_manager::event_loop::EventLoop; use machine_manager::machine::{HypervisorType, MachineInterface, VmState}; @@ -96,7 +96,7 @@ use util::{ arg_parser, seccomp::{BpfRule, SeccompOpt, SyscallFilter}, }; -use vfio::{VfioDevice, VfioPciDevice, KVM_DEVICE_FD}; +use vfio::{VfioConfig, VfioDevice, VfioPciDevice, KVM_DEVICE_FD}; #[cfg(feature = "virtio_gpu")] use virtio::Gpu; #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] @@ -1274,49 +1274,32 @@ pub trait MachineOps { Ok(()) } - fn create_vfio_pci_device( - &mut self, - id: &str, - bdf: &PciBdf, - host: &str, - sysfsdev: &str, - multifunc: bool, - ) -> Result<()> { - let (devfn, parent_bus) = self.get_devfn_and_parent_bus(bdf)?; - let path = if !host.is_empty() { - format!("/sys/bus/pci/devices/{}", host) + fn add_vfio_device(&mut self, cfg_args: &str, hotplug: bool) -> Result<()> { + let hypervisor = self.get_hypervisor(); + let locked_hypervisor = hypervisor.lock().unwrap(); + *KVM_DEVICE_FD.lock().unwrap() = locked_hypervisor.create_vfio_device(); + + let device_cfg = VfioConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + let bdf = PciBdf::new(device_cfg.bus.clone(), device_cfg.addr); + let multi_func = device_cfg.multifunction.unwrap_or_default(); + let (devfn, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?; + let path = if device_cfg.host.is_some() { + format!("/sys/bus/pci/devices/{}", device_cfg.host.unwrap()) } else { - sysfsdev.to_string() + device_cfg.sysfsdev.unwrap() }; let device = VfioDevice::new(Path::new(&path), self.get_sys_mem()) .with_context(|| "Failed to create vfio device.")?; let vfio_pci = VfioPciDevice::new( device, devfn, - id.to_string(), + device_cfg.id.to_string(), parent_bus, - multifunc, + multi_func, self.get_sys_mem().clone(), ); VfioPciDevice::realize(vfio_pci).with_context(|| "Failed to realize vfio-pci device.")?; - Ok(()) - } - - fn add_vfio_device(&mut self, cfg_args: &str, hotplug: bool) -> Result<()> { - let hypervisor = self.get_hypervisor(); - let locked_hypervisor = hypervisor.lock().unwrap(); - *KVM_DEVICE_FD.lock().unwrap() = locked_hypervisor.create_vfio_device(); - let device_cfg: VfioConfig = parse_vfio(cfg_args)?; - let bdf = get_pci_bdf(cfg_args)?; - let multifunc = get_multi_function(cfg_args)?; - self.create_vfio_pci_device( - &device_cfg.id, - &bdf, - &device_cfg.host, - &device_cfg.sysfsdev, - multifunc, - )?; if !hotplug { self.reset_bus(&device_cfg.id)?; } diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index 411dc3ff..d399391d 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -43,7 +43,6 @@ mod sasl_auth; mod smbios; #[cfg(feature = "vnc_auth")] mod tls_creds; -mod vfio; pub use boot_source::*; #[cfg(feature = "usb_camera")] @@ -75,7 +74,6 @@ pub use sasl_auth::*; pub use smbios::*; #[cfg(feature = "vnc_auth")] pub use tls_creds::*; -pub use vfio::*; #[cfg(feature = "vnc")] pub use vnc::*; diff --git a/machine_manager/src/config/vfio.rs b/machine_manager/src/config/vfio.rs deleted file mode 100644 index dddebde7..00000000 --- a/machine_manager/src/config/vfio.rs +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) 2020 Huawei Technologies Co.,Ltd. All rights reserved. -// -// StratoVirt is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan -// PSL v2. -// You may obtain a copy of Mulan PSL v2 at: -// http://license.coscl.org.cn/MulanPSL2 -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY -// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -// See the Mulan PSL v2 for more details. - -use anyhow::{anyhow, Result}; - -use super::error::ConfigError; -use crate::config::{check_arg_too_long, CmdParser, ConfigCheck}; - -#[derive(Default, Debug)] -pub struct VfioConfig { - pub sysfsdev: String, - pub host: String, - pub id: String, -} - -impl ConfigCheck for VfioConfig { - fn check(&self) -> Result<()> { - check_arg_too_long(&self.host, "host")?; - check_arg_too_long(&self.id, "id")?; - - Ok(()) - } -} - -pub fn parse_vfio(vfio_config: &str) -> Result { - let mut cmd_parser = CmdParser::new("vfio-pci"); - cmd_parser - .push("") - .push("host") - .push("sysfsdev") - .push("id") - .push("bus") - .push("addr") - .push("multifunction"); - cmd_parser.parse(vfio_config)?; - - let mut vfio: VfioConfig = VfioConfig::default(); - if let Some(host) = cmd_parser.get_value::("host")? { - vfio.host = host; - } - - if let Some(sysfsdev) = cmd_parser.get_value::("sysfsdev")? { - vfio.sysfsdev = sysfsdev; - } - - if vfio.host.is_empty() && vfio.sysfsdev.is_empty() { - return Err(anyhow!(ConfigError::FieldIsMissing( - "host nor sysfsdev".to_string(), - "vfio".to_string() - ))); - } - - if !vfio.host.is_empty() && !vfio.sysfsdev.is_empty() { - return Err(anyhow!(ConfigError::InvalidParam( - "host and sysfsdev".to_string(), - "vfio".to_string() - ))); - } - - if let Some(id) = cmd_parser.get_value::("id")? { - vfio.id = id; - } - vfio.check()?; - - Ok(vfio) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::config::get_pci_bdf; - - #[test] - fn test_check_vfio_config() { - let mut vfio_config = - parse_vfio("vfio-pci,host=0000:1a:00.3,id=net,bus=pcie.0,addr=0x1.0x2").unwrap(); - assert!(vfio_config.check().is_ok()); - - vfio_config.host = "IYqUdAMXggoUMU28eBJCxQGUirYYSyW1cfGJI3ZpZAzMFCKnVPA5e7gnurLtXjCm\ - YoG5pfqRDbN7M2dpSd8fzSbufAJaor8UY9xbH7BybZ7WDEFmkxgCQp6PWgaBSmLOCe1tEMs4RQ938ZLnh8ej\ - Q81VovbrU7ecafacCn9AJQoidN3Seab3QOEd4SJbtd4hAPeYvsXLVa6xOZxtVjqjRxk9b36feF0C5JrucVcs\ - QsusZZtVfUFUZxOoV8JltVsBmdasnic" - .to_string(); - assert!(vfio_config.check().is_err()); - - vfio_config.id = "LPwM1h4QUTCjL4fX2gFdCdPrF9S0kGHf0onpU6E4fyI6Jmzg0DCM9sffvEVjaVu1ilp\ - 2OrgCWzvNBflYvUUihPj3ePPYs3erSHmSOmQZbnGEFsiBSTJHfPAsRtWJoipeIh9cgIR1tnU3OjwPPli4gmb6\ - E6GgSyMd0oQtUGFyNf5pRHlYqlx3s7PMPVUtRJP0bBnNd5eDwWAotInu33h6UI0zfKgckAxeVdEROKAExx5xWK\ - V3AgPhvvPzFx3chYymy" - .to_string(); - assert!(vfio_config.check().is_err()); - } - - #[test] - fn test_vfio_config_cmdline_parser() { - let vfio_cfg = parse_vfio("vfio-pci,host=0000:1a:00.3,id=net"); - assert!(vfio_cfg.is_ok()); - let vfio_config = vfio_cfg.unwrap(); - assert_eq!(vfio_config.host, "0000:1a:00.3"); - assert_eq!(vfio_config.id, "net"); - } - - #[test] - fn test_pci_vfio_config_cmdline_parser() { - let vfio_cfg1 = "vfio-pci,host=0000:1a:00.3,id=net,bus=pcie.0,addr=0x1.0x2"; - let config1 = parse_vfio(vfio_cfg1); - assert!(config1.is_ok()); - let vfio_cfg2 = "vfio-pci,host=0000:1a:00.3,bus=pcie.0,addr=0x1.0x2"; - let config2 = parse_vfio(vfio_cfg2); - assert!(config2.is_ok()); - let vfio_cfg3 = "vfio-pci,id=net,bus=pcie.0,addr=0x1.0x2"; - let config3 = parse_vfio(vfio_cfg3); - assert!(config3.is_err()); - - let pci_bdf = get_pci_bdf(vfio_cfg1); - assert!(pci_bdf.is_ok()); - let pci = pci_bdf.unwrap(); - assert_eq!(pci.bus, "pcie.0".to_string()); - assert_eq!(pci.addr, (1, 2)); - - let vfio_cfg1 = - "vfio-pci,host=0000:1a:00.3,id=net,bus=pcie.0,addr=0x1.0x2,multifunction=on"; - assert!(parse_vfio(vfio_cfg1).is_ok()); - } -} diff --git a/vfio/Cargo.toml b/vfio/Cargo.toml index ca4a130f..94d7b5e4 100644 --- a/vfio/Cargo.toml +++ b/vfio/Cargo.toml @@ -22,3 +22,4 @@ hypervisor = { path = "../hypervisor"} machine_manager = { path = "../machine_manager" } util = { path = "../util" } devices = { path = "../devices" } +clap = { version = "=4.1.4", default-features = false, features = ["std", "derive"] } diff --git a/vfio/src/lib.rs b/vfio/src/lib.rs index 49c77af1..ab47b6ce 100644 --- a/vfio/src/lib.rs +++ b/vfio/src/lib.rs @@ -22,7 +22,7 @@ pub use vfio_dev::{ VFIO_GROUP_GET_DEVICE_FD, VFIO_GROUP_GET_STATUS, VFIO_GROUP_SET_CONTAINER, VFIO_IOMMU_MAP_DMA, VFIO_IOMMU_UNMAP_DMA, VFIO_SET_IOMMU, }; -pub use vfio_pci::VfioPciDevice; +pub use vfio_pci::{VfioConfig, VfioPciDevice}; use std::collections::HashMap; use std::os::unix::io::RawFd; diff --git a/vfio/src/vfio_pci.rs b/vfio/src/vfio_pci.rs index d354098e..baca7bfe 100644 --- a/vfio/src/vfio_pci.rs +++ b/vfio/src/vfio_pci.rs @@ -17,6 +17,7 @@ use std::sync::{Arc, Mutex, Weak}; use anyhow::{anyhow, bail, Context, Result}; use byteorder::{ByteOrder, LittleEndian}; +use clap::{ArgAction, Parser}; use log::error; use vfio_bindings::bindings::vfio; use vmm_sys_util::eventfd::EventFd; @@ -43,12 +44,33 @@ use devices::pci::{ pci_ext_cap_next, pci_ext_cap_ver, PciBus, PciDevBase, PciDevOps, }; use devices::{pci::MsiVector, Device, DeviceBase}; +use machine_manager::config::{get_pci_df, parse_bool, valid_id}; use util::num_ops::ranges_overlap; use util::unix::host_page_size; const PCI_NUM_BARS: u8 = 6; const PCI_ROM_SLOT: u8 = 6; +#[derive(Parser, Default, Debug)] +#[command(no_binary_name(true))] +#[clap(group = clap::ArgGroup::new("path").args(&["host", "sysfsdev"]).multiple(false).required(true))] +pub struct VfioConfig { + #[arg(long, value_parser = ["vfio-pci"])] + pub classtype: String, + #[arg(long, value_parser = valid_id)] + pub id: String, + #[arg(long, value_parser = valid_id)] + pub host: Option, + #[arg(long)] + pub bus: String, + #[arg(long)] + pub sysfsdev: Option, + #[arg(long, value_parser = get_pci_df)] + pub addr: (u8, u8), + #[arg(long, value_parser = parse_bool, action = ArgAction::Append)] + pub multifunction: Option, +} + struct MsixTable { table_bar: u8, table_offset: u64, @@ -1009,3 +1031,38 @@ fn get_irq_rawfds(gsi_msi_routes: &[GsiMsiRoute], start: u32, count: u32) -> Vec } rawfds } + +#[cfg(test)] +mod tests { + use super::*; + use machine_manager::config::str_slip_to_clap; + + #[test] + fn test_vfio_config_cmdline_parser() { + // Test1: right. + let vfio_cmd1 = "vfio-pci,host=0000:1a:00.3,id=net,bus=pcie.0,addr=0x5,multifunction=on"; + let result = VfioConfig::try_parse_from(str_slip_to_clap(vfio_cmd1, true, false)); + assert!(result.is_ok()); + let vfio_config = result.unwrap(); + assert_eq!(vfio_config.host, Some("0000:1a:00.3".to_string())); + assert_eq!(vfio_config.id, "net"); + assert_eq!(vfio_config.bus, "pcie.0"); + assert_eq!(vfio_config.addr, (5, 0)); + assert_eq!(vfio_config.multifunction, Some(true)); + + // Test2: Missing bus/addr. + let vfio_cmd2 = "vfio-pci,host=0000:1a:00.3,id=net"; + let result = VfioConfig::try_parse_from(str_slip_to_clap(vfio_cmd2, true, false)); + assert!(result.is_err()); + + // Test3: `host` conflicts with `sysfsdev`. + let vfio_cmd3 = "vfio-pci,host=0000:1a:00.3,sysfsdev=/sys/bus/pci/devices/0000:00:02.0,id=net,bus=pcie.0,addr=0x5"; + let result = VfioConfig::try_parse_from(str_slip_to_clap(vfio_cmd3, true, false)); + assert!(result.is_err()); + + // Test4: Missing host/sysfsdev. + let vfio_cmd4 = "vfio-pci,id=net,bus=pcie.0,addr=0x1.0x2"; + let result = VfioConfig::try_parse_from(str_slip_to_clap(vfio_cmd4, true, false)); + assert!(result.is_err()); + } +} -- Gitee From 83d3a2aaa30eb0dfd00314403b065ce3b31be328 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 21 Mar 2024 13:57:58 +0800 Subject: [PATCH 019/489] demo-pci: use clap to parse the parameters of the demo-pci config Use clap to parse the parameters of the demo-pci config. Signed-off-by: liuxiangdong --- devices/src/pci/demo_device/mod.rs | 63 +++++++++++++++-- machine/src/lib.rs | 18 ++--- machine_manager/src/config/demo_dev.rs | 97 -------------------------- machine_manager/src/config/mod.rs | 4 -- 4 files changed, 64 insertions(+), 118 deletions(-) delete mode 100644 machine_manager/src/config/demo_dev.rs diff --git a/devices/src/pci/demo_device/mod.rs b/devices/src/pci/demo_device/mod.rs index 77895366..ff35f475 100644 --- a/devices/src/pci/demo_device/mod.rs +++ b/devices/src/pci/demo_device/mod.rs @@ -42,6 +42,7 @@ use std::{ }; use anyhow::{bail, Result}; +use clap::Parser; use log::error; use crate::pci::demo_device::{ @@ -57,7 +58,30 @@ use crate::pci::{ use crate::pci::{demo_device::base_device::BaseDevice, PciDevBase}; use crate::{Device, DeviceBase}; use address_space::{AddressSpace, GuestAddress, Region, RegionOps}; -use machine_manager::config::DemoDevConfig; +use machine_manager::config::{get_pci_df, valid_id}; + +/// Config struct for `demo_dev`. +/// Contains demo_dev device's attr. +#[derive(Parser, Debug, Clone)] +#[command(no_binary_name(true))] +pub struct DemoDevConfig { + #[arg(long, value_parser = ["pcie-demo-dev"])] + pub classtype: String, + #[arg(long, value_parser = valid_id)] + pub id: String, + #[arg(long)] + pub bus: String, + #[arg(long, value_parser = get_pci_df)] + pub addr: (u8, u8), + // Different device implementations can be configured based on this parameter + #[arg(long, alias = "device_type")] + pub device_type: Option, + #[arg(long, alias = "bar_num", default_value = "0")] + pub bar_num: u8, + // Every bar has the same size just for simplification. + #[arg(long, alias = "bar_size", default_value = "0")] + pub bar_size: u64, +} pub struct DemoDev { base: PciDevBase, @@ -71,14 +95,15 @@ impl DemoDev { pub fn new( cfg: DemoDevConfig, devfn: u8, - _sys_mem: Arc, + sys_mem: Arc, parent_bus: Weak>, ) -> Self { // You can choose different device function based on the parameter of device_type. - let device: Arc> = match cfg.device_type.as_str() { - "demo-gpu" => Arc::new(Mutex::new(DemoGpu::new(_sys_mem, cfg.id.clone()))), - "demo-input" => Arc::new(Mutex::new(DemoKbdMouse::new(_sys_mem))), - "demo-display" => Arc::new(Mutex::new(DemoDisplay::new(_sys_mem))), + let device_type = cfg.device_type.clone().unwrap_or_default(); + let device: Arc> = match device_type.as_str() { + "demo-gpu" => Arc::new(Mutex::new(DemoGpu::new(sys_mem, cfg.id.clone()))), + "demo-input" => Arc::new(Mutex::new(DemoKbdMouse::new(sys_mem))), + "demo-display" => Arc::new(Mutex::new(DemoDisplay::new(sys_mem))), _ => Arc::new(Mutex::new(BaseDevice::new())), }; DemoDev { @@ -234,3 +259,29 @@ pub trait DeviceTypeOperation: Send { fn realize(&mut self) -> Result<()>; fn unrealize(&mut self) -> Result<()>; } + +#[cfg(test)] +mod tests { + use super::*; + use machine_manager::config::str_slip_to_clap; + #[test] + fn test_parse_demo_dev() { + // Test1: Right. + let demo_cmd1 = "pcie-demo-dev,bus=pcie.0,addr=0x4,id=test_0,device_type=demo-gpu,bar_num=3,bar_size=4096"; + let result = DemoDevConfig::try_parse_from(str_slip_to_clap(demo_cmd1, true, false)); + assert!(result.is_ok()); + let demo_cfg = result.unwrap(); + assert_eq!(demo_cfg.id, "test_0".to_string()); + assert_eq!(demo_cfg.device_type, Some("demo-gpu".to_string())); + assert_eq!(demo_cfg.bar_num, 3); + assert_eq!(demo_cfg.bar_size, 4096); + + // Test2: Default bar_num/bar_size. + let demo_cmd2 = "pcie-demo-dev,bus=pcie.0,addr=4.0,id=test_0,device_type=demo-gpu"; + let result = DemoDevConfig::try_parse_from(str_slip_to_clap(demo_cmd2, true, false)); + assert!(result.is_ok()); + let demo_cfg = result.unwrap(); + assert_eq!(demo_cfg.bar_num, 0); + assert_eq!(demo_cfg.bar_size, 0); + } +} diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 86ae94e4..fbd20a6d 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -51,7 +51,7 @@ use devices::misc::pvpanic::PvPanicPci; #[cfg(feature = "scream")] use devices::misc::scream::{Scream, ScreamConfig}; #[cfg(feature = "demo_device")] -use devices::pci::demo_device::DemoDev; +use devices::pci::demo_device::{DemoDev, DemoDevConfig}; use devices::pci::{PciBus, PciDevOps, PciHost, RootPort}; use devices::smbios::smbios_table::{build_smbios_ep30, SmbiosTable}; use devices::smbios::{SMBIOS_ANCHOR_FILE, SMBIOS_TABLE_FILE}; @@ -72,8 +72,6 @@ use devices::ScsiDisk::{ScsiDevConfig, ScsiDevice}; use hypervisor::{kvm::KvmHypervisor, test::TestHypervisor, HypervisorOps}; #[cfg(feature = "usb_camera")] use machine_manager::config::get_cameradev_by_id; -#[cfg(feature = "demo_device")] -use machine_manager::config::parse_demo_dev; #[cfg(feature = "virtio_gpu")] use machine_manager::config::parse_gpu; #[cfg(feature = "pvpanic")] @@ -1805,7 +1803,7 @@ pub trait MachineOps { #[cfg(feature = "ramfb")] ("ramfb", add_ramfb, cfg_args), #[cfg(feature = "demo_device")] - ("pcie-demo-dev", add_demo_dev, vm_config, cfg_args), + ("pcie-demo-dev", add_demo_dev, cfg_args), #[cfg(feature = "scream")] ("ivshmem-scream", add_ivshmem_scream, vm_config, cfg_args, token_id), #[cfg(feature = "pvpanic")] @@ -1833,15 +1831,13 @@ pub trait MachineOps { } #[cfg(feature = "demo_device")] - fn add_demo_dev(&mut self, vm_config: &mut VmConfig, cfg_args: &str) -> Result<()> { - let bdf = get_pci_bdf(cfg_args)?; - let (devfn, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?; - - let demo_cfg = parse_demo_dev(vm_config, cfg_args.to_string()) + fn add_demo_dev(&mut self, cfg_args: &str) -> Result<()> { + let config = DemoDevConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false)) .with_context(|| "failed to parse cmdline for demo dev.")?; - + let bdf = PciBdf::new(config.bus.clone(), config.addr); + let (devfn, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?; let sys_mem = self.get_sys_mem().clone(); - let demo_dev = DemoDev::new(demo_cfg, devfn, sys_mem, parent_bus); + let demo_dev = DemoDev::new(config, devfn, sys_mem, parent_bus); demo_dev.realize() } diff --git a/machine_manager/src/config/demo_dev.rs b/machine_manager/src/config/demo_dev.rs deleted file mode 100644 index 10d21994..00000000 --- a/machine_manager/src/config/demo_dev.rs +++ /dev/null @@ -1,97 +0,0 @@ -// Copyright (c) 2023 Huawei Technologies Co.,Ltd. All rights reserved. -// -// StratoVirt is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan -// PSL v2. -// You may obtain a copy of Mulan PSL v2 at: -// http://license.coscl.org.cn/MulanPSL2 -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY -// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -// See the Mulan PSL v2 for more details. - -use anyhow::{bail, Result}; - -use super::{pci_args_check, CmdParser, VmConfig}; - -/// Config struct for `demo_dev`. -/// Contains demo_dev device's attr. -#[derive(Debug, Clone)] -pub struct DemoDevConfig { - pub id: String, - // Different device implementations can be configured based on this parameter - pub device_type: String, - pub bar_num: u8, - // Every bar has the same size just for simplification. - pub bar_size: u64, -} - -impl DemoDevConfig { - pub fn new() -> Self { - Self { - id: "".to_string(), - device_type: "".to_string(), - bar_num: 0, - bar_size: 0, - } - } -} - -impl Default for DemoDevConfig { - fn default() -> Self { - Self::new() - } -} - -pub fn parse_demo_dev(_vm_config: &mut VmConfig, args_str: String) -> Result { - let mut cmd_parser = CmdParser::new("demo-dev"); - cmd_parser - .push("") - .push("id") - .push("addr") - .push("device_type") - .push("bus") - .push("bar_num") - .push("bar_size"); - cmd_parser.parse(&args_str)?; - - pci_args_check(&cmd_parser)?; - - let mut demo_dev_cfg = DemoDevConfig::new(); - - if let Some(id) = cmd_parser.get_value::("id")? { - demo_dev_cfg.id = id; - } else { - bail!("No id configured for demo device"); - } - - if let Some(device_type) = cmd_parser.get_value::("device_type")? { - demo_dev_cfg.device_type = device_type; - } - - if let Some(bar_num) = cmd_parser.get_value::("bar_num")? { - demo_dev_cfg.bar_num = bar_num; - } - - // todo: support parsing hex num "0x**". It just supports decimal number now. - if let Some(bar_size) = cmd_parser.get_value::("bar_size")? { - demo_dev_cfg.bar_size = bar_size; - } - - Ok(demo_dev_cfg) -} - -#[cfg(test)] -mod tests { - use super::*; - #[test] - fn test_parse_demo_dev() { - let mut vm_config = VmConfig::default(); - let config_line = "-device pcie-demo-dev,bus=pcie.0,addr=4.0,id=test_0,device_type=demo-gpu,bar_num=3,bar_size=4096"; - let demo_cfg = parse_demo_dev(&mut vm_config, config_line.to_string()).unwrap(); - assert_eq!(demo_cfg.id, "test_0".to_string()); - assert_eq!(demo_cfg.device_type, "demo-gpu".to_string()); - assert_eq!(demo_cfg.bar_num, 3); - assert_eq!(demo_cfg.bar_size, 4096); - } -} diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index d399391d..444cb59e 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -20,8 +20,6 @@ pub mod vnc; mod boot_source; mod chardev; -#[cfg(feature = "demo_device")] -mod demo_dev; mod devices; mod drive; mod fs; @@ -48,8 +46,6 @@ pub use boot_source::*; #[cfg(feature = "usb_camera")] pub use camera::*; pub use chardev::*; -#[cfg(feature = "demo_device")] -pub use demo_dev::*; pub use devices::*; #[cfg(any(feature = "gtk", feature = "ohui_srv"))] pub use display::*; -- Gitee From c722feaa377f2040792b4388bcdd8831b28f8d92 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 21 Mar 2024 15:12:04 +0800 Subject: [PATCH 020/489] ramfb: use clap to parse the parameters of the ramfb config Use clap to parse the parameters of the ramfb config. Signed-off-by: liuxiangdong --- devices/src/legacy/mod.rs | 2 +- devices/src/legacy/ramfb.rs | 35 +++++++++++++++++++++++++++++ machine/src/aarch64/standard.rs | 12 +++++----- machine_manager/src/config/mod.rs | 4 ---- machine_manager/src/config/ramfb.rs | 24 -------------------- 5 files changed, 43 insertions(+), 34 deletions(-) delete mode 100644 machine_manager/src/config/ramfb.rs diff --git a/devices/src/legacy/mod.rs b/devices/src/legacy/mod.rs index 00632feb..74cc2e4a 100644 --- a/devices/src/legacy/mod.rs +++ b/devices/src/legacy/mod.rs @@ -53,5 +53,5 @@ pub use pl011::PL011; #[cfg(target_arch = "aarch64")] pub use pl031::{PL031, RTC_CR, RTC_DR, RTC_IMSC, RTC_LR}; #[cfg(all(feature = "ramfb", target_arch = "aarch64"))] -pub use ramfb::Ramfb; +pub use ramfb::{Ramfb, RamfbConfig}; pub use serial::{Serial, SERIAL_ADDR}; diff --git a/devices/src/legacy/ramfb.rs b/devices/src/legacy/ramfb.rs index 470fcd79..6dab9da2 100644 --- a/devices/src/legacy/ramfb.rs +++ b/devices/src/legacy/ramfb.rs @@ -16,6 +16,7 @@ use std::sync::{Arc, Mutex, Weak}; use std::time::Duration; use anyhow::{Context, Result}; +use clap::{ArgAction, Parser}; use drm_fourcc::DrmFourcc; use log::error; @@ -24,6 +25,7 @@ use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; use crate::{Device, DeviceBase}; use acpi::AmlBuilder; use address_space::{AddressSpace, GuestAddress}; +use machine_manager::config::valid_id; use machine_manager::event_loop::EventLoop; use ui::console::{ console_init, display_graphic_update, display_replace_surface, ConsoleType, DisplayConsole, @@ -39,6 +41,17 @@ const INSTALL_CHECK_INTERVEL_MS: u64 = 500; const INSTALL_RELEASE_INTERVEL_MS: u64 = 200; const INSTALL_PRESS_INTERVEL_MS: u64 = 100; +#[derive(Parser, Debug, Clone)] +#[command(no_binary_name(true))] +pub struct RamfbConfig { + #[arg(long, value_parser = ["ramfb"])] + pub classtype: String, + #[arg(long, value_parser = valid_id)] + pub id: String, + #[arg(long, default_value = "false", action = ArgAction::Append)] + pub install: bool, +} + #[repr(packed)] struct RamfbCfg { _addr: u64, @@ -317,3 +330,25 @@ fn set_press_event(install: Arc, data: *const u8) { install.store(false, Ordering::Release); } } + +#[cfg(test)] +mod tests { + use super::*; + use machine_manager::config::str_slip_to_clap; + + #[test] + fn test_ramfb_config_cmdline_parser() { + // Test1: install. + let ramfb_cmd1 = "ramfb,id=ramfb0,install=true"; + let ramfb_config = + RamfbConfig::try_parse_from(str_slip_to_clap(ramfb_cmd1, true, false)).unwrap(); + assert_eq!(ramfb_config.id, "ramfb0"); + assert_eq!(ramfb_config.install, true); + + // Test2: Default. + let ramfb_cmd2 = "ramfb,id=ramfb0"; + let ramfb_config = + RamfbConfig::try_parse_from(str_slip_to_clap(ramfb_cmd2, true, false)).unwrap(); + assert_eq!(ramfb_config.install, false); + } +} diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index 56a3a3a2..3dd906e8 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -19,6 +19,8 @@ use std::sync::RwLock; use std::sync::{Arc, Mutex}; use anyhow::{anyhow, bail, Context, Result}; +#[cfg(feature = "ramfb")] +use clap::Parser; use log::{error, info, warn}; use vmm_sys_util::eventfd::EventFd; @@ -45,18 +47,18 @@ use super::pci_host_root::PciHostRoot; use crate::standard_common::syscall::syscall_whitelist; use devices::acpi::ged::{acpi_dsdt_add_power_button, Ged, GedEvent}; use devices::acpi::power::PowerDev; -#[cfg(feature = "ramfb")] -use devices::legacy::Ramfb; use devices::legacy::{ FwCfgEntryType, FwCfgMem, FwCfgOps, LegacyError as DevErrorKind, PFlash, PL011, PL031, }; +#[cfg(feature = "ramfb")] +use devices::legacy::{Ramfb, RamfbConfig}; use devices::pci::{PciDevOps, PciHost, PciIntxState}; use devices::sysbus::SysBusDevType; use devices::{ICGICConfig, ICGICv3Config, GIC_IRQ_MAX}; use hypervisor::kvm::aarch64::*; use hypervisor::kvm::*; #[cfg(feature = "ramfb")] -use machine_manager::config::parse_ramfb; +use machine_manager::config::str_slip_to_clap; use machine_manager::config::ShutdownAction; #[cfg(feature = "gtk")] use machine_manager::config::UiContext; @@ -747,12 +749,12 @@ impl MachineOps for StdMachine { #[cfg(feature = "ramfb")] fn add_ramfb(&mut self, cfg_args: &str) -> Result<()> { - let install = parse_ramfb(cfg_args)?; + let config = RamfbConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; let fwcfg_dev = self .get_fwcfg_dev() .with_context(|| "Ramfb device must be used UEFI to boot, please add pflash devices")?; let sys_mem = self.get_sys_mem(); - let mut ramfb = Ramfb::new(sys_mem.clone(), install); + let mut ramfb = Ramfb::new(sys_mem.clone(), config.install); ramfb.ramfb_state.setup(&fwcfg_dev)?; ramfb.realize(&mut self.base.sysbus) diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index 444cb59e..16587d0f 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -33,8 +33,6 @@ mod numa; mod pci; #[cfg(feature = "pvpanic")] mod pvpanic_pci; -#[cfg(all(feature = "ramfb", target_arch = "aarch64"))] -mod ramfb; mod rng; #[cfg(feature = "vnc_auth")] mod sasl_auth; @@ -62,8 +60,6 @@ pub use numa::*; pub use pci::*; #[cfg(feature = "pvpanic")] pub use pvpanic_pci::*; -#[cfg(all(feature = "ramfb", target_arch = "aarch64"))] -pub use ramfb::*; pub use rng::*; #[cfg(feature = "vnc_auth")] pub use sasl_auth::*; diff --git a/machine_manager/src/config/ramfb.rs b/machine_manager/src/config/ramfb.rs deleted file mode 100644 index 8473c1df..00000000 --- a/machine_manager/src/config/ramfb.rs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2023 Huawei Technologies Co.,Ltd. All rights reserved. -// -// StratoVirt is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan -// PSL v2. -// You may obtain a copy of Mulan PSL v2 at: -// http://license.coscl.org.cn/MulanPSL2 -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY -// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -// See the Mulan PSL v2 for more details. - -use anyhow::Result; - -use crate::config::CmdParser; - -pub fn parse_ramfb(cfg_args: &str) -> Result { - let mut cmd_parser = CmdParser::new("ramfb"); - cmd_parser.push("").push("install").push("id"); - cmd_parser.parse(cfg_args)?; - - let install = cmd_parser.get_value::("install")?.unwrap_or(false); - Ok(install) -} -- Gitee From 71d95a1bca12b88b779735be2df183c0a5d5b189 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 21 Mar 2024 17:45:09 +0800 Subject: [PATCH 021/489] virtiofs: use clap to parse the parameters of the virtiofs config Use clap to parse the parameters of the virtiofs config. Signed-off-by: liuxiangdong --- machine/src/lib.rs | 25 ++++--- machine_manager/src/config/fs.rs | 111 ------------------------------ machine_manager/src/config/mod.rs | 3 - virtio/src/vhost/user/fs.rs | 74 ++++++++++++++++++-- 4 files changed, 86 insertions(+), 127 deletions(-) delete mode 100644 machine_manager/src/config/fs.rs diff --git a/machine/src/lib.rs b/machine/src/lib.rs index fbd20a6d..68abf2e8 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -78,7 +78,7 @@ use machine_manager::config::parse_gpu; use machine_manager::config::parse_pvpanic; use machine_manager::config::{ complete_numa_node, get_multi_function, get_pci_bdf, parse_blk, parse_device_id, - parse_device_type, parse_fs, parse_net, parse_numa_distance, parse_numa_mem, parse_rng_dev, + parse_device_type, parse_net, parse_numa_distance, parse_numa_mem, parse_rng_dev, parse_root_port, parse_vhost_user_blk, parse_virtio_serial, parse_virtserialport, parse_vsock, str_slip_to_clap, BootIndexInfo, BootSource, DriveConfig, DriveFile, Incoming, MachineMemConfig, MigrateMode, NumaConfig, NumaDistance, NumaNode, NumaNodes, PciBdf, @@ -847,29 +847,36 @@ pub trait MachineOps { /// * 'vm_config' - VM configuration. /// * 'cfg_args' - Device configuration arguments. fn add_virtio_fs(&mut self, vm_config: &mut VmConfig, cfg_args: &str) -> Result<()> { - let dev_cfg = parse_fs(vm_config, cfg_args)?; - let id_clone = dev_cfg.id.clone(); + let dev_cfg = + vhost::user::FsConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + let char_dev = vm_config + .chardev + .remove(&dev_cfg.chardev) + .with_context(|| format!("Chardev {:?} not found or is in use", &dev_cfg.chardev))?; let sys_mem = self.get_sys_mem().clone(); if !vm_config.machine_config.mem_config.mem_share { bail!("When configuring the vhost-user-fs-device or vhost-user-fs-pci device, the memory must be shared."); } - match parse_device_type(cfg_args)?.as_str() { + let device = Arc::new(Mutex::new(vhost::user::Fs::new( + dev_cfg.clone(), + char_dev, + sys_mem.clone(), + ))); + match dev_cfg.classtype.as_str() { "vhost-user-fs-device" => { - let device = Arc::new(Mutex::new(vhost::user::Fs::new(dev_cfg, sys_mem.clone()))); let virtio_mmio_device = VirtioMmioDevice::new(&sys_mem, device); self.realize_virtio_mmio_device(virtio_mmio_device) .with_context(|| "Failed to add vhost user fs device")?; } _ => { - let device = Arc::new(Mutex::new(vhost::user::Fs::new(dev_cfg, sys_mem))); - let bdf = get_pci_bdf(cfg_args)?; - let multi_func = get_multi_function(cfg_args)?; + let bdf = PciBdf::new(dev_cfg.bus.clone().unwrap(), dev_cfg.addr.unwrap()); + let multi_func = dev_cfg.multifunction.unwrap_or_default(); let root_bus = self.get_pci_host()?.lock().unwrap().root_bus.clone(); let msi_irq_manager = root_bus.lock().unwrap().msi_irq_manager.clone(); let need_irqfd = msi_irq_manager.as_ref().unwrap().irqfd_enable(); - self.add_virtio_pci_device(&id_clone, &bdf, device, multi_func, need_irqfd) + self.add_virtio_pci_device(&dev_cfg.id, &bdf, device, multi_func, need_irqfd) .with_context(|| "Failed to add pci fs device")?; } } diff --git a/machine_manager/src/config/fs.rs b/machine_manager/src/config/fs.rs deleted file mode 100644 index 6900888f..00000000 --- a/machine_manager/src/config/fs.rs +++ /dev/null @@ -1,111 +0,0 @@ -// Copyright (c) 2022 Huawei Technologies Co.,Ltd. All rights reserved. -// -// StratoVirt is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan -// PSL v2. -// You may obtain a copy of Mulan PSL v2 at: -// http://license.coscl.org.cn/MulanPSL2 -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY -// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -// See the Mulan PSL v2 for more details. - -use anyhow::{anyhow, bail, Context, Result}; - -use super::{error::ConfigError, SocketType}; -use crate::config::{ - pci_args_check, CmdParser, ConfigCheck, VmConfig, MAX_SOCK_PATH_LENGTH, MAX_STRING_LENGTH, - MAX_TAG_LENGTH, -}; - -/// Config struct for `fs`. -/// Contains fs device's attr. -#[derive(Debug, Clone)] -pub struct FsConfig { - /// Device tag. - pub tag: String, - /// Device id. - pub id: String, - /// Char device sock path. - pub sock: String, -} - -impl Default for FsConfig { - fn default() -> Self { - FsConfig { - tag: "".to_string(), - id: "".to_string(), - sock: "".to_string(), - } - } -} - -impl ConfigCheck for FsConfig { - fn check(&self) -> Result<()> { - if self.tag.len() >= MAX_TAG_LENGTH { - return Err(anyhow!(ConfigError::StringLengthTooLong( - "fs device tag".to_string(), - MAX_TAG_LENGTH - 1, - ))); - } - - if self.id.len() >= MAX_STRING_LENGTH { - return Err(anyhow!(ConfigError::StringLengthTooLong( - "fs device id".to_string(), - MAX_STRING_LENGTH - 1, - ))); - } - - if self.sock.len() > MAX_SOCK_PATH_LENGTH { - return Err(anyhow!(ConfigError::StringLengthTooLong( - "fs sock path".to_string(), - MAX_SOCK_PATH_LENGTH, - ))); - } - - Ok(()) - } -} - -pub fn parse_fs(vm_config: &mut VmConfig, fs_config: &str) -> Result { - let mut cmd_parser = CmdParser::new("fs"); - cmd_parser - .push("") - .push("tag") - .push("id") - .push("chardev") - .push("bus") - .push("addr") - .push("multifunction"); - cmd_parser.parse(fs_config)?; - pci_args_check(&cmd_parser)?; - - let mut fs_cfg = FsConfig { - tag: cmd_parser.get_value::("tag")?.with_context(|| { - ConfigError::FieldIsMissing("tag".to_string(), "virtio-fs".to_string()) - })?, - id: cmd_parser.get_value::("id")?.with_context(|| { - ConfigError::FieldIsMissing("id".to_string(), "virtio-fs".to_string()) - })?, - ..Default::default() - }; - - let name = cmd_parser - .get_value::("chardev")? - .with_context(|| { - ConfigError::FieldIsMissing("chardev".to_string(), "virtio-fs".to_string()) - })?; - let char_dev = vm_config - .chardev - .remove(&name) - .with_context(|| format!("Chardev {:?} not found or is in use", &name))?; - match char_dev.classtype.socket_type()? { - SocketType::Unix { path } => { - fs_cfg.sock = path; - } - _ => bail!("Chardev {:?} backend should be unix-socket type.", &name), - }; - - fs_cfg.check()?; - Ok(fs_cfg) -} diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index 16587d0f..57c4b5b7 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -22,7 +22,6 @@ mod boot_source; mod chardev; mod devices; mod drive; -mod fs; #[cfg(feature = "virtio_gpu")] mod gpu; mod incoming; @@ -49,7 +48,6 @@ pub use devices::*; pub use display::*; pub use drive::*; pub use error::ConfigError; -pub use fs::*; #[cfg(feature = "virtio_gpu")] pub use gpu::*; pub use incoming::*; @@ -96,7 +94,6 @@ pub const MAX_SOCK_PATH_LENGTH: usize = 108; pub const MAX_VIRTIO_QUEUE: usize = 32; pub const FAST_UNPLUG_ON: &str = "1"; pub const FAST_UNPLUG_OFF: &str = "0"; -pub const MAX_TAG_LENGTH: usize = 36; pub const MAX_NODES: u32 = 128; /// Default virtqueue size for virtio devices excepts virtio-fs. pub const DEFAULT_VIRTQUEUE_SIZE: u16 = 256; diff --git a/virtio/src/vhost/user/fs.rs b/virtio/src/vhost/user/fs.rs index a1c5ed8d..75c3698a 100644 --- a/virtio/src/vhost/user/fs.rs +++ b/virtio/src/vhost/user/fs.rs @@ -19,7 +19,8 @@ const VIRTIO_FS_QUEUE_SIZE: u16 = 128; use std::sync::{Arc, Mutex}; -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, bail, Context, Result}; +use clap::Parser; use vmm_sys_util::eventfd::EventFd; use super::super::super::{VirtioDevice, VIRTIO_TYPE_FS}; @@ -27,10 +28,45 @@ use super::super::VhostOps; use super::{listen_guest_notifier, VhostBackendType, VhostUserClient}; use crate::{read_config_default, VirtioBase, VirtioInterrupt}; use address_space::AddressSpace; -use machine_manager::config::{FsConfig, MAX_TAG_LENGTH}; +use machine_manager::config::{ + get_pci_df, parse_bool, valid_id, ChardevConfig, ConfigError, SocketType, +}; use machine_manager::event_loop::unregister_event_helper; use util::byte_code::ByteCode; +const MAX_TAG_LENGTH: usize = 36; + +/// Config struct for `fs`. +/// Contains fs device's attr. +#[derive(Parser, Debug, Clone)] +#[command(no_binary_name(true))] +pub struct FsConfig { + #[arg(long, value_parser = ["vhost-user-fs-pci", "vhost-user-fs-device"])] + pub classtype: String, + #[arg(long, value_parser = valid_id)] + pub id: String, + #[arg(long)] + pub chardev: String, + #[arg(long, value_parser = valid_tag)] + pub tag: String, + #[arg(long)] + pub bus: Option, + #[arg(long, value_parser = get_pci_df)] + pub addr: Option<(u8, u8)>, + #[arg(long, value_parser = parse_bool)] + pub multifunction: Option, +} + +fn valid_tag(tag: &str) -> Result { + if tag.len() >= MAX_TAG_LENGTH { + return Err(anyhow!(ConfigError::StringLengthTooLong( + "fs device tag".to_string(), + MAX_TAG_LENGTH - 1, + ))); + } + Ok(tag.to_string()) +} + #[derive(Copy, Clone)] #[repr(C, packed)] struct VirtioFsConfig { @@ -52,6 +88,7 @@ impl ByteCode for VirtioFsConfig {} pub struct Fs { base: VirtioBase, fs_cfg: FsConfig, + chardev_cfg: ChardevConfig, config_space: VirtioFsConfig, client: Option>>, mem_space: Arc, @@ -64,14 +101,16 @@ impl Fs { /// # Arguments /// /// `fs_cfg` - The config of this Fs device. + /// `chardev_cfg` - The config of this Fs device's chardev. /// `mem_space` - The address space of this Fs device. - pub fn new(fs_cfg: FsConfig, mem_space: Arc) -> Self { + pub fn new(fs_cfg: FsConfig, chardev_cfg: ChardevConfig, mem_space: Arc) -> Self { let queue_num = VIRIOT_FS_HIGH_PRIO_QUEUE_NUM + VIRTIO_FS_REQ_QUEUES_NUM; let queue_size = VIRTIO_FS_QUEUE_SIZE; Fs { base: VirtioBase::new(VIRTIO_TYPE_FS, queue_num, queue_size), fs_cfg, + chardev_cfg, config_space: VirtioFsConfig::default(), client: None, mem_space, @@ -91,9 +130,15 @@ impl VirtioDevice for Fs { fn realize(&mut self) -> Result<()> { let queues_num = VIRIOT_FS_HIGH_PRIO_QUEUE_NUM + VIRTIO_FS_REQ_QUEUES_NUM; + + let socket_path = match self.chardev_cfg.classtype.socket_type()? { + SocketType::Unix { path } => path, + _ => bail!("Vhost-user-fs Chardev backend should be unix-socket type."), + }; + let client = VhostUserClient::new( &self.mem_space, - &self.fs_cfg.sock, + &socket_path, queues_num as u64, VhostBackendType::TypeFs, ) @@ -194,3 +239,24 @@ impl VirtioDevice for Fs { self.realize() } } + +#[cfg(test)] +mod tests { + use super::*; + use machine_manager::config::str_slip_to_clap; + + #[test] + fn test_vhostuserfs_cmdline_parser() { + // Test1: Right. + let fs_cmd = "vhost-user-fs-device,id=fs0,chardev=chardev0,tag=tag0"; + let fs_config = FsConfig::try_parse_from(str_slip_to_clap(fs_cmd, true, false)).unwrap(); + assert_eq!(fs_config.id, "fs0"); + assert_eq!(fs_config.chardev, "chardev0"); + assert_eq!(fs_config.tag, "tag0"); + + // Test2: Illegal value. + let fs_cmd = "vhost-user-fs-device,id=fs0,chardev=chardev0,tag=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"; + let result = FsConfig::try_parse_from(str_slip_to_clap(fs_cmd, true, false)); + assert!(result.is_err()); + } +} -- Gitee From 15f68e315e45114bfa5b1b1b060652509de07d97 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 21 Mar 2024 20:48:17 +0800 Subject: [PATCH 022/489] virtio-gpu: use clap to parse the parameters of the virtio-gpu config Use clap to parse the parameters of the virtio-gpu config. Signed-off-by: liuxiangdong --- machine/src/lib.rs | 16 ++- machine_manager/src/config/gpu.rs | 176 ------------------------------ machine_manager/src/config/mod.rs | 6 +- virtio/src/device/gpu.rs | 93 +++++++++++++++- 4 files changed, 101 insertions(+), 190 deletions(-) delete mode 100644 machine_manager/src/config/gpu.rs diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 68abf2e8..25f5a8be 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -72,8 +72,6 @@ use devices::ScsiDisk::{ScsiDevConfig, ScsiDevice}; use hypervisor::{kvm::KvmHypervisor, test::TestHypervisor, HypervisorOps}; #[cfg(feature = "usb_camera")] use machine_manager::config::get_cameradev_by_id; -#[cfg(feature = "virtio_gpu")] -use machine_manager::config::parse_gpu; #[cfg(feature = "pvpanic")] use machine_manager::config::parse_pvpanic; use machine_manager::config::{ @@ -95,8 +93,6 @@ use util::{ seccomp::{BpfRule, SeccompOpt, SyscallFilter}, }; use vfio::{VfioConfig, VfioDevice, VfioPciDevice, KVM_DEVICE_FD}; -#[cfg(feature = "virtio_gpu")] -use virtio::Gpu; #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] use virtio::VirtioDeviceQuirk; use virtio::{ @@ -106,6 +102,8 @@ use virtio::{ Serial, SerialPort, VhostKern, VhostUser, VirtioDevice, VirtioMmioDevice, VirtioMmioState, VirtioNetState, VirtioPciDevice, VirtioSerialState, VIRTIO_TYPE_CONSOLE, }; +#[cfg(feature = "virtio_gpu")] +use virtio::{Gpu, GpuDevConfig}; /// Machine structure include base members. pub struct MachineBase { @@ -1321,10 +1319,10 @@ pub trait MachineOps { #[cfg(feature = "virtio_gpu")] fn add_virtio_pci_gpu(&mut self, cfg_args: &str) -> Result<()> { - let bdf = get_pci_bdf(cfg_args)?; - let multi_func = get_multi_function(cfg_args)?; - let device_cfg = parse_gpu(cfg_args)?; - let device = Arc::new(Mutex::new(Gpu::new(device_cfg.clone()))); + let config = GpuDevConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + config.check(); + let bdf = PciBdf::new(config.bus.clone(), config.addr); + let device = Arc::new(Mutex::new(Gpu::new(config.clone()))); #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] if device.lock().unwrap().device_quirk() == Some(VirtioDeviceQuirk::VirtioGpuEnableBar0) @@ -1334,7 +1332,7 @@ pub trait MachineOps { device.lock().unwrap().set_bar0_fb(self.get_ohui_fb()); } - self.add_virtio_pci_device(&device_cfg.id, &bdf, device, multi_func, false)?; + self.add_virtio_pci_device(&config.id, &bdf, device, false, false)?; Ok(()) } diff --git a/machine_manager/src/config/gpu.rs b/machine_manager/src/config/gpu.rs deleted file mode 100644 index 56ab2842..00000000 --- a/machine_manager/src/config/gpu.rs +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (c) 2022 Huawei Technologies Co.,Ltd. All rights reserved. -// -// StratoVirt is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan -// PSL v2. -// You may obtain a copy of Mulan PSL v2 at: -// http://license.coscl.org.cn/MulanPSL2 -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY -// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -// See the Mulan PSL v2 for more details. - -use anyhow::{anyhow, Result}; -use log::warn; - -use super::{error::ConfigError, M}; -use crate::config::{check_arg_too_long, CmdParser, ConfigCheck}; - -/// The maximum number of outputs. -pub const VIRTIO_GPU_MAX_OUTPUTS: usize = 16; - -pub const VIRTIO_GPU_MAX_HOSTMEM: u64 = 256 * M; - -/// The bar0 size of enable_bar0 features -pub const VIRTIO_GPU_ENABLE_BAR0_SIZE: u64 = 64 * M; - -#[derive(Clone, Debug)] -pub struct GpuDevConfig { - pub id: String, - pub max_outputs: u32, - pub edid: bool, - pub xres: u32, - pub yres: u32, - pub max_hostmem: u64, - pub enable_bar0: bool, -} - -impl Default for GpuDevConfig { - fn default() -> Self { - GpuDevConfig { - id: "".to_string(), - max_outputs: 1, - edid: true, - xres: 1024, - yres: 768, - max_hostmem: VIRTIO_GPU_MAX_HOSTMEM, - enable_bar0: false, - } - } -} - -impl ConfigCheck for GpuDevConfig { - fn check(&self) -> Result<()> { - check_arg_too_long(&self.id, "id")?; - if self.max_outputs > VIRTIO_GPU_MAX_OUTPUTS as u32 || self.max_outputs == 0 { - return Err(anyhow!(ConfigError::IllegalValue( - "max_outputs".to_string(), - 0, - false, - VIRTIO_GPU_MAX_OUTPUTS as u64, - true - ))); - } - - if self.max_hostmem == 0 { - return Err(anyhow!(ConfigError::IllegalValueUnilateral( - "max_hostmem".to_string(), - true, - false, - 0 - ))); - } - - if self.max_hostmem < VIRTIO_GPU_MAX_HOSTMEM { - warn!( - "max_hostmem should >= {}, allocating less than it may cause \ - the GPU to fail to start or refresh.", - VIRTIO_GPU_MAX_HOSTMEM - ); - } - - Ok(()) - } -} - -pub fn parse_gpu(gpu_config: &str) -> Result { - let mut cmd_parser = CmdParser::new("virtio-gpu-pci"); - cmd_parser - .push("") - .push("id") - .push("max_outputs") - .push("edid") - .push("xres") - .push("yres") - .push("max_hostmem") - .push("bus") - .push("addr") - .push("enable_bar0"); - cmd_parser.parse(gpu_config)?; - - let mut gpu_cfg: GpuDevConfig = GpuDevConfig::default(); - if let Some(id) = cmd_parser.get_value::("id")? { - gpu_cfg.id = id; - } - if let Some(max_outputs) = cmd_parser.get_value::("max_outputs")? { - gpu_cfg.max_outputs = max_outputs; - } - if let Some(edid) = cmd_parser.get_value::("edid")? { - gpu_cfg.edid = edid; - } - if let Some(xres) = cmd_parser.get_value::("xres")? { - gpu_cfg.xres = xres; - } - if let Some(yres) = cmd_parser.get_value::("yres")? { - gpu_cfg.yres = yres; - } - if let Some(max_hostmem) = cmd_parser.get_value::("max_hostmem")? { - gpu_cfg.max_hostmem = max_hostmem; - } - if let Some(enable_bar0) = cmd_parser.get_value::("enable_bar0")? { - gpu_cfg.enable_bar0 = enable_bar0; - } - gpu_cfg.check()?; - - Ok(gpu_cfg) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_parse_pci_gpu_config_cmdline_parser() { - let max_hostmem = VIRTIO_GPU_MAX_HOSTMEM + 1; - let gpu_cfg_cmdline = format!( - "{}{}", - "virtio-gpu-pci,id=gpu_1,bus=pcie.0,addr=0x4.0x0,\ - max_outputs=1,edid=true,xres=1024,yres=768,max_hostmem=", - max_hostmem.to_string() - ); - let gpu_cfg_ = parse_gpu(&gpu_cfg_cmdline); - assert!(gpu_cfg_.is_ok()); - let gpu_cfg = gpu_cfg_.unwrap(); - assert_eq!(gpu_cfg.id, "gpu_1"); - assert_eq!(gpu_cfg.max_outputs, 1); - assert_eq!(gpu_cfg.edid, true); - assert_eq!(gpu_cfg.xres, 1024); - assert_eq!(gpu_cfg.yres, 768); - assert_eq!(gpu_cfg.max_hostmem, max_hostmem); - - // max_outputs is illegal - let gpu_cfg_cmdline = format!( - "{}{}", - "virtio-gpu-pci,id=gpu_1,bus=pcie.0,addr=0x4.0x0,\ - max_outputs=17,edid=true,xres=1024,yres=768,max_hostmem=", - max_hostmem.to_string() - ); - let gpu_cfg_ = parse_gpu(&gpu_cfg_cmdline); - assert!(gpu_cfg_.is_err()); - - let gpu_cfg_cmdline = format!( - "{}{}", - "virtio-gpu-pci,id=gpu_1,bus=pcie.0,addr=0x4.0x0,\ - max_outputs=0,edid=true,xres=1024,yres=768,max_hostmem=", - max_hostmem.to_string() - ); - let gpu_cfg_ = parse_gpu(&gpu_cfg_cmdline); - assert!(gpu_cfg_.is_err()); - - // max_hostmem is illegal - let gpu_cfg_cmdline = "virtio-gpu-pci,id=gpu_1,bus=pcie.0,addr=0x4.0x0,\ - max_outputs=1,edid=true,xres=1024,yres=768,max_hostmem=0"; - let gpu_cfg_ = parse_gpu(&gpu_cfg_cmdline); - assert!(gpu_cfg_.is_err()); - } -} diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index 57c4b5b7..519c5b5e 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -22,8 +22,6 @@ mod boot_source; mod chardev; mod devices; mod drive; -#[cfg(feature = "virtio_gpu")] -mod gpu; mod incoming; mod iothread; mod machine_config; @@ -48,8 +46,6 @@ pub use devices::*; pub use display::*; pub use drive::*; pub use error::ConfigError; -#[cfg(feature = "virtio_gpu")] -pub use gpu::*; pub use incoming::*; pub use iothread::*; pub use machine_config::*; @@ -101,6 +97,8 @@ pub const DEFAULT_VIRTQUEUE_SIZE: u16 = 256; pub const MIN_QUEUE_SIZE_SCSI: u64 = 2; // Max size of each virtqueue for virtio-scsi. pub const MAX_QUEUE_SIZE_SCSI: u64 = 1024; +/// The bar0 size of enable_bar0 features +pub const VIRTIO_GPU_ENABLE_BAR0_SIZE: u64 = 64 * M; #[derive(Clone, Default, Debug, Serialize, Deserialize)] pub struct ObjectConfig { diff --git a/virtio/src/device/gpu.rs b/virtio/src/device/gpu.rs index 97ca67c1..98f9d2c3 100644 --- a/virtio/src/device/gpu.rs +++ b/virtio/src/device/gpu.rs @@ -18,6 +18,7 @@ use std::sync::{Arc, Mutex, Weak}; use std::{ptr, vec}; use anyhow::{anyhow, bail, Context, Result}; +use clap::{ArgAction, Parser}; use log::{error, info, warn}; use vmm_sys_util::{epoll::EventSet, eventfd::EventFd}; @@ -36,7 +37,7 @@ use crate::{ VIRTIO_GPU_RESP_OK_EDID, VIRTIO_GPU_RESP_OK_NODATA, VIRTIO_TYPE_GPU, }; use address_space::{AddressSpace, FileBackend, GuestAddress}; -use machine_manager::config::{GpuDevConfig, DEFAULT_VIRTQUEUE_SIZE, VIRTIO_GPU_MAX_OUTPUTS}; +use machine_manager::config::{get_pci_df, valid_id, DEFAULT_VIRTQUEUE_SIZE}; use machine_manager::event_loop::{register_event_helper, unregister_event_helper}; use migration_derive::ByteCode; use ui::console::{ @@ -72,6 +73,49 @@ const VIRTIO_GPU_RES_WIN_FRAMEBUF: u32 = 0x80000000; const VIRTIO_GPU_RES_EFI_FRAMEBUF: u32 = 0x40000000; const VIRTIO_GPU_RES_FRAMEBUF: u32 = VIRTIO_GPU_RES_WIN_FRAMEBUF | VIRTIO_GPU_RES_EFI_FRAMEBUF; +/// The maximum number of outputs. +const VIRTIO_GPU_MAX_OUTPUTS: usize = 16; +/// The default maximum memory 256M. +const VIRTIO_GPU_DEFAULT_MAX_HOSTMEM: u64 = 0x10000000; + +#[derive(Parser, Clone, Debug, Default)] +#[command(no_binary_name(true))] +pub struct GpuDevConfig { + #[arg(long, value_parser = ["virtio-gpu-pci"])] + pub classtype: String, + #[arg(long, value_parser = valid_id)] + pub id: String, + #[arg(long)] + pub bus: String, + #[arg(long, value_parser = get_pci_df)] + pub addr: (u8, u8), + #[arg(long, alias = "max_outputs", default_value="1", value_parser = clap::value_parser!(u32).range(1..=VIRTIO_GPU_MAX_OUTPUTS as i64))] + pub max_outputs: u32, + #[arg(long, default_value="true", action = ArgAction::Append)] + pub edid: bool, + #[arg(long, default_value = "1024")] + pub xres: u32, + #[arg(long, default_value = "768")] + pub yres: u32, + // The default max_hostmem is 256M. + #[arg(long, alias = "max_hostmem", default_value="268435456", value_parser = clap::value_parser!(u64).range(1..))] + pub max_hostmem: u64, + #[arg(long, alias = "enable_bar0", default_value="false", action = ArgAction::Append)] + pub enable_bar0: bool, +} + +impl GpuDevConfig { + pub fn check(&self) { + if self.max_hostmem < VIRTIO_GPU_DEFAULT_MAX_HOSTMEM { + warn!( + "max_hostmem should >= {}, allocating less than it may cause \ + the GPU to fail to start or refresh.", + VIRTIO_GPU_DEFAULT_MAX_HOSTMEM + ); + } + } +} + #[derive(Debug)] struct GpuResource { resource_id: u32, @@ -1843,3 +1887,50 @@ impl VirtioDevice for Gpu { result } } + +#[cfg(test)] +mod tests { + use super::*; + use machine_manager::config::str_slip_to_clap; + + #[test] + fn test_parse_virtio_gpu_pci_cmdline() { + // Test1: Right. + let gpu_cmd = "virtio-gpu-pci,id=gpu_1,bus=pcie.0,addr=0x4.0x0,max_outputs=5,edid=false,\ + xres=2048,yres=800,enable_bar0=true,max_hostmem=268435457"; + let gpu_cfg = GpuDevConfig::try_parse_from(str_slip_to_clap(gpu_cmd, true, false)).unwrap(); + assert_eq!(gpu_cfg.id, "gpu_1"); + assert_eq!(gpu_cfg.bus, "pcie.0"); + assert_eq!(gpu_cfg.addr, (4, 0)); + assert_eq!(gpu_cfg.max_outputs, 5); + assert_eq!(gpu_cfg.xres, 2048); + assert_eq!(gpu_cfg.yres, 800); + assert_eq!(gpu_cfg.edid, false); + assert_eq!(gpu_cfg.max_hostmem, 268435457); + assert_eq!(gpu_cfg.enable_bar0, true); + + // Test2: Default. + let gpu_cmd2 = "virtio-gpu-pci,id=gpu_1,bus=pcie.0,addr=0x4.0x0"; + let gpu_cfg = + GpuDevConfig::try_parse_from(str_slip_to_clap(gpu_cmd2, true, false)).unwrap(); + assert_eq!(gpu_cfg.max_outputs, 1); + assert_eq!(gpu_cfg.xres, 1024); + assert_eq!(gpu_cfg.yres, 768); + assert_eq!(gpu_cfg.edid, true); + assert_eq!(gpu_cfg.max_hostmem, VIRTIO_GPU_DEFAULT_MAX_HOSTMEM); + assert_eq!(gpu_cfg.enable_bar0, false); + + // Test3/4: max_outputs is illegal. + let gpu_cmd3 = "virtio-gpu-pci,id=gpu_1,bus=pcie.0,addr=0x4.0x0,max_outputs=17"; + let result = GpuDevConfig::try_parse_from(str_slip_to_clap(gpu_cmd3, true, false)); + assert!(result.is_err()); + let gpu_cmd4 = "virtio-gpu-pci,id=gpu_1,bus=pcie.0,addr=0x4.0x0,max_outputs=0"; + let result = GpuDevConfig::try_parse_from(str_slip_to_clap(gpu_cmd4, true, false)); + assert!(result.is_err()); + + // Test5: max_hostmem is illegal. + let gpu_cmd5 = "virtio-gpu-pci,id=gpu_1,bus=pcie.0,addr=0x4.0x0,max_hostmem=0"; + let result = GpuDevConfig::try_parse_from(str_slip_to_clap(gpu_cmd5, true, false)); + assert!(result.is_err()); + } +} -- Gitee From 9c88203b2f2ebd7d00caf9b35bee9c053a6ad6a4 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 21 Mar 2024 22:12:18 +0800 Subject: [PATCH 023/489] pvpanic: use clap to parse the parameters of the pvpanic config Use clap to parse the parameters of the pvpanic config. Signed-off-by: liuxiangdong --- devices/src/misc/pvpanic.rs | 53 +++++++++++++++++- machine/src/lib.rs | 11 ++-- machine_manager/src/config/mod.rs | 4 -- machine_manager/src/config/pvpanic_pci.rs | 66 ----------------------- tests/mod_test/tests/pvpanic_test.rs | 2 +- 5 files changed, 57 insertions(+), 79 deletions(-) delete mode 100644 machine_manager/src/config/pvpanic_pci.rs diff --git a/devices/src/misc/pvpanic.rs b/devices/src/misc/pvpanic.rs index e2d29dd1..a6597954 100644 --- a/devices/src/misc/pvpanic.rs +++ b/devices/src/misc/pvpanic.rs @@ -16,7 +16,9 @@ use std::sync::{ }; use anyhow::{bail, Context, Result}; +use clap::Parser; use log::{debug, error, info}; +use serde::{Deserialize, Serialize}; use crate::pci::{ config::{ @@ -29,7 +31,7 @@ use crate::pci::{ }; use crate::{Device, DeviceBase}; use address_space::{GuestAddress, Region, RegionOps}; -use machine_manager::config::{PvpanicDevConfig, PVPANIC_CRASHLOADED, PVPANIC_PANICKED}; +use machine_manager::config::{get_pci_df, valid_id}; const PVPANIC_PCI_REVISION_ID: u8 = 1; const PVPANIC_PCI_VENDOR_ID: u16 = PCI_VENDOR_ID_REDHAT_QUMRANET; @@ -40,6 +42,33 @@ const PVPANIC_REG_BAR_SIZE: u64 = 0x4; #[cfg(target_arch = "x86_64")] const PVPANIC_REG_BAR_SIZE: u64 = 0x1; +pub const PVPANIC_PANICKED: u32 = 1 << 0; +pub const PVPANIC_CRASHLOADED: u32 = 1 << 1; + +#[derive(Parser, Debug, Clone, Serialize, Deserialize)] +#[command(no_binary_name(true))] +pub struct PvpanicDevConfig { + #[arg(long, value_parser = ["pvpanic"])] + pub classtype: String, + #[arg(long, value_parser = valid_id)] + pub id: String, + #[arg(long)] + pub bus: String, + #[arg(long, value_parser = get_pci_df)] + pub addr: (u8, u8), + #[arg(long, alias = "supported-features", default_value = "3", value_parser = valid_supported_features)] + pub supported_features: u32, +} + +fn valid_supported_features(f: &str) -> Result { + let features = f.parse::()?; + let supported_features = match features & !(PVPANIC_PANICKED | PVPANIC_CRASHLOADED) { + 0 => features, + _ => bail!("Unsupported pvpanic device features {}", features), + }; + Ok(supported_features) +} + #[derive(Copy, Clone)] pub struct PvPanicState { supported_features: u32, @@ -244,6 +273,7 @@ impl PciDevOps for PvPanicPci { mod tests { use super::*; use crate::pci::{host::tests::create_pci_host, le_read_u16, PciHost}; + use machine_manager::config::str_slip_to_clap; fn init_pvpanic_dev(devfn: u8, supported_features: u32, dev_id: &str) -> Arc> { let pci_host = create_pci_host(); @@ -253,6 +283,9 @@ mod tests { let config = PvpanicDevConfig { id: dev_id.to_string(), supported_features, + classtype: "".to_string(), + bus: "pcie.0".to_string(), + addr: (3, 0), }; let pvpanic_dev = PvPanicPci::new(&config, devfn, root_bus.clone()); assert_eq!(pvpanic_dev.base.base.id, "pvpanic_test".to_string()); @@ -264,6 +297,24 @@ mod tests { pci_host } + #[test] + fn test_pvpanic_cmdline_parser() { + // Test1: Right. + let cmdline = "pvpanic,id=pvpanic0,bus=pcie.0,addr=0x7,supported-features=0"; + let result = PvpanicDevConfig::try_parse_from(str_slip_to_clap(cmdline, true, false)); + assert_eq!(result.unwrap().supported_features, 0); + + // Test2: Default value. + let cmdline = "pvpanic,id=pvpanic0,bus=pcie.0,addr=0x7"; + let result = PvpanicDevConfig::try_parse_from(str_slip_to_clap(cmdline, true, false)); + assert_eq!(result.unwrap().supported_features, 3); + + // Test3: Illegal value. + let cmdline = "pvpanic,id=pvpanic0,bus=pcie.0,addr=0x7,supported-features=4"; + let result = PvpanicDevConfig::try_parse_from(str_slip_to_clap(cmdline, true, false)); + assert!(result.is_err()); + } + #[test] fn test_pvpanic_attached() { let pci_host = init_pvpanic_dev(7, PVPANIC_PANICKED | PVPANIC_CRASHLOADED, "pvpanic_test"); diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 25f5a8be..7fc1b396 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -47,7 +47,7 @@ use cpu::CPUFeatures; use cpu::{ArchCPU, CPUBootConfig, CPUHypervisorOps, CPUInterface, CPUTopology, CpuTopology, CPU}; use devices::legacy::FwCfgOps; #[cfg(feature = "pvpanic")] -use devices::misc::pvpanic::PvPanicPci; +use devices::misc::pvpanic::{PvPanicPci, PvpanicDevConfig}; #[cfg(feature = "scream")] use devices::misc::scream::{Scream, ScreamConfig}; #[cfg(feature = "demo_device")] @@ -72,8 +72,6 @@ use devices::ScsiDisk::{ScsiDevConfig, ScsiDevice}; use hypervisor::{kvm::KvmHypervisor, test::TestHypervisor, HypervisorOps}; #[cfg(feature = "usb_camera")] use machine_manager::config::get_cameradev_by_id; -#[cfg(feature = "pvpanic")] -use machine_manager::config::parse_pvpanic; use machine_manager::config::{ complete_numa_node, get_multi_function, get_pci_bdf, parse_blk, parse_device_id, parse_device_type, parse_net, parse_numa_distance, parse_numa_mem, parse_rng_dev, @@ -1031,11 +1029,10 @@ pub trait MachineOps { #[cfg(feature = "pvpanic")] fn add_pvpanic(&mut self, cfg_args: &str) -> Result<()> { - let bdf = get_pci_bdf(cfg_args)?; - let device_cfg = parse_pvpanic(cfg_args)?; - + let config = PvpanicDevConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + let bdf = PciBdf::new(config.bus.clone(), config.addr); let (devfn, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?; - let pcidev = PvPanicPci::new(&device_cfg, devfn, parent_bus); + let pcidev = PvPanicPci::new(&config, devfn, parent_bus); pcidev .realize() .with_context(|| "Failed to realize pvpanic device")?; diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index 519c5b5e..05e91a6f 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -28,8 +28,6 @@ mod machine_config; mod network; mod numa; mod pci; -#[cfg(feature = "pvpanic")] -mod pvpanic_pci; mod rng; #[cfg(feature = "vnc_auth")] mod sasl_auth; @@ -52,8 +50,6 @@ pub use machine_config::*; pub use network::*; pub use numa::*; pub use pci::*; -#[cfg(feature = "pvpanic")] -pub use pvpanic_pci::*; pub use rng::*; #[cfg(feature = "vnc_auth")] pub use sasl_auth::*; diff --git a/machine_manager/src/config/pvpanic_pci.rs b/machine_manager/src/config/pvpanic_pci.rs deleted file mode 100644 index d0c3b872..00000000 --- a/machine_manager/src/config/pvpanic_pci.rs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. -// -// StratoVirt is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan -// PSL v2. -// You may obtain a copy of Mulan PSL v2 at: -// http://license.coscl.org.cn/MulanPSL2 -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY -// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -// See the Mulan PSL v2 for more details. - -use crate::config::{CmdParser, ConfigCheck}; -use anyhow::{bail, Context, Result}; -use serde::{Deserialize, Serialize}; - -pub const PVPANIC_PANICKED: u32 = 1 << 0; -pub const PVPANIC_CRASHLOADED: u32 = 1 << 1; - -#[derive(Debug, Clone, Serialize, Deserialize)] -pub struct PvpanicDevConfig { - pub id: String, - pub supported_features: u32, -} - -impl Default for PvpanicDevConfig { - fn default() -> Self { - PvpanicDevConfig { - id: "".to_string(), - supported_features: PVPANIC_PANICKED | PVPANIC_CRASHLOADED, - } - } -} - -impl ConfigCheck for PvpanicDevConfig { - fn check(&self) -> Result<()> { - Ok(()) - } -} - -pub fn parse_pvpanic(args_config: &str) -> Result { - let mut cmd_parser = CmdParser::new("pvpanic"); - cmd_parser - .push("") - .push("id") - .push("bus") - .push("addr") - .push("supported-features"); - cmd_parser.parse(args_config)?; - - let mut pvpanicdevcfg = PvpanicDevConfig::default(); - - if let Some(features) = cmd_parser.get_value::("supported-features")? { - pvpanicdevcfg.supported_features = - match features & !(PVPANIC_PANICKED | PVPANIC_CRASHLOADED) { - 0 => features, - _ => bail!("Unsupported pvpanic device features {}", features), - } - } - - pvpanicdevcfg.id = cmd_parser - .get_value::("id")? - .with_context(|| "No id configured for pvpanic device")?; - - Ok(pvpanicdevcfg) -} diff --git a/tests/mod_test/tests/pvpanic_test.rs b/tests/mod_test/tests/pvpanic_test.rs index 04451596..03dfc678 100644 --- a/tests/mod_test/tests/pvpanic_test.rs +++ b/tests/mod_test/tests/pvpanic_test.rs @@ -15,11 +15,11 @@ use std::fs; use std::path::Path; use std::rc::Rc; +use devices::misc::pvpanic::{PVPANIC_CRASHLOADED, PVPANIC_PANICKED}; use devices::pci::config::{ PCI_CLASS_SYSTEM_OTHER, PCI_DEVICE_ID_REDHAT_PVPANIC, PCI_SUBDEVICE_ID_QEMU, PCI_VENDOR_ID_REDHAT, PCI_VENDOR_ID_REDHAT_QUMRANET, }; -use machine_manager::config::{PVPANIC_CRASHLOADED, PVPANIC_PANICKED}; use mod_test::{ libdriver::{machine::TestStdMachine, pci::*}, libtest::{test_init, TestState, MACHINE_TYPE_ARG}, -- Gitee From 998767d31f91a1abc7dc4d764e462a0e527a8379 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 21 Mar 2024 22:40:30 +0800 Subject: [PATCH 024/489] iothread: use clap to parse the parameters of the iothread config Use clap to parse the parameters of the iothread config. Signed-off-by: liuxiangdong --- machine_manager/src/config/iothread.rs | 28 +++++++++----------------- virtio/src/device/block.rs | 1 + 2 files changed, 11 insertions(+), 18 deletions(-) diff --git a/machine_manager/src/config/iothread.rs b/machine_manager/src/config/iothread.rs index ac3a0a9e..029d6583 100644 --- a/machine_manager/src/config/iothread.rs +++ b/machine_manager/src/config/iothread.rs @@ -11,37 +11,29 @@ // See the Mulan PSL v2 for more details. use anyhow::{anyhow, Result}; +use clap::Parser; use serde::{Deserialize, Serialize}; -use super::error::ConfigError; -use crate::config::{check_arg_too_long, CmdParser, ConfigCheck, VmConfig}; +use super::{error::ConfigError, str_slip_to_clap, valid_id}; +use crate::config::VmConfig; const MAX_IOTHREAD_NUM: usize = 8; /// Config structure for iothread. -#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[derive(Parser, Debug, Clone, Default, Serialize, Deserialize)] +#[command(no_binary_name(true))] pub struct IothreadConfig { + #[arg(long, value_parser = ["iothread"])] + pub classtype: String, + #[arg(long, value_parser = valid_id)] pub id: String, } -impl ConfigCheck for IothreadConfig { - fn check(&self) -> Result<()> { - check_arg_too_long(&self.id, "iothread id") - } -} - impl VmConfig { /// Add new iothread device to `VmConfig`. pub fn add_iothread(&mut self, iothread_config: &str) -> Result<()> { - let mut cmd_parser = CmdParser::new("iothread"); - cmd_parser.push("").push("id"); - cmd_parser.parse(iothread_config)?; - - let mut iothread = IothreadConfig::default(); - if let Some(id) = cmd_parser.get_value::("id")? { - iothread.id = id; - } - iothread.check()?; + let iothread = + IothreadConfig::try_parse_from(str_slip_to_clap(iothread_config, true, false))?; if self.iothreads.is_some() { if self.iothreads.as_ref().unwrap().len() >= MAX_IOTHREAD_NUM { diff --git a/virtio/src/device/block.rs b/virtio/src/device/block.rs index a7719cf3..0aeddca7 100644 --- a/virtio/src/device/block.rs +++ b/virtio/src/device/block.rs @@ -1541,6 +1541,7 @@ mod tests { // spawn io thread let io_conf = IothreadConfig { + classtype: "iothread".to_string(), id: thread_name.clone(), }; EventLoop::object_init(&Some(vec![io_conf])).unwrap(); -- Gitee From 42cc07b58ba4ed06823e68b452b6001de17d7057 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Fri, 22 Mar 2024 10:26:54 +0800 Subject: [PATCH 025/489] authz-simple: use clap to parse the parameters of the authz-simple config Use clap to parse the parameters of the authz-simple config. Signed-off-by: liuxiangdong --- machine_manager/src/config/sasl_auth.rs | 37 +++++++++---------------- 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/machine_manager/src/config/sasl_auth.rs b/machine_manager/src/config/sasl_auth.rs index 506763ad..37b47bc7 100644 --- a/machine_manager/src/config/sasl_auth.rs +++ b/machine_manager/src/config/sasl_auth.rs @@ -10,44 +10,33 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, Result}; +use clap::Parser; use serde::{Deserialize, Serialize}; -use crate::config::{ - ConfigError, {CmdParser, VmConfig}, -}; +use crate::config::{str_slip_to_clap, valid_id, ConfigError, VmConfig}; -#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[derive(Parser, Debug, Clone, Default, Serialize, Deserialize)] +#[command(no_binary_name(true))] pub struct SaslAuthObjConfig { - /// Object Id. + #[arg(long, value_parser = ["authz-simple"])] + pub classtype: String, + #[arg(long, value_parser = valid_id)] pub id: String, /// Authentication User Name. + #[arg(long, default_value = "")] pub identity: String, } impl VmConfig { pub fn add_saslauth(&mut self, saslauth_config: &str) -> Result<()> { - let mut cmd_parser = CmdParser::new("authz-simple"); - cmd_parser.push("").push("id").push("identity"); - cmd_parser.parse(saslauth_config)?; - - let mut saslauth = SaslAuthObjConfig { - id: cmd_parser.get_value::("id")?.with_context(|| { - ConfigError::FieldIsMissing("id".to_string(), "vnc sasl_auth".to_string()) - })?, - ..Default::default() - }; - - if let Some(identity) = cmd_parser.get_value::("identity")? { - saslauth.identity = identity; - } - + let saslauth = + SaslAuthObjConfig::try_parse_from(str_slip_to_clap(saslauth_config, true, false))?; let id = saslauth.id.clone(); - if self.object.sasl_object.get(&id).is_none() { - self.object.sasl_object.insert(id, saslauth); - } else { + if self.object.sasl_object.get(&id).is_some() { return Err(anyhow!(ConfigError::IdRepeat("saslauth".to_string(), id))); } + self.object.sasl_object.insert(id, saslauth); Ok(()) } -- Gitee From 93e053913c0c199b70e3749d054dd2225cb6c642 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Fri, 22 Mar 2024 11:15:45 +0800 Subject: [PATCH 026/489] tls_creds: use clap to parse the parameters of the tls_creds config Use clap to parse the parameters of the tls_creds config. Signed-off-by: liuxiangdong --- machine_manager/src/config/mod.rs | 9 ++++ machine_manager/src/config/tls_creds.rs | 58 +++++++------------------ ui/src/vnc/server_io.rs | 2 +- 3 files changed, 25 insertions(+), 44 deletions(-) diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index 05e91a6f..b8742e51 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -62,6 +62,7 @@ pub use vnc::*; use std::collections::HashMap; use std::fs::{canonicalize, File}; use std::io::Read; +use std::path::Path; use std::str::FromStr; use anyhow::{anyhow, bail, Context, Result}; @@ -822,6 +823,14 @@ pub fn valid_socket_path(sock_path: &str) -> Result { valid_path(sock_path) } +pub fn valid_dir(d: &str) -> Result { + let dir = String::from(d); + if !Path::new(&dir).is_dir() { + return Err(anyhow!(ConfigError::DirNotExist(dir))); + } + Ok(dir) +} + #[cfg(test)] mod tests { use super::*; diff --git a/machine_manager/src/config/tls_creds.rs b/machine_manager/src/config/tls_creds.rs index 8803ea42..92903161 100644 --- a/machine_manager/src/config/tls_creds.rs +++ b/machine_manager/src/config/tls_creds.rs @@ -10,64 +10,36 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use std::path::Path; - -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, Result}; +use clap::{ArgAction, Parser}; use serde::{Deserialize, Serialize}; -use crate::config::{ - ConfigError, {CmdParser, VmConfig}, -}; +use crate::config::{str_slip_to_clap, valid_dir, valid_id, ConfigError, VmConfig}; -#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[derive(Parser, Debug, Clone, Default, Serialize, Deserialize)] +#[command(no_binary_name(true))] pub struct TlsCredObjConfig { + #[arg(long)] + pub classtype: String, + #[arg(long, value_parser = valid_id)] pub id: String, + #[arg(long, value_parser = valid_dir)] pub dir: String, - pub cred_type: String, + #[arg(long)] pub endpoint: Option, + #[arg(long, alias = "verify-peer", default_value= "false", action = ArgAction::Append)] pub verifypeer: bool, } impl VmConfig { pub fn add_tlscred(&mut self, tlscred_config: &str) -> Result<()> { - let mut cmd_parser = CmdParser::new("tls-creds-x509"); - cmd_parser - .push("") - .push("id") - .push("dir") - .push("endpoint") - .push("verify-peer"); - cmd_parser.parse(tlscred_config)?; - - let mut tlscred = TlsCredObjConfig { - id: cmd_parser.get_value::("id")?.with_context(|| { - ConfigError::FieldIsMissing("id".to_string(), "vnc tls_creds".to_string()) - })?, - ..Default::default() - }; - - if let Some(dir) = cmd_parser.get_value::("dir")? { - if Path::new(&dir).is_dir() { - tlscred.dir = dir; - } else { - return Err(anyhow!(ConfigError::DirNotExist(dir))); - } - } - if let Some(endpoint) = cmd_parser.get_value::("endpoint")? { - tlscred.endpoint = Some(endpoint); - } - if let Some(verifypeer) = cmd_parser.get_value::("verify-peer")? { - tlscred.verifypeer = verifypeer == *"true"; - } - tlscred.cred_type = "x509".to_string(); - + let tlscred = + TlsCredObjConfig::try_parse_from(str_slip_to_clap(tlscred_config, true, false))?; let id = tlscred.id.clone(); - if self.object.tls_object.get(&id).is_none() { - self.object.tls_object.insert(id, tlscred); - } else { + if self.object.tls_object.get(&id).is_some() { return Err(anyhow!(ConfigError::IdRepeat("tlscred".to_string(), id))); } - + self.object.tls_object.insert(id, tlscred); Ok(()) } } diff --git a/ui/src/vnc/server_io.rs b/ui/src/vnc/server_io.rs index 76af9e8d..ac577df1 100644 --- a/ui/src/vnc/server_io.rs +++ b/ui/src/vnc/server_io.rs @@ -221,7 +221,7 @@ impl SecurityType { // Tls configuration. if let Some(tls_cred) = object.tls_object.get(&vnc_cfg.tls_creds) { let tlscred = TlsCreds { - cred_type: tls_cred.cred_type.clone(), + cred_type: "x509".to_string(), dir: tls_cred.dir.clone(), endpoint: tls_cred.endpoint.clone(), verifypeer: tls_cred.verifypeer, -- Gitee From af645d20e72c544e15f8d3cc7492dee36ddcb206 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Fri, 22 Mar 2024 19:56:10 +0800 Subject: [PATCH 027/489] rng: use clap to parse the parameters of the rng config Use clap to parse the parameters of the rng config. Signed-off-by: liuxiangdong --- machine/src/lib.rs | 28 ++-- machine_manager/src/config/mod.rs | 9 +- machine_manager/src/config/rng.rs | 241 +----------------------------- virtio/src/device/rng.rs | 150 +++++++++++++++---- virtio/src/lib.rs | 2 +- 5 files changed, 151 insertions(+), 279 deletions(-) diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 7fc1b396..ab1429b2 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -74,11 +74,11 @@ use hypervisor::{kvm::KvmHypervisor, test::TestHypervisor, HypervisorOps}; use machine_manager::config::get_cameradev_by_id; use machine_manager::config::{ complete_numa_node, get_multi_function, get_pci_bdf, parse_blk, parse_device_id, - parse_device_type, parse_net, parse_numa_distance, parse_numa_mem, parse_rng_dev, - parse_root_port, parse_vhost_user_blk, parse_virtio_serial, parse_virtserialport, parse_vsock, - str_slip_to_clap, BootIndexInfo, BootSource, DriveConfig, DriveFile, Incoming, - MachineMemConfig, MigrateMode, NumaConfig, NumaDistance, NumaNode, NumaNodes, PciBdf, - SerialConfig, VmConfig, FAST_UNPLUG_ON, MAX_VIRTIO_QUEUE, + parse_device_type, parse_net, parse_numa_distance, parse_numa_mem, parse_root_port, + parse_vhost_user_blk, parse_virtio_serial, parse_virtserialport, parse_vsock, str_slip_to_clap, + BootIndexInfo, BootSource, DriveConfig, DriveFile, Incoming, MachineMemConfig, MigrateMode, + NumaConfig, NumaDistance, NumaNode, NumaNodes, PciBdf, SerialConfig, VmConfig, FAST_UNPLUG_ON, + MAX_VIRTIO_QUEUE, }; use machine_manager::event_loop::EventLoop; use machine_manager::machine::{HypervisorType, MachineInterface, VmState}; @@ -95,7 +95,7 @@ use vfio::{VfioConfig, VfioDevice, VfioPciDevice, KVM_DEVICE_FD}; use virtio::VirtioDeviceQuirk; use virtio::{ balloon_allow_list, find_port_by_nr, get_max_nr, vhost, Balloon, BalloonConfig, Block, - BlockState, Rng, RngState, + BlockState, Rng, RngConfig, RngState, ScsiCntlr::{scsi_cntlr_create_scsi_bus, ScsiCntlr, ScsiCntlrConfig}, Serial, SerialPort, VhostKern, VhostUser, VirtioDevice, VirtioMmioDevice, VirtioMmioState, VirtioNetState, VirtioPciDevice, VirtioSerialState, VIRTIO_TYPE_CONSOLE, @@ -810,19 +810,25 @@ pub trait MachineOps { /// * `vm_config` - VM configuration. /// * `cfg_args` - Device configuration arguments. fn add_virtio_rng(&mut self, vm_config: &mut VmConfig, cfg_args: &str) -> Result<()> { - let rng_cfg = parse_rng_dev(vm_config, cfg_args)?; + let rng_cfg = RngConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + rng_cfg.bytes_per_sec()?; + let rngobj_cfg = vm_config + .object + .rng_object + .remove(&rng_cfg.rng) + .with_context(|| "Object for rng-random device not found")?; let sys_mem = self.get_sys_mem(); - let rng_dev = Arc::new(Mutex::new(Rng::new(rng_cfg.clone()))); + let rng_dev = Arc::new(Mutex::new(Rng::new(rng_cfg.clone(), rngobj_cfg))); - match parse_device_type(cfg_args)?.as_str() { + match rng_cfg.classtype.as_str() { "virtio-rng-device" => { let device = VirtioMmioDevice::new(sys_mem, rng_dev.clone()); self.realize_virtio_mmio_device(device) .with_context(|| "Failed to add virtio mmio rng device")?; } _ => { - let bdf = get_pci_bdf(cfg_args)?; - let multi_func = get_multi_function(cfg_args)?; + let bdf = PciBdf::new(rng_cfg.bus.clone().unwrap(), rng_cfg.addr.unwrap()); + let multi_func = rng_cfg.multifunction.unwrap_or_default(); self.add_virtio_pci_device(&rng_cfg.id, &bdf, rng_dev.clone(), multi_func, false) .with_context(|| "Failed to add pci rng device")?; } diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index b8742e51..bb69d1e0 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -66,6 +66,7 @@ use std::path::Path; use std::str::FromStr; use anyhow::{anyhow, bail, Context, Result}; +use clap::Parser; use log::error; use serde::{Deserialize, Serialize}; @@ -209,13 +210,13 @@ impl VmConfig { .with_context(|| "Failed to add iothread")?; } "rng-random" => { - let rng_cfg = parse_rng_obj(object_args)?; + let rng_cfg = + RngObjConfig::try_parse_from(str_slip_to_clap(object_args, true, false))?; let id = rng_cfg.id.clone(); - if self.object.rng_object.get(&id).is_none() { - self.object.rng_object.insert(id, rng_cfg); - } else { + if self.object.rng_object.get(&id).is_some() { bail!("Object: {} has been added", id); } + self.object.rng_object.insert(id, rng_cfg); } "memory-backend-ram" | "memory-backend-file" | "memory-backend-memfd" => { self.add_mem_zone(object_args, device_type)?; diff --git a/machine_manager/src/config/rng.rs b/machine_manager/src/config/rng.rs index b153dcf2..78c3ef79 100644 --- a/machine_manager/src/config/rng.rs +++ b/machine_manager/src/config/rng.rs @@ -10,243 +10,18 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use anyhow::{anyhow, bail, Context, Result}; +use clap::Parser; use serde::{Deserialize, Serialize}; -use super::error::ConfigError; -use super::pci_args_check; -use crate::config::{CmdParser, ConfigCheck, VmConfig, MAX_PATH_LENGTH}; +use crate::config::{valid_id, valid_path}; -const MIN_BYTES_PER_SEC: u64 = 64; -const MAX_BYTES_PER_SEC: u64 = 1_000_000_000; - -#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[derive(Parser, Debug, Clone, Default, Serialize, Deserialize)] +#[command(no_binary_name(true))] pub struct RngObjConfig { + #[arg(long, value_parser = ["rng-random"])] + pub classtype: String, + #[arg(long, value_parser = valid_id)] pub id: String, + #[arg(long, value_parser = valid_path)] pub filename: String, } - -/// Config structure for virtio-rng. -#[derive(Debug, Clone, Default)] -pub struct RngConfig { - pub id: String, - pub random_file: String, - pub bytes_per_sec: Option, -} - -impl ConfigCheck for RngConfig { - fn check(&self) -> Result<()> { - if self.id.len() > MAX_PATH_LENGTH { - return Err(anyhow!(ConfigError::StringLengthTooLong( - "rng id".to_string(), - MAX_PATH_LENGTH - ))); - } - - if self.random_file.len() > MAX_PATH_LENGTH { - return Err(anyhow!(ConfigError::StringLengthTooLong( - "rng random file".to_string(), - MAX_PATH_LENGTH, - ))); - } - - if let Some(bytes_per_sec) = self.bytes_per_sec { - if !(MIN_BYTES_PER_SEC..=MAX_BYTES_PER_SEC).contains(&bytes_per_sec) { - return Err(anyhow!(ConfigError::IllegalValue( - "The bytes per second of rng device".to_string(), - MIN_BYTES_PER_SEC, - true, - MAX_BYTES_PER_SEC, - true, - ))); - } - } - - Ok(()) - } -} - -pub fn parse_rng_dev(vm_config: &mut VmConfig, rng_config: &str) -> Result { - let mut cmd_parser = CmdParser::new("rng"); - cmd_parser - .push("") - .push("id") - .push("bus") - .push("addr") - .push("multifunction") - .push("max-bytes") - .push("period") - .push("rng"); - - cmd_parser.parse(rng_config)?; - pci_args_check(&cmd_parser)?; - let mut rng_cfg = RngConfig::default(); - let rng = cmd_parser - .get_value::("rng")? - .with_context(|| ConfigError::FieldIsMissing("rng".to_string(), "rng".to_string()))?; - - rng_cfg.id = cmd_parser.get_value::("id")?.unwrap_or_default(); - - if let Some(max) = cmd_parser.get_value::("max-bytes")? { - if let Some(peri) = cmd_parser.get_value::("period")? { - let mul = max - .checked_mul(1000) - .with_context(|| format!("Illegal max-bytes arguments: {:?}", max))?; - let div = mul - .checked_div(peri) - .with_context(|| format!("Illegal period arguments: {:?}", peri))?; - rng_cfg.bytes_per_sec = Some(div); - } else { - bail!("Argument 'period' is missing"); - } - } else if cmd_parser.get_value::("period")?.is_some() { - bail!("Argument 'max-bytes' is missing"); - } - - rng_cfg.random_file = vm_config - .object - .rng_object - .remove(&rng) - .map(|rng_object| rng_object.filename) - .with_context(|| "Object for rng-random device not found")?; - - rng_cfg.check()?; - Ok(rng_cfg) -} - -pub fn parse_rng_obj(object_args: &str) -> Result { - let mut cmd_params = CmdParser::new("rng-object"); - cmd_params.push("").push("id").push("filename"); - - cmd_params.parse(object_args)?; - let id = cmd_params - .get_value::("id")? - .with_context(|| ConfigError::FieldIsMissing("id".to_string(), "rng-object".to_string()))?; - let filename = cmd_params - .get_value::("filename")? - .with_context(|| { - ConfigError::FieldIsMissing("filename".to_string(), "rng-object".to_string()) - })?; - let rng_obj_cfg = RngObjConfig { id, filename }; - - Ok(rng_obj_cfg) -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::config::get_pci_bdf; - - #[test] - fn test_rng_config_cmdline_parser_01() { - let mut vm_config = VmConfig::default(); - assert!(vm_config - .add_object("rng-random,id=objrng0,filename=/path/to/random_file") - .is_ok()); - let rng_config = parse_rng_dev(&mut vm_config, "virtio-rng-device,rng=objrng0"); - assert!(rng_config.is_ok()); - let config = rng_config.unwrap(); - assert_eq!(config.random_file, "/path/to/random_file"); - assert_eq!(config.bytes_per_sec, None); - - let mut vm_config = VmConfig::default(); - assert!(vm_config - .add_object("rng-random,id=objrng0,filename=/path/to/random_file") - .is_ok()); - let rng_config = parse_rng_dev( - &mut vm_config, - "virtio-rng-device,rng=objrng0,max-bytes=1234,period=1000", - ); - assert!(rng_config.is_ok()); - let config = rng_config.unwrap(); - assert_eq!(config.random_file, "/path/to/random_file"); - assert_eq!(config.bytes_per_sec, Some(1234)); - } - - #[test] - fn test_rng_config_cmdline_parser_02() { - let mut vm_config = VmConfig::default(); - assert!(vm_config - .add_object("rng-random,id=objrng0,filename=/path/to/random_file") - .is_ok()); - let rng_config = parse_rng_dev( - &mut vm_config, - "virtio-rng-device,rng=objrng0,max-bytes=63,period=1000", - ); - assert!(rng_config.is_err()); - - let mut vm_config = VmConfig::default(); - assert!(vm_config - .add_object("rng-random,id=objrng0,filename=/path/to/random_file") - .is_ok()); - let rng_config = parse_rng_dev( - &mut vm_config, - "virtio-rng-device,rng=objrng0,max-bytes=64,period=1000", - ); - assert!(rng_config.is_ok()); - let config = rng_config.unwrap(); - assert_eq!(config.random_file, "/path/to/random_file"); - assert_eq!(config.bytes_per_sec, Some(64)); - - let mut vm_config = VmConfig::default(); - assert!(vm_config - .add_object("rng-random,id=objrng0,filename=/path/to/random_file") - .is_ok()); - let rng_config = parse_rng_dev( - &mut vm_config, - "virtio-rng-device,rng=objrng0,max-bytes=1000000000,period=1000", - ); - assert!(rng_config.is_ok()); - let config = rng_config.unwrap(); - assert_eq!(config.random_file, "/path/to/random_file"); - assert_eq!(config.bytes_per_sec, Some(1000000000)); - - let mut vm_config = VmConfig::default(); - assert!(vm_config - .add_object("rng-random,id=objrng0,filename=/path/to/random_file") - .is_ok()); - let rng_config = parse_rng_dev( - &mut vm_config, - "virtio-rng-device,rng=objrng0,max-bytes=1000000001,period=1000", - ); - assert!(rng_config.is_err()); - } - - #[test] - fn test_pci_rng_config_cmdline_parser() { - let mut vm_config = VmConfig::default(); - assert!(vm_config - .add_object("rng-random,id=objrng0,filename=/path/to/random_file") - .is_ok()); - let rng_cfg = "virtio-rng-pci,rng=objrng0,bus=pcie.0,addr=0x1.0x3"; - let rng_config = parse_rng_dev(&mut vm_config, rng_cfg); - assert!(rng_config.is_ok()); - let config = rng_config.unwrap(); - assert_eq!(config.random_file, "/path/to/random_file"); - assert_eq!(config.bytes_per_sec, None); - let pci_bdf = get_pci_bdf(rng_cfg); - assert!(pci_bdf.is_ok()); - let pci = pci_bdf.unwrap(); - assert_eq!(pci.bus, "pcie.0".to_string()); - assert_eq!(pci.addr, (1, 3)); - - // object "objrng0" has been removed. - let rng_config = parse_rng_dev(&mut vm_config, rng_cfg); - assert!(rng_config.is_err()); - - let mut vm_config = VmConfig::default(); - assert!(vm_config - .add_object("rng-random,id=objrng0,filename=/path/to/random_file") - .is_ok()); - let rng_cfg = "virtio-rng-device,rng=objrng0,bus=pcie.0,addr=0x1.0x3"; - let rng_config = parse_rng_dev(&mut vm_config, rng_cfg); - assert!(rng_config.is_err()); - - let mut vm_config = VmConfig::default(); - assert!(vm_config - .add_object("rng-random,id=objrng0,filename=/path/to/random_file") - .is_ok()); - let rng_cfg = "virtio-rng-pci,rng=objrng0,bus=pcie.0,addr=0x1.0x3,multifunction=on"; - assert!(parse_rng_dev(&mut vm_config, rng_cfg).is_ok()); - } -} diff --git a/virtio/src/device/rng.rs b/virtio/src/device/rng.rs index c4410524..9f1007ed 100644 --- a/virtio/src/device/rng.rs +++ b/virtio/src/device/rng.rs @@ -18,7 +18,8 @@ use std::path::Path; use std::rc::Rc; use std::sync::{Arc, Mutex}; -use anyhow::{bail, Context, Result}; +use anyhow::{anyhow, bail, Context, Result}; +use clap::Parser; use log::error; use vmm_sys_util::epoll::EventSet; use vmm_sys_util::eventfd::EventFd; @@ -30,7 +31,7 @@ use crate::{ }; use address_space::AddressSpace; use machine_manager::{ - config::{RngConfig, DEFAULT_VIRTQUEUE_SIZE}, + config::{get_pci_df, valid_id, ConfigError, RngObjConfig, DEFAULT_VIRTQUEUE_SIZE}, event_loop::EventLoop, event_loop::{register_event_helper, unregister_event_helper}, }; @@ -46,6 +47,62 @@ use util::loop_context::{ const QUEUE_NUM_RNG: usize = 1; const RNG_SIZE_MAX: u32 = 1 << 20; +const MIN_BYTES_PER_SEC: u64 = 64; +const MAX_BYTES_PER_SEC: u64 = 1_000_000_000; + +/// Config structure for virtio-rng. +#[derive(Parser, Debug, Clone, Default)] +#[command(no_binary_name(true))] +pub struct RngConfig { + #[arg(long, value_parser = ["virtio-rng-device", "virtio-rng-pci"])] + pub classtype: String, + #[arg(long, default_value = "", value_parser = valid_id)] + pub id: String, + #[arg(long)] + pub rng: String, + #[arg(long, alias = "max-bytes")] + pub max_bytes: Option, + #[arg(long)] + pub period: Option, + #[arg(long)] + pub bus: Option, + #[arg(long, value_parser = get_pci_df)] + pub addr: Option<(u8, u8)>, + #[arg(long)] + pub multifunction: Option, +} + +impl RngConfig { + pub fn bytes_per_sec(&self) -> Result> { + if self.max_bytes.is_some() != self.period.is_some() { + bail!("\"max_bytes\" and \"period\" should be configured or not configured Simultaneously."); + } + + if let Some(max) = self.max_bytes { + let peri = self.period.unwrap(); + let mul = max + .checked_mul(1000) + .with_context(|| format!("Illegal max-bytes arguments: {:?}", max))?; + let bytes_per_sec = mul + .checked_div(peri) + .with_context(|| format!("Illegal period arguments: {:?}", peri))?; + + if !(MIN_BYTES_PER_SEC..=MAX_BYTES_PER_SEC).contains(&bytes_per_sec) { + return Err(anyhow!(ConfigError::IllegalValue( + "The bytes per second of rng device".to_string(), + MIN_BYTES_PER_SEC, + true, + MAX_BYTES_PER_SEC, + true, + ))); + } + + return Ok(Some(bytes_per_sec)); + } + Ok(None) + } +} + fn get_req_data_size(in_iov: &[ElemIovec]) -> Result { let mut size = 0_u32; for iov in in_iov { @@ -216,34 +273,37 @@ pub struct RngState { pub struct Rng { /// Virtio device base property. base: VirtioBase, - /// Configuration of virtio rng device + /// Configuration of virtio rng device. rng_cfg: RngConfig, + /// Configuration of rng-random. + rngobj_cfg: RngObjConfig, /// The file descriptor of random number generator random_file: Option, } impl Rng { - pub fn new(rng_cfg: RngConfig) -> Self { + pub fn new(rng_cfg: RngConfig, rngobj_cfg: RngObjConfig) -> Self { Rng { base: VirtioBase::new(VIRTIO_TYPE_RNG, QUEUE_NUM_RNG, DEFAULT_VIRTQUEUE_SIZE), rng_cfg, + rngobj_cfg, ..Default::default() } } fn check_random_file(&self) -> Result<()> { - let path = Path::new(&self.rng_cfg.random_file); + let path = Path::new(&self.rngobj_cfg.filename); if !path.exists() { bail!( "The path of random file {} is not existed", - self.rng_cfg.random_file + self.rngobj_cfg.filename ); } if !path.metadata().unwrap().file_type().is_char_device() { bail!( "The type of random file {} is not a character special file", - self.rng_cfg.random_file + self.rngobj_cfg.filename ); } @@ -263,7 +323,7 @@ impl VirtioDevice for Rng { fn realize(&mut self) -> Result<()> { self.check_random_file() .with_context(|| "Failed to check random file")?; - let file = File::open(&self.rng_cfg.random_file) + let file = File::open(&self.rngobj_cfg.filename) .with_context(|| "Failed to open file of random number generator")?; self.random_file = Some(file); self.init_config_features()?; @@ -308,7 +368,7 @@ impl VirtioDevice for Rng { .unwrap() .try_clone() .with_context(|| "Failed to clone random file for virtio rng")?, - leak_bucket: match self.rng_cfg.bytes_per_sec { + leak_bucket: match self.rng_cfg.bytes_per_sec()? { Some(bps) => Some(LeakBucket::new(bps)?), None => None, }, @@ -361,7 +421,7 @@ mod tests { use super::*; use crate::*; use address_space::{AddressSpace, GuestAddress, HostMemMapping, Region}; - use machine_manager::config::{RngConfig, DEFAULT_VIRTQUEUE_SIZE}; + use machine_manager::config::{str_slip_to_clap, VmConfig, DEFAULT_VIRTQUEUE_SIZE}; const VIRTQ_DESC_F_NEXT: u16 = 0x01; const VIRTQ_DESC_F_WRITE: u16 = 0x02; @@ -393,21 +453,60 @@ mod tests { sys_space } + #[test] + fn test_rng_config_cmdline_parse() { + // Test1: Right rng-random. + let mut vm_config = VmConfig::default(); + assert!(vm_config + .add_object("rng-random,id=objrng0,filename=/path/to/random_file") + .is_ok()); + let rngobj_cfg = vm_config.object.rng_object.remove("objrng0").unwrap(); + assert_eq!(rngobj_cfg.filename, "/path/to/random_file"); + + // Test2: virtio-rng-device + let rng_cmd = "virtio-rng-device,rng=objrng0"; + let rng_config = RngConfig::try_parse_from(str_slip_to_clap(rng_cmd, true, false)).unwrap(); + assert_eq!(rng_config.bytes_per_sec().unwrap(), None); + assert_eq!(rng_config.multifunction, None); + + // Test3: virtio-rng-pci. + let rng_cmd = "virtio-rng-pci,bus=pcie.0,addr=0x1,rng=objrng0,max-bytes=1234,period=1000"; + let rng_config = RngConfig::try_parse_from(str_slip_to_clap(rng_cmd, true, false)).unwrap(); + assert_eq!(rng_config.bytes_per_sec().unwrap(), Some(1234)); + assert_eq!(rng_config.bus.unwrap(), "pcie.0"); + assert_eq!(rng_config.addr.unwrap(), (1, 0)); + + // Test4: Illegal max-bytes/period. + let rng_cmd = "virtio-rng-device,rng=objrng0,max-bytes=63,period=1000"; + let rng_config = RngConfig::try_parse_from(str_slip_to_clap(rng_cmd, true, false)).unwrap(); + assert!(rng_config.bytes_per_sec().is_err()); + + let rng_cmd = "virtio-rng-device,rng=objrng0,max-bytes=1000000001,period=1000"; + let rng_config = RngConfig::try_parse_from(str_slip_to_clap(rng_cmd, true, false)).unwrap(); + assert!(rng_config.bytes_per_sec().is_err()); + } + #[test] fn test_rng_init() { - let file = TempFile::new().unwrap(); - let random_file = file.as_path().to_str().unwrap().to_string(); + let rngobj_config = RngObjConfig { + classtype: "rng-random".to_string(), + id: "rng0".to_string(), + filename: "".to_string(), + }; let rng_config = RngConfig { - id: "".to_string(), - random_file: random_file.clone(), - bytes_per_sec: Some(64), + classtype: "virtio-rng-pci".to_string(), + rng: "rng0".to_string(), + max_bytes: Some(64), + period: Some(1000), + bus: Some("pcie.0".to_string()), + addr: Some((3, 0)), + ..Default::default() }; - let rng = Rng::new(rng_config); + let rng = Rng::new(rng_config, rngobj_config); assert!(rng.random_file.is_none()); assert_eq!(rng.base.driver_features, 0_u64); assert_eq!(rng.base.device_features, 0_u64); - assert_eq!(rng.rng_cfg.random_file, random_file); - assert_eq!(rng.rng_cfg.bytes_per_sec, Some(64)); + assert_eq!(rng.rng_cfg.bytes_per_sec().unwrap().unwrap(), 64); assert_eq!(rng.queue_num(), QUEUE_NUM_RNG); assert_eq!(rng.queue_size_max(), DEFAULT_VIRTQUEUE_SIZE); @@ -416,18 +515,9 @@ mod tests { #[test] fn test_rng_features() { - let random_file = TempFile::new() - .unwrap() - .as_path() - .to_str() - .unwrap() - .to_string(); - let rng_config = RngConfig { - id: "".to_string(), - random_file, - bytes_per_sec: Some(64), - }; - let mut rng = Rng::new(rng_config); + let rng_config = RngConfig::default(); + let rngobj_cfg = RngObjConfig::default(); + let mut rng = Rng::new(rng_config, rngobj_cfg); // If the device feature is 0, all driver features are not supported. rng.base.device_features = 0; diff --git a/virtio/src/lib.rs b/virtio/src/lib.rs index 9ef9dde8..750d6e1b 100644 --- a/virtio/src/lib.rs +++ b/virtio/src/lib.rs @@ -37,7 +37,7 @@ pub use device::block::{Block, BlockState, VirtioBlkConfig}; #[cfg(feature = "virtio_gpu")] pub use device::gpu::*; pub use device::net::*; -pub use device::rng::{Rng, RngState}; +pub use device::rng::{Rng, RngConfig, RngState}; pub use device::scsi_cntlr as ScsiCntlr; pub use device::serial::{find_port_by_nr, get_max_nr, Serial, SerialPort, VirtioSerialState}; pub use error::VirtioError; -- Gitee From 1914f83f4ff1b1ea95cbf51478312c3b71c460d3 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sat, 23 Mar 2024 01:04:33 +0800 Subject: [PATCH 028/489] rootport: use clap to parse the parameters of the rootport config Use clap to parse the parameters of the rootport config. Signed-off-by: liuxiangdong --- devices/src/pci/bus.rs | 17 +++++++-- devices/src/pci/host.rs | 23 ++++++++++-- devices/src/pci/mod.rs | 2 +- devices/src/pci/root_port.rs | 62 ++++++++++++++++++++++--------- machine/src/lib.rs | 28 ++++++-------- machine_manager/src/config/pci.rs | 62 +------------------------------ 6 files changed, 91 insertions(+), 103 deletions(-) diff --git a/devices/src/pci/bus.rs b/devices/src/pci/bus.rs index d493e181..79746663 100644 --- a/devices/src/pci/bus.rs +++ b/devices/src/pci/bus.rs @@ -275,7 +275,7 @@ mod tests { use crate::pci::bus::PciBus; use crate::pci::config::{PciConfig, PCI_CONFIG_SPACE_SIZE}; use crate::pci::root_port::RootPort; - use crate::pci::{PciDevBase, PciHost}; + use crate::pci::{PciDevBase, PciHost, RootPortConfig}; use crate::{Device, DeviceBase}; use address_space::{AddressSpace, Region}; @@ -372,8 +372,12 @@ mod tests { let pci_host = create_pci_host(); let locked_pci_host = pci_host.lock().unwrap(); let root_bus = Arc::downgrade(&locked_pci_host.root_bus); - - let root_port = RootPort::new("pcie.1".to_string(), 8, 0, root_bus.clone(), false); + let root_port_config = RootPortConfig { + addr: (1, 0), + id: "pcie.1".to_string(), + ..Default::default() + }; + let root_port = RootPort::new(root_port_config, root_bus.clone()); root_port.realize().unwrap(); // Test device is attached to the root bus. @@ -421,7 +425,12 @@ mod tests { let locked_pci_host = pci_host.lock().unwrap(); let root_bus = Arc::downgrade(&locked_pci_host.root_bus); - let root_port = RootPort::new("pcie.1".to_string(), 8, 0, root_bus.clone(), false); + let root_port_config = RootPortConfig { + id: "pcie.1".to_string(), + addr: (1, 0), + ..Default::default() + }; + let root_port = RootPort::new(root_port_config, root_bus.clone()); root_port.realize().unwrap(); let bus = PciBus::find_bus_by_name(&locked_pci_host.root_bus, "pcie.1").unwrap(); diff --git a/devices/src/pci/host.rs b/devices/src/pci/host.rs index b6a44dab..f3957156 100644 --- a/devices/src/pci/host.rs +++ b/devices/src/pci/host.rs @@ -547,7 +547,7 @@ pub mod tests { use super::*; use crate::pci::bus::PciBus; use crate::pci::config::{PciConfig, PCI_CONFIG_SPACE_SIZE, SECONDARY_BUS_NUM}; - use crate::pci::root_port::RootPort; + use crate::pci::root_port::{RootPort, RootPortConfig}; use crate::pci::{PciDevBase, Result}; use crate::{Device, DeviceBase}; use address_space::Region; @@ -658,7 +658,12 @@ pub mod tests { let root_bus = Arc::downgrade(&pci_host.lock().unwrap().root_bus); let pio_addr_ops = PciHost::build_pio_addr_ops(pci_host.clone()); let pio_data_ops = PciHost::build_pio_data_ops(pci_host.clone()); - let root_port = RootPort::new("pcie.1".to_string(), 8, 0, root_bus, false); + let root_port_config = RootPortConfig { + addr: (1, 0), + id: "pcie.1".to_string(), + ..Default::default() + }; + let root_port = RootPort::new(root_port_config, root_bus.clone()); root_port.realize().unwrap(); let mut data = [0_u8; 4]; @@ -735,10 +740,20 @@ pub mod tests { let root_bus = Arc::downgrade(&pci_host.lock().unwrap().root_bus); let mmconfig_region_ops = PciHost::build_mmconfig_ops(pci_host.clone()); - let mut root_port = RootPort::new("pcie.1".to_string(), 8, 0, root_bus.clone(), false); + let root_port_config = RootPortConfig { + addr: (1, 0), + id: "pcie.1".to_string(), + ..Default::default() + }; + let mut root_port = RootPort::new(root_port_config, root_bus.clone()); root_port.write_config(SECONDARY_BUS_NUM as usize, &[1]); root_port.realize().unwrap(); - let mut root_port = RootPort::new("pcie.2".to_string(), 16, 0, root_bus, false); + let root_port_config = RootPortConfig { + addr: (2, 0), + id: "pcie.2".to_string(), + ..Default::default() + }; + let mut root_port = RootPort::new(root_port_config, root_bus.clone()); root_port.write_config(SECONDARY_BUS_NUM as usize, &[2]); root_port.realize().unwrap(); diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs index 0c8c0af3..c29d7a0d 100644 --- a/devices/src/pci/mod.rs +++ b/devices/src/pci/mod.rs @@ -28,7 +28,7 @@ pub use error::PciError; pub use host::PciHost; pub use intx::{init_intx, InterruptHandler, PciIntxState}; pub use msix::{init_msix, MsiVector}; -pub use root_port::RootPort; +pub use root_port::{RootPort, RootPortConfig}; use std::{ mem::size_of, diff --git a/devices/src/pci/root_port.rs b/devices/src/pci/root_port.rs index 40130277..6396c0ce 100644 --- a/devices/src/pci/root_port.rs +++ b/devices/src/pci/root_port.rs @@ -14,6 +14,7 @@ use std::sync::atomic::{AtomicU16, Ordering}; use std::sync::{Arc, Mutex, Weak}; use anyhow::{anyhow, bail, Context, Result}; +use clap::{ArgAction, Parser}; use log::{error, info}; use once_cell::sync::OnceCell; @@ -39,17 +40,41 @@ use crate::pci::{ }; use crate::{Device, DeviceBase, MsiIrqManager}; use address_space::Region; +use machine_manager::config::{get_pci_df, parse_bool, valid_id}; use machine_manager::qmp::qmp_channel::send_device_deleted_msg; use migration::{ DeviceStateDesc, FieldDesc, MigrationError, MigrationHook, MigrationManager, StateTransfer, }; use migration_derive::{ByteCode, Desc}; -use util::{byte_code::ByteCode, num_ops::ranges_overlap}; +use util::{ + byte_code::ByteCode, + num_ops::{ranges_overlap, str_to_num}, +}; const DEVICE_ID_RP: u16 = 0x000c; static FAST_UNPLUG_FEATURE: OnceCell = OnceCell::new(); +/// Basic information of RootPort like port number. +#[derive(Parser, Debug, Clone, Default)] +#[command(no_binary_name(true))] +pub struct RootPortConfig { + #[arg(long, value_parser = ["pcie-root-port"])] + pub classtype: String, + #[arg(long, value_parser = str_to_num::)] + pub port: u8, + #[arg(long, value_parser = valid_id)] + pub id: String, + #[arg(long)] + pub bus: String, + #[arg(long, value_parser = get_pci_df)] + pub addr: (u8, u8), + #[arg(long, default_value = "off", value_parser = parse_bool, action = ArgAction::Append)] + pub multifunction: bool, + #[arg(long, default_value = "0")] + pub chassis: u8, +} + /// Device state root port. #[repr(C)] #[derive(Copy, Clone, Desc, ByteCode)] @@ -81,22 +106,15 @@ impl RootPort { /// /// # Arguments /// - /// * `name` - Root port name. - /// * `devfn` - Device number << 3 | Function number. - /// * `port_num` - Root port number. + /// * `cfg` - Root port config. /// * `parent_bus` - Weak reference to the parent bus. - pub fn new( - name: String, - devfn: u8, - port_num: u8, - parent_bus: Weak>, - multifunction: bool, - ) -> Self { + pub fn new(cfg: RootPortConfig, parent_bus: Weak>) -> Self { + let devfn = cfg.addr.0 << 3 | cfg.addr.1; #[cfg(target_arch = "x86_64")] let io_region = Region::init_container_region(1 << 16, "RootPortIo"); let mem_region = Region::init_container_region(u64::max_value(), "RootPortMem"); let sec_bus = Arc::new(Mutex::new(PciBus::new( - name.clone(), + cfg.id.clone(), #[cfg(target_arch = "x86_64")] io_region.clone(), mem_region.clone(), @@ -104,18 +122,18 @@ impl RootPort { Self { base: PciDevBase { - base: DeviceBase::new(name, true), + base: DeviceBase::new(cfg.id, true), config: PciConfig::new(PCIE_CONFIG_SPACE_SIZE, 2), devfn, parent_bus, }, - port_num, + port_num: cfg.port, sec_bus, #[cfg(target_arch = "x86_64")] io_region, mem_region, dev_id: Arc::new(AtomicU16::new(0)), - multifunction, + multifunction: cfg.multifunction, hpev_notified: false, } } @@ -694,7 +712,12 @@ mod tests { fn test_read_config() { let pci_host = create_pci_host(); let root_bus = Arc::downgrade(&pci_host.lock().unwrap().root_bus); - let root_port = RootPort::new("pcie.1".to_string(), 8, 0, root_bus, false); + let root_port_config = RootPortConfig { + addr: (1, 0), + id: "pcie.1".to_string(), + ..Default::default() + }; + let root_port = RootPort::new(root_port_config, root_bus.clone()); root_port.realize().unwrap(); let root_port = pci_host.lock().unwrap().find_device(0, 8).unwrap(); @@ -710,7 +733,12 @@ mod tests { fn test_write_config() { let pci_host = create_pci_host(); let root_bus = Arc::downgrade(&pci_host.lock().unwrap().root_bus); - let root_port = RootPort::new("pcie.1".to_string(), 8, 0, root_bus, false); + let root_port_config = RootPortConfig { + addr: (1, 0), + id: "pcie.1".to_string(), + ..Default::default() + }; + let root_port = RootPort::new(root_port_config, root_bus.clone()); root_port.realize().unwrap(); let root_port = pci_host.lock().unwrap().find_device(0, 8).unwrap(); diff --git a/machine/src/lib.rs b/machine/src/lib.rs index ab1429b2..f308f579 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -52,7 +52,7 @@ use devices::misc::pvpanic::{PvPanicPci, PvpanicDevConfig}; use devices::misc::scream::{Scream, ScreamConfig}; #[cfg(feature = "demo_device")] use devices::pci::demo_device::{DemoDev, DemoDevConfig}; -use devices::pci::{PciBus, PciDevOps, PciHost, RootPort}; +use devices::pci::{PciBus, PciDevOps, PciHost, RootPort, RootPortConfig}; use devices::smbios::smbios_table::{build_smbios_ep30, SmbiosTable}; use devices::smbios::{SMBIOS_ANCHOR_FILE, SMBIOS_TABLE_FILE}; use devices::sysbus::{SysBus, SysBusDevOps, SysBusDevType}; @@ -74,10 +74,10 @@ use hypervisor::{kvm::KvmHypervisor, test::TestHypervisor, HypervisorOps}; use machine_manager::config::get_cameradev_by_id; use machine_manager::config::{ complete_numa_node, get_multi_function, get_pci_bdf, parse_blk, parse_device_id, - parse_device_type, parse_net, parse_numa_distance, parse_numa_mem, parse_root_port, - parse_vhost_user_blk, parse_virtio_serial, parse_virtserialport, parse_vsock, str_slip_to_clap, - BootIndexInfo, BootSource, DriveConfig, DriveFile, Incoming, MachineMemConfig, MigrateMode, - NumaConfig, NumaDistance, NumaNode, NumaNodes, PciBdf, SerialConfig, VmConfig, FAST_UNPLUG_ON, + parse_device_type, parse_net, parse_numa_distance, parse_numa_mem, parse_vhost_user_blk, + parse_virtio_serial, parse_virtserialport, parse_vsock, str_slip_to_clap, BootIndexInfo, + BootSource, DriveConfig, DriveFile, Incoming, MachineMemConfig, MigrateMode, NumaConfig, + NumaDistance, NumaNode, NumaNodes, PciBdf, SerialConfig, VmConfig, FAST_UNPLUG_ON, MAX_VIRTIO_QUEUE, }; use machine_manager::event_loop::EventLoop; @@ -1352,21 +1352,15 @@ pub trait MachineOps { } fn add_pci_root_port(&mut self, cfg_args: &str) -> Result<()> { - let bdf = get_pci_bdf(cfg_args)?; - let (devfn, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?; - let device_cfg = parse_root_port(cfg_args)?; + let dev_cfg = RootPortConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + let bdf = PciBdf::new(dev_cfg.bus.clone(), dev_cfg.addr); + let (_, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?; let pci_host = self.get_pci_host()?; let bus = pci_host.lock().unwrap().root_bus.clone(); - if PciBus::find_bus_by_name(&bus, &device_cfg.id).is_some() { - bail!("ID {} already exists.", &device_cfg.id); + if PciBus::find_bus_by_name(&bus, &dev_cfg.id).is_some() { + bail!("ID {} already exists.", &dev_cfg.id); } - let rootport = RootPort::new( - device_cfg.id, - devfn, - device_cfg.port, - parent_bus, - device_cfg.multifunction, - ); + let rootport = RootPort::new(dev_cfg, parent_bus); rootport .realize() .with_context(|| "Failed to add pci root port")?; diff --git a/machine_manager/src/config/pci.rs b/machine_manager/src/config/pci.rs index e1ad4985..ce53656e 100644 --- a/machine_manager/src/config/pci.rs +++ b/machine_manager/src/config/pci.rs @@ -13,9 +13,8 @@ use anyhow::{bail, Context, Result}; use serde::{Deserialize, Serialize}; -use super::error::ConfigError; -use super::{CmdParser, ConfigCheck, UnsignedInteger}; -use crate::config::{check_arg_too_long, ExBool}; +use super::CmdParser; +use crate::config::ExBool; use util::num_ops::str_to_num; /// Basic information of pci devices such as bus number, @@ -43,30 +42,6 @@ impl Default for PciBdf { } } -/// Basic information of RootPort like port number. -#[derive(Debug, Clone)] -pub struct RootPortConfig { - pub port: u8, - pub id: String, - pub multifunction: bool, -} - -impl ConfigCheck for RootPortConfig { - fn check(&self) -> Result<()> { - check_arg_too_long(&self.id, "root_port id") - } -} - -impl Default for RootPortConfig { - fn default() -> Self { - RootPortConfig { - port: 0, - id: "".to_string(), - multifunction: false, - } - } -} - pub fn get_pci_df(addr: &str) -> Result<(u8, u8)> { let addr_vec: Vec<&str> = addr.split('.').collect(); if addr_vec.len() > 2 { @@ -129,39 +104,6 @@ pub fn get_multi_function(pci_cfg: &str) -> Result { Ok(false) } -pub fn parse_root_port(rootport_cfg: &str) -> Result { - let mut cmd_parser = CmdParser::new("pcie-root-port"); - cmd_parser - .push("") - .push("bus") - .push("addr") - .push("port") - .push("chassis") - .push("multifunction") - .push("id"); - cmd_parser.parse(rootport_cfg)?; - - let root_port = RootPortConfig { - port: cmd_parser - .get_value::("port")? - .with_context(|| { - ConfigError::FieldIsMissing("port".to_string(), "rootport".to_string()) - })? - .0 as u8, - id: cmd_parser.get_value::("id")?.with_context(|| { - ConfigError::FieldIsMissing("id".to_string(), "rootport".to_string()) - })?, - multifunction: cmd_parser - .get_value::("multifunction")? - .map_or(false, bool::from), - }; - - let _ = cmd_parser.get_value::("chassis")?; - - root_port.check()?; - Ok(root_port) -} - pub fn pci_args_check(cmd_parser: &CmdParser) -> Result<()> { let device_type = cmd_parser.get_value::("")?; let dev_type = device_type.unwrap(); -- Gitee From 903b99bde00cfc433e82d5dceefc364c23133327 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sun, 24 Mar 2024 10:43:05 +0800 Subject: [PATCH 029/489] virtio-blk/vhost-user-blk: use clap to parse the parameters of the virtio-blk/vhost-user-blk config Use clap to parse the parameters of the virtio-blk and vhost-user-blk config. Signed-off-by: liuxiangdong --- machine/src/lib.rs | 95 +++++--- machine/src/micro_common/mod.rs | 106 +++++---- machine_manager/src/config/chardev.rs | 17 +- machine_manager/src/config/drive.rs | 317 +------------------------- machine_manager/src/config/mod.rs | 19 +- machine_manager/src/config/network.rs | 6 +- virtio/src/device/block.rs | 218 +++++++++++++----- virtio/src/device/net.rs | 6 +- virtio/src/device/scsi_cntlr.rs | 12 +- virtio/src/lib.rs | 7 +- virtio/src/vhost/user/block.rs | 69 ++++-- virtio/src/vhost/user/mod.rs | 2 +- 12 files changed, 377 insertions(+), 497 deletions(-) diff --git a/machine/src/lib.rs b/machine/src/lib.rs index f308f579..d21fed9f 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -73,12 +73,11 @@ use hypervisor::{kvm::KvmHypervisor, test::TestHypervisor, HypervisorOps}; #[cfg(feature = "usb_camera")] use machine_manager::config::get_cameradev_by_id; use machine_manager::config::{ - complete_numa_node, get_multi_function, get_pci_bdf, parse_blk, parse_device_id, - parse_device_type, parse_net, parse_numa_distance, parse_numa_mem, parse_vhost_user_blk, - parse_virtio_serial, parse_virtserialport, parse_vsock, str_slip_to_clap, BootIndexInfo, - BootSource, DriveConfig, DriveFile, Incoming, MachineMemConfig, MigrateMode, NumaConfig, - NumaDistance, NumaNode, NumaNodes, PciBdf, SerialConfig, VmConfig, FAST_UNPLUG_ON, - MAX_VIRTIO_QUEUE, + complete_numa_node, get_multi_function, get_pci_bdf, parse_device_id, parse_device_type, + parse_net, parse_numa_distance, parse_numa_mem, parse_virtio_serial, parse_virtserialport, + parse_vsock, str_slip_to_clap, BootIndexInfo, BootSource, DriveConfig, DriveFile, Incoming, + MachineMemConfig, MigrateMode, NumaConfig, NumaDistance, NumaNode, NumaNodes, PciBdf, + SerialConfig, VmConfig, FAST_UNPLUG_ON, MAX_VIRTIO_QUEUE, }; use machine_manager::event_loop::EventLoop; use machine_manager::machine::{HypervisorType, MachineInterface, VmState}; @@ -97,8 +96,8 @@ use virtio::{ balloon_allow_list, find_port_by_nr, get_max_nr, vhost, Balloon, BalloonConfig, Block, BlockState, Rng, RngConfig, RngState, ScsiCntlr::{scsi_cntlr_create_scsi_bus, ScsiCntlr, ScsiCntlrConfig}, - Serial, SerialPort, VhostKern, VhostUser, VirtioDevice, VirtioMmioDevice, VirtioMmioState, - VirtioNetState, VirtioPciDevice, VirtioSerialState, VIRTIO_TYPE_CONSOLE, + Serial, SerialPort, VhostKern, VhostUser, VirtioBlkDevConfig, VirtioDevice, VirtioMmioDevice, + VirtioMmioState, VirtioNetState, VirtioPciDevice, VirtioSerialState, VIRTIO_TYPE_CONSOLE, }; #[cfg(feature = "virtio_gpu")] use virtio::{Gpu, GpuDevConfig}; @@ -1052,26 +1051,37 @@ pub trait MachineOps { cfg_args: &str, hotplug: bool, ) -> Result<()> { - let bdf = get_pci_bdf(cfg_args)?; - let multi_func = get_multi_function(cfg_args)?; - let queues_auto = Some(VirtioPciDevice::virtio_pci_auto_queues_num( - 0, - vm_config.machine_config.nr_cpus, - MAX_VIRTIO_QUEUE, - )); - let device_cfg = parse_blk(vm_config, cfg_args, queues_auto)?; - if let Some(bootindex) = device_cfg.boot_index { + let mut device_cfg = + VirtioBlkDevConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + let bdf = PciBdf::new(device_cfg.bus.clone().unwrap(), device_cfg.addr.unwrap()); + let multi_func = device_cfg.multifunction.unwrap_or_default(); + if device_cfg.num_queues.is_none() { + let queues_auto = VirtioPciDevice::virtio_pci_auto_queues_num( + 0, + vm_config.machine_config.nr_cpus, + MAX_VIRTIO_QUEUE, + ); + device_cfg.num_queues = Some(queues_auto); + } + if let Some(bootindex) = device_cfg.bootindex { self.check_bootindex(bootindex) .with_context(|| "Fail to add virtio pci blk device for invalid bootindex")?; } + + let drive_cfg = vm_config + .drives + .remove(&device_cfg.drive) + .with_context(|| "No drive configured matched for blk device")?; + let device = Arc::new(Mutex::new(Block::new( device_cfg.clone(), + drive_cfg, self.get_drive_files(), ))); let pci_dev = self .add_virtio_pci_device(&device_cfg.id, &bdf, device.clone(), multi_func, false) .with_context(|| "Failed to add virtio pci device")?; - if let Some(bootindex) = device_cfg.boot_index { + if let Some(bootindex) = device_cfg.bootindex { // Eg: OpenFirmware device path(virtio-blk disk): // /pci@i0cf8/scsi@6[,3]/disk@0,0 // | | | | | @@ -1233,27 +1243,42 @@ pub trait MachineOps { cfg_args: &str, hotplug: bool, ) -> Result<()> { - let bdf = get_pci_bdf(cfg_args)?; - let multi_func = get_multi_function(cfg_args)?; - let queues_auto = Some(VirtioPciDevice::virtio_pci_auto_queues_num( - 0, - vm_config.machine_config.nr_cpus, - MAX_VIRTIO_QUEUE, - )); - let device_cfg = parse_vhost_user_blk(vm_config, cfg_args, queues_auto)?; + let mut device_cfg = VhostUser::VhostUserBlkDevConfig::try_parse_from(str_slip_to_clap( + cfg_args, true, false, + ))?; + let bdf = PciBdf::new(device_cfg.bus.clone().unwrap(), device_cfg.addr.unwrap()); + if device_cfg.num_queues.is_none() { + let queues_auto = VirtioPciDevice::virtio_pci_auto_queues_num( + 0, + vm_config.machine_config.nr_cpus, + MAX_VIRTIO_QUEUE, + ); + device_cfg.num_queues = Some(queues_auto); + } + let chardev_cfg = vm_config + .chardev + .remove(&device_cfg.chardev) + .with_context(|| { + format!( + "Chardev: {:?} not found for vhost user blk", + &device_cfg.chardev + ) + })?; + let device: Arc> = Arc::new(Mutex::new(VhostUser::Block::new( &device_cfg, + chardev_cfg, self.get_sys_mem(), ))); let pci_dev = self - .add_virtio_pci_device(&device_cfg.id, &bdf, device.clone(), multi_func, true) + .add_virtio_pci_device(&device_cfg.id, &bdf, device.clone(), false, true) .with_context(|| { format!( "Failed to add virtio pci device, device id: {}", &device_cfg.id ) })?; - if let Some(bootindex) = device_cfg.boot_index { + if let Some(bootindex) = device_cfg.bootindex { if let Some(dev_path) = pci_dev.lock().unwrap().get_dev_path() { self.add_bootindex_devices(bootindex, &dev_path, &device_cfg.id); } @@ -1269,9 +1294,21 @@ pub trait MachineOps { vm_config: &mut VmConfig, cfg_args: &str, ) -> Result<()> { - let device_cfg = parse_vhost_user_blk(vm_config, cfg_args, None)?; + let device_cfg = VhostUser::VhostUserBlkDevConfig::try_parse_from(str_slip_to_clap( + cfg_args, true, false, + ))?; + let chardev_cfg = vm_config + .chardev + .remove(&device_cfg.chardev) + .with_context(|| { + format!( + "Chardev: {:?} not found for vhost user blk", + &device_cfg.chardev + ) + })?; let device: Arc> = Arc::new(Mutex::new(VhostUser::Block::new( &device_cfg, + chardev_cfg, self.get_sys_mem(), ))); let virtio_mmio_device = VirtioMmioDevice::new(self.get_sys_mem(), device); diff --git a/machine/src/micro_common/mod.rs b/machine/src/micro_common/mod.rs index b97f046c..1ac45966 100644 --- a/machine/src/micro_common/mod.rs +++ b/machine/src/micro_common/mod.rs @@ -38,6 +38,7 @@ use std::sync::{Arc, Mutex}; use std::vec::Vec; use anyhow::{anyhow, bail, Context, Result}; +use clap::Parser; use log::{error, info}; #[cfg(target_arch = "aarch64")] @@ -48,7 +49,7 @@ use crate::{MachineBase, MachineError, MachineOps}; use cpu::CpuLifecycleState; use devices::sysbus::{IRQ_BASE, IRQ_MAX}; use machine_manager::config::{ - parse_blk, parse_incoming_uri, parse_net, BlkDevConfig, ConfigCheck, DiskFormat, MigrateMode, + parse_incoming_uri, parse_net, str_slip_to_clap, ConfigCheck, DriveConfig, MigrateMode, NetworkInterfaceConfig, VmConfig, DEFAULT_VIRTQUEUE_SIZE, }; use machine_manager::event; @@ -61,8 +62,8 @@ use machine_manager::qmp::{ qmp_channel::QmpChannel, qmp_response::Response, qmp_schema, qmp_schema::UpdateRegionArgument, }; use migration::MigrationManager; -use util::aio::WriteZeroesState; use util::{loop_context::EventLoopManager, num_ops::str_to_num, set_termi_canon_mode}; +use virtio::device::block::VirtioBlkDevConfig; use virtio::{ create_tap, qmp_balloon, qmp_query_balloon, Block, BlockState, Net, VhostKern, VhostUser, VirtioDevice, VirtioMmioDevice, VirtioMmioState, VirtioNetState, @@ -78,8 +79,8 @@ const MMIO_REPLACEABLE_NET_NR: usize = 2; struct MmioReplaceableConfig { // Device id. id: String, - // The dev_config of the related backend device. - dev_config: Arc, + // The config of the related backend device. Eg: Drive config of virtio mmio device. + back_config: Arc, } // The device information of replaceable device. @@ -158,7 +159,8 @@ impl LightMachine { let mut rpl_devs: Vec = Vec::new(); for id in 0..MMIO_REPLACEABLE_BLK_NR { let block = Arc::new(Mutex::new(Block::new( - BlkDevConfig::default(), + VirtioBlkDevConfig::default(), + DriveConfig::default(), self.get_drive_files(), ))); let virtio_mmio = VirtioMmioDevice::new(&self.base.sys_mem, block.clone()); @@ -217,7 +219,7 @@ impl LightMachine { pub(crate) fn fill_replaceable_device( &mut self, id: &str, - dev_config: Arc, + dev_config: Vec>, index: usize, ) -> Result<()> { let mut replaceable_devices = self.replaceable_info.devices.lock().unwrap(); @@ -232,14 +234,14 @@ impl LightMachine { .device .lock() .unwrap() - .update_config(Some(dev_config.clone())) + .update_config(dev_config.clone()) .with_context(|| MachineError::UpdCfgErr(id.to_string()))?; } - self.add_replaceable_config(id, dev_config) + self.add_replaceable_config(id, dev_config[0].clone()) } - fn add_replaceable_config(&self, id: &str, dev_config: Arc) -> Result<()> { + fn add_replaceable_config(&self, id: &str, back_config: Arc) -> Result<()> { let mut configs_lock = self.replaceable_info.configs.lock().unwrap(); let limit = MMIO_REPLACEABLE_BLK_NR + MMIO_REPLACEABLE_NET_NR; if configs_lock.len() >= limit { @@ -254,7 +256,7 @@ impl LightMachine { let config = MmioReplaceableConfig { id: id.to_string(), - dev_config, + back_config, }; trace::mmio_replaceable_config(&config); @@ -262,21 +264,28 @@ impl LightMachine { Ok(()) } - fn add_replaceable_device(&self, id: &str, driver: &str, slot: usize) -> Result<()> { + fn add_replaceable_device( + &self, + args: Box, + slot: usize, + ) -> Result<()> { + let id = args.id; + let driver = args.driver; + // Find the configuration by id. let configs_lock = self.replaceable_info.configs.lock().unwrap(); - let mut dev_config = None; + let mut configs = Vec::new(); for config in configs_lock.iter() { if config.id == id { - dev_config = Some(config.dev_config.clone()); + configs.push(config.back_config.clone()); } } - if dev_config.is_none() { + if configs.is_empty() { bail!("Failed to find device configuration."); } // Sanity check for config, driver and slot. - let cfg_any = dev_config.as_ref().unwrap().as_any(); + let cfg_any = configs[0].as_any(); let index = if driver.contains("net") { if slot >= MMIO_REPLACEABLE_NET_NR { return Err(anyhow!(MachineError::RplDevLmtErr( @@ -295,9 +304,19 @@ impl LightMachine { MMIO_REPLACEABLE_BLK_NR ))); } - if cfg_any.downcast_ref::().is_none() { + if cfg_any.downcast_ref::().is_none() { return Err(anyhow!(MachineError::DevTypeErr("blk".to_string()))); } + let dev_config = VirtioBlkDevConfig { + classtype: driver, + id: id.clone(), + drive: args.drive.with_context(|| "No drive set")?, + bootindex: args.boot_index, + iothread: args.iothread, + serial: args.serial_num, + ..Default::default() + }; + configs.push(Arc::new(dev_config)); slot } else { bail!("Unsupported replaceable device type."); @@ -316,7 +335,7 @@ impl LightMachine { .device .lock() .unwrap() - .update_config(dev_config) + .update_config(configs) .with_context(|| MachineError::UpdCfgErr(id.to_string()))?; } Ok(()) @@ -328,8 +347,10 @@ impl LightMachine { let mut configs_lock = self.replaceable_info.configs.lock().unwrap(); for (index, config) in configs_lock.iter().enumerate() { if config.id == id { - if let Some(blkconf) = config.dev_config.as_any().downcast_ref::() { - self.unregister_drive_file(&blkconf.path_on_host)?; + if let Some(drive_config) = + config.back_config.as_any().downcast_ref::() + { + self.unregister_drive_file(&drive_config.path_on_host)?; } configs_lock.remove(index); is_exist = true; @@ -347,7 +368,7 @@ impl LightMachine { .device .lock() .unwrap() - .update_config(None) + .update_config(Vec::new()) .with_context(|| MachineError::UpdCfgErr(id.to_string()))?; } } @@ -387,7 +408,11 @@ impl LightMachine { MMIO_REPLACEABLE_NET_NR ); } - self.fill_replaceable_device(&device_cfg.id, Arc::new(device_cfg.clone()), index)?; + self.fill_replaceable_device( + &device_cfg.id, + vec![Arc::new(device_cfg.clone())], + index, + )?; self.replaceable_info.net_count += 1; } Ok(()) @@ -398,7 +423,12 @@ impl LightMachine { vm_config: &mut VmConfig, cfg_args: &str, ) -> Result<()> { - let device_cfg = parse_blk(vm_config, cfg_args, None)?; + let device_cfg = + VirtioBlkDevConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + let drive_cfg = vm_config + .drives + .remove(&device_cfg.drive) + .with_context(|| "No drive configured matched for blk device")?; if self.replaceable_info.block_count >= MMIO_REPLACEABLE_BLK_NR { bail!( "A maximum of {} block replaceable devices are supported.", @@ -406,7 +436,9 @@ impl LightMachine { ); } let index = self.replaceable_info.block_count; - self.fill_replaceable_device(&device_cfg.id, Arc::new(device_cfg.clone()), index)?; + let configs: Vec> = + vec![Arc::new(drive_cfg), Arc::new(device_cfg.clone())]; + self.fill_replaceable_device(&device_cfg.id, configs, index)?; self.replaceable_info.block_count += 1; Ok(()) } @@ -668,7 +700,7 @@ impl DeviceInterface for LightMachine { fn device_add(&mut self, args: Box) -> Response { // get slot of bus by addr or lun let mut slot = 0; - if let Some(addr) = args.addr { + if let Some(addr) = args.addr.clone() { if let Ok(num) = str_to_num::(&addr) { slot = num; } else { @@ -684,7 +716,7 @@ impl DeviceInterface for LightMachine { slot = lun + 1; } - match self.add_replaceable_device(&args.id, &args.driver, slot) { + match self.add_replaceable_device(args.clone(), slot) { Ok(()) => Response::create_empty_response(), Err(ref e) => { error!("{:?}", e); @@ -719,32 +751,22 @@ impl DeviceInterface for LightMachine { } fn blockdev_add(&self, args: Box) -> Response { - let read_only = args.read_only.unwrap_or(false); + let readonly = args.read_only.unwrap_or(false); let mut direct = true; if args.cache.is_some() && !args.cache.unwrap().direct.unwrap_or(true) { direct = false; } - let config = BlkDevConfig { + let config = DriveConfig { id: args.node_name.clone(), + drive_type: "none".to_string(), path_on_host: args.file.filename.clone(), - read_only, + readonly, direct, - serial_num: None, - iothread: None, - iops: None, - queues: 1, - boot_index: None, - chardev: None, - socket_path: None, aio: args.file.aio, - queue_size: DEFAULT_VIRTQUEUE_SIZE, - discard: false, - write_zeroes: WriteZeroesState::Off, - format: DiskFormat::Raw, - l2_cache_size: None, - refcount_cache_size: None, + ..Default::default() }; + if let Err(e) = config.check() { error!("{:?}", e); return Response::create_error_response( @@ -753,7 +775,7 @@ impl DeviceInterface for LightMachine { ); } // Register drive backend file for hotplugged drive. - if let Err(e) = self.register_drive_file(&config.id, &args.file.filename, read_only, direct) + if let Err(e) = self.register_drive_file(&config.id, &args.file.filename, readonly, direct) { error!("{:?}", e); return Response::create_error_response( diff --git a/machine_manager/src/config/chardev.rs b/machine_manager/src/config/chardev.rs index f5ea6067..68c23c6e 100644 --- a/machine_manager/src/config/chardev.rs +++ b/machine_manager/src/config/chardev.rs @@ -199,22 +199,17 @@ pub fn get_chardev_config(args: qmp_schema::CharDevAddArgument) -> Result Result { - let char_dev = vm_config - .chardev - .remove(chardev) - .with_context(|| format!("Chardev: {:?} not found for character device", chardev))?; +pub fn get_chardev_socket_path(chardev: ChardevConfig) -> Result { + let id = chardev.id(); if let ChardevType::Socket { path, server, nowait, .. - } = char_dev.classtype + } = chardev.classtype { - path.clone().with_context(|| { - format!("Chardev {:?} backend should be unix-socket type.", chardev) - })?; + path.clone() + .with_context(|| format!("Chardev {:?} backend should be unix-socket type.", id))?; if server || nowait { bail!( "Argument \'server\' or \'nowait\' is not need for chardev \'{}\'", @@ -223,7 +218,7 @@ pub fn get_chardev_socket_path(chardev: &str, vm_config: &mut VmConfig) -> Resul } return Ok(path.unwrap()); } - bail!("Chardev {:?} backend should be unix-socket type.", chardev); + bail!("Chardev {:?} backend should be unix-socket type.", id); } pub fn parse_virtserialport( diff --git a/machine_manager/src/config/drive.rs b/machine_manager/src/config/drive.rs index a58d0012..3107ce75 100644 --- a/machine_manager/src/config/drive.rs +++ b/machine_manager/src/config/drive.rs @@ -20,24 +20,16 @@ use clap::{ArgAction, Parser}; use log::error; use serde::{Deserialize, Serialize}; -use super::{error::ConfigError, pci_args_check, M}; +use super::{error::ConfigError, M}; use super::{valid_id, valid_path}; use crate::config::{ - check_arg_too_long, get_chardev_socket_path, memory_unit_conversion, parse_bool, - str_slip_to_clap, CmdParser, ConfigCheck, VmConfig, DEFAULT_VIRTQUEUE_SIZE, MAX_STRING_LENGTH, - MAX_VIRTIO_QUEUE, + memory_unit_conversion, parse_bool, str_slip_to_clap, ConfigCheck, VmConfig, MAX_STRING_LENGTH, }; use util::aio::{aio_probe, AioEngine, WriteZeroesState}; -const MAX_SERIAL_NUM: usize = 20; const MAX_IOPS: u64 = 1_000_000; const MAX_UNIT_ID: usize = 2; -// Seg_max = queue_size - 2. So, size of each virtqueue for virtio-blk should be larger than 2. -const MIN_QUEUE_SIZE_BLK: u16 = 2; -// Max size of each virtqueue for virtio-blk. -const MAX_QUEUE_SIZE_BLK: u16 = 1024; - // L2 Cache max size is 32M. pub const MAX_L2_CACHE_SIZE: u64 = 32 * (1 << 20); // Refcount table cache max size is 32M. @@ -63,29 +55,6 @@ pub struct DriveFile { pub buf_align: u32, } -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct BlkDevConfig { - pub id: String, - pub path_on_host: String, - pub read_only: bool, - pub direct: bool, - pub serial_num: Option, - pub iothread: Option, - pub iops: Option, - pub queues: u16, - pub boot_index: Option, - pub chardev: Option, - pub socket_path: Option, - pub aio: AioEngine, - pub queue_size: u16, - pub discard: bool, - pub write_zeroes: WriteZeroesState, - pub format: DiskFormat, - pub l2_cache_size: Option, - pub refcount_cache_size: Option, -} - #[derive(Debug, Clone)] pub struct BootIndexInfo { pub boot_index: u8, @@ -93,31 +62,6 @@ pub struct BootIndexInfo { pub dev_path: String, } -impl Default for BlkDevConfig { - fn default() -> Self { - BlkDevConfig { - id: "".to_string(), - path_on_host: "".to_string(), - read_only: false, - direct: true, - serial_num: None, - iothread: None, - iops: None, - queues: 1, - boot_index: None, - chardev: None, - socket_path: None, - aio: AioEngine::Native, - queue_size: DEFAULT_VIRTQUEUE_SIZE, - discard: false, - write_zeroes: WriteZeroesState::Off, - format: DiskFormat::Raw, - l2_cache_size: None, - refcount_cache_size: None, - } - } -} - #[derive(Default, Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq)] pub enum DiskFormat { #[default] @@ -327,192 +271,6 @@ impl ConfigCheck for DriveConfig { } } -impl ConfigCheck for BlkDevConfig { - fn check(&self) -> Result<()> { - check_arg_too_long(&self.id, "drive device id")?; - if self.serial_num.is_some() && self.serial_num.as_ref().unwrap().len() > MAX_SERIAL_NUM { - return Err(anyhow!(ConfigError::StringLengthTooLong( - "drive serial number".to_string(), - MAX_SERIAL_NUM, - ))); - } - - if self.iothread.is_some() && self.iothread.as_ref().unwrap().len() > MAX_STRING_LENGTH { - return Err(anyhow!(ConfigError::StringLengthTooLong( - "iothread name".to_string(), - MAX_STRING_LENGTH, - ))); - } - - if self.queues < 1 || self.queues > MAX_VIRTIO_QUEUE as u16 { - return Err(anyhow!(ConfigError::IllegalValue( - "number queues of block device".to_string(), - 1, - true, - MAX_VIRTIO_QUEUE as u64, - true, - ))); - } - - if self.queue_size <= MIN_QUEUE_SIZE_BLK || self.queue_size > MAX_QUEUE_SIZE_BLK { - return Err(anyhow!(ConfigError::IllegalValue( - "queue size of block device".to_string(), - MIN_QUEUE_SIZE_BLK as u64, - false, - MAX_QUEUE_SIZE_BLK as u64, - true - ))); - } - - if self.queue_size & (self.queue_size - 1) != 0 { - bail!("Queue size should be power of 2!"); - } - - let fake_drive = DriveConfig { - id: self.id.clone(), - path_on_host: self.path_on_host.clone(), - direct: self.direct, - iops: self.iops, - aio: self.aio, - media: "disk".to_string(), - ..Default::default() - }; - fake_drive.check()?; - #[cfg(not(test))] - if self.chardev.is_none() { - fake_drive.check_path()?; - } - - Ok(()) - } -} - -pub fn parse_blk( - vm_config: &mut VmConfig, - drive_config: &str, - queues_auto: Option, -) -> Result { - let mut cmd_parser = CmdParser::new("virtio-blk"); - cmd_parser - .push("") - .push("id") - .push("bus") - .push("addr") - .push("multifunction") - .push("drive") - .push("bootindex") - .push("serial") - .push("iothread") - .push("num-queues") - .push("queue-size"); - - cmd_parser.parse(drive_config)?; - - pci_args_check(&cmd_parser)?; - - let mut blkdevcfg = BlkDevConfig::default(); - if let Some(boot_index) = cmd_parser.get_value::("bootindex")? { - blkdevcfg.boot_index = Some(boot_index); - } - - let blkdrive = cmd_parser - .get_value::("drive")? - .with_context(|| ConfigError::FieldIsMissing("drive".to_string(), "blk".to_string()))?; - - if let Some(iothread) = cmd_parser.get_value::("iothread")? { - blkdevcfg.iothread = Some(iothread); - } - - if let Some(serial) = cmd_parser.get_value::("serial")? { - blkdevcfg.serial_num = Some(serial); - } - - blkdevcfg.id = cmd_parser - .get_value::("id")? - .with_context(|| "No id configured for blk device")?; - - if let Some(queues) = cmd_parser.get_value::("num-queues")? { - blkdevcfg.queues = queues; - } else if let Some(queues) = queues_auto { - blkdevcfg.queues = queues; - } - - if let Some(queue_size) = cmd_parser.get_value::("queue-size")? { - blkdevcfg.queue_size = queue_size; - } - - let drive_arg = &vm_config - .drives - .remove(&blkdrive) - .with_context(|| "No drive configured matched for blk device")?; - blkdevcfg.path_on_host = drive_arg.path_on_host.clone(); - blkdevcfg.read_only = drive_arg.readonly; - blkdevcfg.direct = drive_arg.direct; - blkdevcfg.iops = drive_arg.iops; - blkdevcfg.aio = drive_arg.aio; - blkdevcfg.discard = drive_arg.discard; - blkdevcfg.write_zeroes = drive_arg.write_zeroes; - blkdevcfg.format = drive_arg.format; - blkdevcfg.l2_cache_size = drive_arg.l2_cache_size; - blkdevcfg.refcount_cache_size = drive_arg.refcount_cache_size; - blkdevcfg.check()?; - Ok(blkdevcfg) -} - -pub fn parse_vhost_user_blk( - vm_config: &mut VmConfig, - drive_config: &str, - queues_auto: Option, -) -> Result { - let mut cmd_parser = CmdParser::new("vhost-user-blk-pci"); - cmd_parser - .push("") - .push("id") - .push("bus") - .push("addr") - .push("num-queues") - .push("chardev") - .push("queue-size") - .push("bootindex"); - - cmd_parser.parse(drive_config)?; - - pci_args_check(&cmd_parser)?; - - let mut blkdevcfg = BlkDevConfig::default(); - - if let Some(boot_index) = cmd_parser.get_value::("bootindex")? { - blkdevcfg.boot_index = Some(boot_index); - } - - blkdevcfg.chardev = cmd_parser - .get_value::("chardev")? - .map(Some) - .with_context(|| { - ConfigError::FieldIsMissing("chardev".to_string(), "vhost-user-blk-pci".to_string()) - })?; - - blkdevcfg.id = cmd_parser - .get_value::("id")? - .with_context(|| "No id configured for blk device")?; - - if let Some(queues) = cmd_parser.get_value::("num-queues")? { - blkdevcfg.queues = queues; - } else if let Some(queues) = queues_auto { - blkdevcfg.queues = queues; - } - - if let Some(size) = cmd_parser.get_value::("queue-size")? { - blkdevcfg.queue_size = size; - } - - if let Some(chardev) = &blkdevcfg.chardev { - blkdevcfg.socket_path = Some(get_chardev_socket_path(chardev, vm_config)?); - } - blkdevcfg.check()?; - Ok(blkdevcfg) -} - impl VmConfig { /// Add '-drive ...' drive config to `VmConfig`, including `block drive` and `pflash drive`. pub fn add_drive(&mut self, drive_config: &str) -> Result { @@ -582,77 +340,6 @@ impl VmConfig { #[cfg(test)] mod tests { use super::*; - use crate::config::get_pci_bdf; - - #[test] - fn test_drive_config_cmdline_parser() { - let mut vm_config = VmConfig::default(); - assert!(vm_config - .add_drive( - "id=rootfs,file=/path/to/rootfs,readonly=off,direct=on,throttling.iops-total=200" - ) - .is_ok()); - let blk_cfg_res = parse_blk( - &mut vm_config, - "virtio-blk-device,drive=rootfs,id=rootfs,iothread=iothread1,serial=111111,num-queues=4", - None, - ); - assert!(blk_cfg_res.is_ok()); - let blk_device_config = blk_cfg_res.unwrap(); - assert_eq!(blk_device_config.id, "rootfs"); - assert_eq!(blk_device_config.path_on_host, "/path/to/rootfs"); - assert_eq!(blk_device_config.direct, true); - assert_eq!(blk_device_config.read_only, false); - assert_eq!(blk_device_config.serial_num, Some(String::from("111111"))); - assert_eq!(blk_device_config.queues, 4); - - let mut vm_config = VmConfig::default(); - assert!(vm_config - .add_drive("id=rootfs,file=/path/to/rootfs,readonly=off,direct=on") - .is_ok()); - let blk_cfg_res = parse_blk( - &mut vm_config, - "virtio-blk-device,drive=rootfs1,id=rootfs1,iothread=iothread1,iops=200,serial=111111", - None, - ); - assert!(blk_cfg_res.is_err()); // Can not find drive named "rootfs1". - } - - #[test] - fn test_pci_block_config_cmdline_parser() { - let mut vm_config = VmConfig::default(); - assert!(vm_config - .add_drive("id=rootfs,file=/path/to/rootfs,readonly=off,direct=on") - .is_ok()); - let blk_cfg = "virtio-blk-pci,id=rootfs,bus=pcie.0,addr=0x1.0x2,drive=rootfs,serial=111111,num-queues=4"; - let blk_cfg_res = parse_blk(&mut vm_config, blk_cfg, None); - assert!(blk_cfg_res.is_ok()); - let drive_configs = blk_cfg_res.unwrap(); - assert_eq!(drive_configs.id, "rootfs"); - assert_eq!(drive_configs.path_on_host, "/path/to/rootfs"); - assert_eq!(drive_configs.direct, true); - assert_eq!(drive_configs.read_only, false); - assert_eq!(drive_configs.serial_num, Some(String::from("111111"))); - assert_eq!(drive_configs.queues, 4); - - let pci_bdf = get_pci_bdf(blk_cfg); - assert!(pci_bdf.is_ok()); - let pci = pci_bdf.unwrap(); - assert_eq!(pci.bus, "pcie.0".to_string()); - assert_eq!(pci.addr, (1, 2)); - - // drive "rootfs" has been removed. - let blk_cfg_res = parse_blk(&mut vm_config, blk_cfg, None); - assert!(blk_cfg_res.is_err()); - - let mut vm_config = VmConfig::default(); - assert!(vm_config - .add_drive("id=rootfs,file=/path/to/rootfs,readonly=off,direct=on") - .is_ok()); - let blk_cfg = - "virtio-blk-pci,id=blk1,bus=pcie.0,addr=0x1.0x2,drive=rootfs,multifunction=on"; - assert!(parse_blk(&mut vm_config, blk_cfg, None).is_ok()); - } #[test] fn test_pflash_drive_config_cmdline_parser() { diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index bb69d1e0..4d1b2ab9 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -91,10 +91,10 @@ pub const FAST_UNPLUG_OFF: &str = "0"; pub const MAX_NODES: u32 = 128; /// Default virtqueue size for virtio devices excepts virtio-fs. pub const DEFAULT_VIRTQUEUE_SIZE: u16 = 256; -// Seg_max = queue_size - 2. So, size of each virtqueue for virtio-scsi should be larger than 2. -pub const MIN_QUEUE_SIZE_SCSI: u64 = 2; -// Max size of each virtqueue for virtio-scsi. -pub const MAX_QUEUE_SIZE_SCSI: u64 = 1024; +// Seg_max = queue_size - 2. So, size of each virtqueue for virtio-scsi/virtio-blk should be larger than 2. +pub const MIN_QUEUE_SIZE_BLOCK_DEVICE: u64 = 2; +// Max size of each virtqueue for virtio-scsi/virtio-blk. +pub const MAX_QUEUE_SIZE_BLOCK_DEVICE: u64 = 1024; /// The bar0 size of enable_bar0 features pub const VIRTIO_GPU_ENABLE_BAR0_SIZE: u64 = 64 * M; @@ -832,6 +832,17 @@ pub fn valid_dir(d: &str) -> Result { Ok(dir) } +pub fn valid_block_device_virtqueue_size(s: &str) -> Result { + let size: u64 = s.parse()?; + valid_virtqueue_size( + size, + MIN_QUEUE_SIZE_BLOCK_DEVICE + 1, + MAX_QUEUE_SIZE_BLOCK_DEVICE, + )?; + + Ok(size as u16) +} + #[cfg(test)] mod tests { use super::*; diff --git a/machine_manager/src/config/network.rs b/machine_manager/src/config/network.rs index f7d79a13..01c7570e 100644 --- a/machine_manager/src/config/network.rs +++ b/machine_manager/src/config/network.rs @@ -296,7 +296,11 @@ pub fn parse_net(vm_config: &mut VmConfig, net_config: &str) -> Result> SECTOR_SHIFT; +/// Max length of serial number. +const MAX_SERIAL_NUM_LEN: usize = 20; type SenderConfig = ( Option>>>, @@ -86,6 +92,70 @@ type SenderConfig = ( bool, ); +fn valid_serial(s: &str) -> Result { + if s.len() > MAX_SERIAL_NUM_LEN { + return Err(anyhow!(ConfigError::StringLengthTooLong( + "device serial number".to_string(), + MAX_SERIAL_NUM_LEN, + ))); + } + Ok(s.to_string()) +} + +#[derive(Parser, Debug, Clone)] +#[command(no_binary_name(true))] +pub struct VirtioBlkDevConfig { + #[arg(long, value_parser = ["virtio-blk-pci", "virtio-blk-device"])] + pub classtype: String, + #[arg(long, value_parser = valid_id)] + pub id: String, + #[arg(long)] + pub bus: Option, + #[arg(long, value_parser = get_pci_df)] + pub addr: Option<(u8, u8)>, + #[arg(long, value_parser = parse_bool)] + pub multifunction: Option, + #[arg(long)] + pub drive: String, + #[arg(long)] + pub bootindex: Option, + #[arg(long, alias = "num-queues", value_parser = clap::value_parser!(u16).range(1..=MAX_VIRTIO_QUEUE as i64))] + pub num_queues: Option, + #[arg(long)] + pub iothread: Option, + #[arg(long, alias = "queue-size", default_value = "256", value_parser = valid_block_device_virtqueue_size)] + pub queue_size: u16, + #[arg(long, value_parser = valid_serial)] + pub serial: Option, +} + +impl Default for VirtioBlkDevConfig { + fn default() -> Self { + Self { + classtype: "".to_string(), + id: "".to_string(), + bus: None, + addr: None, + multifunction: None, + drive: "".to_string(), + num_queues: Some(1), + bootindex: None, + iothread: None, + queue_size: DEFAULT_VIRTQUEUE_SIZE, + serial: None, + } + } +} + +impl ConfigCheck for VirtioBlkDevConfig { + fn check(&self) -> Result<()> { + if self.serial.is_some() { + valid_serial(&self.serial.clone().unwrap())?; + } + Ok(()) + } +} + fn get_serial_num_config(serial_num: &str) -> Vec { let mut id_bytes = vec![0; VIRTIO_BLK_ID_BYTES as usize]; let bytes_to_copy = cmp::min(serial_num.len(), VIRTIO_BLK_ID_BYTES as usize); @@ -955,7 +1025,9 @@ pub struct Block { /// Virtio device base property. base: VirtioBase, /// Configuration of the block device. - blk_cfg: BlkDevConfig, + blk_cfg: VirtioBlkDevConfig, + /// Configuration of the block device's drive. + drive_cfg: DriveConfig, /// Config space of the block device. config_space: VirtioBlkConfig, /// BLock backend opened by the block device. @@ -978,14 +1050,16 @@ pub struct Block { impl Block { pub fn new( - blk_cfg: BlkDevConfig, + blk_cfg: VirtioBlkDevConfig, + drive_cfg: DriveConfig, drive_files: Arc>>, ) -> Block { - let queue_num = blk_cfg.queues as usize; + let queue_num = blk_cfg.num_queues.unwrap_or(1) as usize; let queue_size = blk_cfg.queue_size; Self { base: VirtioBase::new(VIRTIO_TYPE_BLOCK, queue_num, queue_size), blk_cfg, + drive_cfg, req_align: 1, buf_align: 1, drive_files, @@ -999,11 +1073,11 @@ impl Block { // seg_max = queue_size - 2: 32bits self.config_space.seg_max = self.queue_size_max() as u32 - 2; - if self.blk_cfg.queues > 1 { - self.config_space.num_queues = self.blk_cfg.queues; + if self.blk_cfg.num_queues.unwrap_or(1) > 1 { + self.config_space.num_queues = self.blk_cfg.num_queues.unwrap_or(1); } - if self.blk_cfg.discard { + if self.drive_cfg.discard { // Just support one segment per request. self.config_space.max_discard_seg = 1; // The default discard alignment is 1 sector. @@ -1011,7 +1085,7 @@ impl Block { self.config_space.max_discard_sectors = MAX_REQUEST_SECTORS; } - if self.blk_cfg.write_zeroes != WriteZeroesState::Off { + if self.drive_cfg.write_zeroes != WriteZeroesState::Off { // Just support one segment per request. self.config_space.max_write_zeroes_seg = 1; self.config_space.max_write_zeroes_sectors = MAX_REQUEST_SECTORS; @@ -1058,35 +1132,36 @@ impl VirtioDevice for Block { ); } - if !self.blk_cfg.path_on_host.is_empty() { + if !self.drive_cfg.path_on_host.is_empty() { let drive_files = self.drive_files.lock().unwrap(); - let file = VmConfig::fetch_drive_file(&drive_files, &self.blk_cfg.path_on_host)?; - let alignments = VmConfig::fetch_drive_align(&drive_files, &self.blk_cfg.path_on_host)?; + let file = VmConfig::fetch_drive_file(&drive_files, &self.drive_cfg.path_on_host)?; + let alignments = + VmConfig::fetch_drive_align(&drive_files, &self.drive_cfg.path_on_host)?; self.req_align = alignments.0; self.buf_align = alignments.1; - let drive_id = VmConfig::get_drive_id(&drive_files, &self.blk_cfg.path_on_host)?; + let drive_id = VmConfig::get_drive_id(&drive_files, &self.drive_cfg.path_on_host)?; let mut thread_pool = None; - if self.blk_cfg.aio != AioEngine::Off { + if self.drive_cfg.aio != AioEngine::Off { thread_pool = Some(EventLoop::get_ctx(None).unwrap().thread_pool.clone()); } let aio = Aio::new( Arc::new(BlockIoHandler::complete_func), - self.blk_cfg.aio, + self.drive_cfg.aio, thread_pool, )?; let conf = BlockProperty { id: drive_id, - format: self.blk_cfg.format, + format: self.drive_cfg.format, iothread: self.blk_cfg.iothread.clone(), - direct: self.blk_cfg.direct, + direct: self.drive_cfg.direct, req_align: self.req_align, buf_align: self.buf_align, - discard: self.blk_cfg.discard, - write_zeroes: self.blk_cfg.write_zeroes, - l2_cache_size: self.blk_cfg.l2_cache_size, - refcount_cache_size: self.blk_cfg.refcount_cache_size, + discard: self.drive_cfg.discard, + write_zeroes: self.drive_cfg.write_zeroes, + l2_cache_size: self.drive_cfg.l2_cache_size, + refcount_cache_size: self.drive_cfg.refcount_cache_size, }; let backend = create_block_backend(file, aio, conf)?; let disk_size = backend.lock().unwrap().disk_size()?; @@ -1110,16 +1185,16 @@ impl VirtioDevice for Block { | 1_u64 << VIRTIO_F_RING_EVENT_IDX | 1_u64 << VIRTIO_BLK_F_FLUSH | 1_u64 << VIRTIO_BLK_F_SEG_MAX; - if self.blk_cfg.read_only { + if self.drive_cfg.readonly { self.base.device_features |= 1_u64 << VIRTIO_BLK_F_RO; }; - if self.blk_cfg.queues > 1 { + if self.blk_cfg.num_queues.unwrap_or(1) > 1 { self.base.device_features |= 1_u64 << VIRTIO_BLK_F_MQ; } - if self.blk_cfg.discard { + if self.drive_cfg.discard { self.base.device_features |= 1_u64 << VIRTIO_BLK_F_DISCARD; } - if self.blk_cfg.write_zeroes != WriteZeroesState::Off { + if self.drive_cfg.write_zeroes != WriteZeroesState::Off { self.base.device_features |= 1_u64 << VIRTIO_BLK_F_WRITE_ZEROES; } self.build_device_config_space(); @@ -1130,7 +1205,7 @@ impl VirtioDevice for Block { fn unrealize(&mut self) -> Result<()> { MigrationManager::unregister_device_instance(BlockState::descriptor(), &self.blk_cfg.id); let drive_files = self.drive_files.lock().unwrap(); - let drive_id = VmConfig::get_drive_id(&drive_files, &self.blk_cfg.path_on_host)?; + let drive_id = VmConfig::get_drive_id(&drive_files, &self.drive_cfg.path_on_host)?; remove_block_backend(&drive_id); Ok(()) } @@ -1176,20 +1251,20 @@ impl VirtioDevice for Block { req_align: self.req_align, buf_align: self.buf_align, disk_sectors: self.disk_sectors, - direct: self.blk_cfg.direct, - serial_num: self.blk_cfg.serial_num.clone(), + direct: self.drive_cfg.direct, + serial_num: self.blk_cfg.serial.clone(), driver_features, receiver, update_evt: update_evt.clone(), device_broken: self.base.broken.clone(), interrupt_cb: interrupt_cb.clone(), iothread: self.blk_cfg.iothread.clone(), - leak_bucket: match self.blk_cfg.iops { + leak_bucket: match self.drive_cfg.iops { Some(iops) => Some(LeakBucket::new(iops)?), None => None, }, - discard: self.blk_cfg.discard, - write_zeroes: self.blk_cfg.write_zeroes, + discard: self.drive_cfg.discard, + write_zeroes: self.drive_cfg.write_zeroes, }; let notifiers = EventNotifierHelper::internal_notifiers(Arc::new(Mutex::new(handler))); @@ -1236,18 +1311,28 @@ impl VirtioDevice for Block { Ok(()) } - fn update_config(&mut self, dev_config: Option>) -> Result<()> { - let is_plug = dev_config.is_some(); - if let Some(conf) = dev_config { - self.blk_cfg = conf + // configs[0]: DriveConfig. configs[1]: VirtioBlkDevConfig. + fn update_config(&mut self, configs: Vec>) -> Result<()> { + let mut is_plug = false; + if configs.len() == 2 { + self.drive_cfg = configs[0] + .as_any() + .downcast_ref::() + .unwrap() + .clone(); + self.blk_cfg = configs[1] .as_any() - .downcast_ref::() + .downcast_ref::() .unwrap() .clone(); // microvm type block device don't support multiple queue. - self.blk_cfg.queues = QUEUE_NUM_BLK as u16; - } else { + self.blk_cfg.num_queues = Some(QUEUE_NUM_BLK as u16); + is_plug = true; + } else if configs.is_empty() { self.blk_cfg = Default::default(); + self.drive_cfg = Default::default(); + } else { + bail!("Invalid update configs."); } if !is_plug { @@ -1296,8 +1381,8 @@ impl VirtioDevice for Block { self.req_align, self.buf_align, self.disk_sectors, - self.blk_cfg.serial_num.clone(), - self.blk_cfg.direct, + self.blk_cfg.serial.clone(), + self.drive_cfg.direct, )) .with_context(|| VirtioError::ChannelSend("image fd".to_string()))?; } @@ -1354,7 +1439,9 @@ mod tests { use super::*; use crate::*; use address_space::{AddressSpace, GuestAddress, HostMemMapping, Region}; - use machine_manager::config::{IothreadConfig, VmConfig, DEFAULT_VIRTQUEUE_SIZE}; + use machine_manager::config::{ + str_slip_to_clap, IothreadConfig, VmConfig, DEFAULT_VIRTQUEUE_SIZE, + }; const QUEUE_NUM_BLK: usize = 1; const CONFIG_SPACE_SIZE: usize = 60; @@ -1390,11 +1477,36 @@ mod tests { fn init_default_block() -> Block { Block::new( - BlkDevConfig::default(), + VirtioBlkDevConfig::default(), + DriveConfig::default(), Arc::new(Mutex::new(HashMap::new())), ) } + #[test] + fn test_virtio_block_config_cmdline_parser() { + // Test1: Right. + let blk_cmd1 = "virtio-blk-pci,id=rootfs,bus=pcie.0,addr=0x1.0x2,drive=rootfs,serial=111111,num-queues=4"; + let blk_config = + VirtioBlkDevConfig::try_parse_from(str_slip_to_clap(blk_cmd1, true, false)).unwrap(); + assert_eq!(blk_config.id, "rootfs"); + assert_eq!(blk_config.bus.unwrap(), "pcie.0"); + assert_eq!(blk_config.addr.unwrap(), (1, 2)); + assert_eq!(blk_config.serial.unwrap(), "111111"); + assert_eq!(blk_config.num_queues.unwrap(), 4); + + // Test2: Default values. + assert_eq!(blk_config.queue_size, DEFAULT_VIRTQUEUE_SIZE); + + // Test3: Illegal values. + let blk_cmd3 = "virtio-blk-pci,id=rootfs,bus=pcie.0,addr=0x1.0x2,drive=rootfs,serial=111111,num-queues=33"; + let result = VirtioBlkDevConfig::try_parse_from(str_slip_to_clap(blk_cmd3, true, false)); + assert!(result.is_err()); + let blk_cmd3 = "virtio-blk-pci,id=rootfs,drive=rootfs,serial=111111111111111111111111111111111111111111111111111111111111111111111"; + let result = VirtioBlkDevConfig::try_parse_from(str_slip_to_clap(blk_cmd3, true, false)); + assert!(result.is_err()); + } + // Use different input parameters to verify block `new()` and `realize()` functionality. #[test] fn test_block_init() { @@ -1410,16 +1522,16 @@ mod tests { assert!(block.senders.is_empty()); // Realize block device: create TempFile as backing file. - block.blk_cfg.read_only = true; - block.blk_cfg.direct = false; + block.drive_cfg.readonly = true; + block.drive_cfg.direct = false; let f = TempFile::new().unwrap(); - block.blk_cfg.path_on_host = f.as_path().to_str().unwrap().to_string(); + block.drive_cfg.path_on_host = f.as_path().to_str().unwrap().to_string(); VmConfig::add_drive_file( &mut block.drive_files.lock().unwrap(), "", - &block.blk_cfg.path_on_host, - block.blk_cfg.read_only, - block.blk_cfg.direct, + &block.drive_cfg.path_on_host, + block.drive_cfg.readonly, + block.drive_cfg.direct, ) .unwrap(); assert!(block.realize().is_ok()); @@ -1548,19 +1660,19 @@ mod tests { let mut block = init_default_block(); let file = TempFile::new().unwrap(); - block.blk_cfg.path_on_host = file.as_path().to_str().unwrap().to_string(); - block.blk_cfg.direct = false; + block.drive_cfg.path_on_host = file.as_path().to_str().unwrap().to_string(); + block.drive_cfg.direct = false; // config iothread and iops block.blk_cfg.iothread = Some(thread_name); - block.blk_cfg.iops = Some(100); + block.drive_cfg.iops = Some(100); VmConfig::add_drive_file( &mut block.drive_files.lock().unwrap(), "", - &block.blk_cfg.path_on_host, - block.blk_cfg.read_only, - block.blk_cfg.direct, + &block.drive_cfg.path_on_host, + block.drive_cfg.readonly, + block.drive_cfg.direct, ) .unwrap(); diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index 4e605faa..48b19cc4 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -1596,9 +1596,9 @@ impl VirtioDevice for Net { Ok(()) } - fn update_config(&mut self, dev_config: Option>) -> Result<()> { - if let Some(conf) = dev_config { - self.net_cfg = conf + fn update_config(&mut self, dev_config: Vec>) -> Result<()> { + if !dev_config.is_empty() { + self.net_cfg = dev_config[0] .as_any() .downcast_ref::() .unwrap() diff --git a/virtio/src/device/scsi_cntlr.rs b/virtio/src/device/scsi_cntlr.rs index dc2d8f51..8f301df1 100644 --- a/virtio/src/device/scsi_cntlr.rs +++ b/virtio/src/device/scsi_cntlr.rs @@ -34,8 +34,7 @@ use devices::ScsiBus::{ EMULATE_SCSI_OPS, SCSI_CMD_BUF_SIZE, SCSI_SENSE_INVALID_OPCODE, }; use machine_manager::config::{ - get_pci_df, parse_bool, valid_id, valid_virtqueue_size, MAX_QUEUE_SIZE_SCSI, MAX_VIRTIO_QUEUE, - MIN_QUEUE_SIZE_SCSI, + get_pci_df, parse_bool, valid_block_device_virtqueue_size, valid_id, MAX_VIRTIO_QUEUE, }; use machine_manager::event_loop::{register_event_helper, unregister_event_helper, EventLoop}; use util::aio::Iovec; @@ -113,17 +112,10 @@ pub struct ScsiCntlrConfig { pub num_queues: Option, #[arg(long)] pub iothread: Option, - #[arg(long, alias = "queue-size", default_value = "256", value_parser = valid_scsi_cntlr_queue_size)] + #[arg(long, alias = "queue-size", default_value = "256", value_parser = valid_block_device_virtqueue_size)] pub queue_size: u16, } -fn valid_scsi_cntlr_queue_size(s: &str) -> Result { - let size: u64 = s.parse()?; - valid_virtqueue_size(size, MIN_QUEUE_SIZE_SCSI + 1, MAX_QUEUE_SIZE_SCSI)?; - - Ok(size as u16) -} - #[repr(C, packed)] #[derive(Copy, Clone, Debug, Default)] struct VirtioScsiConfig { diff --git a/virtio/src/lib.rs b/virtio/src/lib.rs index 750d6e1b..7f0fac21 100644 --- a/virtio/src/lib.rs +++ b/virtio/src/lib.rs @@ -33,7 +33,7 @@ mod queue; mod transport; pub use device::balloon::*; -pub use device::block::{Block, BlockState, VirtioBlkConfig}; +pub use device::block::{Block, BlockState, VirtioBlkConfig, VirtioBlkDevConfig}; #[cfg(feature = "virtio_gpu")] pub use device::gpu::*; pub use device::net::*; @@ -729,8 +729,9 @@ pub trait VirtioDevice: Send + AsAny { /// /// # Arguments /// - /// * `_file_path` - The related backend file path. - fn update_config(&mut self, _dev_config: Option>) -> Result<()> { + /// * `_configs` - The related configs for device. + /// eg: DriveConfig and VirtioBlkDevConfig for virtio blk device. + fn update_config(&mut self, _configs: Vec>) -> Result<()> { bail!("Unsupported to update configuration") } diff --git a/virtio/src/vhost/user/block.rs b/virtio/src/vhost/user/block.rs index 25d030b7..8c55cac1 100644 --- a/virtio/src/vhost/user/block.rs +++ b/virtio/src/vhost/user/block.rs @@ -13,6 +13,7 @@ use std::sync::{Arc, Mutex}; use anyhow::{anyhow, bail, Context, Result}; +use clap::Parser; use vmm_sys_util::eventfd::EventFd; use super::client::VhostUserClient; @@ -30,14 +31,41 @@ use crate::{ VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_WRITE_ZEROES, VIRTIO_F_VERSION_1, VIRTIO_TYPE_BLOCK, }; use address_space::AddressSpace; -use machine_manager::{config::BlkDevConfig, event_loop::unregister_event_helper}; +use machine_manager::config::{ + get_chardev_socket_path, get_pci_df, valid_block_device_virtqueue_size, valid_id, + ChardevConfig, MAX_VIRTIO_QUEUE, +}; +use machine_manager::event_loop::unregister_event_helper; use util::byte_code::ByteCode; +#[derive(Parser, Debug, Clone, Default)] +#[command(no_binary_name(true))] +pub struct VhostUserBlkDevConfig { + #[arg(long, value_parser = ["vhost-user-blk-device", "vhost-user-blk-pci"])] + pub classtype: String, + #[arg(long, value_parser = valid_id)] + pub id: String, + #[arg(long)] + pub bus: Option, + #[arg(long, value_parser = get_pci_df)] + pub addr: Option<(u8, u8)>, + #[arg(long, alias = "num-queues", value_parser = clap::value_parser!(u16).range(1..=MAX_VIRTIO_QUEUE as i64))] + pub num_queues: Option, + #[arg(long)] + pub chardev: String, + #[arg(long, alias = "queue-size", default_value = "256", value_parser = valid_block_device_virtqueue_size)] + pub queue_size: u16, + #[arg(long)] + pub bootindex: Option, +} + pub struct Block { /// Virtio device base property. base: VirtioBase, /// Configuration of the block device. - blk_cfg: BlkDevConfig, + blk_cfg: VhostUserBlkDevConfig, + /// Configuration of the vhost user blk's socket chardev. + chardev_cfg: ChardevConfig, /// Config space of the block device. config_space: VirtioBlkConfig, /// System address space. @@ -51,13 +79,18 @@ pub struct Block { } impl Block { - pub fn new(cfg: &BlkDevConfig, mem_space: &Arc) -> Self { - let queue_num = cfg.queues as usize; + pub fn new( + cfg: &VhostUserBlkDevConfig, + chardev_cfg: ChardevConfig, + mem_space: &Arc, + ) -> Self { + let queue_num = cfg.num_queues.unwrap_or(1) as usize; let queue_size = cfg.queue_size; Block { base: VirtioBase::new(VIRTIO_TYPE_BLOCK, queue_num, queue_size), blk_cfg: cfg.clone(), + chardev_cfg, config_space: Default::default(), mem_space: mem_space.clone(), client: None, @@ -68,12 +101,7 @@ impl Block { /// Connect with spdk and register update event. fn init_client(&mut self) -> Result<()> { - let socket_path = self - .blk_cfg - .socket_path - .as_ref() - .map(|path| path.to_string()) - .with_context(|| "vhost-user: socket path is not found")?; + let socket_path = get_chardev_socket_path(self.chardev_cfg.clone())?; let client = VhostUserClient::new( &self.mem_space, &socket_path, @@ -146,10 +174,10 @@ impl VirtioDevice for Block { ); } - if self.blk_cfg.queues > 1 { - self.config_space.num_queues = self.blk_cfg.queues; + if self.blk_cfg.num_queues.unwrap_or(1) > 1 { + self.config_space.num_queues = self.blk_cfg.num_queues.unwrap_or(1); } - } else if self.blk_cfg.queues > 1 { + } else if self.blk_cfg.num_queues.unwrap_or(1) > 1 { bail!( "spdk doesn't support multi queue, spdk protocol features: {:#b}", protocol_features @@ -169,7 +197,7 @@ impl VirtioDevice for Block { | 1_u64 << VIRTIO_BLK_F_WRITE_ZEROES | 1_u64 << VIRTIO_BLK_F_SEG_MAX | 1_u64 << VIRTIO_BLK_F_RO; - if self.blk_cfg.queues > 1 { + if self.blk_cfg.num_queues.unwrap_or(1) > 1 { self.base.device_features |= 1_u64 << VIRTIO_BLK_F_MQ; } self.base.device_features &= features; @@ -217,13 +245,7 @@ impl VirtioDevice for Block { if !self.enable_irqfd { let queue_num = self.base.queues.len(); - listen_guest_notifier( - &mut self.base, - &mut client, - self.blk_cfg.iothread.as_ref(), - queue_num, - interrupt_cb, - )?; + listen_guest_notifier(&mut self.base, &mut client, None, queue_num, interrupt_cb)?; } client.activate_vhost_user()?; @@ -235,10 +257,7 @@ impl VirtioDevice for Block { if let Some(client) = &self.client { client.lock().unwrap().reset_vhost_user(false); } - unregister_event_helper( - self.blk_cfg.iothread.as_ref(), - &mut self.base.deactivate_evts, - )?; + unregister_event_helper(None, &mut self.base.deactivate_evts)?; Ok(()) } diff --git a/virtio/src/vhost/user/mod.rs b/virtio/src/vhost/user/mod.rs index 2f0dc96f..8a6e8d42 100644 --- a/virtio/src/vhost/user/mod.rs +++ b/virtio/src/vhost/user/mod.rs @@ -18,7 +18,7 @@ mod message; mod net; mod sock; -pub use self::block::Block; +pub use self::block::{Block, VhostUserBlkDevConfig}; pub use self::client::*; pub use self::fs::*; pub use self::message::*; -- Gitee From de6e08939e8acc6999c7d9f64a12e3d318725beb Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sat, 13 Apr 2024 21:30:37 +0800 Subject: [PATCH 030/489] netdev: use clap to parse the parameters of the netdev config Use clap to parse the parameters of the netdev config. Signed-off-by: liuxiangdong --- machine_manager/src/config/network.rs | 312 +++++++++----------------- 1 file changed, 106 insertions(+), 206 deletions(-) diff --git a/machine_manager/src/config/network.rs b/machine_manager/src/config/network.rs index 01c7570e..d1421309 100644 --- a/machine_manager/src/config/network.rs +++ b/machine_manager/src/config/network.rs @@ -13,9 +13,11 @@ use std::os::unix::io::RawFd; use anyhow::{anyhow, bail, Context, Result}; +use clap::{ArgAction, Parser}; use serde::{Deserialize, Serialize}; use super::{error::ConfigError, pci_args_check}; +use super::{parse_bool, str_slip_to_clap, valid_id}; use crate::config::get_chardev_socket_path; use crate::config::{ check_arg_too_long, CmdParser, ConfigCheck, ExBool, VmConfig, DEFAULT_VIRTQUEUE_SIZE, @@ -30,23 +32,80 @@ pub const MAX_QUEUE_SIZE_NET: u16 = 4096; /// Max num of virtqueues. const MAX_QUEUE_PAIRS: usize = MAX_VIRTIO_QUEUE / 2; -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Parser, Debug, Clone, Serialize, Deserialize)] +#[command(no_binary_name(true))] pub struct NetDevcfg { + #[arg(long, alias="classtype", value_parser = ["tap", "vhost-user"])] + pub netdev_type: String, + #[arg(long, value_parser = valid_id)] pub id: String, + #[arg(long, aliases = ["fds", "fd"], use_value_delimiter = true, value_delimiter = ':')] pub tap_fds: Option>, - pub vhost_type: Option, + #[arg(long, alias = "vhost", default_value = "off", value_parser = parse_bool, action = ArgAction::Append)] + pub vhost_kernel: bool, + #[arg(long, aliases = ["vhostfds", "vhostfd"], use_value_delimiter = true, value_delimiter = ':')] pub vhost_fds: Option>, + #[arg(long, default_value = "", value_parser = valid_id)] pub ifname: String, + #[arg(long, default_value = "1", value_parser = parse_queues)] pub queues: u16, + #[arg(long)] pub chardev: Option, } +impl NetDevcfg { + pub fn vhost_type(&self) -> Option { + if self.vhost_kernel { + return Some("vhost-kernel".to_string()); + } + if self.netdev_type == "vhost-user" { + return Some("vhost-user".to_string()); + } + // Default: virtio net. + None + } + + fn auto_queues(&mut self) -> Result<()> { + if let Some(fds) = &self.tap_fds { + let fds_num = fds + .len() + .checked_mul(2) + .with_context(|| format!("Invalid fds number {}", fds.len()))? + as u16; + if fds_num > self.queues { + self.queues = fds_num; + } + } + if let Some(fds) = &self.vhost_fds { + let fds_num = fds + .len() + .checked_mul(2) + .with_context(|| format!("Invalid vhostfds number {}", fds.len()))? + as u16; + if fds_num > self.queues { + self.queues = fds_num; + } + } + Ok(()) + } +} + +fn parse_queues(q: &str) -> Result { + let queues = q + .parse::()? + .checked_mul(2) + .with_context(|| "Invalid 'queues' value")?; + is_netdev_queues_valid(queues)?; + Ok(queues) +} + impl Default for NetDevcfg { fn default() -> Self { NetDevcfg { + netdev_type: "".to_string(), id: "".to_string(), tap_fds: None, - vhost_type: None, + vhost_kernel: false, vhost_fds: None, ifname: "".to_string(), queues: 2, @@ -57,24 +116,18 @@ impl Default for NetDevcfg { impl ConfigCheck for NetDevcfg { fn check(&self) -> Result<()> { - check_arg_too_long(&self.id, "id")?; - check_arg_too_long(&self.ifname, "ifname")?; - - if let Some(vhost_type) = self.vhost_type.as_ref() { - if vhost_type != "vhost-kernel" && vhost_type != "vhost-user" { - return Err(anyhow!(ConfigError::UnknownVhostType)); - } + if self.vhost_kernel && self.netdev_type == "vhost-user" { + bail!("vhost-user netdev does not support 'vhost' option"); } - if !is_netdev_queues_valid(self.queues) { - return Err(anyhow!(ConfigError::IllegalValue( - "number queues of net device".to_string(), - 1, - true, - MAX_VIRTIO_QUEUE as u64 / 2, - true, - ))); + if self.vhost_fds.is_some() && self.vhost_type().is_none() { + bail!("Argument 'vhostfd' or 'vhostfds' are not needed for virtio-net device"); } + if self.tap_fds.is_none() && self.ifname.eq("") && self.netdev_type.ne("vhost-user") { + bail!("Tap device is missing, use \'ifname\' or \'fd\' to configure a tap device"); + } + + is_netdev_queues_valid(self.queues)?; Ok(()) } @@ -156,102 +209,6 @@ impl ConfigCheck for NetworkInterfaceConfig { } } -fn parse_fds(cmd_parser: &CmdParser, name: &str) -> Result>> { - if let Some(fds) = cmd_parser.get_value::(name)? { - let mut raw_fds = Vec::new(); - for fd in fds.split(':').collect::>().iter() { - raw_fds.push( - (*fd) - .parse::() - .with_context(|| "Failed to parse fds")?, - ); - } - Ok(Some(raw_fds)) - } else { - Ok(None) - } -} - -fn parse_netdev(cmd_parser: CmdParser) -> Result { - let mut net = NetDevcfg::default(); - let netdev_type = cmd_parser.get_value::("")?.unwrap_or_default(); - if netdev_type.ne("tap") && netdev_type.ne("vhost-user") { - bail!("Unsupported netdev type: {:?}", &netdev_type); - } - net.id = cmd_parser - .get_value::("id")? - .with_context(|| ConfigError::FieldIsMissing("id".to_string(), "netdev".to_string()))?; - if let Some(ifname) = cmd_parser.get_value::("ifname")? { - net.ifname = ifname; - } - if let Some(queue_pairs) = cmd_parser.get_value::("queues")? { - let queues = queue_pairs.checked_mul(2); - if queues.is_none() || !is_netdev_queues_valid(queues.unwrap()) { - return Err(anyhow!(ConfigError::IllegalValue( - "number queues of net device".to_string(), - 1, - true, - MAX_VIRTIO_QUEUE as u64 / 2, - true, - ))); - } - - net.queues = queues.unwrap(); - } - - if let Some(tap_fd) = parse_fds(&cmd_parser, "fd")? { - net.tap_fds = Some(tap_fd); - } else if let Some(tap_fds) = parse_fds(&cmd_parser, "fds")? { - net.tap_fds = Some(tap_fds); - } - if let Some(fds) = &net.tap_fds { - let fds_num = - fds.len() - .checked_mul(2) - .with_context(|| format!("Invalid fds number {}", fds.len()))? as u16; - if fds_num > net.queues { - net.queues = fds_num; - } - } - - if let Some(vhost) = cmd_parser.get_value::("vhost")? { - if vhost.into() { - net.vhost_type = Some(String::from("vhost-kernel")); - } - } else if netdev_type.eq("vhost-user") { - net.vhost_type = Some(String::from("vhost-user")); - } - if let Some(chardev) = cmd_parser.get_value::("chardev")? { - net.chardev = Some(chardev); - } - if let Some(vhost_fd) = parse_fds(&cmd_parser, "vhostfd")? { - net.vhost_fds = Some(vhost_fd); - } else if let Some(vhost_fds) = parse_fds(&cmd_parser, "vhostfds")? { - net.vhost_fds = Some(vhost_fds); - } - if let Some(fds) = &net.vhost_fds { - let fds_num = fds - .len() - .checked_mul(2) - .with_context(|| format!("Invalid vhostfds number {}", fds.len()))? - as u16; - if fds_num > net.queues { - net.queues = fds_num; - } - } - - if net.vhost_fds.is_some() && net.vhost_type.is_none() { - bail!("Argument \'vhostfd\' is not needed for virtio-net device"); - } - if net.tap_fds.is_none() && net.ifname.eq("") && netdev_type.ne("vhost-user") { - bail!("Tap device is missing, use \'ifname\' or \'fd\' to configure a tap device"); - } - - net.check()?; - - Ok(net) -} - pub fn parse_net(vm_config: &mut VmConfig, net_config: &str) -> Result { let mut cmd_parser = CmdParser::new("virtio-net"); cmd_parser @@ -293,7 +250,7 @@ pub fn parse_net(vm_config: &mut VmConfig, net_config: &str) -> Result) -> Result) -> Result Result<()> { - let mut cmd_parser = CmdParser::new("netdev"); - cmd_parser - .push("") - .push("id") - .push("fd") - .push("fds") - .push("vhost") - .push("ifname") - .push("vhostfd") - .push("vhostfds") - .push("queues") - .push("chardev"); - - cmd_parser.parse(netdev_config)?; - let drive_cfg = parse_netdev(cmd_parser)?; - self.add_netdev_with_config(drive_cfg) + let mut netdev_cfg = + NetDevcfg::try_parse_from(str_slip_to_clap(netdev_config, true, false))?; + netdev_cfg.auto_queues()?; + netdev_cfg.check()?; + self.add_netdev_with_config(netdev_cfg) } pub fn add_netdev_with_config(&mut self, conf: NetDevcfg) -> Result<()> { let netdev_id = conf.id.clone(); - if self.netdevs.get(&netdev_id).is_none() { - self.netdevs.insert(netdev_id, conf); - } else { + if self.netdevs.get(&netdev_id).is_some() { bail!("Netdev {:?} has been added", netdev_id); } + self.netdevs.insert(netdev_id, conf); Ok(()) } pub fn del_netdev_by_id(&mut self, id: &str) -> Result<()> { - if self.netdevs.get(id).is_some() { - self.netdevs.remove(id); - } else { - bail!("Netdev {} not found", id); - } + self.netdevs + .remove(id) + .with_context(|| format!("Netdev {} not found", id))?; + Ok(()) } } @@ -489,14 +410,24 @@ fn check_mac_address(mac: &str) -> bool { true } -fn is_netdev_queues_valid(queues: u16) -> bool { - queues >= 1 && queues <= MAX_VIRTIO_QUEUE as u16 +fn is_netdev_queues_valid(queues: u16) -> Result<()> { + if !(queues >= 2 && queues <= MAX_VIRTIO_QUEUE as u16) { + return Err(anyhow!(ConfigError::IllegalValue( + "number queues of net device".to_string(), + 1, + true, + MAX_QUEUE_PAIRS as u64, + true, + ))); + } + + Ok(()) } #[cfg(test)] mod tests { use super::*; - use crate::config::{get_pci_bdf, MAX_STRING_LENGTH}; + use crate::config::get_pci_bdf; #[test] fn test_network_config_cmdline_parser() { @@ -661,37 +592,6 @@ mod tests { assert!(net_cfg_res.is_err()); } - #[test] - fn test_netdev_config_check() { - let mut netdev_conf = NetDevcfg::default(); - for _ in 0..MAX_STRING_LENGTH { - netdev_conf.id += "A"; - } - assert!(netdev_conf.check().is_ok()); - - // Overflow - netdev_conf.id += "A"; - assert!(netdev_conf.check().is_err()); - - let mut netdev_conf = NetDevcfg::default(); - for _ in 0..MAX_STRING_LENGTH { - netdev_conf.ifname += "A"; - } - assert!(netdev_conf.check().is_ok()); - - // Overflow - netdev_conf.ifname += "A"; - assert!(netdev_conf.check().is_err()); - - let mut netdev_conf = NetDevcfg::default(); - netdev_conf.vhost_type = None; - assert!(netdev_conf.check().is_ok()); - netdev_conf.vhost_type = Some(String::from("vhost-kernel")); - assert!(netdev_conf.check().is_ok()); - netdev_conf.vhost_type = Some(String::from("vhost-")); - assert!(netdev_conf.check().is_err()); - } - #[test] fn test_add_netdev_with_different_queues() { let mut vm_config = VmConfig::default(); @@ -815,9 +715,9 @@ mod tests { ..qmp_schema::NetDevAddArgument::default() }); let net_cfg = get_netdev_config(netdev).unwrap(); + assert_eq!(net_cfg.vhost_type().unwrap(), "vhost-kernel"); assert_eq!(net_cfg.tap_fds.unwrap()[0], 11); assert_eq!(net_cfg.vhost_fds.unwrap()[0], 21); - assert_eq!(net_cfg.vhost_type.unwrap(), "vhost-kernel"); } // Normal test with 'vhostfds'. @@ -835,9 +735,9 @@ mod tests { ..qmp_schema::NetDevAddArgument::default() }); let net_cfg = get_netdev_config(netdev).unwrap(); - assert_eq!(net_cfg.tap_fds.unwrap(), [11, 12, 13, 14]); - assert_eq!(net_cfg.vhost_fds.unwrap(), [21, 22, 23, 24]); - assert_eq!(net_cfg.vhost_type.unwrap(), "vhost-kernel"); + assert_eq!(net_cfg.vhost_type().unwrap(), "vhost-kernel"); + assert_eq!(net_cfg.tap_fds.unwrap(), vec![11, 12, 13, 14]); + assert_eq!(net_cfg.vhost_fds.unwrap(), vec![21, 22, 23, 24]); } let err_msgs = [ @@ -863,8 +763,7 @@ mod tests { ..qmp_schema::NetDevAddArgument::default() }); let err_msg = format!( - "The 'queues' {} is bigger than max queue num {}", - MAX_QUEUE_PAIRS + 1, + "number queues of net device must >= 1 and <= {}.", MAX_QUEUE_PAIRS ); check_err_msg(netdev, &err_msg); @@ -933,6 +832,7 @@ mod tests { fds: Some(fds.to_string()), ..qmp_schema::NetDevAddArgument::default() }); + // number queues of net device let err_msg = format!( "The num of fd {} is bigger than max queue num {}", MAX_QUEUE_PAIRS + 1, -- Gitee From 6720e56920a91fef00f8a5d76a0384da7a8d4fcc Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sun, 14 Apr 2024 10:08:00 +0800 Subject: [PATCH 031/489] network: use clap to parse the parameters of the virtio-net/vhost-net/vhost-user-net config Use clap to parse the parameters of the virtio-net/vhost-net/vhost-user-net config. Signed-off-by: liuxiangdong --- machine/src/lib.rs | 50 ++-- machine/src/micro_common/mod.rs | 78 +++--- machine_manager/src/config/network.rs | 363 +++++++++----------------- virtio/src/device/net.rs | 37 ++- virtio/src/vhost/kernel/net.rs | 86 +++--- virtio/src/vhost/user/net.rs | 32 ++- 6 files changed, 296 insertions(+), 350 deletions(-) diff --git a/machine/src/lib.rs b/machine/src/lib.rs index d21fed9f..eaafa909 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -73,11 +73,12 @@ use hypervisor::{kvm::KvmHypervisor, test::TestHypervisor, HypervisorOps}; #[cfg(feature = "usb_camera")] use machine_manager::config::get_cameradev_by_id; use machine_manager::config::{ - complete_numa_node, get_multi_function, get_pci_bdf, parse_device_id, parse_device_type, - parse_net, parse_numa_distance, parse_numa_mem, parse_virtio_serial, parse_virtserialport, - parse_vsock, str_slip_to_clap, BootIndexInfo, BootSource, DriveConfig, DriveFile, Incoming, - MachineMemConfig, MigrateMode, NumaConfig, NumaDistance, NumaNode, NumaNodes, PciBdf, - SerialConfig, VmConfig, FAST_UNPLUG_ON, MAX_VIRTIO_QUEUE, + complete_numa_node, get_chardev_socket_path, get_multi_function, get_pci_bdf, parse_device_id, + parse_device_type, parse_numa_distance, parse_numa_mem, parse_virtio_serial, + parse_virtserialport, parse_vsock, str_slip_to_clap, BootIndexInfo, BootSource, DriveConfig, + DriveFile, Incoming, MachineMemConfig, MigrateMode, NetworkInterfaceConfig, NumaConfig, + NumaDistance, NumaNode, NumaNodes, PciBdf, SerialConfig, VmConfig, FAST_UNPLUG_ON, + MAX_VIRTIO_QUEUE, }; use machine_manager::event_loop::EventLoop; use machine_manager::machine::{HypervisorType, MachineInterface, VmState}; @@ -1204,35 +1205,52 @@ pub trait MachineOps { cfg_args: &str, hotplug: bool, ) -> Result<()> { - let bdf = get_pci_bdf(cfg_args)?; - let multi_func = get_multi_function(cfg_args)?; - let device_cfg = parse_net(vm_config, cfg_args)?; + let net_cfg = + NetworkInterfaceConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + let netdev_cfg = vm_config + .netdevs + .remove(&net_cfg.netdev) + .with_context(|| format!("Netdev: {:?} not found for net device", &net_cfg.netdev))?; + let bdf = PciBdf::new(net_cfg.bus.clone().unwrap(), net_cfg.addr.unwrap()); + let multi_func = net_cfg.multifunction.unwrap_or_default(); + let mut need_irqfd = false; - let device: Arc> = if device_cfg.vhost_type.is_some() { + let device: Arc> = if netdev_cfg.vhost_type().is_some() { need_irqfd = true; - if device_cfg.vhost_type == Some(String::from("vhost-kernel")) { + if netdev_cfg.vhost_type().unwrap() == "vhost-kernel" { Arc::new(Mutex::new(VhostKern::Net::new( - &device_cfg, + &net_cfg, + netdev_cfg, self.get_sys_mem(), ))) } else { + let chardev = netdev_cfg.chardev.clone().with_context(|| { + format!("Chardev not configured for netdev {:?}", netdev_cfg.id) + })?; + let chardev_cfg = vm_config + .chardev + .remove(&chardev) + .with_context(|| format!("Chardev: {:?} not found for netdev", chardev))?; + let sock_path = get_chardev_socket_path(chardev_cfg)?; Arc::new(Mutex::new(VhostUser::Net::new( - &device_cfg, + &net_cfg, + netdev_cfg, + sock_path, self.get_sys_mem(), ))) } } else { - let device = Arc::new(Mutex::new(virtio::Net::new(device_cfg.clone()))); + let device = Arc::new(Mutex::new(virtio::Net::new(net_cfg.clone(), netdev_cfg))); MigrationManager::register_device_instance( VirtioNetState::descriptor(), device.clone(), - &device_cfg.id, + &net_cfg.id, ); device }; - self.add_virtio_pci_device(&device_cfg.id, &bdf, device, multi_func, need_irqfd)?; + self.add_virtio_pci_device(&net_cfg.id, &bdf, device, multi_func, need_irqfd)?; if !hotplug { - self.reset_bus(&device_cfg.id)?; + self.reset_bus(&net_cfg.id)?; } Ok(()) } diff --git a/machine/src/micro_common/mod.rs b/machine/src/micro_common/mod.rs index 1ac45966..ba58236b 100644 --- a/machine/src/micro_common/mod.rs +++ b/machine/src/micro_common/mod.rs @@ -49,8 +49,8 @@ use crate::{MachineBase, MachineError, MachineOps}; use cpu::CpuLifecycleState; use devices::sysbus::{IRQ_BASE, IRQ_MAX}; use machine_manager::config::{ - parse_incoming_uri, parse_net, str_slip_to_clap, ConfigCheck, DriveConfig, MigrateMode, - NetworkInterfaceConfig, VmConfig, DEFAULT_VIRTQUEUE_SIZE, + get_chardev_socket_path, parse_incoming_uri, str_slip_to_clap, ConfigCheck, DriveConfig, + MigrateMode, NetDevcfg, NetworkInterfaceConfig, VmConfig, }; use machine_manager::event; use machine_manager::event_loop::EventLoop; @@ -79,7 +79,8 @@ const MMIO_REPLACEABLE_NET_NR: usize = 2; struct MmioReplaceableConfig { // Device id. id: String, - // The config of the related backend device. Eg: Drive config of virtio mmio device. + // The config of the related backend device. + // Eg: Drive config of virtio mmio block. Netdev config of virtio mmio net. back_config: Arc, } @@ -173,7 +174,10 @@ impl LightMachine { ); } for id in 0..MMIO_REPLACEABLE_NET_NR { - let net = Arc::new(Mutex::new(Net::new(NetworkInterfaceConfig::default()))); + let net = Arc::new(Mutex::new(Net::new( + NetworkInterfaceConfig::default(), + NetDevcfg::default(), + ))); let virtio_mmio = VirtioMmioDevice::new(&self.base.sys_mem, net.clone()); rpl_devs.push(virtio_mmio); @@ -293,9 +297,18 @@ impl LightMachine { MMIO_REPLACEABLE_NET_NR ))); } - if cfg_any.downcast_ref::().is_none() { + if cfg_any.downcast_ref::().is_none() { return Err(anyhow!(MachineError::DevTypeErr("net".to_string()))); } + let net_config = NetworkInterfaceConfig { + classtype: driver, + id: id.clone(), + netdev: args.chardev.with_context(|| "No chardev set")?, + mac: args.mac, + iothread: args.iothread, + ..Default::default() + }; + configs.push(Arc::new(net_config)); slot + MMIO_REPLACEABLE_BLK_NR } else if driver.contains("blk") { if slot >= MMIO_REPLACEABLE_BLK_NR { @@ -384,17 +397,33 @@ impl LightMachine { vm_config: &mut VmConfig, cfg_args: &str, ) -> Result<()> { - let device_cfg = parse_net(vm_config, cfg_args)?; - if device_cfg.vhost_type.is_some() { - let device = if device_cfg.vhost_type == Some(String::from("vhost-kernel")) { + let net_cfg = + NetworkInterfaceConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + let netdev_cfg = vm_config + .netdevs + .remove(&net_cfg.netdev) + .with_context(|| format!("Netdev: {:?} not found for net device", &net_cfg.netdev))?; + if netdev_cfg.vhost_type().is_some() { + let device = if netdev_cfg.vhost_type().unwrap() == "vhost-kernel" { let net = Arc::new(Mutex::new(VhostKern::Net::new( - &device_cfg, + &net_cfg, + netdev_cfg, &self.base.sys_mem, ))); VirtioMmioDevice::new(&self.base.sys_mem, net) } else { + let chardev = netdev_cfg.chardev.clone().with_context(|| { + format!("Chardev not configured for netdev {:?}", netdev_cfg.id) + })?; + let chardev_cfg = vm_config + .chardev + .remove(&chardev) + .with_context(|| format!("Chardev: {:?} not found for netdev", chardev))?; + let sock_path = get_chardev_socket_path(chardev_cfg)?; let net = Arc::new(Mutex::new(VhostUser::Net::new( - &device_cfg, + &net_cfg, + netdev_cfg, + sock_path, &self.base.sys_mem, ))); VirtioMmioDevice::new(&self.base.sys_mem, net) @@ -408,11 +437,9 @@ impl LightMachine { MMIO_REPLACEABLE_NET_NR ); } - self.fill_replaceable_device( - &device_cfg.id, - vec![Arc::new(device_cfg.clone())], - index, - )?; + let configs: Vec> = + vec![Arc::new(netdev_cfg), Arc::new(net_cfg.clone())]; + self.fill_replaceable_device(&net_cfg.id, configs, index)?; self.replaceable_info.net_count += 1; } Ok(()) @@ -805,18 +832,9 @@ impl DeviceInterface for LightMachine { } fn netdev_add(&mut self, args: Box) -> Response { - let mut config = NetworkInterfaceConfig { + let mut netdev_cfg = NetDevcfg { id: args.id.clone(), - host_dev_name: "".to_string(), - mac: None, - tap_fds: None, - vhost_type: None, - vhost_fds: None, - iothread: None, - queues: 2, - mq: false, - socket_path: None, - queue_size: DEFAULT_VIRTQUEUE_SIZE, + ..Default::default() }; if let Some(fds) = args.fds { @@ -828,7 +846,7 @@ impl DeviceInterface for LightMachine { }; if let Some(fd_num) = QmpChannel::get_fd(&netdev_fd) { - config.tap_fds = Some(vec![fd_num]); + netdev_cfg.tap_fds = Some(vec![fd_num]); } else { // try to convert string to RawFd let fd_num = match netdev_fd.parse::() { @@ -846,10 +864,10 @@ impl DeviceInterface for LightMachine { ); } }; - config.tap_fds = Some(vec![fd_num]); + netdev_cfg.tap_fds = Some(vec![fd_num]); } } else if let Some(if_name) = args.if_name { - config.host_dev_name = if_name.clone(); + netdev_cfg.ifname = if_name.clone(); if create_tap(None, Some(&if_name), 1).is_err() { return Response::create_error_response( qmp_schema::QmpErrorClass::GenericError( @@ -860,7 +878,7 @@ impl DeviceInterface for LightMachine { } } - match self.add_replaceable_config(&args.id, Arc::new(config)) { + match self.add_replaceable_config(&args.id, Arc::new(netdev_cfg)) { Ok(()) => Response::create_empty_response(), Err(ref e) => { error!("{:?}", e); diff --git a/machine_manager/src/config/network.rs b/machine_manager/src/config/network.rs index d1421309..c9e58976 100644 --- a/machine_manager/src/config/network.rs +++ b/machine_manager/src/config/network.rs @@ -16,19 +16,15 @@ use anyhow::{anyhow, bail, Context, Result}; use clap::{ArgAction, Parser}; use serde::{Deserialize, Serialize}; -use super::{error::ConfigError, pci_args_check}; -use super::{parse_bool, str_slip_to_clap, valid_id}; -use crate::config::get_chardev_socket_path; -use crate::config::{ - check_arg_too_long, CmdParser, ConfigCheck, ExBool, VmConfig, DEFAULT_VIRTQUEUE_SIZE, - MAX_PATH_LENGTH, MAX_VIRTIO_QUEUE, -}; +use super::error::ConfigError; +use super::{get_pci_df, parse_bool, str_slip_to_clap, valid_id, valid_virtqueue_size}; +use crate::config::{ConfigCheck, VmConfig, DEFAULT_VIRTQUEUE_SIZE, MAX_VIRTIO_QUEUE}; use crate::qmp::{qmp_channel::QmpChannel, qmp_schema}; const MAC_ADDRESS_LENGTH: usize = 17; /// Max virtqueue size of each virtqueue. -pub const MAX_QUEUE_SIZE_NET: u16 = 4096; +const MAX_QUEUE_SIZE_NET: u64 = 4096; /// Max num of virtqueues. const MAX_QUEUE_PAIRS: usize = MAX_VIRTIO_QUEUE / 2; @@ -135,135 +131,73 @@ impl ConfigCheck for NetDevcfg { /// Config struct for network /// Contains network device config, such as `host_dev_name`, `mac`... -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize, Parser)] #[serde(deny_unknown_fields)] +#[command(no_binary_name(true))] pub struct NetworkInterfaceConfig { + #[arg(long, value_parser = ["virtio-net-pci", "virtio-net-device"])] + pub classtype: String, + #[arg(long, default_value = "", value_parser = valid_id)] pub id: String, - pub host_dev_name: String, + #[arg(long)] + pub netdev: String, + #[arg(long)] + pub bus: Option, + #[arg(long, value_parser = get_pci_df)] + pub addr: Option<(u8, u8)>, + #[arg(long, value_parser = parse_bool, action = ArgAction::Append)] + pub multifunction: Option, + #[arg(long, value_parser = valid_mac)] pub mac: Option, - pub tap_fds: Option>, - pub vhost_type: Option, - pub vhost_fds: Option>, + #[arg(long)] pub iothread: Option, - pub queues: u16, + #[arg(long, default_value="off", value_parser = parse_bool, action = ArgAction::Append)] pub mq: bool, - pub socket_path: Option, - /// All queues of a net device have the same queue size now. + // All queues of a net device have the same queue size now. + #[arg(long, default_value = "256", alias = "queue-size", value_parser = valid_network_queue_size)] pub queue_size: u16, + // MSI-X vectors the this network device has. This member isn't used now in stratovirt. + #[arg(long, default_value = "0")] + pub vectors: u16, } impl Default for NetworkInterfaceConfig { fn default() -> Self { NetworkInterfaceConfig { + classtype: "".to_string(), id: "".to_string(), - host_dev_name: "".to_string(), + netdev: "".to_string(), + bus: None, + addr: None, + multifunction: None, mac: None, - tap_fds: None, - vhost_type: None, - vhost_fds: None, iothread: None, - queues: 2, mq: false, - socket_path: None, queue_size: DEFAULT_VIRTQUEUE_SIZE, + vectors: 0, } } } +fn valid_network_queue_size(s: &str) -> Result { + let size: u64 = s.parse()?; + valid_virtqueue_size(size, DEFAULT_VIRTQUEUE_SIZE as u64, MAX_QUEUE_SIZE_NET)?; + + Ok(size as u16) +} + impl ConfigCheck for NetworkInterfaceConfig { fn check(&self) -> Result<()> { - check_arg_too_long(&self.id, "id")?; - check_arg_too_long(&self.host_dev_name, "host dev name")?; - if self.mac.is_some() && !check_mac_address(self.mac.as_ref().unwrap()) { return Err(anyhow!(ConfigError::MacFormatError)); } - if self.iothread.is_some() { - check_arg_too_long(self.iothread.as_ref().unwrap(), "iothread name")?; - } - - if self.socket_path.is_some() && self.socket_path.as_ref().unwrap().len() > MAX_PATH_LENGTH - { - return Err(anyhow!(ConfigError::StringLengthTooLong( - "socket path".to_string(), - MAX_PATH_LENGTH - ))); - } - - if self.queue_size < DEFAULT_VIRTQUEUE_SIZE || self.queue_size > MAX_QUEUE_SIZE_NET { - return Err(anyhow!(ConfigError::IllegalValue( - "queue size of net device".to_string(), - DEFAULT_VIRTQUEUE_SIZE as u64, - true, - MAX_QUEUE_SIZE_NET as u64, - true - ))); - } - - if self.queue_size & (self.queue_size - 1) != 0 { - bail!("queue size of net device should be power of 2!"); - } + valid_network_queue_size(&self.queue_size.to_string())?; Ok(()) } } -pub fn parse_net(vm_config: &mut VmConfig, net_config: &str) -> Result { - let mut cmd_parser = CmdParser::new("virtio-net"); - cmd_parser - .push("") - .push("id") - .push("netdev") - .push("mq") - .push("vectors") - .push("bus") - .push("addr") - .push("multifunction") - .push("mac") - .push("iothread") - .push("queue-size"); - - cmd_parser.parse(net_config)?; - pci_args_check(&cmd_parser)?; - let mut netdevinterfacecfg = NetworkInterfaceConfig::default(); - - let netdev = cmd_parser - .get_value::("netdev")? - .with_context(|| ConfigError::FieldIsMissing("netdev".to_string(), "net".to_string()))?; - let netid = cmd_parser.get_value::("id")?.unwrap_or_default(); - - if let Some(mq) = cmd_parser.get_value::("mq")? { - netdevinterfacecfg.mq = mq.inner; - } - netdevinterfacecfg.iothread = cmd_parser.get_value::("iothread")?; - netdevinterfacecfg.mac = cmd_parser.get_value::("mac")?; - if let Some(queue_size) = cmd_parser.get_value::("queue-size")? { - netdevinterfacecfg.queue_size = queue_size; - } - - let netcfg = &vm_config - .netdevs - .remove(&netdev) - .with_context(|| format!("Netdev: {:?} not found for net device", &netdev))?; - netdevinterfacecfg.id = netid; - netdevinterfacecfg.host_dev_name = netcfg.ifname.clone(); - netdevinterfacecfg.tap_fds = netcfg.tap_fds.clone(); - netdevinterfacecfg.vhost_fds = netcfg.vhost_fds.clone(); - netdevinterfacecfg.vhost_type = netcfg.vhost_type(); - netdevinterfacecfg.queues = netcfg.queues; - if let Some(chardev) = &netcfg.chardev { - let char_dev = vm_config - .chardev - .remove(chardev) - .with_context(|| format!("Chardev: {:?} not found for character device", chardev))?; - netdevinterfacecfg.socket_path = Some(get_chardev_socket_path(char_dev)?); - } - - netdevinterfacecfg.check()?; - Ok(netdevinterfacecfg) -} - fn get_netdev_fd(fd_name: &str) -> Result { if let Some(fd) = QmpChannel::get_fd(fd_name) { Ok(fd) @@ -381,6 +315,13 @@ impl VmConfig { } } +fn valid_mac(mac: &str) -> Result { + if !check_mac_address(mac) { + return Err(anyhow!(ConfigError::MacFormatError)); + } + Ok(mac.to_string()) +} + fn check_mac_address(mac: &str) -> bool { if mac.len() != MAC_ADDRESS_LENGTH { return false; @@ -427,169 +368,119 @@ fn is_netdev_queues_valid(queues: u16) -> Result<()> { #[cfg(test)] mod tests { use super::*; - use crate::config::get_pci_bdf; #[test] - fn test_network_config_cmdline_parser() { + fn test_netdev_config_cmdline_parser() { let mut vm_config = VmConfig::default(); + + // Test1: Right. assert!(vm_config.add_netdev("tap,id=eth0,ifname=tap0").is_ok()); - let net_cfg_res = parse_net( - &mut vm_config, - "virtio-net-device,id=net0,netdev=eth0,iothread=iothread0", - ); - assert!(net_cfg_res.is_ok()); - let network_configs = net_cfg_res.unwrap(); - assert_eq!(network_configs.id, "net0"); - assert_eq!(network_configs.host_dev_name, "tap0"); - assert_eq!(network_configs.iothread, Some("iothread0".to_string())); - assert!(network_configs.mac.is_none()); - assert!(network_configs.tap_fds.is_none()); - assert!(network_configs.vhost_type.is_none()); - assert!(network_configs.vhost_fds.is_none()); + assert!(vm_config.add_netdev("tap,id=eth0,ifname=tap0").is_err()); + let netdev_cfg = vm_config.netdevs.get("eth0").unwrap(); + assert_eq!(netdev_cfg.id, "eth0"); + assert_eq!(netdev_cfg.ifname, "tap0"); + assert!(netdev_cfg.tap_fds.is_none()); + assert_eq!(netdev_cfg.vhost_kernel, false); + assert!(netdev_cfg.vhost_fds.is_none()); + assert_eq!(netdev_cfg.queues, 2); + assert!(netdev_cfg.vhost_type().is_none()); - let mut vm_config = VmConfig::default(); assert!(vm_config .add_netdev("tap,id=eth1,ifname=tap1,vhost=on,vhostfd=4") .is_ok()); - let net_cfg_res = parse_net( - &mut vm_config, - "virtio-net-device,id=net1,netdev=eth1,mac=12:34:56:78:9A:BC", - ); - assert!(net_cfg_res.is_ok()); - let network_configs = net_cfg_res.unwrap(); - assert_eq!(network_configs.id, "net1"); - assert_eq!(network_configs.host_dev_name, "tap1"); - assert_eq!(network_configs.mac, Some(String::from("12:34:56:78:9A:BC"))); - assert!(network_configs.tap_fds.is_none()); - assert_eq!( - network_configs.vhost_type, - Some(String::from("vhost-kernel")) - ); - assert_eq!(network_configs.vhost_fds, Some(vec![4])); + let netdev_cfg = vm_config.netdevs.get("eth1").unwrap(); + assert_eq!(netdev_cfg.ifname, "tap1"); + assert_eq!(netdev_cfg.vhost_type().unwrap(), "vhost-kernel"); + assert_eq!(netdev_cfg.vhost_fds, Some(vec![4])); - let mut vm_config = VmConfig::default(); - assert!(vm_config.add_netdev("tap,id=eth1,fd=35").is_ok()); - let net_cfg_res = parse_net(&mut vm_config, "virtio-net-device,id=net1,netdev=eth1"); - assert!(net_cfg_res.is_ok()); - let network_configs = net_cfg_res.unwrap(); - assert_eq!(network_configs.id, "net1"); - assert_eq!(network_configs.host_dev_name, ""); - assert_eq!(network_configs.tap_fds, Some(vec![35])); + assert!(vm_config.add_netdev("tap,id=eth2,fd=35").is_ok()); + let netdev_cfg = vm_config.netdevs.get("eth2").unwrap(); + assert_eq!(netdev_cfg.tap_fds, Some(vec![35])); - let mut vm_config = VmConfig::default(); assert!(vm_config - .add_netdev("tap,id=eth1,ifname=tap1,vhost=on,vhostfd=4") + .add_netdev("tap,id=eth3,ifname=tap0,queues=4") .is_ok()); - let net_cfg_res = parse_net( - &mut vm_config, - "virtio-net-device,id=net1,netdev=eth2,mac=12:34:56:78:9A:BC", - ); - assert!(net_cfg_res.is_err()); + let netdev_cfg = vm_config.netdevs.get("eth3").unwrap(); + assert_eq!(netdev_cfg.queues, 8); - let mut vm_config = VmConfig::default(); - assert!(vm_config.add_netdev("tap,id=eth1,fd=35").is_ok()); - let net_cfg_res = parse_net(&mut vm_config, "virtio-net-device,id=net1,netdev=eth3"); - assert!(net_cfg_res.is_err()); - - // multi queue testcases - let mut vm_config = VmConfig::default(); assert!(vm_config - .add_netdev("tap,id=eth0,ifname=tap0,queues=4") + .add_netdev("tap,id=eth4,fds=34:35:36:37:38") .is_ok()); - let net_cfg_res = parse_net( - &mut vm_config, - "virtio-net-device,id=net0,netdev=eth0,iothread=iothread0,mq=on,vectors=6", - ); - assert!(net_cfg_res.is_ok()); - let network_configs = net_cfg_res.unwrap(); - assert_eq!(network_configs.queues, 8); - assert_eq!(network_configs.mq, true); + let netdev_cfg = vm_config.netdevs.get("eth4").unwrap(); + assert_eq!(netdev_cfg.queues, 10); + assert_eq!(netdev_cfg.tap_fds, Some(vec![34, 35, 36, 37, 38])); - let mut vm_config = VmConfig::default(); assert!(vm_config - .add_netdev("tap,id=eth0,fds=34:35:36:37:38") + .add_netdev("tap,id=eth5,fds=34:35:36:37:38,vhost=on,vhostfds=39:40:41:42:43") .is_ok()); - let net_cfg_res = parse_net( - &mut vm_config, - "virtio-net-device,id=net0,netdev=eth0,iothread=iothread0,mq=off,vectors=12", - ); - assert!(net_cfg_res.is_ok()); - let network_configs = net_cfg_res.unwrap(); - assert_eq!(network_configs.queues, 10); - assert_eq!(network_configs.tap_fds, Some(vec![34, 35, 36, 37, 38])); - assert_eq!(network_configs.mq, false); + let netdev_cfg = vm_config.netdevs.get("eth5").unwrap(); + assert_eq!(netdev_cfg.queues, 10); + assert_eq!(netdev_cfg.vhost_fds, Some(vec![39, 40, 41, 42, 43])); - let mut vm_config = VmConfig::default(); + // Test2: Missing values assert!(vm_config - .add_netdev("tap,id=eth0,fds=34:35:36:37:38,vhost=on,vhostfds=39:40:41:42:43") - .is_ok()); - let net_cfg_res = parse_net( - &mut vm_config, - "virtio-net-device,id=net0,netdev=eth0,iothread=iothread0,mq=off,vectors=12", - ); - assert!(net_cfg_res.is_ok()); - let network_configs = net_cfg_res.unwrap(); - assert_eq!(network_configs.queues, 10); - assert_eq!(network_configs.vhost_fds, Some(vec![39, 40, 41, 42, 43])); - assert_eq!(network_configs.mq, false); + .add_netdev("tap,fds=34:35:36:37:38,vhost=on") + .is_err()); + + // Test3: Illegal values. + assert!(vm_config + .add_netdev("tap,id=eth10,fds=34:35:36:37:38,vhost=on,vhostfds=39,40,41,42,43") + .is_err()); + assert!(vm_config.add_netdev("tap,id=eth10,queues=0").is_err()); + assert!(vm_config.add_netdev("tap,id=eth10,queues=17").is_err()); } #[test] - fn test_pci_network_config_cmdline_parser() { + fn test_networkinterface_config_cmdline_parser() { + // Test1: Right. let mut vm_config = VmConfig::default(); - assert!(vm_config .add_netdev("tap,id=eth1,ifname=tap1,vhost=on,vhostfd=4") .is_ok()); + let net_cmd = + "virtio-net-pci,id=net1,netdev=eth1,bus=pcie.0,addr=0x1.0x2,mac=12:34:56:78:9A:BC,mq=on,vectors=6,queue-size=2048,multifunction=on"; let net_cfg = - "virtio-net-pci,id=net1,netdev=eth1,bus=pcie.0,addr=0x1.0x2,mac=12:34:56:78:9A:BC"; - let net_cfg_res = parse_net(&mut vm_config, net_cfg); - assert!(net_cfg_res.is_ok()); - let network_configs = net_cfg_res.unwrap(); - assert_eq!(network_configs.id, "net1"); - assert_eq!(network_configs.host_dev_name, "tap1"); - assert_eq!(network_configs.mac, Some(String::from("12:34:56:78:9A:BC"))); - assert!(network_configs.tap_fds.is_none()); - assert_eq!( - network_configs.vhost_type, - Some(String::from("vhost-kernel")) - ); - assert_eq!(network_configs.vhost_fds.unwrap()[0], 4); - let pci_bdf = get_pci_bdf(net_cfg); - assert!(pci_bdf.is_ok()); - let pci = pci_bdf.unwrap(); - assert_eq!(pci.bus, "pcie.0".to_string()); - assert_eq!(pci.addr, (1, 2)); - - let net_cfg_res = parse_net(&mut vm_config, net_cfg); - assert!(net_cfg_res.is_err()); - + NetworkInterfaceConfig::try_parse_from(str_slip_to_clap(net_cmd, true, false)).unwrap(); + assert_eq!(net_cfg.id, "net1"); + assert_eq!(net_cfg.netdev, "eth1"); + assert_eq!(net_cfg.bus.unwrap(), "pcie.0"); + assert_eq!(net_cfg.addr.unwrap(), (1, 2)); + assert_eq!(net_cfg.mac.unwrap(), "12:34:56:78:9A:BC"); + assert_eq!(net_cfg.vectors, 6); + assert_eq!(net_cfg.mq, true); + assert_eq!(net_cfg.queue_size, 2048); + assert_eq!(net_cfg.multifunction, Some(true)); + let netdev_cfg = vm_config.netdevs.get(&net_cfg.netdev).unwrap(); + assert_eq!(netdev_cfg.vhost_type().unwrap(), "vhost-kernel"); + + // Test2: Default values. let mut vm_config = VmConfig::default(); - assert!(vm_config - .add_netdev("tap,id=eth1,ifname=tap1,vhost=on,vhostfd=4") - .is_ok()); - let net_cfg = - "virtio-net-pci,id=net1,netdev=eth1,bus=pcie.0,addr=0x1.0x2,mac=12:34:56:78:9A:BC,multifunction=on"; - assert!(parse_net(&mut vm_config, net_cfg).is_ok()); - - // For vhost-user net assert!(vm_config.add_netdev("vhost-user,id=netdevid").is_ok()); - let net_cfg = + let net_cmd = "virtio-net-pci,id=netid,netdev=netdevid,bus=pcie.0,addr=0x2.0x0,mac=12:34:56:78:9A:BC"; - let net_cfg_res = parse_net(&mut vm_config, net_cfg); - assert!(net_cfg_res.is_ok()); - let network_configs = net_cfg_res.unwrap(); - assert_eq!(network_configs.id, "netid"); - assert_eq!(network_configs.vhost_type, Some("vhost-user".to_string())); - assert_eq!(network_configs.mac, Some("12:34:56:78:9A:BC".to_string())); - - assert!(vm_config - .add_netdev("vhost-user,id=netdevid2,chardev=chardevid2") - .is_ok()); let net_cfg = - "virtio-net-pci,id=netid2,netdev=netdevid2,bus=pcie.0,addr=0x2.0x0,mac=12:34:56:78:9A:BC"; - let net_cfg_res = parse_net(&mut vm_config, net_cfg); - assert!(net_cfg_res.is_err()); + NetworkInterfaceConfig::try_parse_from(str_slip_to_clap(net_cmd, true, false)).unwrap(); + assert_eq!(net_cfg.queue_size, 256); + assert_eq!(net_cfg.mq, false); + assert_eq!(net_cfg.vectors, 0); + let netdev_cfg = vm_config.netdevs.get(&net_cfg.netdev).unwrap(); + assert_eq!(netdev_cfg.vhost_type().unwrap(), "vhost-user"); + + // Test3: Missing Parameters. + let net_cmd = "virtio-net-pci,id=netid"; + let result = NetworkInterfaceConfig::try_parse_from(str_slip_to_clap(net_cmd, true, false)); + assert!(result.is_err()); + + // Test4: Illegal Parameters. + let net_cmd = "virtio-net-pci,id=netid,netdev=netdevid,mac=1:1:1"; + let result = NetworkInterfaceConfig::try_parse_from(str_slip_to_clap(net_cmd, true, false)); + assert!(result.is_err()); + let net_cmd = "virtio-net-pci,id=netid,netdev=netdevid,queue-size=128"; + let result = NetworkInterfaceConfig::try_parse_from(str_slip_to_clap(net_cmd, true, false)); + assert!(result.is_err()); + let net_cmd = "virtio-net-pci,id=netid,netdev=netdevid,queue-size=10240"; + let result = NetworkInterfaceConfig::try_parse_from(str_slip_to_clap(net_cmd, true, false)); + assert!(result.is_err()); } #[test] diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index 48b19cc4..1691dc06 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -46,7 +46,7 @@ use crate::{ use address_space::{AddressSpace, RegionCache}; use machine_manager::event_loop::{register_event_helper, unregister_event_helper}; use machine_manager::{ - config::{ConfigCheck, NetworkInterfaceConfig}, + config::{ConfigCheck, NetDevcfg, NetworkInterfaceConfig}, event_loop::EventLoop, }; use migration::{ @@ -1190,6 +1190,8 @@ pub struct Net { base: VirtioBase, /// Configuration of the network device. net_cfg: NetworkInterfaceConfig, + /// Configuration of the network device. + netdev_cfg: NetDevcfg, /// Virtio net configurations. config_space: Arc>, /// Tap device opened. @@ -1203,9 +1205,9 @@ pub struct Net { } impl Net { - pub fn new(net_cfg: NetworkInterfaceConfig) -> Self { + pub fn new(net_cfg: NetworkInterfaceConfig, netdev_cfg: NetDevcfg) -> Self { let queue_num = if net_cfg.mq { - (net_cfg.queues + 1) as usize + (netdev_cfg.queues + 1) as usize } else { QUEUE_NUM_NET }; @@ -1214,6 +1216,7 @@ impl Net { Self { base: VirtioBase::new(VIRTIO_TYPE_NET, queue_num, queue_size), net_cfg, + netdev_cfg, ..Default::default() } } @@ -1397,11 +1400,11 @@ impl VirtioDevice for Net { ); } - let queue_pairs = self.net_cfg.queues / 2; - if !self.net_cfg.host_dev_name.is_empty() { - self.taps = create_tap(None, Some(&self.net_cfg.host_dev_name), queue_pairs) + let queue_pairs = self.netdev_cfg.queues / 2; + if !self.netdev_cfg.ifname.is_empty() { + self.taps = create_tap(None, Some(&self.netdev_cfg.ifname), queue_pairs) .with_context(|| "Failed to open tap with file path")?; - } else if let Some(fds) = self.net_cfg.tap_fds.as_mut() { + } else if let Some(fds) = self.netdev_cfg.tap_fds.as_mut() { let mut created_fds = 0; if let Some(taps) = &self.taps { for (index, tap) in taps.iter().enumerate() { @@ -1444,7 +1447,7 @@ impl VirtioDevice for Net { let mut locked_config = self.config_space.lock().unwrap(); - let queue_pairs = self.net_cfg.queues / 2; + let queue_pairs = self.netdev_cfg.queues / 2; if self.net_cfg.mq && (VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN..=VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX) .contains(&queue_pairs) @@ -1596,9 +1599,15 @@ impl VirtioDevice for Net { Ok(()) } + // configs[0]: NetDevcfg. configs[1]: NetworkInterfaceConfig. fn update_config(&mut self, dev_config: Vec>) -> Result<()> { if !dev_config.is_empty() { - self.net_cfg = dev_config[0] + self.netdev_cfg = dev_config[0] + .as_any() + .downcast_ref::() + .unwrap() + .clone(); + self.net_cfg = dev_config[1] .as_any() .downcast_ref::() .unwrap() @@ -1703,16 +1712,16 @@ mod tests { #[test] fn test_net_init() { // test net new method - let mut net = Net::new(NetworkInterfaceConfig::default()); + let mut net = Net::new(NetworkInterfaceConfig::default(), NetDevcfg::default()); assert_eq!(net.base.device_features, 0); assert_eq!(net.base.driver_features, 0); assert_eq!(net.taps.is_none(), true); assert_eq!(net.senders.is_none(), true); assert_eq!(net.net_cfg.mac.is_none(), true); - assert_eq!(net.net_cfg.tap_fds.is_none(), true); - assert_eq!(net.net_cfg.vhost_type.is_none(), true); - assert_eq!(net.net_cfg.vhost_fds.is_none(), true); + assert_eq!(net.netdev_cfg.tap_fds.is_none(), true); + assert!(net.netdev_cfg.vhost_type().is_none()); + assert_eq!(net.netdev_cfg.vhost_fds.is_none(), true); // test net realize method net.realize().unwrap(); @@ -1864,7 +1873,7 @@ mod tests { #[test] fn test_iothread() { - let mut net = Net::new(NetworkInterfaceConfig::default()); + let mut net = Net::new(NetworkInterfaceConfig::default(), NetDevcfg::default()); net.net_cfg.iothread = Some("iothread".to_string()); if let Err(err) = net.realize() { let err_msg = format!( diff --git a/virtio/src/vhost/kernel/net.rs b/virtio/src/vhost/kernel/net.rs index 55a49724..8a4f6c02 100644 --- a/virtio/src/vhost/kernel/net.rs +++ b/virtio/src/vhost/kernel/net.rs @@ -31,7 +31,7 @@ use crate::{ VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_MQ, VIRTIO_TYPE_NET, }; use address_space::AddressSpace; -use machine_manager::config::NetworkInterfaceConfig; +use machine_manager::config::{NetDevcfg, NetworkInterfaceConfig}; use machine_manager::event_loop::{register_event_helper, unregister_event_helper}; use util::byte_code::ByteCode; use util::loop_context::EventNotifierHelper; @@ -79,6 +79,8 @@ pub struct Net { base: VirtioBase, /// Configuration of the network device. net_cfg: NetworkInterfaceConfig, + /// Configuration of the backend netdev. + netdev_cfg: NetDevcfg, /// Virtio net configurations. config_space: Arc>, /// Tap device opened. @@ -94,17 +96,22 @@ pub struct Net { } impl Net { - pub fn new(cfg: &NetworkInterfaceConfig, mem_space: &Arc) -> Self { - let queue_num = if cfg.mq { - (cfg.queues + 1) as usize + pub fn new( + net_cfg: &NetworkInterfaceConfig, + netdev_cfg: NetDevcfg, + mem_space: &Arc, + ) -> Self { + let queue_num = if net_cfg.mq { + (netdev_cfg.queues + 1) as usize } else { QUEUE_NUM_NET }; - let queue_size = cfg.queue_size; + let queue_size = net_cfg.queue_size; Net { base: VirtioBase::new(VIRTIO_TYPE_NET, queue_num, queue_size), - net_cfg: cfg.clone(), + net_cfg: net_cfg.clone(), + netdev_cfg, config_space: Default::default(), taps: None, backends: None, @@ -125,10 +132,10 @@ impl VirtioDevice for Net { } fn realize(&mut self) -> Result<()> { - let queue_pairs = self.net_cfg.queues / 2; + let queue_pairs = self.netdev_cfg.queues / 2; let mut backends = Vec::with_capacity(queue_pairs as usize); for index in 0..queue_pairs { - let fd = if let Some(fds) = self.net_cfg.vhost_fds.as_mut() { + let fd = if let Some(fds) = self.netdev_cfg.vhost_fds.as_mut() { fds.get(index as usize).copied() } else { None @@ -142,12 +149,12 @@ impl VirtioDevice for Net { backends.push(backend); } - let host_dev_name = match self.net_cfg.host_dev_name.as_str() { + let host_dev_name = match self.netdev_cfg.ifname.as_str() { "" => None, - _ => Some(self.net_cfg.host_dev_name.as_str()), + _ => Some(self.netdev_cfg.ifname.as_str()), }; - self.taps = create_tap(self.net_cfg.tap_fds.as_ref(), host_dev_name, queue_pairs) + self.taps = create_tap(self.netdev_cfg.tap_fds.as_ref(), host_dev_name, queue_pairs) .with_context(|| "Failed to create tap for vhost net")?; self.backends = Some(backends); @@ -174,7 +181,7 @@ impl VirtioDevice for Net { let mut locked_config = self.config_space.lock().unwrap(); - let queue_pairs = self.net_cfg.queues / 2; + let queue_pairs = self.netdev_cfg.queues / 2; if self.net_cfg.mq && (VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN..=VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX) .contains(&queue_pairs) @@ -385,7 +392,7 @@ impl VirtioDevice for Net { } fn reset(&mut self) -> Result<()> { - let queue_pairs = self.net_cfg.queues / 2; + let queue_pairs = self.netdev_cfg.queues / 2; for index in 0..queue_pairs as usize { let backend = match &self.backends { None => return Err(anyhow!("Failed to get backend for vhost net")), @@ -441,46 +448,43 @@ mod tests { #[test] fn test_vhost_net_realize() { - let net1 = NetworkInterfaceConfig { - id: "eth1".to_string(), - host_dev_name: "tap1".to_string(), - mac: Some("1F:2C:3E:4A:5B:6D".to_string()), - vhost_type: Some("vhost-kernel".to_string()), + let netdev_cfg1 = NetDevcfg { + netdev_type: "tap".to_string(), + id: "net1".to_string(), tap_fds: Some(vec![4]), + vhost_kernel: true, vhost_fds: Some(vec![5]), - iothread: None, + ifname: "tap1".to_string(), queues: 2, + ..Default::default() + }; + let vhost_net_conf = NetworkInterfaceConfig { + id: "eth1".to_string(), + mac: Some("1F:2C:3E:4A:5B:6D".to_string()), + iothread: None, mq: false, - socket_path: None, queue_size: DEFAULT_VIRTQUEUE_SIZE, + ..Default::default() }; - let conf = vec![net1]; - let confs = Some(conf); - let vhost_net_confs = confs.unwrap(); - let vhost_net_conf = vhost_net_confs[0].clone(); let vhost_net_space = vhost_address_space_init(); - let mut vhost_net = Net::new(&vhost_net_conf, &vhost_net_space); + let mut vhost_net = Net::new(&vhost_net_conf, netdev_cfg1, &vhost_net_space); // the tap_fd and vhost_fd attribute of vhost-net can't be assigned. - assert_eq!(vhost_net.realize().is_ok(), false); + assert!(vhost_net.realize().is_err()); - let net1 = NetworkInterfaceConfig { - id: "eth0".to_string(), - host_dev_name: "".to_string(), - mac: Some("1A:2B:3C:4D:5E:6F".to_string()), - vhost_type: Some("vhost-kernel".to_string()), - tap_fds: None, - vhost_fds: None, - iothread: None, + let netdev_cfg2 = NetDevcfg { + netdev_type: "tap".to_string(), + id: "net2".to_string(), + vhost_kernel: true, queues: 2, - mq: false, - socket_path: None, + ..Default::default() + }; + let net_cfg2 = NetworkInterfaceConfig { + id: "eth2".to_string(), + mac: Some("1A:2B:3C:4D:5E:6F".to_string()), queue_size: DEFAULT_VIRTQUEUE_SIZE, + ..Default::default() }; - let conf = vec![net1]; - let confs = Some(conf); - let vhost_net_confs = confs.unwrap(); - let vhost_net_conf = vhost_net_confs[0].clone(); - let mut vhost_net = Net::new(&vhost_net_conf, &vhost_net_space); + let mut vhost_net = Net::new(&net_cfg2, netdev_cfg2, &vhost_net_space); // if fail to open vhost-net device, no need to continue. if let Err(_e) = File::open("/dev/vhost-net") { diff --git a/virtio/src/vhost/user/net.rs b/virtio/src/vhost/user/net.rs index e7f0964b..4dc76345 100644 --- a/virtio/src/vhost/user/net.rs +++ b/virtio/src/vhost/user/net.rs @@ -28,7 +28,7 @@ use crate::{ VIRTIO_NET_F_MRG_RXBUF, VIRTIO_TYPE_NET, }; use address_space::AddressSpace; -use machine_manager::config::NetworkInterfaceConfig; +use machine_manager::config::{NetDevcfg, NetworkInterfaceConfig}; use machine_manager::event_loop::{register_event_helper, unregister_event_helper}; use util::byte_code::ByteCode; use util::loop_context::EventNotifierHelper; @@ -42,6 +42,10 @@ pub struct Net { base: VirtioBase, /// Configuration of the vhost user network device. net_cfg: NetworkInterfaceConfig, + /// Configuration of the backend netdev. + netdev_cfg: NetDevcfg, + /// path of the socket chardev. + sock_path: String, /// Virtio net configurations. config_space: Arc>, /// System address space. @@ -53,18 +57,25 @@ pub struct Net { } impl Net { - pub fn new(cfg: &NetworkInterfaceConfig, mem_space: &Arc) -> Self { - let queue_num = if cfg.mq { + pub fn new( + net_cfg: &NetworkInterfaceConfig, + netdev_cfg: NetDevcfg, + sock_path: String, + mem_space: &Arc, + ) -> Self { + let queue_num = if net_cfg.mq { // If support multi-queue, it should add 1 control queue. - (cfg.queues + 1) as usize + (netdev_cfg.queues + 1) as usize } else { QUEUE_NUM_NET }; - let queue_size = cfg.queue_size; + let queue_size = net_cfg.queue_size; Net { base: VirtioBase::new(VIRTIO_TYPE_NET, queue_num, queue_size), - net_cfg: cfg.clone(), + net_cfg: net_cfg.clone(), + netdev_cfg, + sock_path, config_space: Default::default(), mem_space: mem_space.clone(), client: None, @@ -115,14 +126,9 @@ impl VirtioDevice for Net { } fn realize(&mut self) -> Result<()> { - let socket_path = self - .net_cfg - .socket_path - .as_ref() - .with_context(|| "vhost-user: socket path is not found")?; let client = VhostUserClient::new( &self.mem_space, - socket_path, + &self.sock_path, self.queue_num() as u64, VhostBackendType::TypeNet, ) @@ -158,7 +164,7 @@ impl VirtioDevice for Net { let mut locked_config = self.config_space.lock().unwrap(); - let queue_pairs = self.net_cfg.queues / 2; + let queue_pairs = self.netdev_cfg.queues / 2; if self.net_cfg.mq && (VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN..=VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX) .contains(&queue_pairs) -- Gitee From 7a9d5a35b4a5762ce68f4b346f6bd0d706c87145 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Mon, 22 Apr 2024 03:20:07 +0800 Subject: [PATCH 032/489] virtio-serial: use clap to parse the parameters of the virtio-serial/virtserialport/virtconsole config Use clap to parse the parameters of the virtio-serial/virtserialport/virtconsole config. Signed-off-by: liuxiangdong --- machine/src/lib.rs | 54 +++-- machine_manager/src/config/chardev.rs | 283 ++++++++++---------------- virtio/src/device/serial.rs | 36 ++-- 3 files changed, 164 insertions(+), 209 deletions(-) diff --git a/machine/src/lib.rs b/machine/src/lib.rs index eaafa909..5888f684 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -74,10 +74,10 @@ use hypervisor::{kvm::KvmHypervisor, test::TestHypervisor, HypervisorOps}; use machine_manager::config::get_cameradev_by_id; use machine_manager::config::{ complete_numa_node, get_chardev_socket_path, get_multi_function, get_pci_bdf, parse_device_id, - parse_device_type, parse_numa_distance, parse_numa_mem, parse_virtio_serial, - parse_virtserialport, parse_vsock, str_slip_to_clap, BootIndexInfo, BootSource, DriveConfig, - DriveFile, Incoming, MachineMemConfig, MigrateMode, NetworkInterfaceConfig, NumaConfig, - NumaDistance, NumaNode, NumaNodes, PciBdf, SerialConfig, VmConfig, FAST_UNPLUG_ON, + parse_device_type, parse_numa_distance, parse_numa_mem, parse_vsock, str_slip_to_clap, + BootIndexInfo, BootSource, ConfigCheck, DriveConfig, DriveFile, Incoming, MachineMemConfig, + MigrateMode, NetworkInterfaceConfig, NumaConfig, NumaDistance, NumaNode, NumaNodes, PciBdf, + SerialConfig, VirtioSerialInfo, VirtioSerialPortCfg, VmConfig, FAST_UNPLUG_ON, MAX_VIRTIO_QUEUE, }; use machine_manager::event_loop::EventLoop; @@ -694,11 +694,17 @@ pub trait MachineOps { /// * `vm_config` - VM configuration. /// * `cfg_args` - Device configuration args. fn add_virtio_serial(&mut self, vm_config: &mut VmConfig, cfg_args: &str) -> Result<()> { - let serial_cfg = parse_virtio_serial(vm_config, cfg_args)?; + if vm_config.virtio_serial.is_some() { + bail!("Only one virtio serial device is supported"); + } + let mut serial_cfg = + VirtioSerialInfo::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + serial_cfg.auto_max_ports(); + serial_cfg.check()?; let sys_mem = self.get_sys_mem().clone(); let serial = Arc::new(Mutex::new(Serial::new(serial_cfg.clone()))); - match parse_device_type(cfg_args)?.as_str() { + match serial_cfg.classtype.as_str() { "virtio-serial-device" => { let device = VirtioMmioDevice::new(&sys_mem, serial.clone()); MigrationManager::register_device_instance( @@ -709,8 +715,8 @@ pub trait MachineOps { ); } _ => { - let bdf = serial_cfg.pci_bdf.unwrap(); - let multi_func = serial_cfg.multifunction; + let bdf = PciBdf::new(serial_cfg.bus.clone().unwrap(), serial_cfg.addr.unwrap()); + let multi_func = serial_cfg.multifunction.unwrap_or_default(); self.add_virtio_pci_device(&serial_cfg.id, &bdf, serial.clone(), multi_func, false) .with_context(|| "Failed to add virtio pci serial device")?; } @@ -722,6 +728,7 @@ pub trait MachineOps { &serial_cfg.id, ); + vm_config.virtio_serial = Some(serial_cfg); Ok(()) } @@ -738,7 +745,7 @@ pub trait MachineOps { .with_context(|| "No virtio serial device specified")?; let mut virtio_device = None; - if serial_cfg.pci_bdf.is_none() { + if serial_cfg.bus.is_none() { // Micro_vm. for dev in self.get_sys_bus().devices.iter() { let locked_busdev = dev.lock().unwrap(); @@ -775,24 +782,31 @@ pub trait MachineOps { let mut virtio_dev_h = virtio_dev.lock().unwrap(); let serial = virtio_dev_h.as_any_mut().downcast_mut::().unwrap(); - let is_console = matches!(parse_device_type(cfg_args)?.as_str(), "virtconsole"); + let mut serialport_cfg = + VirtioSerialPortCfg::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; let free_port0 = find_port_by_nr(&serial.ports, 0).is_none(); // Note: port 0 is reserved for a virtconsole. let free_nr = get_max_nr(&serial.ports) + 1; - let serialport_cfg = - parse_virtserialport(vm_config, cfg_args, is_console, free_nr, free_port0)?; - if serialport_cfg.nr >= serial.max_nr_ports { + serialport_cfg.auto_nr(free_port0, free_nr, serial.max_nr_ports)?; + serialport_cfg.check()?; + if find_port_by_nr(&serial.ports, serialport_cfg.nr.unwrap()).is_some() { bail!( - "virtio serial port nr {} should be less than virtio serial's max_nr_ports {}", - serialport_cfg.nr, - serial.max_nr_ports + "Repetitive virtio serial port nr {}.", + serialport_cfg.nr.unwrap() ); } - if find_port_by_nr(&serial.ports, serialport_cfg.nr).is_some() { - bail!("Repetitive virtio serial port nr {}.", serialport_cfg.nr,); - } + let is_console = matches!(serialport_cfg.classtype.as_str(), "virtconsole"); + let chardev_cfg = vm_config + .chardev + .remove(&serialport_cfg.chardev) + .with_context(|| { + format!( + "Chardev {:?} not found or is in use", + &serialport_cfg.chardev + ) + })?; - let mut serial_port = SerialPort::new(serialport_cfg); + let mut serial_port = SerialPort::new(serialport_cfg, chardev_cfg); let port = Arc::new(Mutex::new(serial_port.clone())); serial_port.realize()?; if !is_console { diff --git a/machine_manager/src/config/chardev.rs b/machine_manager/src/config/chardev.rs index 68c23c6e..124a6288 100644 --- a/machine_manager/src/config/chardev.rs +++ b/machine_manager/src/config/chardev.rs @@ -18,10 +18,10 @@ use clap::{ArgAction, Parser, Subcommand}; use log::error; use serde::{Deserialize, Serialize}; -use super::{error::ConfigError, get_pci_bdf, pci_args_check, str_slip_to_clap, PciBdf}; +use super::{error::ConfigError, pci_args_check, str_slip_to_clap}; +use super::{get_pci_df, parse_bool}; use crate::config::{ - check_arg_too_long, valid_id, valid_path, valid_socket_path, CmdParser, ConfigCheck, ExBool, - VmConfig, + check_arg_too_long, valid_id, valid_path, valid_socket_path, CmdParser, ConfigCheck, VmConfig, }; use crate::qmp::qmp_schema; @@ -32,17 +32,50 @@ const MIN_GUEST_CID: u64 = 3; const DEFAULT_SERIAL_PORTS_NUMBER: u32 = 31; /// Config structure for virtio-serial-port. -#[derive(Debug, Clone)] -pub struct VirtioSerialPort { +#[derive(Parser, Debug, Clone)] +#[command(no_binary_name(true))] +pub struct VirtioSerialPortCfg { + #[arg(long, value_parser = ["virtconsole", "virtserialport"])] + pub classtype: String, + #[arg(long, value_parser = valid_id)] pub id: String, - pub chardev: ChardevConfig, - pub nr: u32, - pub is_console: bool, + #[arg(long)] + pub chardev: String, + #[arg(long)] + pub nr: Option, } -impl ConfigCheck for VirtioSerialPort { +impl ConfigCheck for VirtioSerialPortCfg { fn check(&self) -> Result<()> { - check_arg_too_long(&self.id, "chardev id") + if self.classtype != "virtconsole" && self.nr.unwrap() == 0 { + bail!("Port number 0 on virtio-serial devices reserved for virtconsole device."); + } + + Ok(()) + } +} + +impl VirtioSerialPortCfg { + /// If nr is not set in command line. Configure incremental maximum value for virtconsole. + /// Configure incremental maximum value(except 0) for virtserialport. + pub fn auto_nr(&mut self, free_port0: bool, free_nr: u32, max_nr_ports: u32) -> Result<()> { + let free_console_nr = if free_port0 { 0 } else { free_nr }; + let auto_nr = match self.classtype.as_str() { + "virtconsole" => free_console_nr, + "virtserialport" => free_nr, + _ => bail!("Invalid classtype."), + }; + let nr = self.nr.unwrap_or(auto_nr); + if nr >= max_nr_ports { + bail!( + "virtio serial port nr {} should be less than virtio serial's max_nr_ports {}", + nr, + max_nr_ports + ); + } + + self.nr = Some(nr); + Ok(()) } } @@ -221,47 +254,6 @@ pub fn get_chardev_socket_path(chardev: ChardevConfig) -> Result { bail!("Chardev {:?} backend should be unix-socket type.", id); } -pub fn parse_virtserialport( - vm_config: &mut VmConfig, - config_args: &str, - is_console: bool, - free_nr: u32, - free_port0: bool, -) -> Result { - let mut cmd_parser = CmdParser::new("virtserialport"); - cmd_parser.push("").push("id").push("chardev").push("nr"); - cmd_parser.parse(config_args)?; - - let chardev_name = cmd_parser - .get_value::("chardev")? - .with_context(|| { - ConfigError::FieldIsMissing("chardev".to_string(), "virtserialport".to_string()) - })?; - let id = cmd_parser.get_value::("id")?.with_context(|| { - ConfigError::FieldIsMissing("id".to_string(), "virtserialport".to_string()) - })?; - - let nr = cmd_parser - .get_value::("nr")? - .unwrap_or(if is_console && free_port0 { 0 } else { free_nr }); - - if nr == 0 && !is_console { - bail!("Port number 0 on virtio-serial devices reserved for virtconsole device."); - } - - if let Some(chardev) = vm_config.chardev.remove(&chardev_name) { - let port_cfg = VirtioSerialPort { - id, - chardev, - nr, - is_console, - }; - port_cfg.check()?; - return Ok(port_cfg); - } - bail!("Chardev {:?} not found or is in use", &chardev_name); -} - impl VmConfig { /// Add chardev config to `VmConfig`. pub fn add_chardev(&mut self, chardev_config: &str) -> Result<()> { @@ -388,127 +380,87 @@ pub fn parse_vsock(vsock_config: &str) -> Result { Ok(vsock) } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Parser, Clone, Debug, Serialize, Deserialize)] +#[command(no_binary_name(true))] pub struct VirtioSerialInfo { + #[arg(long, value_parser = ["virtio-serial-pci", "virtio-serial-device"])] + pub classtype: String, + #[arg(long, default_value = "", value_parser = valid_id)] pub id: String, - pub pci_bdf: Option, - pub multifunction: bool, + #[arg(long)] + pub bus: Option, + #[arg(long, value_parser = get_pci_df)] + pub addr: Option<(u8, u8)>, + #[arg(long, value_parser = parse_bool, action = ArgAction::Append)] + pub multifunction: Option, + #[arg(long, default_value = "31", value_parser = clap::value_parser!(u32).range(1..=DEFAULT_SERIAL_PORTS_NUMBER as i64))] pub max_ports: u32, } -impl ConfigCheck for VirtioSerialInfo { - fn check(&self) -> Result<()> { - check_arg_too_long(&self.id, "virtio-serial id")?; - - if self.max_ports < 1 || self.max_ports > DEFAULT_SERIAL_PORTS_NUMBER { - return Err(anyhow!(ConfigError::IllegalValue( - "Virtio-serial max_ports".to_string(), - 1, - true, - DEFAULT_SERIAL_PORTS_NUMBER as u64, - true - ))); +impl VirtioSerialInfo { + pub fn auto_max_ports(&mut self) { + if self.classtype == "virtio-serial-device" { + // Micro_vm does not support multi-ports in virtio-serial-device. + self.max_ports = 1; } - - Ok(()) } } -pub fn parse_virtio_serial( - vm_config: &mut VmConfig, - serial_config: &str, -) -> Result { - let mut cmd_parser = CmdParser::new("virtio-serial"); - cmd_parser - .push("") - .push("id") - .push("bus") - .push("addr") - .push("multifunction") - .push("max_ports"); - cmd_parser.parse(serial_config)?; - pci_args_check(&cmd_parser)?; - - if vm_config.virtio_serial.is_some() { - bail!("Only one virtio serial device is supported"); - } - - let id = cmd_parser.get_value::("id")?.unwrap_or_default(); - let multifunction = cmd_parser - .get_value::("multifunction")? - .map_or(false, |switch| switch.into()); - let max_ports = cmd_parser - .get_value::("max_ports")? - .unwrap_or(DEFAULT_SERIAL_PORTS_NUMBER); - let virtio_serial = if serial_config.contains("-pci") { - let pci_bdf = get_pci_bdf(serial_config)?; - VirtioSerialInfo { - id, - pci_bdf: Some(pci_bdf), - multifunction, - max_ports, - } - } else { - VirtioSerialInfo { - id, - pci_bdf: None, - multifunction, - // Micro_vm does not support multi-ports in virtio-serial-device. - max_ports: 1, +impl ConfigCheck for VirtioSerialInfo { + fn check(&self) -> Result<()> { + match self.classtype.as_str() { + "virtio-serial-pci" => {} + "virtio-serial-device" => { + if self.bus.is_some() || self.addr.is_some() || self.multifunction.is_some() { + bail!("virtio mmio device should not set bus/addr/multifunction"); + } + } + _ => { + bail!("Invalid classtype."); + } } - }; - virtio_serial.check()?; - vm_config.virtio_serial = Some(virtio_serial.clone()); - Ok(virtio_serial) + Ok(()) + } } #[cfg(test)] mod tests { use super::*; - use crate::config::parse_virtio_serial; fn test_mmio_console_config_cmdline_parser(chardev_cfg: &str, expected_chardev: ChardevType) { let mut vm_config = VmConfig::default(); - assert!(parse_virtio_serial(&mut vm_config, "virtio-serial-device").is_ok()); + let serial_cmd = "virtio-serial-device"; + let mut serial_cfg = + VirtioSerialInfo::try_parse_from(str_slip_to_clap(serial_cmd, true, false)).unwrap(); + serial_cfg.auto_max_ports(); + assert!(serial_cfg.check().is_ok()); + vm_config.virtio_serial = Some(serial_cfg.clone()); assert!(vm_config.add_chardev(chardev_cfg).is_ok()); - let virt_console = parse_virtserialport( - &mut vm_config, - "virtconsole,chardev=test_console,id=console1,nr=1", - true, - 0, - true, - ); - assert!(virt_console.is_ok()); - - let console_cfg = virt_console.unwrap(); - assert_eq!(console_cfg.id, "console1"); - assert_eq!(console_cfg.chardev.classtype, expected_chardev); + let port_cmd = "virtconsole,chardev=test_console,id=console1,nr=0"; + let mut port_cfg = + VirtioSerialPortCfg::try_parse_from(str_slip_to_clap(port_cmd, true, false)).unwrap(); + assert!(port_cfg.auto_nr(true, 0, serial_cfg.max_ports).is_ok()); + let chardev = vm_config.chardev.remove(&port_cfg.chardev).unwrap(); + assert_eq!(port_cfg.id, "console1"); + assert_eq!(port_cfg.nr.unwrap(), 0); + assert_eq!(chardev.classtype, expected_chardev); + + // Error: VirtioSerialPortCfg.nr >= VirtioSerialInfo.max_nr_ports. + let port_cmd = "virtconsole,chardev=test_console,id=console1,nr=1"; + let mut port_cfg = + VirtioSerialPortCfg::try_parse_from(str_slip_to_clap(port_cmd, true, false)).unwrap(); + assert!(port_cfg.auto_nr(true, 0, serial_cfg.max_ports).is_err()); let mut vm_config = VmConfig::default(); - assert!( - parse_virtio_serial(&mut vm_config, "virtio-serial-device,bus=pcie.0,addr=0x1") - .is_err() - ); + let serial_cmd = "virtio-serial-device,bus=pcie.0,addr=0x1"; + let serial_cfg = + VirtioSerialInfo::try_parse_from(str_slip_to_clap(serial_cmd, true, false)).unwrap(); + assert!(serial_cfg.check().is_err()); assert!(vm_config .add_chardev("sock,id=test_console,path=/path/to/socket") .is_err()); - - let mut vm_config = VmConfig::default(); - assert!(parse_virtio_serial(&mut vm_config, "virtio-serial-device").is_ok()); - assert!(vm_config - .add_chardev("socket,id=test_console,path=/path/to/socket,server,nowait") - .is_ok()); - let virt_console = parse_virtserialport( - &mut vm_config, - "virtconsole,chardev=test_console1,id=console1,nr=1", - true, - 0, - true, - ); - // test_console1 does not exist. - assert!(virt_console.is_err()); } #[test] @@ -541,34 +493,25 @@ mod tests { fn test_pci_console_config_cmdline_parser(chardev_cfg: &str, expected_chardev: ChardevType) { let mut vm_config = VmConfig::default(); - let virtio_arg = "virtio-serial-pci,bus=pcie.0,addr=0x1.0x2"; - assert!(parse_virtio_serial(&mut vm_config, virtio_arg).is_ok()); + let serial_cmd = "virtio-serial-pci,bus=pcie.0,addr=0x1.0x2,multifunction=on"; + let mut serial_cfg = + VirtioSerialInfo::try_parse_from(str_slip_to_clap(serial_cmd, true, false)).unwrap(); + serial_cfg.auto_max_ports(); + assert!(serial_cfg.check().is_ok()); + vm_config.virtio_serial = Some(serial_cfg.clone()); assert!(vm_config.add_chardev(chardev_cfg).is_ok()); - let virt_console = parse_virtserialport( - &mut vm_config, - "virtconsole,chardev=test_console,id=console1,nr=1", - true, - 0, - true, - ); - assert!(virt_console.is_ok()); - let console_cfg = virt_console.unwrap(); - + let console_cmd = "virtconsole,chardev=test_console,id=console1,nr=1"; + let mut console_cfg = + VirtioSerialPortCfg::try_parse_from(str_slip_to_clap(console_cmd, true, false)) + .unwrap(); + assert!(console_cfg.auto_nr(true, 0, serial_cfg.max_ports).is_ok()); + let chardev = vm_config.chardev.remove(&console_cfg.chardev).unwrap(); assert_eq!(console_cfg.id, "console1"); let serial_info = vm_config.virtio_serial.clone().unwrap(); - assert!(serial_info.pci_bdf.is_some()); - let bdf = serial_info.pci_bdf.unwrap(); - assert_eq!(bdf.bus, "pcie.0"); - assert_eq!(bdf.addr, (1, 2)); - assert_eq!(console_cfg.chardev.classtype, expected_chardev); - - let mut vm_config = VmConfig::default(); - assert!(parse_virtio_serial( - &mut vm_config, - "virtio-serial-pci,bus=pcie.0,addr=0x1.0x2,multifunction=on" - ) - .is_ok()); + assert_eq!(serial_info.bus.unwrap(), "pcie.0"); + assert_eq!(serial_info.addr.unwrap(), (1, 2)); + assert_eq!(chardev.classtype, expected_chardev); } #[test] diff --git a/virtio/src/device/serial.rs b/virtio/src/device/serial.rs index 57955619..3968821c 100644 --- a/virtio/src/device/serial.rs +++ b/virtio/src/device/serial.rs @@ -20,6 +20,7 @@ use std::{cmp, usize}; use anyhow::{anyhow, bail, Context, Result}; use byteorder::{ByteOrder, LittleEndian}; use log::{error, info, warn}; +use machine_manager::config::ChardevConfig; use vmm_sys_util::epoll::EventSet; use vmm_sys_util::eventfd::EventFd; @@ -31,7 +32,7 @@ use crate::{ use address_space::AddressSpace; use chardev_backend::chardev::{Chardev, ChardevNotifyDevice, ChardevStatus, InputReceiver}; use machine_manager::{ - config::{ChardevType, VirtioSerialInfo, VirtioSerialPort, DEFAULT_VIRTQUEUE_SIZE}, + config::{ChardevType, VirtioSerialInfo, VirtioSerialPortCfg, DEFAULT_VIRTQUEUE_SIZE}, event_loop::EventLoop, event_loop::{register_event_helper, unregister_event_helper}, }; @@ -354,20 +355,21 @@ pub struct SerialPort { } impl SerialPort { - pub fn new(port_cfg: VirtioSerialPort) -> Self { + pub fn new(port_cfg: VirtioSerialPortCfg, chardev_cfg: ChardevConfig) -> Self { // Console is default host connected. And pty chardev has opened by default in realize() // function. - let mut host_connected = port_cfg.is_console; - if let ChardevType::Pty { .. } = port_cfg.chardev.classtype { + let is_console = matches!(port_cfg.classtype.as_str(), "virtconsole"); + let mut host_connected = is_console; + if let ChardevType::Pty { .. } = chardev_cfg.classtype { host_connected = true; } SerialPort { name: Some(port_cfg.id), paused: false, - chardev: Arc::new(Mutex::new(Chardev::new(port_cfg.chardev))), - nr: port_cfg.nr, - is_console: port_cfg.is_console, + chardev: Arc::new(Mutex::new(Chardev::new(chardev_cfg))), + nr: port_cfg.nr.unwrap(), + is_console, guest_connected: false, host_connected, ctrl_handler: None, @@ -1023,18 +1025,15 @@ impl ChardevNotifyDevice for SerialPort { mod tests { pub use super::*; - use machine_manager::config::PciBdf; - #[test] fn test_set_driver_features() { let mut serial = Serial::new(VirtioSerialInfo { + classtype: "virtio-serial-pci".to_string(), id: "serial".to_string(), - pci_bdf: Some(PciBdf { - bus: "pcie.0".to_string(), - addr: (0, 0), - }), - multifunction: false, + multifunction: Some(false), max_ports: 31, + bus: Some("pcie.0".to_string()), + addr: Some((0, 0)), }); // If the device feature is 0, all driver features are not supported. @@ -1097,13 +1096,12 @@ mod tests { fn test_read_config() { let max_ports: u8 = 31; let serial = Serial::new(VirtioSerialInfo { + classtype: "virtio-serial-pci".to_string(), id: "serial".to_string(), - pci_bdf: Some(PciBdf { - bus: "pcie.0".to_string(), - addr: (0, 0), - }), - multifunction: false, + multifunction: Some(false), max_ports: max_ports as u32, + bus: Some("pcie.0".to_string()), + addr: Some((0, 0)), }); // The offset of configuration that needs to be read exceeds the maximum. -- Gitee From 4eda538128182318c6d058d9c748fd9dd8ce47e0 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Mon, 22 Apr 2024 03:56:29 +0800 Subject: [PATCH 033/489] vhost-vsock: use clap to parse the parameters of the vhost-vsock config Use clap to parse the parameters of the vhost-vsock config. Signed-off-by: liuxiangdong --- machine/src/lib.rs | 18 +++--- machine_manager/src/config/chardev.rs | 85 +-------------------------- virtio/src/vhost/kernel/mod.rs | 2 +- virtio/src/vhost/kernel/vsock.rs | 50 ++++++++++++++-- 4 files changed, 58 insertions(+), 97 deletions(-) diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 5888f684..a068fdbe 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -73,12 +73,11 @@ use hypervisor::{kvm::KvmHypervisor, test::TestHypervisor, HypervisorOps}; #[cfg(feature = "usb_camera")] use machine_manager::config::get_cameradev_by_id; use machine_manager::config::{ - complete_numa_node, get_chardev_socket_path, get_multi_function, get_pci_bdf, parse_device_id, - parse_device_type, parse_numa_distance, parse_numa_mem, parse_vsock, str_slip_to_clap, - BootIndexInfo, BootSource, ConfigCheck, DriveConfig, DriveFile, Incoming, MachineMemConfig, - MigrateMode, NetworkInterfaceConfig, NumaConfig, NumaDistance, NumaNode, NumaNodes, PciBdf, - SerialConfig, VirtioSerialInfo, VirtioSerialPortCfg, VmConfig, FAST_UNPLUG_ON, - MAX_VIRTIO_QUEUE, + complete_numa_node, get_chardev_socket_path, get_pci_bdf, parse_device_id, parse_device_type, + parse_numa_distance, parse_numa_mem, str_slip_to_clap, BootIndexInfo, BootSource, ConfigCheck, + DriveConfig, DriveFile, Incoming, MachineMemConfig, MigrateMode, NetworkInterfaceConfig, + NumaConfig, NumaDistance, NumaNode, NumaNodes, PciBdf, SerialConfig, VirtioSerialInfo, + VirtioSerialPortCfg, VmConfig, FAST_UNPLUG_ON, MAX_VIRTIO_QUEUE, }; use machine_manager::event_loop::EventLoop; use machine_manager::machine::{HypervisorType, MachineInterface, VmState}; @@ -566,7 +565,8 @@ pub trait MachineOps { /// /// * `cfg_args` - Device configuration. fn add_virtio_vsock(&mut self, cfg_args: &str) -> Result<()> { - let device_cfg = parse_vsock(cfg_args)?; + let device_cfg = + VhostKern::VsockConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; let sys_mem = self.get_sys_mem().clone(); let vsock = Arc::new(Mutex::new(VhostKern::Vsock::new(&device_cfg, &sys_mem))); match parse_device_type(cfg_args)?.as_str() { @@ -580,8 +580,8 @@ pub trait MachineOps { ); } _ => { - let bdf = get_pci_bdf(cfg_args)?; - let multi_func = get_multi_function(cfg_args)?; + let bdf = PciBdf::new(device_cfg.bus.clone().unwrap(), device_cfg.addr.unwrap()); + let multi_func = device_cfg.multifunction.unwrap_or_default(); self.add_virtio_pci_device(&device_cfg.id, &bdf, vsock.clone(), multi_func, true) .with_context(|| "Failed to add virtio pci vsock device")?; } diff --git a/machine_manager/src/config/chardev.rs b/machine_manager/src/config/chardev.rs index 124a6288..73c3033a 100644 --- a/machine_manager/src/config/chardev.rs +++ b/machine_manager/src/config/chardev.rs @@ -18,16 +18,11 @@ use clap::{ArgAction, Parser, Subcommand}; use log::error; use serde::{Deserialize, Serialize}; -use super::{error::ConfigError, pci_args_check, str_slip_to_clap}; +use super::{error::ConfigError, str_slip_to_clap}; use super::{get_pci_df, parse_bool}; -use crate::config::{ - check_arg_too_long, valid_id, valid_path, valid_socket_path, CmdParser, ConfigCheck, VmConfig, -}; +use crate::config::{valid_id, valid_path, valid_socket_path, ConfigCheck, VmConfig}; use crate::qmp::qmp_schema; -const MAX_GUEST_CID: u64 = 4_294_967_295; -const MIN_GUEST_CID: u64 = 3; - /// Default value of max ports for virtio-serial. const DEFAULT_SERIAL_PORTS_NUMBER: u32 = 31; @@ -325,61 +320,6 @@ impl VmConfig { } } -/// Config structure for virtio-vsock. -#[derive(Debug, Clone, Default, Serialize, Deserialize)] -pub struct VsockConfig { - pub id: String, - pub guest_cid: u64, - pub vhost_fd: Option, -} - -impl ConfigCheck for VsockConfig { - fn check(&self) -> Result<()> { - check_arg_too_long(&self.id, "vsock id")?; - - if self.guest_cid < MIN_GUEST_CID || self.guest_cid >= MAX_GUEST_CID { - return Err(anyhow!(ConfigError::IllegalValue( - "Vsock guest-cid".to_string(), - MIN_GUEST_CID, - true, - MAX_GUEST_CID, - false, - ))); - } - - Ok(()) - } -} - -pub fn parse_vsock(vsock_config: &str) -> Result { - let mut cmd_parser = CmdParser::new("vhost-vsock"); - cmd_parser - .push("") - .push("id") - .push("bus") - .push("addr") - .push("multifunction") - .push("guest-cid") - .push("vhostfd"); - cmd_parser.parse(vsock_config)?; - pci_args_check(&cmd_parser)?; - let id = cmd_parser - .get_value::("id")? - .with_context(|| ConfigError::FieldIsMissing("id".to_string(), "vsock".to_string()))?; - - let guest_cid = cmd_parser.get_value::("guest-cid")?.with_context(|| { - ConfigError::FieldIsMissing("guest-cid".to_string(), "vsock".to_string()) - })?; - - let vhost_fd = cmd_parser.get_value::("vhostfd")?; - let vsock = VsockConfig { - id, - guest_cid, - vhost_fd, - }; - Ok(vsock) -} - #[derive(Parser, Clone, Debug, Serialize, Deserialize)] #[command(no_binary_name(true))] pub struct VirtioSerialInfo { @@ -542,27 +482,6 @@ mod tests { test_pci_console_config_cmdline_parser(chardev_cfg, expected_chardev) } - #[test] - fn test_vsock_config_cmdline_parser() { - let vsock_cfg_op = parse_vsock("vhost-vsock-device,id=test_vsock,guest-cid=3"); - assert!(vsock_cfg_op.is_ok()); - - let vsock_config = vsock_cfg_op.unwrap(); - assert_eq!(vsock_config.id, "test_vsock"); - assert_eq!(vsock_config.guest_cid, 3); - assert_eq!(vsock_config.vhost_fd, None); - assert!(vsock_config.check().is_ok()); - - let vsock_cfg_op = parse_vsock("vhost-vsock-device,id=test_vsock,guest-cid=3,vhostfd=4"); - assert!(vsock_cfg_op.is_ok()); - - let vsock_config = vsock_cfg_op.unwrap(); - assert_eq!(vsock_config.id, "test_vsock"); - assert_eq!(vsock_config.guest_cid, 3); - assert_eq!(vsock_config.vhost_fd, Some(4)); - assert!(vsock_config.check().is_ok()); - } - #[test] fn test_chardev_config_cmdline_parser() { let check_argument = |arg: String, expect: ChardevType| { diff --git a/virtio/src/vhost/kernel/mod.rs b/virtio/src/vhost/kernel/mod.rs index 02d55cad..2111e2bb 100644 --- a/virtio/src/vhost/kernel/mod.rs +++ b/virtio/src/vhost/kernel/mod.rs @@ -14,7 +14,7 @@ mod net; mod vsock; pub use net::Net; -pub use vsock::{Vsock, VsockState}; +pub use vsock::{Vsock, VsockConfig, VsockState}; use std::fs::{File, OpenOptions}; use std::os::unix::fs::OpenOptionsExt; diff --git a/virtio/src/vhost/kernel/vsock.rs b/virtio/src/vhost/kernel/vsock.rs index 8d782c62..89bcd112 100644 --- a/virtio/src/vhost/kernel/vsock.rs +++ b/virtio/src/vhost/kernel/vsock.rs @@ -16,6 +16,7 @@ use std::sync::{Arc, Mutex}; use anyhow::{anyhow, bail, Context, Result}; use byteorder::{ByteOrder, LittleEndian}; +use clap::{ArgAction, Parser}; use vmm_sys_util::eventfd::EventFd; use vmm_sys_util::ioctl::ioctl_with_ref; @@ -26,7 +27,7 @@ use crate::{ VirtioInterruptType, VIRTIO_F_ACCESS_PLATFORM, VIRTIO_TYPE_VSOCK, }; use address_space::AddressSpace; -use machine_manager::config::{VsockConfig, DEFAULT_VIRTQUEUE_SIZE}; +use machine_manager::config::{get_pci_df, parse_bool, valid_id, DEFAULT_VIRTQUEUE_SIZE}; use machine_manager::event_loop::{register_event_helper, unregister_event_helper}; use migration::{DeviceStateDesc, FieldDesc, MigrationHook, MigrationManager, StateTransfer}; use migration_derive::{ByteCode, Desc}; @@ -40,6 +41,29 @@ const VHOST_PATH: &str = "/dev/vhost-vsock"; /// Event transport reset const VIRTIO_VSOCK_EVENT_TRANSPORT_RESET: u32 = 0; +const MAX_GUEST_CID: u64 = 4_294_967_295; +const MIN_GUEST_CID: u64 = 3; + +/// Config structure for virtio-vsock. +#[derive(Parser, Debug, Clone, Default)] +#[command(no_binary_name(true))] +pub struct VsockConfig { + #[arg(long, value_parser = ["vhost-vsock-pci", "vhost-vsock-device"])] + pub classtype: String, + #[arg(long, value_parser = valid_id)] + pub id: String, + #[arg(long)] + pub bus: Option, + #[arg(long, value_parser = get_pci_df)] + pub addr: Option<(u8, u8)>, + #[arg(long, value_parser = parse_bool, action = ArgAction::Append)] + pub multifunction: Option, + #[arg(long, alias = "guest-cid", value_parser = clap::value_parser!(u64).range(MIN_GUEST_CID..=MAX_GUEST_CID))] + pub guest_cid: u64, + #[arg(long, alias = "vhostfd")] + pub vhost_fd: Option, +} + trait VhostVsockBackend { /// Each guest should have an unique CID which is used to route data to the guest. fn set_guest_cid(&self, cid: u64) -> Result<()>; @@ -390,9 +414,9 @@ impl MigrationHook for Vsock { #[cfg(test)] mod tests { - pub use super::super::*; - pub use super::*; - pub use address_space::*; + use super::*; + use address_space::*; + use machine_manager::config::str_slip_to_clap; fn vsock_address_space_init() -> Arc { let root = Region::init_container_region(u64::max_value(), "sysmem"); @@ -405,12 +429,30 @@ mod tests { id: "test_vsock_1".to_string(), guest_cid: 3, vhost_fd: None, + ..Default::default() }; let sys_mem = vsock_address_space_init(); let vsock = Vsock::new(&vsock_conf, &sys_mem); vsock } + #[test] + fn test_vsock_config_cmdline_parser() { + let vsock_cmd = "vhost-vsock-device,id=test_vsock,guest-cid=3"; + let vsock_config = + VsockConfig::try_parse_from(str_slip_to_clap(vsock_cmd, true, false)).unwrap(); + assert_eq!(vsock_config.id, "test_vsock"); + assert_eq!(vsock_config.guest_cid, 3); + assert_eq!(vsock_config.vhost_fd, None); + + let vsock_cmd = "vhost-vsock-device,id=test_vsock,guest-cid=3,vhostfd=4"; + let vsock_config = + VsockConfig::try_parse_from(str_slip_to_clap(vsock_cmd, true, false)).unwrap(); + assert_eq!(vsock_config.id, "test_vsock"); + assert_eq!(vsock_config.guest_cid, 3); + assert_eq!(vsock_config.vhost_fd, Some(4)); + } + #[test] fn test_vsock_init() { // test vsock new method -- Gitee From 56de7c1fbed48c231a82c4e4003fa22ac15eb8bb Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Wed, 24 Apr 2024 06:23:28 +0800 Subject: [PATCH 034/489] vnc: use clap to parse the parameters of the vnc config Use clap to parse the parameters of the vnc config. Signed-off-by: liuxiangdong --- machine_manager/src/config/vnc.rs | 62 ++++++++----------------------- ui/src/vnc/mod.rs | 2 +- 2 files changed, 17 insertions(+), 47 deletions(-) diff --git a/machine_manager/src/config/vnc.rs b/machine_manager/src/config/vnc.rs index b243d945..ca1fd104 100644 --- a/machine_manager/src/config/vnc.rs +++ b/machine_manager/src/config/vnc.rs @@ -13,22 +13,26 @@ use std::net::Ipv4Addr; use anyhow::{anyhow, Context, Result}; +use clap::{ArgAction, Parser}; use serde::{Deserialize, Serialize}; -use crate::config::{CmdParser, ConfigError, VmConfig}; +use crate::config::{str_slip_to_clap, ConfigError, VmConfig}; /// Configuration of vnc. -#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[derive(Parser, Debug, Clone, Default, Serialize, Deserialize)] +#[command(no_binary_name(true))] pub struct VncConfig { - /// Listening ip. - pub ip: String, - /// Listening port. - pub port: String, + /// Vnc listening addr (ip, port). + #[arg(long, alias = "classtype", value_parser = parse_ip_port)] + pub addr: (String, u16), /// Configuration of encryption. + #[arg(long, alias = "tls-creds", default_value = "")] pub tls_creds: String, /// Authentication switch. + #[arg(long, default_value = "false", action = ArgAction::SetTrue)] pub sasl: bool, /// Configuration of authentication. + #[arg(long, alias = "sasl-authz", default_value = "")] pub sasl_authz: String, } @@ -38,45 +42,13 @@ const VNC_PORT_OFFSET: i32 = 5900; impl VmConfig { /// Make configuration for vnc: "chardev" -> "vnc". pub fn add_vnc(&mut self, vnc_config: &str) -> Result<()> { - let mut cmd_parser = CmdParser::new("vnc"); - cmd_parser - .push("") - .push("tls-creds") - .push("sasl") - .push("sasl-authz"); - cmd_parser.parse(vnc_config)?; - - let mut vnc_config = VncConfig::default(); - // Parse Ip:Port. - if let Some(addr) = cmd_parser.get_value::("")? { - parse_port(&mut vnc_config, addr)?; - } else { - return Err(anyhow!(ConfigError::FieldIsMissing( - "ip".to_string(), - "port".to_string() - ))); - } - - // VNC Security Type. - if let Some(tls_creds) = cmd_parser.get_value::("tls-creds")? { - vnc_config.tls_creds = tls_creds - } - if let Some(_sasl) = cmd_parser.get_value::("sasl")? { - vnc_config.sasl = true - } else { - vnc_config.sasl = false - } - if let Some(sasl_authz) = cmd_parser.get_value::("sasl-authz")? { - vnc_config.sasl_authz = sasl_authz; - } - + let vnc_config = VncConfig::try_parse_from(str_slip_to_clap(vnc_config, true, false))?; self.vnc = Some(vnc_config); Ok(()) } } -/// Parse Ip:port. -fn parse_port(vnc_config: &mut VncConfig, addr: String) -> Result<()> { +fn parse_ip_port(addr: &str) -> Result<(String, u16)> { let v: Vec<&str> = addr.split(':').collect(); if v.len() != 2 { return Err(anyhow!(ConfigError::FieldIsMissing( @@ -97,10 +69,8 @@ fn parse_port(vnc_config: &mut VncConfig, addr: String) -> Result<()> { "port".to_string() ))); } - vnc_config.ip = ip.to_string(); - vnc_config.port = ((base_port + VNC_PORT_OFFSET) as u16).to_string(); - Ok(()) + Ok((ip.to_string(), (base_port + VNC_PORT_OFFSET) as u16)) } #[cfg(test)] @@ -113,8 +83,8 @@ mod tests { let config_line = "0.0.0.0:1,tls-creds=vnc-tls-creds0,sasl,sasl-authz=authz0"; assert!(vm_config.add_vnc(config_line).is_ok()); let vnc_config = vm_config.vnc.unwrap(); - assert_eq!(vnc_config.ip, String::from("0.0.0.0")); - assert_eq!(vnc_config.port, String::from("5901")); + assert_eq!(vnc_config.addr.0, String::from("0.0.0.0")); + assert_eq!(vnc_config.addr.1, 5901); assert_eq!(vnc_config.tls_creds, String::from("vnc-tls-creds0")); assert_eq!(vnc_config.sasl, true); assert_eq!(vnc_config.sasl_authz, String::from("authz0")); @@ -124,7 +94,7 @@ mod tests { assert!(vm_config.add_vnc(config_line).is_ok()); let vnc_config = vm_config.vnc.unwrap(); assert_eq!(vnc_config.sasl, false); - assert_eq!(vnc_config.port, String::from("11800")); + assert_eq!(vnc_config.addr.1, 11800); let mut vm_config = VmConfig::default(); let config_line = "0.0.0.0:1,sasl,sasl-authz=authz0"; diff --git a/ui/src/vnc/mod.rs b/ui/src/vnc/mod.rs index 9f0a7e93..ff2e48c9 100644 --- a/ui/src/vnc/mod.rs +++ b/ui/src/vnc/mod.rs @@ -290,7 +290,7 @@ pub fn vnc_init(vnc: &Option, object: &ObjectConfig) -> Result<()> { None => return Ok(()), }; - let addr = format!("{}:{}", vnc_cfg.ip, vnc_cfg.port); + let addr = format!("{}:{}", vnc_cfg.addr.0, vnc_cfg.addr.1); let listener: TcpListener = match TcpListener::bind(addr.as_str()) { Ok(l) => l, Err(e) => { -- Gitee From ef1158abb072b23ae2443327bb6b3faf51c30997 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 25 Apr 2024 13:06:19 +0800 Subject: [PATCH 035/489] machine_manager: add check_arg_exist and check_arg_nonexist macro Add check_arg_exist/check_arg_nonexist macro to make sure args are existed/not existed. Signed-off-by: liuxiangdong --- machine/src/lib.rs | 42 ++++++++++++++++++++++----- machine/src/micro_common/mod.rs | 12 +++++++- machine_manager/src/config/chardev.rs | 24 --------------- machine_manager/src/config/mod.rs | 28 ++++++++++++++++-- 4 files changed, 71 insertions(+), 35 deletions(-) diff --git a/machine/src/lib.rs b/machine/src/lib.rs index a068fdbe..63fd7205 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -81,6 +81,7 @@ use machine_manager::config::{ }; use machine_manager::event_loop::EventLoop; use machine_manager::machine::{HypervisorType, MachineInterface, VmState}; +use machine_manager::{check_arg_exist, check_arg_nonexist}; use migration::{MigrateOps, MigrationManager}; #[cfg(feature = "windows_emu_pid")] use ui::console::{get_run_stage, VmRunningStage}; @@ -571,6 +572,11 @@ pub trait MachineOps { let vsock = Arc::new(Mutex::new(VhostKern::Vsock::new(&device_cfg, &sys_mem))); match parse_device_type(cfg_args)?.as_str() { "vhost-vsock-device" => { + check_arg_nonexist!( + ("bus", device_cfg.bus), + ("addr", device_cfg.addr), + ("multifunction", device_cfg.multifunction) + ); let device = VirtioMmioDevice::new(&sys_mem, vsock.clone()); MigrationManager::register_device_instance( VirtioMmioState::descriptor(), @@ -580,6 +586,7 @@ pub trait MachineOps { ); } _ => { + check_arg_exist!(("bus", device_cfg.bus), ("addr", device_cfg.addr)); let bdf = PciBdf::new(device_cfg.bus.clone().unwrap(), device_cfg.addr.unwrap()); let multi_func = device_cfg.multifunction.unwrap_or_default(); self.add_virtio_pci_device(&device_cfg.id, &bdf, vsock.clone(), multi_func, true) @@ -667,16 +674,16 @@ pub trait MachineOps { Balloon::object_init(balloon.clone()); match config.classtype.as_str() { "virtio-balloon-device" => { - if config.addr.is_some() || config.bus.is_some() || config.multifunction.is_some() { - bail!("virtio balloon device config is error!"); - } + check_arg_nonexist!( + ("bus", config.bus), + ("addr", config.addr), + ("multifunction", config.multifunction) + ); let device = VirtioMmioDevice::new(sys_mem, balloon); self.realize_virtio_mmio_device(device)?; } _ => { - if config.addr.is_none() || config.bus.is_none() { - bail!("virtio balloon pci config is error!"); - } + check_arg_exist!(("bus", config.bus), ("addr", config.addr)); let bdf = PciBdf::new(config.bus.unwrap(), config.addr.unwrap()); let multi_func = config.multifunction.unwrap_or_default(); self.add_virtio_pci_device(&config.id, &bdf, balloon, multi_func, false) @@ -700,12 +707,16 @@ pub trait MachineOps { let mut serial_cfg = VirtioSerialInfo::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; serial_cfg.auto_max_ports(); - serial_cfg.check()?; let sys_mem = self.get_sys_mem().clone(); let serial = Arc::new(Mutex::new(Serial::new(serial_cfg.clone()))); match serial_cfg.classtype.as_str() { "virtio-serial-device" => { + check_arg_nonexist!( + ("bus", serial_cfg.bus), + ("addr", serial_cfg.addr), + ("multifunction", serial_cfg.multifunction) + ); let device = VirtioMmioDevice::new(&sys_mem, serial.clone()); MigrationManager::register_device_instance( VirtioMmioState::descriptor(), @@ -715,6 +726,7 @@ pub trait MachineOps { ); } _ => { + check_arg_exist!(("bus", serial_cfg.bus), ("addr", serial_cfg.addr)); let bdf = PciBdf::new(serial_cfg.bus.clone().unwrap(), serial_cfg.addr.unwrap()); let multi_func = serial_cfg.multifunction.unwrap_or_default(); self.add_virtio_pci_device(&serial_cfg.id, &bdf, serial.clone(), multi_func, false) @@ -836,11 +848,17 @@ pub trait MachineOps { match rng_cfg.classtype.as_str() { "virtio-rng-device" => { + check_arg_nonexist!( + ("bus", rng_cfg.bus), + ("addr", rng_cfg.addr), + ("multifunction", rng_cfg.multifunction) + ); let device = VirtioMmioDevice::new(sys_mem, rng_dev.clone()); self.realize_virtio_mmio_device(device) .with_context(|| "Failed to add virtio mmio rng device")?; } _ => { + check_arg_exist!(("bus", rng_cfg.bus), ("addr", rng_cfg.addr)); let bdf = PciBdf::new(rng_cfg.bus.clone().unwrap(), rng_cfg.addr.unwrap()); let multi_func = rng_cfg.multifunction.unwrap_or_default(); self.add_virtio_pci_device(&rng_cfg.id, &bdf, rng_dev.clone(), multi_func, false) @@ -882,11 +900,17 @@ pub trait MachineOps { ))); match dev_cfg.classtype.as_str() { "vhost-user-fs-device" => { + check_arg_nonexist!( + ("bus", dev_cfg.bus), + ("addr", dev_cfg.addr), + ("multifunction", dev_cfg.multifunction) + ); let virtio_mmio_device = VirtioMmioDevice::new(&sys_mem, device); self.realize_virtio_mmio_device(virtio_mmio_device) .with_context(|| "Failed to add vhost user fs device")?; } _ => { + check_arg_exist!(("bus", dev_cfg.bus), ("addr", dev_cfg.addr)); let bdf = PciBdf::new(dev_cfg.bus.clone().unwrap(), dev_cfg.addr.unwrap()); let multi_func = dev_cfg.multifunction.unwrap_or_default(); let root_bus = self.get_pci_host()?.lock().unwrap().root_bus.clone(); @@ -1068,6 +1092,7 @@ pub trait MachineOps { ) -> Result<()> { let mut device_cfg = VirtioBlkDevConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + check_arg_exist!(("bus", device_cfg.bus), ("addr", device_cfg.addr)); let bdf = PciBdf::new(device_cfg.bus.clone().unwrap(), device_cfg.addr.unwrap()); let multi_func = device_cfg.multifunction.unwrap_or_default(); if device_cfg.num_queues.is_none() { @@ -1225,6 +1250,7 @@ pub trait MachineOps { .netdevs .remove(&net_cfg.netdev) .with_context(|| format!("Netdev: {:?} not found for net device", &net_cfg.netdev))?; + check_arg_exist!(("bus", net_cfg.bus), ("addr", net_cfg.addr)); let bdf = PciBdf::new(net_cfg.bus.clone().unwrap(), net_cfg.addr.unwrap()); let multi_func = net_cfg.multifunction.unwrap_or_default(); @@ -1278,6 +1304,7 @@ pub trait MachineOps { let mut device_cfg = VhostUser::VhostUserBlkDevConfig::try_parse_from(str_slip_to_clap( cfg_args, true, false, ))?; + check_arg_exist!(("bus", device_cfg.bus), ("addr", device_cfg.addr)); let bdf = PciBdf::new(device_cfg.bus.clone().unwrap(), device_cfg.addr.unwrap()); if device_cfg.num_queues.is_none() { let queues_auto = VirtioPciDevice::virtio_pci_auto_queues_num( @@ -1329,6 +1356,7 @@ pub trait MachineOps { let device_cfg = VhostUser::VhostUserBlkDevConfig::try_parse_from(str_slip_to_clap( cfg_args, true, false, ))?; + check_arg_nonexist!(("bus", device_cfg.bus), ("addr", device_cfg.addr)); let chardev_cfg = vm_config .chardev .remove(&device_cfg.chardev) diff --git a/machine/src/micro_common/mod.rs b/machine/src/micro_common/mod.rs index ba58236b..b4051b46 100644 --- a/machine/src/micro_common/mod.rs +++ b/machine/src/micro_common/mod.rs @@ -52,7 +52,6 @@ use machine_manager::config::{ get_chardev_socket_path, parse_incoming_uri, str_slip_to_clap, ConfigCheck, DriveConfig, MigrateMode, NetDevcfg, NetworkInterfaceConfig, VmConfig, }; -use machine_manager::event; use machine_manager::event_loop::EventLoop; use machine_manager::machine::{ DeviceInterface, MachineAddressInterface, MachineExternalInterface, MachineInterface, @@ -61,6 +60,7 @@ use machine_manager::machine::{ use machine_manager::qmp::{ qmp_channel::QmpChannel, qmp_response::Response, qmp_schema, qmp_schema::UpdateRegionArgument, }; +use machine_manager::{check_arg_nonexist, event}; use migration::MigrationManager; use util::{loop_context::EventLoopManager, num_ops::str_to_num, set_termi_canon_mode}; use virtio::device::block::VirtioBlkDevConfig; @@ -399,6 +399,11 @@ impl LightMachine { ) -> Result<()> { let net_cfg = NetworkInterfaceConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + check_arg_nonexist!( + ("bus", net_cfg.bus), + ("addr", net_cfg.addr), + ("multifunction", net_cfg.multifunction) + ); let netdev_cfg = vm_config .netdevs .remove(&net_cfg.netdev) @@ -452,6 +457,11 @@ impl LightMachine { ) -> Result<()> { let device_cfg = VirtioBlkDevConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + check_arg_nonexist!( + ("bus", device_cfg.bus), + ("addr", device_cfg.addr), + ("multifunction", device_cfg.multifunction) + ); let drive_cfg = vm_config .drives .remove(&device_cfg.drive) diff --git a/machine_manager/src/config/chardev.rs b/machine_manager/src/config/chardev.rs index 73c3033a..0ea4d49b 100644 --- a/machine_manager/src/config/chardev.rs +++ b/machine_manager/src/config/chardev.rs @@ -346,24 +346,6 @@ impl VirtioSerialInfo { } } -impl ConfigCheck for VirtioSerialInfo { - fn check(&self) -> Result<()> { - match self.classtype.as_str() { - "virtio-serial-pci" => {} - "virtio-serial-device" => { - if self.bus.is_some() || self.addr.is_some() || self.multifunction.is_some() { - bail!("virtio mmio device should not set bus/addr/multifunction"); - } - } - _ => { - bail!("Invalid classtype."); - } - } - - Ok(()) - } -} - #[cfg(test)] mod tests { use super::*; @@ -374,7 +356,6 @@ mod tests { let mut serial_cfg = VirtioSerialInfo::try_parse_from(str_slip_to_clap(serial_cmd, true, false)).unwrap(); serial_cfg.auto_max_ports(); - assert!(serial_cfg.check().is_ok()); vm_config.virtio_serial = Some(serial_cfg.clone()); assert!(vm_config.add_chardev(chardev_cfg).is_ok()); @@ -394,10 +375,6 @@ mod tests { assert!(port_cfg.auto_nr(true, 0, serial_cfg.max_ports).is_err()); let mut vm_config = VmConfig::default(); - let serial_cmd = "virtio-serial-device,bus=pcie.0,addr=0x1"; - let serial_cfg = - VirtioSerialInfo::try_parse_from(str_slip_to_clap(serial_cmd, true, false)).unwrap(); - assert!(serial_cfg.check().is_err()); assert!(vm_config .add_chardev("sock,id=test_console,path=/path/to/socket") .is_err()); @@ -437,7 +414,6 @@ mod tests { let mut serial_cfg = VirtioSerialInfo::try_parse_from(str_slip_to_clap(serial_cmd, true, false)).unwrap(); serial_cfg.auto_max_ports(); - assert!(serial_cfg.check().is_ok()); vm_config.virtio_serial = Some(serial_cfg.clone()); assert!(vm_config.add_chardev(chardev_cfg).is_ok()); diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index 4d1b2ab9..6863bac4 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -713,10 +713,32 @@ pub fn check_path_too_long(arg: &str, name: &str) -> Result<()> { Ok(()) } -pub fn check_arg_nonexist(arg: Option, name: &str, device: &str) -> Result<()> { - arg.with_context(|| ConfigError::FieldIsMissing(name.to_string(), device.to_string()))?; +/// Make sure args are existed. +/// +/// arg_name: Name of arg. +/// arg_value: Value of arg. Should be Option<> class. +/// Eg: +/// check_arg_exist!(("id", id)); +/// check_arg_exist!(("bus", bus), ("addr", addr)); +#[macro_export] +macro_rules! check_arg_exist{ + ($(($arg_name:tt, $arg_value:expr)),*) => { + $($arg_value.clone().with_context(|| format!("Should set {}.", $arg_name))?;)* + } +} - Ok(()) +/// Make sure args are existed. +/// +/// arg_name: Name of arg. +/// arg_value: Value of arg. Should be Option<> class. +/// Eg: +/// check_arg_nonexist!(("id", id)); +/// check_arg_nonexist!(("bus", bus), ("addr", addr)); +#[macro_export] +macro_rules! check_arg_nonexist{ + ($(($arg_name:tt, $arg_value:expr)),*) => { + $($arg_value.clone().map_or(Some(0), |_| None).with_context(|| format!("Should not set {}", $arg_name))?;)* + } } /// Configure StratoVirt parameters in clap format. -- Gitee From a7403902e35e828f2f677b211fdbeaee16094a78 Mon Sep 17 00:00:00 2001 From: yexiao Date: Thu, 25 Apr 2024 00:07:59 +0800 Subject: [PATCH 036/489] qcow2: fix some error in qcow2 If there is some io error in loading metadata for qcow2 disk, it's better to report io error rather than virtio error. Signed-off-by: Xiao Ye --- block_backend/src/file.rs | 16 +++++----------- block_backend/src/qcow2/mod.rs | 20 ++++++++++++++++---- 2 files changed, 21 insertions(+), 15 deletions(-) diff --git a/block_backend/src/file.rs b/block_backend/src/file.rs index 56fac1e0..83237651 100644 --- a/block_backend/src/file.rs +++ b/block_backend/src/file.rs @@ -102,7 +102,7 @@ impl FileDriver { completecb: T, ) -> Result<()> { if req_list.is_empty() { - return self.complete_request(opcode, &Vec::new(), 0, 0, completecb); + return self.complete_request(opcode, 0, completecb); } let single_req = req_list.len() == 1; let cnt = Arc::new(AtomicU32::new(req_list.len() as u32)); @@ -127,16 +127,10 @@ impl FileDriver { self.process_request(OpCode::Preadv, req_list, completecb) } - fn complete_request( - &mut self, - opcode: OpCode, - iovec: &[Iovec], - offset: usize, - nbytes: u64, - completecb: T, - ) -> Result<()> { - let aiocb = self.package_aiocb(opcode, iovec.to_vec(), offset, nbytes, completecb); - (self.aio.borrow_mut().complete_func)(&aiocb, nbytes as i64) + pub fn complete_request(&mut self, opcode: OpCode, res: i64, completecb: T) -> Result<()> { + let iovec: Vec = Vec::new(); + let aiocb = self.package_aiocb(opcode, iovec.to_vec(), 0, 0, completecb); + (self.aio.borrow_mut().complete_func)(&aiocb, res) } pub fn write_vectored(&mut self, req_list: Vec, completecb: T) -> Result<()> { diff --git a/block_backend/src/qcow2/mod.rs b/block_backend/src/qcow2/mod.rs index 2dd1e4ac..b3529fbb 100644 --- a/block_backend/src/qcow2/mod.rs +++ b/block_backend/src/qcow2/mod.rs @@ -1672,8 +1672,8 @@ impl BlockDriverOps for Qcow2Driver { let mut copied = 0; while copied < nbytes { let pos = offset as u64 + copied; - match self.host_offset_for_read(pos, nbytes - copied)? { - HostRange::DataAddress(host_offset, cnt) => { + match self.host_offset_for_read(pos, nbytes - copied) { + Ok(HostRange::DataAddress(host_offset, cnt)) => { let (begin, end) = iovecs_split(left, cnt); left = end; req_list.push(CombineRequest { @@ -1683,12 +1683,16 @@ impl BlockDriverOps for Qcow2Driver { }); copied += cnt; } - HostRange::DataNotInit(cnt) => { + Ok(HostRange::DataNotInit(cnt)) => { let (begin, end) = iovecs_split(left, cnt); left = end; iovec_write_zero(&begin); copied += cnt; } + Err(e) => { + error!("Failed to read vectored: {:?}", e); + return self.driver.complete_request(OpCode::Preadv, -1, completecb); + } } } @@ -1706,7 +1710,15 @@ impl BlockDriverOps for Qcow2Driver { while copied < nbytes { let pos = offset as u64 + copied; let count = self.cluster_aligned_bytes(pos, nbytes - copied); - let host_offset = self.host_offset_for_write(pos, count)?; + let host_offset = match self.host_offset_for_write(pos, count) { + Ok(host_offset) => host_offset, + Err(e) => { + error!("Failed to write vectored: {:?}", e); + return self + .driver + .complete_request(OpCode::Pwritev, -1, completecb); + } + }; if let Some(end) = req_list.last_mut() { if end.offset + end.nbytes == host_offset { end.nbytes += count; -- Gitee From 2a8b651aaa8467839c8a66991e008618c1ad5d5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A5=9A=E5=BD=B1?= Date: Tue, 14 May 2024 15:14:36 +0800 Subject: [PATCH 037/489] add oh ui trace Signed-off-by: Jiahong Li --- trace/trace_info/ui.toml | 54 +++++++++++++++++++++++++++++++++++ ui/src/ohui_srv/msg_handle.rs | 9 ++++++ 2 files changed, 63 insertions(+) diff --git a/trace/trace_info/ui.toml b/trace/trace_info/ui.toml index 091c0564..3c63d328 100644 --- a/trace/trace_info/ui.toml +++ b/trace/trace_info/ui.toml @@ -219,3 +219,57 @@ name = "console_select" args = "con_id: &dyn fmt::Debug" message = "console id={:?}" enabled = true + +[[events]] +name = "oh_event_mouse_button" +args = "msg_btn: u32, action: u32" +message = "msg_btn={} action={}" +enabled = true + +[[events]] +name = "oh_event_mouse_motion" +args = "x: f64, y: f64" +message = "x={} y={}" +enabled = true + +[[events]] +name = "oh_event_keyboard" +args = "keycode: u16, key_action: u16" +message = "keycode={} key_action={}" +enabled = true + +[[events]] +name = "oh_event_windowinfo" +args = "width: u32, height: u32" +message = "width={} height={}" +enabled = true + +[[events]] +name = "oh_event_scroll" +args = "direction: u32" +message = "direction={}" +enabled = true + +[[events]] +name = "oh_event_ledstate" +args = "state: u32" +message = "state={}" +enabled = true + +[[events]] +name = "oh_event_focus" +args = "state: u32" +message = "state={}" +enabled = true + +[[events]] +name = "oh_event_greet" +args = "id: u64" +message = "token_id={}" +enabled = true + +[[events]] +name = "oh_event_unsupported_type" +args = "ty: &dyn fmt::Debug, size: u32" +message = "type={:?} body_size={}" +enabled = true diff --git a/ui/src/ohui_srv/msg_handle.rs b/ui/src/ohui_srv/msg_handle.rs index 9f063f1f..eeb44c15 100755 --- a/ui/src/ohui_srv/msg_handle.rs +++ b/ui/src/ohui_srv/msg_handle.rs @@ -196,6 +196,7 @@ impl OhUiMsgHandler { } EventType::Focus => { let body = FocusEvent::from_bytes(&body_bytes[..]).unwrap(); + trace::oh_event_focus(body.state); if body.state == CLIENT_FOCUSOUT_EVENT { reader.clear(); release_all_key()?; @@ -209,6 +210,7 @@ impl OhUiMsgHandler { } EventType::Greet => { let body = GreetEvent::from_bytes(&body_bytes[..]).unwrap(); + trace::oh_event_greet(body.token_id); *token_id.write().unwrap() = body.token_id; Ok(()) } @@ -217,6 +219,7 @@ impl OhUiMsgHandler { "unsupported type {:?} and body size {}", event_type, body_size ); + trace::oh_event_unsupported_type(&event_type, body_size.try_into().unwrap()); Ok(()) } } { @@ -228,6 +231,7 @@ impl OhUiMsgHandler { fn handle_mouse_button(&self, mb: &MouseButtonEvent) -> Result<()> { let (msg_btn, action) = (mb.button, mb.btn_action); + trace::oh_event_mouse_button(msg_btn, action); let btn = match msg_btn { CLIENT_MOUSE_BUTTON_LEFT => INPUT_POINT_LEFT, CLIENT_MOUSE_BUTTON_RIGHT => INPUT_POINT_RIGHT, @@ -264,6 +268,7 @@ impl OhUiMsgHandler { // NOTE: we only support absolute position info now, that means usb-mouse does not work. fn handle_mouse_motion(&self, mm: &MouseMotionEvent) -> Result<()> { + trace::oh_event_mouse_motion(mm.x, mm.y); self.state.lock().unwrap().move_pointer(mm.x, mm.y) } @@ -278,6 +283,7 @@ impl OhUiMsgHandler { bail!("not supported keycode {}", hmkey); } }; + trace::oh_event_keyboard(keycode, ke.key_action); self.state .lock() .unwrap() @@ -295,6 +301,7 @@ impl OhUiMsgHandler { }; self.state.lock().unwrap().press_btn(dir)?; self.state.lock().unwrap().release_btn(dir)?; + trace::oh_event_scroll(dir); Ok(()) } @@ -310,6 +317,7 @@ impl OhUiMsgHandler { error!("handle_windowinfo failed with error {e}"); } } + trace::oh_event_windowinfo(wi.width, wi.height); } fn handle_ledstate(&self, led: &LedstateEvent) { @@ -317,6 +325,7 @@ impl OhUiMsgHandler { .lock() .unwrap() .update_host_ledstate(led.state as u8); + trace::oh_event_ledstate(led.state); } pub fn send_windowinfo(&self, w: u32, h: u32) { -- Gitee From 65b4c6718ae0076779da1ea12ecd7a57b33b7e30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A5=9A=E5=BD=B1?= Date: Wed, 15 May 2024 11:59:06 +0800 Subject: [PATCH 038/489] add oh scream trace Signed-off-by: Jiahong Li --- devices/src/misc/scream/ohaudio.rs | 6 +++++ trace/trace_info/misc.toml | 36 ++++++++++++++++++++++++++++++ util/src/ohos_binding/audio/mod.rs | 1 + 3 files changed, 43 insertions(+) diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index bd7d89c2..f1ea1061 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -108,6 +108,7 @@ impl OhAudioProcess for OhAudioRender { match self.ctx.as_ref().unwrap().start() { Ok(()) => { self.start = true; + trace::oh_scream_render_init(&self.ctx); } Err(e) => { error!("failed to start oh audio renderer: {}", e); @@ -128,6 +129,7 @@ impl OhAudioProcess for OhAudioRender { let mut locked_data = self.stream_data.lock().unwrap(); locked_data.clear(); self.data_size.store(0, Ordering::Relaxed); + trace::oh_scream_render_destroy(); } fn process(&mut self, recv_data: &StreamData) -> i32 { @@ -197,6 +199,7 @@ impl OhAudioProcess for OhAudioCapture { match self.ctx.as_ref().unwrap().start() { Ok(()) => { self.start = true; + trace::oh_scream_capture_init(&self.ctx); true } Err(e) => { @@ -214,6 +217,7 @@ impl OhAudioProcess for OhAudioCapture { } self.ctx = None; } + trace::oh_scream_capture_destroy(); } fn preprocess(&mut self, start_addr: u64, sh_header: &ShmemStreamHeader) { @@ -271,6 +275,7 @@ extern "C" fn on_write_data_cb( unsafe { ptr::copy_nonoverlapping(su.addr as *const u8, dst_addr as *mut u8, len as usize) }; + trace::oh_scream_on_write_data_cb(len as usize); dst_addr += len; left -= len; @@ -330,6 +335,7 @@ extern "C" fn on_read_data_cb( len as usize, ) }; + trace::oh_scream_on_read_data_cb(len as usize); left -= len; src_addr += len; capture.cur_pos += len; diff --git a/trace/trace_info/misc.toml b/trace/trace_info/misc.toml index 78ac9d19..c0574193 100644 --- a/trace/trace_info/misc.toml +++ b/trace/trace_info/misc.toml @@ -27,3 +27,39 @@ name = "scream_setup_alsa_hwp" args = "name: &str, hwp: &dyn fmt::Debug" message = "scream {} setup hardware parameters: {:?}" enabled = true + +[[events]] +name = "oh_scream_render_init" +args = "context: &dyn fmt::Debug" +message = "context: {:?}" +enabled = true + +[[events]] +name = "oh_scream_render_destroy" +args = "" +message = "" +enabled = true + +[[events]] +name = "oh_scream_capture_init" +args = "context: &dyn fmt::Debug" +message = "context: {:?}" +enabled = true + +[[events]] +name = "oh_scream_capture_destroy" +args = "" +message = "" +enabled = true + +[[events]] +name = "oh_scream_on_write_data_cb" +args = "len: usize" +message = "len: {}" +enabled = true + +[[events]] +name = "oh_scream_on_read_data_cb" +args = "len: usize" +message = "len: {}" +enabled = true diff --git a/util/src/ohos_binding/audio/mod.rs b/util/src/ohos_binding/audio/mod.rs index 9590dad7..4dd7687f 100755 --- a/util/src/ohos_binding/audio/mod.rs +++ b/util/src/ohos_binding/audio/mod.rs @@ -197,6 +197,7 @@ pub enum AudioProcessCb { ), } +#[derive(Debug)] pub struct AudioContext { stream_type: AudioStreamType, spec: AudioSpec, -- Gitee From 96cd7c2dd406bd6e90f7c68d629b804ee16b6ef6 Mon Sep 17 00:00:00 2001 From: Yan Wang Date: Thu, 9 May 2024 19:45:45 +0800 Subject: [PATCH 039/489] block_backend: do not call contains_keys for set/get_refcount Do not call contains_keys() in set/get_refcount() for performance. Signed-off-by: Yan Wang --- block_backend/src/qcow2/refcount.rs | 40 ++++++++++++++--------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/block_backend/src/qcow2/refcount.rs b/block_backend/src/qcow2/refcount.rs index 1a3dfddd..bb80381d 100644 --- a/block_backend/src/qcow2/refcount.rs +++ b/block_backend/src/qcow2/refcount.rs @@ -381,6 +381,22 @@ impl RefCount { self.refcount_blk_cache.flush(self.sync_aio.clone()) } + fn get_refcount_block_cache(&mut self, rt_idx: u64) -> Result>> { + let entry = self.refcount_blk_cache.get(rt_idx); + let cache_entry = if let Some(entry) = entry { + entry.clone() + } else { + self.load_refcount_block(rt_idx).with_context(|| { + format!("Failed to get refcount block cache, index is {}", rt_idx) + })?; + self.refcount_blk_cache + .get(rt_idx) + .with_context(|| format!("Not found refcount block cache, index is {}", rt_idx))? + .clone() + }; + Ok(cache_entry) + } + fn set_refcount( &mut self, rt_idx: u64, @@ -391,17 +407,9 @@ impl RefCount { ) -> Result<()> { let is_add = added > 0; let added_value = added.unsigned_abs() as u16; - if !self.refcount_blk_cache.contains_keys(rt_idx) { - self.load_refcount_block(rt_idx).with_context(|| { - format!("Failed to get refcount block cache, index is {}", rt_idx) - })?; - } let cache_entry = self - .refcount_blk_cache - .get(rt_idx) - .with_context(|| format!("Not found refcount block cache, index is {}", rt_idx))? - .clone(); - + .get_refcount_block_cache(rt_idx) + .with_context(|| "Get refcount block cache failed")?; let mut rb_vec = Vec::new(); let mut borrowed_entry = cache_entry.borrow_mut(); let is_dirty = borrowed_entry.dirty_info.is_dirty; @@ -471,17 +479,9 @@ impl RefCount { ); } - if !self.refcount_blk_cache.contains_keys(rt_idx) { - self.load_refcount_block(rt_idx).with_context(|| { - format!("Failed to get refcount block cache, index is {}", rt_idx) - })?; - } let cache_entry = self - .refcount_blk_cache - .get(rt_idx) - .with_context(|| format!("Not found refcount block cache, index is {}", rt_idx))? - .clone(); - + .get_refcount_block_cache(rt_idx) + .with_context(|| "Get refcount block cache failed")?; let rb_idx = self.cluster_in_rc_block(cluster) as usize; let rc_value = cache_entry.borrow_mut().get_entry_map(rb_idx).unwrap(); -- Gitee From ad180382f3edff03f88e3a5db970cb368dcdaef5 Mon Sep 17 00:00:00 2001 From: Yan Wang Date: Thu, 9 May 2024 21:08:52 +0800 Subject: [PATCH 040/489] block_backend: do not write zero for new data cluster There is no need to write zero for new allocated data cluster. Signed-off-by: Yan Wang --- block_backend/src/qcow2/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/block_backend/src/qcow2/mod.rs b/block_backend/src/qcow2/mod.rs index b3529fbb..30689180 100644 --- a/block_backend/src/qcow2/mod.rs +++ b/block_backend/src/qcow2/mod.rs @@ -435,7 +435,7 @@ impl Qcow2Driver { l2_entry &= !QCOW2_OFLAG_ZERO; let mut cluster_addr = l2_entry & L2_TABLE_OFFSET_MASK; if cluster_addr == 0 { - let new_addr = self.alloc_cluster(1, true)?; + let new_addr = self.alloc_cluster(1, false)?; l2_entry = new_addr | QCOW2_OFFSET_COPIED; cluster_addr = new_addr & L2_TABLE_OFFSET_MASK; } else if l2_entry & QCOW2_OFFSET_COPIED == 0 { -- Gitee From 43990c909921b4806a81904b6a4e6430cfc48d0f Mon Sep 17 00:00:00 2001 From: Yan Wang Date: Thu, 9 May 2024 21:18:36 +0800 Subject: [PATCH 041/489] block_backend: init capacity for vec element Pre-allocate capacity for vec element Signed-off-by: Yan Wang --- block_backend/src/qcow2/refcount.rs | 4 ++-- util/src/aio/mod.rs | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/block_backend/src/qcow2/refcount.rs b/block_backend/src/qcow2/refcount.rs index bb80381d..7b680402 100644 --- a/block_backend/src/qcow2/refcount.rs +++ b/block_backend/src/qcow2/refcount.rs @@ -316,7 +316,7 @@ impl RefCount { bail!("Failed to update refcount, offset is not aligned to cluster"); } let first_cluster = bytes_to_clusters(offset, self.cluster_size).unwrap(); - let mut rc_vec = Vec::new(); + let mut rc_vec: Vec<(u64, u64, usize)> = Vec::with_capacity(clusters as usize); let mut i = 0; while i < clusters { let rt_idx = (first_cluster + i) >> self.refcount_blk_bits; @@ -410,7 +410,7 @@ impl RefCount { let cache_entry = self .get_refcount_block_cache(rt_idx) .with_context(|| "Get refcount block cache failed")?; - let mut rb_vec = Vec::new(); + let mut rb_vec: Vec = Vec::with_capacity(clusters); let mut borrowed_entry = cache_entry.borrow_mut(); let is_dirty = borrowed_entry.dirty_info.is_dirty; for i in 0..clusters { diff --git a/util/src/aio/mod.rs b/util/src/aio/mod.rs index 0b117b85..03183b80 100644 --- a/util/src/aio/mod.rs +++ b/util/src/aio/mod.rs @@ -813,8 +813,9 @@ fn iovec_is_zero(iovecs: &[Iovec]) -> bool { } pub fn iovecs_split(iovecs: Vec, mut size: u64) -> (Vec, Vec) { - let mut begin = Vec::new(); - let mut end = Vec::new(); + let len = iovecs.len(); + let mut begin: Vec = Vec::with_capacity(len); + let mut end: Vec = Vec::with_capacity(len); for iov in iovecs { if size == 0 { end.push(iov); -- Gitee From e11cb93410be7efa61a6b091f9d5d97d67073558 Mon Sep 17 00:00:00 2001 From: Yan Wang Date: Mon, 13 May 2024 16:21:24 +0800 Subject: [PATCH 042/489] block_backend: optimize check_overlap funtion Using hashmap to optimize check_overlap function. Signed-off-by: Yan Wang --- block_backend/src/qcow2/mod.rs | 45 +++++++++++++++-------------- block_backend/src/qcow2/refcount.rs | 14 ++++++++- block_backend/src/qcow2/table.rs | 15 +++++++++- 3 files changed, 51 insertions(+), 23 deletions(-) diff --git a/block_backend/src/qcow2/mod.rs b/block_backend/src/qcow2/mod.rs index 30689180..922233f6 100644 --- a/block_backend/src/qcow2/mod.rs +++ b/block_backend/src/qcow2/mod.rs @@ -341,6 +341,13 @@ impl Qcow2Driver { .sync_aio .borrow_mut() .read_ctrl_cluster(self.header.refcount_table_offset, sz)?; + for block_offset in &self.refcount.refcount_table { + if *block_offset == 0 { + continue; + } + let rfb_offset = block_offset & REFCOUNT_TABLE_OFFSET_MASK; + self.refcount.refcount_table_map.insert(rfb_offset, 1); + } Ok(()) } @@ -865,6 +872,11 @@ impl Qcow2Driver { self.table.l1_table_offset = new_l1_table_offset; self.table.l1_size = snap.l1_size; self.table.l1_table = snap_l1_table; + self.table.l1_table_map.clear(); + for l1_entry in self.table.l1_table.iter() { + let addr = l1_entry & L1_TABLE_OFFSET_MASK; + self.table.l1_table_map.insert(addr, 1); + } self.qcow2_update_snapshot_refcount(old_l1_table_offset, old_l1_size as usize, -1)?; @@ -1291,13 +1303,14 @@ impl Qcow2Driver { return 0; } - if check & METADATA_OVERLAP_CHECK_MAINHEADER != 0 && offset < self.header.cluster_size() { + let cluster_size = self.header.cluster_size(); + if check & METADATA_OVERLAP_CHECK_MAINHEADER != 0 && offset < cluster_size { return METADATA_OVERLAP_CHECK_MAINHEADER as i64; } let size = round_up( self.refcount.offset_into_cluster(offset) + size, - self.header.cluster_size(), + cluster_size, ) .unwrap() as usize; let offset = self.refcount.start_of_cluster(offset) as usize; @@ -1321,15 +1334,10 @@ impl Qcow2Driver { } if check & METADATA_OVERLAP_CHECK_ACTIVEL2 != 0 { - for l1_entry in &self.table.l1_table { - if ranges_overlap( - offset, - size, - (l1_entry & L1_TABLE_OFFSET_MASK) as usize, - self.header.cluster_size() as usize, - ) - .unwrap() - { + let num = size as u64 / cluster_size; + for i in 0..num { + let addr = offset as u64 + i * cluster_size; + if self.table.l1_table_map.contains_key(&addr) { return METADATA_OVERLAP_CHECK_ACTIVEL2 as i64; } } @@ -1340,7 +1348,7 @@ impl Qcow2Driver { offset, size, self.header.refcount_table_offset as usize, - self.header.refcount_table_clusters as usize * self.header.cluster_size() as usize, + self.header.refcount_table_clusters as usize * cluster_size as usize, ) .unwrap() { @@ -1348,15 +1356,10 @@ impl Qcow2Driver { } if check & METADATA_OVERLAP_CHECK_REFCOUNTBLOCK != 0 { - for block_offset in &self.refcount.refcount_table { - if ranges_overlap( - offset, - size, - (block_offset & REFCOUNT_TABLE_OFFSET_MASK) as usize, - self.header.cluster_size() as usize, - ) - .unwrap() - { + let num = size as u64 / cluster_size; + for i in 0..num { + let addr = offset as u64 + i * cluster_size; + if self.refcount.refcount_table_map.contains_key(&addr) { return METADATA_OVERLAP_CHECK_REFCOUNTBLOCK as i64; } } diff --git a/block_backend/src/qcow2/refcount.rs b/block_backend/src/qcow2/refcount.rs index 7b680402..b58e3718 100644 --- a/block_backend/src/qcow2/refcount.rs +++ b/block_backend/src/qcow2/refcount.rs @@ -10,7 +10,7 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use std::{cell::RefCell, rc::Rc}; +use std::{cell::RefCell, collections::HashMap, rc::Rc}; use anyhow::{bail, Context, Result}; use log::{error, info}; @@ -32,6 +32,9 @@ use util::{ // The max refcount table size default is 4 clusters; const MAX_REFTABLE_NUM: u64 = 4; +// Default refcount table map length, which can describe 512GiB data for 64Kib cluster. +const REFCOUNT_TABLE_MAP_LEN: usize = 256; + #[derive(Eq, PartialEq, Clone)] pub enum Qcow2DiscardType { Never, @@ -64,6 +67,7 @@ impl DiscardTask { #[derive(Clone)] pub struct RefCount { pub refcount_table: Vec, + pub refcount_table_map: HashMap, sync_aio: Rc>, pub(crate) refcount_blk_cache: Qcow2Cache, pub discard_list: Vec, @@ -87,6 +91,7 @@ impl RefCount { pub fn new(sync_aio: Rc>) -> Self { RefCount { refcount_table: Vec::new(), + refcount_table_map: HashMap::with_capacity(REFCOUNT_TABLE_MAP_LEN), sync_aio, refcount_blk_cache: Qcow2Cache::default(), discard_list: Vec::new(), @@ -217,9 +222,11 @@ impl RefCount { new_table.resize(new_table_size as usize, 0); let start_offset = start_idx * self.cluster_size; let mut table_offset = start_offset; + let mut added_rb = Vec::new(); for i in 0..new_block_clusters { if new_table[i as usize] == 0 { new_table[i as usize] = table_offset; + added_rb.push(table_offset & REFCOUNT_TABLE_OFFSET_MASK); table_offset += self.cluster_size; } } @@ -247,6 +254,9 @@ impl RefCount { let old_table_offset = self.refcount_table_offset; let old_table_clusters = self.refcount_table_clusters; self.refcount_table = new_table; + for rb_offset in added_rb.iter() { + self.refcount_table_map.insert(*rb_offset, 1); + } self.refcount_table_offset = header.refcount_table_offset; self.refcount_table_clusters = header.refcount_table_clusters; self.refcount_table_size = new_table_size; @@ -542,6 +552,8 @@ impl RefCount { // Update refcount table. self.refcount_table[rt_idx as usize] = alloc_offset; + let rb_offset = alloc_offset & REFCOUNT_TABLE_OFFSET_MASK; + self.refcount_table_map.insert(rb_offset, 1); let rc_block = vec![0_u8; self.cluster_size as usize]; let cache_entry = Rc::new(RefCell::new(CacheTable::new( alloc_offset, diff --git a/block_backend/src/qcow2/table.rs b/block_backend/src/qcow2/table.rs index 5886becb..6554f3fb 100644 --- a/block_backend/src/qcow2/table.rs +++ b/block_backend/src/qcow2/table.rs @@ -10,7 +10,7 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use std::{cell::RefCell, rc::Rc}; +use std::{cell::RefCell, collections::HashMap, rc::Rc}; use anyhow::{Context, Result}; use log::info; @@ -28,6 +28,9 @@ use crate::{ use machine_manager::config::MAX_L2_CACHE_SIZE; use util::num_ops::div_round_up; +// Default l1 table map length, which can describe 512GiB data for 64KiB cluster. +const L1_TABLE_MAP_LEN: usize = 1024; + #[derive(PartialEq, Eq, Debug)] pub enum Qcow2ClusterType { /// Cluster is unallocated. @@ -81,6 +84,7 @@ pub struct Qcow2Table { cluster_bits: u64, cluster_size: u64, pub l1_table: Vec, + pub l1_table_map: HashMap, pub l1_table_offset: u64, pub l1_size: u32, pub l2_table_cache: Qcow2Cache, @@ -96,6 +100,7 @@ impl Qcow2Table { cluster_bits: 0, cluster_size: 0, l1_table: Vec::new(), + l1_table_map: HashMap::with_capacity(L1_TABLE_MAP_LEN), l1_table_offset: 0, l1_size: 0, l2_table_cache: Qcow2Cache::default(), @@ -143,6 +148,10 @@ impl Qcow2Table { .sync_aio .borrow_mut() .read_ctrl_cluster(self.l1_table_offset, self.l1_size as u64)?; + for l1_entry in &self.l1_table { + let l1_entry_addr = l1_entry & L1_TABLE_OFFSET_MASK; + self.l1_table_map.insert(l1_entry_addr, 1); + } Ok(()) } @@ -185,7 +194,11 @@ impl Qcow2Table { } pub fn update_l1_table(&mut self, l1_index: usize, l2_address: u64) { + let old_addr = self.l1_table[l1_index] & L1_TABLE_OFFSET_MASK; + let new_addr = l2_address & L1_TABLE_OFFSET_MASK; self.l1_table[l1_index] = l2_address; + self.l1_table_map.remove(&old_addr); + self.l1_table_map.insert(new_addr, 1); } pub fn update_l2_table( -- Gitee From 8e74fa5491d2262de35eda17b241ef4b25b59667 Mon Sep 17 00:00:00 2001 From: Yan Wang Date: Tue, 14 May 2024 14:49:01 +0800 Subject: [PATCH 043/489] block: using cache to get address map Using cache to get address map to improve the gpa->hva conversion performance. Signed-off-by: Yan Wang --- address_space/src/address_space.rs | 3 ++- devices/src/usb/xhci/xhci_controller.rs | 8 +++++-- virtio/src/device/block.rs | 32 +++++++++++++++---------- virtio/src/lib.rs | 23 +++++++++++++++--- 4 files changed, 48 insertions(+), 18 deletions(-) diff --git a/address_space/src/address_space.rs b/address_space/src/address_space.rs index ae18dd86..f935d01b 100644 --- a/address_space/src/address_space.rs +++ b/address_space/src/address_space.rs @@ -503,6 +503,7 @@ impl AddressSpace { /// * `count` - Memory needed length pub fn get_address_map( &self, + cache: &Option, addr: GuestAddress, count: u64, res: &mut Vec, @@ -512,7 +513,7 @@ impl AddressSpace { loop { let io_vec = self - .addr_cache_init(start) + .get_host_address_from_cache(start, cache) .map(|(hva, fr_len)| Iovec { iov_base: hva, iov_len: std::cmp::min(len, fr_len), diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index ba2e1385..a5887719 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -1936,8 +1936,12 @@ impl XhciDevice { trb.parameter }; - self.mem_space - .get_address_map(GuestAddress(dma_addr), chunk as u64, &mut vec)?; + self.mem_space.get_address_map( + &None, + GuestAddress(dma_addr), + chunk as u64, + &mut vec, + )?; } } diff --git a/virtio/src/device/block.rs b/virtio/src/device/block.rs index d33d3be6..f8cd6d65 100644 --- a/virtio/src/device/block.rs +++ b/virtio/src/device/block.rs @@ -26,17 +26,17 @@ use log::{error, warn}; use vmm_sys_util::{epoll::EventSet, eventfd::EventFd}; use crate::{ - check_config_space_rw, gpa_hva_iovec_map, iov_discard_back, iov_discard_front, iov_to_buf, - read_config_default, report_virtio_error, virtio_has_feature, Element, Queue, VirtioBase, - VirtioDevice, VirtioError, VirtioInterrupt, VirtioInterruptType, VIRTIO_BLK_F_DISCARD, - VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_SEG_MAX, - VIRTIO_BLK_F_WRITE_ZEROES, VIRTIO_BLK_ID_BYTES, VIRTIO_BLK_S_IOERR, VIRTIO_BLK_S_OK, - VIRTIO_BLK_S_UNSUPP, VIRTIO_BLK_T_DISCARD, VIRTIO_BLK_T_FLUSH, VIRTIO_BLK_T_GET_ID, - VIRTIO_BLK_T_IN, VIRTIO_BLK_T_OUT, VIRTIO_BLK_T_WRITE_ZEROES, + check_config_space_rw, gpa_hva_iovec_map_by_cache, iov_discard_back, iov_discard_front, + iov_to_buf_by_cache, read_config_default, report_virtio_error, virtio_has_feature, Element, + Queue, VirtioBase, VirtioDevice, VirtioError, VirtioInterrupt, VirtioInterruptType, + VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_RO, + VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_WRITE_ZEROES, VIRTIO_BLK_ID_BYTES, VIRTIO_BLK_S_IOERR, + VIRTIO_BLK_S_OK, VIRTIO_BLK_S_UNSUPP, VIRTIO_BLK_T_DISCARD, VIRTIO_BLK_T_FLUSH, + VIRTIO_BLK_T_GET_ID, VIRTIO_BLK_T_IN, VIRTIO_BLK_T_OUT, VIRTIO_BLK_T_WRITE_ZEROES, VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP, VIRTIO_F_RING_EVENT_IDX, VIRTIO_F_RING_INDIRECT_DESC, VIRTIO_F_VERSION_1, VIRTIO_TYPE_BLOCK, }; -use address_space::{AddressSpace, GuestAddress}; +use address_space::{AddressSpace, GuestAddress, RegionCache}; use block_backend::{ create_block_backend, remove_block_backend, BlockDriverOps, BlockIoErrorCallback, BlockProperty, BlockStatus, @@ -270,7 +270,12 @@ struct Request { } impl Request { - fn new(handler: &BlockIoHandler, elem: &mut Element, status: &mut u8) -> Result { + fn new( + handler: &BlockIoHandler, + cache: &Option, + elem: &mut Element, + status: &mut u8, + ) -> Result { if elem.out_iovec.is_empty() || elem.in_iovec.is_empty() { bail!( "Missed header for block request: out {} in {} desc num {}", @@ -281,8 +286,9 @@ impl Request { } let mut out_header = RequestOutHeader::default(); - iov_to_buf( + iov_to_buf_by_cache( &handler.mem_space, + cache, &elem.out_iovec, out_header.as_mut_bytes(), ) @@ -338,7 +344,8 @@ impl Request { } .with_context(|| "Empty data for block request")?; - let (data_len, iovec) = gpa_hva_iovec_map(data_iovec, &handler.mem_space)?; + let (data_len, iovec) = + gpa_hva_iovec_map_by_cache(data_iovec, &handler.mem_space, cache)?; request.data_len = data_len; request.iovec = iovec; } @@ -651,7 +658,8 @@ impl BlockIoHandler { // Init and put valid request into request queue. let mut status = VIRTIO_BLK_S_OK; - let req = Request::new(self, &mut elem, &mut status)?; + let cache = queue.vring.get_cache(); + let req = Request::new(self, cache, &mut elem, &mut status)?; if status != VIRTIO_BLK_S_OK { let aiocompletecb = AioCompleteCb::new( self.queue.clone(), diff --git a/virtio/src/lib.rs b/virtio/src/lib.rs index 7f0fac21..58fbe4f0 100644 --- a/virtio/src/lib.rs +++ b/virtio/src/lib.rs @@ -57,7 +57,7 @@ use anyhow::{anyhow, bail, Context, Result}; use log::{error, warn}; use vmm_sys_util::eventfd::EventFd; -use address_space::AddressSpace; +use address_space::{AddressSpace, RegionCache}; use machine_manager::config::ConfigCheck; use migration_derive::ByteCode; use util::aio::{mem_to_buf, Iovec}; @@ -790,12 +790,21 @@ pub fn report_virtio_error( /// Read iovec to buf and return the read number of bytes. pub fn iov_to_buf(mem_space: &AddressSpace, iovec: &[ElemIovec], buf: &mut [u8]) -> Result { + iov_to_buf_by_cache(mem_space, &None, iovec, buf) +} + +pub fn iov_to_buf_by_cache( + mem_space: &AddressSpace, + cache: &Option, + iovec: &[ElemIovec], + buf: &mut [u8], +) -> Result { let mut start: usize = 0; let mut end: usize = 0; for iov in iovec { let mut addr_map = Vec::new(); - mem_space.get_address_map(iov.addr, iov.len as u64, &mut addr_map)?; + mem_space.get_address_map(cache, iov.addr, iov.len as u64, &mut addr_map)?; for addr in addr_map.into_iter() { end = cmp::min(start + addr.iov_len as usize, buf.len()); mem_to_buf(&mut buf[start..end], addr.iov_base)?; @@ -839,12 +848,20 @@ pub fn iov_discard_back(iovec: &mut [ElemIovec], mut size: u64) -> Option<&mut [ fn gpa_hva_iovec_map( gpa_elemiovec: &[ElemIovec], mem_space: &AddressSpace, +) -> Result<(u64, Vec)> { + gpa_hva_iovec_map_by_cache(gpa_elemiovec, mem_space, &None) +} + +fn gpa_hva_iovec_map_by_cache( + gpa_elemiovec: &[ElemIovec], + mem_space: &AddressSpace, + cache: &Option, ) -> Result<(u64, Vec)> { let mut iov_size = 0; let mut hva_iovec = Vec::with_capacity(gpa_elemiovec.len()); for elem in gpa_elemiovec.iter() { - mem_space.get_address_map(elem.addr, elem.len as u64, &mut hva_iovec)?; + mem_space.get_address_map(cache, elem.addr, elem.len as u64, &mut hva_iovec)?; iov_size += elem.len as u64; } -- Gitee From 8e627edbb1d74b8fb2f6a4eb47fcba43f7de8279 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Mon, 29 Apr 2024 03:45:08 +0800 Subject: [PATCH 044/489] machine_manager: using local variable instead of `mut` input parameter Using local variable is more semantically consistent than using `mut` input parameter. Signed-off-by: liuxiangdong --- machine_manager/src/config/mod.rs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index 6863bac4..ab8e687a 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -768,9 +768,10 @@ macro_rules! check_arg_nonexist{ pub fn str_slip_to_clap( args: &str, first_pos_is_type: bool, - mut first_pos_is_subcommand: bool, + first_pos_is_subcommand: bool, ) -> Vec { - let args_str = if first_pos_is_type && !first_pos_is_subcommand { + let mut subcommand = first_pos_is_subcommand; + let args_str = if first_pos_is_type && !subcommand { format!("classtype={}", args) } else { args.to_string() @@ -783,9 +784,9 @@ pub fn str_slip_to_clap( // Command line like "key" will be converted to "--key". for (cnt, param) in key_value.iter().enumerate() { if cnt % 2 == 0 { - if first_pos_is_subcommand { + if subcommand { itr.push(param.to_string()); - first_pos_is_subcommand = false; + subcommand = false; } else { itr.push(format!("--{}", param)); } -- Gitee From ea171f65ad11f367e4a68ef7463e24d065a84dee Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Mon, 29 Apr 2024 04:07:44 +0800 Subject: [PATCH 045/489] global: use clap to parse the parameters of the global config Use clap to parse the parameters of the global config. Signed-off-by: liuxiangdong --- machine_manager/src/config/mod.rs | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index ab8e687a..51b8bf4c 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -98,6 +98,13 @@ pub const MAX_QUEUE_SIZE_BLOCK_DEVICE: u64 = 1024; /// The bar0 size of enable_bar0 features pub const VIRTIO_GPU_ENABLE_BAR0_SIZE: u64 = 64 * M; +#[derive(Parser)] +#[command(no_binary_name(true))] +struct GlobalConfig { + #[arg(long, alias = "pcie-root-port.fast-unplug", value_parser = ["0", "1"])] + fast_unplug: Option, +} + #[derive(Clone, Default, Debug, Serialize, Deserialize)] pub struct ObjectConfig { pub rng_object: HashMap, @@ -243,24 +250,18 @@ impl VmConfig { /// /// * `global_config` - The args of global config. pub fn add_global_config(&mut self, global_config: &str) -> Result<()> { - let mut cmd_parser = CmdParser::new("global"); - cmd_parser.push("pcie-root-port.fast-unplug"); - cmd_parser.parse(global_config)?; + let global_config = + GlobalConfig::try_parse_from(str_slip_to_clap(global_config, false, false))?; - if let Some(fast_unplug_value) = - cmd_parser.get_value::("pcie-root-port.fast-unplug")? - { - if fast_unplug_value != FAST_UNPLUG_ON && fast_unplug_value != FAST_UNPLUG_OFF { - bail!("The value of fast-unplug is invalid: {}", fast_unplug_value); - } + if let Some(fast_unplug_value) = global_config.fast_unplug { let fast_unplug_key = String::from("pcie-root-port.fast-unplug"); - if self.global_config.get(&fast_unplug_key).is_none() { - self.global_config - .insert(fast_unplug_key, fast_unplug_value); - } else { + if self.global_config.get(&fast_unplug_key).is_some() { bail!("Global config {} has been added", fast_unplug_key); } + self.global_config + .insert(fast_unplug_key, fast_unplug_value); } + Ok(()) } -- Gitee From fc0e640e39c0496b175473733708b895680f6616 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Mon, 29 Apr 2024 16:26:09 +0800 Subject: [PATCH 046/489] mem-backend: use clap to parse the parameters of the mem-backend config Use clap to parse the parameters of the mem-backend config. Signed-off-by: liuxiangdong --- address_space/src/host_mmap.rs | 2 +- machine_manager/src/config/drive.rs | 12 +- machine_manager/src/config/machine_config.rs | 242 ++++++------------- machine_manager/src/config/mod.rs | 20 +- 4 files changed, 85 insertions(+), 191 deletions(-) diff --git a/address_space/src/host_mmap.rs b/address_space/src/host_mmap.rs index ed2ce2e9..da850b03 100644 --- a/address_space/src/host_mmap.rs +++ b/address_space/src/host_mmap.rs @@ -294,7 +294,7 @@ pub fn create_default_mem(mem_config: &MachineMemConfig, thread_num: u8) -> Resu pub fn create_backend_mem(mem_config: &MemZoneConfig, thread_num: u8) -> Result { let mut f_back: Option = None; - if mem_config.memfd { + if mem_config.memfd() { let anon_fd = memfd_create( &CString::new("stratovirt_anon_mem")?, MemFdCreateFlag::empty(), diff --git a/machine_manager/src/config/drive.rs b/machine_manager/src/config/drive.rs index 3107ce75..e8e1a60c 100644 --- a/machine_manager/src/config/drive.rs +++ b/machine_manager/src/config/drive.rs @@ -20,11 +20,8 @@ use clap::{ArgAction, Parser}; use log::error; use serde::{Deserialize, Serialize}; -use super::{error::ConfigError, M}; -use super::{valid_id, valid_path}; -use crate::config::{ - memory_unit_conversion, parse_bool, str_slip_to_clap, ConfigCheck, VmConfig, MAX_STRING_LENGTH, -}; +use super::{error::ConfigError, parse_size, valid_id, valid_path}; +use crate::config::{parse_bool, str_slip_to_clap, ConfigCheck, VmConfig, MAX_STRING_LENGTH}; use util::aio::{aio_probe, AioEngine, WriteZeroesState}; const MAX_IOPS: u64 = 1_000_000; @@ -90,11 +87,6 @@ impl ToString for DiskFormat { } } -fn parse_size(s: &str) -> Result { - let size = memory_unit_conversion(s, M).with_context(|| format!("Invalid size: {}", s))?; - Ok(size) -} - fn valid_l2_cache_size(s: &str) -> Result { let size = parse_size(s)?; if size > MAX_L2_CACHE_SIZE { diff --git a/machine_manager/src/config/machine_config.rs b/machine_manager/src/config/machine_config.rs index 490ee907..89a40471 100644 --- a/machine_manager/src/config/machine_config.rs +++ b/machine_manager/src/config/machine_config.rs @@ -13,13 +13,12 @@ use std::str::FromStr; use anyhow::{anyhow, bail, Context, Result}; +use clap::{ArgAction, Parser}; use serde::{Deserialize, Serialize}; use super::error::ConfigError; -use crate::config::{ - check_arg_too_long, check_path_too_long, CmdParser, ConfigCheck, ExBool, IntegerList, VmConfig, - MAX_NODES, -}; +use super::{parse_bool, parse_size, str_slip_to_clap, valid_id, valid_path}; +use crate::config::{CmdParser, ConfigCheck, ExBool, IntegerList, VmConfig, MAX_NODES}; use crate::machine::HypervisorType; const DEFAULT_CPUS: u8 = 1; @@ -83,32 +82,37 @@ impl From for HostMemPolicy { } } -#[derive(Clone, Debug, Serialize, Deserialize)] +#[derive(Parser, Clone, Debug, Serialize, Deserialize)] +#[command(no_binary_name(true))] pub struct MemZoneConfig { + #[arg(long, alias = "classtype", value_parser = ["memory-backend-ram", "memory-backend-file", "memory-backend-memfd"])] + pub mem_type: String, + #[arg(long, value_parser = valid_id)] pub id: String, + #[arg(long, value_parser = parse_size)] pub size: u64, - pub host_numa_nodes: Option>, + // Note: + // `Clap` will incorrectly assume that we're trying to get multiple arguments since we got + // a `Vec` from parser function `get_host_nodes`. Generally, we should use `Box` or a `new struct type` + // to encapsulate this `Vec`. And fortunately, there's a trick (using full qualified path of Vec) + // to avoid the new type wrapper. See: github.com/clap-rs/clap/issues/4626. + #[arg(long, alias = "host-nodes", value_parser = get_host_nodes)] + pub host_numa_nodes: Option<::std::vec::Vec>, + #[arg(long, default_value = "default", value_parser=["default", "preferred", "bind", "interleave"])] pub policy: String, + #[arg(long, value_parser = valid_path)] pub mem_path: Option, + #[arg(long, default_value = "true", value_parser = parse_bool, action = ArgAction::Append)] pub dump_guest_core: bool, + #[arg(long, default_value = "off", value_parser = parse_bool, action = ArgAction::Append)] pub share: bool, + #[arg(long, alias = "mem-prealloc", default_value = "false", value_parser = parse_bool, action = ArgAction::Append)] pub prealloc: bool, - pub memfd: bool, } -impl Default for MemZoneConfig { - fn default() -> Self { - MemZoneConfig { - id: String::new(), - size: 0, - host_numa_nodes: None, - policy: String::from("bind"), - mem_path: None, - dump_guest_core: true, - share: false, - prealloc: false, - memfd: false, - } +impl MemZoneConfig { + pub fn memfd(&self) -> bool { + self.mem_type.eq("memory-backend-memfd") } } @@ -461,149 +465,26 @@ impl VmConfig { } impl VmConfig { - fn get_mem_zone_id(&self, cmd_parser: &CmdParser) -> Result { - if let Some(id) = cmd_parser.get_value::("id")? { - check_arg_too_long(&id, "id")?; - Ok(id) - } else { - Err(anyhow!(ConfigError::FieldIsMissing( - "id".to_string(), - "memory-backend-ram".to_string() - ))) - } - } - - fn get_mem_path(&self, cmd_parser: &CmdParser) -> Result> { - if let Some(path) = cmd_parser.get_value::("mem-path")? { - check_path_too_long(&path, "mem-path")?; - return Ok(Some(path)); - } - Ok(None) - } - - fn get_mem_zone_size(&self, cmd_parser: &CmdParser) -> Result { - if let Some(mem) = cmd_parser.get_value::("size")? { - let size = memory_unit_conversion(&mem, M)?; - Ok(size) - } else { - Err(anyhow!(ConfigError::FieldIsMissing( - "size".to_string(), - "memory-backend-ram".to_string() - ))) - } - } - - fn get_mem_zone_host_nodes(&self, cmd_parser: &CmdParser) -> Result>> { - if let Some(mut host_nodes) = cmd_parser - .get_value::("host-nodes") - .with_context(|| { - ConfigError::ConvertValueFailed(String::from("u32"), "host-nodes".to_string()) - })? - .map(|v| v.0.iter().map(|e| *e as u32).collect::>()) - { - host_nodes.sort_unstable(); - if host_nodes[host_nodes.len() - 1] >= MAX_NODES { - return Err(anyhow!(ConfigError::IllegalValue( - "host_nodes".to_string(), - 0, - true, - MAX_NODES as u64, - false, - ))); - } - Ok(Some(host_nodes)) - } else { - Ok(None) - } - } - - fn get_mem_zone_policy(&self, cmd_parser: &CmdParser) -> Result { - let policy = cmd_parser - .get_value::("policy")? - .unwrap_or_else(|| "default".to_string()); - if HostMemPolicy::from(policy.clone()) == HostMemPolicy::NotSupported { - return Err(anyhow!(ConfigError::InvalidParam( - "policy".to_string(), - policy - ))); - } - Ok(policy) - } - - fn get_mem_share(&self, cmd_parser: &CmdParser) -> Result { - let share = cmd_parser - .get_value::("share")? - .unwrap_or_else(|| "off".to_string()); - - if share.eq("on") || share.eq("off") { - Ok(share.eq("on")) - } else { - Err(anyhow!(ConfigError::InvalidParam( - "share".to_string(), - share - ))) - } - } - - fn get_mem_dump(&self, cmd_parser: &CmdParser) -> Result { - if let Some(dump_guest) = cmd_parser.get_value::("dump-guest-core")? { - return Ok(dump_guest.into()); - } - Ok(true) - } - - fn get_mem_prealloc(&self, cmd_parser: &CmdParser) -> Result { - if let Some(mem_prealloc) = cmd_parser.get_value::("mem-prealloc")? { - return Ok(mem_prealloc.into()); - } - Ok(false) - } - /// Convert memory zone cmdline to VM config /// /// # Arguments /// /// * `mem_zone` - The memory zone cmdline string. - /// * `mem_type` - The memory zone type - pub fn add_mem_zone(&mut self, mem_zone: &str, mem_type: String) -> Result { - let mut cmd_parser = CmdParser::new("mem_zone"); - cmd_parser - .push("") - .push("id") - .push("size") - .push("host-nodes") - .push("policy") - .push("share") - .push("mem-path") - .push("dump-guest-core") - .push("mem-prealloc"); - cmd_parser.parse(mem_zone)?; - - let zone_config = MemZoneConfig { - id: self.get_mem_zone_id(&cmd_parser)?, - size: self.get_mem_zone_size(&cmd_parser)?, - host_numa_nodes: self.get_mem_zone_host_nodes(&cmd_parser)?, - policy: self.get_mem_zone_policy(&cmd_parser)?, - dump_guest_core: self.get_mem_dump(&cmd_parser)?, - share: self.get_mem_share(&cmd_parser)?, - mem_path: self.get_mem_path(&cmd_parser)?, - prealloc: self.get_mem_prealloc(&cmd_parser)?, - memfd: mem_type.eq("memory-backend-memfd"), - }; + pub fn add_mem_zone(&mut self, mem_zone: &str) -> Result { + let zone_config = MemZoneConfig::try_parse_from(str_slip_to_clap(mem_zone, true, false))?; - if (zone_config.mem_path.is_none() && mem_type.eq("memory-backend-file")) - || (zone_config.mem_path.is_some() && mem_type.ne("memory-backend-file")) + if (zone_config.mem_path.is_none() && zone_config.mem_type.eq("memory-backend-file")) + || (zone_config.mem_path.is_some() && zone_config.mem_type.ne("memory-backend-file")) { - bail!("Object type: {} config path err", mem_type); + bail!("Object type: {} config path err", zone_config.mem_type); } - if self.object.mem_object.get(&zone_config.id).is_none() { - self.object - .mem_object - .insert(zone_config.id.clone(), zone_config.clone()); - } else { + if self.object.mem_object.get(&zone_config.id).is_some() { bail!("Object: {} has been added", zone_config.id); } + self.object + .mem_object + .insert(zone_config.id.clone(), zone_config.clone()); if zone_config.host_numa_nodes.is_none() { return Ok(zone_config); @@ -740,6 +621,34 @@ fn get_inner(outer: Option) -> Result { outer.with_context(|| ConfigError::IntegerOverflow("-m".to_string())) } +fn get_host_nodes(nodes: &str) -> Result> { + let mut host_nodes = IntegerList::from_str(nodes) + .with_context(|| { + ConfigError::ConvertValueFailed(String::from("u32"), "host-nodes".to_string()) + })? + .0 + .iter() + .map(|e| *e as u32) + .collect::>(); + + if host_nodes.is_empty() { + bail!("Got empty host nodes list!"); + } + + host_nodes.sort_unstable(); + if host_nodes[host_nodes.len() - 1] >= MAX_NODES { + return Err(anyhow!(ConfigError::IllegalValue( + "host_nodes".to_string(), + 0, + true, + MAX_NODES as u64, + false, + ))); + } + + Ok(host_nodes) +} + #[cfg(test)] mod tests { use super::*; @@ -1089,10 +998,7 @@ mod tests { fn test_add_mem_zone() { let mut vm_config = VmConfig::default(); let zone_config_1 = vm_config - .add_mem_zone( - "-object memory-backend-ram,size=2G,id=mem1,host-nodes=1,policy=bind", - String::from("memory-backend-ram"), - ) + .add_mem_zone("memory-backend-ram,size=2G,id=mem1,host-nodes=1,policy=bind") .unwrap(); assert_eq!(zone_config_1.id, "mem1"); assert_eq!(zone_config_1.size, 2147483648); @@ -1100,38 +1006,26 @@ mod tests { assert_eq!(zone_config_1.policy, "bind"); let zone_config_2 = vm_config - .add_mem_zone( - "-object memory-backend-ram,size=2G,id=mem2,host-nodes=1-2,policy=default", - String::from("memory-backend-ram"), - ) + .add_mem_zone("memory-backend-ram,size=2G,id=mem2,host-nodes=1-2,policy=default") .unwrap(); assert_eq!(zone_config_2.host_numa_nodes, Some(vec![1, 2])); let zone_config_3 = vm_config - .add_mem_zone( - "-object memory-backend-ram,size=2M,id=mem3,share=on", - String::from("memory-backend-ram"), - ) + .add_mem_zone("memory-backend-ram,size=2M,id=mem3,share=on") .unwrap(); assert_eq!(zone_config_3.size, 2 * 1024 * 1024); assert_eq!(zone_config_3.share, true); let zone_config_4 = vm_config - .add_mem_zone( - "-object memory-backend-ram,size=2M,id=mem4", - String::from("memory-backend-ram"), - ) + .add_mem_zone("memory-backend-ram,size=2M,id=mem4") .unwrap(); assert_eq!(zone_config_4.share, false); - assert_eq!(zone_config_4.memfd, false); + assert_eq!(zone_config_4.memfd(), false); let zone_config_5 = vm_config - .add_mem_zone( - "-object memory-backend-memfd,size=2M,id=mem5", - String::from("memory-backend-memfd"), - ) + .add_mem_zone("memory-backend-memfd,size=2M,id=mem5") .unwrap(); - assert_eq!(zone_config_5.memfd, true); + assert_eq!(zone_config_5.memfd(), true); } #[test] diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index 51b8bf4c..da327e1f 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -226,7 +226,7 @@ impl VmConfig { self.object.rng_object.insert(id, rng_cfg); } "memory-backend-ram" | "memory-backend-file" | "memory-backend-memfd" => { - self.add_mem_zone(object_args, device_type)?; + self.add_mem_zone(object_args)?; } #[cfg(feature = "vnc_auth")] "tls-creds-x509" => { @@ -657,7 +657,7 @@ impl FromStr for UnsignedInteger { pub struct IntegerList(pub Vec); impl FromStr for IntegerList { - type Err = (); + type Err = anyhow::Error; fn from_str(s: &str) -> std::result::Result { let mut integer_list = Vec::new(); @@ -669,19 +669,22 @@ impl FromStr for IntegerList { for list in lists.iter() { let items: Vec<&str> = list.split('-').collect(); if items.len() > 2 { - return Err(()); + return Err(anyhow!( + "{} parameters connected by -, should be no more than 2.", + items.len() + )); } let start = items[0] .parse::() - .map_err(|e| error!("Invalid value {}, error is {:?}", items[0], e))?; + .map_err(|e| anyhow!("Invalid value {}, error is {:?}", items[0], e))?; integer_list.push(start); if items.len() == 2 { let end = items[1] .parse::() - .map_err(|e| error!("Invalid value {}, error is {:?}", items[1], e))?; + .map_err(|e| anyhow!("Invalid value {}, error is {:?}", items[1], e))?; if start >= end { - return Err(()); + return Err(anyhow!("start {} is bigger than end {}.", start, end)); } for i in start..end { @@ -867,6 +870,11 @@ pub fn valid_block_device_virtqueue_size(s: &str) -> Result { Ok(size as u16) } +pub fn parse_size(s: &str) -> Result { + let size = memory_unit_conversion(s, M).with_context(|| format!("Invalid size: {}", s))?; + Ok(size) +} + #[cfg(test)] mod tests { use super::*; -- Gitee From 83b4aa755a652a9f3589a725dd1001a862fef580 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Mon, 29 Apr 2024 16:35:16 +0800 Subject: [PATCH 047/489] machine_manager: delete useless function get_multi_function Delete useless function get_multi_function. Signed-off-by: liuxiangdong --- machine_manager/src/config/pci.rs | 37 ------------------------------- 1 file changed, 37 deletions(-) diff --git a/machine_manager/src/config/pci.rs b/machine_manager/src/config/pci.rs index ce53656e..cad97dec 100644 --- a/machine_manager/src/config/pci.rs +++ b/machine_manager/src/config/pci.rs @@ -89,21 +89,6 @@ pub fn get_pci_bdf(pci_cfg: &str) -> Result { Ok(pci_bdf) } -pub fn get_multi_function(pci_cfg: &str) -> Result { - let mut cmd_parser = CmdParser::new("multifunction"); - cmd_parser.push("").push("multifunction"); - cmd_parser.get_parameters(pci_cfg)?; - - if let Some(multi_func) = cmd_parser - .get_value::("multifunction") - .with_context(|| "Failed to get multifunction parameter, please set on or off (default).")? - { - return Ok(multi_func.inner); - } - - Ok(false) -} - pub fn pci_args_check(cmd_parser: &CmdParser) -> Result<()> { let device_type = cmd_parser.get_value::("")?; let dev_type = device_type.unwrap(); @@ -183,26 +168,4 @@ mod tests { let pci_bdf = get_pci_bdf("virtio-balloon-device,addr=0x1.0x2"); assert!(pci_bdf.is_err()); } - - #[test] - fn test_get_multi_function() { - assert_eq!( - get_multi_function("virtio-balloon-device,bus=pcie.0,addr=0x1.0x2").unwrap(), - false - ); - assert_eq!( - get_multi_function("virtio-balloon-device,bus=pcie.0,addr=0x1.0x2,multifunction=on") - .unwrap(), - true - ); - assert_eq!( - get_multi_function("virtio-balloon-device,bus=pcie.0,addr=0x1.0x2,multifunction=off") - .unwrap(), - false - ); - assert!(get_multi_function( - "virtio-balloon-device,bus=pcie.0,addr=0x1.0x2,multifunction=close" - ) - .is_err()); - } } -- Gitee From 34770fd3a199b5c86c46f15b8c585edbc6e4ed83 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Mon, 29 Apr 2024 18:57:02 +0800 Subject: [PATCH 048/489] trace: use clap to parse the parameters of the trace config Use clap to parse the parameters of the trace config. Signed-off-by: liuxiangdong --- machine_manager/src/cmdline.rs | 4 ++-- machine_manager/src/config/mod.rs | 27 ++++++++++++++------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/machine_manager/src/cmdline.rs b/machine_manager/src/cmdline.rs index 65907018..c9f54f6e 100644 --- a/machine_manager/src/cmdline.rs +++ b/machine_manager/src/cmdline.rs @@ -13,7 +13,7 @@ use anyhow::{bail, Context, Result}; use crate::{ - config::{parse_trace_options, ChardevType, CmdParser, MachineType, SocketType, VmConfig}, + config::{add_trace, ChardevType, CmdParser, MachineType, SocketType, VmConfig}, qmp::qmp_socket::QmpSocketPath, temp_cleaner::TempCleaner, }; @@ -587,7 +587,7 @@ pub fn create_vmconfig(args: &ArgMatches) -> Result { add_args_to_config_multi!((args.values_of("cameradev")), vm_cfg, add_camera_backend); add_args_to_config_multi!((args.values_of("smbios")), vm_cfg, add_smbios); if let Some(opt) = args.value_of("trace") { - parse_trace_options(&opt)?; + add_trace(&opt)?; } // Check the mini-set for Vm to start is ok diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index da327e1f..0355a6b9 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -628,15 +628,16 @@ fn enable_trace_state(path: &str) -> Result<()> { Ok(()) } -pub fn parse_trace_options(opt: &str) -> Result<()> { - let mut cmd_parser = CmdParser::new("trace"); - cmd_parser.push("file"); - cmd_parser.get_parameters(opt)?; - - let path = cmd_parser - .get_value::("file")? - .with_context(|| "trace: trace file must be set.")?; - enable_trace_state(&path)?; +#[derive(Parser)] +#[command(no_binary_name(true))] +struct TraceConfig { + #[arg(long)] + file: String, +} + +pub fn add_trace(opt: &str) -> Result<()> { + let trace_cfg = TraceConfig::try_parse_from(str_slip_to_clap(opt, false, false))?; + enable_trace_state(&trace_cfg.file)?; Ok(()) } @@ -968,10 +969,10 @@ mod tests { } #[test] - fn test_parse_trace_options() { - assert!(parse_trace_options("fil=test_trace").is_err()); - assert!(parse_trace_options("file").is_err()); - assert!(parse_trace_options("file=test_trace").is_err()); + fn test_add_trace() { + assert!(add_trace("fil=test_trace").is_err()); + assert!(add_trace("file").is_err()); + assert!(add_trace("file=test_trace").is_err()); } #[test] -- Gitee From 5f4ebf08282afa2fa41930885a1fabae73568596 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Mon, 29 Apr 2024 20:56:42 +0800 Subject: [PATCH 049/489] cpu-features: use clap to parse the parameters of the cpu features config Use clap to parse the parameters of the cpu features config. Signed-off-by: liuxiangdong --- machine_manager/src/config/machine_config.rs | 81 +++++++++++++------- 1 file changed, 52 insertions(+), 29 deletions(-) diff --git a/machine_manager/src/config/machine_config.rs b/machine_manager/src/config/machine_config.rs index 89a40471..fa277b03 100644 --- a/machine_manager/src/config/machine_config.rs +++ b/machine_manager/src/config/machine_config.rs @@ -140,9 +140,14 @@ impl Default for MachineMemConfig { } } -#[derive(Clone, Debug, Serialize, Deserialize, Default)] +#[derive(Parser, Clone, Debug, Serialize, Deserialize, Default)] +#[command(no_binary_name(true))] pub struct CpuConfig { + #[arg(long, alias = "classtype", value_parser = ["host"])] + pub family: String, + #[arg(long, default_value = "off")] pub pmu: PmuConfig, + #[arg(long, default_value = "off")] pub sve: SveConfig, } @@ -153,6 +158,20 @@ pub enum PmuConfig { Off, } +impl FromStr for PmuConfig { + type Err = anyhow::Error; + + fn from_str(s: &str) -> std::result::Result { + match s { + "on" => Ok(PmuConfig::On), + "off" => Ok(PmuConfig::Off), + _ => Err(anyhow!( + "Invalid PMU option,must be one of \'on\" or \"off\"." + )), + } + } +} + #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq, Default)] pub enum SveConfig { On, @@ -160,6 +179,20 @@ pub enum SveConfig { Off, } +impl FromStr for SveConfig { + type Err = anyhow::Error; + + fn from_str(s: &str) -> std::result::Result { + match s { + "on" => Ok(SveConfig::On), + "off" => Ok(SveConfig::Off), + _ => Err(anyhow!( + "Invalid SVE option, must be one of \"on\" or \"off\"." + )), + } + } +} + #[derive(Serialize, Deserialize, Debug, Copy, Clone, PartialEq, Eq, Default)] pub enum ShutdownAction { #[default] @@ -418,28 +451,8 @@ impl VmConfig { } pub fn add_cpu_feature(&mut self, features: &str) -> Result<()> { - let mut cmd_parser = CmdParser::new("cpu"); - cmd_parser.push(""); - cmd_parser.push("pmu"); - cmd_parser.push("sve"); - cmd_parser.parse(features)?; - - // Check PMU when actually enabling PMU. - if let Some(k) = cmd_parser.get_value::("pmu")? { - self.machine_config.cpu_config.pmu = match k.as_ref() { - "on" => PmuConfig::On, - "off" => PmuConfig::Off, - _ => bail!("Invalid PMU option,must be one of \'on\" or \"off\"."), - } - } - - if let Some(k) = cmd_parser.get_value::("sve")? { - self.machine_config.cpu_config.sve = match k.as_ref() { - "on" => SveConfig::On, - "off" => SveConfig::Off, - _ => bail!("Invalid SVE option, must be one of \"on\" or \"off\"."), - } - } + let cpu_config = CpuConfig::try_parse_from(str_slip_to_clap(features, true, false))?; + self.machine_config.cpu_config = cpu_config; Ok(()) } @@ -1049,15 +1062,25 @@ mod tests { assert!(vm_config.machine_config.cpu_config.pmu == PmuConfig::Off); vm_config.add_cpu_feature("host,pmu=off").unwrap(); assert!(vm_config.machine_config.cpu_config.pmu == PmuConfig::Off); - vm_config.add_cpu_feature("pmu=off").unwrap(); - assert!(vm_config.machine_config.cpu_config.pmu == PmuConfig::Off); vm_config.add_cpu_feature("host,pmu=on").unwrap(); assert!(vm_config.machine_config.cpu_config.pmu == PmuConfig::On); - vm_config.add_cpu_feature("pmu=on").unwrap(); - assert!(vm_config.machine_config.cpu_config.pmu == PmuConfig::On); - vm_config.add_cpu_feature("sve=on").unwrap(); + vm_config.add_cpu_feature("host,sve=on").unwrap(); assert!(vm_config.machine_config.cpu_config.sve == SveConfig::On); - vm_config.add_cpu_feature("sve=off").unwrap(); + vm_config.add_cpu_feature("host,sve=off").unwrap(); assert!(vm_config.machine_config.cpu_config.sve == SveConfig::Off); + + // Illegal cpu command lines: should set cpu family. + let result = vm_config.add_cpu_feature("pmu=off"); + assert!(result.is_err()); + let result = vm_config.add_cpu_feature("sve=on"); + assert!(result.is_err()); + + // Illegal parameters. + let result = vm_config.add_cpu_feature("host,sve1=on"); + assert!(result.is_err()); + + // Illegal values. + let result = vm_config.add_cpu_feature("host,sve=false"); + assert!(result.is_err()); } } -- Gitee From 57cc965ba34cb7b8dfcb9bb1d4603625e6ec7498 Mon Sep 17 00:00:00 2001 From: Mingwang Li Date: Thu, 16 May 2024 17:34:51 +0800 Subject: [PATCH 050/489] trace: add trace for fwcfg Signed-off-by: Mingwang Li --- devices/src/legacy/fwcfg.rs | 21 +++++++++++++++------ trace/trace_info/device_legacy.toml | 24 ++++++++++++++++++++++++ 2 files changed, 39 insertions(+), 6 deletions(-) diff --git a/devices/src/legacy/fwcfg.rs b/devices/src/legacy/fwcfg.rs index 2abf4368..e675fb7d 100644 --- a/devices/src/legacy/fwcfg.rs +++ b/devices/src/legacy/fwcfg.rs @@ -361,11 +361,14 @@ impl FwCfgCommon { /// Select the entry by the key specified fn select_entry(&mut self, key: u16) { + let ret; self.cur_offset = 0; if (key & FW_CFG_ENTRY_MASK) >= self.max_entry() { self.cur_entry = FW_CFG_INVALID; + ret = 0; } else { self.cur_entry = key; + ret = 1; // unwrap() is safe because we have checked the range of `key`. let selected_entry = self.get_entry_mut().unwrap(); @@ -373,6 +376,8 @@ impl FwCfgCommon { cb.select_callback(); } } + + trace::fwcfg_select_entry(key, get_key_name(key as usize), ret); } fn add_entry( @@ -404,11 +409,12 @@ impl FwCfgCommon { warn!("Entry not empty, will override"); } - entry.data = data; + entry.data = data.clone(); entry.select_cb = select_cb; entry.allow_write = allow_write; entry.write_cb = write_cb; + trace::fwcfg_add_entry(key, get_key_name(key as usize), data); Ok(()) } @@ -467,11 +473,8 @@ impl FwCfgCommon { } } - let file = FwCfgFile::new( - data.len() as u32, - FW_CFG_FILE_FIRST + index as u16, - filename, - ); + let data_len = data.len(); + let file = FwCfgFile::new(data_len as u32, FW_CFG_FILE_FIRST + index as u16, filename); self.files.insert(index, file); self.files.iter_mut().skip(index + 1).for_each(|f| { f.select += 1; @@ -489,6 +492,8 @@ impl FwCfgCommon { FW_CFG_FILE_FIRST as usize + index, FwCfgEntry::new(data, select_cb, write_cb, allow_write), ); + + trace::fwcfg_add_file(index, filename, data_len); Ok(()) } @@ -650,6 +655,8 @@ impl FwCfgCommon { self.cur_offset = offset; write_dma_result(&self.mem_space, dma_addr, dma.control)?; + + trace::fwcfg_read_data(0); Ok(()) } @@ -743,6 +750,8 @@ impl FwCfgCommon { value <<= 8 * size as u64; } self.cur_offset = cur_offset; + + trace::fwcfg_read_data(value); Ok(value) } diff --git a/trace/trace_info/device_legacy.toml b/trace/trace_info/device_legacy.toml index 14ed9433..42bbae08 100644 --- a/trace/trace_info/device_legacy.toml +++ b/trace/trace_info/device_legacy.toml @@ -201,3 +201,27 @@ name = "pflash_write_data" args = "offset: u64, size: usize, value: &[u8], counter: u32" message = "data offset: 0x{:04x}, size: {}, value: 0x{:x?}, counter: 0x{:04x}" enabled = true + +[[events]] +name = "fwcfg_select_entry" +args = "key: u16, key_name: &'static str, ret: i32" +message = "key_value {} key_name {:?} ret {}" +enabled = true + +[[events]] +name = "fwcfg_add_entry" +args = "key: u16, key_name: &'static str, data: Vec" +message = "key_value {} key_name {:?} data {:?}" +enabled = true + +[[events]] +name = "fwcfg_read_data" +args = "value: u64" +message = "value {}" +enabled = true + +[[events]] +name = "fwcfg_add_file" +args = "index: usize, filename: &str, data_len: usize" +message = "index {} filename {:?} data_len {}" +enabled = true -- Gitee From 2768a4e69147b9368b5e835bb92ae629b7365978 Mon Sep 17 00:00:00 2001 From: Jinhao Gao Date: Thu, 16 May 2024 16:31:44 +0800 Subject: [PATCH 051/489] Build: Add debug option for building release version Add debug option of profile in cargo.toml for building release version with more debug information like symbal table. Signed-off-by: Jinhao Gao --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index a82f9b79..b00a2da0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -55,3 +55,4 @@ panic = "abort" [profile.release] panic = "abort" lto = true +debug = true -- Gitee From c9f615b212db77d3fe615c3fe218bf168fae62f9 Mon Sep 17 00:00:00 2001 From: Mingwang Li Date: Thu, 16 May 2024 21:49:53 +0800 Subject: [PATCH 052/489] trace: add trace for ged and power Signed-off-by: Mingwang Li --- devices/src/acpi/ged.rs | 4 ++++ devices/src/acpi/power.rs | 3 +++ trace/trace_info/acpi.toml | 23 +++++++++++++++++++++++ 3 files changed, 30 insertions(+) create mode 100644 trace/trace_info/acpi.toml diff --git a/devices/src/acpi/ged.rs b/devices/src/acpi/ged.rs index f50e1b11..55e5ba0f 100644 --- a/devices/src/acpi/ged.rs +++ b/devices/src/acpi/ged.rs @@ -122,6 +122,7 @@ impl Ged { .notification_type .store(AcpiEvent::PowerDown as u32, Ordering::SeqCst); ged_clone.inject_interrupt(); + trace::ged_inject_acpi_event(AcpiEvent::PowerDown as u32); if QmpChannel::is_connected() { event!(Powerdown); } @@ -151,6 +152,7 @@ impl Ged { .notification_type .store(AcpiEvent::CpuResize as u32, Ordering::SeqCst); clone_ged.inject_interrupt(); + trace::ged_inject_acpi_event(AcpiEvent::CpuResize as u32); if QmpChannel::is_connected() { event!(CpuResize); } @@ -174,6 +176,7 @@ impl Ged { self.notification_type .fetch_or(evt as u32, Ordering::SeqCst); self.inject_interrupt(); + trace::ged_inject_acpi_event(evt as u32); } } @@ -203,6 +206,7 @@ impl SysBusDevOps for Ged { let value = self .notification_type .swap(AcpiEvent::Nothing as u32, Ordering::SeqCst); + trace::ged_read(value); write_data_u32(data, value) } diff --git a/devices/src/acpi/power.rs b/devices/src/acpi/power.rs index a51071d8..5d5685d3 100644 --- a/devices/src/acpi/power.rs +++ b/devices/src/acpi/power.rs @@ -154,6 +154,8 @@ impl PowerDev { // unit: mW self.regs[REG_IDX_BAT_PRATE] = (self.regs[REG_IDX_BAT_PRATE] * self.regs[REG_IDX_BAT_PVOLT]) / 1000; + + trace::power_status_read(&self.regs); Ok(()) } @@ -253,6 +255,7 @@ impl SysBusDevOps for PowerDev { return false; } let value = self.regs[reg_idx as usize]; + trace::power_read(reg_idx, value); write_data_u32(data, value) } diff --git a/trace/trace_info/acpi.toml b/trace/trace_info/acpi.toml new file mode 100644 index 00000000..9b4352aa --- /dev/null +++ b/trace/trace_info/acpi.toml @@ -0,0 +1,23 @@ +[[events]] +name = "ged_inject_acpi_event" +args = "event: u32" +message = "acpi_sevent {}" +enabled = true + +[[events]] +name = "ged_read" +args = "event: u32" +message = "acpi_sevent {}" +enabled = true + +[[events]] +name = "power_read" +args = "reg_idx: u64, value: u32" +message = "reg_idx {} value {}" +enabled = true + +[[events]] +name = "power_status_read" +args = "regs: &dyn fmt::Debug" +message = "regs {:?}" +enabled = true -- Gitee From aeffab78f2c209b9c6ba78402651b68c2ade6cc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A5=9A=E5=BD=B1?= Date: Fri, 17 May 2024 11:05:02 +0800 Subject: [PATCH 053/489] oh camera fmt Signed-off-by: Jiahong Li --- devices/src/camera_backend/demo.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devices/src/camera_backend/demo.rs b/devices/src/camera_backend/demo.rs index 0640c781..19b1d4da 100644 --- a/devices/src/camera_backend/demo.rs +++ b/devices/src/camera_backend/demo.rs @@ -549,7 +549,7 @@ fn convert_to_nv12(source: &[u8], width: u32, height: u32) -> Vec { source[idx + 2] as f32, ); let y = (0.299 * r + 0.587 * g + 0.114 * b) as u8; - img_nv12.push(y as u8); + img_nv12.push(y); } for i in 0..(width * height / 2) { let idx = (i * 2 * pixel) as usize; -- Gitee From b0a336ed026fa8bfdae1ebd9a53461824b4ae5d7 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Fri, 17 May 2024 15:00:17 +0800 Subject: [PATCH 054/489] event-loop: introduce new operations to update event This patch introduces two operations to add/delete events from current event table for a file descriptor. Signed-off-by: Zhao Yi Min --- util/src/loop_context.rs | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/util/src/loop_context.rs b/util/src/loop_context.rs index 10e4cf70..ecad86e2 100644 --- a/util/src/loop_context.rs +++ b/util/src/loop_context.rs @@ -54,6 +54,10 @@ pub enum NotifierOperation { Park = 16, /// Resume a file descriptor from the event table Resume = 32, + /// Add events to current event table for a file descriptor + AddEvents = 64, + /// Delete events from current event table for a file descriptor + DeleteEvents = 128, } #[derive(Debug, PartialEq)] @@ -466,6 +470,35 @@ impl EventLoopContext { Ok(()) } + fn update_events_for_fd(&mut self, event: &EventNotifier, add: bool) -> Result<()> { + let mut events_map = self.events.write().unwrap(); + match events_map.get_mut(&event.raw_fd) { + Some(notifier) => { + let new_events = if add { + event.event | notifier.event + } else { + !event.event & notifier.event + }; + if new_events != notifier.event { + self.epoll + .ctl( + ControlOperation::Modify, + notifier.raw_fd, + EpollEvent::new(new_events, &**notifier as *const _ as u64), + ) + .with_context(|| { + format!("Failed to add events, event fd: {}", notifier.raw_fd) + })?; + notifier.event = new_events; + } + } + _ => { + return Err(anyhow!(UtilError::NoRegisterFd(event.raw_fd))); + } + } + Ok(()) + } + /// update fds registered to `EventLoop` according to the operation type. /// /// # Arguments @@ -490,6 +523,12 @@ impl EventLoopContext { NotifierOperation::Resume => { self.resume_event(&en)?; } + NotifierOperation::AddEvents => { + self.update_events_for_fd(&en, true)?; + } + NotifierOperation::DeleteEvents => { + self.update_events_for_fd(&en, false)?; + } } } self.kick(); -- Gitee From 7563490d9a8f9786e55458f375371d6ee76de6df Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Thu, 16 May 2024 11:40:34 +0800 Subject: [PATCH 055/489] virtio-serial: fixup data discard issue when socket is blocked If the peer of chardev receives data too slowly, output fd of chardev might be blocked. This makes the data discarded. This patch introduces an output buffer to save left data. When blocked error occurs, add output stream fd to event poll. After the stream fd can be written, the handler notifies output virtqueue of virtio-serial device to continue sending data. Signed-off-by: Zhao Yi Min --- chardev_backend/src/chardev.rs | 73 +++++++++++++++++-- virtio/src/device/serial.rs | 127 +++++++++++++++++++++++---------- 2 files changed, 160 insertions(+), 40 deletions(-) diff --git a/chardev_backend/src/chardev.rs b/chardev_backend/src/chardev.rs index 3f34fc61..cf4bb712 100644 --- a/chardev_backend/src/chardev.rs +++ b/chardev_backend/src/chardev.rs @@ -15,6 +15,7 @@ use std::io::{Stdin, Stdout}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::path::PathBuf; use std::rc::Rc; +use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex}; use std::time::Duration; @@ -24,6 +25,7 @@ use nix::fcntl::{fcntl, FcntlArg, OFlag}; use nix::pty::openpty; use nix::sys::termios::{cfmakeraw, tcgetattr, tcsetattr, SetArg, Termios}; use vmm_sys_util::epoll::EventSet; +use vmm_sys_util::eventfd::EventFd; use machine_manager::event_loop::EventLoop; use machine_manager::machine::{PathInfo, PTY_PATH}; @@ -85,6 +87,10 @@ pub struct Chardev { /// Scheduled DPC to unpause input stream. /// Unpause must be done inside event-loop unpause_timer: Option, + /// output stream fd is blocked + output_blocked: Option>, + /// output listener to notify when output stream fd can be written + output_listener_fd: Option>, } impl Chardev { @@ -100,6 +106,8 @@ impl Chardev { dev: None, wait_port: false, unpause_timer: None, + output_blocked: None, + output_listener_fd: None, } } @@ -222,7 +230,7 @@ impl Chardev { let unpause_fn = Box::new(move || { let res = EventLoop::update_event( vec![EventNotifier::new( - NotifierOperation::Modify, + NotifierOperation::AddEvents, input_fd, None, EventSet::IN | EventSet::HANG_UP, @@ -246,6 +254,33 @@ impl Chardev { self.unpause_timer = None; } } + + pub fn add_listen_for_tx( + &mut self, + listener_fd: Arc, + blocked: Arc, + ) -> Result<()> { + let event_notifier = EventNotifier::new( + NotifierOperation::AddEvents, + self.stream_fd.unwrap(), + None, + EventSet::OUT, + Vec::new(), + ); + + match EventLoop::update_event(vec![event_notifier], None) { + Ok(()) => { + self.output_blocked = Some(blocked.clone()); + self.output_listener_fd = Some(listener_fd); + blocked.store(true, Ordering::Release); + Ok(()) + } + Err(e) => { + blocked.store(false, Ordering::Release); + Err(e) + } + } + } } fn set_pty_raw_mode() -> Result<(i32, PathBuf)> { @@ -438,10 +473,10 @@ fn get_socket_notifier(chardev: Arc>) -> Option { locked_receiver.set_paused(); return Some(vec![EventNotifier::new( - NotifierOperation::Modify, + NotifierOperation::DeleteEvents, stream_fd, None, - EventSet::HANG_UP, + EventSet::IN, vec![], )]); } @@ -471,12 +506,42 @@ fn get_socket_notifier(chardev: Arc>) -> Option { None }); + let handling_chardev = cloned_chardev.clone(); + let output_handler = Rc::new(move |event, fd| { + if event & EventSet::OUT != EventSet::OUT { + return None; + } + + let mut locked_cdev = handling_chardev.lock().unwrap(); + if locked_cdev.output_blocked.is_some() && locked_cdev.output_listener_fd.is_some() { + let fd = locked_cdev.output_listener_fd.as_ref().unwrap(); + if let Err(e) = fd.write(1) { + error!("Failed to write eventfd with error {:?}", e); + return None; + } + locked_cdev + .output_blocked + .as_ref() + .unwrap() + .store(false, Ordering::Release); + locked_cdev.output_blocked = None; + locked_cdev.output_listener_fd = None; + } + Some(vec![EventNotifier::new( + NotifierOperation::DeleteEvents, + fd, + None, + EventSet::OUT, + Vec::new(), + )]) + }); + Some(vec![EventNotifier::new( NotifierOperation::AddShared, stream_fd, Some(listener_fd), EventSet::IN | EventSet::HANG_UP, - vec![input_handler], + vec![input_handler, output_handler], )]) }); diff --git a/virtio/src/device/serial.rs b/virtio/src/device/serial.rs index 3968821c..7d4b11ea 100644 --- a/virtio/src/device/serial.rs +++ b/virtio/src/device/serial.rs @@ -25,8 +25,8 @@ use vmm_sys_util::epoll::EventSet; use vmm_sys_util::eventfd::EventFd; use crate::{ - gpa_hva_iovec_map, iov_discard_front, iov_to_buf, read_config_default, report_virtio_error, - Element, Queue, VirtioBase, VirtioDevice, VirtioError, VirtioInterrupt, VirtioInterruptType, + gpa_hva_iovec_map, iov_to_buf, read_config_default, report_virtio_error, Element, Queue, + VirtioBase, VirtioDevice, VirtioError, VirtioInterrupt, VirtioInterruptType, VIRTIO_CONSOLE_F_MULTIPORT, VIRTIO_CONSOLE_F_SIZE, VIRTIO_F_VERSION_1, VIRTIO_TYPE_CONSOLE, }; use address_space::AddressSpace; @@ -277,6 +277,10 @@ impl VirtioDevice for Serial { device_broken: self.base.broken.clone(), port: port.clone(), nr, + outbuf: Vec::with_capacity(BUF_SIZE), + outbuf_consumed: 0, + outbuf_len: 0, + output_blocked: Arc::new(AtomicBool::new(false)), }; let handler_h = Arc::new(Mutex::new(handler)); let notifiers = EventNotifierHelper::internal_notifiers(handler_h.clone()); @@ -419,6 +423,10 @@ struct SerialPortHandler { device_broken: Arc, port: Option>>, nr: u32, + outbuf: Vec, + outbuf_consumed: usize, + outbuf_len: usize, + output_blocked: Arc, } /// Handler for queues which are used for control. @@ -457,9 +465,24 @@ impl SerialPortHandler { } fn output_handle_internal(&mut self) -> Result<()> { - let mut queue_lock = self.output_queue.lock().unwrap(); + // If fd for tx is blocked, copy data to output buffer and wait for POLL_OUT event. + if self.output_blocked.load(Ordering::Acquire) { + return Ok(()); + } - loop { + match self.consume_outbuf() { + Ok(blocked) => { + if blocked { + return Ok(()); + } + } + Err(e) => bail!("Failed to consume out buffer with error {:?}", e), + } + + let queue = self.output_queue.clone(); + let mut queue_lock = queue.lock().unwrap(); + let mut blocked = false; + while !blocked { let elem = queue_lock .vring .pop_avail(&self.mem_space, self.driver_features)?; @@ -467,25 +490,28 @@ impl SerialPortHandler { break; } + assert_eq!(self.outbuf_len, 0); + // Discard requests when there is no port using this queue. Popping elements without // processing means discarding the request. if self.port.is_some() { - let mut iovec = elem.out_iovec; - let mut iovec_size = Element::iovec_size(&iovec); - while iovec_size > 0 { - let mut buffer = [0_u8; BUF_SIZE]; - let size = iov_to_buf(&self.mem_space, &iovec, &mut buffer)? as u64; - - self.write_chardev_msg(&buffer, size as usize); - - iovec = iov_discard_front(&mut iovec, size) - .unwrap_or_default() - .to_vec(); - // Safety: iovec follows the iov_discard_front operation and - // iovec_size always equals Element::iovec_size(&iovec). - iovec_size -= size; - trace::virtio_serial_output_data(iovec_size, size); + let iovec = elem.out_iovec; + let iovec_size = Element::iovec_size(&iovec); + if iovec_size as usize > self.outbuf.len() { + self.outbuf.resize(iovec_size as usize, 0); + } + + let buffer = &mut self.outbuf[..]; + let size = iov_to_buf(&self.mem_space, &iovec, buffer)? as u64; + + assert_eq!(size, iovec_size); + self.outbuf_len = size as usize; + + match self.consume_outbuf() { + Ok(b) => blocked = b, + Err(e) => bail!("Failed to consume out buffer with error {:?}", e), } + trace::virtio_serial_output_data(iovec_size, size); } queue_lock @@ -516,28 +542,57 @@ impl SerialPortHandler { Ok(()) } - fn write_chardev_msg(&self, buffer: &[u8], write_len: usize) { - let port_locked = self.port.as_ref().unwrap().lock().unwrap(); + fn clear_outbuf(&mut self) { + self.outbuf_len = 0; + self.outbuf_consumed = 0; + } + + fn consume_outbuf(&mut self) -> Result { + if self.outbuf_len == 0 { + return Ok(false); + } + + let port_cloned = self.port.clone(); + let port_locked = port_cloned.as_ref().unwrap().lock().unwrap(); // Discard output buffer if this port's chardev is not connected. if !port_locked.host_connected { - return; + self.clear_outbuf(); + return Ok(false); } - if let Some(output) = &mut port_locked.chardev.lock().unwrap().output { - let mut locked_output = output.lock().unwrap(); - // To do: - // If the buffer is not fully written to chardev, the incomplete part will be discarded. - // This may occur when chardev is abnormal. Consider optimizing this logic in the - // future. - if let Err(e) = locked_output.write_all(&buffer[..write_len]) { - error!("Port {} failed to write msg to chardev: {:?}", self.nr, e); - } - if let Err(e) = locked_output.flush() { - error!("Port {} failed to flush msg to chardev: {:?}", self.nr, e); + let mut locked_chardev = port_locked.chardev.lock().unwrap(); + if locked_chardev.output.is_none() { + error!("Port {} failed to get output interface", self.nr); + self.clear_outbuf(); + return Ok(false); + } + let output = locked_chardev.output.clone(); + let mut locked_output = output.as_ref().unwrap().lock().unwrap(); + + while self.outbuf_consumed < self.outbuf_len { + match locked_output.write(&self.outbuf[self.outbuf_consumed..self.outbuf_len]) { + Ok(size) => self.outbuf_consumed += size, + Err(e) => { + let err_type = e.kind(); + if err_type != std::io::ErrorKind::WouldBlock + && err_type != std::io::ErrorKind::Interrupted + { + self.clear_outbuf(); + bail!("chardev failed to write message with error {:?}", e); + } + if let Err(e) = locked_chardev.add_listen_for_tx( + self.output_queue_evt.clone(), + self.output_blocked.clone(), + ) { + error!("failed to wait for tx fd with error {:?}", e); + continue; + } + return Ok(true); + } } - } else { - error!("Port {} failed to get output fd", self.nr); - }; + } + self.clear_outbuf(); + Ok(false) } fn get_input_avail_bytes(&mut self, max_size: usize) -> usize { -- Gitee From c1fffa19a17cc6df5d8321cc8a78c8b6272e952c Mon Sep 17 00:00:00 2001 From: li-huachao Date: Mon, 13 May 2024 20:03:09 +0800 Subject: [PATCH 056/489] Balloon: fix trace::virtio_receive_request Whe req_type is flase, the balloon request type is deflate. --- virtio/src/device/balloon.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/virtio/src/device/balloon.rs b/virtio/src/device/balloon.rs index 6e6095f9..bc86b048 100644 --- a/virtio/src/device/balloon.rs +++ b/virtio/src/device/balloon.rs @@ -616,7 +616,7 @@ impl BalloonIoHandler { trace::virtio_receive_request("Balloon".to_string(), "to inflate".to_string()); &self.inf_queue } else { - trace::virtio_receive_request("Balloon".to_string(), "to inflate".to_string()); + trace::virtio_receive_request("Balloon".to_string(), "to deflate".to_string()); &self.def_queue }; let mut locked_queue = queue.lock().unwrap(); -- Gitee From 4bbbdf1970281ef7e57e8539073f7c2a67e4e50d Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Fri, 17 May 2024 01:47:22 +0800 Subject: [PATCH 057/489] address_space: fix panic when writing address space `ByteCode::from_bytes` will check date's length and will return `None` when it's not equal to the expected size. Panic will happend when writing address space if buf's length is less than 8. Signed-off-by: liuxiangdong --- address_space/src/address_space.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/address_space/src/address_space.rs b/address_space/src/address_space.rs index f935d01b..bad13f3b 100644 --- a/address_space/src/address_space.rs +++ b/address_space/src/address_space.rs @@ -650,6 +650,7 @@ impl AddressSpace { src.read_to_end(&mut buf).unwrap(); if buf.len() <= 8 { + buf.resize(8, 0); let data = u64::from_bytes(buf.as_slice()).unwrap(); if *data == evtfd.data { if let Err(e) = evtfd.fd.write(1) { -- Gitee From 999de4a5535b75adeb8a08feb9af4858c0fc5008 Mon Sep 17 00:00:00 2001 From: yexiao Date: Fri, 26 Apr 2024 04:58:41 +0800 Subject: [PATCH 058/489] Virtio: initialize device name in VirtioMmioDevice Signed-off-by: Xiao Ye --- machine/src/lib.rs | 14 ++++--- machine/src/micro_common/mod.rs | 10 +++-- virtio/src/transport/virtio_mmio.rs | 58 ++++++++++++++++++++++++----- 3 files changed, 63 insertions(+), 19 deletions(-) diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 63fd7205..ab0957c9 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -577,7 +577,7 @@ pub trait MachineOps { ("addr", device_cfg.addr), ("multifunction", device_cfg.multifunction) ); - let device = VirtioMmioDevice::new(&sys_mem, vsock.clone()); + let device = VirtioMmioDevice::new(&sys_mem, device_cfg.id.clone(), vsock.clone()); MigrationManager::register_device_instance( VirtioMmioState::descriptor(), self.realize_virtio_mmio_device(device) @@ -679,7 +679,7 @@ pub trait MachineOps { ("addr", config.addr), ("multifunction", config.multifunction) ); - let device = VirtioMmioDevice::new(sys_mem, balloon); + let device = VirtioMmioDevice::new(sys_mem, config.id.clone(), balloon); self.realize_virtio_mmio_device(device)?; } _ => { @@ -717,7 +717,7 @@ pub trait MachineOps { ("addr", serial_cfg.addr), ("multifunction", serial_cfg.multifunction) ); - let device = VirtioMmioDevice::new(&sys_mem, serial.clone()); + let device = VirtioMmioDevice::new(&sys_mem, serial_cfg.id.clone(), serial.clone()); MigrationManager::register_device_instance( VirtioMmioState::descriptor(), self.realize_virtio_mmio_device(device) @@ -853,7 +853,7 @@ pub trait MachineOps { ("addr", rng_cfg.addr), ("multifunction", rng_cfg.multifunction) ); - let device = VirtioMmioDevice::new(sys_mem, rng_dev.clone()); + let device = VirtioMmioDevice::new(sys_mem, rng_cfg.id.clone(), rng_dev.clone()); self.realize_virtio_mmio_device(device) .with_context(|| "Failed to add virtio mmio rng device")?; } @@ -905,7 +905,8 @@ pub trait MachineOps { ("addr", dev_cfg.addr), ("multifunction", dev_cfg.multifunction) ); - let virtio_mmio_device = VirtioMmioDevice::new(&sys_mem, device); + let virtio_mmio_device = + VirtioMmioDevice::new(&sys_mem, dev_cfg.id.clone(), device); self.realize_virtio_mmio_device(virtio_mmio_device) .with_context(|| "Failed to add vhost user fs device")?; } @@ -1371,7 +1372,8 @@ pub trait MachineOps { chardev_cfg, self.get_sys_mem(), ))); - let virtio_mmio_device = VirtioMmioDevice::new(self.get_sys_mem(), device); + let virtio_mmio_device = + VirtioMmioDevice::new(self.get_sys_mem(), device_cfg.id.clone(), device); self.realize_virtio_mmio_device(virtio_mmio_device) .with_context(|| "Failed to add vhost user block device")?; Ok(()) diff --git a/machine/src/micro_common/mod.rs b/machine/src/micro_common/mod.rs index b4051b46..c8b96d59 100644 --- a/machine/src/micro_common/mod.rs +++ b/machine/src/micro_common/mod.rs @@ -164,7 +164,8 @@ impl LightMachine { DriveConfig::default(), self.get_drive_files(), ))); - let virtio_mmio = VirtioMmioDevice::new(&self.base.sys_mem, block.clone()); + let virtio_mmio = + VirtioMmioDevice::new(&self.base.sys_mem, id.to_string(), block.clone()); rpl_devs.push(virtio_mmio); MigrationManager::register_device_instance( @@ -178,7 +179,8 @@ impl LightMachine { NetworkInterfaceConfig::default(), NetDevcfg::default(), ))); - let virtio_mmio = VirtioMmioDevice::new(&self.base.sys_mem, net.clone()); + let virtio_mmio = + VirtioMmioDevice::new(&self.base.sys_mem, id.to_string(), net.clone()); rpl_devs.push(virtio_mmio); MigrationManager::register_device_instance( @@ -415,7 +417,7 @@ impl LightMachine { netdev_cfg, &self.base.sys_mem, ))); - VirtioMmioDevice::new(&self.base.sys_mem, net) + VirtioMmioDevice::new(&self.base.sys_mem, net_cfg.id.clone(), net) } else { let chardev = netdev_cfg.chardev.clone().with_context(|| { format!("Chardev not configured for netdev {:?}", netdev_cfg.id) @@ -431,7 +433,7 @@ impl LightMachine { sock_path, &self.base.sys_mem, ))); - VirtioMmioDevice::new(&self.base.sys_mem, net) + VirtioMmioDevice::new(&self.base.sys_mem, net_cfg.id.clone(), net) }; self.realize_virtio_mmio_device(device)?; } else { diff --git a/virtio/src/transport/virtio_mmio.rs b/virtio/src/transport/virtio_mmio.rs index 55381c5e..1340fd9c 100644 --- a/virtio/src/transport/virtio_mmio.rs +++ b/virtio/src/transport/virtio_mmio.rs @@ -134,12 +134,20 @@ pub struct VirtioMmioDevice { } impl VirtioMmioDevice { - pub fn new(mem_space: &Arc, device: Arc>) -> Self { + pub fn new( + mem_space: &Arc, + name: String, + device: Arc>, + ) -> Self { let device_clone = device.clone(); let queue_num = device_clone.lock().unwrap().queue_num(); VirtioMmioDevice { base: SysBusDevBase { + base: DeviceBase { + id: name, + hotpluggable: false, + }, dev_type: SysBusDevType::VirtioMmio, interrupt_evt: Some(Arc::new(EventFd::new(libc::EFD_NONBLOCK).unwrap())), ..Default::default() @@ -696,7 +704,11 @@ mod tests { fn test_virtio_mmio_device_new() { let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); let sys_space = address_space_init(); - let virtio_mmio_device = VirtioMmioDevice::new(&sys_space, virtio_device.clone()); + let virtio_mmio_device = VirtioMmioDevice::new( + &sys_space, + "test_virtio_mmio_device".to_string(), + virtio_device.clone(), + ); let locked_device = virtio_device.lock().unwrap(); assert_eq!(locked_device.device_activated(), false); @@ -716,7 +728,11 @@ mod tests { fn test_virtio_mmio_device_read_01() { let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); let sys_space = address_space_init(); - let mut virtio_mmio_device = VirtioMmioDevice::new(&sys_space, virtio_device.clone()); + let mut virtio_mmio_device = VirtioMmioDevice::new( + &sys_space, + "test_virtio_mmio_device".to_string(), + virtio_device.clone(), + ); let addr = GuestAddress(0); // read the register of magic value @@ -775,7 +791,11 @@ mod tests { fn test_virtio_mmio_device_read_02() { let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); let sys_space = address_space_init(); - let mut virtio_mmio_device = VirtioMmioDevice::new(&sys_space, virtio_device.clone()); + let mut virtio_mmio_device = VirtioMmioDevice::new( + &sys_space, + "test_virtio_mmio_device".to_string(), + virtio_device.clone(), + ); let addr = GuestAddress(0); // read the register representing max size of the queue @@ -867,7 +887,11 @@ mod tests { fn test_virtio_mmio_device_read_03() { let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); let sys_space = address_space_init(); - let mut virtio_mmio_device = VirtioMmioDevice::new(&sys_space, virtio_device.clone()); + let mut virtio_mmio_device = VirtioMmioDevice::new( + &sys_space, + "test_virtio_mmio_device".to_string(), + virtio_device.clone(), + ); let addr = GuestAddress(0); // read the configuration atomic value @@ -915,7 +939,11 @@ mod tests { fn test_virtio_mmio_device_write_01() { let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); let sys_space = address_space_init(); - let mut virtio_mmio_device = VirtioMmioDevice::new(&sys_space, virtio_device.clone()); + let mut virtio_mmio_device = VirtioMmioDevice::new( + &sys_space, + "test_virtio_mmio_device".to_string(), + virtio_device.clone(), + ); let addr = GuestAddress(0); // write the selector for device features @@ -1029,7 +1057,11 @@ mod tests { fn test_virtio_mmio_device_write_02() { let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); let sys_space = address_space_init(); - let mut virtio_mmio_device = VirtioMmioDevice::new(&sys_space, virtio_device.clone()); + let mut virtio_mmio_device = VirtioMmioDevice::new( + &sys_space, + "test_virtio_mmio_device".to_string(), + virtio_device.clone(), + ); let addr = GuestAddress(0); // write the ready status of queue @@ -1096,7 +1128,11 @@ mod tests { fn test_virtio_mmio_device_write_03() { let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); let sys_space = address_space_init(); - let mut virtio_mmio_device = VirtioMmioDevice::new(&sys_space, virtio_device.clone()); + let mut virtio_mmio_device = VirtioMmioDevice::new( + &sys_space, + "test_virtio_mmio_device".to_string(), + virtio_device.clone(), + ); let addr = GuestAddress(0); // write the low 32bit of queue's descriptor table address @@ -1221,7 +1257,11 @@ mod tests { fn test_virtio_mmio_device_write_04() { let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); let sys_space = address_space_init(); - let mut virtio_mmio_device = VirtioMmioDevice::new(&sys_space, virtio_device.clone()); + let mut virtio_mmio_device = VirtioMmioDevice::new( + &sys_space, + "test_virtio_mmio_device".to_string(), + virtio_device.clone(), + ); let addr = GuestAddress(0); virtio_mmio_device.assign_interrupt_cb(); -- Gitee From 73122d2883686ccb9f0ee81257a2402ec5a9bc0a Mon Sep 17 00:00:00 2001 From: zhanghan64 Date: Tue, 21 May 2024 19:37:13 +0800 Subject: [PATCH 059/489] Camera: fix "create session"'s position We just call create_session before start stream, not when camera reset. Signed-off-by: zhanghan64 --- util/src/ohos_binding/camera.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/util/src/ohos_binding/camera.rs b/util/src/ohos_binding/camera.rs index c481403e..e481e887 100644 --- a/util/src/ohos_binding/camera.rs +++ b/util/src/ohos_binding/camera.rs @@ -110,6 +110,9 @@ impl OhCamera { ) -> Result<()> { // SAFETY: We call related API sequentially for specified ctx. unsafe { + if (self.capi.create_session)(self.ctx) != 0 { + bail!("OH Camera: failed to create session"); + } if (self.capi.pre_start)(self.ctx, buffer_proc, broken_proc) != 0 { bail!("OH Camera: failed to prestart camera stream"); } @@ -123,7 +126,6 @@ impl OhCamera { pub fn reset_camera(&self) { // SAFETY: We call related API sequentially for specified ctx. unsafe { - (self.capi.create_session)(self.ctx); (self.capi.init_cameras)(self.ctx); (self.capi.init_profiles)(self.ctx); } -- Gitee From 1d7b05f94960b6eaa72a4f60698e0f8ea3cac58a Mon Sep 17 00:00:00 2001 From: yexiao Date: Fri, 26 Apr 2024 18:17:40 +0800 Subject: [PATCH 060/489] stratovirt-img: add query operation Add query operation for stratovirt-img, which can be used for query image info. Signed-off-by: Xiao Ye --- block_backend/src/lib.rs | 12 ++++++++++++ block_backend/src/qcow2/mod.rs | 6 +++++- block_backend/src/raw.rs | 6 +++++- image/src/img.rs | 4 ++++ image/src/main.rs | 3 ++- 5 files changed, 28 insertions(+), 3 deletions(-) diff --git a/block_backend/src/lib.rs b/block_backend/src/lib.rs index cbe37dfa..c4877097 100644 --- a/block_backend/src/lib.rs +++ b/block_backend/src/lib.rs @@ -151,6 +151,16 @@ impl CreateOptions { } } +#[derive(Default)] +pub struct ImageInfo { + pub path: String, + pub format: String, + pub actual_size: u64, + pub virtual_size: u64, + pub cluster_size: Option, + pub snap_lists: Option, +} + #[derive(Default, Clone, Copy)] pub struct DiskFragments { pub allocated_clusters: u64, @@ -291,6 +301,8 @@ impl Default for BlockProperty { pub trait BlockDriverOps: Send { fn create_image(&mut self, options: &CreateOptions) -> Result; + fn query_image(&mut self, image_info: &mut ImageInfo) -> Result<()>; + fn check_image(&mut self, res: &mut CheckResult, quite: bool, fix: u64) -> Result<()>; fn disk_size(&mut self) -> Result; diff --git a/block_backend/src/qcow2/mod.rs b/block_backend/src/qcow2/mod.rs index 922233f6..9f30c22b 100644 --- a/block_backend/src/qcow2/mod.rs +++ b/block_backend/src/qcow2/mod.rs @@ -50,7 +50,7 @@ use crate::{ table::{Qcow2ClusterType, Qcow2Table}, }, BlockDriverOps, BlockIoErrorCallback, BlockProperty, BlockStatus, CheckResult, CreateOptions, - SECTOR_SIZE, + ImageInfo, SECTOR_SIZE, }; use machine_manager::event_loop::EventLoop; use machine_manager::qmp::qmp_schema::SnapshotInfo; @@ -1643,6 +1643,10 @@ impl BlockDriverOps for Qcow2Driver { Ok(image_info) } + fn query_image(&mut self, _info: &mut ImageInfo) -> Result<()> { + todo!(); + } + fn check_image(&mut self, res: &mut CheckResult, quite: bool, fix: u64) -> Result<()> { let cluster_size = self.header.cluster_size(); let refcount_order = self.header.refcount_order; diff --git a/block_backend/src/raw.rs b/block_backend/src/raw.rs index c051b3f1..ccbc31a6 100644 --- a/block_backend/src/raw.rs +++ b/block_backend/src/raw.rs @@ -25,7 +25,7 @@ use crate::{ file::{CombineRequest, FileDriver}, qcow2::is_aligned, BlockDriverOps, BlockIoErrorCallback, BlockProperty, BlockStatus, CheckResult, CreateOptions, - SECTOR_SIZE, + ImageInfo, SECTOR_SIZE, }; use util::{ aio::{get_iov_size, raw_write, Aio, Iovec}, @@ -92,6 +92,10 @@ impl BlockDriverOps for RawDriver { Ok(image_info) } + fn query_image(&mut self, _info: &mut ImageInfo) -> Result<()> { + todo!(); + } + fn check_image(&mut self, _res: &mut CheckResult, _quite: bool, _fix: u64) -> Result<()> { bail!("This image format does not support checks"); } diff --git a/image/src/img.rs b/image/src/img.rs index 0e54d0b9..fd3c5a43 100644 --- a/image/src/img.rs +++ b/image/src/img.rs @@ -190,6 +190,10 @@ pub(crate) fn image_create(args: Vec) -> Result<()> { Ok(()) } +pub(crate) fn image_info(_args: Vec) -> Result<()> { + todo!() +} + pub(crate) fn image_check(args: Vec) -> Result<()> { let mut arg_parser = ArgsParse::create(vec!["no_print_error", "h", "help"], vec!["f", "r"], vec![]); diff --git a/image/src/main.rs b/image/src/main.rs index 055ac211..b9c7aef5 100644 --- a/image/src/main.rs +++ b/image/src/main.rs @@ -21,7 +21,7 @@ use std::{ use anyhow::{bail, Result}; use crate::img::{ - image_check, image_create, image_resize, image_snapshot, print_help, print_version, + image_check, image_create, image_info, image_resize, image_snapshot, print_help, print_version, }; const BINARY_NAME: &str = "stratovirt-img"; @@ -83,6 +83,7 @@ fn run(args: Vec) -> Result<()> { image_operation_matches!( opt.as_str(); ("create", image_create, cmd_args), + ("info", image_info, cmd_args), ("check", image_check, cmd_args), ("resize", image_resize, cmd_args), ("snapshot", image_snapshot, cmd_args); -- Gitee From 83542983704424226ec955af7b4619bb98e1a3f6 Mon Sep 17 00:00:00 2001 From: yexiao Date: Fri, 26 Apr 2024 18:33:14 +0800 Subject: [PATCH 061/489] stratovirt-img: add arg parse for query operation Cmd line of query operation is as follows: stratovirt-img info filename Signed-off-by: Xiao Ye --- block_backend/src/lib.rs | 51 ++++++++++++++++++++++++++++++++++++++++ image/src/img.rs | 51 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 98 insertions(+), 4 deletions(-) diff --git a/block_backend/src/lib.rs b/block_backend/src/lib.rs index c4877097..b6f42513 100644 --- a/block_backend/src/lib.rs +++ b/block_backend/src/lib.rs @@ -15,6 +15,7 @@ pub mod qcow2; pub mod raw; use std::{ + fmt, fs::File, sync::{ atomic::{AtomicBool, AtomicU64, Ordering}, @@ -151,6 +152,30 @@ impl CreateOptions { } } +// Transform size into string with storage units. +fn size_to_string(size: f64) -> Result { + let units = vec!["", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"]; + + // Switch to higher power if the integer part is >= 1000, + // For example: 1000 * 2^30 bytes + // It's better to output 0.978 TiB, rather than 1000 GiB. + let n = (size / 1000.0 * 1024.0).log2() as u64; + let idx = n / 10; + if idx >= units.len() as u64 { + bail!("Input value {} is too large", size); + } + let div = 1_u64 << (idx * 10); + + // Keep three significant digits and do not output any extra zeros, + // For example: 512 * 2^20 bytes + // It's better to output 512 MiB, rather than 512.000 MiB. + let num_str = format!("{:.3}", size / div as f64); + let num_str = num_str.trim_end_matches('0').trim_end_matches('.'); + + let res = format!("{} {}", num_str, units[idx as usize]); + Ok(res) +} + #[derive(Default)] pub struct ImageInfo { pub path: String, @@ -161,6 +186,32 @@ pub struct ImageInfo { pub snap_lists: Option, } +impl fmt::Display for ImageInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!( + f, + "image: {}\n\ + file format: {}\n\ + virtual size: {} ({} bytes)\n\ + disk size: {}", + self.path, + self.format, + size_to_string(self.virtual_size as f64).unwrap_or_else(|e| format!("{:?}", e)), + self.virtual_size, + size_to_string(self.actual_size as f64).unwrap_or_else(|e| format!("{:?}", e)) + )?; + + if let Some(cluster_size) = self.cluster_size { + writeln!(f, "cluster_size: {}", cluster_size)?; + } + + if let Some(snap_lists) = &self.snap_lists { + write!(f, "Snapshot list:\n{}", snap_lists)?; + } + Ok(()) + } +} + #[derive(Default, Clone, Copy)] pub struct DiskFragments { pub allocated_clusters: u64, diff --git a/image/src/img.rs b/image/src/img.rs index fd3c5a43..caf1ebf3 100644 --- a/image/src/img.rs +++ b/image/src/img.rs @@ -23,8 +23,8 @@ use crate::{cmdline::ArgsParse, BINARY_NAME}; use block_backend::{ qcow2::{header::QcowHeader, InternalSnapshotOps, Qcow2Driver, SyncAioInfo}, raw::RawDriver, - BlockDriverOps, BlockProperty, CheckResult, CreateOptions, FIX_ERRORS, FIX_LEAKS, NO_FIX, - SECTOR_SIZE, + BlockDriverOps, BlockProperty, CheckResult, CreateOptions, ImageInfo, FIX_ERRORS, FIX_LEAKS, + NO_FIX, SECTOR_SIZE, }; use machine_manager::config::{memory_unit_conversion, DiskFormat}; use util::{ @@ -190,8 +190,50 @@ pub(crate) fn image_create(args: Vec) -> Result<()> { Ok(()) } -pub(crate) fn image_info(_args: Vec) -> Result<()> { - todo!() +pub(crate) fn image_info(args: Vec) -> Result<()> { + if args.len() < 1 { + bail!("Not enough arguments"); + } + let mut arg_parser = ArgsParse::create(vec!["h", "help"], vec![], vec![]); + arg_parser.parse(args)?; + + if arg_parser.opt_present("h") || arg_parser.opt_present("help") { + print_help(); + return Ok(()); + } + + // Parse the image path. + let len = arg_parser.free.len(); + let img_path = match len { + 0 => bail!("Image path is needed"), + 1 => arg_parser.free[0].clone(), + _ => { + let param = arg_parser.free[1].clone(); + bail!("Unexpected argument: {}", param); + } + }; + + let aio = Aio::new(Arc::new(SyncAioInfo::complete_func), AioEngine::Off, None)?; + let image_file = ImageFile::create(&img_path, false)?; + let detect_fmt = image_file.detect_img_format()?; + + let mut conf = BlockProperty::default(); + conf.format = detect_fmt; + let mut driver: Box> = match detect_fmt { + DiskFormat::Raw => Box::new(RawDriver::new(image_file.file.try_clone()?, aio, conf)), + DiskFormat::Qcow2 => { + let mut qocw2_driver = + Qcow2Driver::new(image_file.file.try_clone()?, aio, conf.clone())?; + qocw2_driver.load_metadata(conf)?; + Box::new(qocw2_driver) + } + }; + + let mut image_info = ImageInfo::default(); + image_info.path = img_path; + driver.query_image(&mut image_info)?; + print!("{}", image_info); + Ok(()) } pub(crate) fn image_check(args: Vec) -> Result<()> { @@ -478,6 +520,7 @@ Stratovirt disk image utility Command syntax: create [-f fmt] [-o options] filename [size] +info filename check [-r [leaks | all]] [-no_print_error] [-f fmt] filename resize [-f fmt] filename [+]size snapshot [-l | -a snapshot | -c snapshot | -d snapshot] filename -- Gitee From 1b8fe9c45a07cddf02db1a7ed1eacf73b929658b Mon Sep 17 00:00:00 2001 From: yexiao Date: Fri, 26 Apr 2024 18:47:27 +0800 Subject: [PATCH 062/489] stratovirt-img: implement query operation. Implement query operations for raw and qcow2. Signed-off-by: Xiao Ye --- block_backend/src/file.rs | 12 ++++++++++-- block_backend/src/qcow2/mod.rs | 14 +++++++++++--- block_backend/src/raw.rs | 7 +++++-- 3 files changed, 26 insertions(+), 7 deletions(-) diff --git a/block_backend/src/file.rs b/block_backend/src/file.rs index 83237651..45ea1549 100644 --- a/block_backend/src/file.rs +++ b/block_backend/src/file.rs @@ -14,7 +14,10 @@ use std::{ cell::RefCell, fs::File, io::{Seek, SeekFrom}, - os::unix::prelude::{AsRawFd, RawFd}, + os::{ + linux::fs::MetadataExt, + unix::prelude::{AsRawFd, RawFd}, + }, rc::Rc, sync::{ atomic::{AtomicBool, AtomicI64, AtomicU32, AtomicU64, Ordering}, @@ -26,7 +29,7 @@ use anyhow::{Context, Result}; use log::error; use vmm_sys_util::epoll::EventSet; -use crate::{BlockIoErrorCallback, BlockProperty}; +use crate::{qcow2::DEFAULT_SECTOR_SIZE, BlockIoErrorCallback, BlockProperty}; use machine_manager::event_loop::{register_event_helper, unregister_event_helper}; use util::{ aio::{Aio, AioCb, AioEngine, Iovec, OpCode}, @@ -188,6 +191,11 @@ impl FileDriver { unregister_event_helper(self.block_prop.iothread.as_ref(), &mut self.delete_evts) } + pub fn actual_size(&mut self) -> Result { + let meta_data = self.file.metadata()?; + Ok(meta_data.st_blocks() * DEFAULT_SECTOR_SIZE) + } + pub fn disk_size(&mut self) -> Result { let disk_size = self .file diff --git a/block_backend/src/qcow2/mod.rs b/block_backend/src/qcow2/mod.rs index 9f30c22b..1b5a3dfb 100644 --- a/block_backend/src/qcow2/mod.rs +++ b/block_backend/src/qcow2/mod.rs @@ -77,7 +77,7 @@ pub const QCOW2_OFLAG_ZERO: u64 = 1 << 0; const QCOW2_OFFSET_COMPRESSED: u64 = 1 << 62; pub const QCOW2_OFFSET_COPIED: u64 = 1 << 63; const MAX_L1_SIZE: u64 = 32 * (1 << 20); -const DEFAULT_SECTOR_SIZE: u64 = 512; +pub(crate) const DEFAULT_SECTOR_SIZE: u64 = 512; pub(crate) const QCOW2_MAX_L1_SIZE: u64 = 1 << 25; // The default flush interval is 30s. @@ -1643,8 +1643,16 @@ impl BlockDriverOps for Qcow2Driver { Ok(image_info) } - fn query_image(&mut self, _info: &mut ImageInfo) -> Result<()> { - todo!(); + fn query_image(&mut self, info: &mut ImageInfo) -> Result<()> { + info.format = "qcow2".to_string(); + info.virtual_size = self.disk_size()?; + info.actual_size = self.driver.actual_size()?; + info.cluster_size = Some(self.header.cluster_size()); + + if !self.snapshot.snapshots.is_empty() { + info.snap_lists = Some(self.qcow2_list_snapshots()); + } + Ok(()) } fn check_image(&mut self, res: &mut CheckResult, quite: bool, fix: u64) -> Result<()> { diff --git a/block_backend/src/raw.rs b/block_backend/src/raw.rs index ccbc31a6..d8622d5a 100644 --- a/block_backend/src/raw.rs +++ b/block_backend/src/raw.rs @@ -92,8 +92,11 @@ impl BlockDriverOps for RawDriver { Ok(image_info) } - fn query_image(&mut self, _info: &mut ImageInfo) -> Result<()> { - todo!(); + fn query_image(&mut self, info: &mut ImageInfo) -> Result<()> { + info.format = "raw".to_string(); + info.virtual_size = self.disk_size()?; + info.actual_size = self.driver.actual_size()?; + Ok(()) } fn check_image(&mut self, _res: &mut CheckResult, _quite: bool, _fix: u64) -> Result<()> { -- Gitee From 8cf099b6e493c87fef3b3f35f4a65cc6a54a72a1 Mon Sep 17 00:00:00 2001 From: yexiao Date: Fri, 26 Apr 2024 19:15:16 +0800 Subject: [PATCH 063/489] stratovirt-img: add unit test Add unit test for the function of image_info. Signed-off-by: Xiao Ye --- image/src/img.rs | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/image/src/img.rs b/image/src/img.rs index caf1ebf3..e106b70e 100644 --- a/image/src/img.rs +++ b/image/src/img.rs @@ -807,6 +807,55 @@ mod test { assert!(remove_file(path).is_ok()); } + /// Test the function of query image. + /// TestStep: + /// 2. Query image info with different type. + /// Expect: + /// 1. Ihe invalid args will result in failure. + #[test] + fn test_args_parse_of_image_info() { + let path = "/tmp/test_args_parse_of_image_info.qcow2"; + let test_case = vec![ + ("img_path", true), + ("-f qcow2", false), + ("invalid_args", false), + ("img_path +1G", false), + ("-h", true), + ("--help", true), + ]; + + for case in test_case { + let cmd_str = case.0.replace("img_path", path); + let args: Vec = cmd_str + .split(' ') + .into_iter() + .map(|str| str.to_string()) + .collect(); + + // Query image info with type of qcow2. + assert!(image_create(vec![ + "-f".to_string(), + "qcow2".to_string(), + path.to_string(), + "+10M".to_string() + ]) + .is_ok()); + assert_eq!(image_info(args.clone()).is_ok(), case.1); + + // Query image info with type of raw. + assert!(image_create(vec![ + "-f".to_string(), + "raw".to_string(), + path.to_string(), + "+10M".to_string() + ]) + .is_ok()); + assert_eq!(image_info(args).is_ok(), case.1); + } + + assert!(remove_file(path).is_ok()); + } + /// Test the function of creating image. /// TestStep: /// 1. Create image with different cluster bits, image size and refcount bits. -- Gitee From c2cd634e16d3b0074239b323e03cdaa747ac17d9 Mon Sep 17 00:00:00 2001 From: yexiao Date: Fri, 26 Apr 2024 19:21:44 +0800 Subject: [PATCH 064/489] stratovirt-img: add docs Add docs for query operation of stratovirt-img. Signed-off-by: Xiao Ye --- docs/stratovirt-img.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/stratovirt-img.md b/docs/stratovirt-img.md index e44be8d6..7021e565 100644 --- a/docs/stratovirt-img.md +++ b/docs/stratovirt-img.md @@ -35,6 +35,16 @@ stratovirt-img create -f qcow2 -o cluster-size=65536 img_path img_size Note: 1. The cluster size can be only be set for `qcow2` or default to 65536. 2. Disk format is default to raw. +## Info + +Query the information of virtual disk. + +Sample Configuration: + +```shell +stratovirt-img info img_path +``` + ## Check Check if there are some mistakes on the image and choose to fix. -- Gitee From 9e778487a8a8c6b4fd39b30d8c5b9814626a0883 Mon Sep 17 00:00:00 2001 From: zhanghan64 Date: Thu, 23 May 2024 16:30:04 +0800 Subject: [PATCH 065/489] ohcam: remove useless format Now OH camera subsystem supports NV12&YUY2 We don't need NV21, let's remove it. Signed-off-by: zhanghan64 --- devices/src/camera_backend/ohcam.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/devices/src/camera_backend/ohcam.rs b/devices/src/camera_backend/ohcam.rs index 2bf3253f..3debe893 100755 --- a/devices/src/camera_backend/ohcam.rs +++ b/devices/src/camera_backend/ohcam.rs @@ -30,11 +30,7 @@ static OHCAM_CALLBACK: Lazy = Lazy::new(|| RwLock::new(OhCamCallBack::d // So, fps * interval / 10_000_000 == 1. const FPS_INTERVAL_TRANS: u32 = 10_000_000; const RESOLUTION_WHITELIST: [(i32, i32); 2] = [(640, 480), (1280, 720)]; -const FRAME_FORMAT_WHITELIST: [i32; 3] = [ - CAMERA_FORMAT_YUV420SP, - CAMERA_FORMAT_YUYV422, - CAMERA_FORMAT_NV12, -]; +const FRAME_FORMAT_WHITELIST: [i32; 2] = [CAMERA_FORMAT_YUYV422, CAMERA_FORMAT_NV12]; const FPS_WHITELIST: [i32; 1] = [30]; #[derive(Default)] -- Gitee From 1ad1ecd428e02ca56d6967db865de2b44cdd5f3f Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Wed, 22 May 2024 20:53:10 +0800 Subject: [PATCH 066/489] util: Avoid potential unsafe use of unwrap Signed-off-by: Keqian Zhu --- util/src/unix.rs | 86 +++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 45 deletions(-) diff --git a/util/src/unix.rs b/util/src/unix.rs index d71e3c82..6a723ed2 100644 --- a/util/src/unix.rs +++ b/util/src/unix.rs @@ -187,10 +187,11 @@ impl UnixSock { /// The listener accepts incoming client connections. pub fn accept(&mut self) -> Result<()> { - let (sock, _addr) = self + let listener = self .listener .as_ref() - .unwrap() + .with_context(|| "UnixSock is not bound")?; + let (sock, _addr) = listener .accept() .with_context(|| format!("Failed to accept the socket {}", self.path))?; self.sock = Some(sock); @@ -203,8 +204,12 @@ impl UnixSock { } pub fn server_connection_refuse(&mut self) -> Result<()> { + let listener = self + .listener + .as_ref() + .with_context(|| "UnixSock is not bound")?; // Refuse connection by finishing life cycle of stream fd from listener fd. - self.listener.as_ref().unwrap().accept().with_context(|| { + listener.accept().with_context(|| { format!( "Failed to accept the socket for refused connection {}", self.path @@ -224,18 +229,21 @@ impl UnixSock { } pub fn listen_set_nonblocking(&self, nonblocking: bool) -> Result<()> { - self.listener + let listener = self + .listener .as_ref() - .unwrap() + .with_context(|| "UnixSock is not bound")?; + listener .set_nonblocking(nonblocking) .with_context(|| "couldn't set nonblocking for unix sock listener") } pub fn set_nonblocking(&self, nonblocking: bool) -> Result<()> { - self.sock + let sock = self + .sock .as_ref() - .unwrap() - .set_nonblocking(nonblocking) + .with_context(|| "UnixSock is not connected")?; + sock.set_nonblocking(nonblocking) .with_context(|| "couldn't set nonblocking") } @@ -287,7 +295,7 @@ impl UnixSock { /// # Errors /// /// The socket file descriptor is broken. - pub fn send_msg(&self, iovecs: &mut [iovec], out_fds: &[RawFd]) -> std::io::Result { + pub fn send_msg(&self, iovecs: &mut [iovec], out_fds: &[RawFd]) -> Result { // SAFETY: We checked the iovecs lens before. let iovecs_len = iovecs.len(); // SAFETY: We checked the out_fds lens before. @@ -331,17 +339,17 @@ impl UnixSock { msg.msg_controllen = cmsg_capacity as _; } - let write_count = - // SAFETY: msg parameters are valid. - unsafe { sendmsg(self.sock.as_ref().unwrap().as_raw_fd(), &msg, MSG_NOSIGNAL) }; + let sock = self + .sock + .as_ref() + .with_context(|| "UnixSock is not connected")?; + // SAFETY: msg parameters are valid. + let write_count = unsafe { sendmsg(sock.as_raw_fd(), &msg, MSG_NOSIGNAL) }; if write_count == -1 { - Err(std::io::Error::new( - std::io::ErrorKind::InvalidData, - format!( - "Failed to send msg, err: {}", - std::io::Error::last_os_error() - ), + Err(anyhow!( + "Failed to send msg, err: {}", + std::io::Error::last_os_error() )) } else { Ok(write_count as usize) @@ -358,11 +366,7 @@ impl UnixSock { /// # Errors /// /// The socket file descriptor is broken. - pub fn recv_msg( - &self, - iovecs: &mut [iovec], - in_fds: &mut [RawFd], - ) -> std::io::Result<(usize, usize)> { + pub fn recv_msg(&self, iovecs: &mut [iovec], in_fds: &mut [RawFd]) -> Result<(usize, usize)> { // SAFETY: We check the iovecs lens before. let iovecs_len = iovecs.len(); // SAFETY: We check the in_fds lens before. @@ -386,33 +390,25 @@ impl UnixSock { msg.msg_controllen = cmsg_capacity as _; } + let sock = self + .sock + .as_ref() + .with_context(|| "UnixSock is not connected")?; // SAFETY: msg parameters are valid. - let total_read = unsafe { - recvmsg( - self.sock.as_ref().unwrap().as_raw_fd(), - &mut msg, - MSG_WAITALL, - ) - }; + let total_read = unsafe { recvmsg(sock.as_raw_fd(), &mut msg, MSG_WAITALL) }; if total_read == -1 { - return Err(std::io::Error::new( - std::io::ErrorKind::InvalidData, - format!( - "Failed to recv msg, err: {}", - std::io::Error::last_os_error() - ), - )); + bail!( + "Failed to recv msg, err: {}", + std::io::Error::last_os_error() + ); } if total_read == 0 && (msg.msg_controllen as u64) < size_of::() as u64 { - return Err(std::io::Error::new( - std::io::ErrorKind::InvalidData, - format!( - "The length of control message is invalid, {} {}", - msg.msg_controllen, - size_of::() - ), - )); + bail!( + "The length of control message is invalid, {} {}", + msg.msg_controllen, + size_of::() + ); } let mut cmsg_ptr = msg.msg_control as *mut cmsghdr; -- Gitee From 3a7e5bb7dfea5b2ad26e80a70a85f7f0dc5a96a8 Mon Sep 17 00:00:00 2001 From: Mingwang Li Date: Thu, 23 May 2024 21:35:07 +0800 Subject: [PATCH 067/489] iothread: stratovirt exit wait for iothread exit When the process exits, resources are reclaimed, but the iothread is still running. As a result, some unexpected results are caused. Signed-off-by: Mingwang Li --- machine/src/aarch64/standard.rs | 2 ++ machine/src/micro_common/mod.rs | 2 +- machine/src/x86_64/standard.rs | 2 ++ machine_manager/src/event_loop.rs | 47 ++++++++++++++++++++++----- machine_manager/src/signal_handler.rs | 2 +- src/main.rs | 6 ++-- util/src/loop_context.rs | 26 +++++++-------- 7 files changed, 59 insertions(+), 28 deletions(-) diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index 3dd906e8..bb46ce38 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -66,6 +66,7 @@ use machine_manager::config::{ parse_incoming_uri, BootIndexInfo, DriveConfig, MigrateMode, NumaNode, SerialConfig, VmConfig, }; use machine_manager::event; +use machine_manager::event_loop::EventLoop; use machine_manager::machine::{ MachineExternalInterface, MachineInterface, MachineLifecycle, MachineTestInterface, MigrateInterface, VmState, @@ -271,6 +272,7 @@ impl StdMachine { } } + EventLoop::kick_all(); info!("vm destroy"); Ok(()) diff --git a/machine/src/micro_common/mod.rs b/machine/src/micro_common/mod.rs index c8b96d59..49cd1534 100644 --- a/machine/src/micro_common/mod.rs +++ b/machine/src/micro_common/mod.rs @@ -532,7 +532,7 @@ impl MachineLifecycle for LightMachine { } info!("vm destroy"); - EventLoop::get_ctx(None).unwrap().kick(); + EventLoop::kick_all(); true } diff --git a/machine/src/x86_64/standard.rs b/machine/src/x86_64/standard.rs index fdb88d1e..289737e1 100644 --- a/machine/src/x86_64/standard.rs +++ b/machine/src/x86_64/standard.rs @@ -48,6 +48,7 @@ use machine_manager::config::{ parse_incoming_uri, BootIndexInfo, DriveConfig, MigrateMode, NumaNode, SerialConfig, VmConfig, }; use machine_manager::event; +use machine_manager::event_loop::EventLoop; use machine_manager::machine::{ MachineExternalInterface, MachineInterface, MachineLifecycle, MachineTestInterface, MigrateInterface, VmState, @@ -220,6 +221,7 @@ impl StdMachine { } } + EventLoop::kick_all(); info!("vm destroy"); Ok(()) diff --git a/machine_manager/src/event_loop.rs b/machine_manager/src/event_loop.rs index 7acaca84..79d7cf6f 100644 --- a/machine_manager/src/event_loop.rs +++ b/machine_manager/src/event_loop.rs @@ -12,7 +12,7 @@ use std::collections::HashMap; use std::os::unix::prelude::RawFd; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Barrier, Mutex}; use std::{process, thread}; use anyhow::{bail, Result}; @@ -49,9 +49,18 @@ impl EventLoop { /// * `iothreads` - refer to `-iothread` params pub fn object_init(iothreads: &Option>) -> Result<()> { let mut io_threads = HashMap::new(); + let cnt = match iothreads { + Some(thrs) => thrs.len(), + None => 0, + }; + let thread_exit_barrier = Arc::new(Barrier::new(cnt + 1)); + if let Some(thrs) = iothreads { for thr in thrs { - io_threads.insert(thr.id.clone(), EventLoopContext::new()); + io_threads.insert( + thr.id.clone(), + EventLoopContext::new(thread_exit_barrier.clone()), + ); } } @@ -60,7 +69,7 @@ impl EventLoop { unsafe { if GLOBAL_EVENT_LOOP.is_none() { GLOBAL_EVENT_LOOP = Some(EventLoop { - main_loop: EventLoopContext::new(), + main_loop: EventLoopContext::new(thread_exit_barrier), io_threads, }); @@ -76,10 +85,11 @@ impl EventLoop { }; IOTHREADS.lock().unwrap().push(iothread_info); while let Ok(ret) = ctx.iothread_run() { - if !ret { + if !ret || get_signal() != 0 { break; } } + ctx.thread_exit_barrier.wait(); })?; } } else { @@ -115,11 +125,16 @@ impl EventLoop { /// /// # Arguments /// - /// * `manager` - The main part to manager the event loop specified by name. - /// * `name` - specify which event loop to manage - pub fn set_manager(manager: Arc>, name: Option<&String>) { - if let Some(ctx) = Self::get_ctx(name) { - ctx.set_manager(manager) + /// * `manager` - The main part to manager the event loop. + pub fn set_manager(manager: Arc>) { + // SAFETY: All concurrently accessed data of EventLoopContext is protected. + unsafe { + if let Some(event_loop) = GLOBAL_EVENT_LOOP.as_mut() { + event_loop.main_loop.set_manager(manager.clone()); + for (_name, io_thread) in event_loop.io_threads.iter_mut() { + io_thread.set_manager(manager.clone()); + } + } } } @@ -152,10 +167,12 @@ impl EventLoop { let sig_num = get_signal(); if sig_num != 0 { info!("MainLoop exits due to receive signal {}", sig_num); + event_loop.main_loop.thread_exit_barrier.wait(); return Ok(()); } if !event_loop.main_loop.run()? { info!("MainLoop exits due to guest internal operation."); + event_loop.main_loop.thread_exit_barrier.wait(); return Ok(()); } } @@ -172,6 +189,18 @@ impl EventLoop { GLOBAL_EVENT_LOOP = None; } } + + pub fn kick_all() { + // SAFETY: All concurrently accessed data of EventLoopContext is protected. + unsafe { + if let Some(event_loop) = GLOBAL_EVENT_LOOP.as_mut() { + for (_name, io_thread) in event_loop.io_threads.iter_mut() { + io_thread.kick(); + } + event_loop.main_loop.kick(); + } + } + } } pub fn register_event_helper( diff --git a/machine_manager/src/signal_handler.rs b/machine_manager/src/signal_handler.rs index 2f1ba86e..6d679192 100644 --- a/machine_manager/src/signal_handler.rs +++ b/machine_manager/src/signal_handler.rs @@ -50,7 +50,7 @@ pub fn set_signal(num: c_int) { unsafe { RECEIVED_SIGNAL.store(num, Ordering::SeqCst); } - EventLoop::get_ctx(None).unwrap().kick(); + EventLoop::kick_all(); } } diff --git a/src/main.rs b/src/main.rs index 89c4e23e..5f038103 100644 --- a/src/main.rs +++ b/src/main.rs @@ -160,7 +160,7 @@ fn real_main(cmd_args: &arg_parser::ArgMatches, vm_config: &mut VmConfig) -> Res LightMachine::new(vm_config).with_context(|| "Failed to init MicroVM")?, )); MachineOps::realize(&vm, vm_config).with_context(|| "Failed to realize micro VM.")?; - EventLoop::set_manager(vm.clone(), None); + EventLoop::set_manager(vm.clone()); for listener in listeners { sockets.push(Socket::from_listener(listener, Some(vm.clone()))); @@ -173,7 +173,7 @@ fn real_main(cmd_args: &arg_parser::ArgMatches, vm_config: &mut VmConfig) -> Res )); MachineOps::realize(&vm, vm_config) .with_context(|| "Failed to realize standard VM.")?; - EventLoop::set_manager(vm.clone(), None); + EventLoop::set_manager(vm.clone()); if is_test_enabled() { let sock_path = cmd_args.value_of("mod-test"); @@ -199,7 +199,7 @@ fn real_main(cmd_args: &arg_parser::ArgMatches, vm_config: &mut VmConfig) -> Res let vm = Arc::new(Mutex::new( StdMachine::new(vm_config).with_context(|| "Failed to init NoneVM")?, )); - EventLoop::set_manager(vm.clone(), None); + EventLoop::set_manager(vm.clone()); for listener in listeners { sockets.push(Socket::from_listener(listener, Some(vm.clone()))); diff --git a/util/src/loop_context.rs b/util/src/loop_context.rs index ecad86e2..ded2f1fe 100644 --- a/util/src/loop_context.rs +++ b/util/src/loop_context.rs @@ -16,7 +16,7 @@ use std::fmt::Debug; use std::os::unix::io::{AsRawFd, RawFd}; use std::rc::Rc; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; -use std::sync::{Arc, Mutex, RwLock}; +use std::sync::{Arc, Barrier, Mutex, RwLock}; use std::time::{Duration, Instant}; use anyhow::{anyhow, Context, Result}; @@ -219,6 +219,8 @@ pub struct EventLoopContext { pub thread_pool: Arc, /// Record VM clock state. pub clock_state: Arc>, + /// The io thread barrier. + pub thread_exit_barrier: Arc, } impl Drop for EventLoopContext { @@ -235,7 +237,7 @@ unsafe impl Send for EventLoopContext {} impl EventLoopContext { /// Constructs a new `EventLoopContext`. - pub fn new() -> Self { + pub fn new(thread_exit_barrier: Arc) -> Self { let mut ctx = EventLoopContext { epoll: Epoll::new().unwrap(), manager: None, @@ -249,6 +251,7 @@ impl EventLoopContext { timer_next_id: AtomicU64::new(0), thread_pool: Arc::new(ThreadPool::default()), clock_state: Arc::new(Mutex::new(ClockState::default())), + thread_exit_barrier, }; ctx.init_kick(); ctx @@ -716,12 +719,6 @@ impl EventLoopContext { } } -impl Default for EventLoopContext { - fn default() -> Self { - Self::new() - } -} - pub fn read_fd(fd: RawFd) -> u64 { let mut value: u64 = 0; @@ -746,6 +743,7 @@ pub fn read_fd(fd: RawFd) -> u64 { #[cfg(test)] mod test { use std::os::unix::io::{AsRawFd, RawFd}; + use std::sync::Barrier; use vmm_sys_util::{epoll::EventSet, eventfd::EventFd}; @@ -794,7 +792,7 @@ mod test { #[test] fn basic_test() { - let mut mainloop = EventLoopContext::new(); + let mut mainloop = EventLoopContext::new(Arc::new(Barrier::new(1))); let mut notifiers = Vec::new(); let fd1 = EventFd::new(EFD_NONBLOCK).unwrap(); let fd1_related = EventFd::new(EFD_NONBLOCK).unwrap(); @@ -822,7 +820,7 @@ mod test { #[test] fn parked_event_test() { - let mut mainloop = EventLoopContext::new(); + let mut mainloop = EventLoopContext::new(Arc::new(Barrier::new(1))); let mut notifiers = Vec::new(); let fd1 = EventFd::new(EFD_NONBLOCK).unwrap(); let fd2 = EventFd::new(EFD_NONBLOCK).unwrap(); @@ -869,7 +867,7 @@ mod test { #[test] fn event_handler_test() { - let mut mainloop = EventLoopContext::new(); + let mut mainloop = EventLoopContext::new(Arc::new(Barrier::new(1))); let mut notifiers = Vec::new(); let fd1 = EventFd::new(EFD_NONBLOCK).unwrap(); let fd1_related = EventFd::new(EFD_NONBLOCK).unwrap(); @@ -908,7 +906,7 @@ mod test { #[test] fn error_operation_test() { - let mut mainloop = EventLoopContext::new(); + let mut mainloop = EventLoopContext::new(Arc::new(Barrier::new(1))); let fd1 = EventFd::new(EFD_NONBLOCK).unwrap(); let leisure_fd = EventFd::new(EFD_NONBLOCK).unwrap(); @@ -945,7 +943,7 @@ mod test { #[test] fn error_parked_operation_test() { - let mut mainloop = EventLoopContext::new(); + let mut mainloop = EventLoopContext::new(Arc::new(Barrier::new(1))); let fd1 = EventFd::new(EFD_NONBLOCK).unwrap(); let fd2 = EventFd::new(EFD_NONBLOCK).unwrap(); @@ -980,7 +978,7 @@ mod test { #[test] fn fd_released_test() { - let mut mainloop = EventLoopContext::new(); + let mut mainloop = EventLoopContext::new(Arc::new(Barrier::new(1))); let fd = mainloop.create_event(); // In this case, fd is already closed. But program was wrote to ignore the error. -- Gitee From 435606fbfe12e623e30c4da0b4f0699b6f95cc3f Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 16 May 2024 14:49:11 +0800 Subject: [PATCH 068/489] machine_manager: add func to get value of a parameter from string Add func `get_value_of_parameter` to get value of parameter from string. Signed-off-by: liuxiangdong --- machine_manager/src/config/mod.rs | 34 +++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index 0355a6b9..f6a5d9a2 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -803,6 +803,24 @@ pub fn str_slip_to_clap( itr } +/// Retrieve the value of the specified parameter from a string in the format "key=value". +pub fn get_value_of_parameter(parameter: &str, args_str: &str) -> Result { + let args_vecs = args_str.split([',']).collect::>(); + + for args in args_vecs { + let key_value = args.split(['=']).collect::>(); + if key_value.len() != 2 || key_value[0] != parameter { + continue; + } + if key_value[1].is_empty() { + bail!("Find empty arg {} in string {}.", key_value[0], args_str); + } + return Ok(key_value[1].to_string()); + } + + bail!("Cannot find {}'s value from string {}", parameter, args_str); +} + pub fn valid_id(id: &str) -> Result { check_arg_too_long(id, "id")?; Ok(id.to_string()) @@ -1007,4 +1025,20 @@ mod tests { let res = vm_config.add_global_config("pcie-root-port.fast-unplug=1"); assert!(res.is_err()); } + + #[test] + fn test_get_value_of_parameter() { + let cmd = "scsi-hd,id=disk1,drive=scsi-drive-0"; + let id = get_value_of_parameter("id", cmd).unwrap(); + assert_eq!(id, "disk1"); + + let cmd = "id="; + assert!(get_value_of_parameter("id", cmd).is_err()); + + let cmd = "id"; + assert!(get_value_of_parameter("id", cmd).is_err()); + + let cmd = "scsi-hd,idxxx=disk1"; + assert!(get_value_of_parameter("id", cmd).is_err()); + } } -- Gitee From 8c911f5cb2183e43019e76a26c6e04d30b049598 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 16 May 2024 19:22:11 +0800 Subject: [PATCH 069/489] machine_manager: use `get_value_of_parameter` to get a single parameter's value Use `get_value_of_parameter` func to get a single parameter's value. Signed-off-by: liuxiangdong --- machine/src/lib.rs | 16 +++++----- machine_manager/src/config/devices.rs | 45 ++------------------------- machine_manager/src/config/mod.rs | 32 ++++++++++--------- machine_manager/src/config/numa.rs | 32 ++++++++----------- machine_manager/src/config/pci.rs | 23 +++++--------- 5 files changed, 49 insertions(+), 99 deletions(-) diff --git a/machine/src/lib.rs b/machine/src/lib.rs index ab0957c9..990f9cc2 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -73,11 +73,11 @@ use hypervisor::{kvm::KvmHypervisor, test::TestHypervisor, HypervisorOps}; #[cfg(feature = "usb_camera")] use machine_manager::config::get_cameradev_by_id; use machine_manager::config::{ - complete_numa_node, get_chardev_socket_path, get_pci_bdf, parse_device_id, parse_device_type, - parse_numa_distance, parse_numa_mem, str_slip_to_clap, BootIndexInfo, BootSource, ConfigCheck, - DriveConfig, DriveFile, Incoming, MachineMemConfig, MigrateMode, NetworkInterfaceConfig, - NumaConfig, NumaDistance, NumaNode, NumaNodes, PciBdf, SerialConfig, VirtioSerialInfo, - VirtioSerialPortCfg, VmConfig, FAST_UNPLUG_ON, MAX_VIRTIO_QUEUE, + complete_numa_node, get_chardev_socket_path, get_class_type, get_pci_bdf, + get_value_of_parameter, parse_numa_distance, parse_numa_mem, str_slip_to_clap, BootIndexInfo, + BootSource, ConfigCheck, DriveConfig, DriveFile, Incoming, MachineMemConfig, MigrateMode, + NetworkInterfaceConfig, NumaConfig, NumaDistance, NumaNode, NumaNodes, PciBdf, SerialConfig, + VirtioSerialInfo, VirtioSerialPortCfg, VmConfig, FAST_UNPLUG_ON, MAX_VIRTIO_QUEUE, }; use machine_manager::event_loop::EventLoop; use machine_manager::machine::{HypervisorType, MachineInterface, VmState}; @@ -570,7 +570,7 @@ pub trait MachineOps { VhostKern::VsockConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; let sys_mem = self.get_sys_mem().clone(); let vsock = Arc::new(Mutex::new(VhostKern::Vsock::new(&device_cfg, &sys_mem))); - match parse_device_type(cfg_args)?.as_str() { + match device_cfg.classtype.as_str() { "vhost-vsock-device" => { check_arg_nonexist!( ("bus", device_cfg.bus), @@ -1771,7 +1771,7 @@ pub trait MachineOps { /// * `driver` - USB device class. /// * `cfg_args` - USB device Configuration. fn add_usb_device(&mut self, vm_config: &mut VmConfig, cfg_args: &str) -> Result<()> { - let usb_device = match parse_device_type(cfg_args)?.as_str() { + let usb_device = match get_class_type(cfg_args)?.as_str() { "usb-kbd" => { let config = UsbKeyboardConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; @@ -1873,7 +1873,7 @@ pub trait MachineOps { for dev in &cloned_vm_config.devices { let cfg_args = dev.1.as_str(); // Check whether the device id exists to ensure device uniqueness. - let id = parse_device_id(cfg_args)?; + let id = get_value_of_parameter("id", cfg_args)?; self.check_device_id_existed(&id) .with_context(|| format!("Failed to check device id: config {}", cfg_args))?; #[cfg(feature = "scream")] diff --git a/machine_manager/src/config/devices.rs b/machine_manager/src/config/devices.rs index cf42739b..e355b88f 100644 --- a/machine_manager/src/config/devices.rs +++ b/machine_manager/src/config/devices.rs @@ -13,7 +13,7 @@ use anyhow::{Context, Result}; use regex::Regex; -use super::{CmdParser, VmConfig}; +use super::{get_class_type, VmConfig}; use crate::qmp::qmp_schema; impl VmConfig { @@ -117,7 +117,7 @@ impl VmConfig { } pub fn add_device(&mut self, device_config: &str) -> Result<()> { - let device_type = parse_device_type(device_config)?; + let device_type = get_class_type(device_config).with_context(|| "Missing driver field.")?; self.devices.push((device_type, device_config.to_string())); Ok(()) @@ -135,44 +135,3 @@ impl VmConfig { } } } - -pub fn parse_device_type(device_config: &str) -> Result { - let mut cmd_params = CmdParser::new("device"); - cmd_params.push(""); - cmd_params.get_parameters(device_config)?; - cmd_params - .get_value::("")? - .with_context(|| "Missing driver field.") -} - -pub fn parse_device_id(device_config: &str) -> Result { - let mut cmd_parser = CmdParser::new("device"); - cmd_parser.push("id"); - - cmd_parser.get_parameters(device_config)?; - if let Some(id) = cmd_parser.get_value::("id")? { - Ok(id) - } else { - Ok(String::new()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_parse_device_id() { - let test_conf = "virtio-blk-device,drive=rootfs,id=blkid"; - let ret = parse_device_id(test_conf); - assert!(ret.is_ok()); - let id = ret.unwrap(); - assert_eq!("blkid", id); - - let test_conf = "virtio-blk-device,drive=rootfs"; - let ret = parse_device_id(test_conf); - assert!(ret.is_ok()); - let id = ret.unwrap(); - assert_eq!("", id); - } -} diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index f6a5d9a2..ab6c0edf 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -204,14 +204,9 @@ impl VmConfig { /// /// * `object_args` - The args of object. pub fn add_object(&mut self, object_args: &str) -> Result<()> { - let mut cmd_params = CmdParser::new("object"); - cmd_params.push(""); - - cmd_params.get_parameters(object_args)?; - let device_type = cmd_params - .get_value::("")? - .with_context(|| "Object type not specified")?; - match device_type.as_str() { + let object_type = + get_class_type(object_args).with_context(|| "Object type not specified")?; + match object_type.as_str() { "iothread" => { self.add_iothread(object_args) .with_context(|| "Failed to add iothread")?; @@ -237,7 +232,7 @@ impl VmConfig { self.add_saslauth(object_args)?; } _ => { - bail!("Unknow object type: {:?}", &device_type); + bail!("Unknow object type: {:?}", &object_type); } } @@ -746,6 +741,14 @@ macro_rules! check_arg_nonexist{ } } +fn concat_classtype(args: &str, concat: bool) -> String { + if concat { + format!("classtype={}", args) + } else { + args.to_string() + } +} + /// Configure StratoVirt parameters in clap format. /// /// The first parameter will be parsed as the `binary name` unless Command::no_binary_name is used when using `clap`. @@ -776,11 +779,7 @@ pub fn str_slip_to_clap( first_pos_is_subcommand: bool, ) -> Vec { let mut subcommand = first_pos_is_subcommand; - let args_str = if first_pos_is_type && !subcommand { - format!("classtype={}", args) - } else { - args.to_string() - }; + let args_str = concat_classtype(args, first_pos_is_type && !subcommand); let args_vecs = args_str.split([',']).collect::>(); let mut itr: Vec = Vec::with_capacity(args_vecs.len() * 2); for params in args_vecs { @@ -821,6 +820,11 @@ pub fn get_value_of_parameter(parameter: &str, args_str: &str) -> Result bail!("Cannot find {}'s value from string {}", parameter, args_str); } +pub fn get_class_type(args: &str) -> Result { + let args_str = concat_classtype(args, true); + get_value_of_parameter("classtype", &args_str) +} + pub fn valid_id(id: &str) -> Result { check_arg_too_long(id, "id")?; Ok(id.to_string()) diff --git a/machine_manager/src/config/numa.rs b/machine_manager/src/config/numa.rs index a9a0bfa3..27da8260 100644 --- a/machine_manager/src/config/numa.rs +++ b/machine_manager/src/config/numa.rs @@ -16,6 +16,7 @@ use std::collections::{BTreeMap, HashSet}; use anyhow::{anyhow, bail, Context, Result}; use super::error::ConfigError; +use super::get_class_type; use crate::config::{CmdParser, IntegerList, VmConfig, MAX_NODES}; const MIN_NUMA_DISTANCE: u8 = 10; @@ -238,13 +239,8 @@ impl VmConfig { /// /// * `numa_config` - The NUMA node configuration. pub fn add_numa(&mut self, numa_config: &str) -> Result<()> { - let mut cmd_params = CmdParser::new("numa"); - cmd_params.push(""); - - cmd_params.get_parameters(numa_config)?; - if let Some(numa_type) = cmd_params.get_value::("")? { - self.numa_nodes.push((numa_type, numa_config.to_string())); - } + let numa_type = get_class_type(numa_config).with_context(|| "Numa type not specified")?; + self.numa_nodes.push((numa_type, numa_config.to_string())); Ok(()) } @@ -258,17 +254,15 @@ mod tests { fn test_parse_numa_mem() { let mut vm_config = VmConfig::default(); assert!(vm_config - .add_numa("-numa node,nodeid=0,cpus=0-1,memdev=mem0") - .is_ok()); - assert!(vm_config - .add_numa("-numa node,nodeid=1,cpus=2-1,memdev=mem1") + .add_numa("node,nodeid=0,cpus=0-1,memdev=mem0") .is_ok()); assert!(vm_config - .add_numa("-numa node,nodeid=2,memdev=mem2") + .add_numa("node,nodeid=1,cpus=2-1,memdev=mem1") .is_ok()); - assert!(vm_config.add_numa("-numa node,nodeid=3,cpus=3-4").is_ok()); + assert!(vm_config.add_numa("node,nodeid=2,memdev=mem2").is_ok()); + assert!(vm_config.add_numa("node,nodeid=3,cpus=3-4").is_ok()); assert!(vm_config - .add_numa("-numa node,nodeid=0,cpus=[0-1:3-5],memdev=mem0") + .add_numa("node,nodeid=0,cpus=[0-1:3-5],memdev=mem0") .is_ok()); let numa = vm_config.numa_nodes.get(0).unwrap(); @@ -291,11 +285,11 @@ mod tests { #[test] fn test_parse_numa_distance() { let mut vm_config = VmConfig::default(); - assert!(vm_config.add_numa("-numa dist,src=0,dst=1,val=15").is_ok()); - assert!(vm_config.add_numa("-numa dist,dst=1,val=10").is_ok()); - assert!(vm_config.add_numa("-numa dist,src=0,val=10").is_ok()); - assert!(vm_config.add_numa("-numa dist,src=0,dst=1").is_ok()); - assert!(vm_config.add_numa("-numa dist,src=0,dst=1,val=10").is_ok()); + assert!(vm_config.add_numa("dist,src=0,dst=1,val=15").is_ok()); + assert!(vm_config.add_numa("dist,dst=1,val=10").is_ok()); + assert!(vm_config.add_numa("dist,src=0,val=10").is_ok()); + assert!(vm_config.add_numa("dist,src=0,dst=1").is_ok()); + assert!(vm_config.add_numa("dist,src=0,dst=1,val=10").is_ok()); let numa = vm_config.numa_nodes.get(0).unwrap(); let dist = parse_numa_distance(numa.1.as_str()).unwrap(); diff --git a/machine_manager/src/config/pci.rs b/machine_manager/src/config/pci.rs index cad97dec..4f054e90 100644 --- a/machine_manager/src/config/pci.rs +++ b/machine_manager/src/config/pci.rs @@ -13,7 +13,7 @@ use anyhow::{bail, Context, Result}; use serde::{Deserialize, Serialize}; -use super::CmdParser; +use super::{get_value_of_parameter, CmdParser}; use crate::config::ExBool; use util::num_ops::str_to_num; @@ -71,21 +71,14 @@ pub fn get_pci_df(addr: &str) -> Result<(u8, u8)> { } pub fn get_pci_bdf(pci_cfg: &str) -> Result { - let mut cmd_parser = CmdParser::new("bdf"); - cmd_parser.push("").push("bus").push("addr"); - cmd_parser.get_parameters(pci_cfg)?; - - let mut pci_bdf = PciBdf { - bus: cmd_parser - .get_value::("bus")? - .with_context(|| "Bus not specified for pci device")?, - ..Default::default() - }; - if let Some(addr) = cmd_parser.get_value::("addr")? { - pci_bdf.addr = get_pci_df(&addr).with_context(|| "Failed to get addr")?; - } else { - bail!("No addr found for pci device"); + let bus = get_value_of_parameter("bus", pci_cfg)?; + let addr_str = get_value_of_parameter("addr", pci_cfg)?; + if addr_str.is_empty() { + bail!("Invalid addr."); } + let addr = get_pci_df(&addr_str).with_context(|| "Failed to get addr")?; + let pci_bdf = PciBdf::new(bus, addr); + Ok(pci_bdf) } -- Gitee From e3185201135cd691ef38dcac8d21d03ff667be51 Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Thu, 2 May 2024 15:47:38 +0300 Subject: [PATCH 070/489] net: Refactor rx, improve tx Suppress tx virtio queue notify and listen for tap fd OUT event when the tap is full instead of going into a busy loop. Remove redundant recv_evt for rx. Signed-off-by: goriainovstanislav --- virtio/src/device/net.rs | 172 ++++++++++++++++++++++++++------------- 1 file changed, 115 insertions(+), 57 deletions(-) diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index 1691dc06..0e5a9a84 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -672,13 +672,18 @@ impl EventNotifierHelper for NetCtrlHandler { } struct TxVirtio { + tap_full: bool, queue: Arc>, queue_evt: Arc, } impl TxVirtio { fn new(queue: Arc>, queue_evt: Arc) -> Self { - TxVirtio { queue, queue_evt } + TxVirtio { + tap_full: false, + queue, + queue_evt, + } } } @@ -686,16 +691,14 @@ struct RxVirtio { queue_full: bool, queue: Arc>, queue_evt: Arc, - recv_evt: Arc, } impl RxVirtio { - fn new(queue: Arc>, queue_evt: Arc, recv_evt: Arc) -> Self { + fn new(queue: Arc>, queue_evt: Arc) -> Self { RxVirtio { queue_full: false, queue, queue_evt, - recv_evt, } } } @@ -863,7 +866,7 @@ impl NetIoHandler { rx_packets += 1; if rx_packets >= self.queue_size { self.rx - .recv_evt + .queue_evt .write(1) .with_context(|| "Failed to trigger tap queue event".to_string())?; break; @@ -925,10 +928,12 @@ impl NetIoHandler { }; if tap_fd != -1 && self.send_packets(tap_fd, &iovecs) == -1 { queue.vring.push_back(); - self.tx.queue_evt.write(1).with_context(|| { - "Failed to trigger tx queue event when writev blocked".to_string() - })?; - return Ok(()); + queue + .vring + .suppress_queue_notify(&self.mem_space, self.driver_features, true) + .with_context(|| "Failed to suppress tx queue notify")?; + self.tx.tap_full = true; + break; } queue @@ -959,6 +964,50 @@ impl NetIoHandler { Ok(()) } + fn tap_fd_handler(net_io: &mut Self) -> Vec { + let mut notifiers = Vec::new(); + + if !net_io.is_listening && (!net_io.rx.queue_full || net_io.tx.tap_full) { + notifiers.push(EventNotifier::new( + NotifierOperation::Resume, + net_io.tap_fd, + None, + EventSet::empty(), + Vec::new(), + )); + net_io.is_listening = true; + } + + if !net_io.is_listening { + return notifiers; + } + + // NOTE: We want to poll for OUT event when the tap is full, and for IN event when the + // virtio queue is NOT full. + let tap_events = match (net_io.rx.queue_full, net_io.tx.tap_full) { + (false, true) => EventSet::OUT | EventSet::IN | EventSet::EDGE_TRIGGERED, + (true, true) => EventSet::OUT | EventSet::EDGE_TRIGGERED, + (false, false) => EventSet::IN | EventSet::EDGE_TRIGGERED, + (true, false) => EventSet::empty(), + }; + + let tap_operation = if tap_events.is_empty() { + net_io.is_listening = false; + NotifierOperation::Park + } else { + NotifierOperation::Modify + }; + + notifiers.push(EventNotifier::new( + tap_operation, + net_io.tap_fd, + None, + tap_events, + Vec::new(), + )); + notifiers + } + fn update_evt_handler(net_io: &Arc>) -> Vec { let mut locked_net_io = net_io.lock().unwrap(); locked_net_io.tap = match locked_net_io.receiver.recv() { @@ -977,7 +1026,6 @@ impl NetIoHandler { let mut notifiers_fds = vec![ locked_net_io.update_evt.as_raw_fd(), locked_net_io.rx.queue_evt.as_raw_fd(), - locked_net_io.rx.recv_evt.as_raw_fd(), locked_net_io.tx.queue_evt.as_raw_fd(), ]; if old_tap_fd != -1 { @@ -1055,30 +1103,23 @@ impl EventNotifierHelper for NetIoHandler { return None; } - if let Err(ref e) = locked_net_io.rx.recv_evt.write(1) { - error!("Failed to trigger tap receive event, {:?}", e); + locked_net_io.rx.queue_full = false; + + if let Err(ref err) = locked_net_io.handle_rx() { + error!("Failed to handle receive queue event: {:?}", err); report_virtio_error( locked_net_io.interrupt_cb.clone(), locked_net_io.driver_features, &locked_net_io.device_broken, ); + return None; } - if let Some(tap) = locked_net_io.tap.as_ref() { - if !locked_net_io.is_listening { - let notifier = vec![EventNotifier::new( - NotifierOperation::Resume, - tap.as_raw_fd(), - None, - EventSet::IN | EventSet::EDGE_TRIGGERED, - Vec::new(), - )]; - locked_net_io.is_listening = true; - locked_net_io.rx.queue_full = false; - return Some(notifier); - } + if locked_net_io.tap.is_some() { + Some(NetIoHandler::tap_fd_handler(&mut locked_net_io)) + } else { + None } - None }); let rx_fd = locked_net_io.rx.queue_evt.as_raw_fd(); notifiers.push(build_event_notifier( @@ -1096,6 +1137,7 @@ impl EventNotifierHelper for NetIoHandler { if locked_net_io.device_broken.load(Ordering::SeqCst) { return None; } + if let Err(ref e) = locked_net_io.handle_tx() { error!("Failed to handle tx(tx event) for net, {:?}", e); report_virtio_error( @@ -1104,7 +1146,12 @@ impl EventNotifierHelper for NetIoHandler { &locked_net_io.device_broken, ); } - None + + if locked_net_io.tap.is_some() { + Some(NetIoHandler::tap_fd_handler(&mut locked_net_io)) + } else { + None + } }); let tx_fd = locked_net_io.tx.queue_evt.as_raw_fd(); notifiers.push(build_event_notifier( @@ -1117,50 +1164,62 @@ impl EventNotifierHelper for NetIoHandler { // Register event notifier for tap. let cloned_net_io = net_io.clone(); if let Some(tap) = locked_net_io.tap.as_ref() { - let handler: Rc = Rc::new(move |_, _| { + let handler: Rc = Rc::new(move |events: EventSet, _| { let mut locked_net_io = cloned_net_io.lock().unwrap(); if locked_net_io.device_broken.load(Ordering::SeqCst) { return None; } - if let Err(ref e) = locked_net_io.handle_rx() { - error!("Failed to handle rx(tap event), {:?}", e); - report_virtio_error( - locked_net_io.interrupt_cb.clone(), + if events.contains(EventSet::OUT) { + locked_net_io.tx.tap_full = false; + let mut locked_queue = locked_net_io.tx.queue.lock().unwrap(); + + if let Err(ref err) = locked_queue.vring.suppress_queue_notify( + &locked_net_io.mem_space, locked_net_io.driver_features, - &locked_net_io.device_broken, - ); - return None; + false, + ) { + error!("Failed to enable tx queue notify: {:?}", err); + report_virtio_error( + locked_net_io.interrupt_cb.clone(), + locked_net_io.driver_features, + &locked_net_io.device_broken, + ); + return None; + }; + + drop(locked_queue); + + if let Err(ref e) = locked_net_io.handle_tx() { + error!("Failed to handle tx(tx event) for net, {:?}", e); + report_virtio_error( + locked_net_io.interrupt_cb.clone(), + locked_net_io.driver_features, + &locked_net_io.device_broken, + ); + } } - if let Some(tap) = locked_net_io.tap.as_ref() { - if locked_net_io.rx.queue_full && locked_net_io.is_listening { - let notifier = vec![EventNotifier::new( - NotifierOperation::Park, - tap.as_raw_fd(), - None, - EventSet::IN | EventSet::EDGE_TRIGGERED, - Vec::new(), - )]; - locked_net_io.is_listening = false; - return Some(notifier); + if events.contains(EventSet::IN) { + if let Err(ref err) = locked_net_io.handle_rx() { + error!("Failed to handle receive queue event: {:?}", err); + report_virtio_error( + locked_net_io.interrupt_cb.clone(), + locked_net_io.driver_features, + &locked_net_io.device_broken, + ); + return None; } } - None + + Some(NetIoHandler::tap_fd_handler(&mut locked_net_io)) }); let tap_fd = tap.as_raw_fd(); notifiers.push(build_event_notifier( tap_fd, Some(handler.clone()), NotifierOperation::AddShared, - EventSet::IN | EventSet::EDGE_TRIGGERED, - )); - let recv_evt_fd = locked_net_io.rx.recv_evt.as_raw_fd(); - notifiers.push(build_event_notifier( - recv_evt_fd, - Some(handler), - NotifierOperation::AddShared, - EventSet::IN | EventSet::EDGE_TRIGGERED, + EventSet::OUT | EventSet::IN | EventSet::EDGE_TRIGGERED, )); } @@ -1565,9 +1624,8 @@ impl VirtioDevice for Net { } let update_evt = Arc::new(EventFd::new(libc::EFD_NONBLOCK)?); - let recv_evt = Arc::new(EventFd::new(libc::EFD_NONBLOCK)?); let mut handler = NetIoHandler { - rx: RxVirtio::new(rx_queue, rx_queue_evt, recv_evt), + rx: RxVirtio::new(rx_queue, rx_queue_evt), tx: TxVirtio::new(tx_queue, tx_queue_evt), tap: self.taps.as_ref().map(|t| t[index].clone()), tap_fd: -1, -- Gitee From 3b76cd2df3144fbe156064bf0d2dd181fedb0e19 Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Tue, 7 May 2024 15:25:57 +0300 Subject: [PATCH 071/489] net: Tweak rx queue notify Suppress rx virtio queue notifications when the queue isn't empty. Signed-off-by: goriainovstanislav --- virtio/src/device/net.rs | 45 +++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 12 deletions(-) diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index 0e5a9a84..198f4b7f 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -688,7 +688,7 @@ impl TxVirtio { } struct RxVirtio { - queue_full: bool, + queue_avail: bool, queue: Arc>, queue_evt: Arc, } @@ -696,7 +696,7 @@ struct RxVirtio { impl RxVirtio { fn new(queue: Arc>, queue_evt: Arc) -> Self { RxVirtio { - queue_full: false, + queue_avail: false, queue, queue_evt, } @@ -795,7 +795,11 @@ impl NetIoHandler { .pop_avail(&self.mem_space, self.driver_features) .with_context(|| "Failed to pop avail ring for net rx")?; if elem.desc_num == 0 { - self.rx.queue_full = true; + queue + .vring + .suppress_queue_notify(&self.mem_space, self.driver_features, false) + .with_context(|| "Failed to enable rx queue notify")?; + self.rx.queue_avail = false; break; } else if elem.in_iovec.is_empty() { bail!("The length of in iovec is 0"); @@ -868,7 +872,7 @@ impl NetIoHandler { self.rx .queue_evt .write(1) - .with_context(|| "Failed to trigger tap queue event".to_string())?; + .with_context(|| "Failed to trigger rx queue event".to_string())?; break; } } @@ -967,7 +971,7 @@ impl NetIoHandler { fn tap_fd_handler(net_io: &mut Self) -> Vec { let mut notifiers = Vec::new(); - if !net_io.is_listening && (!net_io.rx.queue_full || net_io.tx.tap_full) { + if !net_io.is_listening && (net_io.rx.queue_avail || net_io.tx.tap_full) { notifiers.push(EventNotifier::new( NotifierOperation::Resume, net_io.tap_fd, @@ -983,12 +987,12 @@ impl NetIoHandler { } // NOTE: We want to poll for OUT event when the tap is full, and for IN event when the - // virtio queue is NOT full. - let tap_events = match (net_io.rx.queue_full, net_io.tx.tap_full) { - (false, true) => EventSet::OUT | EventSet::IN | EventSet::EDGE_TRIGGERED, - (true, true) => EventSet::OUT | EventSet::EDGE_TRIGGERED, - (false, false) => EventSet::IN | EventSet::EDGE_TRIGGERED, - (true, false) => EventSet::empty(), + // virtio queue is available. + let tap_events = match (net_io.rx.queue_avail, net_io.tx.tap_full) { + (true, true) => EventSet::OUT | EventSet::IN | EventSet::EDGE_TRIGGERED, + (false, true) => EventSet::OUT | EventSet::EDGE_TRIGGERED, + (true, false) => EventSet::IN | EventSet::EDGE_TRIGGERED, + (false, false) => EventSet::empty(), }; let tap_operation = if tap_events.is_empty() { @@ -1103,7 +1107,24 @@ impl EventNotifierHelper for NetIoHandler { return None; } - locked_net_io.rx.queue_full = false; + locked_net_io.rx.queue_avail = true; + let mut locked_queue = locked_net_io.rx.queue.lock().unwrap(); + + if let Err(ref err) = locked_queue.vring.suppress_queue_notify( + &locked_net_io.mem_space, + locked_net_io.driver_features, + true, + ) { + error!("Failed to suppress rx queue notify: {:?}", err); + report_virtio_error( + locked_net_io.interrupt_cb.clone(), + locked_net_io.driver_features, + &locked_net_io.device_broken, + ); + return None; + }; + + drop(locked_queue); if let Err(ref err) = locked_net_io.handle_rx() { error!("Failed to handle receive queue event: {:?}", err); -- Gitee From 5ab6a296752fb84fab59005288ef8af5a0b5a366 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Mon, 27 May 2024 14:40:06 +0800 Subject: [PATCH 072/489] ohaudio: fixup hang issue while destorying capturer Currently we stop capturer firstly then set start to false. The capture callback might loop forever because start is true. Then the stop function we called would hang because capture callback cannot reuturn. So let's set start to false firstly and then call stop function. Signed-off-by: Zhao Yi Min --- devices/src/misc/scream/ohaudio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index f1ea1061..10f9cb85 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -212,8 +212,8 @@ impl OhAudioProcess for OhAudioCapture { fn destroy(&mut self) { if self.ctx.is_some() { if self.start { - self.ctx.as_mut().unwrap().stop(); self.start = false; + self.ctx.as_mut().unwrap().stop(); } self.ctx = None; } -- Gitee From 90bbc03acf6460d4af5bb446a7697fce59fb8cc3 Mon Sep 17 00:00:00 2001 From: yexiao Date: Sat, 27 Apr 2024 20:29:28 +0800 Subject: [PATCH 073/489] log: modify some log Modify some log information. Signed-off-by: Xiao Ye --- machine/src/standard_common/mod.rs | 4 ++-- machine_manager/src/cmdline.rs | 2 +- machine_manager/src/config/mod.rs | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index 67ab3e22..bac724a8 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -882,11 +882,11 @@ impl StdMachine { power_button: Arc, shutdown_req: Arc, ) { - let emu_pid = vm_config.windows_emu_pid.as_ref(); + let emu_pid = vm_config.emulator_pid.as_ref(); if emu_pid.is_none() { return; } - log::info!("Watching on windows emu lifetime"); + log::info!("Watching on emulator lifetime"); crate::check_windows_emu_pid( "/proc/".to_owned() + emu_pid.unwrap(), power_button, diff --git a/machine_manager/src/cmdline.rs b/machine_manager/src/cmdline.rs index c9f54f6e..de8e54c4 100644 --- a/machine_manager/src/cmdline.rs +++ b/machine_manager/src/cmdline.rs @@ -509,7 +509,7 @@ pub fn create_args_parser<'a>() -> ArgParser<'a> { .multiple(false) .long("windows_emu_pid") .value_name("pid") - .help("watch on the external windows emu pid") + .help("watch on the external emulator pid") .takes_value(true), ); diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index ab6c0edf..36ae7a40 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -141,7 +141,7 @@ pub struct VmConfig { #[cfg(feature = "usb_camera")] pub camera_backend: HashMap, #[cfg(feature = "windows_emu_pid")] - pub windows_emu_pid: Option, + pub emulator_pid: Option, pub smbios: SmbiosConfig, } @@ -268,9 +268,9 @@ impl VmConfig { #[cfg(feature = "windows_emu_pid")] pub fn add_windows_emu_pid(&mut self, windows_emu_pid: &str) -> Result<()> { if windows_emu_pid.is_empty() { - bail!("The arg of windows_emu_pid is empty!"); + bail!("The arg of emulator_pid is empty!"); } - self.windows_emu_pid = Some(windows_emu_pid.to_string()); + self.emulator_pid = Some(windows_emu_pid.to_string()); Ok(()) } -- Gitee From 10adf4e23c986d9485fcf176069dcf747590d5bd Mon Sep 17 00:00:00 2001 From: Yan Wang Date: Sat, 25 May 2024 15:31:57 +0800 Subject: [PATCH 074/489] ohui: add hitrace for ohui message Signed-off-by: Yan Wang --- trace/trace_info/ui.toml | 6 ++++++ ui/src/ohui_srv/msg_handle.rs | 1 + 2 files changed, 7 insertions(+) diff --git a/trace/trace_info/ui.toml b/trace/trace_info/ui.toml index 3c63d328..1df64556 100644 --- a/trace/trace_info/ui.toml +++ b/trace/trace_info/ui.toml @@ -273,3 +273,9 @@ name = "oh_event_unsupported_type" args = "ty: &dyn fmt::Debug, size: u32" message = "type={:?} body_size={}" enabled = true + +[[scopes]] +name = "handle_msg" +args = "opcode: &dyn fmt::Debug" +message = "handle ohui {:?} message" +enabled = true diff --git a/ui/src/ohui_srv/msg_handle.rs b/ui/src/ohui_srv/msg_handle.rs index eeb44c15..6b71cf9f 100755 --- a/ui/src/ohui_srv/msg_handle.rs +++ b/ui/src/ohui_srv/msg_handle.rs @@ -170,6 +170,7 @@ impl OhUiMsgHandler { reader.clear(); return Ok(()); } + trace::trace_scope_start!(handle_msg, args = (&event_type)); let body_bytes = reader.body.as_ref().unwrap(); if let Err(e) = match event_type { -- Gitee From e17896b0e8eb46fa77dce863fde121b0e15daa90 Mon Sep 17 00:00:00 2001 From: zhanghan64 Date: Tue, 28 May 2024 11:04:31 +0800 Subject: [PATCH 075/489] OHUI: fix related files' permisson Permission of ohui's cursor/fb/sock is default(644) now, We limit it to 600, removing redundant permission. --- ui/src/ohui_srv/channel.rs | 15 +++++++++++++-- ui/src/ohui_srv/mod.rs | 14 +++++++++++++- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/ui/src/ohui_srv/channel.rs b/ui/src/ohui_srv/channel.rs index 861a1634..7818367b 100755 --- a/ui/src/ohui_srv/channel.rs +++ b/ui/src/ohui_srv/channel.rs @@ -19,7 +19,7 @@ use libc::iovec; use log::error; use util::byte_code::ByteCode; -use util::unix::UnixSock; +use util::unix::{limit_permission, UnixSock}; pub struct OhUiChannel { pub sock: RwLock, @@ -35,7 +35,18 @@ impl OhUiChannel { } pub fn bind(&self) -> Result<()> { - self.sock.write().unwrap().bind(true) + match self.sock.write().unwrap().bind(true) { + Ok(_) => { + limit_permission(self.path.as_str()).unwrap_or_else(|e| { + error!( + "Failed to limit permission for ohui-sock {}, err: {:?}", + self.path, e + ); + }); + Ok(()) + } + Err(e) => Err(e), + } } pub fn get_listener_raw_fd(&self) -> RawFd { diff --git a/ui/src/ohui_srv/mod.rs b/ui/src/ohui_srv/mod.rs index b5689b57..53cbbfbd 100755 --- a/ui/src/ohui_srv/mod.rs +++ b/ui/src/ohui_srv/mod.rs @@ -52,7 +52,7 @@ use util::{ NotifierOperation, }, pixman::{pixman_format_code_t, pixman_image_t}, - unix::do_mmap, + unix::{do_mmap, limit_permission}, }; #[derive(Debug, Clone)] @@ -127,6 +127,12 @@ impl OhUiServer { .ok_or_else(|| anyhow!("init_fb_file: Failed to get str from {}", path))?; let fb_backend = FileBackend::new_mem(fb_file, VIRTIO_GPU_ENABLE_BAR0_SIZE)?; TempCleaner::add_path(fb_file.to_string()); + limit_permission(fb_file).unwrap_or_else(|e| { + error!( + "Failed to limit permission for ohui-fb {}, err: {:?}", + fb_file, e + ); + }); let host_addr = do_mmap( &Some(fb_backend.file.as_ref()), @@ -147,6 +153,12 @@ impl OhUiServer { .ok_or_else(|| anyhow!("init_cursor_file: Failed to get str from {}", path))?; let cursor_backend = FileBackend::new_mem(cursor_file, CURSOR_SIZE)?; TempCleaner::add_path(cursor_file.to_string()); + limit_permission(cursor_file).unwrap_or_else(|e| { + error!( + "Failed to limit permission for ohui-cursor {}, err: {:?}", + cursor_file, e + ); + }); let cursorbuffer = do_mmap( &Some(cursor_backend.file.as_ref()), -- Gitee From 348ee8d423d99cb13079c564d849cd8c9467a1b1 Mon Sep 17 00:00:00 2001 From: Mingwang Li Date: Tue, 28 May 2024 19:34:02 +0800 Subject: [PATCH 076/489] ged: replace store with fetch_or Using store may overwrite other events, so fetch_or is used instead. Signed-off-by: Mingwang Li --- devices/src/acpi/ged.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/devices/src/acpi/ged.rs b/devices/src/acpi/ged.rs index 55e5ba0f..7a87180b 100644 --- a/devices/src/acpi/ged.rs +++ b/devices/src/acpi/ged.rs @@ -120,7 +120,7 @@ impl Ged { read_fd(power_down_fd); ged_clone .notification_type - .store(AcpiEvent::PowerDown as u32, Ordering::SeqCst); + .fetch_or(AcpiEvent::PowerDown as u32, Ordering::SeqCst); ged_clone.inject_interrupt(); trace::ged_inject_acpi_event(AcpiEvent::PowerDown as u32); if QmpChannel::is_connected() { @@ -150,7 +150,7 @@ impl Ged { read_fd(cpu_resize_fd); clone_ged .notification_type - .store(AcpiEvent::CpuResize as u32, Ordering::SeqCst); + .fetch_or(AcpiEvent::CpuResize as u32, Ordering::SeqCst); clone_ged.inject_interrupt(); trace::ged_inject_acpi_event(AcpiEvent::CpuResize as u32); if QmpChannel::is_connected() { -- Gitee From 888a14c6b678a3bcd3b216e3398e7819d2f23461 Mon Sep 17 00:00:00 2001 From: Gan Qixin Date: Tue, 26 Mar 2024 02:29:28 +0800 Subject: [PATCH 077/489] Trace: Fix compilation error when enabled=false Signed-off-by: Gan Qixin --- trace/trace_generator/src/lib.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/trace/trace_generator/src/lib.rs b/trace/trace_generator/src/lib.rs index 008263cc..4d1a80a4 100644 --- a/trace/trace_generator/src/lib.rs +++ b/trace/trace_generator/src/lib.rs @@ -216,6 +216,11 @@ pub fn gen_trace_scope_func(_input: TokenStream) -> TokenStream { } }; + let func_decl = match desc.enabled { + true => quote!(pub fn #func_name(asyn: bool, #func_args) -> trace_scope::Scope), + false => quote!(pub fn #func_name(asyn: bool, #func_args)), + }; + let message_args = match desc.args.is_empty() { true => quote!(), false => { @@ -258,7 +263,7 @@ pub fn gen_trace_scope_func(_input: TokenStream) -> TokenStream { all(target_env = "ohos", feature = "trace_to_hitrace") ))] #[inline(always)] - pub fn #func_name(asyn: bool, #func_args) -> trace_scope::Scope { + #func_decl { #func_body } -- Gitee From adb702c7ce0c83df84d7b408ac9f2fe4f2c1d857 Mon Sep 17 00:00:00 2001 From: li-huachao Date: Mon, 27 May 2024 19:29:26 +0800 Subject: [PATCH 078/489] Balloon: introduce scopes traces. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add scopes traces for balloon when handle normal balloon、fpr and auto-balloon. --- trace/trace_info/virtio.toml | 18 ++++++++++++++++++ virtio/src/device/balloon.rs | 3 +++ 2 files changed, 21 insertions(+) diff --git a/trace/trace_info/virtio.toml b/trace/trace_info/virtio.toml index 7bff17c5..1f8ea241 100644 --- a/trace/trace_info/virtio.toml +++ b/trace/trace_info/virtio.toml @@ -297,3 +297,21 @@ name = "vhost_delete_mem_range_failed" args = "" message = "Vhost: deleting mem region failed: not matched." enabled = true + +[[scopes]] +name = "auto_msg_evt_handler" +args = "" +message = "Balloon: handle auto balloon message" +enabled = true + +[[scopes]] +name = "reporting_evt_handler" +args = "" +message = "Balloon: handle fpr message" +enabled = true + +[[scopes]] +name = "process_balloon_queue" +args = "" +message = "Balloon: handle normal balloon message" +enabled = true diff --git a/virtio/src/device/balloon.rs b/virtio/src/device/balloon.rs index bc86b048..33f89d3e 100644 --- a/virtio/src/device/balloon.rs +++ b/virtio/src/device/balloon.rs @@ -612,6 +612,7 @@ impl BalloonIoHandler { /// if `req_type` is `BALLOON_INFLATE_EVENT`, then inflate the balloon, otherwise, deflate the /// balloon. fn process_balloon_queue(&mut self, req_type: bool) -> Result<()> { + trace::trace_scope_start!(process_balloon_queue); let queue = if req_type { trace::virtio_receive_request("Balloon".to_string(), "to inflate".to_string()); &self.inf_queue @@ -648,6 +649,7 @@ impl BalloonIoHandler { } fn reporting_evt_handler(&mut self) -> Result<()> { + trace::trace_scope_start!(reporting_evt_handler); let queue = self .report_queue .as_ref() @@ -682,6 +684,7 @@ impl BalloonIoHandler { } fn auto_msg_evt_handler(&mut self) -> Result<()> { + trace::trace_scope_start!(auto_msg_evt_handler); let queue = self .msg_queue .as_ref() -- Gitee From 0595e35c94e2a38a884b3260d91adad9dd2f28b2 Mon Sep 17 00:00:00 2001 From: li-huachao Date: Mon, 27 May 2024 20:33:17 +0800 Subject: [PATCH 079/489] Memory: introduce scopes traces. --- address_space/Cargo.toml | 1 + address_space/src/address_space.rs | 11 ++++++++ address_space/src/host_mmap.rs | 1 + machine/src/lib.rs | 1 + trace/trace_info/memory.toml | 41 ++++++++++++++++++++++++++++++ 5 files changed, 55 insertions(+) create mode 100644 trace/trace_info/memory.toml diff --git a/address_space/Cargo.toml b/address_space/Cargo.toml index 7ff40882..3c1a6e14 100644 --- a/address_space/Cargo.toml +++ b/address_space/Cargo.toml @@ -19,3 +19,4 @@ machine_manager = { path = "../machine_manager" } migration = { path = "../migration" } migration_derive = { path = "../migration/migration_derive" } util = { path = "../util" } +trace = { path = "../trace" } diff --git a/address_space/src/address_space.rs b/address_space/src/address_space.rs index bad13f3b..fd419d77 100644 --- a/address_space/src/address_space.rs +++ b/address_space/src/address_space.rs @@ -611,6 +611,7 @@ impl AddressSpace { /// /// Return Error if the `addr` is not mapped. pub fn read(&self, dst: &mut dyn std::io::Write, addr: GuestAddress, count: u64) -> Result<()> { + trace::trace_scope_start!(address_space_read, args = (&addr, count)); let view = self.flat_view.load(); view.read(dst, addr, count)?; @@ -629,6 +630,7 @@ impl AddressSpace { /// /// Return Error if the `addr` is not mapped. pub fn write(&self, src: &mut dyn std::io::Read, addr: GuestAddress, count: u64) -> Result<()> { + trace::trace_scope_start!(address_space_write, args = (&addr, count)); let view = self.flat_view.load(); if !*self.hyp_ioevtfd_enabled.get_or_init(|| false) { @@ -693,6 +695,10 @@ impl AddressSpace { /// # Note /// To use this method, it is necessary to implement `ByteCode` trait for your object. pub fn write_object_direct(&self, data: &T, host_addr: u64) -> Result<()> { + trace::trace_scope_start!( + address_space_write_direct, + args = (host_addr, std::mem::size_of::()) + ); // Mark vmm dirty page manually if live migration is active. MigrationManager::mark_dirty_log(host_addr, data.as_bytes().len() as u64); @@ -732,6 +738,10 @@ impl AddressSpace { /// # Note /// To use this method, it is necessary to implement `ByteCode` trait for your object. pub fn read_object_direct(&self, host_addr: u64) -> Result { + trace::trace_scope_start!( + address_space_read_direct, + args = (host_addr, std::mem::size_of::()) + ); let mut obj = T::default(); let mut dst = obj.as_mut_bytes(); // SAFETY: host_addr is managed by address_space, it has been verified for legality. @@ -746,6 +756,7 @@ impl AddressSpace { /// Update the topology of memory. pub fn update_topology(&self) -> Result<()> { + trace::trace_scope_start!(address_update_topology); let old_fv = self.flat_view.load(); let addr_range = AddressRange::new(GuestAddress(0), self.root.size()); diff --git a/address_space/src/host_mmap.rs b/address_space/src/host_mmap.rs index da850b03..ca309770 100644 --- a/address_space/src/host_mmap.rs +++ b/address_space/src/host_mmap.rs @@ -205,6 +205,7 @@ fn touch_pages(start: u64, page_size: u64, nr_pages: u64) { /// * `size` - Size of memory. /// * `nr_vcpus` - Number of vcpus. fn mem_prealloc(host_addr: u64, size: u64, nr_vcpus: u8) { + trace::trace_scope_start!(pre_alloc, args = (size)); let page_size = host_page_size(); let threads = max_nr_threads(nr_vcpus); let nr_pages = (size + page_size - 1) / page_size; diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 990f9cc2..f58634cf 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -403,6 +403,7 @@ pub trait MachineOps { sys_mem: &Arc, nr_cpus: u8, ) -> Result<()> { + trace::trace_scope_start!(init_memory); let migrate_info = self.get_migrate_info(); if migrate_info.0 != MigrateMode::File { self.create_machine_ram(mem_config, nr_cpus)?; diff --git a/trace/trace_info/memory.toml b/trace/trace_info/memory.toml new file mode 100644 index 00000000..4ff485a5 --- /dev/null +++ b/trace/trace_info/memory.toml @@ -0,0 +1,41 @@ +[[scopes]] +name = "address_space_read" +args = "addr: &dyn fmt::Debug, count: u64" +message = "Memory: flatview_read addr {:?}, count {}" +enabled = true + +[[scopes]] +name = "address_space_write" +args = "addr: &dyn fmt::Debug, count: u64" +message = "Memory: flatview_write addr {:?}, count {}" +enabled = true + +[[scopes]] +name = "address_space_read_direct" +args = "host_addr: u64, count: usize" +message = "Memory: address_space_read_direct host_addr {}, count {}" +enabled = true + +[[scopes]] +name = "address_space_write_direct" +args = "host_addr: u64, count: usize" +message = "Memory: address_space_write_direct host_addr {}, count {}" +enabled = true + +[[scopes]] +name = "address_update_topology" +args = "" +message = "Memory: update opology" +enabled = true + +[[scopes]] +name = "pre_alloc" +args = "size: u64" +message = "Memory: pre_alloc ram size is {}" +enabled = true + +[[scopes]] +name = "init_memory" +args = "" +message = "Memory: init memory" +enabled = true -- Gitee From 0a9d4b08816810ff16887c865195983b8367072a Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Wed, 29 May 2024 14:43:32 +0800 Subject: [PATCH 080/489] ohui: optimize socket interface Because send/recv have better performance than sendmsg/recvmsg. Let's use util::socket instead of util::unix::UnixSock. Signed-off-by: Zhao Yi Min --- ui/src/ohui_srv/channel.rs | 107 +++++++++++++--------------------- ui/src/ohui_srv/mod.rs | 31 +++++----- ui/src/ohui_srv/msg_handle.rs | 59 ++++++++----------- 3 files changed, 83 insertions(+), 114 deletions(-) diff --git a/ui/src/ohui_srv/channel.rs b/ui/src/ohui_srv/channel.rs index 7818367b..561dd765 100755 --- a/ui/src/ohui_srv/channel.rs +++ b/ui/src/ohui_srv/channel.rs @@ -10,83 +10,65 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use std::os::raw::c_void; +use std::io::{Read, Write}; +use std::os::fd::AsRawFd; use std::os::unix::io::RawFd; -use std::sync::RwLock; -use anyhow::Result; -use libc::iovec; +use anyhow::{bail, Result}; use log::error; use util::byte_code::ByteCode; -use util::unix::{limit_permission, UnixSock}; +use util::socket::{SocketListener, SocketStream}; +use util::unix::limit_permission; pub struct OhUiChannel { - pub sock: RwLock, pub path: String, + pub listener: SocketListener, + pub stream: Option, } impl OhUiChannel { - pub fn new(path: &str) -> Self { - OhUiChannel { - sock: RwLock::new(UnixSock::new(path)), - path: String::from(path), - } - } + pub fn new(path: &str) -> Result { + let listener = match SocketListener::bind_by_uds(path) { + Ok(l) => l, + Err(e) => bail!("Failed to create listener with path {}, {:?}", path, e), + }; + limit_permission(path.as_str()).unwrap_or_else(|e| { + error!( + "Failed to limit permission for ohui-sock {}, err: {:?}", + path, e + ); + }); - pub fn bind(&self) -> Result<()> { - match self.sock.write().unwrap().bind(true) { - Ok(_) => { - limit_permission(self.path.as_str()).unwrap_or_else(|e| { - error!( - "Failed to limit permission for ohui-sock {}, err: {:?}", - self.path, e - ); - }); - Ok(()) - } - Err(e) => Err(e), - } + Ok(OhUiChannel { + path: String::from(path), + listener, + stream: None, + }) } pub fn get_listener_raw_fd(&self) -> RawFd { - self.sock.read().unwrap().get_listener_raw_fd() - } - - pub fn get_stream_raw_fd(&self) -> RawFd { - self.sock.read().unwrap().get_stream_raw_fd() + self.listener.as_raw_fd() } - pub fn set_nonblocking(&self, nb: bool) -> Result<()> { - self.sock.read().unwrap().set_nonblocking(nb) + pub fn get_stream_raw_fd(&self) -> Option { + self.stream.as_ref().and_then(|s| Some(s.as_raw_fd())) } - pub fn set_listener_nonblocking(&self, nb: bool) -> Result<()> { - self.sock.read().unwrap().listen_set_nonblocking(nb) - } - - pub fn accept(&self) -> Result<()> { - self.sock.write().unwrap().accept() - } - - pub fn send(&self, data: *const u8, len: usize) -> Result { - let mut iovs = Vec::with_capacity(1); - iovs.push(iovec { - iov_base: data as *mut c_void, - iov_len: len, - }); - let ret = self.sock.read().unwrap().send_msg(&mut iovs, &[])?; - Ok(ret) + pub fn accept(&mut self) -> Result<()> { + self.stream = Some(self.listener.accept()?); + Ok(()) } - pub fn send_by_obj(&self, obj: &T) -> Result<()> { + pub fn send_by_obj(&mut self, obj: &T) -> Result<()> { + let stream = self.get_stream()?; let slice = obj.as_bytes(); let mut left = slice.len(); let mut count = 0_usize; while left > 0 { let buf = &slice[count..]; - match self.send(buf.as_ptr(), left) { + match stream.write(buf) { Ok(n) => { left -= n; count += n; @@ -95,19 +77,20 @@ impl OhUiChannel { if std::io::Error::last_os_error().raw_os_error().unwrap() == libc::EAGAIN { continue; } - return Err(e); + bail!(e); } } } Ok(()) } - pub fn recv_slice(&self, data: &mut [u8]) -> Result { + pub fn recv_slice(&mut self, data: &mut [u8]) -> Result { + let stream = self.get_stream()?; let len = data.len(); if len == 0 { return Ok(0); } - let ret = self.recv(data.as_mut_ptr(), len); + let ret = stream.read(data); match ret { Ok(n) => Ok(n), Err(e) => { @@ -116,24 +99,18 @@ impl OhUiChannel { .unwrap_or(libc::EIO) != libc::EAGAIN { - error!("recv_slice(): error occurred: {}", e); + bail!("recv_slice(): error occurred: {:?}", e); } Ok(0) } } } - pub fn recv(&self, data: *mut u8, len: usize) -> Result { - let mut iovs = Vec::with_capacity(1); - iovs.push(iovec { - iov_base: data as *mut c_void, - iov_len: len, - }); - - let ret = self.sock.read().unwrap().recv_msg(&mut iovs, &mut []); - match ret { - Ok((n, _)) => Ok(n), - Err(e) => Err(e.into()), + fn get_stream(&mut self) -> Result<&mut SocketStream> { + if self.stream.is_some() { + Ok(self.stream.as_mut().unwrap()) + } else { + bail!("No connection established") } } } diff --git a/ui/src/ohui_srv/mod.rs b/ui/src/ohui_srv/mod.rs index 53cbbfbd..e53a2fcf 100755 --- a/ui/src/ohui_srv/mod.rs +++ b/ui/src/ohui_srv/mod.rs @@ -93,7 +93,7 @@ pub struct OhUiServer { // guest surface for framebuffer surface: RwLock, // transfer channel via unix sock - channel: Arc, + channel: Arc>, // message handler msg_handler: Arc, // connected or not @@ -111,13 +111,13 @@ pub struct OhUiServer { } impl OhUiServer { - fn init_channel(path: &String) -> Result> { + fn init_channel(path: &String) -> Result>> { let file_path = Path::new(path.as_str()).join("ohui.sock"); let sock_file = file_path .to_str() .ok_or_else(|| anyhow!("init_channel: Failed to get str from {}", path))?; TempCleaner::add_path(sock_file.to_string()); - Ok(Arc::new(OhUiChannel::new(sock_file))) + Ok(Arc::new(Mutex::new(OhUiChannel::new(sock_file)?))) } fn init_fb_file(path: &String) -> Result<(Option, u64)> { @@ -198,8 +198,8 @@ impl OhUiServer { } #[inline(always)] - fn get_channel(&self) -> &OhUiChannel { - self.channel.as_ref() + fn get_channel(&self) -> Arc> { + self.channel.clone() } #[inline(always)] @@ -404,7 +404,12 @@ impl OhUiTrans { } fn get_fd(&self) -> RawFd { - self.server.get_channel().get_stream_raw_fd() + self.server + .get_channel() + .lock() + .unwrap() + .get_stream_raw_fd() + .unwrap() } } @@ -449,8 +454,6 @@ impl OhUiListener { } fn handle_connection(&self) -> Result<()> { - // Set stream sock with nonblocking - self.server.get_channel().set_nonblocking(true)?; // Register OhUiTrans read notifier ohui_register_event(OhUiTrans::new(self.server.clone()), self.server.clone())?; self.server.set_connect(true); @@ -460,11 +463,15 @@ impl OhUiListener { } fn accept(&self) -> Result<()> { - self.server.get_channel().accept() + self.server.get_channel().lock().unwrap().accept() } fn get_fd(&self) -> RawFd { - self.server.get_channel().get_listener_raw_fd() + self.server + .get_channel() + .lock() + .unwrap() + .get_listener_raw_fd() } } @@ -511,10 +518,6 @@ fn ohui_register_event(e: T, srv: Arc) -> Re } fn ohui_start_listener(server: Arc) -> Result<()> { - // Bind and set listener nonblocking - let channel = server.get_channel(); - channel.bind()?; - channel.set_listener_nonblocking(true)?; ohui_register_event(OhUiListener::new(server.clone()), server.clone())?; info!("Successfully start listener."); Ok(()) diff --git a/ui/src/ohui_srv/msg_handle.rs b/ui/src/ohui_srv/msg_handle.rs index 6b71cf9f..7a8f894b 100755 --- a/ui/src/ohui_srv/msg_handle.rs +++ b/ui/src/ohui_srv/msg_handle.rs @@ -124,30 +124,25 @@ pub struct OhUiMsgHandler { state: Mutex, hmcode2svcode: HashMap, reader: Mutex, - writer: Mutex, + writer: MsgWriter, } impl SyncLedstate for OhUiMsgHandler { fn sync_to_host(&self, state: u8) { let body = LedstateEvent::new(state as u32); - if let Err(e) = self - .writer - .lock() - .unwrap() - .send_message(EventType::Ledstate, &body) - { + if let Err(e) = self.writer.send_message(EventType::Ledstate, &body) { error!("sync_to_host: failed to send message with error {e}"); } } } impl OhUiMsgHandler { - pub fn new(channel: Arc) -> Self { + pub fn new(channel: Arc>) -> Self { OhUiMsgHandler { state: Mutex::new(WindowState::default()), hmcode2svcode: KeyCode::keysym_to_qkeycode(DpyMod::Ohui), reader: Mutex::new(MsgReader::new(channel.clone())), - writer: Mutex::new(MsgWriter::new(channel)), + writer: MsgWriter::new(channel), } } @@ -257,12 +252,7 @@ impl OhUiMsgHandler { size_per_pixel: u32, ) { let body = HWCursorEvent::new(w, h, hot_x, hot_y, size_per_pixel); - if let Err(e) = self - .writer - .lock() - .unwrap() - .send_message(EventType::CursorDefine, &body) - { + if let Err(e) = self.writer.send_message(EventType::CursorDefine, &body) { error!("handle_cursor_define: failed to send message with error {e}"); } } @@ -332,24 +322,14 @@ impl OhUiMsgHandler { pub fn send_windowinfo(&self, w: u32, h: u32) { self.state.lock().unwrap().update_window_info(w, h); let body = WindowInfoEvent::new(w, h); - if let Err(e) = self - .writer - .lock() - .unwrap() - .send_message(EventType::WindowInfo, &body) - { + if let Err(e) = self.writer.send_message(EventType::WindowInfo, &body) { error!("send_windowinfo: failed to send message with error {e}"); } } pub fn handle_dirty_area(&self, x: u32, y: u32, w: u32, h: u32) { let body = FrameBufferDirtyEvent::new(x, y, w, h); - if let Err(e) = self - .writer - .lock() - .unwrap() - .send_message(EventType::FrameBufferDirty, &body) - { + if let Err(e) = self.writer.send_message(EventType::FrameBufferDirty, &body) { error!("handle_dirty_area: failed to send message with error {e}"); } } @@ -357,7 +337,7 @@ impl OhUiMsgHandler { struct MsgReader { /// socket to read - channel: Arc, + channel: Arc>, /// cache for header pub header: EventMsgHdr, /// received byte size of header @@ -369,7 +349,7 @@ struct MsgReader { } impl MsgReader { - pub fn new(channel: Arc) -> Self { + pub fn new(channel: Arc>) -> Self { MsgReader { channel, header: EventMsgHdr::default(), @@ -398,7 +378,11 @@ impl MsgReader { } let buf = self.header.as_mut_bytes(); - self.header_ready += self.channel.recv_slice(&mut buf[self.header_ready..])?; + self.header_ready += self + .channel + .lock() + .unwrap() + .recv_slice(&mut buf[self.header_ready..])?; Ok(self.header_ready == EVENT_MSG_HDR_SIZE as usize) } @@ -420,22 +404,27 @@ impl MsgReader { unsafe { buf.set_len(body_size); } - self.body_ready += self.channel.recv_slice(&mut buf[self.body_ready..])?; + self.body_ready += self + .channel + .lock() + .unwrap() + .recv_slice(&mut buf[self.body_ready..])?; Ok(self.body_ready == body_size) } } -struct MsgWriter(Arc); +struct MsgWriter(Arc>); impl MsgWriter { - fn new(channel: Arc) -> Self { + fn new(channel: Arc>) -> Self { MsgWriter(channel) } fn send_message(&self, t: EventType, body: &T) -> Result<()> { + let mut channel = self.0.lock().unwrap(); let hdr = EventMsgHdr::new(t); - self.0.send_by_obj(&hdr)?; - self.0.send_by_obj(body) + channel.send_by_obj(&hdr)?; + channel.send_by_obj(body) } } -- Gitee From e5751f48a7bad58138f50495cfbf09e9280b253d Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Wed, 29 May 2024 19:57:11 +0800 Subject: [PATCH 081/489] ohui: disconnect if received data is wrong If received data is wrong, we should notify the client but for now we have no this kind of mechanism. So let's disconnect directly. Signed-off-by: Zhao Yi Min --- ui/src/ohui_srv/channel.rs | 6 ++++++ ui/src/ohui_srv/mod.rs | 2 ++ ui/src/ohui_srv/msg_handle.rs | 9 ++++++--- 3 files changed, 14 insertions(+), 3 deletions(-) diff --git a/ui/src/ohui_srv/channel.rs b/ui/src/ohui_srv/channel.rs index 561dd765..008a7e26 100755 --- a/ui/src/ohui_srv/channel.rs +++ b/ui/src/ohui_srv/channel.rs @@ -106,6 +106,12 @@ impl OhUiChannel { } } + pub fn disconnect(&mut self) { + if self.stream.is_some() { + self.stream = None; + } + } + fn get_stream(&mut self) -> Result<&mut SocketStream> { if self.stream.is_some() { Ok(self.stream.as_mut().unwrap()) diff --git a/ui/src/ohui_srv/mod.rs b/ui/src/ohui_srv/mod.rs index e53a2fcf..603abb60 100755 --- a/ui/src/ohui_srv/mod.rs +++ b/ui/src/ohui_srv/mod.rs @@ -269,6 +269,8 @@ impl OhUiServer { register_led_sync(self.msg_handler.clone()); } else { unregister_led_sync(); + self.channel.lock().unwrap().disconnect(); + self.msg_handler.reset(); } } diff --git a/ui/src/ohui_srv/msg_handle.rs b/ui/src/ohui_srv/msg_handle.rs index 7a8f894b..5fb84f5e 100755 --- a/ui/src/ohui_srv/msg_handle.rs +++ b/ui/src/ohui_srv/msg_handle.rs @@ -156,14 +156,13 @@ impl OhUiMsgHandler { let body_size = hdr.size as usize; let event_type = hdr.event_type; if body_size != event_msg_data_len(hdr.event_type) { - warn!( + reader.clear(); + bail!( "{:?} data len is wrong, we want {}, but receive {}", event_type, event_msg_data_len(hdr.event_type), body_size ); - reader.clear(); - return Ok(()); } trace::trace_scope_start!(handle_msg, args = (&event_type)); @@ -333,6 +332,10 @@ impl OhUiMsgHandler { error!("handle_dirty_area: failed to send message with error {e}"); } } + + pub fn reset(&self) { + self.reader.lock().unwrap().clear(); + } } struct MsgReader { -- Gitee From c29682d939d9bfbc13d62ec27376bca881dd3b6f Mon Sep 17 00:00:00 2001 From: Huxiaohang Date: Tue, 28 May 2024 17:29:31 +0800 Subject: [PATCH 082/489] eventfd: add cloexec flag when eventfd create Signed-off-by: Huxiaohang --- devices/src/acpi/ged.rs | 4 ++-- devices/src/legacy/pl011.rs | 5 ++--- devices/src/legacy/pl031.rs | 4 ++-- devices/src/legacy/rtc.rs | 4 ++-- devices/src/legacy/serial.rs | 5 ++--- devices/src/usb/camera.rs | 5 +++-- devices/src/usb/xhci/xhci_pci.rs | 5 +++-- machine/src/aarch64/standard.rs | 12 ++++++------ machine/src/standard_common/mod.rs | 6 ++++-- machine/src/x86_64/standard.rs | 15 +++++++++------ ui/src/vnc/client_io.rs | 8 ++++---- util/src/aio/mod.rs | 3 ++- util/src/leak_bucket.rs | 4 ++-- util/src/loop_context.rs | 9 +++++++-- vfio/src/vfio_pci.rs | 5 +++-- virtio/src/device/block.rs | 5 +++-- virtio/src/device/net.rs | 5 +++-- virtio/src/queue/mod.rs | 3 ++- virtio/src/transport/virtio_mmio.rs | 5 +++-- virtio/src/vhost/kernel/net.rs | 5 ++--- virtio/src/vhost/kernel/vsock.rs | 5 ++--- 21 files changed, 68 insertions(+), 54 deletions(-) diff --git a/devices/src/acpi/ged.rs b/devices/src/acpi/ged.rs index 7a87180b..300868ea 100644 --- a/devices/src/acpi/ged.rs +++ b/devices/src/acpi/ged.rs @@ -35,7 +35,7 @@ use address_space::GuestAddress; use machine_manager::event; use machine_manager::event_loop::EventLoop; use machine_manager::qmp::qmp_channel::QmpChannel; -use util::loop_context::{read_fd, EventNotifier, NotifierOperation}; +use util::loop_context::{create_new_eventfd, read_fd, EventNotifier, NotifierOperation}; use util::{loop_context::NotifierCallback, num_ops::write_data_u32}; #[derive(Clone, Copy)] @@ -96,7 +96,7 @@ impl Ged { region_base: u64, region_size: u64, ) -> Result>> { - self.base.interrupt_evt = Some(Arc::new(EventFd::new(libc::EFD_NONBLOCK)?)); + self.base.interrupt_evt = Some(Arc::new(create_new_eventfd()?)); self.set_sys_resource(sysbus, region_base, region_size) .with_context(|| AcpiError::Alignment(region_size as u32))?; self.battery_present = battery_present; diff --git a/devices/src/legacy/pl011.rs b/devices/src/legacy/pl011.rs index afe1e540..fe76da2d 100644 --- a/devices/src/legacy/pl011.rs +++ b/devices/src/legacy/pl011.rs @@ -14,7 +14,6 @@ use std::sync::{Arc, Mutex}; use anyhow::{Context, Result}; use log::{debug, error}; -use vmm_sys_util::eventfd::EventFd; use super::error::LegacyError; use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType, SysRes}; @@ -36,7 +35,7 @@ use migration::{ }; use migration_derive::{ByteCode, Desc}; use util::byte_code::ByteCode; -use util::loop_context::EventNotifierHelper; +use util::loop_context::{create_new_eventfd, EventNotifierHelper}; use util::num_ops::read_data_u32; const PL011_FLAG_TXFE: u8 = 0x80; @@ -135,7 +134,7 @@ impl PL011 { Ok(PL011 { base: SysBusDevBase { dev_type: SysBusDevType::PL011, - interrupt_evt: Some(Arc::new(EventFd::new(libc::EFD_NONBLOCK)?)), + interrupt_evt: Some(Arc::new(create_new_eventfd()?)), ..Default::default() }, paused: false, diff --git a/devices/src/legacy/pl031.rs b/devices/src/legacy/pl031.rs index a5790dd6..dc5b94e0 100644 --- a/devices/src/legacy/pl031.rs +++ b/devices/src/legacy/pl031.rs @@ -15,7 +15,6 @@ use std::time::{Instant, SystemTime, UNIX_EPOCH}; use anyhow::{Context, Result}; use byteorder::{ByteOrder, LittleEndian}; -use vmm_sys_util::eventfd::EventFd; use super::error::LegacyError; use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType, SysRes}; @@ -28,6 +27,7 @@ use migration::{ }; use migration_derive::{ByteCode, Desc}; use util::byte_code::ByteCode; +use util::loop_context::create_new_eventfd; use util::num_ops::write_data_u32; /// Registers for pl031 from ARM PrimeCell Real Time Clock Technical Reference Manual. @@ -100,7 +100,7 @@ impl PL031 { region_base: u64, region_size: u64, ) -> Result<()> { - self.base.interrupt_evt = Some(Arc::new(EventFd::new(libc::EFD_NONBLOCK)?)); + self.base.interrupt_evt = Some(Arc::new(create_new_eventfd()?)); self.set_sys_resource(sysbus, region_base, region_size) .with_context(|| LegacyError::SetSysResErr)?; diff --git a/devices/src/legacy/rtc.rs b/devices/src/legacy/rtc.rs index 8334c2d1..ccb907cb 100644 --- a/devices/src/legacy/rtc.rs +++ b/devices/src/legacy/rtc.rs @@ -15,7 +15,6 @@ use std::time::{Instant, SystemTime, UNIX_EPOCH}; use anyhow::Result; use log::{debug, error, warn}; -use vmm_sys_util::eventfd::EventFd; use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType, SysRes}; use crate::{Device, DeviceBase}; @@ -24,6 +23,7 @@ use acpi::{ AmlResTemplate, AmlScopeBuilder, }; use address_space::GuestAddress; +use util::loop_context::create_new_eventfd; use util::time::{mktime64, NANOSECONDS_PER_SECOND}; /// IO port of RTC device to select Register to read/write. @@ -126,7 +126,7 @@ impl RTC { region_size: 8, irq: -1, }, - interrupt_evt: Some(Arc::new(EventFd::new(libc::EFD_NONBLOCK)?)), + interrupt_evt: Some(Arc::new(create_new_eventfd()?)), ..Default::default() }, cmos_data: [0_u8; 128], diff --git a/devices/src/legacy/serial.rs b/devices/src/legacy/serial.rs index 8b096f09..80415e07 100644 --- a/devices/src/legacy/serial.rs +++ b/devices/src/legacy/serial.rs @@ -15,7 +15,6 @@ use std::sync::{Arc, Mutex}; use anyhow::{bail, Context, Result}; use log::{debug, error}; -use vmm_sys_util::eventfd::EventFd; use super::error::LegacyError; use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType, SysRes}; @@ -34,7 +33,7 @@ use migration::{ }; use migration_derive::{ByteCode, Desc}; use util::byte_code::ByteCode; -use util::loop_context::EventNotifierHelper; +use util::loop_context::{create_new_eventfd, EventNotifierHelper}; pub const SERIAL_ADDR: u64 = 0x3f8; @@ -144,7 +143,7 @@ impl Serial { .unwrap() .realize() .with_context(|| "Failed to realize chardev")?; - self.base.interrupt_evt = Some(Arc::new(EventFd::new(libc::EFD_NONBLOCK)?)); + self.base.interrupt_evt = Some(Arc::new(create_new_eventfd()?)); self.set_sys_resource(sysbus, region_base, region_size) .with_context(|| LegacyError::SetSysResErr)?; diff --git a/devices/src/usb/camera.rs b/devices/src/usb/camera.rs index f687d455..c4e5e779 100644 --- a/devices/src/usb/camera.rs +++ b/devices/src/usb/camera.rs @@ -41,7 +41,8 @@ use machine_manager::event_loop::{register_event_helper, unregister_event_helper use util::aio::{iov_discard_front_direct, Iovec}; use util::byte_code::ByteCode; use util::loop_context::{ - read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, + create_new_eventfd, read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, + NotifierOperation, }; const INTERFACE_ID_CONTROL: u8 = 0; @@ -505,7 +506,7 @@ impl UsbCamera { Ok(Self { base: UsbDeviceBase::new(config.id, USB_CAMERA_BUFFER_LEN), vs_control: VideoStreamingControl::default(), - camera_fd: Arc::new(EventFd::new(libc::EFD_NONBLOCK)?), + camera_fd: Arc::new(create_new_eventfd()?), camera_backend: camera, packet_list: Arc::new(Mutex::new(LinkedList::new())), payload: Arc::new(Mutex::new(UvcPayload::new())), diff --git a/devices/src/usb/xhci/xhci_pci.rs b/devices/src/usb/xhci/xhci_pci.rs index 09c24f46..0e8ffd23 100644 --- a/devices/src/usb/xhci/xhci_pci.rs +++ b/devices/src/usb/xhci/xhci_pci.rs @@ -39,7 +39,8 @@ use address_space::{AddressRange, AddressSpace, Region, RegionIoEventFd}; use machine_manager::config::{get_pci_df, valid_id}; use machine_manager::event_loop::register_event_helper; use util::loop_context::{ - read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, + create_new_eventfd, read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, + NotifierOperation, }; /// 5.2 PCI Configuration Registers(USB) @@ -122,7 +123,7 @@ impl XhciPciDevice { XHCI_PCI_CONFIG_LENGTH as u64, "XhciPciContainer", ), - doorbell_fd: Arc::new(EventFd::new(libc::EFD_NONBLOCK).unwrap()), + doorbell_fd: Arc::new(create_new_eventfd().unwrap()), delete_evts: Vec::new(), iothread: config.iothread.clone(), } diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index bb46ce38..b803e741 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -81,7 +81,7 @@ use ui::ohui_srv::{ohui_init, OhUiServer}; use ui::vnc::vnc_init; use util::byte_code::ByteCode; use util::device_tree::{self, CompileFDT, FdtBuilder}; -use util::loop_context::EventLoopManager; +use util::loop_context::{create_new_eventfd, EventLoopManager}; use util::seccomp::{BpfRule, SeccompCmpOpt}; use util::set_termi_canon_mode; @@ -186,23 +186,23 @@ impl StdMachine { IRQ_MAP[IrqEntryType::Pcie as usize].0, ))), power_button: Arc::new( - EventFd::new(libc::EFD_NONBLOCK) + create_new_eventfd() .with_context(|| MachineError::InitEventFdErr("power_button".to_string()))?, ), shutdown_req: Arc::new( - EventFd::new(libc::EFD_NONBLOCK) + create_new_eventfd() .with_context(|| MachineError::InitEventFdErr("shutdown_req".to_string()))?, ), reset_req: Arc::new( - EventFd::new(libc::EFD_NONBLOCK) + create_new_eventfd() .with_context(|| MachineError::InitEventFdErr("reset_req".to_string()))?, ), pause_req: Arc::new( - EventFd::new(libc::EFD_NONBLOCK) + create_new_eventfd() .with_context(|| MachineError::InitEventFdErr("pause_req".to_string()))?, ), resume_req: Arc::new( - EventFd::new(libc::EFD_NONBLOCK) + create_new_eventfd() .with_context(|| MachineError::InitEventFdErr("resume_req".to_string()))?, ), dtb_vec: Vec::new(), diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index bac724a8..02780b8e 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -79,7 +79,9 @@ use ui::input::{input_button, input_move_abs, input_point_sync, key_event, Axis} use ui::vnc::qmp_query_vnc; use util::aio::{AioEngine, WriteZeroesState}; use util::byte_code::ByteCode; -use util::loop_context::{read_fd, EventNotifier, NotifierCallback, NotifierOperation}; +use util::loop_context::{ + create_new_eventfd, read_fd, EventNotifier, NotifierCallback, NotifierOperation, +}; use virtio::{qmp_balloon, qmp_query_balloon}; const MAX_REGION_SIZE: u64 = 65536; @@ -1549,7 +1551,7 @@ impl DeviceInterface for StdMachine { region = Region::init_io_region(args.size, dummy_dev_ops, "UpdateRegionTest"); if args.ioeventfd.is_some() && args.ioeventfd.unwrap() { let ioeventfds = vec![RegionIoEventFd { - fd: Arc::new(EventFd::new(libc::EFD_NONBLOCK).unwrap()), + fd: Arc::new(create_new_eventfd().unwrap()), addr_range: AddressRange::from(( 0, args.ioeventfd_size.unwrap_or_default(), diff --git a/machine/src/x86_64/standard.rs b/machine/src/x86_64/standard.rs index 289737e1..c6804809 100644 --- a/machine/src/x86_64/standard.rs +++ b/machine/src/x86_64/standard.rs @@ -61,7 +61,10 @@ use ui::gtk::gtk_display_init; use ui::vnc::vnc_init; use util::seccomp::SeccompCmpOpt; use util::{ - byte_code::ByteCode, loop_context::EventLoopManager, seccomp::BpfRule, set_termi_canon_mode, + byte_code::ByteCode, + loop_context::{create_new_eventfd, EventLoopManager}, + seccomp::BpfRule, + set_termi_canon_mode, }; pub(crate) const VENDOR_ID_INTEL: u16 = 0x8086; @@ -156,20 +159,20 @@ impl StdMachine { IRQ_MAP[IrqEntryType::Pcie as usize].0, ))), reset_req: Arc::new( - EventFd::new(libc::EFD_NONBLOCK) + create_new_eventfd() .with_context(|| MachineError::InitEventFdErr("reset request".to_string()))?, ), shutdown_req: Arc::new( - EventFd::new(libc::EFD_NONBLOCK).with_context(|| { + create_new_eventfd().with_context(|| { MachineError::InitEventFdErr("shutdown request".to_string()) })?, ), power_button: Arc::new( - EventFd::new(libc::EFD_NONBLOCK) + create_new_eventfd() .with_context(|| MachineError::InitEventFdErr("power button".to_string()))?, ), cpu_resize_req: Arc::new( - EventFd::new(libc::EFD_NONBLOCK) + create_new_eventfd() .with_context(|| MachineError::InitEventFdErr("cpu resize".to_string()))?, ), boot_order_list: Arc::new(Mutex::new(Vec::new())), @@ -264,7 +267,7 @@ impl StdMachine { let region_size: u64 = MEM_LAYOUT[LayoutEntryType::CpuController as usize].1; let cpu_config = CpuConfig::new(boot_config, cpu_topology); let hotplug_cpu_req = Arc::new( - EventFd::new(libc::EFD_NONBLOCK) + create_new_eventfd() .with_context(|| MachineError::InitEventFdErr("hotplug cpu".to_string()))?, ); diff --git a/ui/src/vnc/client_io.rs b/ui/src/vnc/client_io.rs index 347e7d58..b4fa9055 100644 --- a/ui/src/vnc/client_io.rs +++ b/ui/src/vnc/client_io.rs @@ -47,8 +47,8 @@ use crate::{ use util::{ bitmap::Bitmap, loop_context::{ - gen_delete_notifiers, read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, - NotifierOperation, + create_new_eventfd, gen_delete_notifiers, read_fd, EventNotifier, EventNotifierHelper, + NotifierCallback, NotifierOperation, }, }; @@ -392,8 +392,8 @@ impl ClientState { pub fn new(addr: String) -> Self { ClientState { addr, - disconn_evt: Arc::new(Mutex::new(EventFd::new(libc::EFD_NONBLOCK).unwrap())), - write_fd: Arc::new(Mutex::new(EventFd::new(libc::EFD_NONBLOCK).unwrap())), + disconn_evt: Arc::new(Mutex::new(create_new_eventfd().unwrap())), + write_fd: Arc::new(Mutex::new(create_new_eventfd().unwrap())), in_buffer: Arc::new(Mutex::new(BuffPool::new())), out_buffer: Arc::new(Mutex::new(BuffPool::new())), client_dpm: Arc::new(Mutex::new(DisplayMode::default())), diff --git a/util/src/aio/mod.rs b/util/src/aio/mod.rs index 03183b80..a9427f67 100644 --- a/util/src/aio/mod.rs +++ b/util/src/aio/mod.rs @@ -32,6 +32,7 @@ use uring::IoUringContext; use vmm_sys_util::eventfd::EventFd; use super::link_list::{List, Node}; +use crate::loop_context::create_new_eventfd; use crate::num_ops::{round_down, round_up}; use crate::thread_pool::ThreadPool; use crate::unix::host_page_size; @@ -504,7 +505,7 @@ impl Aio { thread_pool: Option>, ) -> Result { let max_events: usize = 128; - let fd = EventFd::new(libc::EFD_NONBLOCK)?; + let fd = create_new_eventfd()?; let ctx: Option>> = if let Some(pool) = thread_pool { let threads_aio_ctx = ThreadsAioContext::new(max_events as u32, &fd, pool); match engine { diff --git a/util/src/leak_bucket.rs b/util/src/leak_bucket.rs index 5dd65f2f..cde308c4 100644 --- a/util/src/leak_bucket.rs +++ b/util/src/leak_bucket.rs @@ -20,7 +20,7 @@ use log::error; use vmm_sys_util::eventfd::EventFd; use crate::clock::get_current_time; -use crate::loop_context::EventLoopContext; +use crate::loop_context::{create_new_eventfd, EventLoopContext}; use crate::time::NANOSECONDS_PER_SECOND; /// Used to improve the accuracy of bucket level. @@ -53,7 +53,7 @@ impl LeakBucket { level: 0, prev_time: get_current_time(), timer_started: false, - timer_wakeup: Arc::new(EventFd::new(libc::EFD_NONBLOCK)?), + timer_wakeup: Arc::new(create_new_eventfd()?), }) } diff --git a/util/src/loop_context.rs b/util/src/loop_context.rs index ded2f1fe..957fdb4c 100644 --- a/util/src/loop_context.rs +++ b/util/src/loop_context.rs @@ -13,6 +13,7 @@ use std::collections::BTreeMap; use std::fmt; use std::fmt::Debug; +use std::io::Error; use std::os::unix::io::{AsRawFd, RawFd}; use std::rc::Rc; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; @@ -20,7 +21,7 @@ use std::sync::{Arc, Barrier, Mutex, RwLock}; use std::time::{Duration, Instant}; use anyhow::{anyhow, Context, Result}; -use libc::{c_void, read, EFD_NONBLOCK}; +use libc::{c_void, read, EFD_CLOEXEC, EFD_NONBLOCK}; use log::{error, warn}; use nix::errno::Errno; use nix::{ @@ -158,6 +159,10 @@ pub fn gen_delete_notifiers(fds: &[RawFd]) -> Vec { notifiers } +pub fn create_new_eventfd() -> Result { + EventFd::new(EFD_NONBLOCK | EFD_CLOEXEC) +} + /// EventLoop manager, advise continue running or stop running pub trait EventLoopManager: Send + Sync { fn loop_should_exit(&self) -> bool; @@ -241,7 +246,7 @@ impl EventLoopContext { let mut ctx = EventLoopContext { epoll: Epoll::new().unwrap(), manager: None, - kick_event: EventFd::new(EFD_NONBLOCK).unwrap(), + kick_event: create_new_eventfd().unwrap(), kick_me: AtomicBool::new(false), kicked: AtomicBool::new(false), events: Arc::new(RwLock::new(BTreeMap::new())), diff --git a/vfio/src/vfio_pci.rs b/vfio/src/vfio_pci.rs index baca7bfe..ebf028e5 100644 --- a/vfio/src/vfio_pci.rs +++ b/vfio/src/vfio_pci.rs @@ -45,6 +45,7 @@ use devices::pci::{ }; use devices::{pci::MsiVector, Device, DeviceBase}; use machine_manager::config::{get_pci_df, parse_bool, valid_id}; +use util::loop_context::create_new_eventfd; use util::num_ops::ranges_overlap; use util::unix::host_page_size; @@ -534,7 +535,7 @@ impl VfioPciDevice { let mut locked_gsi_routes = cloned_gsi_routes.lock().unwrap(); let gsi_route = locked_gsi_routes.get_mut(vector as usize).unwrap(); if gsi_route.irq_fd.is_none() { - let irq_fd = EventFd::new(libc::EFD_NONBLOCK).unwrap(); + let irq_fd = create_new_eventfd().unwrap(); gsi_route.irq_fd = Some(Arc::new(irq_fd)); } let irq_fd = gsi_route.irq_fd.clone(); @@ -722,7 +723,7 @@ impl VfioPciDevice { fn vfio_enable_msix(&mut self) -> Result<()> { let mut gsi_routes = self.gsi_msi_routes.lock().unwrap(); if gsi_routes.len() == 0 { - let irq_fd = EventFd::new(libc::EFD_NONBLOCK).unwrap(); + let irq_fd = create_new_eventfd().unwrap(); let gsi_route = GsiMsiRoute { irq_fd: Some(Arc::new(irq_fd)), gsi: -1, diff --git a/virtio/src/device/block.rs b/virtio/src/device/block.rs index f8cd6d65..9b14a880 100644 --- a/virtio/src/device/block.rs +++ b/virtio/src/device/block.rs @@ -58,7 +58,8 @@ use util::aio::{ use util::byte_code::ByteCode; use util::leak_bucket::LeakBucket; use util::loop_context::{ - read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, + create_new_eventfd, read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, + NotifierOperation, }; use util::offset_of; @@ -1249,7 +1250,7 @@ impl VirtioDevice for Block { continue; } let (sender, receiver) = channel(); - let update_evt = Arc::new(EventFd::new(libc::EFD_NONBLOCK)?); + let update_evt = Arc::new(create_new_eventfd()?); let driver_features = self.base.driver_features; let handler = BlockIoHandler { queue: queue.clone(), diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index 198f4b7f..391a6cd0 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -57,7 +57,8 @@ use migration_derive::{ByteCode, Desc}; use util::byte_code::ByteCode; use util::loop_context::gen_delete_notifiers; use util::loop_context::{ - read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, + create_new_eventfd, read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, + NotifierOperation, }; use util::num_ops::str_to_num; use util::tap::{ @@ -1644,7 +1645,7 @@ impl VirtioDevice for Net { .with_context(|| "Failed to set tap offload")?; } - let update_evt = Arc::new(EventFd::new(libc::EFD_NONBLOCK)?); + let update_evt = Arc::new(create_new_eventfd()?); let mut handler = NetIoHandler { rx: RxVirtio::new(rx_queue, rx_queue_evt), tx: TxVirtio::new(tx_queue, tx_queue_evt), diff --git a/virtio/src/queue/mod.rs b/virtio/src/queue/mod.rs index 7f581a04..1e612b29 100644 --- a/virtio/src/queue/mod.rs +++ b/virtio/src/queue/mod.rs @@ -21,6 +21,7 @@ use vmm_sys_util::eventfd::EventFd; use address_space::{AddressSpace, GuestAddress, RegionCache}; use machine_manager::config::DEFAULT_VIRTQUEUE_SIZE; +use util::loop_context::create_new_eventfd; /// Split Virtqueue. pub const QUEUE_TYPE_SPLIT_VRING: u16 = 1; @@ -226,7 +227,7 @@ impl NotifyEventFds { pub fn new(queue_num: usize) -> Self { let mut events = Vec::new(); for _i in 0..queue_num { - events.push(Arc::new(EventFd::new(libc::EFD_NONBLOCK).unwrap())); + events.push(Arc::new(create_new_eventfd().unwrap())); } NotifyEventFds { events } diff --git a/virtio/src/transport/virtio_mmio.rs b/virtio/src/transport/virtio_mmio.rs index 1340fd9c..eb09093f 100644 --- a/virtio/src/transport/virtio_mmio.rs +++ b/virtio/src/transport/virtio_mmio.rs @@ -33,6 +33,7 @@ use machine_manager::config::{BootSource, Param}; use migration::{DeviceStateDesc, FieldDesc, MigrationHook, MigrationManager, StateTransfer}; use migration_derive::{ByteCode, Desc}; use util::byte_code::ByteCode; +use util::loop_context::create_new_eventfd; /// Registers of virtio-mmio device refer to Virtio Spec. /// Magic value - Read Only. @@ -105,7 +106,7 @@ impl HostNotifyInfo { fn new(queue_num: usize) -> Self { let mut events = Vec::new(); for _i in 0..queue_num { - events.push(Arc::new(EventFd::new(libc::EFD_NONBLOCK).unwrap())); + events.push(Arc::new(create_new_eventfd().unwrap())); } HostNotifyInfo { events } @@ -149,7 +150,7 @@ impl VirtioMmioDevice { hotpluggable: false, }, dev_type: SysBusDevType::VirtioMmio, - interrupt_evt: Some(Arc::new(EventFd::new(libc::EFD_NONBLOCK).unwrap())), + interrupt_evt: Some(Arc::new(create_new_eventfd().unwrap())), ..Default::default() }, device, diff --git a/virtio/src/vhost/kernel/net.rs b/virtio/src/vhost/kernel/net.rs index 8a4f6c02..89a29970 100644 --- a/virtio/src/vhost/kernel/net.rs +++ b/virtio/src/vhost/kernel/net.rs @@ -34,7 +34,7 @@ use address_space::AddressSpace; use machine_manager::config::{NetDevcfg, NetworkInterfaceConfig}; use machine_manager::event_loop::{register_event_helper, unregister_event_helper}; use util::byte_code::ByteCode; -use util::loop_context::EventNotifierHelper; +use util::loop_context::{create_new_eventfd, EventNotifierHelper}; use util::tap::Tap; /// Number of virtqueues. @@ -327,8 +327,7 @@ impl VirtioDevice for Net { let event = if self.call_events.is_empty() { let host_notify = VhostNotify { notify_evt: Arc::new( - EventFd::new(libc::EFD_NONBLOCK) - .with_context(|| VirtioError::EventFdCreate)?, + create_new_eventfd().with_context(|| VirtioError::EventFdCreate)?, ), queue: queue_mutex.clone(), }; diff --git a/virtio/src/vhost/kernel/vsock.rs b/virtio/src/vhost/kernel/vsock.rs index 89bcd112..ade3ec2f 100644 --- a/virtio/src/vhost/kernel/vsock.rs +++ b/virtio/src/vhost/kernel/vsock.rs @@ -32,7 +32,7 @@ use machine_manager::event_loop::{register_event_helper, unregister_event_helper use migration::{DeviceStateDesc, FieldDesc, MigrationHook, MigrationManager, StateTransfer}; use migration_derive::{ByteCode, Desc}; use util::byte_code::ByteCode; -use util::loop_context::EventNotifierHelper; +use util::loop_context::{create_new_eventfd, EventNotifierHelper}; /// Number of virtqueues. const QUEUE_NUM_VSOCK: usize = 3; @@ -311,8 +311,7 @@ impl VirtioDevice for Vsock { let event = if self.call_events.is_empty() { let host_notify = VhostNotify { notify_evt: Arc::new( - EventFd::new(libc::EFD_NONBLOCK) - .with_context(|| VirtioError::EventFdCreate)?, + create_new_eventfd().with_context(|| VirtioError::EventFdCreate)?, ), queue: queue_mutex.clone(), }; -- Gitee From bd43d89c7dc72eac61f48fbc65eab111982e8b16 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Thu, 30 May 2024 11:44:13 +0800 Subject: [PATCH 083/489] ohaudio: add hitrace Signed-off-by: Zhao Yi Min --- devices/src/misc/scream/mod.rs | 2 +- devices/src/misc/scream/ohaudio.rs | 11 ++++++++++- trace/trace_info/misc.toml | 24 ++++++++++++++++++++++++ 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index ed089011..496c96c2 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -186,7 +186,7 @@ impl ShmemStreamFmt { } /// Audio stream data structure. -#[derive(Default)] +#[derive(Debug, Default)] pub struct StreamData { pub fmt: ShmemStreamFmt, chunk_idx: u16, diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index 10f9cb85..fc6fccf0 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -137,6 +137,8 @@ impl OhAudioProcess for OhAudioRender { fence(Ordering::Acquire); + trace::trace_scope_start!(ohaudio_render_process, args = (recv_data)); + let su = StreamUnit { addr: recv_data.audio_base, len: recv_data.audio_size as u64, @@ -230,6 +232,9 @@ impl OhAudioProcess for OhAudioCapture { fn process(&mut self, recv_data: &StreamData) -> i32 { self.check_fmt_update(recv_data); + + trace::trace_scope_start!(ohaudio_capturer_process, args = (recv_data)); + if !self.start && !self.init(recv_data) { self.destroy(); return 0; @@ -255,8 +260,10 @@ extern "C" fn on_write_data_cb( .as_mut() .unwrap_unchecked() }; - let data_size = render.data_size.load(Ordering::Relaxed); + + trace::trace_scope_start!(ohaudio_write_cb, args = (length, data_size)); + if !render.flushing.load(Ordering::Acquire) && data_size < length { // SAFETY: we checked len. unsafe { ptr::write_bytes(buffer as *mut u8, 0, length as usize) }; @@ -313,6 +320,8 @@ extern "C" fn on_read_data_cb( .unwrap_unchecked() }; + trace::trace_scope_start!(ohaudio_read_cb, args = (length)); + loop { if !capture.start { return 0; diff --git a/trace/trace_info/misc.toml b/trace/trace_info/misc.toml index c0574193..897a6bc0 100644 --- a/trace/trace_info/misc.toml +++ b/trace/trace_info/misc.toml @@ -63,3 +63,27 @@ name = "oh_scream_on_read_data_cb" args = "len: usize" message = "len: {}" enabled = true + +[[scopes]] +name = "ohaudio_render_process" +args = "data: &dyn fmt::Debug" +message = "audio data {:?} to render" +enabled = true + +[[scopes]] +name = "ohaudio_capturer_process" +args = "data: &dyn fmt::Debug" +message = "audio data {:?} to capture" +enabled = true + +[[scopes]] +name = "ohaudio_write_cb" +args = "to_copy: i32, len: i32" +message = "OH audio expect audio data {} bytes, we have {} bytes" +enabled = true + +[[scopes]] +name = "ohaudio_read_cb" +args = "len: i32" +message = "OH audio captured {} bytes" +enabled = true -- Gitee From 78ef801a9c3056bfefdc32b1adbe43f2bbd000da Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Thu, 30 May 2024 20:17:54 +0800 Subject: [PATCH 084/489] ohui: fixup compile error for OHOS target Fixup compiple error if target env is OHOS. Signed-off-by: Zhao Yi Min --- ui/src/ohui_srv/channel.rs | 2 +- ui/src/ohui_srv/msg_handle.rs | 7 ++++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/ui/src/ohui_srv/channel.rs b/ui/src/ohui_srv/channel.rs index 008a7e26..93f8625e 100755 --- a/ui/src/ohui_srv/channel.rs +++ b/ui/src/ohui_srv/channel.rs @@ -33,7 +33,7 @@ impl OhUiChannel { Ok(l) => l, Err(e) => bail!("Failed to create listener with path {}, {:?}", path, e), }; - limit_permission(path.as_str()).unwrap_or_else(|e| { + limit_permission(path).unwrap_or_else(|e| { error!( "Failed to limit permission for ohui-sock {}, err: {:?}", path, e diff --git a/ui/src/ohui_srv/msg_handle.rs b/ui/src/ohui_srv/msg_handle.rs index 5fb84f5e..cc0d679e 100755 --- a/ui/src/ohui_srv/msg_handle.rs +++ b/ui/src/ohui_srv/msg_handle.rs @@ -14,7 +14,7 @@ use std::collections::HashMap; use std::sync::{Arc, Mutex, RwLock}; use anyhow::{anyhow, bail, Result}; -use log::{error, warn}; +use log::error; use util::byte_code::ByteCode; use super::{channel::OhUiChannel, msg::*}; @@ -155,12 +155,13 @@ impl OhUiMsgHandler { let hdr = &reader.header; let body_size = hdr.size as usize; let event_type = hdr.event_type; - if body_size != event_msg_data_len(hdr.event_type) { + let expect_body_size = event_msg_data_len(hdr.event_type); + if body_size != expect_body_size { reader.clear(); bail!( "{:?} data len is wrong, we want {}, but receive {}", event_type, - event_msg_data_len(hdr.event_type), + expect_body_size, body_size ); } -- Gitee From 12b5e636379b24804a9759a406e64dd0f7ad9da6 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Thu, 30 May 2024 20:41:24 +0800 Subject: [PATCH 085/489] ohui: fixup clippy error Fixup clippy error. Signed-off-by: Zhao Yi Min --- ui/src/ohui_srv/channel.rs | 2 +- ui/src/ohui_srv/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/src/ohui_srv/channel.rs b/ui/src/ohui_srv/channel.rs index 93f8625e..cfa86d47 100755 --- a/ui/src/ohui_srv/channel.rs +++ b/ui/src/ohui_srv/channel.rs @@ -52,7 +52,7 @@ impl OhUiChannel { } pub fn get_stream_raw_fd(&self) -> Option { - self.stream.as_ref().and_then(|s| Some(s.as_raw_fd())) + self.stream.as_ref().map(|s| s.as_raw_fd()) } pub fn accept(&mut self) -> Result<()> { diff --git a/ui/src/ohui_srv/mod.rs b/ui/src/ohui_srv/mod.rs index 603abb60..8f72b132 100755 --- a/ui/src/ohui_srv/mod.rs +++ b/ui/src/ohui_srv/mod.rs @@ -520,7 +520,7 @@ fn ohui_register_event(e: T, srv: Arc) -> Re } fn ohui_start_listener(server: Arc) -> Result<()> { - ohui_register_event(OhUiListener::new(server.clone()), server.clone())?; + ohui_register_event(OhUiListener::new(server.clone()), server)?; info!("Successfully start listener."); Ok(()) } -- Gitee From 38318221504f549f4d7887d4951bb8c53abdf4dc Mon Sep 17 00:00:00 2001 From: yexiao Date: Fri, 31 May 2024 09:29:07 +0800 Subject: [PATCH 086/489] Cargo: update Cargo.lock file Signed-off-by: Xiao Ye --- Cargo.lock | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.lock b/Cargo.lock index dfcfbe29..fb50c772 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -28,6 +28,7 @@ dependencies = [ "nix 0.26.2", "once_cell", "thiserror", + "trace", "util", "vmm-sys-util", ] -- Gitee From 05e68df3befb56dbd4d31680b28a88953dcc01af Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Fri, 31 May 2024 09:57:09 +0800 Subject: [PATCH 087/489] virtio_pci: Do not send msix when vector is INVALID Signed-off-by: Keqian Zhu --- virtio/src/transport/virtio_pci.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/virtio/src/transport/virtio_pci.rs b/virtio/src/transport/virtio_pci.rs index 041356f9..8ca54015 100644 --- a/virtio/src/transport/virtio_pci.rs +++ b/virtio/src/transport/virtio_pci.rs @@ -390,7 +390,9 @@ impl VirtioPciDevice { let mut locked_msix = cloned_msix.lock().unwrap(); if locked_msix.enabled { - locked_msix.notify(vector, dev_id.load(Ordering::Acquire)); + if vector != INVALID_VECTOR_NUM { + locked_msix.notify(vector, dev_id.load(Ordering::Acquire)); + } } else { cloned_intx.lock().unwrap().notify(1); } -- Gitee From dd356dbfd05f1b3973a5a6f4913f85714088ade7 Mon Sep 17 00:00:00 2001 From: yexiao Date: Fri, 31 May 2024 09:38:04 +0800 Subject: [PATCH 088/489] log: modify some log Signed-off-by: Xiao Ye --- machine/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/machine/src/lib.rs b/machine/src/lib.rs index f58634cf..bc663ff8 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -2316,7 +2316,7 @@ fn check_windows_emu_pid( ) { let mut check_delay = Duration::from_millis(4000); if !Path::new(&pid_path).exists() { - log::info!("Detect windows emu exited, let VM exits now"); + log::info!("Detect emulator exited, let VM exits now"); if get_run_stage() == VmRunningStage::Os { if let Err(e) = powerdown_req.write(1) { log::error!("Failed to send powerdown request after emu exits: {:?}", e); -- Gitee From be915dcbba1a829ee27439c22ea0c11f946165f0 Mon Sep 17 00:00:00 2001 From: zhanghan64 Date: Fri, 31 May 2024 11:38:48 +0800 Subject: [PATCH 089/489] usbCamera: clean resource when camera is deleted When frontend is using camera which means register_camera_fd() has been called, if camera is to be deleted, we need to unregistered it. Without unregistering, camera_backend of UsbCamera wont be dropped. --- devices/src/usb/camera.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/devices/src/usb/camera.rs b/devices/src/usb/camera.rs index c4e5e779..710a7110 100644 --- a/devices/src/usb/camera.rs +++ b/devices/src/usb/camera.rs @@ -777,6 +777,7 @@ impl UsbDevice for UsbCamera { fn unrealize(&mut self) -> Result<()> { info!("Camera {} unrealize", self.device_id()); + self.unregister_camera_fd()?; self.camera_backend.lock().unwrap().reset(); Ok(()) } -- Gitee From c87bf7ea9bda848d62296e4a61d79b72fc31398f Mon Sep 17 00:00:00 2001 From: zhanghan64 Date: Thu, 30 May 2024 14:28:53 +0800 Subject: [PATCH 090/489] VIOGPU: another way to set OS stage OS stage was set when we report EDID info. But sometimes EDID is disabled, for which OS stage will not be set. Let's fix this logic. Signed-off-by: zhanghan64 --- virtio/src/device/gpu.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/virtio/src/device/gpu.rs b/virtio/src/device/gpu.rs index 98f9d2c3..2d138ed2 100644 --- a/virtio/src/device/gpu.rs +++ b/virtio/src/device/gpu.rs @@ -1226,6 +1226,12 @@ impl GpuIoHandler { scanout.width = info_set_scanout.rect.width; scanout.height = info_set_scanout.rect.height; + if (self.driver_features & (1 << VIRTIO_GPU_F_EDID)) == 0 + && (info_set_scanout.resource_id & VIRTIO_GPU_RES_WIN_FRAMEBUF) != 0 + { + self.change_run_stage()?; + } + self.response_nodata(VIRTIO_GPU_RESP_OK_NODATA, req) } -- Gitee From be1bba713557c34407d6a358f5ae127a13b5470e Mon Sep 17 00:00:00 2001 From: zhanghan64 Date: Thu, 30 May 2024 20:27:32 +0800 Subject: [PATCH 091/489] windows_emu_pid: fix checking logic 1s is too short for windows' power-down duration. We enlarge it to 30s. Signed-off-by: zhanghan64 --- machine/src/lib.rs | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/machine/src/lib.rs b/machine/src/lib.rs index bc663ff8..9bd6b29c 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -103,6 +103,10 @@ use virtio::{ #[cfg(feature = "virtio_gpu")] use virtio::{Gpu, GpuDevConfig}; +const WINDOWS_EMU_PID_DEFAULT_INTERVAL: u64 = 4000; +const WINDOWS_EMU_PID_SHUTDOWN_INTERVAL: u64 = 1000; +const WINDOWS_EMU_PID_POWERDOWN_INTERVAL: u64 = 30000; + /// Machine structure include base members. pub struct MachineBase { /// `vCPU` topology, support sockets, cores, threads. @@ -2314,18 +2318,22 @@ fn check_windows_emu_pid( powerdown_req: Arc, shutdown_req: Arc, ) { - let mut check_delay = Duration::from_millis(4000); + let mut check_delay = Duration::from_millis(WINDOWS_EMU_PID_DEFAULT_INTERVAL); if !Path::new(&pid_path).exists() { log::info!("Detect emulator exited, let VM exits now"); if get_run_stage() == VmRunningStage::Os { + // Wait 30s for windows normal exit. + check_delay = Duration::from_millis(WINDOWS_EMU_PID_POWERDOWN_INTERVAL); if let Err(e) = powerdown_req.write(1) { log::error!("Failed to send powerdown request after emu exits: {:?}", e); } - } else if let Err(e) = shutdown_req.write(1) { - log::error!("Failed to send shutdown request after emu exits: {:?}", e); + } else { + // Wait 1s for windows shutdown. + check_delay = Duration::from_millis(WINDOWS_EMU_PID_SHUTDOWN_INTERVAL); + if let Err(e) = shutdown_req.write(1) { + log::error!("Failed to send shutdown request after emu exits: {:?}", e); + } } - // Continue checking to prevent exit failed. - check_delay = Duration::from_millis(1000); } let check_emu_alive = Box::new(move || { -- Gitee From 48108a3e763da490ae73347e3935dc58cf0cffbb Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Mon, 3 Jun 2024 15:47:08 +0800 Subject: [PATCH 092/489] trace: export trace scope and add Clone trait Let's export trace scope and add Clone trait for later use. Signed-off-by: Zhao Yi Min --- trace/src/lib.rs | 2 +- trace/src/trace_scope.rs | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/trace/src/lib.rs b/trace/src/lib.rs index 1501a502..32646d2f 100644 --- a/trace/src/lib.rs +++ b/trace/src/lib.rs @@ -19,7 +19,7 @@ pub(crate) mod hitrace; feature = "trace_to_ftrace", all(target_env = "ohos", feature = "trace_to_hitrace") ))] -pub(crate) mod trace_scope; +pub mod trace_scope; use std::{ fmt, diff --git a/trace/src/trace_scope.rs b/trace/src/trace_scope.rs index 4a021017..a860ef8d 100644 --- a/trace/src/trace_scope.rs +++ b/trace/src/trace_scope.rs @@ -20,12 +20,14 @@ use crate::ftrace::write_trace_marker; static mut TRACE_SCOPE_COUNTER: AtomicI32 = AtomicI32::new(i32::MIN); +#[derive(Clone)] pub enum Scope { Common(TraceScope), Asyn(TraceScopeAsyn), None, } +#[derive(Clone)] pub struct TraceScope {} impl TraceScope { @@ -63,6 +65,7 @@ impl Drop for TraceScope { } } +#[derive(Clone)] pub struct TraceScopeAsyn { value: String, id: i32, -- Gitee From ccb32559ecd01c1da4a76894852af97708f1bc6b Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Mon, 3 Jun 2024 15:54:50 +0800 Subject: [PATCH 093/489] ohcam: introduce scope traces This patch introduces two scope traces for ohcam: 1) function scope trace for get_frame(); 2) async scope trace for next_frame(); Signed-off-by: Zhao Yi Min --- devices/src/camera_backend/ohcam.rs | 65 +++++++++++++++++++++++++++++ trace/trace_info/camera.toml | 12 ++++++ 2 files changed, 77 insertions(+) diff --git a/devices/src/camera_backend/ohcam.rs b/devices/src/camera_backend/ohcam.rs index 3debe893..55b6a80a 100755 --- a/devices/src/camera_backend/ohcam.rs +++ b/devices/src/camera_backend/ohcam.rs @@ -20,6 +20,12 @@ use crate::camera_backend::{ CamBasicFmt, CameraBackend, CameraBrokenCallback, CameraFormatList, CameraFrame, CameraNotifyCallback, FmtType, }; +#[cfg(any( + feature = "trace_to_logger", + feature = "trace_to_ftrace", + all(target_env = "ohos", feature = "trace_to_hitrace") +))] +use trace::trace_scope::Scope; use util::aio::Iovec; use util::ohos_binding::camera::*; @@ -79,6 +85,33 @@ impl OhCamCallBack { } } +#[cfg(any( + feature = "trace_to_logger", + feature = "trace_to_ftrace", + all(target_env = "ohos", feature = "trace_to_hitrace") +))] +#[derive(Clone, Default)] +struct OhCameraAsyncScope { + next_frame_id: u64, + async_scope: Option, +} + +#[cfg(any( + feature = "trace_to_logger", + feature = "trace_to_ftrace", + all(target_env = "ohos", feature = "trace_to_hitrace") +))] +impl OhCameraAsyncScope { + fn start(&mut self) { + self.async_scope = Some(trace::ohcam_next_frame(true, self.next_frame_id)); + self.next_frame_id += 1; + } + + fn stop(&mut self) { + self.async_scope = None; + } +} + #[derive(Clone)] pub struct OhCameraBackend { id: String, @@ -87,6 +120,12 @@ pub struct OhCameraBackend { ctx: OhCamera, fmt_list: Vec, selected_profile: u8, + #[cfg(any( + feature = "trace_to_logger", + feature = "trace_to_ftrace", + all(target_env = "ohos", feature = "trace_to_hitrace") + ))] + async_scope: Box, } // SAFETY: Send and Sync is not auto-implemented for raw pointer type. @@ -121,6 +160,12 @@ impl OhCameraBackend { ctx, fmt_list: vec![], selected_profile: 0, + #[cfg(any( + feature = "trace_to_logger", + feature = "trace_to_ftrace", + all(target_env = "ohos", feature = "trace_to_hitrace") + ))] + async_scope: Box::new(OhCameraAsyncScope::default()), }) } } @@ -163,6 +208,12 @@ impl CameraBackend for OhCameraBackend { fn video_stream_off(&mut self) -> Result<()> { self.ctx.stop_stream(); OHCAM_CALLBACK.write().unwrap().clear_buffer(); + #[cfg(any( + feature = "trace_to_logger", + feature = "trace_to_ftrace", + all(target_env = "ohos", feature = "trace_to_hitrace") + ))] + self.async_scope.stop(); Ok(()) } @@ -201,6 +252,12 @@ impl CameraBackend for OhCameraBackend { fn reset(&mut self) { OHCAM_CALLBACK.write().unwrap().clear_buffer(); self.ctx.reset_camera(); + #[cfg(any( + feature = "trace_to_logger", + feature = "trace_to_ftrace", + all(target_env = "ohos", feature = "trace_to_hitrace") + ))] + self.async_scope.stop(); } fn get_format_by_index(&self, format_index: u8, frame_index: u8) -> Result { @@ -240,6 +297,12 @@ impl CameraBackend for OhCameraBackend { } fn next_frame(&mut self) -> Result<()> { + #[cfg(any( + feature = "trace_to_logger", + feature = "trace_to_ftrace", + all(target_env = "ohos", feature = "trace_to_hitrace") + ))] + self.async_scope.start(); self.ctx.next_frame(); OHCAM_CALLBACK.write().unwrap().clear_buffer(); Ok(()) @@ -255,6 +318,8 @@ impl CameraBackend for OhCameraBackend { bail!("Invalid frame offset {} or len {}", frame_offset, len); } + trace::trace_scope_start!(ohcam_get_frame, args = (frame_offset, len)); + let mut copied = 0; for iov in iovecs { if len == copied { diff --git a/trace/trace_info/camera.toml b/trace/trace_info/camera.toml index 4e0ee65d..e1f044ff 100644 --- a/trace/trace_info/camera.toml +++ b/trace/trace_info/camera.toml @@ -21,3 +21,15 @@ name = "camera_get_format_by_index" args = "format_index: u8, frame_index: u8, out: &dyn fmt::Debug" message = "V4l2 fmt {}, frm {}, info {:?}." enabled = true + +[[scopes]] +name = "ohcam_get_frame" +args = "offset: usize, len: usize" +message = "ohcam get frame offset {} len {}" +enabled = true + +[[scopes]] +name = "ohcam_next_frame" +args = "frame_id: u64" +message = "ohcam next frame {}" +enabled = true -- Gitee From d8f9ec2e2f1835c2ddde5f2df456c25c6aaac82e Mon Sep 17 00:00:00 2001 From: Fan Xuan Zhe Date: Fri, 31 May 2024 18:01:24 +0800 Subject: [PATCH 094/489] usb-host: add dlopen support Add dlopen support for OH USB subsystem Signed-off-by: Fan Xuan Zhe --- util/Cargo.toml | 1 + util/src/ohos_binding/hwf_adapter/mod.rs | 23 +++++++++++ util/src/ohos_binding/hwf_adapter/usb.rs | 45 +++++++++++++++++++++ util/src/ohos_binding/mod.rs | 2 + util/src/ohos_binding/usb.rs | 50 ++++++++++++++++++++++++ 5 files changed, 121 insertions(+) create mode 100644 util/src/ohos_binding/hwf_adapter/usb.rs create mode 100644 util/src/ohos_binding/usb.rs diff --git a/util/Cargo.toml b/util/Cargo.toml index 95aefcda..8d8a38ec 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -28,5 +28,6 @@ trace = {path = "../trace"} default = [] usb_camera_v4l2 = ["dep:v4l2-sys-mit"] usb_camera_oh = [] +usb_host = [] scream_ohaudio = [] pixman = [] diff --git a/util/src/ohos_binding/hwf_adapter/mod.rs b/util/src/ohos_binding/hwf_adapter/mod.rs index ffa11457..2709c81f 100644 --- a/util/src/ohos_binding/hwf_adapter/mod.rs +++ b/util/src/ohos_binding/hwf_adapter/mod.rs @@ -12,6 +12,8 @@ #[cfg(feature = "usb_camera_oh")] pub mod camera; +#[cfg(feature = "usb_host")] +pub mod usb; use std::ffi::OsStr; use std::sync::Arc; @@ -23,6 +25,8 @@ use once_cell::sync::Lazy; #[cfg(feature = "usb_camera_oh")] use camera::CamFuncTable; +#[cfg(feature = "usb_host")] +use usb::UsbFuncTable; static LIB_HWF_ADAPTER: Lazy = Lazy::new(|| // SAFETY: The dynamic library should be always existing. @@ -40,6 +44,8 @@ struct LibHwfAdapter { library: Library, #[cfg(feature = "usb_camera_oh")] camera: Arc, + #[cfg(feature = "usb_host")] + usb: Arc, } impl LibHwfAdapter { @@ -52,10 +58,17 @@ impl LibHwfAdapter { CamFuncTable::new(&library).with_context(|| "failed to init camera function table")?, ); + #[cfg(feature = "usb_host")] + let usb = Arc::new( + UsbFuncTable::new(&library).with_context(|| "failed to init usb function table")?, + ); + Ok(Self { library, #[cfg(feature = "usb_camera_oh")] camera, + #[cfg(feature = "usb_host")] + usb, }) } @@ -63,9 +76,19 @@ impl LibHwfAdapter { fn get_camera_api(&self) -> Arc { self.camera.clone() } + + #[cfg(feature = "usb_host")] + fn get_usb_api(&self) -> Arc { + self.usb.clone() + } } #[cfg(feature = "usb_camera_oh")] pub fn hwf_adapter_camera_api() -> Arc { LIB_HWF_ADAPTER.get_camera_api() } + +#[cfg(feature = "usb_host")] +pub fn hwf_adapter_usb_api() -> Arc { + LIB_HWF_ADAPTER.get_usb_api() +} diff --git a/util/src/ohos_binding/hwf_adapter/usb.rs b/util/src/ohos_binding/hwf_adapter/usb.rs new file mode 100644 index 00000000..abb3cc74 --- /dev/null +++ b/util/src/ohos_binding/hwf_adapter/usb.rs @@ -0,0 +1,45 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::os::raw::c_int; + +use anyhow::{Context, Result}; +use libloading::os::unix::Symbol as RawSymbol; +use libloading::Library; + +use crate::get_libfn; + +#[allow(non_snake_case)] +#[repr(C)] +#[derive(Eq, PartialEq, Clone, Copy, Debug)] +pub struct OhusbDevice { + pub busNum: u8, + pub devAddr: u8, + pub fd: c_int, +} + +type OhusbOpenDeviceFn = unsafe extern "C" fn(*mut OhusbDevice) -> c_int; +type OhusbCloseDeviceFn = unsafe extern "C" fn(*mut OhusbDevice) -> c_int; + +pub struct UsbFuncTable { + pub open_device: RawSymbol, + pub close_device: RawSymbol, +} + +impl UsbFuncTable { + pub unsafe fn new(library: &Library) -> Result { + Ok(Self { + open_device: get_libfn!(library, OhusbOpenDeviceFn, OhusbOpenDevice), + close_device: get_libfn!(library, OhusbCloseDeviceFn, OhusbCloseDevice), + }) + } +} diff --git a/util/src/ohos_binding/mod.rs b/util/src/ohos_binding/mod.rs index 5f876ba5..2e6a3cfc 100644 --- a/util/src/ohos_binding/mod.rs +++ b/util/src/ohos_binding/mod.rs @@ -15,6 +15,8 @@ pub mod audio; #[cfg(feature = "usb_camera_oh")] pub mod camera; pub mod misc; +#[cfg(feature = "usb_host")] +pub mod usb; #[cfg(feature = "usb_camera_oh")] mod hwf_adapter; diff --git a/util/src/ohos_binding/usb.rs b/util/src/ohos_binding/usb.rs new file mode 100644 index 00000000..a8d227bd --- /dev/null +++ b/util/src/ohos_binding/usb.rs @@ -0,0 +1,50 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +pub use super::hwf_adapter::usb::OhusbDevice; + +use std::sync::Arc; + +use anyhow::{bail, Result}; + +use super::hwf_adapter::hwf_adapter_usb_api; +use super::hwf_adapter::usb::UsbFuncTable; + +#[derive(Clone)] +pub struct OhUsb { + capi: Arc, +} + +impl OhUsb { + pub fn new() -> Result { + let capi = hwf_adapter_usb_api(); + Ok(Self { capi }) + } + + pub fn open_device(&self, dev_handle: *mut OhusbDevice) -> Result { + // SAFETY: We call related API sequentially for specified ctx. + let ret = unsafe { (self.capi.open_device)(dev_handle) }; + if ret < 0 { + bail!("OH USB: open device failed."); + } + Ok(ret) + } + + pub fn close_device(&self, dev_handle: *mut OhusbDevice) -> Result { + // SAFETY: We call related API sequentially for specified ctx. + let ret = unsafe { (self.capi.close_device)(dev_handle) }; + if ret < 0 { + bail!("OH USB: close device failed."); + } + Ok(ret) + } +} -- Gitee From 694cc0ba2b9338e774b496e0bc8e39ab87854e32 Mon Sep 17 00:00:00 2001 From: Fan Xuan Zhe Date: Fri, 31 May 2024 18:03:47 +0800 Subject: [PATCH 095/489] usb-host: usb subsystem support for permission issues Add USB subsystem calls in the usb-host module to solve permission issues in the current libusb-based USB device pass-through solution. Signed-off-by: Fan Xuan Zhe --- build.rs | 1 + devices/Cargo.toml | 2 +- devices/src/usb/usbhost/host_usblib.rs | 19 ++++++ devices/src/usb/usbhost/mod.rs | 50 ++++++++++++---- devices/src/usb/usbhost/ohusb.rs | 83 ++++++++++++++++++++++++++ 5 files changed, 144 insertions(+), 11 deletions(-) create mode 100644 devices/src/usb/usbhost/ohusb.rs diff --git a/build.rs b/build.rs index 96f77ffd..53d0c9b2 100644 --- a/build.rs +++ b/build.rs @@ -16,6 +16,7 @@ fn ohos_env_configure() { println!("cargo:rustc-link-arg=--verbose"); println!("cargo:rustc-link-arg=--sysroot={}/sysroot", ohos_sdk_path); println!("cargo:rustc-link-arg=-lpixman_static"); + println!("cargo:rustc-link-arg=-lusb-1.0"); println!( "cargo:rustc-link-search={}/sysroot/usr/lib/aarch64-linux-ohos", ohos_sdk_path diff --git a/devices/Cargo.toml b/devices/Cargo.toml index 5d54eabf..00181b49 100644 --- a/devices/Cargo.toml +++ b/devices/Cargo.toml @@ -47,7 +47,7 @@ scream_pulseaudio = ["scream", "dep:pulse", "dep:psimple", "machine_manager/scre scream_ohaudio = ["scream", "machine_manager/scream_ohaudio", "util/scream_ohaudio"] pvpanic = ["machine_manager/pvpanic"] demo_device = ["machine_manager/demo_device", "ui/console", "util/pixman"] -usb_host = ["dep:libusb1-sys", "dep:rusb", "machine_manager/usb_host"] +usb_host = ["dep:libusb1-sys", "dep:rusb", "machine_manager/usb_host", "util/usb_host"] usb_camera = ["machine_manager/usb_camera"] usb_camera_v4l2 = ["usb_camera", "dep:v4l2-sys-mit", "machine_manager/usb_camera_v4l2", "util/usb_camera_v4l2"] usb_camera_oh = ["usb_camera", "machine_manager/usb_camera_oh", "util/usb_camera_oh"] diff --git a/devices/src/usb/usbhost/host_usblib.rs b/devices/src/usb/usbhost/host_usblib.rs index 2ee7a9de..e558f814 100644 --- a/devices/src/usb/usbhost/host_usblib.rs +++ b/devices/src/usb/usbhost/host_usblib.rs @@ -16,6 +16,8 @@ use std::{ }; use libc::{c_int, c_uint, c_void, EPOLLIN, EPOLLOUT}; +#[cfg(all(target_arch = "aarch64", target_env = "ohos"))] +use libusb1_sys::{constants::LIBUSB_SUCCESS, libusb_context, libusb_set_option}; use libusb1_sys::{ constants::{ LIBUSB_ERROR_ACCESS, LIBUSB_ERROR_BUSY, LIBUSB_ERROR_INTERRUPTED, @@ -380,3 +382,20 @@ pub fn free_host_transfer(transfer: *mut libusb_transfer) { // SAFETY: have checked the validity of transfer before call libusb_free_transfer. unsafe { libusb1_sys::libusb_free_transfer(transfer) }; } + +#[cfg(all(target_arch = "aarch64", target_env = "ohos"))] +pub fn set_option(opt: u32) -> Result<()> { + // SAFETY: This function will only configure a specific option within libusb, null for ctx is valid. + let err = unsafe { + libusb_set_option( + std::ptr::null_mut() as *mut libusb_context, + opt, + std::ptr::null_mut() as *mut c_void, + ) + }; + if err != LIBUSB_SUCCESS { + return Err(from_libusb(err)); + } + + Ok(()) +} diff --git a/devices/src/usb/usbhost/mod.rs b/devices/src/usb/usbhost/mod.rs index 40d7c8af..bd87be43 100644 --- a/devices/src/usb/usbhost/mod.rs +++ b/devices/src/usb/usbhost/mod.rs @@ -11,6 +11,8 @@ // See the Mulan PSL v2 for more details. mod host_usblib; +#[cfg(all(target_arch = "aarch64", target_env = "ohos"))] +mod ohusb; use std::{ collections::LinkedList, @@ -20,7 +22,7 @@ use std::{ time::Duration, }; -use anyhow::{anyhow, bail, Result}; +use anyhow::{anyhow, Context as anyhowContext, Result}; use clap::Parser; use libc::c_int; use libusb1_sys::{ @@ -50,6 +52,8 @@ use machine_manager::{ event_loop::{register_event_helper, unregister_event_helper}, temp_cleaner::{ExitNotifier, TempCleaner}, }; +#[cfg(all(target_arch = "aarch64", target_env = "ohos"))] +use ohusb::OhUsbDev; use util::{ byte_code::ByteCode, link_list::{List, Node}, @@ -404,6 +408,8 @@ pub struct UsbHost { iso_queues: Arc>>>>, iso_urb_frames: u32, iso_urb_count: u32, + #[cfg(all(target_arch = "aarch64", target_env = "ohos"))] + oh_dev: OhUsbDev, } // SAFETY: Send and Sync is not auto-implemented for util::link_list::List. @@ -414,6 +420,9 @@ unsafe impl Send for UsbHost {} impl UsbHost { pub fn new(config: UsbHostConfig) -> Result { + #[cfg(all(target_arch = "aarch64", target_env = "ohos"))] + let oh_dev = OhUsbDev::new()?; + let mut context = Context::new()?; context.set_log_level(rusb::LogLevel::None); let iso_urb_frames = config.iso_urb_frames; @@ -434,9 +443,12 @@ impl UsbHost { iso_queues: Arc::new(Mutex::new(LinkedList::new())), iso_urb_frames, iso_urb_count, + #[cfg(all(target_arch = "aarch64", target_env = "ohos"))] + oh_dev, }) } + #[cfg(not(all(target_arch = "aarch64", target_env = "ohos")))] fn find_libdev(&self) -> Option> { if self.config.vendorid != 0 && self.config.productid != 0 { self.find_dev_by_vendor_product() @@ -449,6 +461,7 @@ impl UsbHost { } } + #[cfg(not(all(target_arch = "aarch64", target_env = "ohos")))] fn find_dev_by_bus_addr(&self) -> Option> { self.context .devices() @@ -465,6 +478,7 @@ impl UsbHost { .unwrap_or_else(|| None) } + #[cfg(not(all(target_arch = "aarch64", target_env = "ohos")))] fn find_dev_by_vendor_product(&self) -> Option> { self.context .devices() @@ -482,6 +496,7 @@ impl UsbHost { .unwrap_or_else(|| None) } + #[cfg(not(all(target_arch = "aarch64", target_env = "ohos")))] fn find_dev_by_bus_port(&self) -> Option> { let hostport: Vec<&str> = self.config.hostport.as_ref().unwrap().split('.').collect(); let mut port: Vec = Vec::new(); @@ -644,8 +659,7 @@ impl UsbHost { } } - fn open_and_init(&mut self) -> Result<()> { - self.handle = Some(self.libdev.as_ref().unwrap().open()?); + fn init_usbdev(&mut self) -> Result<()> { self.config.hostbus = self.libdev.as_ref().unwrap().bus_number(); self.config.hostaddr = self.libdev.as_ref().unwrap().address(); trace::usb_host_open_started(self.config.hostbus, self.config.hostaddr); @@ -982,6 +996,26 @@ impl UsbHost { locked_packet.is_async = true; } + + #[cfg(not(all(target_arch = "aarch64", target_env = "ohos")))] + fn open_usbdev(&mut self) -> Result<()> { + self.libdev = Some( + self.find_libdev() + .with_context(|| format!("Invalid USB host config: {:?}", self.config))?, + ); + self.handle = Some(self.libdev.as_ref().unwrap().open()?); + Ok(()) + } + + #[cfg(all(target_arch = "aarch64", target_env = "ohos"))] + fn open_usbdev(&mut self) -> Result<()> { + self.handle = Some( + self.oh_dev + .open(self.config.clone(), self.context.clone())?, + ); + self.libdev = Some(self.handle.as_ref().unwrap().device()); + Ok(()) + } } impl Drop for UsbHost { @@ -1023,13 +1057,9 @@ impl UsbDevice for UsbHost { } fn realize(mut self) -> Result>> { - self.libdev = self.find_libdev(); - if self.libdev.is_none() { - bail!("Invalid USB host config: {:?}", self.config); - } - info!("Open and init usbhost device: {:?}", self.config); - self.open_and_init()?; + self.open_usbdev()?; + self.init_usbdev()?; let usbhost = Arc::new(Mutex::new(self)); let notifiers = EventNotifierHelper::internal_notifiers(usbhost.clone()); @@ -1296,7 +1326,7 @@ impl UsbDevice for UsbHost { } } -fn check_device_valid(device: &Device) -> bool { +pub fn check_device_valid(device: &Device) -> bool { let ddesc = match device.device_descriptor() { Ok(ddesc) => ddesc, Err(_) => return false, diff --git a/devices/src/usb/usbhost/ohusb.rs b/devices/src/usb/usbhost/ohusb.rs new file mode 100644 index 00000000..22027c9f --- /dev/null +++ b/devices/src/usb/usbhost/ohusb.rs @@ -0,0 +1,83 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::os::fd::AsRawFd; +use std::ptr; + +use anyhow::{bail, Context as anyhowContext, Result}; +use libc::c_int; +use libusb1_sys::constants::LIBUSB_OPTION_NO_DEVICE_DISCOVERY; +use log::{error, info}; +use rusb::{Context, DeviceHandle, UsbContext}; + +use super::host_usblib::set_option; +use super::{check_device_valid, UsbHostConfig}; +use util::ohos_binding::usb::*; + +pub struct OhUsbDev { + dev: OhusbDevice, + lib: OhUsb, +} + +impl Drop for OhUsbDev { + fn drop(&mut self) { + if let Err(e) = self.lib.close_device(ptr::addr_of_mut!(self.dev)) { + error!("Failed to close usb device with error {:?}", e) + } + } +} + +impl OhUsbDev { + pub fn new() -> Result { + // In combination with libusb_wrap_sys_device(), in order to access a device directly without prior device scanning on ohos. + set_option(LIBUSB_OPTION_NO_DEVICE_DISCOVERY)?; + + Ok(Self { + dev: OhusbDevice { + busNum: u8::MAX, + devAddr: u8::MAX, + fd: -1, + }, + lib: OhUsb::new()?, + }) + } + + pub fn open(&mut self, cfg: UsbHostConfig, ctx: Context) -> Result> { + self.dev.busNum = cfg.hostbus; + self.dev.devAddr = cfg.hostaddr; + + match self.lib.open_device(ptr::addr_of_mut!(self.dev))? { + 0 => { + if self.dev.fd < 0 { + bail!( + "Failed to open usb device due to invalid fd {}", + self.dev.fd + ); + } + } + _ => bail!("Failed to open usb device"), + } + info!("OH USB: open_device: returned fd is {}", self.dev.fd); + + // SAFETY: fd is valid. + let handle = unsafe { + ctx.open_device_with_fd(self.dev.fd.as_raw_fd()) + .with_context(|| format!("os last error: {:?}", std::io::Error::last_os_error()))? + }; + + if !check_device_valid(&handle.device()) { + bail!("Invalid USB host config: {:?}", cfg); + } + + Ok(handle) + } +} -- Gitee From cee5569e0d377687fe8290b6be36b975e39bf61e Mon Sep 17 00:00:00 2001 From: Fan Xuan Zhe Date: Tue, 4 Jun 2024 10:41:49 +0800 Subject: [PATCH 096/489] usb-host: remove unused use statement, add conditional compile remove unused use statement and add conditional compile to eliminate warnings while compiling. Signed-off-by: Fan Xuan Zhe --- devices/src/usb/usbhost/mod.rs | 4 +++- devices/src/usb/usbhost/ohusb.rs | 1 - 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/devices/src/usb/usbhost/mod.rs b/devices/src/usb/usbhost/mod.rs index bd87be43..3da8cf05 100644 --- a/devices/src/usb/usbhost/mod.rs +++ b/devices/src/usb/usbhost/mod.rs @@ -22,7 +22,9 @@ use std::{ time::Duration, }; -use anyhow::{anyhow, Context as anyhowContext, Result}; +#[cfg(not(all(target_arch = "aarch64", target_env = "ohos")))] +use anyhow::Context as anyhowContext; +use anyhow::{anyhow, Result}; use clap::Parser; use libc::c_int; use libusb1_sys::{ diff --git a/devices/src/usb/usbhost/ohusb.rs b/devices/src/usb/usbhost/ohusb.rs index 22027c9f..469a17a0 100644 --- a/devices/src/usb/usbhost/ohusb.rs +++ b/devices/src/usb/usbhost/ohusb.rs @@ -14,7 +14,6 @@ use std::os::fd::AsRawFd; use std::ptr; use anyhow::{bail, Context as anyhowContext, Result}; -use libc::c_int; use libusb1_sys::constants::LIBUSB_OPTION_NO_DEVICE_DISCOVERY; use log::{error, info}; use rusb::{Context, DeviceHandle, UsbContext}; -- Gitee From 7388fc1fecfaa26188801041ab8485edce6bc7c4 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sun, 19 May 2024 20:32:29 +0800 Subject: [PATCH 097/489] Devices: add trait object conversion function Stratovirt will implement DEVICE/BUS framework as a simple simplified `QOM`. Add Trait object conversion function to make preparation for the next commits. Signed-off-by: liuxiangdong --- devices/src/lib.rs | 6 ++- devices/src/misc/mod.rs | 2 +- devices/src/pci/mod.rs | 79 ++++++++++++++++++++++++++++++------- devices/src/sysbus/mod.rs | 80 +++++++++++++++++++++++++++++++++++++- machine/src/aarch64/mod.rs | 2 +- machine/src/lib.rs | 42 +++++++++++++++++--- machine/src/x86_64/mod.rs | 3 +- src/main.rs | 4 +- vfio/src/lib.rs | 6 +++ virtio/src/lib.rs | 10 +++++ 10 files changed, 208 insertions(+), 26 deletions(-) diff --git a/devices/src/lib.rs b/devices/src/lib.rs index a155ff64..0486bf1e 100644 --- a/devices/src/lib.rs +++ b/devices/src/lib.rs @@ -39,6 +39,10 @@ pub use legacy::error::LegacyError as LegacyErrs; pub use scsi::bus as ScsiBus; pub use scsi::disk as ScsiDisk; +use std::any::Any; + +use util::AsAny; + #[derive(Clone, Default)] pub struct DeviceBase { /// Name of this device @@ -53,7 +57,7 @@ impl DeviceBase { } } -pub trait Device { +pub trait Device: Any + AsAny { fn device_base(&self) -> &DeviceBase; fn device_base_mut(&mut self) -> &mut DeviceBase; diff --git a/devices/src/misc/mod.rs b/devices/src/misc/mod.rs index 36c2d9c5..0e0c015a 100644 --- a/devices/src/misc/mod.rs +++ b/devices/src/misc/mod.rs @@ -14,7 +14,7 @@ pub mod scream; #[cfg(feature = "scream")] -mod ivshmem; +pub mod ivshmem; #[cfg(feature = "pvpanic")] pub mod pvpanic; diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs index c29d7a0d..7a90d6ea 100644 --- a/devices/src/pci/mod.rs +++ b/devices/src/pci/mod.rs @@ -30,20 +30,23 @@ pub use intx::{init_intx, InterruptHandler, PciIntxState}; pub use msix::{init_msix, MsiVector}; pub use root_port::{RootPort, RootPortConfig}; -use std::{ - mem::size_of, - sync::{Arc, Mutex, Weak}, -}; +use std::any::{Any, TypeId}; +use std::collections::HashMap; +use std::mem::size_of; +use std::sync::{Arc, Mutex, Weak}; use anyhow::{bail, Result}; use byteorder::{ByteOrder, LittleEndian}; -use crate::{ - pci::config::{HEADER_TYPE, HEADER_TYPE_MULTIFUNC, MAX_FUNC}, - MsiIrqManager, -}; -use crate::{Device, DeviceBase}; -use util::AsAny; +#[cfg(feature = "scream")] +use crate::misc::ivshmem::Ivshmem; +#[cfg(feature = "pvpanic")] +use crate::misc::pvpanic::PvPanicPci; +use crate::pci::config::{HEADER_TYPE, HEADER_TYPE_MULTIFUNC, MAX_FUNC}; +use crate::usb::xhci::xhci_pci::XhciPciDevice; +use crate::{Device, DeviceBase, MsiIrqManager}; +#[cfg(feature = "demo_device")] +use demo_device::DemoDev; const BDF_FUNC_SHIFT: u8 = 3; pub const PCI_SLOT_MAX: u8 = 32; @@ -142,7 +145,7 @@ pub struct PciDevBase { pub parent_bus: Weak>, } -pub trait PciDevOps: Device + Send + AsAny { +pub trait PciDevOps: Device + Send { /// Get base property of pci device. fn pci_base(&self) -> &PciDevBase; @@ -270,6 +273,57 @@ pub trait PciDevOps: Device + Send + AsAny { } } +pub type ToPciDevOpsFunc = fn(&dyn Any) -> &dyn PciDevOps; + +static mut PCIDEVOPS_HASHMAP: Option> = None; + +pub fn convert_to_pcidevops(item: &dyn Any) -> &dyn PciDevOps { + // SAFETY: The typeid of `T` is the typeid recorded in the hashmap. The target structure type of + // the conversion is its own structure type, so the conversion result will definitely not be `None`. + let t = item.downcast_ref::().unwrap(); + t as &dyn PciDevOps +} + +pub fn register_pcidevops_type() -> Result<()> { + let type_id = TypeId::of::(); + // SAFETY: PCIDEVOPS_HASHMAP will be built in `type_init` function sequentially in the main thread. + // And will not be changed after `type_init`. + unsafe { + if PCIDEVOPS_HASHMAP.is_none() { + PCIDEVOPS_HASHMAP = Some(HashMap::new()); + } + let types = PCIDEVOPS_HASHMAP.as_mut().unwrap(); + if types.get(&type_id).is_some() { + bail!("Type Id {:?} has been registered.", type_id); + } + types.insert(type_id, convert_to_pcidevops::); + } + + Ok(()) +} + +pub fn devices_register_pcidevops_type() -> Result<()> { + #[cfg(feature = "scream")] + register_pcidevops_type::()?; + #[cfg(feature = "pvpanic")] + register_pcidevops_type::()?; + register_pcidevops_type::()?; + #[cfg(feature = "demo_device")] + register_pcidevops_type::()?; + register_pcidevops_type::() +} + +pub fn to_pcidevops(dev: &dyn Device) -> Option<&dyn PciDevOps> { + let type_id = dev.type_id(); + // SAFETY: PCIDEVOPS_HASHMAP has been built. And this function is called without changing hashmap. + unsafe { + let types = PCIDEVOPS_HASHMAP.as_mut().unwrap(); + let func = types.get(&type_id)?; + let pcidev = func(dev.as_any()); + Some(pcidev) + } +} + /// Init multifunction for pci devices. /// /// # Arguments @@ -349,11 +403,10 @@ pub fn swizzle_map_irq(devfn: u8, pin: u8) -> u32 { #[cfg(test)] mod tests { + use super::*; use crate::DeviceBase; use address_space::{AddressSpace, Region}; - use super::*; - #[test] fn test_le_write_u16_01() { let mut buf: [u8; 2] = [0; 2]; diff --git a/devices/src/sysbus/mod.rs b/devices/src/sysbus/mod.rs index 36003cd1..6083bb3f 100644 --- a/devices/src/sysbus/mod.rs +++ b/devices/src/sysbus/mod.rs @@ -14,16 +14,30 @@ pub mod error; pub use error::SysBusError; +use std::any::{Any, TypeId}; +use std::collections::HashMap; use std::fmt; use std::sync::{Arc, Mutex}; use anyhow::{bail, Context, Result}; use vmm_sys_util::eventfd::EventFd; +#[cfg(target_arch = "x86_64")] +use crate::acpi::cpu_controller::CpuController; +use crate::acpi::ged::Ged; +#[cfg(target_arch = "aarch64")] +use crate::acpi::power::PowerDev; +#[cfg(all(feature = "ramfb", target_arch = "aarch64"))] +use crate::legacy::Ramfb; +#[cfg(target_arch = "x86_64")] +use crate::legacy::{FwCfgIO, RTC}; +#[cfg(target_arch = "aarch64")] +use crate::legacy::{FwCfgMem, PL011, PL031}; +use crate::legacy::{PFlash, Serial}; +use crate::pci::PciHost; use crate::{Device, DeviceBase, IrqState, LineIrqManager, TriggerMode}; use acpi::{AmlBuilder, AmlScope}; use address_space::{AddressSpace, GuestAddress, Region, RegionIoEventFd, RegionOps}; -use util::AsAny; // Now that the serial device use a hardcoded IRQ number (4), and the starting // free IRQ number can be 5. @@ -251,7 +265,7 @@ impl SysBusDevBase { } /// Operations for sysbus devices. -pub trait SysBusDevOps: Device + Send + AmlBuilder + AsAny { +pub trait SysBusDevOps: Device + Send + AmlBuilder { fn sysbusdev_base(&self) -> &SysBusDevBase; fn sysbusdev_base_mut(&mut self) -> &mut SysBusDevBase; @@ -342,3 +356,65 @@ impl AmlBuilder for SysBus { scope.aml_bytes() } } + +pub type ToSysBusDevOpsFunc = fn(&dyn Any) -> &dyn SysBusDevOps; + +static mut SYSBUSDEVTYPE_HASHMAP: Option> = None; + +pub fn convert_to_sysbusdevops(item: &dyn Any) -> &dyn SysBusDevOps { + // SAFETY: The typeid of `T` is the typeid recorded in the hashmap. The target structure type of + // the conversion is its own structure type, so the conversion result will definitely not be `None`. + let t = item.downcast_ref::().unwrap(); + t as &dyn SysBusDevOps +} + +pub fn register_sysbusdevops_type() -> Result<()> { + let type_id = TypeId::of::(); + // SAFETY: SYSBUSDEVTYPE_HASHMAP will be built in `type_init` function sequentially in the main thread. + // And will not be changed after `type_init`. + unsafe { + if SYSBUSDEVTYPE_HASHMAP.is_none() { + SYSBUSDEVTYPE_HASHMAP = Some(HashMap::new()); + } + let types = SYSBUSDEVTYPE_HASHMAP.as_mut().unwrap(); + if types.get(&type_id).is_some() { + bail!("Type Id {:?} has been registered.", type_id); + } + types.insert(type_id, convert_to_sysbusdevops::); + } + + Ok(()) +} + +pub fn devices_register_sysbusdevops_type() -> Result<()> { + #[cfg(target_arch = "x86_64")] + { + register_sysbusdevops_type::()?; + register_sysbusdevops_type::()?; + register_sysbusdevops_type::()?; + } + #[cfg(target_arch = "aarch64")] + { + register_sysbusdevops_type::()?; + #[cfg(all(feature = "ramfb"))] + register_sysbusdevops_type::()?; + register_sysbusdevops_type::()?; + register_sysbusdevops_type::()?; + register_sysbusdevops_type::()?; + } + register_sysbusdevops_type::()?; + register_sysbusdevops_type::()?; + register_sysbusdevops_type::()?; + register_sysbusdevops_type::() +} + +pub fn to_sysbusdevops(dev: &dyn Device) -> Option<&dyn SysBusDevOps> { + let type_id = dev.type_id(); + // SAFETY: SYSBUSDEVTYPE_HASHMAP has been built. And this function is called without changing hashmap. + unsafe { + let types = SYSBUSDEVTYPE_HASHMAP.as_mut().unwrap(); + let func = types.get(&type_id)?; + let sysbusdev = func(dev.as_any()); + Some(sysbusdev) + } +} diff --git a/machine/src/aarch64/mod.rs b/machine/src/aarch64/mod.rs index ee107ad4..3ffe949f 100644 --- a/machine/src/aarch64/mod.rs +++ b/machine/src/aarch64/mod.rs @@ -11,7 +11,7 @@ // See the Mulan PSL v2 for more details. pub mod micro; +pub mod pci_host_root; pub mod standard; mod fdt; -mod pci_host_root; diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 9bd6b29c..94d07f5b 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -52,10 +52,13 @@ use devices::misc::pvpanic::{PvPanicPci, PvpanicDevConfig}; use devices::misc::scream::{Scream, ScreamConfig}; #[cfg(feature = "demo_device")] use devices::pci::demo_device::{DemoDev, DemoDevConfig}; -use devices::pci::{PciBus, PciDevOps, PciHost, RootPort, RootPortConfig}; +use devices::pci::{ + devices_register_pcidevops_type, register_pcidevops_type, PciBus, PciDevOps, PciHost, RootPort, + RootPortConfig, +}; use devices::smbios::smbios_table::{build_smbios_ep30, SmbiosTable}; use devices::smbios::{SMBIOS_ANCHOR_FILE, SMBIOS_TABLE_FILE}; -use devices::sysbus::{SysBus, SysBusDevOps, SysBusDevType}; +use devices::sysbus::{devices_register_sysbusdevops_type, SysBus, SysBusDevOps, SysBusDevType}; #[cfg(feature = "usb_camera")] use devices::usb::camera::{UsbCamera, UsbCameraConfig}; use devices::usb::keyboard::{UsbKeyboard, UsbKeyboardConfig}; @@ -90,12 +93,13 @@ use util::{ arg_parser, seccomp::{BpfRule, SeccompOpt, SyscallFilter}, }; -use vfio::{VfioConfig, VfioDevice, VfioPciDevice, KVM_DEVICE_FD}; +use vfio::{vfio_register_pcidevops_type, VfioConfig, VfioDevice, VfioPciDevice, KVM_DEVICE_FD}; #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] use virtio::VirtioDeviceQuirk; use virtio::{ - balloon_allow_list, find_port_by_nr, get_max_nr, vhost, Balloon, BalloonConfig, Block, - BlockState, Rng, RngConfig, RngState, + balloon_allow_list, find_port_by_nr, get_max_nr, vhost, virtio_register_pcidevops_type, + virtio_register_sysbusdevops_type, Balloon, BalloonConfig, Block, BlockState, Rng, RngConfig, + RngState, ScsiCntlr::{scsi_cntlr_create_scsi_bus, ScsiCntlr, ScsiCntlrConfig}, Serial, SerialPort, VhostKern, VhostUser, VirtioBlkDevConfig, VirtioDevice, VirtioMmioDevice, VirtioMmioState, VirtioNetState, VirtioPciDevice, VirtioSerialState, VIRTIO_TYPE_CONSOLE, @@ -2347,3 +2351,31 @@ fn check_windows_emu_pid( .unwrap() .timer_add(check_emu_alive, check_delay); } + +fn machine_register_pcidevops_type() -> Result<()> { + #[cfg(target_arch = "x86_64")] + { + register_pcidevops_type::()?; + register_pcidevops_type::()?; + } + #[cfg(target_arch = "aarch64")] + { + register_pcidevops_type::()?; + } + + Ok(()) +} + +pub fn type_init() -> Result<()> { + // Register all sysbus devices type. + virtio_register_sysbusdevops_type()?; + devices_register_sysbusdevops_type()?; + + // Register all pci devices type. + machine_register_pcidevops_type()?; + vfio_register_pcidevops_type()?; + virtio_register_pcidevops_type()?; + devices_register_pcidevops_type()?; + + Ok(()) +} diff --git a/machine/src/x86_64/mod.rs b/machine/src/x86_64/mod.rs index 47b4ecbe..b3227f99 100644 --- a/machine/src/x86_64/mod.rs +++ b/machine/src/x86_64/mod.rs @@ -11,7 +11,6 @@ // See the Mulan PSL v2 for more details. pub mod ich9_lpc; +pub mod mch; pub mod micro; pub mod standard; - -mod mch; diff --git a/src/main.rs b/src/main.rs index 5f038103..4a777564 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,7 +18,7 @@ use anyhow::{bail, Context, Result}; use log::{error, info}; use thiserror::Error; -use machine::{LightMachine, MachineOps, StdMachine}; +use machine::{type_init, LightMachine, MachineOps, StdMachine}; use machine_manager::{ cmdline::{check_api_channel, create_args_parser, create_vmconfig}, config::MachineType, @@ -71,6 +71,8 @@ fn main() -> ExitCode { } fn run() -> Result<()> { + type_init()?; + let cmd_args = create_args_parser().get_matches()?; if cmd_args.is_present("mod-test") { diff --git a/vfio/src/lib.rs b/vfio/src/lib.rs index ab47b6ce..3d2705a3 100644 --- a/vfio/src/lib.rs +++ b/vfio/src/lib.rs @@ -28,9 +28,11 @@ use std::collections::HashMap; use std::os::unix::io::RawFd; use std::sync::{Arc, Mutex}; +use anyhow::Result; use kvm_ioctls::DeviceFd; use once_cell::sync::Lazy; +use devices::pci::register_pcidevops_type; use vfio_dev::VfioGroup; pub static KVM_DEVICE_FD: Lazy>> = Lazy::new(|| Mutex::new(None)); @@ -38,3 +40,7 @@ pub static CONTAINERS: Lazy>>>> = Lazy::new(|| Mutex::new(HashMap::new())); pub static GROUPS: Lazy>>> = Lazy::new(|| Mutex::new(HashMap::new())); + +pub fn vfio_register_pcidevops_type() -> Result<()> { + register_pcidevops_type::() +} diff --git a/virtio/src/lib.rs b/virtio/src/lib.rs index 58fbe4f0..1fed7f32 100644 --- a/virtio/src/lib.rs +++ b/virtio/src/lib.rs @@ -58,6 +58,8 @@ use log::{error, warn}; use vmm_sys_util::eventfd::EventFd; use address_space::{AddressSpace, RegionCache}; +use devices::pci::register_pcidevops_type; +use devices::sysbus::register_sysbusdevops_type; use machine_manager::config::ConfigCheck; use migration_derive::ByteCode; use util::aio::{mem_to_buf, Iovec}; @@ -867,3 +869,11 @@ fn gpa_hva_iovec_map_by_cache( Ok((iov_size, hva_iovec)) } + +pub fn virtio_register_sysbusdevops_type() -> Result<()> { + register_sysbusdevops_type::() +} + +pub fn virtio_register_pcidevops_type() -> Result<()> { + register_pcidevops_type::() +} -- Gitee From 073c902347e813abc4b27baabe78d4000c376b44 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sat, 18 May 2024 15:35:46 +0800 Subject: [PATCH 098/489] accel: use clap to parse the parameters of the accel config Use clap to parse the parameters of the accel config. Signed-off-by: liuxiangdong --- machine_manager/src/config/machine_config.rs | 39 ++++++++++++++------ machine_manager/src/machine.rs | 8 ++-- 2 files changed, 33 insertions(+), 14 deletions(-) diff --git a/machine_manager/src/config/machine_config.rs b/machine_manager/src/config/machine_config.rs index fa277b03..20b52fe1 100644 --- a/machine_manager/src/config/machine_config.rs +++ b/machine_manager/src/config/machine_config.rs @@ -251,6 +251,13 @@ impl ConfigCheck for MachineConfig { } } +#[derive(Parser)] +#[command(no_binary_name(true))] +struct AccelConfig { + #[arg(long, alias = "classtype")] + hypervisor: HypervisorType, +} + impl VmConfig { /// Add argument `name` to `VmConfig`. /// @@ -317,17 +324,8 @@ impl VmConfig { /// Add '-accel' accelerator config to `VmConfig`. pub fn add_accel(&mut self, accel_config: &str) -> Result<()> { - let mut cmd_parser = CmdParser::new("accel"); - cmd_parser.push(""); - cmd_parser.parse(accel_config)?; - - if let Some(accel) = cmd_parser - .get_value::("") - .with_context(|| "Only \'kvm\' and \'test\' is supported for \'accel\'")? - { - self.machine_config.hypervisor = accel; - } - + let accel_cfg = AccelConfig::try_parse_from(str_slip_to_clap(accel_config, true, false))?; + self.machine_config.hypervisor = accel_cfg.hypervisor; Ok(()) } @@ -1083,4 +1081,23 @@ mod tests { let result = vm_config.add_cpu_feature("host,sve=false"); assert!(result.is_err()); } + + #[test] + fn test_add_accel() { + let mut vm_config = VmConfig::default(); + let accel_cfg = "kvm"; + assert!(vm_config.add_accel(accel_cfg).is_ok()); + let machine_cfg = vm_config.machine_config; + assert_eq!(machine_cfg.hypervisor, HypervisorType::Kvm); + + let mut vm_config = VmConfig::default(); + let accel_cfg = "kvm:tcg"; + assert!(vm_config.add_accel(accel_cfg).is_ok()); + let machine_cfg = vm_config.machine_config; + assert_eq!(machine_cfg.hypervisor, HypervisorType::Kvm); + + let mut vm_config = VmConfig::default(); + let accel_cfg = "kvm1"; + assert!(vm_config.add_accel(accel_cfg).is_err()); + } } diff --git a/machine_manager/src/machine.rs b/machine_manager/src/machine.rs index ff4d8586..a040d6ef 100644 --- a/machine_manager/src/machine.rs +++ b/machine_manager/src/machine.rs @@ -14,6 +14,7 @@ use std::os::unix::io::RawFd; use std::str::FromStr; use std::sync::Mutex; +use anyhow::anyhow; use once_cell::sync::Lazy; use serde::{Deserialize, Serialize}; use strum::VariantNames; @@ -54,13 +55,14 @@ pub enum HypervisorType { } impl FromStr for HypervisorType { - type Err = (); + type Err = anyhow::Error; fn from_str(s: &str) -> std::result::Result { match s { - "kvm" => Ok(HypervisorType::Kvm), + // Note: "kvm:tcg" is a configuration compatible with libvirt. + "kvm" | "kvm:tcg" => Ok(HypervisorType::Kvm), "test" => Ok(HypervisorType::Test), - _ => Err(()), + _ => Err(anyhow!("Not supported or invalid hypervisor type {}.", s)), } } } -- Gitee From 92d1271d8ef49723bf07bae11edfc2a9f6c9e26e Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sat, 18 May 2024 16:20:54 +0800 Subject: [PATCH 099/489] qmp/mon: use clap to parse the parameters of the qmp/mon config Use clap to parse the parameters of the qmp/mon config. Signed-off-by: liuxiangdong --- machine_manager/src/cmdline.rs | 70 ++++++++++++++++------------------ 1 file changed, 33 insertions(+), 37 deletions(-) diff --git a/machine_manager/src/cmdline.rs b/machine_manager/src/cmdline.rs index de8e54c4..619a7c2b 100644 --- a/machine_manager/src/cmdline.rs +++ b/machine_manager/src/cmdline.rs @@ -11,9 +11,10 @@ // See the Mulan PSL v2 for more details. use anyhow::{bail, Context, Result}; +use clap::{ArgAction, Parser}; use crate::{ - config::{add_trace, ChardevType, CmdParser, MachineType, SocketType, VmConfig}, + config::{add_trace, str_slip_to_clap, ChardevType, MachineType, SocketType, VmConfig}, qmp::qmp_socket::QmpSocketPath, temp_cleaner::TempCleaner, }; @@ -599,6 +600,28 @@ pub fn create_vmconfig(args: &ArgMatches) -> Result { Ok(vm_cfg) } +#[derive(Parser)] +#[command(no_binary_name(true))] +struct QmpConfig { + #[arg(long, alias = "classtype")] + uri: String, + #[arg(long, action = ArgAction::SetTrue, required = true)] + server: bool, + #[arg(long, action = ArgAction::SetTrue, required = true)] + nowait: bool, +} + +#[derive(Parser)] +#[command(no_binary_name(true))] +struct MonConfig { + #[arg(long, default_value = "")] + id: String, + #[arg(long, value_parser = ["control"])] + mode: String, + #[arg(long)] + chardev: String, +} + /// This function is to parse qmp socket path and type. /// /// # Arguments @@ -613,45 +636,18 @@ pub fn check_api_channel( vm_config: &mut VmConfig, ) -> Result> { let mut sock_paths = Vec::new(); - if let Some(qmp_config) = args.value_of("qmp") { - let mut cmd_parser = CmdParser::new("qmp"); - cmd_parser.push("").push("server").push("nowait"); - - cmd_parser.parse(&qmp_config)?; - if let Some(uri) = cmd_parser.get_value::("")? { - let sock_path = - QmpSocketPath::new(uri).with_context(|| "Failed to parse qmp socket path")?; - sock_paths.push(sock_path); - } else { - bail!("No uri found for qmp"); - } - if cmd_parser.get_value::("server")?.is_none() { - bail!("Argument \'server\' is needed for qmp"); - } - if cmd_parser.get_value::("nowait")?.is_none() { - bail!("Argument \'nowait\' is needed for qmp"); - } + if let Some(qmp_args) = args.value_of("qmp") { + let qmp_cfg = QmpConfig::try_parse_from(str_slip_to_clap(&qmp_args, true, false))?; + let sock_path = + QmpSocketPath::new(qmp_cfg.uri).with_context(|| "Failed to parse qmp socket path")?; + sock_paths.push(sock_path); } - if let Some(mon_config) = args.value_of("mon") { - let mut cmd_parser = CmdParser::new("monitor"); - cmd_parser.push("id").push("mode").push("chardev"); - cmd_parser.parse(&mon_config)?; - - let chardev = cmd_parser - .get_value::("chardev")? - .with_context(|| "Argument \'chardev\' is missing for \'mon\'")?; - - let mode = cmd_parser - .get_value::("mode")? - .with_context(|| "Argument \'mode\' of \'mon\' should be set to \'control\'.")?; - if mode != "control" { - bail!("Invalid \'mode\' parameter: {:?} for monitor", &mode); - } - + if let Some(mon_args) = args.value_of("mon") { + let mon_cfg = MonConfig::try_parse_from(str_slip_to_clap(&mon_args, false, false))?; let cfg = vm_config .chardev - .remove(&chardev) - .with_context(|| format!("No chardev found: {}", &chardev))?; + .remove(&mon_cfg.chardev) + .with_context(|| format!("No chardev found: {}", &mon_cfg.chardev))?; let socket = cfg .classtype .socket_type() -- Gitee From 1d7707c1820b903e387dd06b4d7f7487171f2222 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Mon, 20 May 2024 05:10:53 +0800 Subject: [PATCH 100/489] numa: use clap to parse the parameters of the numa config Use clap to parse the parameters of the numa config Signed-off-by: liuxiangdong --- machine/src/lib.rs | 39 +++--- machine_manager/src/config/numa.rs | 198 +++++++++++------------------ 2 files changed, 91 insertions(+), 146 deletions(-) diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 94d07f5b..1ae93787 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -79,8 +79,8 @@ use machine_manager::config::{ complete_numa_node, get_chardev_socket_path, get_class_type, get_pci_bdf, get_value_of_parameter, parse_numa_distance, parse_numa_mem, str_slip_to_clap, BootIndexInfo, BootSource, ConfigCheck, DriveConfig, DriveFile, Incoming, MachineMemConfig, MigrateMode, - NetworkInterfaceConfig, NumaConfig, NumaDistance, NumaNode, NumaNodes, PciBdf, SerialConfig, - VirtioSerialInfo, VirtioSerialPortCfg, VmConfig, FAST_UNPLUG_ON, MAX_VIRTIO_QUEUE, + NetworkInterfaceConfig, NumaNode, NumaNodes, PciBdf, SerialConfig, VirtioSerialInfo, + VirtioSerialPortCfg, VmConfig, FAST_UNPLUG_ON, MAX_VIRTIO_QUEUE, }; use machine_manager::event_loop::EventLoop; use machine_manager::machine::{HypervisorType, MachineInterface, VmState}; @@ -1571,46 +1571,47 @@ pub trait MachineOps { for numa in vm_config.numa_nodes.iter() { match numa.0.as_str() { "node" => { - let numa_config: NumaConfig = parse_numa_mem(numa.1.as_str())?; - if numa_nodes.contains_key(&numa_config.numa_id) { - bail!("Numa node id is repeated {}", numa_config.numa_id); + let node_config = parse_numa_mem(numa.1.as_str())?; + if numa_nodes.contains_key(&node_config.numa_id) { + bail!("Numa node id is repeated {}", node_config.numa_id); } let mut numa_node = NumaNode { - cpus: numa_config.cpus, - mem_dev: numa_config.mem_dev.clone(), + cpus: node_config.cpus, + mem_dev: node_config.mem_dev.clone(), ..Default::default() }; numa_node.size = vm_config .object .mem_object - .remove(&numa_config.mem_dev) + .remove(&node_config.mem_dev) .map(|mem_conf| mem_conf.size) .with_context(|| { format!( "Object for memory-backend {} config not found", - numa_config.mem_dev + node_config.mem_dev ) })?; - numa_nodes.insert(numa_config.numa_id, numa_node); + numa_nodes.insert(node_config.numa_id, numa_node); } "dist" => { - let dist: (u32, NumaDistance) = parse_numa_distance(numa.1.as_str())?; - if !numa_nodes.contains_key(&dist.0) { - bail!("Numa node id is not found {}", dist.0); + let dist_config = parse_numa_distance(numa.1.as_str())?; + if !numa_nodes.contains_key(&dist_config.numa_id) { + bail!("Numa node id is not found {}", dist_config.numa_id); } - if !numa_nodes.contains_key(&dist.1.destination) { - bail!("Numa node id is not found {}", dist.1.destination); + if !numa_nodes.contains_key(&dist_config.destination) { + bail!("Numa node id is not found {}", dist_config.destination); } - if let Some(n) = numa_nodes.get_mut(&dist.0) { - if n.distances.contains_key(&dist.1.destination) { + if let Some(n) = numa_nodes.get_mut(&dist_config.numa_id) { + if n.distances.contains_key(&dist_config.destination) { bail!( "Numa destination info {} repeat settings", - dist.1.destination + dist_config.destination ); } - n.distances.insert(dist.1.destination, dist.1.distance); + n.distances + .insert(dist_config.destination, dist_config.distance); } } _ => { diff --git a/machine_manager/src/config/numa.rs b/machine_manager/src/config/numa.rs index 27da8260..664b1803 100644 --- a/machine_manager/src/config/numa.rs +++ b/machine_manager/src/config/numa.rs @@ -12,30 +12,17 @@ use std::cmp::max; use std::collections::{BTreeMap, HashSet}; +use std::str::FromStr; -use anyhow::{anyhow, bail, Context, Result}; +use anyhow::{bail, Context, Result}; +use clap::Parser; use super::error::ConfigError; -use super::get_class_type; -use crate::config::{CmdParser, IntegerList, VmConfig, MAX_NODES}; +use super::{get_class_type, str_slip_to_clap}; +use crate::config::{IntegerList, VmConfig, MAX_NODES}; const MIN_NUMA_DISTANCE: u8 = 10; -#[derive(Default, Debug)] -pub struct NumaDistance { - pub destination: u32, - pub distance: u8, -} - -#[derive(Default, Debug)] -pub struct NumaConfig { - pub numa_id: u32, - pub cpus: Vec, - pub distances: Option>, - pub size: u64, - pub mem_dev: String, -} - #[derive(Default)] pub struct NumaNode { pub cpus: Vec, @@ -110,126 +97,83 @@ pub fn complete_numa_node(numa_nodes: &mut NumaNodes, nr_cpus: u8, mem_size: u64 Ok(()) } -/// Parse the NUMA node memory parameters. -/// -/// # Arguments -/// -/// * `numa_config` - The NUMA node configuration. -pub fn parse_numa_mem(numa_config: &str) -> Result { - let mut cmd_parser = CmdParser::new("numa"); - cmd_parser - .push("") - .push("nodeid") - .push("cpus") - .push("memdev"); - cmd_parser.parse(numa_config)?; - - let mut config: NumaConfig = NumaConfig::default(); - if let Some(node_id) = cmd_parser.get_value::("nodeid")? { - if node_id >= MAX_NODES { - return Err(anyhow!(ConfigError::IllegalValue( - "nodeid".to_string(), - 0, - true, - MAX_NODES as u64, - false, - ))); - } - config.numa_id = node_id; - } else { - return Err(anyhow!(ConfigError::FieldIsMissing( - "nodeid".to_string(), - "numa".to_string() - ))); - } - if let Some(mut cpus) = cmd_parser - .get_value::("cpus") +#[derive(Parser)] +#[command(no_binary_name(true))] +pub struct NumaNodeConfig { + #[arg(long, value_parser = ["node"])] + pub classtype: String, + #[arg(long, alias = "nodeid", value_parser = clap::value_parser!(u32).range(..MAX_NODES as i64))] + pub numa_id: u32, + #[arg(long, value_parser = get_cpus)] + pub cpus: ::std::vec::Vec, + #[arg(long, alias = "memdev")] + pub mem_dev: String, +} + +fn get_cpus(cpus_str: &str) -> Result> { + let mut cpus = IntegerList::from_str(cpus_str) .with_context(|| ConfigError::ConvertValueFailed(String::from("u8"), "cpus".to_string()))? - .map(|v| v.0.iter().map(|e| *e as u8).collect::>()) - { - cpus.sort_unstable(); - config.cpus = cpus; - } else { - return Err(anyhow!(ConfigError::FieldIsMissing( - "cpus".to_string(), - "numa".to_string() - ))); + .0 + .iter() + .map(|e| *e as u8) + .collect::>(); + + if cpus.is_empty() { + bail!("Got empty cpus list!"); } - config.mem_dev = cmd_parser - .get_value::("memdev")? - .with_context(|| ConfigError::FieldIsMissing("memdev".to_string(), "numa".to_string()))?; - Ok(config) + cpus.sort_unstable(); + + Ok(cpus) } -/// Parse the NUMA node distance parameters. +/// Parse the NUMA node memory parameters. /// /// # Arguments /// -/// * `numa_dist` - The NUMA node distance configuration. -pub fn parse_numa_distance(numa_dist: &str) -> Result<(u32, NumaDistance)> { - let mut cmd_parser = CmdParser::new("numa"); - cmd_parser.push("").push("src").push("dst").push("val"); - cmd_parser.parse(numa_dist)?; - - let mut dist: NumaDistance = NumaDistance::default(); - let numa_id = if let Some(src) = cmd_parser.get_value::("src")? { - if src >= MAX_NODES { - return Err(anyhow!(ConfigError::IllegalValue( - "src".to_string(), - 0, - true, - MAX_NODES as u64, - false, - ))); - } - src - } else { - return Err(anyhow!(ConfigError::FieldIsMissing( - "src".to_string(), - "numa".to_string() - ))); - }; - if let Some(dst) = cmd_parser.get_value::("dst")? { - if dst >= MAX_NODES { - return Err(anyhow!(ConfigError::IllegalValue( - "dst".to_string(), - 0, - true, - MAX_NODES as u64, - false, - ))); - } - dist.destination = dst; - } else { - return Err(anyhow!(ConfigError::FieldIsMissing( - "dst".to_string(), - "numa".to_string() - ))); - } - if let Some(val) = cmd_parser.get_value::("val")? { - if val < MIN_NUMA_DISTANCE { - bail!("NUMA distance shouldn't be less than 10"); - } - if numa_id == dist.destination && val != MIN_NUMA_DISTANCE { - bail!("Local distance of node {} should be 10.", numa_id); +/// * `numa_config` - The NUMA node configuration. +pub fn parse_numa_mem(numa_config: &str) -> Result { + let config = NumaNodeConfig::try_parse_from(str_slip_to_clap(numa_config, true, false))?; + Ok(config) +} + +#[derive(Parser)] +#[command(no_binary_name(true))] +pub struct NumaDistConfig { + #[arg(long, value_parser = ["dist"])] + pub classtype: String, + #[arg(long, alias = "src", value_parser = clap::value_parser!(u32).range(..MAX_NODES as i64))] + pub numa_id: u32, + #[arg(long, alias = "dst", value_parser = clap::value_parser!(u32).range(..MAX_NODES as i64))] + pub destination: u32, + #[arg(long, alias = "val", value_parser = clap::value_parser!(u8).range(MIN_NUMA_DISTANCE as i64..))] + pub distance: u8, +} + +impl NumaDistConfig { + fn check(&self) -> Result<()> { + if self.numa_id == self.destination && self.distance != MIN_NUMA_DISTANCE { + bail!("Local distance of node {} should be 10.", self.numa_id); } - if numa_id != dist.destination && val == MIN_NUMA_DISTANCE { + if self.numa_id != self.destination && self.distance == MIN_NUMA_DISTANCE { bail!( "Remote distance of node {} should be more than 10.", - numa_id + self.numa_id ); } - - dist.distance = val; - } else { - return Err(anyhow!(ConfigError::FieldIsMissing( - "val".to_string(), - "numa".to_string() - ))); + Ok(()) } +} - Ok((numa_id, dist)) +/// Parse the NUMA node distance parameters. +/// +/// # Arguments +/// +/// * `numa_dist` - The NUMA node distance configuration. +pub fn parse_numa_distance(numa_dist: &str) -> Result { + let dist_cfg = NumaDistConfig::try_parse_from(str_slip_to_clap(numa_dist, true, false))?; + dist_cfg.check()?; + Ok(dist_cfg) } impl VmConfig { @@ -292,10 +236,10 @@ mod tests { assert!(vm_config.add_numa("dist,src=0,dst=1,val=10").is_ok()); let numa = vm_config.numa_nodes.get(0).unwrap(); - let dist = parse_numa_distance(numa.1.as_str()).unwrap(); - assert_eq!(dist.0, 0); - assert_eq!(dist.1.destination, 1); - assert_eq!(dist.1.distance, 15); + let dist_cfg = parse_numa_distance(numa.1.as_str()).unwrap(); + assert_eq!(dist_cfg.numa_id, 0); + assert_eq!(dist_cfg.destination, 1); + assert_eq!(dist_cfg.distance, 15); let numa = vm_config.numa_nodes.get(1).unwrap(); assert!(parse_numa_distance(numa.1.as_str()).is_err()); -- Gitee From 1fadfd8b8db187f8c0cad03d883cd8c577116f90 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Mon, 20 May 2024 05:58:49 +0800 Subject: [PATCH 101/489] memory size: use clap to parse the parameters of the memory size config Use clap to parse the parameters of the memory size config Signed-off-by: liuxiangdong --- machine_manager/src/config/machine_config.rs | 36 ++++++++++---------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/machine_manager/src/config/machine_config.rs b/machine_manager/src/config/machine_config.rs index 20b52fe1..ec60bc7c 100644 --- a/machine_manager/src/config/machine_config.rs +++ b/machine_manager/src/config/machine_config.rs @@ -17,7 +17,9 @@ use clap::{ArgAction, Parser}; use serde::{Deserialize, Serialize}; use super::error::ConfigError; -use super::{parse_bool, parse_size, str_slip_to_clap, valid_id, valid_path}; +use super::{ + get_value_of_parameter, parse_bool, parse_size, str_slip_to_clap, valid_id, valid_path, +}; use crate::config::{CmdParser, ConfigCheck, ExBool, IntegerList, VmConfig, MAX_NODES}; use crate::machine::HypervisorType; @@ -258,6 +260,13 @@ struct AccelConfig { hypervisor: HypervisorType, } +#[derive(Parser)] +#[command(no_binary_name(true))] +struct MemSizeConfig { + #[arg(long, alias = "classtype", value_parser = parse_size)] + size: u64, +} + impl VmConfig { /// Add argument `name` to `VmConfig`. /// @@ -331,23 +340,14 @@ impl VmConfig { /// Add '-m' memory config to `VmConfig`. pub fn add_memory(&mut self, mem_config: &str) -> Result<()> { - let mut cmd_parser = CmdParser::new("m"); - cmd_parser.push("").push("size"); - - cmd_parser.parse(mem_config)?; - - let mem = if let Some(mem_size) = cmd_parser.get_value::("")? { - memory_unit_conversion(&mem_size, M)? - } else if let Some(mem_size) = cmd_parser.get_value::("size")? { - memory_unit_conversion(&mem_size, M)? - } else { - return Err(anyhow!(ConfigError::FieldIsMissing( - "size".to_string(), - "memory".to_string() - ))); - }; - - self.machine_config.mem_config.mem_size = mem; + // Is there a "size=" prefix tag in the command line. + let mut has_size_label = false; + if get_value_of_parameter("size", mem_config).is_ok() { + has_size_label = true; + } + let mem_cfg = + MemSizeConfig::try_parse_from(str_slip_to_clap(mem_config, !has_size_label, false))?; + self.machine_config.mem_config.mem_size = mem_cfg.size; Ok(()) } -- Gitee From 15269c3ceb23a44df468f09226421dd5880edf63 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Mon, 20 May 2024 07:20:34 +0800 Subject: [PATCH 102/489] smbios: use clap to parse the parameters of the smbios config Use clap to parse the parameters of the smbios config. As of now, all `get_parameters` have been replaced by `get_value_of_parameter`, delete useless `get_parameters`. Signed-off-by: liuxiangdong --- devices/src/smbios/smbios_table.rs | 4 +- machine_manager/src/config/mod.rs | 42 ----- machine_manager/src/config/smbios.rs | 251 ++++++++++++--------------- 3 files changed, 116 insertions(+), 181 deletions(-) diff --git a/devices/src/smbios/smbios_table.rs b/devices/src/smbios/smbios_table.rs index 9211bd88..f476025b 100644 --- a/devices/src/smbios/smbios_table.rs +++ b/devices/src/smbios/smbios_table.rs @@ -656,9 +656,9 @@ impl SmbiosTable { fn build_type0(&mut self, type0: SmbiosType0Config) { let mut table0: SmbiosType0Table = SmbiosType0Table::new(); - if let Some(vender) = type0.vender { + if let Some(vendor) = type0.vendor { table0.header.vendor_idx = table0.str_index + 1; - table0.set_str(vender); + table0.set_str(vendor); } if let Some(version) = type0.version { diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index 36ae7a40..d88d4937 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -500,48 +500,6 @@ impl CmdParser { Ok(()) } - /// Parse all cmdline parameters string into `params`. - /// - /// # Arguments - /// - /// * `cmd_param`: The whole cmdline parameter string. - fn get_parameters(&mut self, cmd_param: &str) -> Result<()> { - if cmd_param.starts_with(',') || cmd_param.ends_with(',') { - return Err(anyhow!(ConfigError::InvalidParam( - cmd_param.to_string(), - self.name.clone() - ))); - } - let param_items = cmd_param.split(',').collect::>(); - for param_item in param_items { - let param = param_item.splitn(2, '=').collect::>(); - let (param_key, param_value) = match param.len() { - 1 => ("", param[0]), - 2 => (param[0], param[1]), - _ => { - return Err(anyhow!(ConfigError::InvalidParam( - param_item.to_string(), - self.name.clone() - ))); - } - }; - - if self.params.contains_key(param_key) { - let field_value = self.params.get_mut(param_key).unwrap(); - if field_value.is_none() { - *field_value = Some(String::from(param_value)); - } else { - return Err(anyhow!(ConfigError::FieldRepeat( - self.name.clone(), - param_key.to_string() - ))); - } - } - } - - Ok(()) - } - /// Get cmdline parameters value from param field name. /// /// # Arguments diff --git a/machine_manager/src/config/smbios.rs b/machine_manager/src/config/smbios.rs index 2c8f0d95..75220f45 100644 --- a/machine_manager/src/config/smbios.rs +++ b/machine_manager/src/config/smbios.rs @@ -12,74 +12,138 @@ use std::str::FromStr; -use anyhow::{bail, Context, Result}; +use anyhow::{anyhow, bail, Result}; +use clap::Parser; use serde::{Deserialize, Serialize}; -use crate::config::{CmdParser, VmConfig}; +use super::{get_value_of_parameter, str_slip_to_clap}; +use crate::config::VmConfig; -#[derive(Clone, Default, Debug, Serialize, Deserialize)] +#[derive(Parser, Clone, Default, Debug, Serialize, Deserialize)] +#[command(no_binary_name(true))] pub struct SmbiosType0Config { - pub vender: Option, + #[arg(long, alias = "type", value_parser = ["0"])] + pub smbios_type: String, + #[arg(long)] + pub vendor: Option, + #[arg(long)] pub version: Option, + #[arg(long)] pub date: Option, + // Note: we don't set `ArgAction::Append` for `added`, so it cannot be specified + // from the command line, as command line will parse errors. + #[arg(long, default_value = "true")] pub added: bool, } -#[derive(Clone, Default, Debug, Serialize, Deserialize)] +#[derive(Parser, Clone, Default, Debug, Serialize, Deserialize)] +#[command(no_binary_name(true))] pub struct SmbiosType1Config { + #[arg(long, alias = "type", value_parser = ["1"])] + pub smbios_type: String, + #[arg(long)] pub manufacturer: Option, + #[arg(long)] pub product: Option, + #[arg(long)] pub version: Option, + #[arg(long)] pub serial: Option, + #[arg(long)] pub sku: Option, + #[arg(long)] pub family: Option, + #[arg(long, value_parser = get_uuid)] pub uuid: Option, + #[arg(long, default_value = "true")] pub added: bool, } -#[derive(Clone, Default, Debug, Serialize, Deserialize)] +#[derive(Parser, Clone, Default, Debug, Serialize, Deserialize)] +#[command(no_binary_name(true))] pub struct SmbiosType2Config { + #[arg(long, alias = "type", value_parser = ["2"])] + pub smbios_type: String, + #[arg(long)] pub manufacturer: Option, + #[arg(long)] pub product: Option, + #[arg(long)] pub version: Option, + #[arg(long)] pub serial: Option, + #[arg(long)] pub asset: Option, + #[arg(long)] pub location: Option, + #[arg(long, default_value = "true")] pub added: bool, } -#[derive(Clone, Default, Debug, Serialize, Deserialize)] +#[derive(Parser, Clone, Default, Debug, Serialize, Deserialize)] +#[command(no_binary_name(true))] pub struct SmbiosType3Config { + #[arg(long, alias = "type", value_parser = ["3"])] + pub smbios_type: String, + #[arg(long)] pub manufacturer: Option, + #[arg(long)] pub version: Option, + #[arg(long)] pub serial: Option, + #[arg(long)] pub sku: Option, + #[arg(long)] pub asset: Option, + #[arg(long, default_value = "true")] pub added: bool, } -#[derive(Clone, Default, Debug, Serialize, Deserialize)] +#[derive(Parser, Clone, Default, Debug, Serialize, Deserialize)] +#[command(no_binary_name(true))] pub struct SmbiosType4Config { + #[arg(long, alias = "type", value_parser = ["4"])] + pub smbios_type: String, + #[arg(long)] pub manufacturer: Option, + #[arg(long)] pub version: Option, + #[arg(long)] pub serial: Option, + #[arg(long)] pub asset: Option, + #[arg(long, alias = "sock_pfx")] pub sock_pfx: Option, + #[arg(long)] pub part: Option, + #[arg(long)] pub max_speed: Option, + #[arg(long)] pub current_speed: Option, + #[arg(long, default_value = "true")] pub added: bool, } -#[derive(Clone, Default, Debug, Serialize, Deserialize)] +#[derive(Parser, Clone, Default, Debug, Serialize, Deserialize)] +#[command(no_binary_name(true))] pub struct SmbiosType17Config { + #[arg(long, alias = "type", value_parser = ["17"])] + pub smbios_type: String, + #[arg(long)] pub manufacturer: Option, + #[arg(long)] pub serial: Option, + #[arg(long)] pub asset: Option, + #[arg(long, alias = "loc_pfx")] pub loc_pfx: Option, + #[arg(long)] pub part: Option, + #[arg(long, default_value = "0")] pub speed: u16, + #[arg(long)] pub bank: Option, + #[arg(long, default_value = "true")] pub added: bool, } @@ -124,13 +188,13 @@ pub struct Uuid { } impl FromStr for Uuid { - type Err = (); + type Err = anyhow::Error; fn from_str(str: &str) -> std::result::Result { let name = str.to_string(); if !check_valid_uuid(&name) { - return Err(()); + return Err(anyhow!("Invalid uuid {}", name)); } let mut uuid_bytes = Vec::new(); @@ -149,6 +213,11 @@ impl FromStr for Uuid { } } +fn get_uuid(s: &str) -> Result { + let uuid = Uuid::from_str(s)?; + Ok(uuid) +} + impl VmConfig { /// # Arguments /// @@ -158,19 +227,8 @@ impl VmConfig { bail!("smbios type0 has been added"); } - let mut cmd_parser = CmdParser::new("smbios"); - cmd_parser - .push("") - .push("type") - .push("vendor") - .push("version") - .push("date"); - cmd_parser.parse(type0)?; - - self.smbios.type0.vender = cmd_parser.get_value::("vendor")?; - self.smbios.type0.version = cmd_parser.get_value::("version")?; - self.smbios.type0.date = cmd_parser.get_value::("date")?; - self.smbios.type0.added = true; + let type0_cfg = SmbiosType0Config::try_parse_from(str_slip_to_clap(type0, false, false))?; + self.smbios.type0 = type0_cfg; Ok(()) } @@ -183,27 +241,8 @@ impl VmConfig { bail!("smbios type1 has been added"); } - let mut cmd_parser = CmdParser::new("smbios"); - cmd_parser - .push("") - .push("type") - .push("manufacturer") - .push("product") - .push("version") - .push("serial") - .push("sku") - .push("uuid") - .push("family"); - cmd_parser.parse(type1)?; - - self.smbios.type1.manufacturer = cmd_parser.get_value::("manufacturer")?; - self.smbios.type1.product = cmd_parser.get_value::("product")?; - self.smbios.type1.version = cmd_parser.get_value::("version")?; - self.smbios.type1.serial = cmd_parser.get_value::("serial")?; - self.smbios.type1.sku = cmd_parser.get_value::("sku")?; - self.smbios.type1.family = cmd_parser.get_value::("family")?; - self.smbios.type1.uuid = cmd_parser.get_value::("uuid")?; - self.smbios.type1.added = true; + let type1_cfg = SmbiosType1Config::try_parse_from(str_slip_to_clap(type1, false, false))?; + self.smbios.type1 = type1_cfg; Ok(()) } @@ -215,26 +254,8 @@ impl VmConfig { if self.smbios.type2.added { bail!("smbios type2 has been added"); } - - let mut cmd_parser = CmdParser::new("smbios"); - cmd_parser - .push("") - .push("type") - .push("manufacturer") - .push("product") - .push("version") - .push("serial") - .push("asset") - .push("location"); - cmd_parser.parse(type2)?; - - self.smbios.type2.manufacturer = cmd_parser.get_value::("manufacturer")?; - self.smbios.type2.product = cmd_parser.get_value::("product")?; - self.smbios.type2.version = cmd_parser.get_value::("version")?; - self.smbios.type2.serial = cmd_parser.get_value::("serial")?; - self.smbios.type2.asset = cmd_parser.get_value::("asset")?; - self.smbios.type2.location = cmd_parser.get_value::("location")?; - self.smbios.type2.added = true; + let type2_cfg = SmbiosType2Config::try_parse_from(str_slip_to_clap(type2, false, false))?; + self.smbios.type2 = type2_cfg; Ok(()) } @@ -247,23 +268,8 @@ impl VmConfig { bail!("smbios type3 has been added"); } - let mut cmd_parser = CmdParser::new("smbios"); - cmd_parser - .push("") - .push("type") - .push("manufacturer") - .push("version") - .push("serial") - .push("sku") - .push("asset"); - cmd_parser.parse(type3)?; - - self.smbios.type3.manufacturer = cmd_parser.get_value::("manufacturer")?; - self.smbios.type3.version = cmd_parser.get_value::("version")?; - self.smbios.type3.serial = cmd_parser.get_value::("serial")?; - self.smbios.type3.sku = cmd_parser.get_value::("sku")?; - self.smbios.type3.asset = cmd_parser.get_value::("asset")?; - self.smbios.type3.added = true; + let type3_cfg = SmbiosType3Config::try_parse_from(str_slip_to_clap(type3, false, false))?; + self.smbios.type3 = type3_cfg; Ok(()) } @@ -276,29 +282,8 @@ impl VmConfig { bail!("smbios type4 has been added"); } - let mut cmd_parser = CmdParser::new("smbios"); - cmd_parser - .push("") - .push("type") - .push("manufacturer") - .push("version") - .push("serial") - .push("sock_pfx") - .push("max-speed") - .push("current-speed") - .push("part") - .push("asset"); - cmd_parser.parse(type4)?; - - self.smbios.type4.manufacturer = cmd_parser.get_value::("manufacturer")?; - self.smbios.type4.version = cmd_parser.get_value::("version")?; - self.smbios.type4.serial = cmd_parser.get_value::("serial")?; - self.smbios.type4.asset = cmd_parser.get_value::("asset")?; - self.smbios.type4.part = cmd_parser.get_value::("part")?; - self.smbios.type4.sock_pfx = cmd_parser.get_value::("sock_pfx")?; - self.smbios.type4.max_speed = cmd_parser.get_value::("max-speed")?; - self.smbios.type4.current_speed = cmd_parser.get_value::("current-speed")?; - self.smbios.type4.added = true; + let type4_cfg = SmbiosType4Config::try_parse_from(str_slip_to_clap(type4, false, false))?; + self.smbios.type4 = type4_cfg; Ok(()) } @@ -311,31 +296,9 @@ impl VmConfig { bail!("smbios type17 has been added"); } - let mut cmd_parser = CmdParser::new("smbios"); - cmd_parser - .push("") - .push("type") - .push("loc_pfx") - .push("bank") - .push("manufacturer") - .push("serial") - .push("speed") - .push("part") - .push("asset"); - cmd_parser.parse(type17)?; - - self.smbios.type17.manufacturer = cmd_parser.get_value::("manufacturer")?; - self.smbios.type17.loc_pfx = cmd_parser.get_value::("loc_pfx")?; - self.smbios.type17.serial = cmd_parser.get_value::("serial")?; - self.smbios.type17.asset = cmd_parser.get_value::("asset")?; - self.smbios.type17.part = cmd_parser.get_value::("part")?; - self.smbios.type17.speed = if let Some(speed) = cmd_parser.get_value::("speed")? { - speed - } else { - 0 - }; - self.smbios.type17.bank = cmd_parser.get_value::("bank")?; - self.smbios.type17.added = true; + let type17_cfg = + SmbiosType17Config::try_parse_from(str_slip_to_clap(type17, false, false))?; + self.smbios.type17 = type17_cfg; Ok(()) } @@ -346,13 +309,7 @@ impl VmConfig { /// /// * `smbios_args` - The args of object. pub fn add_smbios(&mut self, smbios_args: &str) -> Result<()> { - let mut cmd_params = CmdParser::new("smbios"); - cmd_params.push("").push("type"); - - cmd_params.get_parameters(smbios_args)?; - let smbios_type = cmd_params - .get_value::("type")? - .with_context(|| "smbios type not specified")?; + let smbios_type = get_value_of_parameter("type", smbios_args)?; match smbios_type.as_str() { "0" => { self.add_smbios_type0(smbios_args)?; @@ -397,4 +354,24 @@ mod test { ] ); } + + #[test] + fn test_add_smbios() { + let mut vm_config = VmConfig::default(); + + let smbios0 = "type=0,vendor=fake,version=fake,date=fake"; + let smbios1 = "type=1,manufacturer=fake,version=fake,product=fake,serial=fake,uuid=33DB4D5E-1FF7-401C-9657-7441C03DD766,sku=fake,family=fake"; + let smbios2 = "type=2,manufacturer=fake,product=fake,version=fake,serial=fake,asset=fake,location=fake"; + let smbios3 = "type=3,manufacturer=fake,version=fake,serial=fake,asset=fake,sku=fake"; + let smbios4 = "type=4,sock_pfx=fake,manufacturer=fake,version=fake,serial=fake,asset=fake,part=fake,max-speed=1,current-speed=1"; + let smbios17 = "type=17,loc_pfx=fake,bank=fake,manufacturer=fake,serial=fake,asset=fake,part=fake,speed=1"; + + assert!(vm_config.add_smbios(smbios0).is_ok()); + assert!(vm_config.add_smbios(smbios1).is_ok()); + assert!(vm_config.add_smbios(smbios2).is_ok()); + assert!(vm_config.add_smbios(smbios3).is_ok()); + assert!(vm_config.add_smbios(smbios4).is_ok()); + assert!(vm_config.add_smbios(smbios17).is_ok()); + assert!(vm_config.add_smbios(smbios0).is_err()); + } } -- Gitee From fc0ce42ce670b6a263595de7c278f7df06ff5886 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Mon, 20 May 2024 11:25:11 +0800 Subject: [PATCH 103/489] machine: use clap to parse the parameters of the machine config Use clap to parse the parameters of the machine config Signed-off-by: liuxiangdong --- machine_manager/src/config/machine_config.rs | 96 ++++++++------------ 1 file changed, 40 insertions(+), 56 deletions(-) diff --git a/machine_manager/src/config/machine_config.rs b/machine_manager/src/config/machine_config.rs index ec60bc7c..2d675427 100644 --- a/machine_manager/src/config/machine_config.rs +++ b/machine_manager/src/config/machine_config.rs @@ -20,7 +20,7 @@ use super::error::ConfigError; use super::{ get_value_of_parameter, parse_bool, parse_size, str_slip_to_clap, valid_id, valid_path, }; -use crate::config::{CmdParser, ConfigCheck, ExBool, IntegerList, VmConfig, MAX_NODES}; +use crate::config::{CmdParser, ConfigCheck, IntegerList, VmConfig, MAX_NODES}; use crate::machine::HypervisorType; const DEFAULT_CPUS: u8 = 1; @@ -47,7 +47,7 @@ pub enum MachineType { } impl FromStr for MachineType { - type Err = (); + type Err = anyhow::Error; fn from_str(s: &str) -> std::result::Result { match s.to_lowercase().as_str() { @@ -57,7 +57,7 @@ impl FromStr for MachineType { "q35" => Ok(MachineType::StandardVm), #[cfg(target_arch = "aarch64")] "virt" => Ok(MachineType::StandardVm), - _ => Err(()), + _ => Err(anyhow!("Invalid machine type.")), } } } @@ -267,6 +267,27 @@ struct MemSizeConfig { size: u64, } +#[derive(Parser)] +#[command(no_binary_name(true))] +struct MachineCmdConfig { + #[arg(long, aliases = ["classtype", "type"])] + mach_type: MachineType, + #[arg(long, default_value = "on", action = ArgAction::Append, value_parser = parse_bool)] + dump_guest_core: bool, + #[arg(long, default_value = "off", action = ArgAction::Append, value_parser = parse_bool)] + mem_share: bool, + #[arg(long, default_value = "kvm")] + accel: HypervisorType, + // The "usb" member is added for compatibility with libvirt and is currently not in use. + // It only supports configuration as "off". Currently, a `String` type is used to verify incoming values. + // When it will be used, it needs to be changed to a `bool` type. + #[arg(long, default_value = "off", value_parser = ["off"])] + usb: String, + #[cfg(target_arch = "aarch64")] + #[arg(long, default_value = "3", value_parser = clap::value_parser!(u8).range(3..=3))] + gic_version: u8, +} + impl VmConfig { /// Add argument `name` to `VmConfig`. /// @@ -274,59 +295,21 @@ impl VmConfig { /// /// * `name` - The name `String` added to `VmConfig`. pub fn add_machine(&mut self, mach_config: &str) -> Result<()> { - let mut cmd_parser = CmdParser::new("machine"); - cmd_parser - .push("") - .push("type") - .push("accel") - .push("usb") - .push("dump-guest-core") - .push("mem-share"); - #[cfg(target_arch = "aarch64")] - cmd_parser.push("gic-version"); - cmd_parser.parse(mach_config)?; - - #[cfg(target_arch = "aarch64")] - if let Some(gic_version) = cmd_parser.get_value::("gic-version")? { - if gic_version != 3 { - bail!("Unsupported gic version, only gicv3 is supported"); - } - } - - if let Some(accel) = cmd_parser.get_value::("accel")? { - // Libvirt checks the parameter types of 'kvm', 'kvm:tcg' and 'tcg'. - if accel.ne("kvm:tcg") && accel.ne("tcg") && accel.ne("kvm") && accel.ne("test") { - bail!("Only \'kvm\', \'kvm:tcg\', \'test\' and \'tcg\' are supported for \'accel\' of \'machine\'"); - } - - match accel.as_str() { - "test" => self.machine_config.hypervisor = HypervisorType::Test, - _ => self.machine_config.hypervisor = HypervisorType::Kvm, - }; - } - if let Some(usb) = cmd_parser.get_value::("usb")? { - if usb.into() { - bail!("Argument \'usb\' should be set to \'off\'"); - } - } - if let Some(mach_type) = cmd_parser - .get_value::("") - .with_context(|| "Unrecognized machine type")? - { - self.machine_config.mach_type = mach_type; - } - if let Some(mach_type) = cmd_parser - .get_value::("type") - .with_context(|| "Unrecognized machine type")? - { - self.machine_config.mach_type = mach_type; - } - if let Some(dump_guest) = cmd_parser.get_value::("dump-guest-core")? { - self.machine_config.mem_config.dump_guest_core = dump_guest.into(); - } - if let Some(mem_share) = cmd_parser.get_value::("mem-share")? { - self.machine_config.mem_config.mem_share = mem_share.into(); + let mut has_type_label = false; + if get_value_of_parameter("type", mach_config).is_ok() { + has_type_label = true; } + let mach_cfg = MachineCmdConfig::try_parse_from(str_slip_to_clap( + mach_config, + !has_type_label, + false, + ))?; + // TODO: The current "accel" configuration in "-machine" command line and "-accel" command line are not foolproof. + // Later parsing will overwrite first parsing. We will optimize this in the future. + self.machine_config.hypervisor = mach_cfg.accel; + self.machine_config.mach_type = mach_cfg.mach_type; + self.machine_config.mem_config.dump_guest_core = mach_cfg.dump_guest_core; + self.machine_config.mem_config.mem_share = mach_cfg.mem_share; Ok(()) } @@ -900,11 +883,12 @@ mod tests { assert_eq!(machine_cfg.mem_config.mem_share, true); let mut vm_config = VmConfig::default(); - let memory_cfg_str = "type=none,dump-guest-core=off,mem-share=off,accel=kvm,usb=off"; + let memory_cfg_str = "none,dump-guest-core=off,mem-share=off,accel=kvm,usb=off"; let machine_cfg_ret = vm_config.add_machine(memory_cfg_str); assert!(machine_cfg_ret.is_ok()); let machine_cfg = vm_config.machine_config; assert_eq!(machine_cfg.mach_type, MachineType::None); + assert_eq!(machine_cfg.hypervisor, HypervisorType::Kvm); assert_eq!(machine_cfg.mem_config.dump_guest_core, false); assert_eq!(machine_cfg.mem_config.mem_share, false); -- Gitee From 87d99623779798b728e4be4b1c85359e7998d227 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Mon, 20 May 2024 12:19:17 +0800 Subject: [PATCH 104/489] display: use clap to parse the parameters of the display config Use clap to parse the parameters of the display config Signed-off-by: liuxiangdong --- machine/src/aarch64/standard.rs | 6 +- machine/src/x86_64/standard.rs | 2 +- machine_manager/src/config/display.rs | 115 ++++++++++---------------- ui/src/ohui_srv/mod.rs | 2 +- 4 files changed, 47 insertions(+), 78 deletions(-) diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index b803e741..12fe4086 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -361,7 +361,7 @@ impl StdMachine { #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] fn add_ohui_server(&mut self, vm_config: &VmConfig) -> Result<()> { if let Some(dpy) = vm_config.display.as_ref() { - if !dpy.ohui_config.ohui { + if dpy.display_type != "ohui" { return Ok(()); } self.ohui_server = Some(Arc::new(OhUiServer::new(dpy.get_ui_path())?)); @@ -722,7 +722,7 @@ impl MachineOps for StdMachine { #[cfg(any(feature = "gtk", all(target_env = "ohos", feature = "ohui_srv")))] match vm_config.display { #[cfg(feature = "gtk")] - Some(ref ds_cfg) if ds_cfg.gtk => { + Some(ref ds_cfg) if ds_cfg.display_type == "gtk" => { let ui_context = UiContext { vm_name: vm_config.guest_name.clone(), power_button: Some(self.power_button.clone()), @@ -735,7 +735,7 @@ impl MachineOps for StdMachine { } // OHUI server init. #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] - Some(ref ds_cfg) if ds_cfg.ohui_config.ohui => { + Some(ref ds_cfg) if ds_cfg.display_type == "ohui" => { ohui_init(self.ohui_server.as_ref().unwrap().clone(), ds_cfg) .with_context(|| "Failed to init OH UI server!")?; } diff --git a/machine/src/x86_64/standard.rs b/machine/src/x86_64/standard.rs index c6804809..0dc5da82 100644 --- a/machine/src/x86_64/standard.rs +++ b/machine/src/x86_64/standard.rs @@ -702,7 +702,7 @@ impl MachineOps for StdMachine { // GTK display init. #[cfg(feature = "gtk")] match vm_config.display { - Some(ref ds_cfg) if ds_cfg.gtk => { + Some(ref ds_cfg) if ds_cfg.display_type == "gtk" => { let ui_context = UiContext { vm_name: vm_config.guest_name.clone(), power_button: None, diff --git a/machine_manager/src/config/display.rs b/machine_manager/src/config/display.rs index 8f1f2e08..a8eca8c0 100644 --- a/machine_manager/src/config/display.rs +++ b/machine_manager/src/config/display.rs @@ -13,17 +13,15 @@ #[cfg(feature = "gtk")] use std::sync::Arc; +use anyhow::Result; #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] -use anyhow::Context; -use anyhow::{bail, Result}; +use anyhow::{bail, Context}; +use clap::{ArgAction, Parser}; use serde::{Deserialize, Serialize}; #[cfg(feature = "gtk")] use vmm_sys_util::eventfd::EventFd; -use crate::config::{CmdParser, ExBool, VmConfig}; - -#[cfg(all(target_env = "ohos", feature = "ohui_srv"))] -static DEFAULT_UI_PATH: &str = "/tmp/"; +use crate::config::{parse_bool, str_slip_to_clap, VmConfig}; /// Event fd related to power button in gtk. #[cfg(feature = "gtk")] @@ -41,88 +39,59 @@ pub struct UiContext { } #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] -#[derive(Debug, Clone, Default, Serialize, Deserialize)] -pub struct OhuiConfig { - /// Use OHUI. - pub ohui: bool, - /// Create the OHUI thread. - pub iothread: Option, - /// Confirm related files' path. - pub path: String, +fn get_sock_path(p: &str) -> Result { + let path = std::fs::canonicalize(p.clone()) + .with_context(|| format!("Failed to get real directory path: {:?}", p.clone()))?; + if !path.exists() { + bail!( + "The defined directory {:?} path doesn't exist", + path.as_os_str() + ); + } + if !path.is_dir() { + bail!( + "The defined socks-path {:?} is not directory", + path.as_os_str() + ); + } + + Ok(path.to_str().unwrap().to_string()) } /// GTK and OHUI related configuration. -#[derive(Debug, Clone, Default, Serialize, Deserialize)] +#[derive(Parser, Debug, Clone, Default, Serialize, Deserialize)] +#[command(no_binary_name(true))] + pub struct DisplayConfig { - /// Create the GTK thread. - pub gtk: bool, + #[arg(long, alias = "classtype", value_parser = ["gtk", "ohui"])] + pub display_type: String, /// App name if configured. + #[arg(long)] pub app_name: Option, /// Keep the window fill the desktop. + #[arg(long, default_value = "off", action = ArgAction::Append, value_parser = parse_bool)] pub full_screen: bool, - /// Used for OHUI + /// Create the OHUI thread. #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] - pub ohui_config: OhuiConfig, + #[arg(long)] + pub iothread: Option, + /// Confirm related files' path. Default ui path is "/tmp". + #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] + #[arg(long, alias = "socks-path", default_value = "/tmp/", value_parser = get_sock_path)] + pub path: String, } #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] impl DisplayConfig { pub fn get_ui_path(&self) -> String { - self.ohui_config.path.clone() + self.path.clone() } } impl VmConfig { pub fn add_display(&mut self, vm_config: &str) -> Result<()> { - let mut cmd_parser = CmdParser::new("display"); - cmd_parser.push("").push("full-screen").push("app-name"); - #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] - cmd_parser.push("iothread").push("socks-path"); - cmd_parser.parse(vm_config)?; - let mut display_config = DisplayConfig::default(); - if let Some(str) = cmd_parser.get_value::("")? { - match str.as_str() { - "gtk" => display_config.gtk = true, - #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] - "ohui" => display_config.ohui_config.ohui = true, - _ => bail!("Unsupported device: {}", str), - } - } - if let Some(name) = cmd_parser.get_value::("app-name")? { - display_config.app_name = Some(name); - } - if let Some(default) = cmd_parser.get_value::("full-screen")? { - display_config.full_screen = default.into(); - } - - #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] - if display_config.ohui_config.ohui { - if let Some(iothread) = cmd_parser.get_value::("iothread")? { - display_config.ohui_config.iothread = Some(iothread); - } - - if let Some(path) = cmd_parser.get_value::("socks-path")? { - let path = std::fs::canonicalize(path.clone()).with_context(|| { - format!("Failed to get real directory path: {:?}", path.clone()) - })?; - if !path.exists() { - bail!( - "The defined directory {:?} path doesn't exist", - path.as_os_str() - ); - } - if !path.is_dir() { - bail!( - "The defined socks-path {:?} is not directory", - path.as_os_str() - ); - } - display_config.ohui_config.path = path.to_str().unwrap().to_string(); - } else { - display_config.ohui_config.path = DEFAULT_UI_PATH.to_string(); - } - } - + let display_config = + DisplayConfig::try_parse_from(str_slip_to_clap(vm_config, true, false))?; self.display = Some(display_config); Ok(()) } @@ -141,28 +110,28 @@ mod tests { let config_line = "gtk"; assert!(vm_config.add_display(config_line).is_ok()); let display_config = vm_config.display.unwrap(); - assert_eq!(display_config.gtk, true); + assert_eq!(display_config.display_type, "gtk"); assert_eq!(display_config.full_screen, false); let mut vm_config = VmConfig::default(); let config_line = "gtk,full-screen=on"; assert!(vm_config.add_display(config_line).is_ok()); let display_config = vm_config.display.unwrap(); - assert_eq!(display_config.gtk, true); + assert_eq!(display_config.display_type, "gtk"); assert_eq!(display_config.full_screen, true); let mut vm_config = VmConfig::default(); let config_line = "gtk,full-screen=off"; assert!(vm_config.add_display(config_line).is_ok()); let display_config = vm_config.display.unwrap(); - assert_eq!(display_config.gtk, true); + assert_eq!(display_config.display_type, "gtk"); assert_eq!(display_config.full_screen, false); let mut vm_config = VmConfig::default(); let config_line = "gtk,app-name=desktopappengine"; assert!(vm_config.add_display(config_line).is_ok()); let display_config = vm_config.display.unwrap(); - assert_eq!(display_config.gtk, true); + assert_eq!(display_config.display_type, "gtk"); assert_eq!(display_config.full_screen, false); assert_eq!( display_config.app_name, diff --git a/ui/src/ohui_srv/mod.rs b/ui/src/ohui_srv/mod.rs index 8f72b132..1d25483a 100755 --- a/ui/src/ohui_srv/mod.rs +++ b/ui/src/ohui_srv/mod.rs @@ -373,7 +373,7 @@ impl DisplayChangeListenerOperations for OhUiServer { pub fn ohui_init(ohui_srv: Arc, cfg: &DisplayConfig) -> Result<()> { // set iothread - ohui_srv.set_iothread(cfg.ohui_config.iothread.clone()); + ohui_srv.set_iothread(cfg.iothread.clone()); // Register ohui interface let dcl = Arc::new(Mutex::new(DisplayChangeListener::new( None, -- Gitee From c76d3bed0957d06c9e67c7b838224d095d4db0c9 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Mon, 20 May 2024 14:05:33 +0800 Subject: [PATCH 105/489] smp: use clap to parse the parameters of the smp config Use clap to parse the parameters of the smp config Signed-off-by: liuxiangdong --- machine_manager/src/config/machine_config.rs | 239 ++++++++----------- 1 file changed, 93 insertions(+), 146 deletions(-) diff --git a/machine_manager/src/config/machine_config.rs b/machine_manager/src/config/machine_config.rs index 2d675427..2f9cf70e 100644 --- a/machine_manager/src/config/machine_config.rs +++ b/machine_manager/src/config/machine_config.rs @@ -20,7 +20,7 @@ use super::error::ConfigError; use super::{ get_value_of_parameter, parse_bool, parse_size, str_slip_to_clap, valid_id, valid_path, }; -use crate::config::{CmdParser, ConfigCheck, IntegerList, VmConfig, MAX_NODES}; +use crate::config::{ConfigCheck, IntegerList, VmConfig, MAX_NODES}; use crate::machine::HypervisorType; const DEFAULT_CPUS: u8 = 1; @@ -288,6 +288,84 @@ struct MachineCmdConfig { gic_version: u8, } +#[derive(Parser)] +#[command(no_binary_name(true))] +struct SmpConfig { + #[arg(long, alias = "classtype", value_parser = clap::value_parser!(u64).range(MIN_NR_CPUS..=MAX_NR_CPUS))] + cpus: u64, + #[arg(long, default_value = "0")] + maxcpus: u64, + #[arg(long, default_value = "0", value_parser = clap::value_parser!(u64).range(..u8::MAX as u64))] + sockets: u64, + #[arg(long, default_value = "1", value_parser = clap::value_parser!(u64).range(1..u8::MAX as u64))] + dies: u64, + #[arg(long, default_value = "1", value_parser = clap::value_parser!(u64).range(1..u8::MAX as u64))] + clusters: u64, + #[arg(long, default_value = "0", value_parser = clap::value_parser!(u64).range(..u8::MAX as u64))] + cores: u64, + #[arg(long, default_value = "0", value_parser = clap::value_parser!(u64).range(..u8::MAX as u64))] + threads: u64, +} + +impl SmpConfig { + fn auto_adjust_topology(&mut self) -> Result<()> { + let mut max_cpus = self.maxcpus; + let mut sockets = self.sockets; + let mut cores = self.cores; + let mut threads = self.threads; + + if max_cpus == 0 { + if sockets * self.dies * self.clusters * cores * threads > 0 { + max_cpus = sockets * self.dies * self.clusters * cores * threads; + } else { + max_cpus = self.cpus; + } + } + + if cores == 0 { + if sockets == 0 { + sockets = 1; + } + if threads == 0 { + threads = 1; + } + cores = max_cpus / (sockets * self.dies * self.clusters * threads); + } else if sockets == 0 { + if threads == 0 { + threads = 1; + } + sockets = max_cpus / (self.dies * self.clusters * cores * threads); + } + + if threads == 0 { + threads = max_cpus / (sockets * self.dies * self.clusters * cores); + } + + let min_max_cpus = std::cmp::max(self.cpus, MIN_NR_CPUS); + + if !(min_max_cpus..=MAX_NR_CPUS).contains(&max_cpus) { + return Err(anyhow!(ConfigError::IllegalValue( + "MAX CPU number".to_string(), + min_max_cpus, + true, + MAX_NR_CPUS, + true, + ))); + } + + if sockets * self.dies * self.clusters * cores * threads != max_cpus { + bail!("sockets * dies * clusters * cores * threads must be equal to max_cpus"); + } + + self.maxcpus = max_cpus; + self.sockets = sockets; + self.cores = cores; + self.threads = threads; + + Ok(()) + } +} + impl VmConfig { /// Add argument `name` to `VmConfig`. /// @@ -337,96 +415,21 @@ impl VmConfig { /// Add '-smp' cpu config to `VmConfig`. pub fn add_cpu(&mut self, cpu_config: &str) -> Result<()> { - let mut cmd_parser = CmdParser::new("smp"); - cmd_parser - .push("") - .push("maxcpus") - .push("sockets") - .push("dies") - .push("clusters") - .push("cores") - .push("threads") - .push("cpus"); - - cmd_parser.parse(cpu_config)?; - - let cpu = if let Some(cpu) = cmd_parser.get_value::("")? { - cpu - } else if let Some(cpu) = cmd_parser.get_value::("cpus")? { - if cpu == 0 { - return Err(anyhow!(ConfigError::IllegalValue( - "cpu".to_string(), - 1, - true, - MAX_NR_CPUS, - true - ))); - } - cpu - } else { - return Err(anyhow!(ConfigError::FieldIsMissing( - "cpus".to_string(), - "smp".to_string() - ))); - }; - - let sockets = smp_read_and_check(&cmd_parser, "sockets", 0)?; - - let dies = smp_read_and_check(&cmd_parser, "dies", 1)?; - - let clusters = smp_read_and_check(&cmd_parser, "clusters", 1)?; - - let cores = smp_read_and_check(&cmd_parser, "cores", 0)?; - - let threads = smp_read_and_check(&cmd_parser, "threads", 0)?; - - let max_cpus = cmd_parser.get_value::("maxcpus")?.unwrap_or_default(); - - let (max_cpus, sockets, cores, threads) = - adjust_topology(cpu, max_cpus, sockets, dies, clusters, cores, threads); - - // limit cpu count - if !(MIN_NR_CPUS..=MAX_NR_CPUS).contains(&cpu) { - return Err(anyhow!(ConfigError::IllegalValue( - "CPU number".to_string(), - MIN_NR_CPUS, - true, - MAX_NR_CPUS, - true, - ))); - } - - if !(MIN_NR_CPUS..=MAX_NR_CPUS).contains(&max_cpus) { - return Err(anyhow!(ConfigError::IllegalValue( - "MAX CPU number".to_string(), - MIN_NR_CPUS, - true, - MAX_NR_CPUS, - true, - ))); - } - - if max_cpus < cpu { - return Err(anyhow!(ConfigError::IllegalValue( - "maxcpus".to_string(), - cpu, - true, - MAX_NR_CPUS, - true, - ))); + let mut has_cpus_label = false; + if get_value_of_parameter("cpus", cpu_config).is_ok() { + has_cpus_label = true; } - - if sockets * dies * clusters * cores * threads != max_cpus { - bail!("sockets * dies * clusters * cores * threads must be equal to max_cpus"); - } - - self.machine_config.nr_cpus = cpu as u8; - self.machine_config.nr_threads = threads as u8; - self.machine_config.nr_cores = cores as u8; - self.machine_config.nr_dies = dies as u8; - self.machine_config.nr_clusters = clusters as u8; - self.machine_config.nr_sockets = sockets as u8; - self.machine_config.max_cpus = max_cpus as u8; + let mut smp_cfg = + SmpConfig::try_parse_from(str_slip_to_clap(cpu_config, !has_cpus_label, false))?; + smp_cfg.auto_adjust_topology()?; + + self.machine_config.nr_cpus = smp_cfg.cpus as u8; + self.machine_config.nr_threads = smp_cfg.threads as u8; + self.machine_config.nr_cores = smp_cfg.cores as u8; + self.machine_config.nr_dies = smp_cfg.dies as u8; + self.machine_config.nr_clusters = smp_cfg.clusters as u8; + self.machine_config.nr_sockets = smp_cfg.sockets as u8; + self.machine_config.max_cpus = smp_cfg.maxcpus as u8; Ok(()) } @@ -499,62 +502,6 @@ impl VmConfig { } } -fn smp_read_and_check(cmd_parser: &CmdParser, name: &str, default_val: u64) -> Result { - if let Some(values) = cmd_parser.get_value::(name)? { - if values == 0 { - return Err(anyhow!(ConfigError::IllegalValue( - name.to_string(), - 1, - true, - u8::MAX as u64, - false - ))); - } - Ok(values) - } else { - Ok(default_val) - } -} - -fn adjust_topology( - cpu: u64, - mut max_cpus: u64, - mut sockets: u64, - dies: u64, - clusters: u64, - mut cores: u64, - mut threads: u64, -) -> (u64, u64, u64, u64) { - if max_cpus == 0 { - if sockets * dies * clusters * cores * threads > 0 { - max_cpus = sockets * dies * clusters * cores * threads; - } else { - max_cpus = cpu; - } - } - - if cores == 0 { - if sockets == 0 { - sockets = 1; - } - if threads == 0 { - threads = 1; - } - cores = max_cpus / (sockets * dies * clusters * threads); - } else if sockets == 0 { - if threads == 0 { - threads = 1; - } - sockets = max_cpus / (dies * clusters * cores * threads); - } - - if threads == 0 { - threads = max_cpus / (sockets * dies * clusters * cores); - } - - (max_cpus, sockets, cores, threads) -} - /// Convert memory units from GiB, Mib to Byte. /// /// # Arguments -- Gitee From e6b605b4b092c1586436a27c24077cdf36229ccd Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Mon, 20 May 2024 14:08:09 +0800 Subject: [PATCH 106/489] machine_manager: delete CmdParser So far, we have replaced all `Cmdparser` with `clap` and `get_value_of_parameter` Delete useless `CmdPaser`. Signed-off-by: liuxiangdong --- devices/src/scsi/disk.rs | 2 +- machine_manager/src/config/mod.rs | 203 ------------------------------ machine_manager/src/config/pci.rs | 22 +--- 3 files changed, 2 insertions(+), 225 deletions(-) diff --git a/devices/src/scsi/disk.rs b/devices/src/scsi/disk.rs index 7edccdeb..37aca3da 100644 --- a/devices/src/scsi/disk.rs +++ b/devices/src/scsi/disk.rs @@ -221,7 +221,7 @@ impl ScsiDevice { } let drive_files = self.drive_files.lock().unwrap(); - // File path can not be empty string. And it has also been checked in CmdParser::parse. + // File path can not be empty string. And it has also been checked in command parsing by using `Clap`. let file = VmConfig::fetch_drive_file(&drive_files, &self.drive_cfg.path_on_host)?; let alignments = VmConfig::fetch_drive_align(&drive_files, &self.drive_cfg.path_on_host)?; diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index d88d4937..ca1281a6 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -415,121 +415,6 @@ pub trait ConfigCheck: AsAny + Send + Sync + std::fmt::Debug { fn check(&self) -> Result<()>; } -/// Struct `CmdParser` used to parse and check cmdline parameters to vm config. -pub struct CmdParser { - name: String, - params: HashMap>, -} - -impl CmdParser { - /// Allocates an empty `CmdParser`. - pub fn new(name: &str) -> Self { - CmdParser { - name: name.to_string(), - params: HashMap::>::new(), - } - } - - /// Push a new param field into `params`. - /// - /// # Arguments - /// - /// * `param_field`: The cmdline parameter field name. - pub fn push(&mut self, param_field: &str) -> &mut Self { - self.params.insert(param_field.to_string(), None); - - self - } - - /// Parse cmdline parameters string into `params`. - /// - /// # Arguments - /// - /// * `cmd_param`: The whole cmdline parameter string. - pub fn parse(&mut self, cmd_param: &str) -> Result<()> { - if cmd_param.starts_with(',') || cmd_param.ends_with(',') { - return Err(anyhow!(ConfigError::InvalidParam( - cmd_param.to_string(), - self.name.clone() - ))); - } - let param_items = cmd_param.split(',').collect::>(); - for (i, param_item) in param_items.iter().enumerate() { - if param_item.starts_with('=') || param_item.ends_with('=') { - return Err(anyhow!(ConfigError::InvalidParam( - param_item.to_string(), - self.name.clone() - ))); - } - let param = param_item.splitn(2, '=').collect::>(); - let (param_key, param_value) = match param.len() { - 1 => { - if i == 0 { - ("", param[0]) - } else { - (param[0], "") - } - } - 2 => (param[0], param[1]), - _ => { - return Err(anyhow!(ConfigError::InvalidParam( - param_item.to_string(), - self.name.clone() - ))); - } - }; - - if self.params.contains_key(param_key) { - let field_value = self.params.get_mut(param_key).unwrap(); - if field_value.is_none() { - *field_value = Some(String::from(param_value)); - } else { - return Err(anyhow!(ConfigError::FieldRepeat( - self.name.clone(), - param_key.to_string() - ))); - } - } else { - return Err(anyhow!(ConfigError::InvalidParam( - param[0].to_string(), - self.name.clone() - ))); - } - } - - Ok(()) - } - - /// Get cmdline parameters value from param field name. - /// - /// # Arguments - /// - /// * `param_field`: The cmdline parameter field name. - pub fn get_value(&self, param_field: &str) -> Result> { - match self.params.get(param_field) { - Some(value) => { - let field_msg = if param_field.is_empty() { - &self.name - } else { - param_field - }; - - if let Some(raw_value) = value { - Ok(Some(raw_value.parse().map_err(|_| { - anyhow!(ConfigError::ConvertValueFailed( - field_msg.to_string(), - raw_value.clone() - )) - })?)) - } else { - Ok(None) - } - } - None => Ok(None), - } - } -} - /// This struct is a wrapper for `bool`. /// More switch string can be transferred to this structure. pub struct ExBool { @@ -860,94 +745,6 @@ pub fn parse_size(s: &str) -> Result { mod tests { use super::*; - #[test] - fn test_cmd_parser() { - let mut cmd_parser = CmdParser::new("test"); - cmd_parser - .push("") - .push("id") - .push("path") - .push("num") - .push("test1") - .push("test2") - .push("test3") - .push("test4") - .push("test5") - .push("test6") - .push("test7"); - assert!(cmd_parser - .parse("socket,id=charconsole0,path=/tmp/console.sock,num=1,test1=true,test2=on,test3=yes,test4=false,test5=off,test6=no,test7=random") - .is_ok()); - assert_eq!( - cmd_parser.get_value::("").unwrap().unwrap(), - "socket".to_string() - ); - assert_eq!( - cmd_parser.get_value::("id").unwrap().unwrap(), - "charconsole0".to_string() - ); - assert_eq!( - cmd_parser.get_value::("path").unwrap().unwrap(), - "/tmp/console.sock".to_string() - ); - assert_eq!(cmd_parser.get_value::("num").unwrap().unwrap(), 1_u64); - assert_eq!(cmd_parser.get_value::("num").unwrap().unwrap(), 1_u32); - assert_eq!(cmd_parser.get_value::("num").unwrap().unwrap(), 1_u16); - assert_eq!(cmd_parser.get_value::("num").unwrap().unwrap(), 1_u8); - assert_eq!(cmd_parser.get_value::("num").unwrap().unwrap(), 1_i64); - assert_eq!(cmd_parser.get_value::("num").unwrap().unwrap(), 1_i32); - assert_eq!(cmd_parser.get_value::("num").unwrap().unwrap(), 1_i16); - assert_eq!(cmd_parser.get_value::("num").unwrap().unwrap(), 1_i8); - assert!(cmd_parser.get_value::("test1").unwrap().unwrap()); - assert!( - cmd_parser - .get_value::("test1") - .unwrap() - .unwrap() - .inner - ); - assert!( - cmd_parser - .get_value::("test2") - .unwrap() - .unwrap() - .inner - ); - assert!( - cmd_parser - .get_value::("test3") - .unwrap() - .unwrap() - .inner - ); - assert!(!cmd_parser.get_value::("test4").unwrap().unwrap()); - assert!( - !cmd_parser - .get_value::("test4") - .unwrap() - .unwrap() - .inner - ); - assert!( - !cmd_parser - .get_value::("test5") - .unwrap() - .unwrap() - .inner - ); - assert!( - !cmd_parser - .get_value::("test6") - .unwrap() - .unwrap() - .inner - ); - assert!(cmd_parser.get_value::("test7").is_err()); - assert!(cmd_parser.get_value::("test7").is_err()); - assert!(cmd_parser.get_value::("random").unwrap().is_none()); - assert!(cmd_parser.parse("random=false").is_err()); - } - #[test] fn test_add_trace() { assert!(add_trace("fil=test_trace").is_err()); diff --git a/machine_manager/src/config/pci.rs b/machine_manager/src/config/pci.rs index 4f054e90..6642f4f6 100644 --- a/machine_manager/src/config/pci.rs +++ b/machine_manager/src/config/pci.rs @@ -13,8 +13,7 @@ use anyhow::{bail, Context, Result}; use serde::{Deserialize, Serialize}; -use super::{get_value_of_parameter, CmdParser}; -use crate::config::ExBool; +use super::get_value_of_parameter; use util::num_ops::str_to_num; /// Basic information of pci devices such as bus number, @@ -82,25 +81,6 @@ pub fn get_pci_bdf(pci_cfg: &str) -> Result { Ok(pci_bdf) } -pub fn pci_args_check(cmd_parser: &CmdParser) -> Result<()> { - let device_type = cmd_parser.get_value::("")?; - let dev_type = device_type.unwrap(); - // Safe, because this function only be called when certain - // devices type are added. - if dev_type.ends_with("-device") { - if cmd_parser.get_value::("bus")?.is_some() { - bail!("virtio mmio device does not support bus arguments"); - } - if cmd_parser.get_value::("addr")?.is_some() { - bail!("virtio mmio device does not support addr arguments"); - } - if cmd_parser.get_value::("multifunction")?.is_some() { - bail!("virtio mmio device does not support multifunction arguments"); - } - } - Ok(()) -} - #[cfg(test)] mod tests { use super::*; -- Gitee From 51df6992ec5837d36c80259956f502ecde74dee0 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Wed, 22 May 2024 00:11:10 +0800 Subject: [PATCH 107/489] usb: adjust log content "Error" words can easily cause misunderstandings among the caller. Adjust the print information content for `handle_control_for_descriptor`. Signed-off-by: liuxiangdong --- devices/src/usb/camera.rs | 2 +- devices/src/usb/keyboard.rs | 5 ++++- devices/src/usb/storage.rs | 2 +- devices/src/usb/tablet.rs | 2 +- devices/src/usb/uas.rs | 4 ++-- 5 files changed, 9 insertions(+), 6 deletions(-) diff --git a/devices/src/usb/camera.rs b/devices/src/usb/camera.rs index 710a7110..79cc1ba5 100644 --- a/devices/src/usb/camera.rs +++ b/devices/src/usb/camera.rs @@ -810,7 +810,7 @@ impl UsbDevice for UsbCamera { } } Err(e) => { - warn!("Camera descriptor error {:?}", e); + warn!("Received incorrect USB Camera descriptor message: {:?}", e); locked_packet.status = UsbPacketStatus::Stall; return; } diff --git a/devices/src/usb/keyboard.rs b/devices/src/usb/keyboard.rs index 71685603..53291427 100644 --- a/devices/src/usb/keyboard.rs +++ b/devices/src/usb/keyboard.rs @@ -241,7 +241,10 @@ impl UsbDevice for UsbKeyboard { } } Err(e) => { - warn!("Keyboard descriptor error {:?}", e); + warn!( + "Received incorrect USB Keyboard descriptor message: {:?}", + e + ); locked_packet.status = UsbPacketStatus::Stall; return; } diff --git a/devices/src/usb/storage.rs b/devices/src/usb/storage.rs index 2f9d4c96..2f924d8a 100644 --- a/devices/src/usb/storage.rs +++ b/devices/src/usb/storage.rs @@ -595,7 +595,7 @@ impl UsbDevice for UsbStorage { self.handle_control_packet(&mut locked_packet, device_req) } Err(e) => { - warn!("Storage descriptor error {:?}", e); + warn!("Received incorrect USB Storage descriptor message: {:?}", e); locked_packet.status = UsbPacketStatus::Stall; } } diff --git a/devices/src/usb/tablet.rs b/devices/src/usb/tablet.rs index fffb4df4..a4bfebf4 100644 --- a/devices/src/usb/tablet.rs +++ b/devices/src/usb/tablet.rs @@ -284,7 +284,7 @@ impl UsbDevice for UsbTablet { } } Err(e) => { - warn!("Tablet descriptor error {:?}", e); + warn!("Received incorrect USB Tablet descriptor message: {:?}", e); locked_packet.status = UsbPacketStatus::Stall; return; } diff --git a/devices/src/usb/uas.rs b/devices/src/usb/uas.rs index 9ba134cd..4bdfc398 100644 --- a/devices/src/usb/uas.rs +++ b/devices/src/usb/uas.rs @@ -1108,8 +1108,8 @@ impl UsbDevice for UsbUas { locked_packet.status = UsbPacketStatus::Stall; } Err(err) => { - error!( - "UAS {} device descriptor error {:?}.", + warn!( + "{} received incorrect UAS descriptor message: {:?}", self.device_id(), err ); -- Gitee From a84906c74454acc8c308e0d0cd5f1614ab64479c Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Wed, 22 May 2024 12:23:24 +0800 Subject: [PATCH 108/489] virtio-mmio: use `realize_virtio_mmio_device` to create virtiommio device Replace the `VirtioMmioDevice::realize` with the existing function `realize_virtio_mmio_device`. Signed-off-by: liuxiangdong --- machine/src/micro_common/mod.rs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/machine/src/micro_common/mod.rs b/machine/src/micro_common/mod.rs index 49cd1534..d4db45b0 100644 --- a/machine/src/micro_common/mod.rs +++ b/machine/src/micro_common/mod.rs @@ -190,8 +190,6 @@ impl LightMachine { ); } - let mut region_base = self.base.sysbus.min_free_base; - let region_size = MEM_LAYOUT[LayoutEntryType::Mmio as usize].1; for (id, dev) in rpl_devs.into_iter().enumerate() { self.replaceable_info .devices @@ -205,20 +203,11 @@ impl LightMachine { MigrationManager::register_transport_instance( VirtioMmioState::descriptor(), - VirtioMmioDevice::realize( - dev, - &mut self.base.sysbus, - region_base, - MEM_LAYOUT[LayoutEntryType::Mmio as usize].1, - #[cfg(target_arch = "x86_64")] - &self.base.boot_source, - ) - .with_context(|| MachineError::RlzVirtioMmioErr)?, + self.realize_virtio_mmio_device(dev)?, &id.to_string(), ); - region_base += region_size; } - self.base.sysbus.min_free_base = region_base; + Ok(()) } -- Gitee From cc8ae27f7b7dcccbe8fdcd8d2a4e1bada256d5eb Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Wed, 5 Jun 2024 20:13:41 +0800 Subject: [PATCH 109/489] ohui: solve lock race between send and recv data While sending or receiving data, both of logic route should hold channel lock. This has side effect on the performance. This patch solves this issue of lock race. Signed-off-by: Zhao Yi Min --- ui/src/ohui_srv/channel.rs | 91 +++++++++++--------------- ui/src/ohui_srv/mod.rs | 5 +- ui/src/ohui_srv/msg_handle.rs | 119 +++++++++++++++++++++------------- 3 files changed, 114 insertions(+), 101 deletions(-) diff --git a/ui/src/ohui_srv/channel.rs b/ui/src/ohui_srv/channel.rs index cfa86d47..64d6e0ac 100755 --- a/ui/src/ohui_srv/channel.rs +++ b/ui/src/ohui_srv/channel.rs @@ -10,7 +10,7 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use std::io::{Read, Write}; +use std::io::{ErrorKind, Read, Write}; use std::os::fd::AsRawFd; use std::os::unix::io::RawFd; @@ -22,9 +22,8 @@ use util::socket::{SocketListener, SocketStream}; use util::unix::limit_permission; pub struct OhUiChannel { - pub path: String, - pub listener: SocketListener, - pub stream: Option, + listener: SocketListener, + stream: Option, } impl OhUiChannel { @@ -41,7 +40,6 @@ impl OhUiChannel { }); Ok(OhUiChannel { - path: String::from(path), listener, stream: None, }) @@ -60,63 +58,50 @@ impl OhUiChannel { Ok(()) } - pub fn send_by_obj(&mut self, obj: &T) -> Result<()> { - let stream = self.get_stream()?; - let slice = obj.as_bytes(); - let mut left = slice.len(); - let mut count = 0_usize; - - while left > 0 { - let buf = &slice[count..]; - match stream.write(buf) { - Ok(n) => { - left -= n; - count += n; - } - Err(e) => { - if std::io::Error::last_os_error().raw_os_error().unwrap() == libc::EAGAIN { - continue; - } - bail!(e); - } - } - } - Ok(()) + pub fn disconnect(&mut self) { + self.stream = None; } +} - pub fn recv_slice(&mut self, data: &mut [u8]) -> Result { - let stream = self.get_stream()?; - let len = data.len(); - if len == 0 { - return Ok(0); - } - let ret = stream.read(data); - match ret { - Ok(n) => Ok(n), +pub fn recv_slice(stream: &mut dyn Read, data: &mut [u8]) -> Result { + let len = data.len(); + let mut ret = 0; + + while ret < len { + match stream.read(&mut data[ret..len]) { + Ok(0) => break, + Ok(n) => ret += n, Err(e) => { - if std::io::Error::last_os_error() - .raw_os_error() - .unwrap_or(libc::EIO) - != libc::EAGAIN - { - bail!("recv_slice(): error occurred: {:?}", e); + let ek = e.kind(); + if ek != ErrorKind::WouldBlock && ek != ErrorKind::Interrupted { + bail!("recv_slice: error occurred: {:?}", e); } - Ok(0) + break; } } } + Ok(ret) +} - pub fn disconnect(&mut self) { - if self.stream.is_some() { - self.stream = None; - } - } +pub fn send_obj(stream: &mut dyn Write, obj: &T) -> Result<()> { + let slice = obj.as_bytes(); + let mut left = slice.len(); + let mut count = 0_usize; - fn get_stream(&mut self) -> Result<&mut SocketStream> { - if self.stream.is_some() { - Ok(self.stream.as_mut().unwrap()) - } else { - bail!("No connection established") + while left > 0 { + match stream.write(&slice[count..]) { + Ok(n) => { + left -= n; + count += n; + } + Err(e) => { + let ek = e.kind(); + if ek == ErrorKind::WouldBlock || ek == ErrorKind::Interrupted { + continue; + } + bail!(e); + } } } + Ok(()) } diff --git a/ui/src/ohui_srv/mod.rs b/ui/src/ohui_srv/mod.rs index 1d25483a..899d2634 100755 --- a/ui/src/ohui_srv/mod.rs +++ b/ui/src/ohui_srv/mod.rs @@ -180,8 +180,8 @@ impl OhUiServer { Ok(OhUiServer { passthru: OnceCell::new(), surface: RwLock::new(GuestSurface::new()), - channel: channel.clone(), - msg_handler: Arc::new(OhUiMsgHandler::new(channel)), + channel, + msg_handler: Arc::new(OhUiMsgHandler::new()), connected: AtomicBool::new(false), iothread: OnceCell::new(), cursorbuffer, @@ -266,6 +266,7 @@ impl OhUiServer { fn set_connect(&self, conn: bool) { self.connected.store(conn, Ordering::Relaxed); if conn { + self.msg_handler.update_sock(self.channel.clone()); register_led_sync(self.msg_handler.clone()); } else { unregister_led_sync(); diff --git a/ui/src/ohui_srv/msg_handle.rs b/ui/src/ohui_srv/msg_handle.rs index cc0d679e..dffd0914 100755 --- a/ui/src/ohui_srv/msg_handle.rs +++ b/ui/src/ohui_srv/msg_handle.rs @@ -11,13 +11,18 @@ // See the Mulan PSL v2 for more details. use std::collections::HashMap; +use std::os::fd::{FromRawFd, RawFd}; +use std::os::unix::net::UnixStream; use std::sync::{Arc, Mutex, RwLock}; -use anyhow::{anyhow, bail, Result}; +use anyhow::{anyhow, bail, Context, Result}; use log::error; use util::byte_code::ByteCode; -use super::{channel::OhUiChannel, msg::*}; +use super::{ + channel::{recv_slice, send_obj, OhUiChannel}, + msg::*, +}; use crate::{ console::{get_active_console, graphic_hardware_ui_info}, input::{ @@ -120,34 +125,46 @@ impl WindowState { } } +#[derive(Default)] pub struct OhUiMsgHandler { state: Mutex, hmcode2svcode: HashMap, - reader: Mutex, - writer: MsgWriter, + reader: Mutex>, + writer: Mutex>, } impl SyncLedstate for OhUiMsgHandler { fn sync_to_host(&self, state: u8) { - let body = LedstateEvent::new(state as u32); - if let Err(e) = self.writer.send_message(EventType::Ledstate, &body) { - error!("sync_to_host: failed to send message with error {e}"); + if let Some(writer) = self.writer.lock().unwrap().as_mut() { + let body = LedstateEvent::new(state as u32); + if let Err(e) = writer.send_message(EventType::Ledstate, &body) { + error!("sync_to_host: failed to send message with error {e}"); + } } } } impl OhUiMsgHandler { - pub fn new(channel: Arc>) -> Self { + pub fn new() -> Self { OhUiMsgHandler { state: Mutex::new(WindowState::default()), hmcode2svcode: KeyCode::keysym_to_qkeycode(DpyMod::Ohui), - reader: Mutex::new(MsgReader::new(channel.clone())), - writer: MsgWriter::new(channel), + reader: Mutex::new(None), + writer: Mutex::new(None), } } + pub fn update_sock(&self, channel: Arc>) { + let fd = channel.lock().unwrap().get_stream_raw_fd().unwrap(); + *self.reader.lock().unwrap() = Some(MsgReader::new(fd)); + *self.writer.lock().unwrap() = Some(MsgWriter::new(fd)); + } + pub fn handle_msg(&self, token_id: Arc>) -> Result<()> { - let mut reader = self.reader.lock().unwrap(); + let mut locked_reader = self.reader.lock().unwrap(); + let reader = locked_reader + .as_mut() + .with_context(|| "handle_msg: no connection established")?; if !reader.recv()? { return Ok(()); } @@ -251,9 +268,11 @@ impl OhUiMsgHandler { hot_y: u32, size_per_pixel: u32, ) { - let body = HWCursorEvent::new(w, h, hot_x, hot_y, size_per_pixel); - if let Err(e) = self.writer.send_message(EventType::CursorDefine, &body) { - error!("handle_cursor_define: failed to send message with error {e}"); + if let Some(writer) = self.writer.lock().unwrap().as_mut() { + let body = HWCursorEvent::new(w, h, hot_x, hot_y, size_per_pixel); + if let Err(e) = writer.send_message(EventType::CursorDefine, &body) { + error!("handle_cursor_define: failed to send message with error {e}"); + } } } @@ -321,45 +340,52 @@ impl OhUiMsgHandler { pub fn send_windowinfo(&self, w: u32, h: u32) { self.state.lock().unwrap().update_window_info(w, h); - let body = WindowInfoEvent::new(w, h); - if let Err(e) = self.writer.send_message(EventType::WindowInfo, &body) { - error!("send_windowinfo: failed to send message with error {e}"); + if let Some(writer) = self.writer.lock().unwrap().as_mut() { + let body = WindowInfoEvent::new(w, h); + if let Err(e) = writer.send_message(EventType::WindowInfo, &body) { + error!("send_windowinfo: failed to send message with error {e}"); + } } } pub fn handle_dirty_area(&self, x: u32, y: u32, w: u32, h: u32) { - let body = FrameBufferDirtyEvent::new(x, y, w, h); - if let Err(e) = self.writer.send_message(EventType::FrameBufferDirty, &body) { - error!("handle_dirty_area: failed to send message with error {e}"); + if let Some(writer) = self.writer.lock().unwrap().as_mut() { + let body = FrameBufferDirtyEvent::new(x, y, w, h); + if let Err(e) = writer.send_message(EventType::FrameBufferDirty, &body) { + error!("handle_dirty_area: failed to send message with error {e}"); + } } } pub fn reset(&self) { - self.reader.lock().unwrap().clear(); + *self.reader.lock().unwrap() = None; + *self.writer.lock().unwrap() = None; } } struct MsgReader { - /// socket to read - channel: Arc>, /// cache for header - pub header: EventMsgHdr, + header: EventMsgHdr, /// received byte size of header - pub header_ready: usize, + header_ready: usize, /// cache of body - pub body: Option>, + body: Option>, /// received byte size of body - pub body_ready: usize, + body_ready: usize, + /// UnixStream to read + sock: UnixStream, } impl MsgReader { - pub fn new(channel: Arc>) -> Self { + pub fn new(fd: RawFd) -> Self { MsgReader { - channel, header: EventMsgHdr::default(), header_ready: 0, body: None, body_ready: 0, + // SAFETY: The fd is valid only when the new connection has been established + // and MsgReader instance would be destroyed when disconnected. + sock: unsafe { UnixStream::from_raw_fd(fd) }, } } @@ -382,11 +408,7 @@ impl MsgReader { } let buf = self.header.as_mut_bytes(); - self.header_ready += self - .channel - .lock() - .unwrap() - .recv_slice(&mut buf[self.header_ready..])?; + self.header_ready += recv_slice(&mut self.sock, &mut buf[self.header_ready..])?; Ok(self.header_ready == EVENT_MSG_HDR_SIZE as usize) } @@ -408,27 +430,32 @@ impl MsgReader { unsafe { buf.set_len(body_size); } - self.body_ready += self - .channel - .lock() - .unwrap() - .recv_slice(&mut buf[self.body_ready..])?; + self.body_ready += recv_slice(&mut self.sock, &mut buf[self.body_ready..])?; Ok(self.body_ready == body_size) } } -struct MsgWriter(Arc>); +struct MsgWriter { + sock: UnixStream, +} impl MsgWriter { - fn new(channel: Arc>) -> Self { - MsgWriter(channel) + fn new(fd: RawFd) -> Self { + Self { + // SAFETY: The fd is valid only when the new connection has been established + // and MsgWriter instance would be destroyed when disconnected. + sock: unsafe { UnixStream::from_raw_fd(fd) }, + } } - fn send_message(&self, t: EventType, body: &T) -> Result<()> { - let mut channel = self.0.lock().unwrap(); + fn send_message( + &mut self, + t: EventType, + body: &T, + ) -> Result<()> { let hdr = EventMsgHdr::new(t); - channel.send_by_obj(&hdr)?; - channel.send_by_obj(body) + send_obj(&mut self.sock, &hdr)?; + send_obj(&mut self.sock, body) } } -- Gitee From 66ba438a9e4783a6e4b47c9c4ddb21f9c1886418 Mon Sep 17 00:00:00 2001 From: "limingwang (A)" Date: Thu, 6 Jun 2024 11:52:02 +0800 Subject: [PATCH 110/489] bugfix: enable shutdown vm again After the shutdown fails, perform the shutdown again. Signed-off-by: Mingwang Li --- machine/src/aarch64/standard.rs | 5 +++-- machine/src/standard_common/mod.rs | 2 +- machine/src/x86_64/standard.rs | 5 +++-- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index 12fe4086..4b6eebdf 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -258,7 +258,7 @@ impl StdMachine { Ok(()) } - pub fn handle_destroy_request(vm: &Arc>) -> Result<()> { + pub fn handle_destroy_request(vm: &Arc>) -> bool { let locked_vm = vm.lock().unwrap(); let vmstate = { let state = locked_vm.base.vm_state.deref().0.lock().unwrap(); @@ -270,12 +270,13 @@ impl StdMachine { if locked_vm.shutdown_req.write(1).is_err() { error!("Failed to send shutdown request.") } + return false; } EventLoop::kick_all(); info!("vm destroy"); - Ok(()) + true } fn build_pptt_cores(&self, pptt: &mut AcpiTable, cluster_offset: u32, uid: &mut u32) { diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index 02780b8e..f18350ae 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -343,7 +343,7 @@ pub(crate) trait StdMachineOps: AcpiBuilder + MachineOps { let shutdown_req_fd = shutdown_req.as_raw_fd(); let shutdown_req_handler: Rc = Rc::new(move |_, _| { let _ret = shutdown_req.read(); - if StdMachine::handle_destroy_request(&clone_vm).is_ok() { + if StdMachine::handle_destroy_request(&clone_vm) { Some(gen_delete_notifiers(&[shutdown_req_fd])) } else { None diff --git a/machine/src/x86_64/standard.rs b/machine/src/x86_64/standard.rs index 0dc5da82..8dca2db7 100644 --- a/machine/src/x86_64/standard.rs +++ b/machine/src/x86_64/standard.rs @@ -210,7 +210,7 @@ impl StdMachine { Ok(()) } - pub fn handle_destroy_request(vm: &Arc>) -> Result<()> { + pub fn handle_destroy_request(vm: &Arc>) -> bool { let locked_vm = vm.lock().unwrap(); let vmstate = { let state = locked_vm.base.vm_state.deref().0.lock().unwrap(); @@ -222,12 +222,13 @@ impl StdMachine { if locked_vm.shutdown_req.write(1).is_err() { error!("Failed to send shutdown request.") } + return false; } EventLoop::kick_all(); info!("vm destroy"); - Ok(()) + true } fn init_ich9_lpc(&self, vm: Arc>) -> Result<()> { -- Gitee From 3451c70d430f72228b835dd9628b968a0cce2ce3 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Wed, 22 May 2024 11:08:08 +0800 Subject: [PATCH 111/489] virtio-mmio: add function `add_virtio_mmio_device` Add function `add_virtio_mmio_device` to add a new virtio mmio device. This function includes two steps: `new` and `realize`. This is the pre-patch for the next Realize unified patch. No functional changes. Signed-off-by: liuxiangdong --- machine/src/aarch64/micro.rs | 9 +++-- machine/src/lib.rs | 37 ++++++++---------- machine/src/micro_common/mod.rs | 67 +++++++++++++++++---------------- machine/src/x86_64/micro.rs | 9 +++-- 4 files changed, 61 insertions(+), 61 deletions(-) diff --git a/machine/src/aarch64/micro.rs b/machine/src/aarch64/micro.rs index d7e1b1d4..40c8baff 100644 --- a/machine/src/aarch64/micro.rs +++ b/machine/src/aarch64/micro.rs @@ -26,7 +26,7 @@ use util::{ device_tree::{self, CompileFDT, FdtBuilder}, seccomp::{BpfRule, SeccompCmpOpt}, }; -use virtio::VirtioMmioDevice; +use virtio::{VirtioDevice, VirtioMmioDevice}; #[repr(usize)] pub enum LayoutEntryType { @@ -218,11 +218,12 @@ impl MachineOps for LightMachine { self.add_virtio_mmio_block(vm_config, cfg_args) } - fn realize_virtio_mmio_device( + fn add_virtio_mmio_device( &mut self, - dev: VirtioMmioDevice, + name: String, + device: Arc>, ) -> Result>> { - self.realize_virtio_mmio_device(dev) + self.add_virtio_mmio_device(name, device) } fn syscall_whitelist(&self) -> Vec { diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 1ae93787..c1f10314 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -586,11 +586,12 @@ pub trait MachineOps { ("addr", device_cfg.addr), ("multifunction", device_cfg.multifunction) ); - let device = VirtioMmioDevice::new(&sys_mem, device_cfg.id.clone(), vsock.clone()); + let device = self + .add_virtio_mmio_device(device_cfg.id.clone(), vsock.clone()) + .with_context(|| MachineError::RlzVirtioMmioErr)?; MigrationManager::register_device_instance( VirtioMmioState::descriptor(), - self.realize_virtio_mmio_device(device) - .with_context(|| MachineError::RlzVirtioMmioErr)?, + device, &device_cfg.id, ); } @@ -612,9 +613,10 @@ pub trait MachineOps { Ok(()) } - fn realize_virtio_mmio_device( + fn add_virtio_mmio_device( &mut self, - _dev: VirtioMmioDevice, + _name: String, + _device: Arc>, ) -> Result>> { bail!("Virtio mmio devices not supported"); } @@ -688,8 +690,7 @@ pub trait MachineOps { ("addr", config.addr), ("multifunction", config.multifunction) ); - let device = VirtioMmioDevice::new(sys_mem, config.id.clone(), balloon); - self.realize_virtio_mmio_device(device)?; + self.add_virtio_mmio_device(config.id.clone(), balloon)?; } _ => { check_arg_exist!(("bus", config.bus), ("addr", config.addr)); @@ -716,7 +717,6 @@ pub trait MachineOps { let mut serial_cfg = VirtioSerialInfo::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; serial_cfg.auto_max_ports(); - let sys_mem = self.get_sys_mem().clone(); let serial = Arc::new(Mutex::new(Serial::new(serial_cfg.clone()))); match serial_cfg.classtype.as_str() { @@ -726,11 +726,12 @@ pub trait MachineOps { ("addr", serial_cfg.addr), ("multifunction", serial_cfg.multifunction) ); - let device = VirtioMmioDevice::new(&sys_mem, serial_cfg.id.clone(), serial.clone()); + let device = self + .add_virtio_mmio_device(serial_cfg.id.clone(), serial.clone()) + .with_context(|| MachineError::RlzVirtioMmioErr)?; MigrationManager::register_device_instance( VirtioMmioState::descriptor(), - self.realize_virtio_mmio_device(device) - .with_context(|| MachineError::RlzVirtioMmioErr)?, + device, &serial_cfg.id, ); } @@ -852,7 +853,6 @@ pub trait MachineOps { .rng_object .remove(&rng_cfg.rng) .with_context(|| "Object for rng-random device not found")?; - let sys_mem = self.get_sys_mem(); let rng_dev = Arc::new(Mutex::new(Rng::new(rng_cfg.clone(), rngobj_cfg))); match rng_cfg.classtype.as_str() { @@ -862,8 +862,7 @@ pub trait MachineOps { ("addr", rng_cfg.addr), ("multifunction", rng_cfg.multifunction) ); - let device = VirtioMmioDevice::new(sys_mem, rng_cfg.id.clone(), rng_dev.clone()); - self.realize_virtio_mmio_device(device) + self.add_virtio_mmio_device(rng_cfg.id.clone(), rng_dev.clone()) .with_context(|| "Failed to add virtio mmio rng device")?; } _ => { @@ -905,7 +904,7 @@ pub trait MachineOps { let device = Arc::new(Mutex::new(vhost::user::Fs::new( dev_cfg.clone(), char_dev, - sys_mem.clone(), + sys_mem, ))); match dev_cfg.classtype.as_str() { "vhost-user-fs-device" => { @@ -914,9 +913,7 @@ pub trait MachineOps { ("addr", dev_cfg.addr), ("multifunction", dev_cfg.multifunction) ); - let virtio_mmio_device = - VirtioMmioDevice::new(&sys_mem, dev_cfg.id.clone(), device); - self.realize_virtio_mmio_device(virtio_mmio_device) + self.add_virtio_mmio_device(dev_cfg.id.clone(), device) .with_context(|| "Failed to add vhost user fs device")?; } _ => { @@ -1381,9 +1378,7 @@ pub trait MachineOps { chardev_cfg, self.get_sys_mem(), ))); - let virtio_mmio_device = - VirtioMmioDevice::new(self.get_sys_mem(), device_cfg.id.clone(), device); - self.realize_virtio_mmio_device(virtio_mmio_device) + self.add_virtio_mmio_device(device_cfg.id.clone(), device) .with_context(|| "Failed to add vhost user block device")?; Ok(()) } diff --git a/machine/src/micro_common/mod.rs b/machine/src/micro_common/mod.rs index d4db45b0..8aee4003 100644 --- a/machine/src/micro_common/mod.rs +++ b/machine/src/micro_common/mod.rs @@ -157,54 +157,54 @@ impl LightMachine { } pub(crate) fn create_replaceable_devices(&mut self) -> Result<()> { - let mut rpl_devs: Vec = Vec::new(); for id in 0..MMIO_REPLACEABLE_BLK_NR { let block = Arc::new(Mutex::new(Block::new( VirtioBlkDevConfig::default(), DriveConfig::default(), self.get_drive_files(), ))); - let virtio_mmio = - VirtioMmioDevice::new(&self.base.sys_mem, id.to_string(), block.clone()); - rpl_devs.push(virtio_mmio); - MigrationManager::register_device_instance( BlockState::descriptor(), - block, + block.clone(), + &id.to_string(), + ); + + let blk_mmio = self.add_virtio_mmio_device(id.to_string(), block.clone())?; + let info = MmioReplaceableDevInfo { + device: block, + id: id.to_string(), + used: false, + }; + self.replaceable_info.devices.lock().unwrap().push(info); + MigrationManager::register_transport_instance( + VirtioMmioState::descriptor(), + blk_mmio, &id.to_string(), ); } for id in 0..MMIO_REPLACEABLE_NET_NR { + let total_id = id + MMIO_REPLACEABLE_BLK_NR; let net = Arc::new(Mutex::new(Net::new( NetworkInterfaceConfig::default(), NetDevcfg::default(), ))); - let virtio_mmio = - VirtioMmioDevice::new(&self.base.sys_mem, id.to_string(), net.clone()); - rpl_devs.push(virtio_mmio); - MigrationManager::register_device_instance( VirtioNetState::descriptor(), - net, - &id.to_string(), + net.clone(), + &total_id.to_string(), ); - } - - for (id, dev) in rpl_devs.into_iter().enumerate() { - self.replaceable_info - .devices - .lock() - .unwrap() - .push(MmioReplaceableDevInfo { - device: dev.device.clone(), - id: id.to_string(), - used: false, - }); + let net_mmio = self.add_virtio_mmio_device(total_id.to_string(), net.clone())?; + let info = MmioReplaceableDevInfo { + device: net, + id: total_id.to_string(), + used: false, + }; + self.replaceable_info.devices.lock().unwrap().push(info); MigrationManager::register_transport_instance( VirtioMmioState::descriptor(), - self.realize_virtio_mmio_device(dev)?, - &id.to_string(), + net_mmio, + &total_id.to_string(), ); } @@ -400,13 +400,13 @@ impl LightMachine { .remove(&net_cfg.netdev) .with_context(|| format!("Netdev: {:?} not found for net device", &net_cfg.netdev))?; if netdev_cfg.vhost_type().is_some() { - let device = if netdev_cfg.vhost_type().unwrap() == "vhost-kernel" { + if netdev_cfg.vhost_type().unwrap() == "vhost-kernel" { let net = Arc::new(Mutex::new(VhostKern::Net::new( &net_cfg, netdev_cfg, &self.base.sys_mem, ))); - VirtioMmioDevice::new(&self.base.sys_mem, net_cfg.id.clone(), net) + self.add_virtio_mmio_device(net_cfg.id.clone(), net)?; } else { let chardev = netdev_cfg.chardev.clone().with_context(|| { format!("Chardev not configured for netdev {:?}", netdev_cfg.id) @@ -422,9 +422,8 @@ impl LightMachine { sock_path, &self.base.sys_mem, ))); - VirtioMmioDevice::new(&self.base.sys_mem, net_cfg.id.clone(), net) + self.add_virtio_mmio_device(net_cfg.id.clone(), net)?; }; - self.realize_virtio_mmio_device(device)?; } else { let index = MMIO_REPLACEABLE_BLK_NR + self.replaceable_info.net_count; if index >= MMIO_REPLACEABLE_BLK_NR + MMIO_REPLACEABLE_NET_NR { @@ -471,10 +470,14 @@ impl LightMachine { Ok(()) } - pub(crate) fn realize_virtio_mmio_device( + pub(crate) fn add_virtio_mmio_device( &mut self, - dev: VirtioMmioDevice, + name: String, + device: Arc>, ) -> Result>> { + let sys_mem = self.get_sys_mem().clone(); + let dev = VirtioMmioDevice::new(&sys_mem, name, device); + let region_base = self.base.sysbus.min_free_base; let region_size = MEM_LAYOUT[LayoutEntryType::Mmio as usize].1; let realized_virtio_mmio_device = VirtioMmioDevice::realize( diff --git a/machine/src/x86_64/micro.rs b/machine/src/x86_64/micro.rs index d8fb92e6..e5d17ce5 100644 --- a/machine/src/x86_64/micro.rs +++ b/machine/src/x86_64/micro.rs @@ -25,7 +25,7 @@ use hypervisor::kvm::*; use machine_manager::config::{SerialConfig, VmConfig}; use migration::{MigrationManager, MigrationStatus}; use util::seccomp::{BpfRule, SeccompCmpOpt}; -use virtio::VirtioMmioDevice; +use virtio::{VirtioDevice, VirtioMmioDevice}; #[repr(usize)] pub enum LayoutEntryType { @@ -204,11 +204,12 @@ impl MachineOps for LightMachine { self.add_virtio_mmio_block(vm_config, cfg_args) } - fn realize_virtio_mmio_device( + fn add_virtio_mmio_device( &mut self, - dev: VirtioMmioDevice, + name: String, + device: Arc>, ) -> Result>> { - self.realize_virtio_mmio_device(dev) + self.add_virtio_mmio_device(name, device) } fn syscall_whitelist(&self) -> Vec { -- Gitee From ae2928f29fdec5f9cb39991ed9f99c04eaea5aa9 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Mon, 3 Jun 2024 21:18:30 +0800 Subject: [PATCH 112/489] util/socket: add set_nonblocking interface to fixup main-loop hang issue Accepted stream is blocking mode although listening stream has been set nonblocked. This might block char device write. Then main-loop would be also blocked. So let's introduce an interface to set nonblocking and set accepted fd with nonblocking mode by default. Signed-off-by: Zhao Yi Min --- util/src/socket.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/util/src/socket.rs b/util/src/socket.rs index 3b1290bb..573b7f44 100644 --- a/util/src/socket.rs +++ b/util/src/socket.rs @@ -41,6 +41,13 @@ impl SocketStream { } => link_description.clone(), } } + + pub fn set_nonblocking(&mut self, nonblocking: bool) -> IoResult<()> { + match self { + SocketStream::Tcp { stream, .. } => stream.set_nonblocking(nonblocking), + SocketStream::Unix { stream, .. } => stream.set_nonblocking(nonblocking), + } + } } impl AsRawFd for SocketStream { @@ -132,6 +139,7 @@ impl SocketListener { match self { SocketListener::Tcp { listener, address } => { let (stream, sock_addr) = listener.accept()?; + stream.set_nonblocking(true)?; let peer_address = sock_addr.to_string(); let link_description = format!( "{{ protocol: tcp, address: {}, peer: {} }}", @@ -144,6 +152,7 @@ impl SocketListener { } SocketListener::Unix { listener, address } => { let (stream, _) = listener.accept()?; + stream.set_nonblocking(true)?; let link_description = format!("{{ protocol: unix, address: {} }}", address); Ok(SocketStream::Unix { link_description, -- Gitee From 0287a6133cc463ddd3297f821c29c6dcc6a8a8ef Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Tue, 4 Jun 2024 20:30:58 +0800 Subject: [PATCH 113/489] chardev: introduce out buffer queue This patch introduces an out buffer queue to temporarily save the data to be written out. The out stream fd would be registerred to main loop if the buffer queue is not empty. When all the data has been consumed, remove the handler for OUT event from main loop. Signed-off-by: Zhao Yi Min --- chardev_backend/src/chardev.rs | 135 +++++++++++++++++++++++++++++++-- 1 file changed, 127 insertions(+), 8 deletions(-) diff --git a/chardev_backend/src/chardev.rs b/chardev_backend/src/chardev.rs index cf4bb712..7bf53e20 100644 --- a/chardev_backend/src/chardev.rs +++ b/chardev_backend/src/chardev.rs @@ -10,8 +10,9 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. +use std::collections::VecDeque; use std::fs::{read_link, File, OpenOptions}; -use std::io::{Stdin, Stdout}; +use std::io::{ErrorKind, Stdin, Stdout}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::path::PathBuf; use std::rc::Rc; @@ -41,6 +42,8 @@ use util::set_termi_raw_mode; use util::socket::{SocketListener, SocketStream}; use util::unix::limit_permission; +const BUF_QUEUE_SIZE: usize = 128; + /// Provide the trait that helps handle the input data. pub trait InputReceiver: Send { /// Handle the input data and trigger interrupt if necessary. @@ -91,6 +94,8 @@ pub struct Chardev { output_blocked: Option>, /// output listener to notify when output stream fd can be written output_listener_fd: Option>, + /// output buffer queue + outbuf: VecDeque>, } impl Chardev { @@ -108,6 +113,7 @@ impl Chardev { unpause_timer: None, output_blocked: None, output_listener_fd: None, + outbuf: VecDeque::with_capacity(BUF_QUEUE_SIZE), } } @@ -255,6 +261,58 @@ impl Chardev { } } + fn clear_outbuf(&mut self) { + self.outbuf.clear(); + } + + pub fn outbuf_is_full(&self) -> bool { + self.outbuf.len() == self.outbuf.capacity() + } + + pub fn fill_outbuf(&mut self, buf: Vec, listener_fd: Option>) -> Result<()> { + match self.backend { + ChardevType::File { .. } | ChardevType::Pty { .. } | ChardevType::Stdio { .. } => { + if self.output.is_none() { + bail!("chardev has no output"); + } + return file_write_direct(self.output.as_ref().unwrap().clone(), buf); + } + ChardevType::Socket { .. } => (), + } + + if self.output.is_none() { + return Ok(()); + } + + if self.outbuf_is_full() { + bail!("Failed to append buffer because output buffer queue is full"); + } + self.outbuf.push_back(buf); + self.output_listener_fd = listener_fd; + + let event_notifier = EventNotifier::new( + NotifierOperation::AddEvents, + self.stream_fd.unwrap(), + None, + EventSet::OUT, + Vec::new(), + ); + EventLoop::update_event(vec![event_notifier], None)?; + Ok(()) + } + + fn consume_outbuf(&mut self) -> Result<()> { + let cloned_output = self.output.as_ref().unwrap().clone(); + while !self.outbuf.is_empty() { + if write_buffer_out(cloned_output.clone(), self.outbuf.front_mut().unwrap())? { + break; + } + self.outbuf.pop_front(); + } + cloned_output.lock().unwrap().flush()?; + Ok(()) + } + pub fn add_listen_for_tx( &mut self, listener_fd: Arc, @@ -283,6 +341,50 @@ impl Chardev { } } +fn file_write_direct(writer: Arc>, buf: Vec) -> Result<()> { + let len = buf.len(); + let mut written = 0; + let mut locked_writer = writer.lock().unwrap(); + + while written < len { + match locked_writer.write(&buf[written..len]) { + Ok(n) => written += n, + Err(e) => bail!("chardev failed to write file with error {:?}", e), + } + } + Ok(()) +} + +// If write is blocked, return true. Otherwise return false. +fn write_buffer_out( + writer: Arc>, + buf: &mut Vec, +) -> Result { + let len = buf.len(); + let mut locked_writer = writer.lock().unwrap(); + let mut written = 0; + + while written < len { + match locked_writer.write(&buf[written..len]) { + Ok(0) => break, + Ok(n) => written += n, + Err(e) => { + let err_type = e.kind(); + if err_type != ErrorKind::WouldBlock && err_type != ErrorKind::Interrupted { + bail!("chardev failed to write data with error {:?}", e); + } + break; + } + } + } + + if written == len { + return Ok(false); + } + buf.drain(0..written); + Ok(true) +} + fn set_pty_raw_mode() -> Result<(i32, PathBuf)> { let (master, slave) = match openpty(None, None) { Ok(res) => (res.master, res.slave), @@ -513,6 +615,18 @@ fn get_socket_notifier(chardev: Arc>) -> Option { } let mut locked_cdev = handling_chardev.lock().unwrap(); + if let Err(e) = locked_cdev.consume_outbuf() { + error!("Failed to consume outbuf with error {:?}", e); + locked_cdev.clear_outbuf(); + return Some(vec![EventNotifier::new( + NotifierOperation::DeleteEvents, + fd, + None, + EventSet::OUT, + Vec::new(), + )]); + } + if locked_cdev.output_blocked.is_some() && locked_cdev.output_listener_fd.is_some() { let fd = locked_cdev.output_listener_fd.as_ref().unwrap(); if let Err(e) = fd.write(1) { @@ -527,13 +641,18 @@ fn get_socket_notifier(chardev: Arc>) -> Option { locked_cdev.output_blocked = None; locked_cdev.output_listener_fd = None; } - Some(vec![EventNotifier::new( - NotifierOperation::DeleteEvents, - fd, - None, - EventSet::OUT, - Vec::new(), - )]) + + if locked_cdev.outbuf.is_empty() { + Some(vec![EventNotifier::new( + NotifierOperation::DeleteEvents, + fd, + None, + EventSet::OUT, + Vec::new(), + )]) + } else { + None + } }); Some(vec![EventNotifier::new( -- Gitee From 1d43b643856d413ca3b31b1bbdddb4162cdbd32b Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Tue, 4 Jun 2024 20:53:13 +0800 Subject: [PATCH 114/489] virtio-serial: fit output handler to chardev outbuf Let's fit the output handler of virtio-serial to the new mechanism of chardev output buffer and clean up the code. Signed-off-by: Zhao Yi Min --- chardev_backend/src/chardev.rs | 39 +----------- virtio/src/device/serial.rs | 110 ++++++--------------------------- 2 files changed, 21 insertions(+), 128 deletions(-) diff --git a/chardev_backend/src/chardev.rs b/chardev_backend/src/chardev.rs index 7bf53e20..a1c158d5 100644 --- a/chardev_backend/src/chardev.rs +++ b/chardev_backend/src/chardev.rs @@ -16,7 +16,6 @@ use std::io::{ErrorKind, Stdin, Stdout}; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::path::PathBuf; use std::rc::Rc; -use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::{Arc, Mutex}; use std::time::Duration; @@ -90,8 +89,6 @@ pub struct Chardev { /// Scheduled DPC to unpause input stream. /// Unpause must be done inside event-loop unpause_timer: Option, - /// output stream fd is blocked - output_blocked: Option>, /// output listener to notify when output stream fd can be written output_listener_fd: Option>, /// output buffer queue @@ -111,7 +108,6 @@ impl Chardev { dev: None, wait_port: false, unpause_timer: None, - output_blocked: None, output_listener_fd: None, outbuf: VecDeque::with_capacity(BUF_QUEUE_SIZE), } @@ -312,33 +308,6 @@ impl Chardev { cloned_output.lock().unwrap().flush()?; Ok(()) } - - pub fn add_listen_for_tx( - &mut self, - listener_fd: Arc, - blocked: Arc, - ) -> Result<()> { - let event_notifier = EventNotifier::new( - NotifierOperation::AddEvents, - self.stream_fd.unwrap(), - None, - EventSet::OUT, - Vec::new(), - ); - - match EventLoop::update_event(vec![event_notifier], None) { - Ok(()) => { - self.output_blocked = Some(blocked.clone()); - self.output_listener_fd = Some(listener_fd); - blocked.store(true, Ordering::Release); - Ok(()) - } - Err(e) => { - blocked.store(false, Ordering::Release); - Err(e) - } - } - } } fn file_write_direct(writer: Arc>, buf: Vec) -> Result<()> { @@ -627,18 +596,12 @@ fn get_socket_notifier(chardev: Arc>) -> Option { )]); } - if locked_cdev.output_blocked.is_some() && locked_cdev.output_listener_fd.is_some() { + if locked_cdev.output_listener_fd.is_some() { let fd = locked_cdev.output_listener_fd.as_ref().unwrap(); if let Err(e) = fd.write(1) { error!("Failed to write eventfd with error {:?}", e); return None; } - locked_cdev - .output_blocked - .as_ref() - .unwrap() - .store(false, Ordering::Release); - locked_cdev.output_blocked = None; locked_cdev.output_listener_fd = None; } diff --git a/virtio/src/device/serial.rs b/virtio/src/device/serial.rs index 7d4b11ea..102a3ed6 100644 --- a/virtio/src/device/serial.rs +++ b/virtio/src/device/serial.rs @@ -277,10 +277,6 @@ impl VirtioDevice for Serial { device_broken: self.base.broken.clone(), port: port.clone(), nr, - outbuf: Vec::with_capacity(BUF_SIZE), - outbuf_consumed: 0, - outbuf_len: 0, - output_blocked: Arc::new(AtomicBool::new(false)), }; let handler_h = Arc::new(Mutex::new(handler)); let notifiers = EventNotifierHelper::internal_notifiers(handler_h.clone()); @@ -423,10 +419,6 @@ struct SerialPortHandler { device_broken: Arc, port: Option>>, nr: u32, - outbuf: Vec, - outbuf_consumed: usize, - outbuf_len: usize, - output_blocked: Arc, } /// Handler for queues which are used for control. @@ -465,24 +457,17 @@ impl SerialPortHandler { } fn output_handle_internal(&mut self) -> Result<()> { - // If fd for tx is blocked, copy data to output buffer and wait for POLL_OUT event. - if self.output_blocked.load(Ordering::Acquire) { - return Ok(()); - } + let mut queue_lock = self.output_queue.lock().unwrap(); - match self.consume_outbuf() { - Ok(blocked) => { - if blocked { - return Ok(()); + loop { + if let Some(port) = self.port.as_ref() { + let locked_port = port.lock().unwrap(); + let locked_cdev = locked_port.chardev.lock().unwrap(); + if locked_cdev.outbuf_is_full() { + break; } } - Err(e) => bail!("Failed to consume out buffer with error {:?}", e), - } - let queue = self.output_queue.clone(); - let mut queue_lock = queue.lock().unwrap(); - let mut blocked = false; - while !blocked { let elem = queue_lock .vring .pop_avail(&self.mem_space, self.driver_features)?; @@ -490,26 +475,24 @@ impl SerialPortHandler { break; } - assert_eq!(self.outbuf_len, 0); - // Discard requests when there is no port using this queue. Popping elements without // processing means discarding the request. - if self.port.is_some() { + if let Some(port) = self.port.as_ref() { let iovec = elem.out_iovec; let iovec_size = Element::iovec_size(&iovec); - if iovec_size as usize > self.outbuf.len() { - self.outbuf.resize(iovec_size as usize, 0); - } + let mut buf = vec![0u8; iovec_size as usize]; + let size = iov_to_buf(&self.mem_space, &iovec, &mut buf[..])? as u64; - let buffer = &mut self.outbuf[..]; - let size = iov_to_buf(&self.mem_space, &iovec, buffer)? as u64; - - assert_eq!(size, iovec_size); - self.outbuf_len = size as usize; - - match self.consume_outbuf() { - Ok(b) => blocked = b, - Err(e) => bail!("Failed to consume out buffer with error {:?}", e), + let locked_port = port.lock().unwrap(); + if locked_port.host_connected { + if let Err(e) = locked_port + .chardev + .lock() + .unwrap() + .fill_outbuf(buf, Some(self.output_queue_evt.clone())) + { + error!("Failed to append elem buffer to chardev with error {:?}", e); + } } trace::virtio_serial_output_data(iovec_size, size); } @@ -542,59 +525,6 @@ impl SerialPortHandler { Ok(()) } - fn clear_outbuf(&mut self) { - self.outbuf_len = 0; - self.outbuf_consumed = 0; - } - - fn consume_outbuf(&mut self) -> Result { - if self.outbuf_len == 0 { - return Ok(false); - } - - let port_cloned = self.port.clone(); - let port_locked = port_cloned.as_ref().unwrap().lock().unwrap(); - // Discard output buffer if this port's chardev is not connected. - if !port_locked.host_connected { - self.clear_outbuf(); - return Ok(false); - } - - let mut locked_chardev = port_locked.chardev.lock().unwrap(); - if locked_chardev.output.is_none() { - error!("Port {} failed to get output interface", self.nr); - self.clear_outbuf(); - return Ok(false); - } - let output = locked_chardev.output.clone(); - let mut locked_output = output.as_ref().unwrap().lock().unwrap(); - - while self.outbuf_consumed < self.outbuf_len { - match locked_output.write(&self.outbuf[self.outbuf_consumed..self.outbuf_len]) { - Ok(size) => self.outbuf_consumed += size, - Err(e) => { - let err_type = e.kind(); - if err_type != std::io::ErrorKind::WouldBlock - && err_type != std::io::ErrorKind::Interrupted - { - self.clear_outbuf(); - bail!("chardev failed to write message with error {:?}", e); - } - if let Err(e) = locked_chardev.add_listen_for_tx( - self.output_queue_evt.clone(), - self.output_blocked.clone(), - ) { - error!("failed to wait for tx fd with error {:?}", e); - continue; - } - return Ok(true); - } - } - } - self.clear_outbuf(); - Ok(false) - } - fn get_input_avail_bytes(&mut self, max_size: usize) -> usize { let port = self.port.as_ref(); if port.is_none() || !port.unwrap().lock().unwrap().guest_connected { -- Gitee From b25a11ec71c25db448a2ef1b61dd2c785b5aacc9 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Tue, 4 Jun 2024 21:01:05 +0800 Subject: [PATCH 115/489] legacy-serial: use new chardev output mechanism Let's fit legacy-serial to the new chardev output mechanism. Signed-off-by: Zhao Yi Min --- devices/src/legacy/serial.rs | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/devices/src/legacy/serial.rs b/devices/src/legacy/serial.rs index 80415e07..192de908 100644 --- a/devices/src/legacy/serial.rs +++ b/devices/src/legacy/serial.rs @@ -296,19 +296,10 @@ impl Serial { self.rbr.push_back(data); self.state.lsr |= UART_LSR_DR; - } else { - let output = self.chardev.lock().unwrap().output.clone(); - if output.is_none() { - self.update_iir(); - bail!("serial: failed to get output fd."); - } - let mut locked_output = output.as_ref().unwrap().lock().unwrap(); - locked_output - .write_all(&[data]) - .with_context(|| "serial: failed to write.")?; - locked_output - .flush() - .with_context(|| "serial: failed to flush.")?; + } else if let Err(e) = + self.chardev.lock().unwrap().fill_outbuf(vec![data], None) + { + bail!("Failed to append data to output buffer of chardev, {:?}", e); } self.update_iir(); -- Gitee From 26feb521187b3e383d84cc175cc36408b80f8e58 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Tue, 4 Jun 2024 21:08:52 +0800 Subject: [PATCH 116/489] pl011: use new chardev output mechanism Let's fit pl011 to the new output mechanism of chardev. Signed-off-by: Zhao Yi Min --- devices/src/legacy/pl011.rs | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/devices/src/legacy/pl011.rs b/devices/src/legacy/pl011.rs index fe76da2d..b2ff1ca1 100644 --- a/devices/src/legacy/pl011.rs +++ b/devices/src/legacy/pl011.rs @@ -13,7 +13,7 @@ use std::sync::{Arc, Mutex}; use anyhow::{Context, Result}; -use log::{debug, error}; +use log::error; use super::error::LegacyError; use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType, SysRes}; @@ -352,20 +352,10 @@ impl SysBusDevOps for PL011 { match offset >> 2 { 0 => { let ch = value as u8; - - if let Some(output) = &mut self.chardev.lock().unwrap().output { - let mut locked_output = output.lock().unwrap(); - if let Err(e) = locked_output.write_all(&[ch]) { - debug!("Failed to write to pl011 output fd, error is {:?}", e); - } - if let Err(e) = locked_output.flush() { - debug!("Failed to flush pl011, error is {:?}", e); - } - } else { - debug!("Failed to get output fd"); + if let Err(e) = self.chardev.lock().unwrap().fill_outbuf(vec![ch], None) { + error!("Failed to append pl011 data to outbuf of chardev, {:?}", e); return false; } - self.state.int_level |= INT_TX; self.interrupt(); } -- Gitee From 5d563bb171f792914056b80300d7d41508b5185b Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Fri, 7 Jun 2024 15:25:44 +0800 Subject: [PATCH 117/489] chardev: flush data after write out Current code only writes data without flushing. So this will make peer cannot get data immediately. So flush data after write. Signed-off-by: Zhao Yi Min --- chardev_backend/src/chardev.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/chardev_backend/src/chardev.rs b/chardev_backend/src/chardev.rs index a1c158d5..1b24d090 100644 --- a/chardev_backend/src/chardev.rs +++ b/chardev_backend/src/chardev.rs @@ -305,7 +305,6 @@ impl Chardev { } self.outbuf.pop_front(); } - cloned_output.lock().unwrap().flush()?; Ok(()) } } @@ -321,6 +320,9 @@ fn file_write_direct(writer: Arc>, buf: Vec bail!("chardev failed to write file with error {:?}", e), } } + locked_writer + .flush() + .with_context(|| "chardev failed to flush")?; Ok(()) } @@ -346,6 +348,9 @@ fn write_buffer_out( } } } + locked_writer + .flush() + .with_context(|| "chardev failed to flush")?; if written == len { return Ok(false); -- Gitee From 0d28ffce2ff4d7b9751e208d4a4a1d967933ba86 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Fri, 7 Jun 2024 15:50:41 +0800 Subject: [PATCH 118/489] chardev: optimize the code of writing out Use sync/async as suffix of the function name to be better readable. And also remove extra clone operation. Signed-off-by: Zhao Yi Min --- chardev_backend/src/chardev.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/chardev_backend/src/chardev.rs b/chardev_backend/src/chardev.rs index 1b24d090..bd2b37db 100644 --- a/chardev_backend/src/chardev.rs +++ b/chardev_backend/src/chardev.rs @@ -271,7 +271,7 @@ impl Chardev { if self.output.is_none() { bail!("chardev has no output"); } - return file_write_direct(self.output.as_ref().unwrap().clone(), buf); + return write_buffer_sync(self.output.as_ref().unwrap().clone(), buf); } ChardevType::Socket { .. } => (), } @@ -298,9 +298,9 @@ impl Chardev { } fn consume_outbuf(&mut self) -> Result<()> { - let cloned_output = self.output.as_ref().unwrap().clone(); + let output = self.output.as_ref().unwrap(); while !self.outbuf.is_empty() { - if write_buffer_out(cloned_output.clone(), self.outbuf.front_mut().unwrap())? { + if write_buffer_async(output.clone(), self.outbuf.front_mut().unwrap())? { break; } self.outbuf.pop_front(); @@ -309,7 +309,7 @@ impl Chardev { } } -fn file_write_direct(writer: Arc>, buf: Vec) -> Result<()> { +fn write_buffer_sync(writer: Arc>, buf: Vec) -> Result<()> { let len = buf.len(); let mut written = 0; let mut locked_writer = writer.lock().unwrap(); @@ -327,7 +327,7 @@ fn file_write_direct(writer: Arc>, buf: Vec>, buf: &mut Vec, ) -> Result { -- Gitee From e234591069733e9942fc3777fa869e03525309ff Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Wed, 22 May 2024 09:01:06 +0800 Subject: [PATCH 119/489] sysbus: don't pass in mem region information when `attach_device` Sysbusdev has got its mem region information when `set_sys_resource`, so we needn't to pass it again. Remove these useless function parameters in function `attach_device`. And, we can assume that this device does not have its own memory layout when region_base/region_size are both 0 such as `Ramfb`. Thus, we can remove useless `get_sys_resource_mut`. For these dynamic devices, use `attach_device` to replace `attach_dynamic_device`. Signed-off-by: liuxiangdong --- devices/src/acpi/cpu_controller.rs | 12 +-- devices/src/acpi/ged.rs | 10 +-- devices/src/acpi/power.rs | 10 +-- devices/src/legacy/fwcfg.rs | 43 +++------ devices/src/legacy/pflash.rs | 15 ++-- devices/src/legacy/pl011.rs | 10 +-- devices/src/legacy/pl031.rs | 10 +-- devices/src/legacy/ramfb.rs | 2 +- devices/src/legacy/rtc.rs | 10 +-- devices/src/legacy/serial.rs | 10 +-- devices/src/sysbus/mod.rs | 131 ++++++++++++++-------------- virtio/src/transport/virtio_mmio.rs | 10 +-- 12 files changed, 109 insertions(+), 164 deletions(-) diff --git a/devices/src/acpi/cpu_controller.rs b/devices/src/acpi/cpu_controller.rs index 1259e8d2..4fe256c6 100644 --- a/devices/src/acpi/cpu_controller.rs +++ b/devices/src/acpi/cpu_controller.rs @@ -19,7 +19,7 @@ use anyhow::{bail, Context, Result}; use log::{error, info}; use vmm_sys_util::eventfd::EventFd; -use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysRes}; +use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps}; use crate::{Device, DeviceBase}; use acpi::{ AcpiError, AcpiLocalApic, AmlAcquire, AmlAddressSpaceType, AmlArg, AmlBuffer, AmlBuilder, @@ -99,11 +99,11 @@ impl CpuController { self.max_cpus = max_cpus; self.cpu_config = Some(cpu_config); self.hotplug_cpu_req = Some(hotplug_cpu_req); - self.set_sys_resource(sysbus, region_base, region_size) + self.set_sys_resource(sysbus, region_base, region_size, "CPUController") .with_context(|| AcpiError::Alignment(region_size.try_into().unwrap()))?; let dev = Arc::new(Mutex::new(self)); let ret_dev = dev.clone(); - sysbus.attach_device(&dev, region_base, region_size, "CPUController")?; + sysbus.attach_device(&dev)?; Ok(ret_dev) } @@ -329,15 +329,11 @@ impl SysBusDevOps for CpuController { } true } - - fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> { - Some(&mut self.base.res) - } } impl AmlBuilder for CpuController { fn aml_bytes(&self) -> Vec { - let res = self.base.res; + let res = self.base.res.clone(); let mut cpu_hotplug_controller = AmlDevice::new("PRES"); cpu_hotplug_controller.append_child(AmlNameDecl::new("_HID", AmlEisaId::new("PNP0A06"))); cpu_hotplug_controller.append_child(AmlNameDecl::new( diff --git a/devices/src/acpi/ged.rs b/devices/src/acpi/ged.rs index 300868ea..ea6c52da 100644 --- a/devices/src/acpi/ged.rs +++ b/devices/src/acpi/ged.rs @@ -19,7 +19,7 @@ use anyhow::{Context, Result}; use vmm_sys_util::epoll::EventSet; use vmm_sys_util::eventfd::EventFd; -use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysRes}; +use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps}; use crate::{Device, DeviceBase}; use acpi::{ AcpiError, AmlActiveLevel, AmlAddressSpaceType, AmlAnd, AmlBuilder, AmlDevice, AmlEdgeLevel, @@ -97,12 +97,12 @@ impl Ged { region_size: u64, ) -> Result>> { self.base.interrupt_evt = Some(Arc::new(create_new_eventfd()?)); - self.set_sys_resource(sysbus, region_base, region_size) + self.set_sys_resource(sysbus, region_base, region_size, "Ged") .with_context(|| AcpiError::Alignment(region_size as u32))?; self.battery_present = battery_present; let dev = Arc::new(Mutex::new(self)); - sysbus.attach_device(&dev, region_base, region_size, "Ged")?; + sysbus.attach_device(&dev)?; let ged = dev.lock().unwrap(); ged.register_acpi_powerdown_event(ged_event.power_button) @@ -213,10 +213,6 @@ impl SysBusDevOps for Ged { fn write(&mut self, _data: &[u8], _base: GuestAddress, _offset: u64) -> bool { true } - - fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> { - Some(&mut self.base.res) - } } impl AmlBuilder for Ged { diff --git a/devices/src/acpi/power.rs b/devices/src/acpi/power.rs index 5d5685d3..d64486fc 100644 --- a/devices/src/acpi/power.rs +++ b/devices/src/acpi/power.rs @@ -18,7 +18,7 @@ use anyhow::{Context, Result}; use log::info; use crate::acpi::ged::{AcpiEvent, Ged}; -use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysRes}; +use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps}; use crate::{Device, DeviceBase}; use acpi::{ AcpiError, AmlAddressSpaceType, AmlBuilder, AmlDevice, AmlField, AmlFieldAccessType, @@ -183,11 +183,11 @@ impl PowerDev { region_base: u64, region_size: u64, ) -> Result<()> { - self.set_sys_resource(sysbus, region_base, region_size) + self.set_sys_resource(sysbus, region_base, region_size, "PowerDev") .with_context(|| AcpiError::Alignment(region_size as u32))?; let dev = Arc::new(Mutex::new(self)); - sysbus.attach_device(&dev, region_base, region_size, "PowerDev")?; + sysbus.attach_device(&dev)?; let pdev_available: bool; { @@ -262,10 +262,6 @@ impl SysBusDevOps for PowerDev { fn write(&mut self, _data: &[u8], _base: GuestAddress, _offset: u64) -> bool { true } - - fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> { - Some(&mut self.base.res) - } } impl AmlBuilder for PowerDev { diff --git a/devices/src/legacy/fwcfg.rs b/devices/src/legacy/fwcfg.rs index e675fb7d..45ac6d4b 100644 --- a/devices/src/legacy/fwcfg.rs +++ b/devices/src/legacy/fwcfg.rs @@ -19,7 +19,7 @@ use byteorder::{BigEndian, ByteOrder}; use log::{error, warn}; use crate::legacy::error::LegacyError; -use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType, SysRes}; +use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; use crate::{Device, DeviceBase}; use acpi::{ AmlBuilder, AmlDevice, AmlInteger, AmlNameDecl, AmlResTemplate, AmlScopeBuilder, AmlString, @@ -856,12 +856,12 @@ impl FwCfgMem { region_size: u64, ) -> Result>> { self.fwcfg.common_realize()?; - self.set_sys_resource(sysbus, region_base, region_size) + self.set_sys_resource(sysbus, region_base, region_size, "FwCfgMem") .with_context(|| "Failed to allocate system resource for FwCfg.")?; let dev = Arc::new(Mutex::new(self)); sysbus - .attach_device(&dev, region_base, region_size, "FwCfgMem") + .attach_device(&dev) .with_context(|| "Failed to attach FwCfg device to system bus.")?; Ok(dev) } @@ -989,19 +989,15 @@ impl SysBusDevOps for FwCfgMem { true } - fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> { - Some(&mut self.base.res) - } - fn set_sys_resource( &mut self, _sysbus: &mut SysBus, region_base: u64, region_size: u64, + region_name: &str, ) -> Result<()> { - let res = self.get_sys_resource_mut().unwrap(); - res.region_base = region_base; - res.region_size = region_size; + self.sysbusdev_base_mut() + .set_sys(-1, region_base, region_size, region_name); Ok(()) } @@ -1022,30 +1018,19 @@ pub struct FwCfgIO { impl FwCfgIO { pub fn new(sys_mem: Arc) -> Self { FwCfgIO { - base: SysBusDevBase { - base: DeviceBase::default(), - dev_type: SysBusDevType::FwCfg, - res: SysRes { - region_base: FW_CFG_IO_BASE, - region_size: FW_CFG_IO_SIZE, - irq: -1, - }, - ..Default::default() - }, + base: SysBusDevBase::new(SysBusDevType::FwCfg), fwcfg: FwCfgCommon::new(sys_mem), } } pub fn realize(mut self, sysbus: &mut SysBus) -> Result>> { self.fwcfg.common_realize()?; - let region_base = self.base.res.region_base; - let region_size = self.base.res.region_size; - self.set_sys_resource(sysbus, region_base, region_size) + self.set_sys_resource(sysbus, FW_CFG_IO_BASE, FW_CFG_IO_SIZE, "FwCfgIO") .with_context(|| "Failed to allocate system resource for FwCfg.")?; let dev = Arc::new(Mutex::new(self)); sysbus - .attach_device(&dev, region_base, region_size, "FwCfgIO") + .attach_device(&dev) .with_context(|| "Failed to attach FwCfg device to system bus.")?; Ok(dev) } @@ -1174,19 +1159,15 @@ impl SysBusDevOps for FwCfgIO { true } - fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> { - Some(&mut self.base.res) - } - fn set_sys_resource( &mut self, _sysbus: &mut SysBus, region_base: u64, region_size: u64, + region_name: &str, ) -> Result<()> { - let res = self.get_sys_resource_mut().unwrap(); - res.region_base = region_base; - res.region_size = region_size; + self.sysbusdev_base_mut() + .set_sys(-1, region_base, region_size, region_name); Ok(()) } diff --git a/devices/src/legacy/pflash.rs b/devices/src/legacy/pflash.rs index e1003922..6c225f67 100644 --- a/devices/src/legacy/pflash.rs +++ b/devices/src/legacy/pflash.rs @@ -18,7 +18,7 @@ use anyhow::{anyhow, bail, Context, Result}; use log::{error, warn}; use super::error::LegacyError; -use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType, SysRes}; +use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; use crate::{Device, DeviceBase}; use acpi::AmlBuilder; use address_space::{FileBackend, GuestAddress, HostMemMapping, Region}; @@ -214,7 +214,7 @@ impl PFlash { backend: Option, ) -> Result<()> { let region_size = Self::flash_region_size(region_max_size, &backend, self.read_only)?; - self.set_sys_resource(sysbus, region_base, region_size) + self.set_sys_resource(sysbus, region_base, region_size, "PflashRom") .with_context(|| "Failed to allocate system resource for PFlash.")?; let host_mmap = Arc::new(HostMemMapping::new( @@ -893,20 +893,15 @@ impl SysBusDevOps for PFlash { } } - fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> { - Some(&mut self.base.res) - } - fn set_sys_resource( &mut self, _sysbus: &mut SysBus, region_base: u64, region_size: u64, + region_name: &str, ) -> Result<()> { - let res = self.get_sys_resource_mut().unwrap(); - res.region_base = region_base; - res.region_size = region_size; - res.irq = 0; + self.sysbusdev_base_mut() + .set_sys(0, region_base, region_size, region_name); Ok(()) } diff --git a/devices/src/legacy/pl011.rs b/devices/src/legacy/pl011.rs index b2ff1ca1..f5fdafae 100644 --- a/devices/src/legacy/pl011.rs +++ b/devices/src/legacy/pl011.rs @@ -16,7 +16,7 @@ use anyhow::{Context, Result}; use log::error; use super::error::LegacyError; -use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType, SysRes}; +use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; use crate::{Device, DeviceBase}; use acpi::{ AmlActiveLevel, AmlBuilder, AmlDevice, AmlEdgeLevel, AmlExtendedInterrupt, AmlIntShare, @@ -165,12 +165,12 @@ impl PL011 { .unwrap() .realize() .with_context(|| "Failed to realize chardev")?; - self.set_sys_resource(sysbus, region_base, region_size) + self.set_sys_resource(sysbus, region_base, region_size, "PL011") .with_context(|| "Failed to set system resource for PL011.")?; let dev = Arc::new(Mutex::new(self)); sysbus - .attach_device(&dev, region_base, region_size, "PL011") + .attach_device(&dev) .with_context(|| "Failed to attach PL011 to system bus.")?; bs.lock().unwrap().kernel_cmdline.push(Param { @@ -414,10 +414,6 @@ impl SysBusDevOps for PL011 { true } - - fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> { - Some(&mut self.base.res) - } } impl StateTransfer for PL011 { diff --git a/devices/src/legacy/pl031.rs b/devices/src/legacy/pl031.rs index dc5b94e0..9ad650b0 100644 --- a/devices/src/legacy/pl031.rs +++ b/devices/src/legacy/pl031.rs @@ -17,7 +17,7 @@ use anyhow::{Context, Result}; use byteorder::{ByteOrder, LittleEndian}; use super::error::LegacyError; -use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType, SysRes}; +use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; use crate::{Device, DeviceBase}; use acpi::AmlBuilder; use address_space::GuestAddress; @@ -101,11 +101,11 @@ impl PL031 { region_size: u64, ) -> Result<()> { self.base.interrupt_evt = Some(Arc::new(create_new_eventfd()?)); - self.set_sys_resource(sysbus, region_base, region_size) + self.set_sys_resource(sysbus, region_base, region_size, "PL031") .with_context(|| LegacyError::SetSysResErr)?; let dev = Arc::new(Mutex::new(self)); - sysbus.attach_device(&dev, region_base, region_size, "PL031")?; + sysbus.attach_device(&dev)?; MigrationManager::register_device_instance( PL031State::descriptor(), @@ -198,10 +198,6 @@ impl SysBusDevOps for PL031 { true } - - fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> { - Some(&mut self.base.res) - } } impl AmlBuilder for PL031 { diff --git a/devices/src/legacy/ramfb.rs b/devices/src/legacy/ramfb.rs index 6dab9da2..3945de43 100644 --- a/devices/src/legacy/ramfb.rs +++ b/devices/src/legacy/ramfb.rs @@ -252,7 +252,7 @@ impl Ramfb { pub fn realize(self, sysbus: &mut SysBus) -> Result<()> { let dev = Arc::new(Mutex::new(self)); - sysbus.attach_dynamic_device(&dev)?; + sysbus.attach_device(&dev)?; Ok(()) } } diff --git a/devices/src/legacy/rtc.rs b/devices/src/legacy/rtc.rs index ccb907cb..1e498084 100644 --- a/devices/src/legacy/rtc.rs +++ b/devices/src/legacy/rtc.rs @@ -124,7 +124,7 @@ impl RTC { res: SysRes { region_base: RTC_PORT_INDEX, region_size: 8, - irq: -1, + ..Default::default() }, interrupt_evt: Some(Arc::new(create_new_eventfd()?)), ..Default::default() @@ -269,10 +269,10 @@ impl RTC { pub fn realize(mut self, sysbus: &mut SysBus) -> Result<()> { let region_base = self.base.res.region_base; let region_size = self.base.res.region_size; - self.set_sys_resource(sysbus, region_base, region_size)?; + self.set_sys_resource(sysbus, region_base, region_size, "RTC")?; let dev = Arc::new(Mutex::new(self)); - sysbus.attach_device(&dev, region_base, region_size, "RTC")?; + sysbus.attach_device(&dev)?; Ok(()) } @@ -391,10 +391,6 @@ impl SysBusDevOps for RTC { } } - fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> { - Some(&mut self.base.res) - } - fn reset(&mut self) -> Result<()> { self.cmos_data.fill(0); self.init_rtc_reg(); diff --git a/devices/src/legacy/serial.rs b/devices/src/legacy/serial.rs index 192de908..520e929c 100644 --- a/devices/src/legacy/serial.rs +++ b/devices/src/legacy/serial.rs @@ -17,7 +17,7 @@ use anyhow::{bail, Context, Result}; use log::{debug, error}; use super::error::LegacyError; -use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType, SysRes}; +use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; use crate::{Device, DeviceBase}; use acpi::{ AmlActiveLevel, AmlBuilder, AmlDevice, AmlEdgeLevel, AmlEisaId, AmlExtendedInterrupt, @@ -144,11 +144,11 @@ impl Serial { .realize() .with_context(|| "Failed to realize chardev")?; self.base.interrupt_evt = Some(Arc::new(create_new_eventfd()?)); - self.set_sys_resource(sysbus, region_base, region_size) + self.set_sys_resource(sysbus, region_base, region_size, "Serial") .with_context(|| LegacyError::SetSysResErr)?; let dev = Arc::new(Mutex::new(self)); - sysbus.attach_device(&dev, region_base, region_size, "Serial")?; + sysbus.attach_device(&dev)?; MigrationManager::register_device_instance( SerialState::descriptor(), @@ -406,10 +406,6 @@ impl SysBusDevOps for Serial { fn get_irq(&self, _sysbus: &mut SysBus) -> Result { Ok(UART_IRQ) } - - fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> { - Some(&mut self.base.res) - } } impl AmlBuilder for Serial { diff --git a/devices/src/sysbus/mod.rs b/devices/src/sysbus/mod.rs index 6083bb3f..95c71ec8 100644 --- a/devices/src/sysbus/mod.rs +++ b/devices/src/sysbus/mod.rs @@ -118,84 +118,82 @@ impl SysBus { } } - pub fn attach_device( - &mut self, - dev: &Arc>, - region_base: u64, - region_size: u64, - region_name: &str, - ) -> Result<()> { - let region_ops = self.build_region_ops(dev); - let region = Region::init_io_region(region_size, region_ops, region_name); - let locked_dev = dev.lock().unwrap(); - - region.set_ioeventfds(&locked_dev.ioeventfds()); - match locked_dev.sysbusdev_base().dev_type { - SysBusDevType::Serial if cfg!(target_arch = "x86_64") => { - #[cfg(target_arch = "x86_64")] - self.sys_io - .root() - .add_subregion(region, region_base) - .with_context(|| { - format!( - "Failed to register region in I/O space: offset={},size={}", - region_base, region_size - ) - })?; - } - SysBusDevType::FwCfg if cfg!(target_arch = "x86_64") => { - #[cfg(target_arch = "x86_64")] - self.sys_io + pub fn attach_device(&mut self, dev: &Arc>) -> Result<()> { + let res = dev.lock().unwrap().get_sys_resource().clone(); + let region_base = res.region_base; + let region_size = res.region_size; + let region_name = res.region_name; + + // region_base/region_size are both 0 means this device doesn't have its own memory layout. + // The normally allocated device region_base is above the `MEM_LAYOUT[LayoutEntryType::Mmio as usize].0`. + if region_base != 0 && region_size != 0 { + let region_ops = self.build_region_ops(dev); + let region = Region::init_io_region(region_size, region_ops, ®ion_name); + let locked_dev = dev.lock().unwrap(); + + region.set_ioeventfds(&locked_dev.ioeventfds()); + match locked_dev.sysbusdev_base().dev_type { + SysBusDevType::Serial if cfg!(target_arch = "x86_64") => { + #[cfg(target_arch = "x86_64")] + self.sys_io + .root() + .add_subregion(region, region_base) + .with_context(|| { + format!( + "Failed to register region in I/O space: offset={},size={}", + region_base, region_size + ) + })?; + } + SysBusDevType::FwCfg if cfg!(target_arch = "x86_64") => { + #[cfg(target_arch = "x86_64")] + self.sys_io + .root() + .add_subregion(region, region_base) + .with_context(|| { + format!( + "Failed to register region in I/O space: offset 0x{:x}, size {}", + region_base, region_size + ) + })?; + } + SysBusDevType::Rtc if cfg!(target_arch = "x86_64") => { + #[cfg(target_arch = "x86_64")] + self.sys_io + .root() + .add_subregion(region, region_base) + .with_context(|| { + format!( + "Failed to register region in I/O space: offset 0x{:x}, size {}", + region_base, region_size + ) + })?; + } + _ => self + .sys_mem .root() .add_subregion(region, region_base) .with_context(|| { format!( - "Failed to register region in I/O space: offset 0x{:x}, size {}", + "Failed to register region in memory space: offset={},size={}", region_base, region_size ) - })?; + })?, } - SysBusDevType::Rtc if cfg!(target_arch = "x86_64") => { - #[cfg(target_arch = "x86_64")] - self.sys_io - .root() - .add_subregion(region, region_base) - .with_context(|| { - format!( - "Failed to register region in I/O space: offset 0x{:x}, size {}", - region_base, region_size - ) - })?; - } - _ => self - .sys_mem - .root() - .add_subregion(region, region_base) - .with_context(|| { - format!( - "Failed to register region in memory space: offset={},size={}", - region_base, region_size - ) - })?, } self.devices.push(dev.clone()); Ok(()) } - - pub fn attach_dynamic_device( - &mut self, - dev: &Arc>, - ) -> Result<()> { - self.devices.push(dev.clone()); - Ok(()) - } } -#[derive(Copy, Clone)] +#[derive(Clone)] pub struct SysRes { + // Note: region_base/region_size are both 0 means that this device doesn't have its own memory layout. + // The normally allocated device memory region is above the `MEM_LAYOUT[LayoutEntryType::Mmio as usize].0`. pub region_base: u64, pub region_size: u64, + pub region_name: String, pub irq: i32, } @@ -204,6 +202,7 @@ impl Default for SysRes { Self { region_base: 0, region_size: 0, + region_name: "".to_string(), irq: -1, } } @@ -257,10 +256,11 @@ impl SysBusDevBase { } } - pub fn set_sys(&mut self, irq: i32, region_base: u64, region_size: u64) { + pub fn set_sys(&mut self, irq: i32, region_base: u64, region_size: u64, region_name: &str) { self.res.irq = irq; self.res.region_base = region_base; self.res.region_size = region_size; + self.res.region_name = region_name.to_string(); } } @@ -306,8 +306,8 @@ pub trait SysBusDevOps: Device + Send + AmlBuilder { Ok(irq) } - fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> { - None + fn get_sys_resource(&mut self) -> &mut SysRes { + &mut self.sysbusdev_base_mut().res } fn set_sys_resource( @@ -315,6 +315,7 @@ pub trait SysBusDevOps: Device + Send + AmlBuilder { sysbus: &mut SysBus, region_base: u64, region_size: u64, + region_name: &str, ) -> Result<()> { let irq = self.get_irq(sysbus)?; let interrupt_evt = self.sysbusdev_base().interrupt_evt.clone(); @@ -326,7 +327,7 @@ pub trait SysBusDevOps: Device + Send + AmlBuilder { irq_state.register_irq()?; self.sysbusdev_base_mut() - .set_sys(irq, region_base, region_size); + .set_sys(irq, region_base, region_size, region_name); Ok(()) } diff --git a/virtio/src/transport/virtio_mmio.rs b/virtio/src/transport/virtio_mmio.rs index eb09093f..2d0598af 100644 --- a/virtio/src/transport/virtio_mmio.rs +++ b/virtio/src/transport/virtio_mmio.rs @@ -26,7 +26,7 @@ use crate::{ QUEUE_TYPE_PACKED_VRING, VIRTIO_F_RING_PACKED, VIRTIO_MMIO_INT_CONFIG, VIRTIO_MMIO_INT_VRING, }; use address_space::{AddressRange, AddressSpace, GuestAddress, RegionIoEventFd}; -use devices::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType, SysRes}; +use devices::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; use devices::{Device, DeviceBase}; #[cfg(target_arch = "x86_64")] use machine_manager::config::{BootSource, Param}; @@ -170,7 +170,7 @@ impl VirtioMmioDevice { if region_base >= sysbus.mmio_region.1 { bail!("Mmio region space exhausted."); } - self.set_sys_resource(sysbus, region_base, region_size)?; + self.set_sys_resource(sysbus, region_base, region_size, "VirtioMmio")?; self.assign_interrupt_cb(); self.device .lock() @@ -179,7 +179,7 @@ impl VirtioMmioDevice { .with_context(|| "Failed to realize virtio.")?; let dev = Arc::new(Mutex::new(self)); - sysbus.attach_device(&dev, region_base, region_size, "VirtioMmio")?; + sysbus.attach_device(&dev)?; #[cfg(target_arch = "x86_64")] bs.lock().unwrap().kernel_cmdline.push(Param { @@ -530,10 +530,6 @@ impl SysBusDevOps for VirtioMmioDevice { } ret } - - fn get_sys_resource_mut(&mut self) -> Option<&mut SysRes> { - Some(&mut self.base.res) - } } impl acpi::AmlBuilder for VirtioMmioDevice { -- Gitee From 4165488c835f6c53da8e27d63c48eeb80f8dc4b1 Mon Sep 17 00:00:00 2001 From: Fan Xuan Zhe Date: Tue, 11 Jun 2024 09:53:38 +0800 Subject: [PATCH 120/489] usb-host: conditionally link the 'libusb-1.0' library based on whether 'usb-host' feature is enabled adds feature check to see whether "usb-host" is enabled, and if so, adds a libusb linker argument during the build process. Signed-off-by: Fan Xuan Zhe --- build.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build.rs b/build.rs index 53d0c9b2..9c03e535 100644 --- a/build.rs +++ b/build.rs @@ -16,7 +16,9 @@ fn ohos_env_configure() { println!("cargo:rustc-link-arg=--verbose"); println!("cargo:rustc-link-arg=--sysroot={}/sysroot", ohos_sdk_path); println!("cargo:rustc-link-arg=-lpixman_static"); - println!("cargo:rustc-link-arg=-lusb-1.0"); + if cfg!(feature = "usb-host") { + println!("cargo:rustc-link-arg=-lusb-1.0"); + } println!( "cargo:rustc-link-search={}/sysroot/usr/lib/aarch64-linux-ohos", ohos_sdk_path -- Gitee From 69b141f433d3b60c48dd74a6a565ad25a31d9580 Mon Sep 17 00:00:00 2001 From: Fan Xuan Zhe Date: Tue, 11 Jun 2024 20:26:16 +0800 Subject: [PATCH 121/489] usb-host: fix typo in conditionally link the specific feature name in code is "usb_host" rather than "usb-host". Signed-off-by: Fan Xuan Zhe --- build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.rs b/build.rs index 9c03e535..13b5a898 100644 --- a/build.rs +++ b/build.rs @@ -16,7 +16,7 @@ fn ohos_env_configure() { println!("cargo:rustc-link-arg=--verbose"); println!("cargo:rustc-link-arg=--sysroot={}/sysroot", ohos_sdk_path); println!("cargo:rustc-link-arg=-lpixman_static"); - if cfg!(feature = "usb-host") { + if cfg!(feature = "usb_host") { println!("cargo:rustc-link-arg=-lusb-1.0"); } println!( -- Gitee From e82ce3e2a94192d617beeb58dbb631a881cf1752 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Fri, 24 May 2024 01:51:01 +0800 Subject: [PATCH 122/489] clippy: fix warnings Fix these warnings: warning: constant `WINDOWS_EMU_PID_DEFAULT_INTERVAL` is never used --> machine/src/lib.rs:110:7 | 110 | const WINDOWS_EMU_PID_DEFAULT_INTERVAL: u64 = 4000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `#[warn(dead_code)]` on by default warning: constant `WINDOWS_EMU_PID_SHUTDOWN_INTERVAL` is never used --> machine/src/lib.rs:111:7 | 111 | const WINDOWS_EMU_PID_SHUTDOWN_INTERVAL: u64 = 1000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: constant `WINDOWS_EMU_PID_POWERDOWN_INTERVAL` is never used --> machine/src/lib.rs:112:7 | 112 | const WINDOWS_EMU_PID_POWERDOWN_INTERVAL: u64 = 30000; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Signed-off-by: liuxiangdong --- machine/src/lib.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/machine/src/lib.rs b/machine/src/lib.rs index c1f10314..bde75da4 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -107,8 +107,11 @@ use virtio::{ #[cfg(feature = "virtio_gpu")] use virtio::{Gpu, GpuDevConfig}; +#[cfg(feature = "windows_emu_pid")] const WINDOWS_EMU_PID_DEFAULT_INTERVAL: u64 = 4000; +#[cfg(feature = "windows_emu_pid")] const WINDOWS_EMU_PID_SHUTDOWN_INTERVAL: u64 = 1000; +#[cfg(feature = "windows_emu_pid")] const WINDOWS_EMU_PID_POWERDOWN_INTERVAL: u64 = 30000; /// Machine structure include base members. -- Gitee From 2a5e6c899bd3b8aedccdcef058fa202e810bcafc Mon Sep 17 00:00:00 2001 From: AlisaWang Date: Wed, 12 Jun 2024 10:45:11 +0800 Subject: [PATCH 123/489] MST:add "-disable-seccomp" on ohos Signed-off-by: AlisaWang --- tests/mod_test/src/libtest.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/mod_test/src/libtest.rs b/tests/mod_test/src/libtest.rs index 6de33d66..ada68e0a 100644 --- a/tests/mod_test/src/libtest.rs +++ b/tests/mod_test/src/libtest.rs @@ -355,7 +355,12 @@ pub fn test_init(extra_arg: Vec<&str>) -> TestState { let listener = init_socket(&test_socket); - let child = Command::new(binary_path) + let mut cmd = Command::new(binary_path); + + #[cfg(target_env = "ohos")] + cmd.args(["-disable-seccomp"]); + + let child = cmd .args(["-accel", "test"]) .args(["-qmp", &format!("unix:{},server,nowait", qmp_socket)]) .args(["-mod-test", &test_socket]) -- Gitee From 73ff16da2de008976004e0b007a2436cdedca001 Mon Sep 17 00:00:00 2001 From: zhanghan Date: Wed, 12 Jun 2024 11:09:15 +0800 Subject: [PATCH 124/489] OHAudio: avoid audio-playing's delay We drop old data before push new one. So data in buffer includes newest chunks. Signed-off-by: zhanghan --- devices/src/misc/scream/ohaudio.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index fc6fccf0..2349d93a 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -35,7 +35,7 @@ struct StreamUnit { pub len: u64, } -const STREAM_DATA_VEC_CAPACITY: usize = 30; +const STREAM_DATA_VEC_CAPACITY: usize = 15; const FLUSH_DELAY_THRESHOLD_MS: u64 = 100; const FLUSH_DELAY_MS: u64 = 5; const FLUSH_DELAY_CNT: u64 = 200; @@ -144,6 +144,15 @@ impl OhAudioProcess for OhAudioRender { len: recv_data.audio_size as u64, }; let mut locked_data = self.stream_data.lock().unwrap(); + // When audio data is not consumed in time, we remove old chunk + // and push new one. So audio-playing won't delay. One chunk means + // 20 ms data. + if locked_data.len() >= STREAM_DATA_VEC_CAPACITY { + let remove_size = locked_data[0].len; + locked_data.remove(0); + self.data_size + .fetch_sub(remove_size as i32, Ordering::Relaxed); + } locked_data.push(su); self.data_size .fetch_add(recv_data.audio_size as i32, Ordering::Relaxed); -- Gitee From 6109fa0d6a48238baa7c443c051d0a45654d4513 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 13 Jun 2024 19:57:19 +0800 Subject: [PATCH 125/489] display: fix clippy warnings in `get_sock_path` Fix clippy warnings in `get_sock_path`. Fix: 2472e3feb(display: use clap to parse the parameters of the display config) Signed-off-by: liuxiangdong --- machine_manager/src/config/display.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/machine_manager/src/config/display.rs b/machine_manager/src/config/display.rs index a8eca8c0..d0782858 100644 --- a/machine_manager/src/config/display.rs +++ b/machine_manager/src/config/display.rs @@ -40,8 +40,8 @@ pub struct UiContext { #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] fn get_sock_path(p: &str) -> Result { - let path = std::fs::canonicalize(p.clone()) - .with_context(|| format!("Failed to get real directory path: {:?}", p.clone()))?; + let path = std::fs::canonicalize(p) + .with_context(|| format!("Failed to get real directory path: {:?}", p))?; if !path.exists() { bail!( "The defined directory {:?} path doesn't exist", -- Gitee From d99885f5e736078d3269233f7236c246bd49e8de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A5=9A=E5=BD=B1?= Date: Wed, 12 Jun 2024 15:15:24 +0800 Subject: [PATCH 126/489] check oh msg header size Signed-off-by: Jiahong Li --- ui/src/ohui_srv/msg_handle.rs | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/ui/src/ohui_srv/msg_handle.rs b/ui/src/ohui_srv/msg_handle.rs index dffd0914..1e085e52 100755 --- a/ui/src/ohui_srv/msg_handle.rs +++ b/ui/src/ohui_srv/msg_handle.rs @@ -170,18 +170,8 @@ impl OhUiMsgHandler { } let hdr = &reader.header; - let body_size = hdr.size as usize; let event_type = hdr.event_type; - let expect_body_size = event_msg_data_len(hdr.event_type); - if body_size != expect_body_size { - reader.clear(); - bail!( - "{:?} data len is wrong, we want {}, but receive {}", - event_type, - expect_body_size, - body_size - ); - } + let body_size = hdr.size as size; trace::trace_scope_start!(handle_msg, args = (&event_type)); let body_bytes = reader.body.as_ref().unwrap(); @@ -391,17 +381,32 @@ impl MsgReader { pub fn recv(&mut self) -> Result { if self.recv_header()? { + self.check_header()?; return self.recv_body(); } Ok(false) } - pub fn clear(&mut self) { + fn clear(&mut self) { self.header_ready = 0; self.body_ready = 0; self.body = None; } + fn check_header(&mut self) -> Result<()> { + let expected_size = event_msg_data_len(self.header.event_type); + if expected_size != self.header.size as usize { + self.clear(); + bail!( + "{:?} data len is wrong, we want {}, but receive {}", + self.header.event_type as EventType, + expected_size, + self.header.size as usize, + ); + } + Ok(()) + } + fn recv_header(&mut self) -> Result { if self.header_ready == EVENT_MSG_HDR_SIZE as usize { return Ok(true); -- Gitee From 39386a009c14bceb2d0dadb6576bfb410a67d8ca Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Fri, 24 May 2024 12:47:01 +0800 Subject: [PATCH 127/489] test: use unified function to create virtio device Use unified function to create virtio pci/mmio device, and then remove these duplicate codes. Signed-off-by: liuxiangdong --- virtio/src/transport/virtio_mmio.rs | 70 +++-------- virtio/src/transport/virtio_pci.rs | 187 +++++----------------------- 2 files changed, 45 insertions(+), 212 deletions(-) diff --git a/virtio/src/transport/virtio_mmio.rs b/virtio/src/transport/virtio_mmio.rs index 2d0598af..77d0ca0a 100644 --- a/virtio/src/transport/virtio_mmio.rs +++ b/virtio/src/transport/virtio_mmio.rs @@ -594,7 +594,7 @@ impl MigrationHook for VirtioMmioDevice { } #[cfg(test)] -mod tests { +pub mod tests { use super::*; use crate::{ check_config_space_rw, read_config_default, VirtioBase, QUEUE_TYPE_SPLIT_VRING, @@ -602,7 +602,7 @@ mod tests { }; use address_space::{AddressSpace, GuestAddress, HostMemMapping, Region}; - fn address_space_init() -> Arc { + pub fn address_space_init() -> Arc { let root = Region::init_container_region(1 << 36, "sysmem"); let sys_space = AddressSpace::new(root, "sysmem", None).unwrap(); let host_mmap = Arc::new( @@ -697,9 +697,9 @@ mod tests { } } - #[test] - fn test_virtio_mmio_device_new() { + fn virtio_mmio_test_init() -> (Arc>, VirtioMmioDevice) { let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); + let sys_space = address_space_init(); let virtio_mmio_device = VirtioMmioDevice::new( &sys_space, @@ -707,6 +707,12 @@ mod tests { virtio_device.clone(), ); + (virtio_device, virtio_mmio_device) + } + + #[test] + fn test_virtio_mmio_device_new() { + let (virtio_device, virtio_mmio_device) = virtio_mmio_test_init(); let locked_device = virtio_device.lock().unwrap(); assert_eq!(locked_device.device_activated(), false); assert_eq!( @@ -723,13 +729,7 @@ mod tests { #[test] fn test_virtio_mmio_device_read_01() { - let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); - let sys_space = address_space_init(); - let mut virtio_mmio_device = VirtioMmioDevice::new( - &sys_space, - "test_virtio_mmio_device".to_string(), - virtio_device.clone(), - ); + let (virtio_device, mut virtio_mmio_device) = virtio_mmio_test_init(); let addr = GuestAddress(0); // read the register of magic value @@ -786,13 +786,7 @@ mod tests { #[test] fn test_virtio_mmio_device_read_02() { - let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); - let sys_space = address_space_init(); - let mut virtio_mmio_device = VirtioMmioDevice::new( - &sys_space, - "test_virtio_mmio_device".to_string(), - virtio_device.clone(), - ); + let (virtio_device, mut virtio_mmio_device) = virtio_mmio_test_init(); let addr = GuestAddress(0); // read the register representing max size of the queue @@ -882,13 +876,7 @@ mod tests { #[test] fn test_virtio_mmio_device_read_03() { - let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); - let sys_space = address_space_init(); - let mut virtio_mmio_device = VirtioMmioDevice::new( - &sys_space, - "test_virtio_mmio_device".to_string(), - virtio_device.clone(), - ); + let (virtio_device, mut virtio_mmio_device) = virtio_mmio_test_init(); let addr = GuestAddress(0); // read the configuration atomic value @@ -934,13 +922,7 @@ mod tests { #[test] fn test_virtio_mmio_device_write_01() { - let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); - let sys_space = address_space_init(); - let mut virtio_mmio_device = VirtioMmioDevice::new( - &sys_space, - "test_virtio_mmio_device".to_string(), - virtio_device.clone(), - ); + let (virtio_device, mut virtio_mmio_device) = virtio_mmio_test_init(); let addr = GuestAddress(0); // write the selector for device features @@ -1052,13 +1034,7 @@ mod tests { #[test] fn test_virtio_mmio_device_write_02() { - let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); - let sys_space = address_space_init(); - let mut virtio_mmio_device = VirtioMmioDevice::new( - &sys_space, - "test_virtio_mmio_device".to_string(), - virtio_device.clone(), - ); + let (virtio_device, mut virtio_mmio_device) = virtio_mmio_test_init(); let addr = GuestAddress(0); // write the ready status of queue @@ -1123,13 +1099,7 @@ mod tests { #[test] fn test_virtio_mmio_device_write_03() { - let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); - let sys_space = address_space_init(); - let mut virtio_mmio_device = VirtioMmioDevice::new( - &sys_space, - "test_virtio_mmio_device".to_string(), - virtio_device.clone(), - ); + let (virtio_device, mut virtio_mmio_device) = virtio_mmio_test_init(); let addr = GuestAddress(0); // write the low 32bit of queue's descriptor table address @@ -1252,13 +1222,7 @@ mod tests { #[test] fn test_virtio_mmio_device_write_04() { - let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); - let sys_space = address_space_init(); - let mut virtio_mmio_device = VirtioMmioDevice::new( - &sys_space, - "test_virtio_mmio_device".to_string(), - virtio_device.clone(), - ); + let (virtio_device, mut virtio_mmio_device) = virtio_mmio_test_init(); let addr = GuestAddress(0); virtio_mmio_device.assign_interrupt_cb(); diff --git a/virtio/src/transport/virtio_pci.rs b/virtio/src/transport/virtio_pci.rs index 8ca54015..111ae3de 100644 --- a/virtio/src/transport/virtio_pci.rs +++ b/virtio/src/transport/virtio_pci.rs @@ -1385,8 +1385,9 @@ mod tests { use vmm_sys_util::eventfd::EventFd; use super::*; + use crate::transport::virtio_mmio::tests::address_space_init; use crate::VirtioBase; - use address_space::{AddressSpace, GuestAddress, HostMemMapping}; + use address_space::{AddressSpace, GuestAddress}; use devices::pci::{ config::{HEADER_TYPE, HEADER_TYPE_MULTIFUNC}, le_read_u16, @@ -1468,31 +1469,40 @@ mod tests { }; } - #[test] - fn test_common_config_dev_feature() { + fn virtio_pci_test_init( + multi_func: bool, + ) -> ( + Arc>, + Arc>, + VirtioPciDevice, + ) { let virtio_dev = Arc::new(Mutex::new(VirtioDeviceTest::new())); - let sys_mem = AddressSpace::new( - Region::init_container_region(u64::max_value(), "sysmem"), - "sysmem", - None, - ) - .unwrap(); + let sys_mem = address_space_init(); let parent_bus = Arc::new(Mutex::new(PciBus::new( String::from("test bus"), #[cfg(target_arch = "x86_64")] Region::init_container_region(1 << 16, "parent_bus"), sys_mem.root().clone(), ))); - let mut virtio_pci = VirtioPciDevice::new( + let virtio_pci = VirtioPciDevice::new( String::from("test device"), 0, sys_mem, virtio_dev.clone(), Arc::downgrade(&parent_bus), - false, + multi_func, false, ); + // Note: if parent_bus is used in the code execution during the testing process, a variable needs to + // be used to maintain the count and avoid rust from automatically releasing this `Arc`. + (virtio_dev, parent_bus, virtio_pci) + } + + #[test] + fn test_common_config_dev_feature() { + let (virtio_dev, _, mut virtio_pci) = virtio_pci_test_init(false); + // Read virtio device features virtio_dev.lock().unwrap().set_hfeatures_sel(0_u32); com_cfg_read_test!(virtio_pci, COMMON_DF_REG, 0xFFFF_FFF0_u32); @@ -1528,28 +1538,7 @@ mod tests { #[test] fn test_common_config_queue() { - let virtio_dev = Arc::new(Mutex::new(VirtioDeviceTest::new())); - let sys_mem = AddressSpace::new( - Region::init_container_region(u64::max_value(), "sysmem"), - "sysmem", - None, - ) - .unwrap(); - let parent_bus = Arc::new(Mutex::new(PciBus::new( - String::from("test bus"), - #[cfg(target_arch = "x86_64")] - Region::init_container_region(1 << 16, "parent_bus"), - sys_mem.root().clone(), - ))); - let virtio_pci = VirtioPciDevice::new( - String::from("test device"), - 0, - sys_mem, - virtio_dev.clone(), - Arc::downgrade(&parent_bus), - false, - false, - ); + let (virtio_dev, _, virtio_pci) = virtio_pci_test_init(false); // Read Queue's Descriptor Table address virtio_dev @@ -1579,29 +1568,7 @@ mod tests { #[test] fn test_common_config_queue_error() { - let virtio_dev = Arc::new(Mutex::new(VirtioDeviceTest::new())); - let sys_mem = AddressSpace::new( - Region::init_container_region(u64::max_value(), "sysmem"), - "sysmem", - None, - ) - .unwrap(); - let parent_bus = Arc::new(Mutex::new(PciBus::new( - String::from("test bus"), - #[cfg(target_arch = "x86_64")] - Region::init_container_region(1 << 16, "parent_bus"), - sys_mem.root().clone(), - ))); - let cloned_virtio_dev = virtio_dev.clone(); - let mut virtio_pci = VirtioPciDevice::new( - String::from("test device"), - 0, - sys_mem, - cloned_virtio_dev, - Arc::downgrade(&parent_bus), - false, - false, - ); + let (virtio_dev, _, mut virtio_pci) = virtio_pci_test_init(false); assert!(init_msix( &mut virtio_pci.base, @@ -1654,29 +1621,8 @@ mod tests { #[test] fn test_virtio_pci_config_access() { - let virtio_dev: Arc> = - Arc::new(Mutex::new(VirtioDeviceTest::new())); - let sys_mem = AddressSpace::new( - Region::init_container_region(u64::max_value(), "sysmem"), - "sysmem", - None, - ) - .unwrap(); - let parent_bus = Arc::new(Mutex::new(PciBus::new( - String::from("test bus"), - #[cfg(target_arch = "x86_64")] - Region::init_container_region(1 << 16, "parent_bus"), - sys_mem.root().clone(), - ))); - let mut virtio_pci = VirtioPciDevice::new( - String::from("test device"), - 0, - sys_mem, - virtio_dev, - Arc::downgrade(&parent_bus), - false, - false, - ); + let (_, _parent_bus, mut virtio_pci) = virtio_pci_test_init(false); + virtio_pci.init_write_mask(false).unwrap(); virtio_pci.init_write_clear_mask(false).unwrap(); @@ -1695,69 +1641,14 @@ mod tests { #[test] fn test_virtio_pci_realize() { - let virtio_dev: Arc> = - Arc::new(Mutex::new(VirtioDeviceTest::new())); - let sys_mem = AddressSpace::new( - Region::init_container_region(u64::max_value(), "sysmem"), - "sysmem", - None, - ) - .unwrap(); - let parent_bus = Arc::new(Mutex::new(PciBus::new( - String::from("test bus"), - #[cfg(target_arch = "x86_64")] - Region::init_container_region(1 << 16, "parent_bus"), - sys_mem.root().clone(), - ))); - let virtio_pci = VirtioPciDevice::new( - String::from("test device"), - 0, - sys_mem, - virtio_dev, - Arc::downgrade(&parent_bus), - false, - false, - ); + let (_, _parent_bus, virtio_pci) = virtio_pci_test_init(false); assert!(virtio_pci.realize().is_ok()); } #[test] fn test_device_activate() { - let sys_mem = AddressSpace::new( - Region::init_container_region(u64::max_value(), "sysmem"), - "sysmem", - None, - ) - .unwrap(); - let mem_size: u64 = 1024 * 1024; - let host_mmap = Arc::new( - HostMemMapping::new(GuestAddress(0), None, mem_size, None, false, false, false) - .unwrap(), - ); - sys_mem - .root() - .add_subregion( - Region::init_ram_region(host_mmap.clone(), "sysmem"), - host_mmap.start_address().raw_value(), - ) - .unwrap(); + let (virtio_dev, _parent_bus, mut virtio_pci) = virtio_pci_test_init(false); - let virtio_dev = Arc::new(Mutex::new(VirtioDeviceTest::new())); - let parent_bus = Arc::new(Mutex::new(PciBus::new( - String::from("test bus"), - #[cfg(target_arch = "x86_64")] - Region::init_container_region(1 << 16, "parent_bus"), - sys_mem.root().clone(), - ))); - let mut virtio_pci = VirtioPciDevice::new( - String::from("test device"), - 0, - sys_mem, - virtio_dev.clone(), - Arc::downgrade(&parent_bus), - false, - false, - ); #[cfg(target_arch = "aarch64")] virtio_pci.base.config.set_interrupt_pin(); @@ -1827,29 +1718,7 @@ mod tests { #[test] fn test_multifunction() { - let virtio_dev: Arc> = - Arc::new(Mutex::new(VirtioDeviceTest::new())); - let sys_mem = AddressSpace::new( - Region::init_container_region(u64::max_value(), "sysmem"), - "sysmem", - None, - ) - .unwrap(); - let parent_bus = Arc::new(Mutex::new(PciBus::new( - String::from("test bus"), - #[cfg(target_arch = "x86_64")] - Region::init_container_region(1 << 16, "parent_bus"), - sys_mem.root().clone(), - ))); - let mut virtio_pci = VirtioPciDevice::new( - String::from("test device"), - 24, - sys_mem, - virtio_dev, - Arc::downgrade(&parent_bus), - true, - false, - ); + let (_, _parent_bus, mut virtio_pci) = virtio_pci_test_init(true); assert!(init_multifunction( virtio_pci.multi_func, -- Gitee From dcda83c392ac5a7e016979b92abac9a3be71a0be Mon Sep 17 00:00:00 2001 From: Huxiaohang Date: Wed, 12 Jun 2024 20:54:39 +0800 Subject: [PATCH 128/489] update vmm-sys-util to 0.12.1 Adding bitflags v2.5.0 Updating kvm-bindings v0.6.0 -> v0.7.0 Updating kvm-ioctls v0.15.0 -> v0.16.0 Updating vmm-sys-util v0.11.1 -> v0.12.1 --- Cargo.lock | 51 +++++++++++-------- address_space/Cargo.toml | 2 +- block_backend/Cargo.toml | 2 +- boot_loader/Cargo.toml | 2 +- chardev_backend/Cargo.toml | 2 +- cpu/Cargo.toml | 4 +- cpu/src/x86_64/mod.rs | 37 ++++++++++++-- devices/Cargo.toml | 2 +- hypervisor/Cargo.toml | 6 +-- hypervisor/src/kvm/mod.rs | 2 +- ...Third_Party_Open_Source_Software_Notice.md | 8 +-- machine/Cargo.toml | 2 +- machine_manager/Cargo.toml | 2 +- migration/Cargo.toml | 2 +- tests/mod_test/Cargo.toml | 2 +- trace/Cargo.toml | 2 +- ui/Cargo.toml | 2 +- util/Cargo.toml | 4 +- util/src/byte_code.rs | 2 +- vfio/Cargo.toml | 6 +-- virtio/Cargo.toml | 2 +- 21 files changed, 90 insertions(+), 54 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fb50c772..bc1a59a9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -49,7 +49,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8512c9117059663fb5606788fbca3619e2a91dac0e3fe516242eab1fa6be5e44" dependencies = [ "alsa-sys", - "bitflags", + "bitflags 1.3.2", "libc", "nix 0.24.3", ] @@ -83,7 +83,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ba16453d10c712284061a05f6510f75abeb92b56ba88dfeb48c74775020cc22" dependencies = [ "atk-sys", - "bitflags", + "bitflags 1.3.2", "glib", "libc", ] @@ -118,7 +118,7 @@ version = "0.65.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cfdf7b466f9a4903edc73f95d6d2bcd5baf8ae620638762244d3f60143643cc5" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cexpr", "clang-sys", "lazy_static", @@ -141,6 +141,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" + [[package]] name = "bitintr" version = "0.3.0" @@ -200,7 +206,7 @@ version = "0.17.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab3603c4028a5e368d09b51c8b624b9a46edcd7c3778284077a6125af73c9f0a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cairo-sys-rs", "glib", "libc", @@ -280,7 +286,7 @@ version = "4.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76" dependencies = [ - "bitflags", + "bitflags 1.3.2", "clap_derive", "clap_lex", "once_cell", @@ -495,7 +501,7 @@ version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be1df5ea52cccd7e3a0897338b5564968274b52f5fd12601e0afa44f454c74d3" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cairo-rs", "gdk-pixbuf", "gdk-sys", @@ -511,7 +517,7 @@ version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b023fbe0c6b407bd3d9805d107d9800da3829dc5a676653210f1d5f16d7f59bf" dependencies = [ - "bitflags", + "bitflags 1.3.2", "gdk-pixbuf-sys", "gio", "glib", @@ -586,7 +592,7 @@ version = "0.17.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d14522e56c6bcb6f7a3aebc25cbcfb06776af4c0c25232b601b4383252d7cb92" dependencies = [ - "bitflags", + "bitflags 1.3.2", "futures-channel", "futures-core", "futures-io", @@ -619,7 +625,7 @@ version = "0.17.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7f1de7cbde31ea4f0a919453a2dcece5d54d5b70e08f8ad254dc4840f5f09b6" dependencies = [ - "bitflags", + "bitflags 1.3.2", "futures-channel", "futures-core", "futures-executor", @@ -685,7 +691,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c4222ab92b08d4d0bab90ddb6185b4e575ceeea8b8cdf00b938d7b6661d966" dependencies = [ "atk", - "bitflags", + "bitflags 1.3.2", "cairo-rs", "field-offset", "futures-channel", @@ -788,7 +794,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b7b36074613a723279637061b40db993208908a94f10ccb14436ce735bc0f57" dependencies = [ - "bitflags", + "bitflags 1.3.2", "libc", ] @@ -809,19 +815,20 @@ dependencies = [ [[package]] name = "kvm-bindings" -version = "0.6.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efe70e65a5b092161d17f5005b66e5eefe7a94a70c332e755036fc4af78c4e79" +checksum = "081fbd8164229a990fbf24a1f35d287740db110c2b5d42addf460165f1b0e032" dependencies = [ "vmm-sys-util", ] [[package]] name = "kvm-ioctls" -version = "0.15.0" +version = "0.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bdde2b46ee7b6587ef79f751019c4726c4f2d3e4628df5d69f3f9c5cb6c6bd4" +checksum = "9002dff009755414f22b962ec6ae6980b07d6d8b06e5297b1062019d72bd6a8c" dependencies = [ + "bitflags 2.5.0", "kvm-bindings", "libc", "vmm-sys-util", @@ -861,7 +868,7 @@ version = "2.27.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1745b20bfc194ac12ef828f144f0ec2d4a7fe993281fa3567a0bd4969aee6890" dependencies = [ - "bitflags", + "bitflags 1.3.2", "libc", "libpulse-sys", "num-derive", @@ -1075,7 +1082,7 @@ version = "0.24.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "libc", ] @@ -1086,7 +1093,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "libc", "memoffset 0.7.1", @@ -1192,7 +1199,7 @@ version = "0.17.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52c280b82a881e4208afb3359a8e7fde27a1b272280981f1f34610bed5770d37" dependencies = [ - "bitflags", + "bitflags 1.3.2", "gio", "glib", "libc", @@ -1905,11 +1912,11 @@ dependencies = [ [[package]] name = "vmm-sys-util" -version = "0.11.1" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd64fe09d8e880e600c324e7d664760a17f56e9672b7495a86381b49e4f72f46" +checksum = "1d1435039746e20da4f8d507a72ee1b916f7b4b05af7a91c093d2c6561934ede" dependencies = [ - "bitflags", + "bitflags 1.3.2", "libc", ] diff --git a/address_space/Cargo.toml b/address_space/Cargo.toml index 3c1a6e14..c77820d3 100644 --- a/address_space/Cargo.toml +++ b/address_space/Cargo.toml @@ -10,7 +10,7 @@ description = "provide memory management for VM" libc = "0.2" log = "0.4" nix = { version = "0.26.2", default-features = false, features = ["fs", "feature"] } -vmm-sys-util = "0.11.1" +vmm-sys-util = "0.12.1" arc-swap = "1.6.0" thiserror = "1.0" anyhow = "1.0" diff --git a/block_backend/Cargo.toml b/block_backend/Cargo.toml index 6f7c45b3..d052bd0d 100644 --- a/block_backend/Cargo.toml +++ b/block_backend/Cargo.toml @@ -7,7 +7,7 @@ license = "Mulan PSL v2" [dependencies] thiserror = "1.0" -vmm-sys-util = "0.11.0" +vmm-sys-util = "0.12.1" anyhow = "1.0" log = "0.4" byteorder = "1.4.3" diff --git a/boot_loader/Cargo.toml b/boot_loader/Cargo.toml index d04c4cea..e2c9c45f 100644 --- a/boot_loader/Cargo.toml +++ b/boot_loader/Cargo.toml @@ -8,7 +8,7 @@ license = "Mulan PSL v2" [dependencies] thiserror = "1.0" anyhow = "1.0" -kvm-bindings = { version = "0.6.0", features = ["fam-wrappers"] } +kvm-bindings = { version = "0.7.0", features = ["fam-wrappers"] } log = "0.4" address_space = { path = "../address_space" } devices = { path = "../devices" } diff --git a/chardev_backend/Cargo.toml b/chardev_backend/Cargo.toml index 83b47b33..8a1b1535 100644 --- a/chardev_backend/Cargo.toml +++ b/chardev_backend/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" license = "Mulan PSL v2" [dependencies] -vmm-sys-util = "0.11.0" +vmm-sys-util = "0.12.1" anyhow = "1.0" log = "0.4" libc = "0.2" diff --git a/cpu/Cargo.toml b/cpu/Cargo.toml index a665edec..57e4d7e2 100644 --- a/cpu/Cargo.toml +++ b/cpu/Cargo.toml @@ -9,11 +9,11 @@ description = "CPU emulation" [dependencies] thiserror = "1.0" anyhow = "1.0" -kvm-bindings = { version = "0.6.0", features = ["fam-wrappers"] } +kvm-bindings = { version = "0.7.0", features = ["fam-wrappers"] } nix = { version = "0.26.2", default-features = false, features = ["fs", "feature"] } log = "0.4" libc = "0.2" -vmm-sys-util = "0.11.1" +vmm-sys-util = "0.12.1" machine_manager = { path = "../machine_manager" } migration = { path = "../migration" } migration_derive = { path = "../migration/migration_derive" } diff --git a/cpu/src/x86_64/mod.rs b/cpu/src/x86_64/mod.rs index 0a8ad169..088d0eb0 100644 --- a/cpu/src/x86_64/mod.rs +++ b/cpu/src/x86_64/mod.rs @@ -120,7 +120,7 @@ impl X86CPUTopology { /// The state of vCPU's register. #[allow(clippy::upper_case_acronyms)] #[repr(C)] -#[derive(Copy, Clone, Desc, ByteCode)] +#[derive(Desc, ByteCode)] #[desc_version(compat_version = "0.1.0")] pub struct X86CPUState { max_vcpus: u32, @@ -142,6 +142,34 @@ pub struct X86CPUState { pub debugregs: DebugRegs, } +impl Clone for X86CPUState { + fn clone(&self) -> Self { + let mut xsave: Xsave = Default::default(); + // we just clone xsave.region, because xsave.extra does not save + // valid values and it is not allowed to be cloned. + xsave.region = self.xsave.region; + Self { + max_vcpus: self.max_vcpus, + nr_threads: self.nr_threads, + nr_cores: self.nr_cores, + nr_dies: self.nr_dies, + nr_sockets: self.nr_sockets, + apic_id: self.apic_id, + regs: self.regs, + sregs: self.sregs, + fpu: self.fpu, + mp_state: self.mp_state, + lapic: self.lapic, + msr_len: self.msr_len, + msr_list: self.msr_list, + cpu_events: self.cpu_events, + xsave, + xcrs: self.xcrs, + debugregs: self.debugregs, + } + } +} + impl X86CPUState { /// Allocates a new `X86CPUState`. /// @@ -181,7 +209,8 @@ impl X86CPUState { self.msr_len = locked_cpu_state.msr_len; self.msr_list = locked_cpu_state.msr_list; self.cpu_events = locked_cpu_state.cpu_events; - self.xsave = locked_cpu_state.xsave; + self.xsave = Default::default(); + self.xsave.region = locked_cpu_state.xsave.region; self.xcrs = locked_cpu_state.xcrs; self.debugregs = locked_cpu_state.debugregs; } @@ -512,11 +541,11 @@ impl StateTransfer for CPU { } fn set_state(&self, state: &[u8]) -> Result<()> { - let cpu_state = *X86CPUState::from_bytes(state) + let cpu_state = X86CPUState::from_bytes(state) .with_context(|| MigrationError::FromBytesError("CPU"))?; let mut cpu_state_locked = self.arch_cpu.lock().unwrap(); - *cpu_state_locked = cpu_state; + *cpu_state_locked = cpu_state.clone(); Ok(()) } diff --git a/devices/Cargo.toml b/devices/Cargo.toml index 00181b49..fec9d5c1 100644 --- a/devices/Cargo.toml +++ b/devices/Cargo.toml @@ -14,7 +14,7 @@ log = "0.4" serde = { version = "1.0", features = ["derive"] } strum = "0.24.1" strum_macros = "0.24.3" -vmm-sys-util = "0.11.1" +vmm-sys-util = "0.12.1" byteorder = "1.4.3" drm-fourcc = ">=2.2.0" once_cell = "1.18.0" diff --git a/hypervisor/Cargo.toml b/hypervisor/Cargo.toml index df70a5b2..ccdf1305 100644 --- a/hypervisor/Cargo.toml +++ b/hypervisor/Cargo.toml @@ -8,11 +8,11 @@ license = "Mulan PSL v2" [dependencies] anyhow = "1.0" thiserror = "1.0" -kvm-bindings = { version = "0.6.0", features = ["fam-wrappers"] } -kvm-ioctls = "0.15.0" +kvm-bindings = { version = "0.7.0", features = ["fam-wrappers"] } +kvm-ioctls = "0.16.0" libc = "0.2" log = "0.4" -vmm-sys-util = "0.11.1" +vmm-sys-util = "0.12.1" address_space = { path = "../address_space" } cpu = { path = "../cpu" } devices = { path = "../devices" } diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs index 3e03a2a9..6689e516 100644 --- a/hypervisor/src/kvm/mod.rs +++ b/hypervisor/src/kvm/mod.rs @@ -466,7 +466,7 @@ impl KvmCpu { return Ok(true); } else { error!( - "Vcpu{} received unexpected system event with type 0x{:x}, flags 0x{:x}", + "Vcpu{} received unexpected system event with type 0x{:x}, flags {:#x?}", cpu.id(), event, flags diff --git a/license/Third_Party_Open_Source_Software_Notice.md b/license/Third_Party_Open_Source_Software_Notice.md index 71a4f777..721534ea 100644 --- a/license/Third_Party_Open_Source_Software_Notice.md +++ b/license/Third_Party_Open_Source_Software_Notice.md @@ -308,7 +308,7 @@ Copyright (c) David Tolnay License: MIT or Apache License Version 2.0 Please see above. -Software: vmm-sys-util 0.11.1 +Software: vmm-sys-util 0.12.1 Copyright notice: Copyright 2019 Intel Corporation. All Rights Reserved. Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. @@ -318,7 +318,7 @@ Copyright (C) 2019 Alibaba Cloud Computing. All rights reserved. Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved. Copyright 2018 The Chromium OS Authors. All rights reserved. Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. -License: Apache License Version 2.0 or BSD 3-Clause +License: BSD 3-Clause Please see above. Software: libusb1-sys 0.6.4 @@ -356,7 +356,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -Software: kvm-ioctls 0.13.0 +Software: kvm-ioctls 0.16.0 Copyright notice: Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. Portions Copyright 2017 The Chromium OS Authors. All rights reserved. @@ -365,7 +365,7 @@ Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. License: MIT or Apache License Version 2.0 Please see above. -Software: kvm-bindings 0.6.0 +Software: kvm-bindings 0.7.0 Copyright notice: Copyright 2019 Amazon.com, Inc. or its affiliates. All Rights Reserved. License: The APACHE 2.0 License diff --git a/machine/Cargo.toml b/machine/Cargo.toml index 2f677f8c..e5d9253a 100644 --- a/machine/Cargo.toml +++ b/machine/Cargo.toml @@ -10,7 +10,7 @@ description = "Emulation machines" log = "0.4" libc = "0.2" serde_json = "1.0" -vmm-sys-util = "0.11.1" +vmm-sys-util = "0.12.1" thiserror = "1.0" anyhow = "1.0" acpi = { path = "../acpi" } diff --git a/machine_manager/Cargo.toml b/machine_manager/Cargo.toml index 29e151bf..ec787bc5 100644 --- a/machine_manager/Cargo.toml +++ b/machine_manager/Cargo.toml @@ -12,7 +12,7 @@ regex = "1" log = "0.4" libc = "0.2" serde_json = "1.0" -vmm-sys-util = "0.11.1" +vmm-sys-util = "0.12.1" hex = "0.4.3" serde = { version = "1.0", features = ["derive"] } strum = "0.24.1" diff --git a/migration/Cargo.toml b/migration/Cargo.toml index e1469d9f..f0d10681 100644 --- a/migration/Cargo.toml +++ b/migration/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Huawei StratoVirt Team"] edition = "2021" [dependencies] -kvm-ioctls = "0.15.0" +kvm-ioctls = "0.16.0" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" once_cell = "1.18.0" diff --git a/tests/mod_test/Cargo.toml b/tests/mod_test/Cargo.toml index 9ccebc05..9b144af1 100644 --- a/tests/mod_test/Cargo.toml +++ b/tests/mod_test/Cargo.toml @@ -8,7 +8,7 @@ license = "Mulan PSL v2" [dependencies] rand = "0.8.5" hex = "0.4.3" -vmm-sys-util = "0.11.1" +vmm-sys-util = "0.12.1" anyhow = "1.0" serde_json = "1.0" libc = "0.2" diff --git a/trace/Cargo.toml b/trace/Cargo.toml index 267a3566..ad6cf1bc 100644 --- a/trace/Cargo.toml +++ b/trace/Cargo.toml @@ -12,7 +12,7 @@ lazy_static = "1.4.0" regex = "1" anyhow = "1.0" trace_generator = { path = "trace_generator" } -vmm-sys-util = "0.11.1" +vmm-sys-util = "0.12.1" [features] trace_to_logger = [] diff --git a/ui/Cargo.toml b/ui/Cargo.toml index 56f2b6f6..b7faa424 100644 --- a/ui/Cargo.toml +++ b/ui/Cargo.toml @@ -12,7 +12,7 @@ anyhow = "1.0" libc = "0.2" log = "0.4" serde_json = "1.0" -vmm-sys-util = "0.11.1" +vmm-sys-util = "0.12.1" once_cell = "1.18.0" sscanf = "0.4.1" bitintr = "0.3.0" diff --git a/util/Cargo.toml b/util/Cargo.toml index 8d8a38ec..806fe935 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -11,12 +11,12 @@ license = "Mulan PSL v2" arc-swap = "1.6.0" thiserror = "1.0" anyhow = "1.0" -kvm-bindings = { version = "0.6.0", features = ["fam-wrappers"] } +kvm-bindings = { version = "0.7.0", features = ["fam-wrappers"] } nix = { version = "0.26.2", default-features = false, features = ["poll", "term", "time", "signal", "fs", "feature"] } libc = "0.2" libloading = "0.7.4" log = { version = "0.4", features = ["std"]} -vmm-sys-util = "0.11.1" +vmm-sys-util = "0.12.1" byteorder = "1.4.3" once_cell = "1.18.0" io-uring = "0.6.0" diff --git a/util/src/byte_code.rs b/util/src/byte_code.rs index 64fe6c9a..5c45ade0 100644 --- a/util/src/byte_code.rs +++ b/util/src/byte_code.rs @@ -15,7 +15,7 @@ use std::slice::{from_raw_parts, from_raw_parts_mut}; /// A trait bound defined for types which are safe to convert to a byte slice and /// to create from a byte slice. -pub trait ByteCode: Default + Copy + Send + Sync { +pub trait ByteCode: Default + Send + Sync { /// Return the contents of an object (impl trait `ByteCode`) as a slice of bytes. /// the inverse of this function is "from_bytes" fn as_bytes(&self) -> &[u8] { diff --git a/vfio/Cargo.toml b/vfio/Cargo.toml index 94d7b5e4..6b3e135a 100644 --- a/vfio/Cargo.toml +++ b/vfio/Cargo.toml @@ -10,11 +10,11 @@ description = "Virtual function I/O" byteorder = "1.4.3" thiserror = "1.0" anyhow = "1.0" -kvm-bindings = { version = "0.6.0", features = ["fam-wrappers"] } -kvm-ioctls = "0.15.0" +kvm-bindings = { version = "0.7.0", features = ["fam-wrappers"] } +kvm-ioctls = "0.16.0" libc = "0.2" log = "0.4" -vmm-sys-util = "0.11.1" +vmm-sys-util = "0.12.1" vfio-bindings = "0.3" once_cell = "1.18.0" address_space = { path = "../address_space" } diff --git a/virtio/Cargo.toml b/virtio/Cargo.toml index d2890ed0..91c89cd0 100644 --- a/virtio/Cargo.toml +++ b/virtio/Cargo.toml @@ -13,7 +13,7 @@ anyhow = "1.0" libc = "0.2" log = "0.4" serde_json = "1.0" -vmm-sys-util = "0.11.1" +vmm-sys-util = "0.12.1" once_cell = "1.18.0" address_space = { path = "../address_space" } machine_manager = { path = "../machine_manager" } -- Gitee From 09fd552a2e1b0b895b36e5295f10a63ba4345b8b Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 23 May 2024 17:25:21 +0800 Subject: [PATCH 129/489] test: add `sysbus_init` function in sysbus mod Many tests require the creation of the sysbus. Use the unified `sysbus_init` function to complete this task. Signed-off-by: liuxiangdong --- devices/src/legacy/fwcfg.rs | 27 +-------------------------- devices/src/legacy/pflash.rs | 28 +--------------------------- devices/src/sysbus/mod.rs | 26 ++++++++++++++++++++++++++ 3 files changed, 28 insertions(+), 53 deletions(-) diff --git a/devices/src/legacy/fwcfg.rs b/devices/src/legacy/fwcfg.rs index 45ac6d4b..5af3c939 100644 --- a/devices/src/legacy/fwcfg.rs +++ b/devices/src/legacy/fwcfg.rs @@ -1292,34 +1292,9 @@ impl AmlBuilder for FwCfgIO { #[cfg(test)] mod test { use super::*; - use crate::sysbus::{IRQ_BASE, IRQ_MAX}; + use crate::sysbus::sysbus_init; use address_space::{AddressSpace, HostMemMapping, Region}; - fn sysbus_init() -> SysBus { - let sys_mem = AddressSpace::new( - Region::init_container_region(u64::max_value(), "sys_mem"), - "sys_mem", - None, - ) - .unwrap(); - #[cfg(target_arch = "x86_64")] - let sys_io = AddressSpace::new( - Region::init_container_region(1 << 16, "sys_io"), - "sys_io", - None, - ) - .unwrap(); - let free_irqs: (i32, i32) = (IRQ_BASE, IRQ_MAX); - let mmio_region: (u64, u64) = (0x0A00_0000, 0x1000_0000); - SysBus::new( - #[cfg(target_arch = "x86_64")] - &sys_io, - &sys_mem, - free_irqs, - mmio_region, - ) - } - fn address_space_init() -> Arc { let root = Region::init_container_region(1 << 36, "root"); let sys_space = AddressSpace::new(root, "sys_space", None).unwrap(); diff --git a/devices/src/legacy/pflash.rs b/devices/src/legacy/pflash.rs index 6c225f67..747d22b9 100644 --- a/devices/src/legacy/pflash.rs +++ b/devices/src/legacy/pflash.rs @@ -930,33 +930,7 @@ mod test { use std::fs::File; use super::*; - use crate::sysbus::{IRQ_BASE, IRQ_MAX}; - use address_space::AddressSpace; - - fn sysbus_init() -> SysBus { - let sys_mem = AddressSpace::new( - Region::init_container_region(u64::max_value(), "sys_mem"), - "sys_mem", - None, - ) - .unwrap(); - #[cfg(target_arch = "x86_64")] - let sys_io = AddressSpace::new( - Region::init_container_region(1 << 16, "sys_io"), - "sys_io", - None, - ) - .unwrap(); - let free_irqs: (i32, i32) = (IRQ_BASE, IRQ_MAX); - let mmio_region: (u64, u64) = (0x0A00_0000, 0x1000_0000); - SysBus::new( - #[cfg(target_arch = "x86_64")] - &sys_io, - &sys_mem, - free_irqs, - mmio_region, - ) - } + use crate::sysbus::sysbus_init; fn pflash_dev_init(file_name: &str) -> Arc> { let sector_len: u32 = 0x40_000; diff --git a/devices/src/sysbus/mod.rs b/devices/src/sysbus/mod.rs index 95c71ec8..f9bbeb5a 100644 --- a/devices/src/sysbus/mod.rs +++ b/devices/src/sysbus/mod.rs @@ -419,3 +419,29 @@ pub fn to_sysbusdevops(dev: &dyn Device) -> Option<&dyn SysBusDevOps> { Some(sysbusdev) } } + +#[cfg(test)] +pub fn sysbus_init() -> SysBus { + let sys_mem = AddressSpace::new( + Region::init_container_region(u64::max_value(), "sys_mem"), + "sys_mem", + None, + ) + .unwrap(); + #[cfg(target_arch = "x86_64")] + let sys_io = AddressSpace::new( + Region::init_container_region(1 << 16, "sys_io"), + "sys_io", + None, + ) + .unwrap(); + let free_irqs: (i32, i32) = (IRQ_BASE, IRQ_MAX); + let mmio_region: (u64, u64) = (0x0A00_0000, 0x1000_0000); + SysBus::new( + #[cfg(target_arch = "x86_64")] + &sys_io, + &sys_mem, + free_irqs, + mmio_region, + ) +} -- Gitee From 59ca73b77da2235633a458ce022ebf5ea7ef5f79 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Fri, 24 May 2024 01:46:52 +0800 Subject: [PATCH 130/489] test: add `address_space_init` function in devices/virtio crate Many tests require the creation of the address space. Use the unified `address_space_init` function to complete this task. In rust, a type under `#[cfg(test)]` exported in crate A can not be used for another test under `#[cfg(test)]` in crate B. So we can not add this function by `#[cfg(test)]` in address_space crate. Because currently only virtio and devices crates will use it, create function `address_space_init` for each crate. Signed-off-by: liuxiangdong --- devices/src/legacy/fwcfg.rs | 27 +------------------ devices/src/lib.rs | 32 ++++++++++++++++++++++ virtio/src/device/balloon.rs | 32 +++------------------- virtio/src/device/block.rs | 30 ++------------------- virtio/src/device/net.rs | 2 +- virtio/src/device/rng.rs | 30 ++------------------- virtio/src/device/serial.rs | 2 +- virtio/src/lib.rs | 34 ++++++++++++++++++++++++ virtio/src/queue/split.rs | 28 ++------------------ virtio/src/transport/virtio_mmio.rs | 41 ++++++----------------------- virtio/src/transport/virtio_pci.rs | 8 +++--- virtio/src/vhost/kernel/net.rs | 31 ++-------------------- virtio/src/vhost/kernel/vsock.rs | 10 ++----- 13 files changed, 94 insertions(+), 213 deletions(-) diff --git a/devices/src/legacy/fwcfg.rs b/devices/src/legacy/fwcfg.rs index 5af3c939..ad3e3f3e 100644 --- a/devices/src/legacy/fwcfg.rs +++ b/devices/src/legacy/fwcfg.rs @@ -1293,32 +1293,7 @@ impl AmlBuilder for FwCfgIO { mod test { use super::*; use crate::sysbus::sysbus_init; - use address_space::{AddressSpace, HostMemMapping, Region}; - - fn address_space_init() -> Arc { - let root = Region::init_container_region(1 << 36, "root"); - let sys_space = AddressSpace::new(root, "sys_space", None).unwrap(); - let host_mmap = Arc::new( - HostMemMapping::new( - GuestAddress(0), - None, - 0x1000_0000, - None, - false, - false, - false, - ) - .unwrap(), - ); - sys_space - .root() - .add_subregion( - Region::init_ram_region(host_mmap.clone(), "region_1"), - host_mmap.start_address().raw_value(), - ) - .unwrap(); - sys_space - } + use crate::test::address_space_init; #[test] fn test_entry_functions() { diff --git a/devices/src/lib.rs b/devices/src/lib.rs index 0486bf1e..491ca1d5 100644 --- a/devices/src/lib.rs +++ b/devices/src/lib.rs @@ -72,3 +72,35 @@ pub trait Device: Any + AsAny { self.device_base().hotpluggable } } + +#[cfg(test)] +pub mod test { + use std::sync::Arc; + + use address_space::{AddressSpace, GuestAddress, HostMemMapping, Region}; + + pub fn address_space_init() -> Arc { + let root = Region::init_container_region(1 << 36, "root"); + let sys_space = AddressSpace::new(root, "sys_space", None).unwrap(); + let host_mmap = Arc::new( + HostMemMapping::new( + GuestAddress(0), + None, + 0x1000_0000, + None, + false, + false, + false, + ) + .unwrap(), + ); + sys_space + .root() + .add_subregion( + Region::init_ram_region(host_mmap.clone(), "region_1"), + host_mmap.start_address().raw_value(), + ) + .unwrap(); + sys_space + } +} diff --git a/virtio/src/device/balloon.rs b/virtio/src/device/balloon.rs index 33f89d3e..fe62211c 100644 --- a/virtio/src/device/balloon.rs +++ b/virtio/src/device/balloon.rs @@ -1245,39 +1245,13 @@ pub fn balloon_allow_list(syscall_allow_list: &mut Vec) { #[cfg(test)] mod tests { - pub use super::*; - pub use crate::*; - + use super::*; + use crate::tests::{address_space_init, MEMORY_SIZE}; + use crate::*; use address_space::{AddressRange, HostMemMapping, Region}; - const MEMORY_SIZE: u64 = 1024 * 1024; const QUEUE_SIZE: u16 = 256; - fn address_space_init() -> Arc { - let root = Region::init_container_region(1 << 36, "space"); - let sys_space = AddressSpace::new(root, "space", None).unwrap(); - let host_mmap = Arc::new( - HostMemMapping::new( - GuestAddress(0), - None, - MEMORY_SIZE, - None, - false, - false, - false, - ) - .unwrap(), - ); - sys_space - .root() - .add_subregion( - Region::init_ram_region(host_mmap.clone(), "space"), - host_mmap.start_address().raw_value(), - ) - .unwrap(); - sys_space - } - fn create_flat_range(addr: u64, size: u64, offset_in_region: u64) -> FlatRange { let mem_mapping = Arc::new( HostMemMapping::new(GuestAddress(addr), None, size, None, false, false, false).unwrap(), diff --git a/virtio/src/device/block.rs b/virtio/src/device/block.rs index 9b14a880..837cfe6d 100644 --- a/virtio/src/device/block.rs +++ b/virtio/src/device/block.rs @@ -1446,8 +1446,9 @@ mod tests { use vmm_sys_util::tempfile::TempFile; use super::*; + use crate::tests::address_space_init; use crate::*; - use address_space::{AddressSpace, GuestAddress, HostMemMapping, Region}; + use address_space::GuestAddress; use machine_manager::config::{ str_slip_to_clap, IothreadConfig, VmConfig, DEFAULT_VIRTQUEUE_SIZE, }; @@ -1456,33 +1457,6 @@ mod tests { const CONFIG_SPACE_SIZE: usize = 60; const VIRTQ_DESC_F_NEXT: u16 = 0x01; const VIRTQ_DESC_F_WRITE: u16 = 0x02; - const SYSTEM_SPACE_SIZE: u64 = (1024 * 1024) as u64; - - // build dummy address space of vm - fn address_space_init() -> Arc { - let root = Region::init_container_region(1 << 36, "sysmem"); - let sys_space = AddressSpace::new(root, "sysmem", None).unwrap(); - let host_mmap = Arc::new( - HostMemMapping::new( - GuestAddress(0), - None, - SYSTEM_SPACE_SIZE, - None, - false, - false, - false, - ) - .unwrap(), - ); - sys_space - .root() - .add_subregion( - Region::init_ram_region(host_mmap.clone(), "sysmem"), - host_mmap.start_address().raw_value(), - ) - .unwrap(); - sys_space - } fn init_default_block() -> Block { Block::new( diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index 391a6cd0..7b400206 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -1787,7 +1787,7 @@ impl MigrationHook for Net {} #[cfg(test)] mod tests { - pub use super::*; + use super::*; #[test] fn test_net_init() { diff --git a/virtio/src/device/rng.rs b/virtio/src/device/rng.rs index 9f1007ed..3d26ea9e 100644 --- a/virtio/src/device/rng.rs +++ b/virtio/src/device/rng.rs @@ -419,39 +419,13 @@ mod tests { use vmm_sys_util::tempfile::TempFile; use super::*; + use crate::tests::address_space_init; use crate::*; - use address_space::{AddressSpace, GuestAddress, HostMemMapping, Region}; + use address_space::GuestAddress; use machine_manager::config::{str_slip_to_clap, VmConfig, DEFAULT_VIRTQUEUE_SIZE}; const VIRTQ_DESC_F_NEXT: u16 = 0x01; const VIRTQ_DESC_F_WRITE: u16 = 0x02; - const SYSTEM_SPACE_SIZE: u64 = (1024 * 1024) as u64; - - // build dummy address space of vm - fn address_space_init() -> Arc { - let root = Region::init_container_region(1 << 36, "sysmem"); - let sys_space = AddressSpace::new(root, "sysmem", None).unwrap(); - let host_mmap = Arc::new( - HostMemMapping::new( - GuestAddress(0), - None, - SYSTEM_SPACE_SIZE, - None, - false, - false, - false, - ) - .unwrap(), - ); - sys_space - .root() - .add_subregion( - Region::init_ram_region(host_mmap.clone(), "sysmem"), - host_mmap.start_address().raw_value(), - ) - .unwrap(); - sys_space - } #[test] fn test_rng_config_cmdline_parse() { diff --git a/virtio/src/device/serial.rs b/virtio/src/device/serial.rs index 102a3ed6..0cf42421 100644 --- a/virtio/src/device/serial.rs +++ b/virtio/src/device/serial.rs @@ -1008,7 +1008,7 @@ impl ChardevNotifyDevice for SerialPort { #[cfg(test)] mod tests { - pub use super::*; + use super::*; #[test] fn test_set_driver_features() { diff --git a/virtio/src/lib.rs b/virtio/src/lib.rs index 1fed7f32..9fc5cd59 100644 --- a/virtio/src/lib.rs +++ b/virtio/src/lib.rs @@ -877,3 +877,37 @@ pub fn virtio_register_sysbusdevops_type() -> Result<()> { pub fn virtio_register_pcidevops_type() -> Result<()> { register_pcidevops_type::() } + +#[cfg(test)] +mod tests { + use std::sync::Arc; + + use address_space::{AddressSpace, GuestAddress, HostMemMapping, Region}; + + pub const MEMORY_SIZE: u64 = 1024 * 1024; + + pub fn address_space_init() -> Arc { + let root = Region::init_container_region(1 << 36, "root"); + let sys_space = AddressSpace::new(root, "sys_space", None).unwrap(); + let host_mmap = Arc::new( + HostMemMapping::new( + GuestAddress(0), + None, + MEMORY_SIZE, + None, + false, + false, + false, + ) + .unwrap(), + ); + sys_space + .root() + .add_subregion( + Region::init_ram_region(host_mmap.clone(), "region_1"), + host_mmap.start_address().raw_value(), + ) + .unwrap(); + sys_space + } +} diff --git a/virtio/src/queue/split.rs b/virtio/src/queue/split.rs index 31b2fe30..302c258d 100644 --- a/virtio/src/queue/split.rs +++ b/virtio/src/queue/split.rs @@ -975,33 +975,9 @@ impl VringOps for SplitVring { #[cfg(test)] mod tests { use super::*; + use crate::tests::address_space_init; use crate::{Queue, QUEUE_TYPE_PACKED_VRING, QUEUE_TYPE_SPLIT_VRING}; - use address_space::{AddressSpace, GuestAddress, HostMemMapping, Region}; - - fn address_space_init() -> Arc { - let root = Region::init_container_region(1 << 36, "sysmem"); - let sys_space = AddressSpace::new(root, "sysmem", None).unwrap(); - let host_mmap = Arc::new( - HostMemMapping::new( - GuestAddress(0), - None, - SYSTEM_SPACE_SIZE, - None, - false, - false, - false, - ) - .unwrap(), - ); - sys_space - .root() - .add_subregion( - Region::init_ram_region(host_mmap.clone(), "sysmem"), - host_mmap.start_address().raw_value(), - ) - .unwrap(); - sys_space - } + use address_space::{AddressSpace, GuestAddress}; trait VringOpsTest { fn set_desc( diff --git a/virtio/src/transport/virtio_mmio.rs b/virtio/src/transport/virtio_mmio.rs index 77d0ca0a..814fbeee 100644 --- a/virtio/src/transport/virtio_mmio.rs +++ b/virtio/src/transport/virtio_mmio.rs @@ -594,53 +594,28 @@ impl MigrationHook for VirtioMmioDevice { } #[cfg(test)] -pub mod tests { +mod tests { use super::*; + use crate::tests::address_space_init; use crate::{ check_config_space_rw, read_config_default, VirtioBase, QUEUE_TYPE_SPLIT_VRING, VIRTIO_TYPE_BLOCK, }; - use address_space::{AddressSpace, GuestAddress, HostMemMapping, Region}; - - pub fn address_space_init() -> Arc { - let root = Region::init_container_region(1 << 36, "sysmem"); - let sys_space = AddressSpace::new(root, "sysmem", None).unwrap(); - let host_mmap = Arc::new( - HostMemMapping::new( - GuestAddress(0), - None, - SYSTEM_SPACE_SIZE, - None, - false, - false, - false, - ) - .unwrap(), - ); - sys_space - .root() - .add_subregion( - Region::init_ram_region(host_mmap.clone(), "sysmem"), - host_mmap.start_address().raw_value(), - ) - .unwrap(); - sys_space - } + use address_space::{AddressSpace, GuestAddress}; - const SYSTEM_SPACE_SIZE: u64 = (1024 * 1024) as u64; const CONFIG_SPACE_SIZE: usize = 16; const QUEUE_NUM: usize = 2; const QUEUE_SIZE: u16 = 256; - pub struct VirtioDeviceTest { + struct VirtioDeviceTest { base: VirtioBase, - pub config_space: Vec, - pub b_active: bool, - pub b_realized: bool, + config_space: Vec, + b_active: bool, + b_realized: bool, } impl VirtioDeviceTest { - pub fn new() -> Self { + fn new() -> Self { let mut config_space = Vec::new(); for i in 0..CONFIG_SPACE_SIZE { config_space.push(i as u8); diff --git a/virtio/src/transport/virtio_pci.rs b/virtio/src/transport/virtio_pci.rs index 111ae3de..a9ba784b 100644 --- a/virtio/src/transport/virtio_pci.rs +++ b/virtio/src/transport/virtio_pci.rs @@ -1385,7 +1385,7 @@ mod tests { use vmm_sys_util::eventfd::EventFd; use super::*; - use crate::transport::virtio_mmio::tests::address_space_init; + use crate::tests::address_space_init; use crate::VirtioBase; use address_space::{AddressSpace, GuestAddress}; use devices::pci::{ @@ -1397,13 +1397,13 @@ mod tests { const VIRTIO_DEVICE_QUEUE_NUM: usize = 2; const VIRTIO_DEVICE_QUEUE_SIZE: u16 = 256; - pub struct VirtioDeviceTest { + struct VirtioDeviceTest { base: VirtioBase, - pub is_activated: bool, + is_activated: bool, } impl VirtioDeviceTest { - pub fn new() -> Self { + fn new() -> Self { let mut base = VirtioBase::new( VIRTIO_DEVICE_TEST_TYPE, VIRTIO_DEVICE_QUEUE_NUM, diff --git a/virtio/src/vhost/kernel/net.rs b/virtio/src/vhost/kernel/net.rs index 89a29970..0933cef4 100644 --- a/virtio/src/vhost/kernel/net.rs +++ b/virtio/src/vhost/kernel/net.rs @@ -415,36 +415,9 @@ mod tests { use std::fs::File; use super::*; - use address_space::*; + use crate::tests::address_space_init; use machine_manager::config::DEFAULT_VIRTQUEUE_SIZE; - const SYSTEM_SPACE_SIZE: u64 = (1024 * 1024) as u64; - - fn vhost_address_space_init() -> Arc { - let root = Region::init_container_region(1 << 36, "sysmem"); - let sys_space = AddressSpace::new(root, "sysmem", None).unwrap(); - let host_mmap = Arc::new( - HostMemMapping::new( - GuestAddress(0), - None, - SYSTEM_SPACE_SIZE, - None, - false, - false, - false, - ) - .unwrap(), - ); - sys_space - .root() - .add_subregion( - Region::init_ram_region(host_mmap.clone(), "sysmem"), - host_mmap.start_address().raw_value(), - ) - .unwrap(); - sys_space - } - #[test] fn test_vhost_net_realize() { let netdev_cfg1 = NetDevcfg { @@ -465,7 +438,7 @@ mod tests { queue_size: DEFAULT_VIRTQUEUE_SIZE, ..Default::default() }; - let vhost_net_space = vhost_address_space_init(); + let vhost_net_space = address_space_init(); let mut vhost_net = Net::new(&vhost_net_conf, netdev_cfg1, &vhost_net_space); // the tap_fd and vhost_fd attribute of vhost-net can't be assigned. assert!(vhost_net.realize().is_err()); diff --git a/virtio/src/vhost/kernel/vsock.rs b/virtio/src/vhost/kernel/vsock.rs index ade3ec2f..8c06c63d 100644 --- a/virtio/src/vhost/kernel/vsock.rs +++ b/virtio/src/vhost/kernel/vsock.rs @@ -414,15 +414,9 @@ impl MigrationHook for Vsock { #[cfg(test)] mod tests { use super::*; - use address_space::*; + use crate::tests::address_space_init; use machine_manager::config::str_slip_to_clap; - fn vsock_address_space_init() -> Arc { - let root = Region::init_container_region(u64::max_value(), "sysmem"); - let sys_mem = AddressSpace::new(root, "sysmem", None).unwrap(); - sys_mem - } - fn vsock_create_instance() -> Vsock { let vsock_conf = VsockConfig { id: "test_vsock_1".to_string(), @@ -430,7 +424,7 @@ mod tests { vhost_fd: None, ..Default::default() }; - let sys_mem = vsock_address_space_init(); + let sys_mem = address_space_init(); let vsock = Vsock::new(&vsock_conf, &sys_mem); vsock } -- Gitee From f1ca78e1e04f28779be719b52c882640fcb550ea Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Fri, 14 Jun 2024 15:02:52 +0800 Subject: [PATCH 131/489] test: use `create_pci_host` function in bus mod There exists `create_pci_host` function, delete redundant one. Signed-off-by: liuxiangdong --- devices/src/pci/bus.rs | 32 ++------------------------------ 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/devices/src/pci/bus.rs b/devices/src/pci/bus.rs index 79746663..3acc5250 100644 --- a/devices/src/pci/bus.rs +++ b/devices/src/pci/bus.rs @@ -274,10 +274,10 @@ mod tests { use super::*; use crate::pci::bus::PciBus; use crate::pci::config::{PciConfig, PCI_CONFIG_SPACE_SIZE}; + use crate::pci::host::tests::create_pci_host; use crate::pci::root_port::RootPort; - use crate::pci::{PciDevBase, PciHost, RootPortConfig}; + use crate::pci::{PciDevBase, RootPortConfig}; use crate::{Device, DeviceBase}; - use address_space::{AddressSpace, Region}; #[derive(Clone)] struct PciDevice { @@ -339,34 +339,6 @@ mod tests { } } - pub fn create_pci_host() -> Arc> { - #[cfg(target_arch = "x86_64")] - let sys_io = AddressSpace::new( - Region::init_container_region(1 << 16, "sysio"), - "sysio", - None, - ) - .unwrap(); - let sys_mem = AddressSpace::new( - Region::init_container_region(u64::max_value(), "sysmem"), - "sysmem", - None, - ) - .unwrap(); - Arc::new(Mutex::new(PciHost::new( - #[cfg(target_arch = "x86_64")] - &sys_io, - &sys_mem, - (0xB000_0000, 0x1000_0000), - (0xC000_0000, 0x3000_0000), - #[cfg(target_arch = "aarch64")] - (0xF000_0000, 0x1000_0000), - #[cfg(target_arch = "aarch64")] - (512 << 30, 512 << 30), - 16, - ))) - } - #[test] fn test_find_attached_bus() { let pci_host = create_pci_host(); -- Gitee From a2b57d1a68390479411d8d0cf4ff7bfc5ec14a75 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sat, 15 Jun 2024 10:15:03 +0800 Subject: [PATCH 132/489] util: add `gen_base_func` macro to replace duplicate code Now, there exist many duplicate codes to get `base` such as `virtio_base`/`device_base`/`machine_base`/`sysbusdev_base`. Use unified macro `gen_base_func` to generate these code. Signed-off-by: liuxiangdong --- devices/src/acpi/cpu_controller.rs | 17 ++------- devices/src/acpi/ged.rs | 23 ++++-------- devices/src/acpi/power.rs | 17 ++------- devices/src/legacy/fwcfg.rs | 34 +++--------------- devices/src/legacy/pflash.rs | 17 ++------- devices/src/legacy/pl011.rs | 17 ++------- devices/src/legacy/pl031.rs | 17 ++------- devices/src/legacy/ramfb.rs | 17 ++------- devices/src/legacy/rtc.rs | 17 ++------- devices/src/legacy/serial.rs | 17 ++------- devices/src/misc/ivshmem.rs | 17 ++------- devices/src/misc/pvpanic.rs | 17 ++------- devices/src/pci/bus.rs | 17 ++------- devices/src/pci/demo_device/mod.rs | 17 ++------- devices/src/pci/host.rs | 33 +++-------------- devices/src/pci/mod.rs | 17 ++------- devices/src/pci/root_port.rs | 23 +++--------- devices/src/scsi/disk.rs | 9 ++--- devices/src/usb/camera.rs | 9 ++--- devices/src/usb/keyboard.rs | 9 ++--- devices/src/usb/storage.rs | 9 ++--- devices/src/usb/tablet.rs | 9 ++--- devices/src/usb/uas.rs | 9 ++--- devices/src/usb/usbhost/mod.rs | 19 ++++------ devices/src/usb/xhci/xhci_pci.rs | 17 ++------- machine/src/aarch64/micro.rs | 15 +++----- machine/src/aarch64/pci_host_root.rs | 17 ++------- machine/src/aarch64/standard.rs | 10 ++---- machine/src/x86_64/ich9_lpc.rs | 17 ++------- machine/src/x86_64/mch.rs | 17 ++------- machine/src/x86_64/micro.rs | 9 ++--- machine/src/x86_64/standard.rs | 18 +++------- util/src/lib.rs | 54 ++++++++++++++++++++++++++++ vfio/src/vfio_pci.rs | 17 ++------- virtio/src/device/balloon.rs | 26 +++++--------- virtio/src/device/block.rs | 10 ++---- virtio/src/device/gpu.rs | 9 ++--- virtio/src/device/net.rs | 14 +++----- virtio/src/device/rng.rs | 9 ++--- virtio/src/device/scsi_cntlr.rs | 9 ++--- virtio/src/device/serial.rs | 9 ++--- virtio/src/transport/virtio_mmio.rs | 25 +++---------- virtio/src/transport/virtio_pci.rs | 29 +++------------ virtio/src/vhost/kernel/net.rs | 9 ++--- virtio/src/vhost/kernel/vsock.rs | 9 ++--- virtio/src/vhost/user/block.rs | 9 ++--- virtio/src/vhost/user/fs.rs | 9 ++--- virtio/src/vhost/user/net.rs | 9 ++--- 48 files changed, 203 insertions(+), 580 deletions(-) diff --git a/devices/src/acpi/cpu_controller.rs b/devices/src/acpi/cpu_controller.rs index 4fe256c6..c3052f61 100644 --- a/devices/src/acpi/cpu_controller.rs +++ b/devices/src/acpi/cpu_controller.rs @@ -32,6 +32,7 @@ use acpi::{ use address_space::GuestAddress; use cpu::{CPUBootConfig, CPUInterface, CPUTopology, CpuLifecycleState, CPU}; use migration::MigrationManager; +use util::gen_base_func; const CPU_ENABLE_FLAG: u8 = 1; const CPU_INSERTING_FLAG: u8 = 2; @@ -242,23 +243,11 @@ impl CpuController { } impl Device for CpuController { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl SysBusDevOps for CpuController { - fn sysbusdev_base(&self) -> &SysBusDevBase { - &self.base - } - - fn sysbusdev_base_mut(&mut self) -> &mut SysBusDevBase { - &mut self.base - } + gen_base_func!(sysbusdev_base, sysbusdev_base_mut, SysBusDevBase, base); fn read(&mut self, data: &mut [u8], _base: GuestAddress, offset: u64) -> bool { data[0] = 0; diff --git a/devices/src/acpi/ged.rs b/devices/src/acpi/ged.rs index ea6c52da..fe153842 100644 --- a/devices/src/acpi/ged.rs +++ b/devices/src/acpi/ged.rs @@ -35,8 +35,11 @@ use address_space::GuestAddress; use machine_manager::event; use machine_manager::event_loop::EventLoop; use machine_manager::qmp::qmp_channel::QmpChannel; -use util::loop_context::{create_new_eventfd, read_fd, EventNotifier, NotifierOperation}; -use util::{loop_context::NotifierCallback, num_ops::write_data_u32}; +use util::gen_base_func; +use util::loop_context::{ + create_new_eventfd, read_fd, EventNotifier, NotifierCallback, NotifierOperation, +}; +use util::num_ops::write_data_u32; #[derive(Clone, Copy)] pub enum AcpiEvent { @@ -181,23 +184,11 @@ impl Ged { } impl Device for Ged { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl SysBusDevOps for Ged { - fn sysbusdev_base(&self) -> &SysBusDevBase { - &self.base - } - - fn sysbusdev_base_mut(&mut self) -> &mut SysBusDevBase { - &mut self.base - } + gen_base_func!(sysbusdev_base, sysbusdev_base_mut, SysBusDevBase, base); fn read(&mut self, data: &mut [u8], _base: GuestAddress, offset: u64) -> bool { if offset != 0 { diff --git a/devices/src/acpi/power.rs b/devices/src/acpi/power.rs index d64486fc..8669e8b3 100644 --- a/devices/src/acpi/power.rs +++ b/devices/src/acpi/power.rs @@ -30,6 +30,7 @@ use machine_manager::event_loop::EventLoop; use migration::{DeviceStateDesc, FieldDesc, MigrationHook, MigrationManager, StateTransfer}; use migration_derive::{ByteCode, Desc}; use util::byte_code::ByteCode; +use util::gen_base_func; use util::num_ops::write_data_u32; const AML_ACAD_REG: &str = "ADPM"; @@ -231,23 +232,11 @@ impl MigrationHook for PowerDev { } impl Device for PowerDev { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl SysBusDevOps for PowerDev { - fn sysbusdev_base(&self) -> &SysBusDevBase { - &self.base - } - - fn sysbusdev_base_mut(&mut self) -> &mut SysBusDevBase { - &mut self.base - } + gen_base_func!(sysbusdev_base, sysbusdev_base_mut, SysBusDevBase, base); fn read(&mut self, data: &mut [u8], _base: GuestAddress, offset: u64) -> bool { let reg_idx: u64 = offset / 4; diff --git a/devices/src/legacy/fwcfg.rs b/devices/src/legacy/fwcfg.rs index ad3e3f3e..5e587f6e 100644 --- a/devices/src/legacy/fwcfg.rs +++ b/devices/src/legacy/fwcfg.rs @@ -31,7 +31,7 @@ use acpi::{AmlMemory32Fixed, AmlReadAndWrite}; use address_space::{AddressSpace, GuestAddress}; use util::byte_code::ByteCode; use util::num_ops::extract_u64; -use util::offset_of; +use util::{gen_base_func, offset_of}; #[cfg(target_arch = "x86_64")] const FW_CFG_IO_BASE: u64 = 0x510; @@ -931,24 +931,12 @@ impl FwCfgOps for FwCfgMem { #[cfg(target_arch = "aarch64")] impl Device for FwCfgMem { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } #[cfg(target_arch = "aarch64")] impl SysBusDevOps for FwCfgMem { - fn sysbusdev_base(&self) -> &SysBusDevBase { - &self.base - } - - fn sysbusdev_base_mut(&mut self) -> &mut SysBusDevBase { - &mut self.base - } + gen_base_func!(sysbusdev_base, sysbusdev_base_mut, SysBusDevBase, base); fn read(&mut self, data: &mut [u8], base: GuestAddress, offset: u64) -> bool { common_read(self, data, base, offset) @@ -1098,24 +1086,12 @@ impl FwCfgOps for FwCfgIO { #[cfg(target_arch = "x86_64")] impl Device for FwCfgIO { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } #[cfg(target_arch = "x86_64")] impl SysBusDevOps for FwCfgIO { - fn sysbusdev_base(&self) -> &SysBusDevBase { - &self.base - } - - fn sysbusdev_base_mut(&mut self) -> &mut SysBusDevBase { - &mut self.base - } + gen_base_func!(sysbusdev_base, sysbusdev_base_mut, SysBusDevBase, base); fn read(&mut self, data: &mut [u8], base: GuestAddress, offset: u64) -> bool { common_read(self, data, base, offset) diff --git a/devices/src/legacy/pflash.rs b/devices/src/legacy/pflash.rs index 747d22b9..2db2ce22 100644 --- a/devices/src/legacy/pflash.rs +++ b/devices/src/legacy/pflash.rs @@ -22,6 +22,7 @@ use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; use crate::{Device, DeviceBase}; use acpi::AmlBuilder; use address_space::{FileBackend, GuestAddress, HostMemMapping, Region}; +use util::gen_base_func; use util::num_ops::{deposit_u32, extract_u32, read_data_u32, round_up, write_data_u32}; use util::unix::host_page_size; @@ -691,23 +692,11 @@ impl PFlash { } impl Device for PFlash { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl SysBusDevOps for PFlash { - fn sysbusdev_base(&self) -> &SysBusDevBase { - &self.base - } - - fn sysbusdev_base_mut(&mut self) -> &mut SysBusDevBase { - &mut self.base - } + gen_base_func!(sysbusdev_base, sysbusdev_base_mut, SysBusDevBase, base); fn read(&mut self, data: &mut [u8], _base: GuestAddress, offset: u64) -> bool { let mut index: u64; diff --git a/devices/src/legacy/pl011.rs b/devices/src/legacy/pl011.rs index f5fdafae..2a6cab1c 100644 --- a/devices/src/legacy/pl011.rs +++ b/devices/src/legacy/pl011.rs @@ -35,6 +35,7 @@ use migration::{ }; use migration_derive::{ByteCode, Desc}; use util::byte_code::ByteCode; +use util::gen_base_func; use util::loop_context::{create_new_eventfd, EventNotifierHelper}; use util::num_ops::read_data_u32; @@ -236,23 +237,11 @@ impl InputReceiver for PL011 { } impl Device for PL011 { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl SysBusDevOps for PL011 { - fn sysbusdev_base(&self) -> &SysBusDevBase { - &self.base - } - - fn sysbusdev_base_mut(&mut self) -> &mut SysBusDevBase { - &mut self.base - } + gen_base_func!(sysbusdev_base, sysbusdev_base_mut, SysBusDevBase, base); fn read(&mut self, data: &mut [u8], _base: GuestAddress, offset: u64) -> bool { if data.len() > 4 { diff --git a/devices/src/legacy/pl031.rs b/devices/src/legacy/pl031.rs index 9ad650b0..98a35196 100644 --- a/devices/src/legacy/pl031.rs +++ b/devices/src/legacy/pl031.rs @@ -27,6 +27,7 @@ use migration::{ }; use migration_derive::{ByteCode, Desc}; use util::byte_code::ByteCode; +use util::gen_base_func; use util::loop_context::create_new_eventfd; use util::num_ops::write_data_u32; @@ -123,23 +124,11 @@ impl PL031 { } impl Device for PL031 { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl SysBusDevOps for PL031 { - fn sysbusdev_base(&self) -> &SysBusDevBase { - &self.base - } - - fn sysbusdev_base_mut(&mut self) -> &mut SysBusDevBase { - &mut self.base - } + gen_base_func!(sysbusdev_base, sysbusdev_base_mut, SysBusDevBase, base); /// Read data from registers by guest. fn read(&mut self, data: &mut [u8], _base: GuestAddress, offset: u64) -> bool { diff --git a/devices/src/legacy/ramfb.rs b/devices/src/legacy/ramfb.rs index 3945de43..278fd8e7 100644 --- a/devices/src/legacy/ramfb.rs +++ b/devices/src/legacy/ramfb.rs @@ -32,6 +32,7 @@ use ui::console::{ DisplaySurface, HardWareOperations, }; use ui::input::{key_event, KEYCODE_RET}; +use util::gen_base_func; use util::pixman::{pixman_format_bpp, pixman_format_code_t, pixman_image_create_bits}; const BYTES_PER_PIXELS: u32 = 8; @@ -258,23 +259,11 @@ impl Ramfb { } impl Device for Ramfb { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl SysBusDevOps for Ramfb { - fn sysbusdev_base(&self) -> &SysBusDevBase { - &self.base - } - - fn sysbusdev_base_mut(&mut self) -> &mut SysBusDevBase { - &mut self.base - } + gen_base_func!(sysbusdev_base, sysbusdev_base_mut, SysBusDevBase, base); fn read(&mut self, _data: &mut [u8], _base: GuestAddress, _offset: u64) -> bool { error!("Ramfb can not be read!"); diff --git a/devices/src/legacy/rtc.rs b/devices/src/legacy/rtc.rs index 1e498084..259ac981 100644 --- a/devices/src/legacy/rtc.rs +++ b/devices/src/legacy/rtc.rs @@ -23,6 +23,7 @@ use acpi::{ AmlResTemplate, AmlScopeBuilder, }; use address_space::GuestAddress; +use util::gen_base_func; use util::loop_context::create_new_eventfd; use util::time::{mktime64, NANOSECONDS_PER_SECOND}; @@ -351,23 +352,11 @@ impl RTC { } impl Device for RTC { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl SysBusDevOps for RTC { - fn sysbusdev_base(&self) -> &SysBusDevBase { - &self.base - } - - fn sysbusdev_base_mut(&mut self) -> &mut SysBusDevBase { - &mut self.base - } + gen_base_func!(sysbusdev_base, sysbusdev_base_mut, SysBusDevBase, base); fn read(&mut self, data: &mut [u8], base: GuestAddress, offset: u64) -> bool { if offset == 0 { diff --git a/devices/src/legacy/serial.rs b/devices/src/legacy/serial.rs index 520e929c..3386f7ff 100644 --- a/devices/src/legacy/serial.rs +++ b/devices/src/legacy/serial.rs @@ -33,6 +33,7 @@ use migration::{ }; use migration_derive::{ByteCode, Desc}; use util::byte_code::ByteCode; +use util::gen_base_func; use util::loop_context::{create_new_eventfd, EventNotifierHelper}; pub const SERIAL_ADDR: u64 = 0x3f8; @@ -371,23 +372,11 @@ impl InputReceiver for Serial { } impl Device for Serial { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl SysBusDevOps for Serial { - fn sysbusdev_base(&self) -> &SysBusDevBase { - &self.base - } - - fn sysbusdev_base_mut(&mut self) -> &mut SysBusDevBase { - &mut self.base - } + gen_base_func!(sysbusdev_base, sysbusdev_base_mut, SysBusDevBase, base); fn read(&mut self, data: &mut [u8], _base: GuestAddress, offset: u64) -> bool { data[0] = self.read_internal(offset); diff --git a/devices/src/misc/ivshmem.rs b/devices/src/misc/ivshmem.rs index e5c7cd74..cc9e383f 100644 --- a/devices/src/misc/ivshmem.rs +++ b/devices/src/misc/ivshmem.rs @@ -26,6 +26,7 @@ use crate::pci::{ }; use crate::{Device, DeviceBase}; use address_space::{GuestAddress, Region, RegionOps}; +use util::gen_base_func; const PCI_VENDOR_ID_IVSHMEM: u16 = PCI_VENDOR_ID_REDHAT_QUMRANET; const PCI_DEVICE_ID_IVSHMEM: u16 = 0x1110; @@ -92,23 +93,11 @@ impl Ivshmem { } impl Device for Ivshmem { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl PciDevOps for Ivshmem { - fn pci_base(&self) -> &PciDevBase { - &self.base - } - - fn pci_base_mut(&mut self) -> &mut PciDevBase { - &mut self.base - } + gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); fn realize(mut self) -> Result<()> { self.init_write_mask(false)?; diff --git a/devices/src/misc/pvpanic.rs b/devices/src/misc/pvpanic.rs index a6597954..cdebea6c 100644 --- a/devices/src/misc/pvpanic.rs +++ b/devices/src/misc/pvpanic.rs @@ -32,6 +32,7 @@ use crate::pci::{ use crate::{Device, DeviceBase}; use address_space::{GuestAddress, Region, RegionOps}; use machine_manager::config::{get_pci_df, valid_id}; +use util::gen_base_func; const PVPANIC_PCI_REVISION_ID: u8 = 1; const PVPANIC_PCI_VENDOR_ID: u16 = PCI_VENDOR_ID_REDHAT_QUMRANET; @@ -166,23 +167,11 @@ impl PvPanicPci { } impl Device for PvPanicPci { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl PciDevOps for PvPanicPci { - fn pci_base(&self) -> &PciDevBase { - &self.base - } - - fn pci_base_mut(&mut self) -> &mut PciDevBase { - &mut self.base - } + gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); fn realize(mut self) -> Result<()> { self.init_write_mask(false)?; diff --git a/devices/src/pci/bus.rs b/devices/src/pci/bus.rs index 3acc5250..1141afe9 100644 --- a/devices/src/pci/bus.rs +++ b/devices/src/pci/bus.rs @@ -278,6 +278,7 @@ mod tests { use crate::pci::root_port::RootPort; use crate::pci::{PciDevBase, RootPortConfig}; use crate::{Device, DeviceBase}; + use util::gen_base_func; #[derive(Clone)] struct PciDevice { @@ -285,23 +286,11 @@ mod tests { } impl Device for PciDevice { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl PciDevOps for PciDevice { - fn pci_base(&self) -> &PciDevBase { - &self.base - } - - fn pci_base_mut(&mut self) -> &mut PciDevBase { - &mut self.base - } + gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); fn write_config(&mut self, offset: usize, data: &[u8]) { #[allow(unused_variables)] diff --git a/devices/src/pci/demo_device/mod.rs b/devices/src/pci/demo_device/mod.rs index ff35f475..987120c3 100644 --- a/devices/src/pci/demo_device/mod.rs +++ b/devices/src/pci/demo_device/mod.rs @@ -59,6 +59,7 @@ use crate::pci::{demo_device::base_device::BaseDevice, PciDevBase}; use crate::{Device, DeviceBase}; use address_space::{AddressSpace, GuestAddress, Region, RegionOps}; use machine_manager::config::{get_pci_df, valid_id}; +use util::gen_base_func; /// Config struct for `demo_dev`. /// Contains demo_dev device's attr. @@ -195,23 +196,11 @@ const DEVICE_ID_DEMO: u16 = 0xBEEF; const CLASS_CODE_DEMO: u16 = 0xEE; impl Device for DemoDev { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl PciDevOps for DemoDev { - fn pci_base(&self) -> &PciDevBase { - &self.base - } - - fn pci_base_mut(&mut self) -> &mut PciDevBase { - &mut self.base - } + gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); /// Realize PCI/PCIe device. fn realize(mut self) -> Result<()> { diff --git a/devices/src/pci/host.rs b/devices/src/pci/host.rs index f3957156..8bcaee72 100644 --- a/devices/src/pci/host.rs +++ b/devices/src/pci/host.rs @@ -34,6 +34,7 @@ use acpi::{AmlIoDecode, AmlIoResource}; #[cfg(target_arch = "aarch64")] use acpi::{AmlOne, AmlQWordDesc}; use address_space::{AddressSpace, GuestAddress, RegionOps}; +use util::gen_base_func; #[cfg(target_arch = "x86_64")] const CONFIG_ADDRESS_ENABLE_MASK: u32 = 0x8000_0000; @@ -231,23 +232,11 @@ impl PciHost { } impl Device for PciHost { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl SysBusDevOps for PciHost { - fn sysbusdev_base(&self) -> &SysBusDevBase { - &self.base - } - - fn sysbusdev_base_mut(&mut self) -> &mut SysBusDevBase { - &mut self.base - } + gen_base_func!(sysbusdev_base, sysbusdev_base_mut, SysBusDevBase, base); fn read(&mut self, data: &mut [u8], _base: GuestAddress, offset: u64) -> bool { let bus_num = ((offset as u32 >> ECAM_BUS_SHIFT) & CONFIG_BUS_MASK) as u8; @@ -557,23 +546,11 @@ pub mod tests { } impl Device for PciDevice { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl PciDevOps for PciDevice { - fn pci_base(&self) -> &PciDevBase { - &self.base - } - - fn pci_base_mut(&mut self) -> &mut PciDevBase { - &mut self.base - } + gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); fn init_write_mask(&mut self, _is_bridge: bool) -> Result<()> { let mut offset = 0_usize; diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs index 7a90d6ea..13da0346 100644 --- a/devices/src/pci/mod.rs +++ b/devices/src/pci/mod.rs @@ -406,6 +406,7 @@ mod tests { use super::*; use crate::DeviceBase; use address_space::{AddressSpace, Region}; + use util::gen_base_func; #[test] fn test_le_write_u16_01() { @@ -453,23 +454,11 @@ mod tests { } impl Device for PciDev { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl PciDevOps for PciDev { - fn pci_base(&self) -> &PciDevBase { - &self.base - } - - fn pci_base_mut(&mut self) -> &mut PciDevBase { - &mut self.base - } + gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); fn write_config(&mut self, _offset: usize, _data: &[u8]) {} diff --git a/devices/src/pci/root_port.rs b/devices/src/pci/root_port.rs index 6396c0ce..9d3bcf25 100644 --- a/devices/src/pci/root_port.rs +++ b/devices/src/pci/root_port.rs @@ -46,10 +46,9 @@ use migration::{ DeviceStateDesc, FieldDesc, MigrationError, MigrationHook, MigrationManager, StateTransfer, }; use migration_derive::{ByteCode, Desc}; -use util::{ - byte_code::ByteCode, - num_ops::{ranges_overlap, str_to_num}, -}; +use util::byte_code::ByteCode; +use util::gen_base_func; +use util::num_ops::{ranges_overlap, str_to_num}; const DEVICE_ID_RP: u16 = 0x000c; @@ -345,23 +344,11 @@ impl RootPort { } impl Device for RootPort { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl PciDevOps for RootPort { - fn pci_base(&self) -> &PciDevBase { - &self.base - } - - fn pci_base_mut(&mut self) -> &mut PciDevBase { - &mut self.base - } + gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); fn realize(mut self) -> Result<()> { self.init_write_mask(true)?; diff --git a/devices/src/scsi/disk.rs b/devices/src/scsi/disk.rs index 37aca3da..178250a4 100644 --- a/devices/src/scsi/disk.rs +++ b/devices/src/scsi/disk.rs @@ -22,6 +22,7 @@ use block_backend::{create_block_backend, BlockDriverOps, BlockProperty}; use machine_manager::config::{valid_id, DriveConfig, DriveFile, VmConfig}; use machine_manager::event_loop::EventLoop; use util::aio::{Aio, AioEngine, WriteZeroesState}; +use util::gen_base_func; /// SCSI DEVICE TYPES. pub const SCSI_TYPE_DISK: u32 = 0x00; @@ -131,13 +132,7 @@ impl ScsiDevState { } impl Device for ScsiDevice { - fn device_base(&self) -> &DeviceBase { - &self.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base); } pub struct ScsiDevice { diff --git a/devices/src/usb/camera.rs b/devices/src/usb/camera.rs index 79cc1ba5..fccd0a17 100644 --- a/devices/src/usb/camera.rs +++ b/devices/src/usb/camera.rs @@ -40,6 +40,7 @@ use machine_manager::config::valid_id; use machine_manager::event_loop::{register_event_helper, unregister_event_helper}; use util::aio::{iov_discard_front_direct, Iovec}; use util::byte_code::ByteCode; +use util::gen_base_func; use util::loop_context::{ create_new_eventfd, read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, @@ -750,13 +751,7 @@ impl UsbCamera { } impl UsbDevice for UsbCamera { - fn usb_device_base(&self) -> &UsbDeviceBase { - &self.base - } - - fn usb_device_base_mut(&mut self) -> &mut UsbDeviceBase { - &mut self.base - } + gen_base_func!(usb_device_base, usb_device_base_mut, UsbDeviceBase, base); fn realize(mut self) -> Result>> { let fmt_list = self.camera_backend.lock().unwrap().list_format()?; diff --git a/devices/src/usb/keyboard.rs b/devices/src/usb/keyboard.rs index 53291427..214ade86 100644 --- a/devices/src/usb/keyboard.rs +++ b/devices/src/usb/keyboard.rs @@ -30,6 +30,7 @@ use super::{ }; use machine_manager::config::valid_id; use ui::input::{register_keyboard, unregister_keyboard, KeyboardOpts}; +use util::gen_base_func; /// Keyboard device descriptor static DESC_DEVICE_KEYBOARD: Lazy> = Lazy::new(|| { @@ -189,13 +190,7 @@ impl UsbKeyboard { } impl UsbDevice for UsbKeyboard { - fn usb_device_base(&self) -> &UsbDeviceBase { - &self.base - } - - fn usb_device_base_mut(&mut self) -> &mut UsbDeviceBase { - &mut self.base - } + gen_base_func!(usb_device_base, usb_device_base_mut, UsbDeviceBase, base); fn realize(mut self) -> Result>> { self.base.reset_usb_endpoint(); diff --git a/devices/src/usb/storage.rs b/devices/src/usb/storage.rs index 2f924d8a..67c03488 100644 --- a/devices/src/usb/storage.rs +++ b/devices/src/usb/storage.rs @@ -37,6 +37,7 @@ use crate::{ }; use machine_manager::config::{DriveConfig, DriveFile}; use util::aio::AioEngine; +use util::gen_base_func; // Storage device descriptor static DESC_DEVICE_STORAGE: Lazy> = Lazy::new(|| { @@ -541,13 +542,7 @@ impl UsbStorage { } impl UsbDevice for UsbStorage { - fn usb_device_base(&self) -> &UsbDeviceBase { - &self.base - } - - fn usb_device_base_mut(&mut self) -> &mut UsbDeviceBase { - &mut self.base - } + gen_base_func!(usb_device_base, usb_device_base_mut, UsbDeviceBase, base); fn realize(mut self) -> Result>> { self.base.reset_usb_endpoint(); diff --git a/devices/src/usb/tablet.rs b/devices/src/usb/tablet.rs index a4bfebf4..78551cb8 100644 --- a/devices/src/usb/tablet.rs +++ b/devices/src/usb/tablet.rs @@ -34,6 +34,7 @@ use ui::input::{ INPUT_BUTTON_MASK, INPUT_BUTTON_WHEEL_DOWN, INPUT_BUTTON_WHEEL_LEFT, INPUT_BUTTON_WHEEL_RIGHT, INPUT_BUTTON_WHEEL_UP, }; +use util::gen_base_func; const INPUT_COORDINATES_MAX: u32 = 0x7fff; @@ -233,13 +234,7 @@ impl PointerOpts for UsbTabletAdapter { } impl UsbDevice for UsbTablet { - fn usb_device_base(&self) -> &UsbDeviceBase { - &self.base - } - - fn usb_device_base_mut(&mut self) -> &mut UsbDeviceBase { - &mut self.base - } + gen_base_func!(usb_device_base, usb_device_base_mut, UsbDeviceBase, base); fn realize(mut self) -> Result>> { self.base.reset_usb_endpoint(); diff --git a/devices/src/usb/uas.rs b/devices/src/usb/uas.rs index 4bdfc398..e913ca5c 100644 --- a/devices/src/usb/uas.rs +++ b/devices/src/usb/uas.rs @@ -44,6 +44,7 @@ use crate::{ }; use machine_manager::config::{DriveConfig, DriveFile}; use util::byte_code::ByteCode; +use util::gen_base_func; // Size of UasIUBody const UAS_IU_BODY_SIZE: usize = 30; @@ -1025,13 +1026,7 @@ impl UsbUas { } impl UsbDevice for UsbUas { - fn usb_device_base(&self) -> &UsbDeviceBase { - &self.base - } - - fn usb_device_base_mut(&mut self) -> &mut UsbDeviceBase { - &mut self.base - } + gen_base_func!(usb_device_base, usb_device_base_mut, UsbDeviceBase, base); fn realize(mut self) -> Result>> { info!("UAS {} device realize.", self.device_id()); diff --git a/devices/src/usb/usbhost/mod.rs b/devices/src/usb/usbhost/mod.rs index 3da8cf05..65e05112 100644 --- a/devices/src/usb/usbhost/mod.rs +++ b/devices/src/usb/usbhost/mod.rs @@ -56,12 +56,11 @@ use machine_manager::{ }; #[cfg(all(target_arch = "aarch64", target_env = "ohos"))] use ohusb::OhUsbDev; -use util::{ - byte_code::ByteCode, - link_list::{List, Node}, - loop_context::{EventNotifier, EventNotifierHelper, NotifierCallback}, - num_ops::str_to_num, -}; +use util::byte_code::ByteCode; +use util::gen_base_func; +use util::link_list::{List, Node}; +use util::loop_context::{EventNotifier, EventNotifierHelper, NotifierCallback}; +use util::num_ops::str_to_num; const NON_ISO_PACKETS_NUMS: c_int = 0; const HANDLE_TIMEOUT_MS: u64 = 2; @@ -1050,13 +1049,7 @@ impl EventNotifierHelper for UsbHost { } impl UsbDevice for UsbHost { - fn usb_device_base(&self) -> &UsbDeviceBase { - &self.base - } - - fn usb_device_base_mut(&mut self) -> &mut UsbDeviceBase { - &mut self.base - } + gen_base_func!(usb_device_base, usb_device_base_mut, UsbDeviceBase, base); fn realize(mut self) -> Result>> { info!("Open and init usbhost device: {:?}", self.config); diff --git a/devices/src/usb/xhci/xhci_pci.rs b/devices/src/usb/xhci/xhci_pci.rs index 0e8ffd23..8a7208e6 100644 --- a/devices/src/usb/xhci/xhci_pci.rs +++ b/devices/src/usb/xhci/xhci_pci.rs @@ -38,6 +38,7 @@ use crate::{Device, DeviceBase}; use address_space::{AddressRange, AddressSpace, Region, RegionIoEventFd}; use machine_manager::config::{get_pci_df, valid_id}; use machine_manager::event_loop::register_event_helper; +use util::gen_base_func; use util::loop_context::{ create_new_eventfd, read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, @@ -237,23 +238,11 @@ impl XhciPciDevice { } impl Device for XhciPciDevice { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl PciDevOps for XhciPciDevice { - fn pci_base(&self) -> &PciDevBase { - &self.base - } - - fn pci_base_mut(&mut self) -> &mut PciDevBase { - &mut self.base - } + gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); fn realize(mut self) -> Result<()> { self.init_write_mask(false)?; diff --git a/machine/src/aarch64/micro.rs b/machine/src/aarch64/micro.rs index 40c8baff..39fed7e4 100644 --- a/machine/src/aarch64/micro.rs +++ b/machine/src/aarch64/micro.rs @@ -22,10 +22,9 @@ use devices::{legacy::PL031, ICGICConfig, ICGICv2Config, ICGICv3Config, GIC_IRQ_ use hypervisor::kvm::aarch64::*; use machine_manager::config::{SerialConfig, VmConfig}; use migration::{MigrationManager, MigrationStatus}; -use util::{ - device_tree::{self, CompileFDT, FdtBuilder}, - seccomp::{BpfRule, SeccompCmpOpt}, -}; +use util::device_tree::{self, CompileFDT, FdtBuilder}; +use util::gen_base_func; +use util::seccomp::{BpfRule, SeccompCmpOpt}; use virtio::{VirtioDevice, VirtioMmioDevice}; #[repr(usize)] @@ -54,13 +53,7 @@ pub const MEM_LAYOUT: &[(u64, u64)] = &[ ]; impl MachineOps for LightMachine { - fn machine_base(&self) -> &MachineBase { - &self.base - } - - fn machine_base_mut(&mut self) -> &mut MachineBase { - &mut self.base - } + gen_base_func!(machine_base, machine_base_mut, MachineBase, base); fn init_machine_ram(&self, sys_mem: &Arc, mem_size: u64) -> Result<()> { let vm_ram = self.get_vm_ram(); diff --git a/machine/src/aarch64/pci_host_root.rs b/machine/src/aarch64/pci_host_root.rs index aec54023..512cf8f3 100644 --- a/machine/src/aarch64/pci_host_root.rs +++ b/machine/src/aarch64/pci_host_root.rs @@ -22,6 +22,7 @@ use devices::pci::{ le_write_u16, PciBus, PciDevBase, PciDevOps, }; use devices::{Device, DeviceBase}; +use util::gen_base_func; const DEVICE_ID_PCIE_HOST: u16 = 0x0008; @@ -44,23 +45,11 @@ impl PciHostRoot { } impl Device for PciHostRoot { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl PciDevOps for PciHostRoot { - fn pci_base(&self) -> &PciDevBase { - &self.base - } - - fn pci_base_mut(&mut self) -> &mut PciDevBase { - &mut self.base - } + gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); fn realize(mut self) -> Result<()> { self.init_write_mask(false)?; diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index 4b6eebdf..cec804b6 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -83,7 +83,7 @@ use util::byte_code::ByteCode; use util::device_tree::{self, CompileFDT, FdtBuilder}; use util::loop_context::{create_new_eventfd, EventLoopManager}; use util::seccomp::{BpfRule, SeccompCmpOpt}; -use util::set_termi_canon_mode; +use util::{gen_base_func, set_termi_canon_mode}; /// The type of memory layout entry on aarch64 pub enum LayoutEntryType { @@ -446,13 +446,7 @@ impl StdMachineOps for StdMachine { } impl MachineOps for StdMachine { - fn machine_base(&self) -> &MachineBase { - &self.base - } - - fn machine_base_mut(&mut self) -> &mut MachineBase { - &mut self.base - } + gen_base_func!(machine_base, machine_base_mut, MachineBase, base); fn init_machine_ram(&self, sys_mem: &Arc, mem_size: u64) -> Result<()> { let vm_ram = self.get_vm_ram(); diff --git a/machine/src/x86_64/ich9_lpc.rs b/machine/src/x86_64/ich9_lpc.rs index 0a93312e..4038e503 100644 --- a/machine/src/x86_64/ich9_lpc.rs +++ b/machine/src/x86_64/ich9_lpc.rs @@ -29,6 +29,7 @@ use devices::pci::config::{ use devices::pci::{le_write_u16, le_write_u32, PciBus, PciDevBase, PciDevOps}; use devices::{Device, DeviceBase}; use util::byte_code::ByteCode; +use util::gen_base_func; use util::num_ops::ranges_overlap; const DEVICE_ID_INTEL_ICH9: u16 = 0x2918; @@ -229,23 +230,11 @@ impl LPCBridge { } impl Device for LPCBridge { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl PciDevOps for LPCBridge { - fn pci_base(&self) -> &PciDevBase { - &self.base - } - - fn pci_base_mut(&mut self) -> &mut PciDevBase { - &mut self.base - } + gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); fn realize(mut self) -> Result<()> { self.init_write_mask(false)?; diff --git a/machine/src/x86_64/mch.rs b/machine/src/x86_64/mch.rs index 5c6f593e..ddf7bd67 100644 --- a/machine/src/x86_64/mch.rs +++ b/machine/src/x86_64/mch.rs @@ -25,6 +25,7 @@ use devices::pci::{ le_read_u64, le_write_u16, PciBus, PciDevBase, PciDevOps, }; use devices::{Device, DeviceBase}; +use util::gen_base_func; use util::num_ops::ranges_overlap; const DEVICE_ID_INTEL_Q35_MCH: u16 = 0x29c0; @@ -121,23 +122,11 @@ impl Mch { } impl Device for Mch { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl PciDevOps for Mch { - fn pci_base(&self) -> &PciDevBase { - &self.base - } - - fn pci_base_mut(&mut self) -> &mut PciDevBase { - &mut self.base - } + gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); fn realize(mut self) -> Result<()> { self.init_write_mask(false)?; diff --git a/machine/src/x86_64/micro.rs b/machine/src/x86_64/micro.rs index e5d17ce5..219df0bd 100644 --- a/machine/src/x86_64/micro.rs +++ b/machine/src/x86_64/micro.rs @@ -24,6 +24,7 @@ use hypervisor::kvm::x86_64::*; use hypervisor::kvm::*; use machine_manager::config::{SerialConfig, VmConfig}; use migration::{MigrationManager, MigrationStatus}; +use util::gen_base_func; use util::seccomp::{BpfRule, SeccompCmpOpt}; use virtio::{VirtioDevice, VirtioMmioDevice}; @@ -47,13 +48,7 @@ pub const MEM_LAYOUT: &[(u64, u64)] = &[ ]; impl MachineOps for LightMachine { - fn machine_base(&self) -> &MachineBase { - &self.base - } - - fn machine_base_mut(&mut self) -> &mut MachineBase { - &mut self.base - } + gen_base_func!(machine_base, machine_base_mut, MachineBase, base); fn init_machine_ram(&self, sys_mem: &Arc, mem_size: u64) -> Result<()> { let vm_ram = self.get_vm_ram(); diff --git a/machine/src/x86_64/standard.rs b/machine/src/x86_64/standard.rs index 8dca2db7..e31d6929 100644 --- a/machine/src/x86_64/standard.rs +++ b/machine/src/x86_64/standard.rs @@ -59,13 +59,11 @@ use migration::{MigrationManager, MigrationStatus}; use ui::gtk::gtk_display_init; #[cfg(feature = "vnc")] use ui::vnc::vnc_init; +use util::byte_code::ByteCode; +use util::loop_context::{create_new_eventfd, EventLoopManager}; +use util::seccomp::BpfRule; use util::seccomp::SeccompCmpOpt; -use util::{ - byte_code::ByteCode, - loop_context::{create_new_eventfd, EventLoopManager}, - seccomp::BpfRule, - set_termi_canon_mode, -}; +use util::{gen_base_func, set_termi_canon_mode}; pub(crate) const VENDOR_ID_INTEL: u16 = 0x8086; const HOLE_640K_START: u64 = 0x000A_0000; @@ -419,13 +417,7 @@ impl StdMachineOps for StdMachine { } impl MachineOps for StdMachine { - fn machine_base(&self) -> &MachineBase { - &self.base - } - - fn machine_base_mut(&mut self) -> &mut MachineBase { - &mut self.base - } + gen_base_func!(machine_base, machine_base_mut, MachineBase, base); fn init_machine_ram(&self, sys_mem: &Arc, mem_size: u64) -> Result<()> { let ram = self.get_vm_ram(); diff --git a/util/src/lib.rs b/util/src/lib.rs index f861d6f6..a33cab3c 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -95,6 +95,60 @@ pub fn set_termi_canon_mode() -> std::io::Result<()> { Ok(()) } +/// Macro: Generate base getting function. +/// +/// # Arguments +/// +/// * `get_func` - Name of getting `&base` function. +/// * `get_mut_func` - Name of getting `&mut base` function. +/// * `base_type` - Type of `base`. +/// * `base` - `base` in self. +/// +/// # Examples +/// +/// ```rust +/// use util::gen_base_func; +/// struct TestBase(u8); +/// struct Test { +/// base: TestBase, +/// } +/// +/// impl Test { +/// gen_base_func!(test_base, test_base_mut, TestBase, base); +/// } +/// ``` +/// +/// This is equivalent to: +/// +/// ```rust +/// struct TestBase(u8); +/// struct Test { +/// base: TestBase, +/// } +/// +/// impl Test { +/// fn test_base(&self) -> &TestBase { +/// &self.base +/// } +/// +/// fn test_base_mut(&mut self) -> &mut TestBase { +/// &mut self.base +/// } +/// } +/// ``` +#[macro_export] +macro_rules! gen_base_func { + ($get_func: ident, $get_mut_func: ident, $base_type: ty, $($base: tt).*) => { + fn $get_func(&self) -> &$base_type { + &self.$($base).* + } + + fn $get_mut_func(&mut self) -> &mut $base_type { + &mut self.$($base).* + } + }; +} + /// This trait is to cast trait object to struct. pub trait AsAny { fn as_any(&self) -> &dyn Any; diff --git a/vfio/src/vfio_pci.rs b/vfio/src/vfio_pci.rs index ebf028e5..7a74badc 100644 --- a/vfio/src/vfio_pci.rs +++ b/vfio/src/vfio_pci.rs @@ -45,6 +45,7 @@ use devices::pci::{ }; use devices::{pci::MsiVector, Device, DeviceBase}; use machine_manager::config::{get_pci_df, parse_bool, valid_id}; +use util::gen_base_func; use util::loop_context::create_new_eventfd; use util::num_ops::ranges_overlap; use util::unix::host_page_size; @@ -813,23 +814,11 @@ impl VfioPciDevice { } impl Device for VfioPciDevice { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl PciDevOps for VfioPciDevice { - fn pci_base(&self) -> &PciDevBase { - &self.base - } - - fn pci_base_mut(&mut self) -> &mut PciDevBase { - &mut self.base - } + gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); fn realize(mut self) -> Result<()> { self.init_write_mask(false)?; diff --git a/virtio/src/device/balloon.rs b/virtio/src/device/balloon.rs index fe62211c..97724ece 100644 --- a/virtio/src/device/balloon.rs +++ b/virtio/src/device/balloon.rs @@ -41,17 +41,15 @@ use machine_manager::{ qmp::qmp_channel::QmpChannel, qmp::qmp_schema::BalloonInfo, }; -use util::{ - bitmap::Bitmap, - byte_code::ByteCode, - loop_context::{ - read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, - }, - num_ops::round_down, - offset_of, - seccomp::BpfRule, - unix::host_page_size, +use util::bitmap::Bitmap; +use util::byte_code::ByteCode; +use util::loop_context::{ + read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, }; +use util::num_ops::round_down; +use util::seccomp::BpfRule; +use util::unix::host_page_size; +use util::{gen_base_func, offset_of}; const VIRTIO_BALLOON_F_DEFLATE_ON_OOM: u32 = 2; const VIRTIO_BALLOON_F_REPORTING: u32 = 5; @@ -1053,13 +1051,7 @@ impl Balloon { } impl VirtioDevice for Balloon { - fn virtio_base(&self) -> &VirtioBase { - &self.base - } - - fn virtio_base_mut(&mut self) -> &mut VirtioBase { - &mut self.base - } + gen_base_func!(virtio_base, virtio_base_mut, VirtioBase, base); fn realize(&mut self) -> Result<()> { self.bln_cfg.check()?; diff --git a/virtio/src/device/block.rs b/virtio/src/device/block.rs index 837cfe6d..26fa748f 100644 --- a/virtio/src/device/block.rs +++ b/virtio/src/device/block.rs @@ -61,7 +61,7 @@ use util::loop_context::{ create_new_eventfd, read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, }; -use util::offset_of; +use util::{gen_base_func, offset_of}; /// Number of virtqueues. const QUEUE_NUM_BLK: usize = 1; @@ -1122,13 +1122,7 @@ impl Block { } impl VirtioDevice for Block { - fn virtio_base(&self) -> &VirtioBase { - &self.base - } - - fn virtio_base_mut(&mut self) -> &mut VirtioBase { - &mut self.base - } + gen_base_func!(virtio_base, virtio_base_mut, VirtioBase, base); fn realize(&mut self) -> Result<()> { // if iothread not found, return err diff --git a/virtio/src/device/gpu.rs b/virtio/src/device/gpu.rs index 2d138ed2..acd74d0a 100644 --- a/virtio/src/device/gpu.rs +++ b/virtio/src/device/gpu.rs @@ -52,6 +52,7 @@ use ui::pixman::{ use util::aio::{iov_from_buf_direct, iov_to_buf_direct, Iovec}; use util::byte_code::ByteCode; use util::edid::EdidInfo; +use util::gen_base_func; use util::loop_context::{ read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, }; @@ -1733,13 +1734,7 @@ impl Gpu { } impl VirtioDevice for Gpu { - fn virtio_base(&self) -> &VirtioBase { - &self.base - } - - fn virtio_base_mut(&mut self) -> &mut VirtioBase { - &mut self.base - } + gen_base_func!(virtio_base, virtio_base_mut, VirtioBase, base); fn device_quirk(&self) -> Option { if self.cfg.enable_bar0 { diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index 7b400206..4101ec9c 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -55,10 +55,10 @@ use migration::{ }; use migration_derive::{ByteCode, Desc}; use util::byte_code::ByteCode; -use util::loop_context::gen_delete_notifiers; +use util::gen_base_func; use util::loop_context::{ - create_new_eventfd, read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, - NotifierOperation, + create_new_eventfd, gen_delete_notifiers, read_fd, EventNotifier, EventNotifierHelper, + NotifierCallback, NotifierOperation, }; use util::num_ops::str_to_num; use util::tap::{ @@ -1462,13 +1462,7 @@ fn get_tap_offload_flags(features: u64) -> u32 { } impl VirtioDevice for Net { - fn virtio_base(&self) -> &VirtioBase { - &self.base - } - - fn virtio_base_mut(&mut self) -> &mut VirtioBase { - &mut self.base - } + gen_base_func!(virtio_base, virtio_base_mut, VirtioBase, base); fn realize(&mut self) -> Result<()> { // if iothread not found, return err diff --git a/virtio/src/device/rng.rs b/virtio/src/device/rng.rs index 3d26ea9e..557e759c 100644 --- a/virtio/src/device/rng.rs +++ b/virtio/src/device/rng.rs @@ -39,6 +39,7 @@ use migration::{DeviceStateDesc, FieldDesc, MigrationHook, MigrationManager, Sta use migration_derive::{ByteCode, Desc}; use util::aio::raw_read; use util::byte_code::ByteCode; +use util::gen_base_func; use util::leak_bucket::LeakBucket; use util::loop_context::{ read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, @@ -312,13 +313,7 @@ impl Rng { } impl VirtioDevice for Rng { - fn virtio_base(&self) -> &VirtioBase { - &self.base - } - - fn virtio_base_mut(&mut self) -> &mut VirtioBase { - &mut self.base - } + gen_base_func!(virtio_base, virtio_base_mut, VirtioBase, base); fn realize(&mut self) -> Result<()> { self.check_random_file() diff --git a/virtio/src/device/scsi_cntlr.rs b/virtio/src/device/scsi_cntlr.rs index 8f301df1..26db5f13 100644 --- a/virtio/src/device/scsi_cntlr.rs +++ b/virtio/src/device/scsi_cntlr.rs @@ -39,6 +39,7 @@ use machine_manager::config::{ use machine_manager::event_loop::{register_event_helper, unregister_event_helper, EventLoop}; use util::aio::Iovec; use util::byte_code::ByteCode; +use util::gen_base_func; use util::loop_context::{ read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, }; @@ -170,13 +171,7 @@ impl ScsiCntlr { } impl VirtioDevice for ScsiCntlr { - fn virtio_base(&self) -> &VirtioBase { - &self.base - } - - fn virtio_base_mut(&mut self) -> &mut VirtioBase { - &mut self.base - } + gen_base_func!(virtio_base, virtio_base_mut, VirtioBase, base); fn realize(&mut self) -> Result<()> { // If iothread not found, return err. diff --git a/virtio/src/device/serial.rs b/virtio/src/device/serial.rs index 0cf42421..73aa4ac6 100644 --- a/virtio/src/device/serial.rs +++ b/virtio/src/device/serial.rs @@ -40,6 +40,7 @@ use migration::{DeviceStateDesc, FieldDesc, MigrationHook, MigrationManager, Sta use migration_derive::{ByteCode, Desc}; use util::aio::iov_from_buf_direct; use util::byte_code::ByteCode; +use util::gen_base_func; use util::loop_context::{ read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, }; @@ -215,13 +216,7 @@ pub fn find_port_by_nr( } impl VirtioDevice for Serial { - fn virtio_base(&self) -> &VirtioBase { - &self.base - } - - fn virtio_base_mut(&mut self) -> &mut VirtioBase { - &mut self.base - } + gen_base_func!(virtio_base, virtio_base_mut, VirtioBase, base); fn realize(&mut self) -> Result<()> { self.init_config_features()?; diff --git a/virtio/src/transport/virtio_mmio.rs b/virtio/src/transport/virtio_mmio.rs index 814fbeee..c538f958 100644 --- a/virtio/src/transport/virtio_mmio.rs +++ b/virtio/src/transport/virtio_mmio.rs @@ -33,6 +33,7 @@ use machine_manager::config::{BootSource, Param}; use migration::{DeviceStateDesc, FieldDesc, MigrationHook, MigrationManager, StateTransfer}; use migration_derive::{ByteCode, Desc}; use util::byte_code::ByteCode; +use util::gen_base_func; use util::loop_context::create_new_eventfd; /// Registers of virtio-mmio device refer to Virtio Spec. @@ -391,23 +392,11 @@ impl VirtioMmioDevice { } impl Device for VirtioMmioDevice { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl SysBusDevOps for VirtioMmioDevice { - fn sysbusdev_base(&self) -> &SysBusDevBase { - &self.base - } - - fn sysbusdev_base_mut(&mut self) -> &mut SysBusDevBase { - &mut self.base - } + gen_base_func!(sysbusdev_base, sysbusdev_base_mut, SysBusDevBase, base); /// Read data by virtio driver from VM. fn read(&mut self, data: &mut [u8], _base: GuestAddress, offset: u64) -> bool { @@ -631,13 +620,7 @@ mod tests { } impl VirtioDevice for VirtioDeviceTest { - fn virtio_base(&self) -> &VirtioBase { - &self.base - } - - fn virtio_base_mut(&mut self) -> &mut VirtioBase { - &mut self.base - } + gen_base_func!(virtio_base, virtio_base_mut, VirtioBase, base); fn realize(&mut self) -> Result<()> { self.b_realized = true; diff --git a/virtio/src/transport/virtio_pci.rs b/virtio/src/transport/virtio_pci.rs index a9ba784b..d80ded3c 100644 --- a/virtio/src/transport/virtio_pci.rs +++ b/virtio/src/transport/virtio_pci.rs @@ -52,9 +52,8 @@ use machine_manager::config::VIRTIO_GPU_ENABLE_BAR0_SIZE; use migration::{DeviceStateDesc, FieldDesc, MigrationHook, MigrationManager, StateTransfer}; use migration_derive::{ByteCode, Desc}; use util::byte_code::ByteCode; -use util::num_ops::ranges_overlap; -use util::num_ops::{read_data_u32, write_data_u32}; -use util::offset_of; +use util::num_ops::{ranges_overlap, read_data_u32, write_data_u32}; +use util::{gen_base_func, offset_of}; const VIRTIO_QUEUE_MAX: u32 = 1024; @@ -1005,23 +1004,11 @@ impl VirtioPciDevice { } impl Device for VirtioPciDevice { - fn device_base(&self) -> &DeviceBase { - &self.base.base - } - - fn device_base_mut(&mut self) -> &mut DeviceBase { - &mut self.base.base - } + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl PciDevOps for VirtioPciDevice { - fn pci_base(&self) -> &PciDevBase { - &self.base - } - - fn pci_base_mut(&mut self) -> &mut PciDevBase { - &mut self.base - } + gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); fn realize(mut self) -> Result<()> { info!("func: realize, id: {:?}", &self.base.base.id); @@ -1418,13 +1405,7 @@ mod tests { } impl VirtioDevice for VirtioDeviceTest { - fn virtio_base(&self) -> &VirtioBase { - &self.base - } - - fn virtio_base_mut(&mut self) -> &mut VirtioBase { - &mut self.base - } + gen_base_func!(virtio_base, virtio_base_mut, VirtioBase, base); fn realize(&mut self) -> Result<()> { self.init_config_features()?; diff --git a/virtio/src/vhost/kernel/net.rs b/virtio/src/vhost/kernel/net.rs index 0933cef4..d55376cf 100644 --- a/virtio/src/vhost/kernel/net.rs +++ b/virtio/src/vhost/kernel/net.rs @@ -34,6 +34,7 @@ use address_space::AddressSpace; use machine_manager::config::{NetDevcfg, NetworkInterfaceConfig}; use machine_manager::event_loop::{register_event_helper, unregister_event_helper}; use util::byte_code::ByteCode; +use util::gen_base_func; use util::loop_context::{create_new_eventfd, EventNotifierHelper}; use util::tap::Tap; @@ -123,13 +124,7 @@ impl Net { } impl VirtioDevice for Net { - fn virtio_base(&self) -> &VirtioBase { - &self.base - } - - fn virtio_base_mut(&mut self) -> &mut VirtioBase { - &mut self.base - } + gen_base_func!(virtio_base, virtio_base_mut, VirtioBase, base); fn realize(&mut self) -> Result<()> { let queue_pairs = self.netdev_cfg.queues / 2; diff --git a/virtio/src/vhost/kernel/vsock.rs b/virtio/src/vhost/kernel/vsock.rs index 8c06c63d..4f2d1a44 100644 --- a/virtio/src/vhost/kernel/vsock.rs +++ b/virtio/src/vhost/kernel/vsock.rs @@ -32,6 +32,7 @@ use machine_manager::event_loop::{register_event_helper, unregister_event_helper use migration::{DeviceStateDesc, FieldDesc, MigrationHook, MigrationManager, StateTransfer}; use migration_derive::{ByteCode, Desc}; use util::byte_code::ByteCode; +use util::gen_base_func; use util::loop_context::{create_new_eventfd, EventNotifierHelper}; /// Number of virtqueues. @@ -193,13 +194,7 @@ impl Vsock { } impl VirtioDevice for Vsock { - fn virtio_base(&self) -> &VirtioBase { - &self.base - } - - fn virtio_base_mut(&mut self) -> &mut VirtioBase { - &mut self.base - } + gen_base_func!(virtio_base, virtio_base_mut, VirtioBase, base); fn realize(&mut self) -> Result<()> { let vhost_fd: Option = self.vsock_cfg.vhost_fd; diff --git a/virtio/src/vhost/user/block.rs b/virtio/src/vhost/user/block.rs index 8c55cac1..8ccce18e 100644 --- a/virtio/src/vhost/user/block.rs +++ b/virtio/src/vhost/user/block.rs @@ -37,6 +37,7 @@ use machine_manager::config::{ }; use machine_manager::event_loop::unregister_event_helper; use util::byte_code::ByteCode; +use util::gen_base_func; #[derive(Parser, Debug, Clone, Default)] #[command(no_binary_name(true))] @@ -119,13 +120,7 @@ impl Block { } impl VirtioDevice for Block { - fn virtio_base(&self) -> &VirtioBase { - &self.base - } - - fn virtio_base_mut(&mut self) -> &mut VirtioBase { - &mut self.base - } + gen_base_func!(virtio_base, virtio_base_mut, VirtioBase, base); fn realize(&mut self) -> Result<()> { self.init_client()?; diff --git a/virtio/src/vhost/user/fs.rs b/virtio/src/vhost/user/fs.rs index 75c3698a..f08ddd39 100644 --- a/virtio/src/vhost/user/fs.rs +++ b/virtio/src/vhost/user/fs.rs @@ -33,6 +33,7 @@ use machine_manager::config::{ }; use machine_manager::event_loop::unregister_event_helper; use util::byte_code::ByteCode; +use util::gen_base_func; const MAX_TAG_LENGTH: usize = 36; @@ -120,13 +121,7 @@ impl Fs { } impl VirtioDevice for Fs { - fn virtio_base(&self) -> &VirtioBase { - &self.base - } - - fn virtio_base_mut(&mut self) -> &mut VirtioBase { - &mut self.base - } + gen_base_func!(virtio_base, virtio_base_mut, VirtioBase, base); fn realize(&mut self) -> Result<()> { let queues_num = VIRIOT_FS_HIGH_PRIO_QUEUE_NUM + VIRTIO_FS_REQ_QUEUES_NUM; diff --git a/virtio/src/vhost/user/net.rs b/virtio/src/vhost/user/net.rs index 4dc76345..fc983446 100644 --- a/virtio/src/vhost/user/net.rs +++ b/virtio/src/vhost/user/net.rs @@ -31,6 +31,7 @@ use address_space::AddressSpace; use machine_manager::config::{NetDevcfg, NetworkInterfaceConfig}; use machine_manager::event_loop::{register_event_helper, unregister_event_helper}; use util::byte_code::ByteCode; +use util::gen_base_func; use util::loop_context::EventNotifierHelper; /// Number of virtqueues. @@ -117,13 +118,7 @@ impl Net { } impl VirtioDevice for Net { - fn virtio_base(&self) -> &VirtioBase { - &self.base - } - - fn virtio_base_mut(&mut self) -> &mut VirtioBase { - &mut self.base - } + gen_base_func!(virtio_base, virtio_base_mut, VirtioBase, base); fn realize(&mut self) -> Result<()> { let client = VhostUserClient::new( -- Gitee From 4d413b9f583bdbdc2cf503ad130ec04f51b8ee75 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Fri, 14 Jun 2024 05:45:01 +0800 Subject: [PATCH 133/489] address_space: fix searching ioeventfd error The address that ioeventfd listens to is not unique. For example, virtio-mmio device will listen to `QueueNotify` register(0x050). This register will receive a value to notify this virtio-mmio device that there are new buffers to process in a queue. So, all virtqueues of this device will listen to this register. In the case of multiple ioevevtfds with the same address range, it is necessary to determine which ioeventfd to use through `datamatch` and `data`. However, according to the description of the rust `slice` library, the action of function `binary_search_by` is: `If there are multiple matches, then any one of the matches could be returned.` Thus, the virtio-mmio device may encounter various exceptions because of this random unexpected ioeventfd calling. Delete this `binary_search_by`. Fix: 07f2d03883574(AddressSpace: Optimized the ioeventfd mechanism) Signed-off-by: liuxiangdong --- address_space/src/address_space.rs | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/address_space/src/address_space.rs b/address_space/src/address_space.rs index fd419d77..d34dd59e 100644 --- a/address_space/src/address_space.rs +++ b/address_space/src/address_space.rs @@ -633,13 +633,15 @@ impl AddressSpace { trace::trace_scope_start!(address_space_write, args = (&addr, count)); let view = self.flat_view.load(); + let mut buf = Vec::new(); + src.read_to_end(&mut buf).unwrap(); + if !*self.hyp_ioevtfd_enabled.get_or_init(|| false) { let ioeventfds = self.ioeventfds.lock().unwrap(); - if let Ok(index) = ioeventfds - .as_slice() - .binary_search_by(|ioevtfd| ioevtfd.addr_range.base.cmp(&addr)) - { - let evtfd = &ioeventfds[index]; + for evtfd in ioeventfds.as_slice() { + if evtfd.addr_range.base != addr { + continue; + } if count == evtfd.addr_range.size || evtfd.addr_range.size == 0 { if !evtfd.data_match { if let Err(e) = evtfd.fd.write(1) { @@ -648,26 +650,27 @@ impl AddressSpace { return Ok(()); } - let mut buf = Vec::new(); - src.read_to_end(&mut buf).unwrap(); + let mut buf_temp = buf.clone(); - if buf.len() <= 8 { - buf.resize(8, 0); - let data = u64::from_bytes(buf.as_slice()).unwrap(); + if buf_temp.len() <= 8 { + buf_temp.resize(8, 0); + let data = u64::from_bytes(buf_temp.as_slice()).unwrap(); if *data == evtfd.data { if let Err(e) = evtfd.fd.write(1) { error!("Failed to write ioeventfd {:?}: {}", evtfd, e); } return Ok(()); + } else { + continue; } } - view.write(&mut buf.as_slice(), addr, count)?; + view.write(&mut buf_temp.as_slice(), addr, count)?; return Ok(()); } } } - view.write(src, addr, count)?; + view.write(&mut buf.as_slice(), addr, count)?; Ok(()) } -- Gitee From 3098f3542260b09598a8561c8218fe88fcb4bf3b Mon Sep 17 00:00:00 2001 From: yexiao Date: Fri, 31 May 2024 10:46:47 +0800 Subject: [PATCH 134/489] gtk: activate the current page duration display init Signed-off-by: Xiao Ye --- ui/src/gtk/menu.rs | 9 +++++++-- ui/src/gtk/mod.rs | 9 ++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/ui/src/gtk/menu.rs b/ui/src/gtk/menu.rs index e89b7a3e..c1e4b6b6 100644 --- a/ui/src/gtk/menu.rs +++ b/ui/src/gtk/menu.rs @@ -42,7 +42,7 @@ pub(crate) struct GtkMenu { pub(crate) window: ApplicationWindow, container: gtk::Box, pub(crate) note_book: gtk::Notebook, - pub(crate) radio_group: Vec, + pub(crate) radio_group: Rc>>, accel_group: AccelGroup, menu_bar: MenuBar, machine_menu: Menu, @@ -64,7 +64,7 @@ impl GtkMenu { window, container: gtk::Box::new(Orientation::Vertical, 0), note_book: gtk::Notebook::default(), - radio_group: vec![], + radio_group: Rc::new(RefCell::new(vec![])), accel_group: AccelGroup::default(), menu_bar: MenuBar::new(), machine_menu: Menu::new(), @@ -258,6 +258,11 @@ impl GtkMenu { self.zoom_fit.activate(); } + if let Some(page_num) = self.note_book.current_page() { + let radio_item = &self.radio_group.borrow()[page_num as usize]; + radio_item.activate(); + } + self.menu_bar.hide(); } } diff --git a/ui/src/gtk/mod.rs b/ui/src/gtk/mod.rs index ced3792b..84b59e5d 100644 --- a/ui/src/gtk/mod.rs +++ b/ui/src/gtk/mod.rs @@ -304,14 +304,17 @@ impl GtkDisplay { })); self.gtk_menu.view_menu.append(&gs_show_menu); - if !self.gtk_menu.radio_group.is_empty() { - let first_radio = &self.gtk_menu.radio_group[0]; + if !self.gtk_menu.radio_group.borrow().is_empty() { + let first_radio = &self.gtk_menu.radio_group.borrow()[0]; gs_show_menu.join_group(Some(first_radio)); } else { note_book.set_current_page(Some(page_num)); } - self.gtk_menu.radio_group.push(gs_show_menu.clone()); + self.gtk_menu + .radio_group + .borrow_mut() + .push(gs_show_menu.clone()); gs.borrow_mut().show_menu = gs_show_menu; gs.borrow_mut().draw_area = draw_area; -- Gitee From 65faea5b5ac914b180d03c20f513c0c48b693f74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A5=9A=E5=BD=B1?= Date: Tue, 11 Jun 2024 15:35:51 +0800 Subject: [PATCH 135/489] ohaudio: introduce vm pause notfier to restart renderer and capturer This patch introduces vm pause notifier to machine. Ohaudio registers notifier which set restart flag. After the machine resumed, the render or capturer of ohaudio would destory current context and re- create an new context. Signed-off-by: Jiahong Li --- devices/src/misc/scream/mod.rs | 45 ++++++++++++++++++++++-------- devices/src/misc/scream/ohaudio.rs | 37 ++++++++++++++++++++++-- machine/src/aarch64/standard.rs | 6 +++- machine/src/lib.rs | 27 ++++++++++++++++-- machine_manager/src/machine.rs | 4 +++ 5 files changed, 102 insertions(+), 17 deletions(-) diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index 496c96c2..d9c8c5cb 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -40,6 +40,7 @@ use super::ivshmem::Ivshmem; use crate::pci::{PciBus, PciDevOps}; use address_space::{GuestAddress, HostMemMapping, Region}; use machine_manager::config::{get_pci_df, parse_bool, valid_id}; +use machine_manager::machine::PauseNotify; #[cfg(all(target_env = "ohos", feature = "scream_ohaudio"))] use ohaudio::OhAudio; #[cfg(feature = "scream_pulseaudio")] @@ -337,27 +338,29 @@ impl StreamData { let header = &mut unsafe { std::slice::from_raw_parts_mut(hva as *mut ShmemHeader, 1) }[0]; let capt = &mut header.capt; let addr = hva + capt.offset as u64; - let mut locked_interface = interface.lock().unwrap(); - locked_interface.pre_receive(addr, capt); + interface.lock().unwrap().pre_receive(addr, capt); while capt.is_started != 0 { if !self.update_buffer_by_chunk_idx(hva, shmem_size, capt) { return; } let recv_chunks_cnt: i32 = if get_record_authority() { - locked_interface.receive(self) + interface.lock().unwrap().receive(self) } else { - locked_interface.destroy(); + interface.lock().unwrap().destroy(); 0 }; - if recv_chunks_cnt > 0 { - self.chunk_idx = (self.chunk_idx + recv_chunks_cnt as u16) % capt.max_chunks; - - // Make sure chunk_idx write does not bypass audio chunk write. - fence(Ordering::SeqCst); - capt.chunk_idx = self.chunk_idx; + match recv_chunks_cnt.cmp(&0) { + std::cmp::Ordering::Less => thread::sleep(time::Duration::from_millis(100)), + std::cmp::Ordering::Greater => { + self.chunk_idx = (self.chunk_idx + recv_chunks_cnt as u16) % capt.max_chunks; + // Make sure chunk_idx write does not bypass audio chunk write. + fence(Ordering::SeqCst); + capt.chunk_idx = self.chunk_idx; + } + std::cmp::Ordering::Equal => continue, } } } @@ -430,6 +433,16 @@ pub struct Scream { size: u64, config: ScreamConfig, token_id: Option>>, + interface_resource: RwLock>>>, +} + +impl PauseNotify for Scream { + fn notify(&self, paused: bool) { + let interfaces = self.interface_resource.read().unwrap(); + for interface in interfaces.iter() { + interface.lock().unwrap().pause(paused); + } + } } impl Scream { @@ -440,6 +453,7 @@ impl Scream { size, config, token_id, + interface_resource: RwLock::new(Vec::new()), } } @@ -464,6 +478,10 @@ impl Scream { let hva = self.hva; let shmem_size = self.size; let interface = self.interface_init("ScreamPlay", ScreamDirection::Playback); + self.interface_resource + .write() + .unwrap() + .push(interface.clone()); thread::Builder::new() .name("scream audio play worker".to_string()) .spawn(move || { @@ -490,6 +508,10 @@ impl Scream { let shmem_size = self.size; let interface = self.interface_init("ScreamCapt", ScreamDirection::Record); let _ti = self.token_id.clone(); + self.interface_resource + .write() + .unwrap() + .push(interface.clone()); thread::Builder::new() .name("scream audio capt worker".to_string()) .spawn(move || { @@ -516,7 +538,7 @@ impl Scream { Ok(()) } - pub fn realize(mut self, devfn: u8, parent_bus: Weak>) -> Result<()> { + pub fn realize(&mut self, devfn: u8, parent_bus: Weak>) -> Result<()> { let header_size = mem::size_of::() as u64; if self.size < header_size { bail!( @@ -554,4 +576,5 @@ pub trait AudioInterface: Send { fn pre_receive(&mut self, start_addr: u64, sh_header: &ShmemStreamHeader) {} fn receive(&mut self, recv_data: &StreamData) -> i32; fn destroy(&mut self); + fn pause(&mut self, _paused: bool) {} } diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index 2349d93a..990648ef 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -27,6 +27,7 @@ trait OhAudioProcess { fn destroy(&mut self); fn preprocess(&mut self, _start_addr: u64, _sh_header: &ShmemStreamHeader) {} fn process(&mut self, recv_data: &StreamData) -> i32; + fn pause(&mut self, paused: bool); } #[derive(Debug, Clone, Copy)] @@ -45,6 +46,7 @@ struct OhAudioRender { stream_data: Arc>>, data_size: AtomicI32, start: bool, + pause: bool, flushing: AtomicBool, } @@ -55,6 +57,7 @@ impl Default for OhAudioRender { stream_data: Arc::new(Mutex::new(Vec::with_capacity(STREAM_DATA_VEC_CAPACITY))), data_size: AtomicI32::new(0), start: false, + pause: false, flushing: AtomicBool::new(false), } } @@ -117,15 +120,27 @@ impl OhAudioProcess for OhAudioRender { self.start } + fn pause(&mut self, paused: bool) { + self.pause = paused; + if paused { + self.destroy(); + } + } + fn destroy(&mut self) { if self.ctx.is_some() { if self.start { - self.flush(); + if !self.pause { + self.flush(); + } self.ctx.as_mut().unwrap().stop(); self.start = false; } self.ctx = None; } + if self.pause { + return; + } let mut locked_data = self.stream_data.lock().unwrap(); locked_data.clear(); self.data_size.store(0, Ordering::Relaxed); @@ -133,6 +148,9 @@ impl OhAudioProcess for OhAudioRender { } fn process(&mut self, recv_data: &StreamData) -> i32 { + if self.pause { + return 0; + } self.check_fmt_update(recv_data); fence(Ordering::Acquire); @@ -175,6 +193,7 @@ struct OhAudioCapture { shm_len: u64, cur_pos: u64, start: bool, + pause: bool, } impl OhAudioCapture { @@ -220,6 +239,13 @@ impl OhAudioProcess for OhAudioCapture { } } + fn pause(&mut self, paused: bool) { + self.pause = paused; + if paused { + self.destroy(); + } + } + fn destroy(&mut self) { if self.ctx.is_some() { if self.start { @@ -240,13 +266,16 @@ impl OhAudioProcess for OhAudioCapture { } fn process(&mut self, recv_data: &StreamData) -> i32 { + if self.pause { + return -1; + } self.check_fmt_update(recv_data); trace::trace_scope_start!(ohaudio_capturer_process, args = (recv_data)); if !self.start && !self.init(recv_data) { self.destroy(); - return 0; + return -1; } self.new_chunks.store(0, Ordering::Release); while self.new_chunks.load(Ordering::Acquire) == 0 { @@ -408,6 +437,10 @@ impl AudioInterface for OhAudio { fn destroy(&mut self) { self.processor.destroy(); } + + fn pause(&mut self, paused: bool) { + self.processor.pause(paused); + } } #[cfg(test)] diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index cec804b6..1dcf86cb 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -69,7 +69,7 @@ use machine_manager::event; use machine_manager::event_loop::EventLoop; use machine_manager::machine::{ MachineExternalInterface, MachineInterface, MachineLifecycle, MachineTestInterface, - MigrateInterface, VmState, + MigrateInterface, PauseNotify, VmState, }; use machine_manager::qmp::{qmp_channel::QmpChannel, qmp_response::Response, qmp_schema}; use migration::{MigrationManager, MigrationStatus}; @@ -463,6 +463,10 @@ impl MachineOps for StdMachine { .add_subregion(ram, MEM_LAYOUT[LayoutEntryType::Mem as usize].0) } + fn register_vm_pause_notifier(&mut self, notifier: Arc) { + self.base.pause_notifiers.push(notifier); + } + fn init_interrupt_controller(&mut self, vcpu_count: u64) -> Result<()> { let v3 = ICGICv3Config { msi: true, diff --git a/machine/src/lib.rs b/machine/src/lib.rs index bde75da4..a956e1f9 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -83,7 +83,7 @@ use machine_manager::config::{ VirtioSerialPortCfg, VmConfig, FAST_UNPLUG_ON, MAX_VIRTIO_QUEUE, }; use machine_manager::event_loop::EventLoop; -use machine_manager::machine::{HypervisorType, MachineInterface, VmState}; +use machine_manager::machine::{HypervisorType, MachineInterface, PauseNotify, VmState}; use machine_manager::{check_arg_exist, check_arg_nonexist}; use migration::{MigrateOps, MigrationManager}; #[cfg(feature = "windows_emu_pid")] @@ -148,6 +148,8 @@ pub struct MachineBase { hypervisor: Arc>, /// migrate hypervisor. migration_hypervisor: Arc>, + /// vm pause notifiers. + pause_notifiers: Vec>, } impl MachineBase { @@ -224,6 +226,7 @@ impl MachineBase { machine_ram, hypervisor, migration_hypervisor, + pause_notifiers: Vec::new(), }) } @@ -1646,6 +1649,9 @@ pub trait MachineOps { Ok(()) } + /// Register vm pause listener. + fn register_vm_pause_notifier(&mut self, _listener: Arc) {} + /// Add scream sound based on ivshmem. /// /// # Arguments @@ -1680,10 +1686,12 @@ pub trait MachineOps { bail!("Object for share config is not on"); } - let scream = Scream::new(mem_cfg.size, config, token_id); + let mut scream = Scream::new(mem_cfg.size, config, token_id); scream .realize(devfn, parent_bus) - .with_context(|| "Failed to realize scream device") + .with_context(|| "Failed to realize scream device")?; + self.register_vm_pause_notifier(Arc::new(scream)); + Ok(()) } /// Get the corresponding device from the PCI bus based on the device id and device type name. @@ -1982,6 +1990,13 @@ pub trait MachineOps { self.machine_base().drive_files.clone() } + //// Trigger vm pause notifiers. + fn notify_vm_pause_notifiers(&self, paused: bool) { + for notifier in self.machine_base().pause_notifiers.iter() { + notifier.notify(paused); + } + } + /// Fetch a cloned file from drive backend files. fn fetch_drive_file(&self, path: &str) -> Result { let files = self.get_drive_files(); @@ -2130,6 +2145,9 @@ pub trait MachineOps { *vm_state = VmState::Paused; + // Notify VM paused. + self.notify_vm_pause_notifiers(true); + Ok(()) } @@ -2153,6 +2171,9 @@ pub trait MachineOps { *vm_state = VmState::Running; + // Notify VM resumed. + self.notify_vm_pause_notifiers(false); + Ok(()) } diff --git a/machine_manager/src/machine.rs b/machine_manager/src/machine.rs index a040d6ef..cd37eefd 100644 --- a/machine_manager/src/machine.rs +++ b/machine_manager/src/machine.rs @@ -67,6 +67,10 @@ impl FromStr for HypervisorType { } } +pub trait PauseNotify: Send + Sync { + fn notify(&self, paused: bool); +} + /// Trait to handle virtual machine lifecycle. /// /// # Notes -- Gitee From 3f774bd8e399bef8714c0465aa6133b24fdd6524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=BA=A2=E5=8D=8E?= Date: Wed, 19 Jun 2024 09:34:51 +0800 Subject: [PATCH 136/489] Main: Add vm config fail error log The error information is added to prevent users from failing to obtain the error infomation when they fail to read the standard error. Signed-off-by: Yihua Jin --- src/main.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 4a777564..f97a395b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -103,7 +103,13 @@ fn run() -> Result<()> { exit_with_code(VM_EXIT_GENE_ERR); })); - let mut vm_config: VmConfig = create_vmconfig(&cmd_args)?; + let mut vm_config: VmConfig = match create_vmconfig(&cmd_args) { + Ok(vm_cfg) => vm_cfg, + Err(e) => { + error!("Failed to create vmconfig {:?}", e); + return Err(e); + } + }; info!("VmConfig is {:?}", vm_config); match real_main(&cmd_args, &mut vm_config) { -- Gitee From e0edbcda448c2f8d657727096a746b55f4b33d31 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sun, 16 Jun 2024 00:39:13 +0800 Subject: [PATCH 137/489] machine: unified `StdMachine` Unified `StdMachine` to reduce redundant code. Signed-off-by: liuxiangdong --- machine/src/aarch64/standard.rs | 178 ++------------------------- machine/src/standard_common/mod.rs | 190 +++++++++++++++++++++++++++-- machine/src/x86_64/standard.rs | 148 +--------------------- 3 files changed, 192 insertions(+), 324 deletions(-) diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index 1dcf86cb..a3cb4dbd 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -13,7 +13,6 @@ pub use crate::error::MachineError; use std::mem::size_of; -use std::ops::Deref; #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] use std::sync::RwLock; use std::sync::{Arc, Mutex}; @@ -21,11 +20,11 @@ use std::sync::{Arc, Mutex}; use anyhow::{anyhow, bail, Context, Result}; #[cfg(feature = "ramfb")] use clap::Parser; -use log::{error, info, warn}; -use vmm_sys_util::eventfd::EventFd; +use super::pci_host_root::PciHostRoot; +use crate::standard_common::syscall::syscall_whitelist; use crate::standard_common::{AcpiBuilder, StdMachineOps}; -use crate::{MachineBase, MachineOps}; +use crate::{MachineBase, MachineOps, StdMachine}; use acpi::{ processor_append_priv_res, AcpiGicCpu, AcpiGicDistributor, AcpiGicIts, AcpiGicRedistributor, AcpiSratGiccAffinity, AcpiSratMemoryAffinity, AcpiTable, AmlBuilder, AmlDevice, AmlInteger, @@ -42,9 +41,6 @@ use acpi::{ use address_space::FileBackend; use address_space::{AddressSpace, GuestAddress, Region}; use cpu::{CPUInterface, CPUTopology, CpuLifecycleState, PMU_INTR, PPI_BASE}; - -use super::pci_host_root::PciHostRoot; -use crate::standard_common::syscall::syscall_whitelist; use devices::acpi::ged::{acpi_dsdt_add_power_button, Ged, GedEvent}; use devices::acpi::power::PowerDev; use devices::legacy::{ @@ -59,19 +55,12 @@ use hypervisor::kvm::aarch64::*; use hypervisor::kvm::*; #[cfg(feature = "ramfb")] use machine_manager::config::str_slip_to_clap; -use machine_manager::config::ShutdownAction; #[cfg(feature = "gtk")] use machine_manager::config::UiContext; -use machine_manager::config::{ - parse_incoming_uri, BootIndexInfo, DriveConfig, MigrateMode, NumaNode, SerialConfig, VmConfig, -}; +use machine_manager::config::{BootIndexInfo, DriveConfig, NumaNode, SerialConfig, VmConfig}; use machine_manager::event; -use machine_manager::event_loop::EventLoop; -use machine_manager::machine::{ - MachineExternalInterface, MachineInterface, MachineLifecycle, MachineTestInterface, - MigrateInterface, PauseNotify, VmState, -}; -use machine_manager::qmp::{qmp_channel::QmpChannel, qmp_response::Response, qmp_schema}; +use machine_manager::machine::{MachineLifecycle, PauseNotify}; +use machine_manager::qmp::{qmp_channel::QmpChannel, qmp_schema}; use migration::{MigrationManager, MigrationStatus}; #[cfg(feature = "gtk")] use ui::gtk::gtk_display_init; @@ -81,9 +70,9 @@ use ui::ohui_srv::{ohui_init, OhUiServer}; use ui::vnc::vnc_init; use util::byte_code::ByteCode; use util::device_tree::{self, CompileFDT, FdtBuilder}; -use util::loop_context::{create_new_eventfd, EventLoopManager}; +use util::gen_base_func; +use util::loop_context::create_new_eventfd; use util::seccomp::{BpfRule, SeccompCmpOpt}; -use util::{gen_base_func, set_termi_canon_mode}; /// The type of memory layout entry on aarch64 pub enum LayoutEntryType { @@ -137,31 +126,6 @@ const IRQ_MAP: &[(i32, i32)] = &[ (16, 19), // Pcie ]; -/// Standard machine structure. -pub struct StdMachine { - /// Machine base members. - base: MachineBase, - /// PCI/PCIe host bridge. - pci_host: Arc>, - /// VM power button, handle VM `Shutdown` event. - pub power_button: Arc, - /// Shutdown request, handle VM `shutdown` event. - shutdown_req: Arc, - /// Reset request, handle VM `Reset` event. - reset_req: Arc, - /// Pause request, handle VM `Pause` event. - pause_req: Arc, - /// Resume request, handle VM `Resume` event. - resume_req: Arc, - /// Device Tree Blob. - dtb_vec: Vec, - /// List contains the boot order of boot devices. - boot_order_list: Arc>>, - /// OHUI server - #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] - ohui_server: Option>, -} - impl StdMachine { pub fn new(vm_config: &VmConfig) -> Result { let free_irqs = ( @@ -258,27 +222,6 @@ impl StdMachine { Ok(()) } - pub fn handle_destroy_request(vm: &Arc>) -> bool { - let locked_vm = vm.lock().unwrap(); - let vmstate = { - let state = locked_vm.base.vm_state.deref().0.lock().unwrap(); - *state - }; - - if !locked_vm.notify_lifecycle(vmstate, VmState::Shutdown) { - warn!("Failed to destroy guest, destroy continue."); - if locked_vm.shutdown_req.write(1).is_err() { - error!("Failed to send shutdown request.") - } - return false; - } - - EventLoop::kick_all(); - info!("vm destroy"); - - true - } - fn build_pptt_cores(&self, pptt: &mut AcpiTable, cluster_offset: u32, uid: &mut u32) { for core in 0..self.base.cpu_topo.cores { let mut priv_resources = vec![0; 3]; @@ -1196,111 +1139,6 @@ impl AcpiBuilder for StdMachine { } } -impl MachineLifecycle for StdMachine { - fn pause(&self) -> bool { - if self.notify_lifecycle(VmState::Running, VmState::Paused) { - event!(Stop); - true - } else { - false - } - } - - fn resume(&self) -> bool { - if !self.notify_lifecycle(VmState::Paused, VmState::Running) { - return false; - } - event!(Resume); - true - } - - fn destroy(&self) -> bool { - if self.shutdown_req.write(1).is_err() { - error!("Failed to send shutdown request."); - return false; - } - - true - } - - fn powerdown(&self) -> bool { - if self.power_button.write(1).is_err() { - error!("ARM standard vm write power button failed"); - return false; - } - true - } - - fn get_shutdown_action(&self) -> ShutdownAction { - self.base - .vm_config - .lock() - .unwrap() - .machine_config - .shutdown_action - } - - fn reset(&mut self) -> bool { - if self.reset_req.write(1).is_err() { - error!("ARM standard vm write reset req failed"); - return false; - } - true - } - - fn notify_lifecycle(&self, old: VmState, new: VmState) -> bool { - if let Err(e) = self.vm_state_transfer( - &self.base.cpus, - &self.base.irq_chip, - &mut self.base.vm_state.0.lock().unwrap(), - old, - new, - ) { - error!("VM state transfer failed: {:?}", e); - return false; - } - true - } -} - -impl MigrateInterface for StdMachine { - fn migrate(&self, uri: String) -> Response { - match parse_incoming_uri(&uri) { - Ok((MigrateMode::File, path)) => migration::snapshot(path), - Ok((MigrateMode::Unix, path)) => migration::migration_unix_mode(path), - Ok((MigrateMode::Tcp, path)) => migration::migration_tcp_mode(path), - _ => Response::create_error_response( - qmp_schema::QmpErrorClass::GenericError(format!("Invalid uri: {}", uri)), - None, - ), - } - } - - fn query_migrate(&self) -> Response { - migration::query_migrate() - } - - fn cancel_migrate(&self) -> Response { - migration::cancel_migrate() - } -} - -impl MachineInterface for StdMachine {} -impl MachineExternalInterface for StdMachine {} -impl MachineTestInterface for StdMachine {} - -impl EventLoopManager for StdMachine { - fn loop_should_exit(&self) -> bool { - let vmstate = self.base.vm_state.deref().0.lock().unwrap(); - *vmstate == VmState::Shutdown - } - - fn loop_cleanup(&self) -> Result<()> { - set_termi_canon_mode().with_context(|| "Failed to set terminal to canonical mode")?; - Ok(()) - } -} - /// Function that helps to generate flash node in device-tree. /// diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index f18350ae..c8617ef9 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -12,11 +12,7 @@ pub mod syscall; -#[cfg(target_arch = "aarch64")] -pub use crate::aarch64::standard::StdMachine; pub use crate::error::MachineError; -#[cfg(target_arch = "x86_64")] -pub use crate::x86_64::standard::StdMachine; use std::mem::size_of; use std::ops::Deref; @@ -28,7 +24,8 @@ use std::sync::{Arc, Mutex}; use std::u64; use anyhow::{bail, Context, Result}; -use log::error; +use log::{error, info, warn}; +use util::set_termi_canon_mode; use vmm_sys_util::epoll::EventSet; use vmm_sys_util::eventfd::EventFd; @@ -40,7 +37,7 @@ use crate::x86_64::ich9_lpc::{ }; #[cfg(target_arch = "x86_64")] use crate::x86_64::standard::{LayoutEntryType, MEM_LAYOUT}; -use crate::MachineOps; +use crate::{MachineBase, MachineOps}; #[cfg(target_arch = "x86_64")] use acpi::AcpiGenericAddress; use acpi::{ @@ -57,18 +54,23 @@ use devices::legacy::FwCfgOps; #[cfg(feature = "scream")] use devices::misc::scream::set_record_authority; use devices::pci::hotplug::{handle_plug, handle_unplug_pci_request}; -use devices::pci::PciBus; +use devices::pci::{PciBus, PciHost}; #[cfg(feature = "usb_camera")] use machine_manager::config::get_cameradev_config; +#[cfg(target_arch = "aarch64")] +use machine_manager::config::ShutdownAction; #[cfg(feature = "windows_emu_pid")] use machine_manager::config::VmConfig; use machine_manager::config::{ - get_chardev_config, get_netdev_config, memory_unit_conversion, ConfigCheck, DiskFormat, - DriveConfig, ExBool, NumaNode, NumaNodes, M, + get_chardev_config, get_netdev_config, memory_unit_conversion, parse_incoming_uri, + BootIndexInfo, ConfigCheck, DiskFormat, DriveConfig, ExBool, MigrateMode, NumaNode, NumaNodes, + M, }; +use machine_manager::event; use machine_manager::event_loop::EventLoop; use machine_manager::machine::{ - DeviceInterface, MachineAddressInterface, MachineLifecycle, VmState, + DeviceInterface, MachineAddressInterface, MachineExternalInterface, MachineInterface, + MachineLifecycle, MachineTestInterface, MigrateInterface, VmState, }; use machine_manager::qmp::qmp_schema::{BlockDevAddArgument, UpdateRegionArgument}; use machine_manager::qmp::{qmp_channel::QmpChannel, qmp_response::Response, qmp_schema}; @@ -80,12 +82,70 @@ use ui::vnc::qmp_query_vnc; use util::aio::{AioEngine, WriteZeroesState}; use util::byte_code::ByteCode; use util::loop_context::{ - create_new_eventfd, read_fd, EventNotifier, NotifierCallback, NotifierOperation, + create_new_eventfd, read_fd, EventLoopManager, EventNotifier, NotifierCallback, + NotifierOperation, }; use virtio::{qmp_balloon, qmp_query_balloon}; const MAX_REGION_SIZE: u64 = 65536; +/// Standard machine structure. +pub struct StdMachine { + /// Machine base members. + pub(crate) base: MachineBase, + /// PCI/PCIe host bridge. + pub(crate) pci_host: Arc>, + /// Reset request, handle VM `Reset` event. + pub(crate) reset_req: Arc, + /// Shutdown request, handle VM `shutdown` event. + pub(crate) shutdown_req: Arc, + /// VM power button, handle VM `Shutdown` event. + pub(crate) power_button: Arc, + /// List contains the boot order of boot devices. + pub(crate) boot_order_list: Arc>>, + /// CPU Resize request, handle vm cpu hot(un)plug event. + #[cfg(target_arch = "x86_64")] + pub(crate) cpu_resize_req: Arc, + /// Cpu Controller. + #[cfg(target_arch = "x86_64")] + pub(crate) cpu_controller: Option>>, + /// Pause request, handle VM `Pause` event. + #[cfg(target_arch = "aarch64")] + pub(crate) pause_req: Arc, + /// Resume request, handle VM `Resume` event. + #[cfg(target_arch = "aarch64")] + pub(crate) resume_req: Arc, + /// Device Tree Blob. + #[cfg(target_arch = "aarch64")] + pub(crate) dtb_vec: Vec, + /// OHUI server + #[cfg(all(target_arch = "aarch64", target_env = "ohos", feature = "ohui_srv"))] + pub(crate) ohui_server: Option>, +} + +impl StdMachine { + pub fn handle_destroy_request(vm: &Arc>) -> bool { + let locked_vm = vm.lock().unwrap(); + let vmstate = { + let state = locked_vm.base.vm_state.deref().0.lock().unwrap(); + *state + }; + + if !locked_vm.notify_lifecycle(vmstate, VmState::Shutdown) { + warn!("Failed to destroy guest, destroy continue."); + if locked_vm.shutdown_req.write(1).is_err() { + error!("Failed to send shutdown request.") + } + return false; + } + + EventLoop::kick_all(); + info!("vm destroy"); + + true + } +} + pub(crate) trait StdMachineOps: AcpiBuilder + MachineOps { fn init_pci_host(&self) -> Result<()>; @@ -930,6 +990,114 @@ impl StdMachine { } } +impl MachineLifecycle for StdMachine { + fn pause(&self) -> bool { + if self.notify_lifecycle(VmState::Running, VmState::Paused) { + event!(Stop); + true + } else { + false + } + } + + fn resume(&self) -> bool { + if !self.notify_lifecycle(VmState::Paused, VmState::Running) { + return false; + } + event!(Resume); + true + } + + fn destroy(&self) -> bool { + if self.shutdown_req.write(1).is_err() { + error!("Failed to send shutdown request."); + return false; + } + + true + } + + #[cfg(target_arch = "aarch64")] + fn powerdown(&self) -> bool { + if self.power_button.write(1).is_err() { + error!("Standard vm write power button failed"); + return false; + } + true + } + + #[cfg(target_arch = "aarch64")] + fn get_shutdown_action(&self) -> ShutdownAction { + self.base + .vm_config + .lock() + .unwrap() + .machine_config + .shutdown_action + } + + fn reset(&mut self) -> bool { + if self.reset_req.write(1).is_err() { + error!("Standard vm write reset request failed"); + return false; + } + true + } + + fn notify_lifecycle(&self, old: VmState, new: VmState) -> bool { + if let Err(e) = self.vm_state_transfer( + &self.base.cpus, + #[cfg(target_arch = "aarch64")] + &self.base.irq_chip, + &mut self.base.vm_state.0.lock().unwrap(), + old, + new, + ) { + error!("VM state transfer failed: {:?}", e); + return false; + } + true + } +} + +impl MigrateInterface for StdMachine { + fn migrate(&self, uri: String) -> Response { + match parse_incoming_uri(&uri) { + Ok((MigrateMode::File, path)) => migration::snapshot(path), + Ok((MigrateMode::Unix, path)) => migration::migration_unix_mode(path), + Ok((MigrateMode::Tcp, path)) => migration::migration_tcp_mode(path), + _ => Response::create_error_response( + qmp_schema::QmpErrorClass::GenericError(format!("Invalid uri: {}", uri)), + None, + ), + } + } + + fn query_migrate(&self) -> Response { + migration::query_migrate() + } + + fn cancel_migrate(&self) -> Response { + migration::cancel_migrate() + } +} + +impl MachineInterface for StdMachine {} +impl MachineExternalInterface for StdMachine {} +impl MachineTestInterface for StdMachine {} + +impl EventLoopManager for StdMachine { + fn loop_should_exit(&self) -> bool { + let vmstate = self.base.vm_state.deref().0.lock().unwrap(); + *vmstate == VmState::Shutdown + } + + fn loop_cleanup(&self) -> Result<()> { + set_termi_canon_mode().with_context(|| "Failed to set terminal to canonical mode")?; + Ok(()) + } +} + impl MachineAddressInterface for StdMachine { #[cfg(target_arch = "x86_64")] fn pio_in(&self, addr: u64, data: &mut [u8]) -> bool { diff --git a/machine/src/x86_64/standard.rs b/machine/src/x86_64/standard.rs index e31d6929..2deb4738 100644 --- a/machine/src/x86_64/standard.rs +++ b/machine/src/x86_64/standard.rs @@ -12,19 +12,16 @@ use std::io::{Seek, SeekFrom}; use std::mem::size_of; -use std::ops::Deref; use std::sync::{Arc, Barrier, Mutex}; use anyhow::{bail, Context, Result}; -use log::{error, info, warn}; -use vmm_sys_util::eventfd::EventFd; use super::ich9_lpc; use super::mch::Mch; use crate::error::MachineError; use crate::standard_common::syscall::syscall_whitelist; use crate::standard_common::{AcpiBuilder, StdMachineOps}; -use crate::{MachineBase, MachineOps}; +use crate::{MachineBase, MachineOps, StdMachine}; use acpi::{ AcpiIoApic, AcpiLocalApic, AcpiSratMemoryAffinity, AcpiSratProcessorAffinity, AcpiTable, AmlBuilder, AmlInteger, AmlNameDecl, AmlPackage, AmlScope, AmlScopeBuilder, TableLoader, @@ -44,26 +41,19 @@ use hypervisor::kvm::x86_64::*; use hypervisor::kvm::*; #[cfg(feature = "gtk")] use machine_manager::config::UiContext; -use machine_manager::config::{ - parse_incoming_uri, BootIndexInfo, DriveConfig, MigrateMode, NumaNode, SerialConfig, VmConfig, -}; +use machine_manager::config::{BootIndexInfo, DriveConfig, NumaNode, SerialConfig, VmConfig}; use machine_manager::event; -use machine_manager::event_loop::EventLoop; -use machine_manager::machine::{ - MachineExternalInterface, MachineInterface, MachineLifecycle, MachineTestInterface, - MigrateInterface, VmState, -}; -use machine_manager::qmp::{qmp_channel::QmpChannel, qmp_response::Response, qmp_schema}; +use machine_manager::qmp::{qmp_channel::QmpChannel, qmp_schema}; use migration::{MigrationManager, MigrationStatus}; #[cfg(feature = "gtk")] use ui::gtk::gtk_display_init; #[cfg(feature = "vnc")] use ui::vnc::vnc_init; use util::byte_code::ByteCode; -use util::loop_context::{create_new_eventfd, EventLoopManager}; +use util::gen_base_func; +use util::loop_context::create_new_eventfd; use util::seccomp::BpfRule; use util::seccomp::SeccompCmpOpt; -use util::{gen_base_func, set_termi_canon_mode}; pub(crate) const VENDOR_ID_INTEL: u16 = 0x8086; const HOLE_640K_START: u64 = 0x000A_0000; @@ -113,26 +103,6 @@ const IRQ_MAP: &[(i32, i32)] = &[ (16, 19), // Pcie ]; -/// Standard machine structure. -pub struct StdMachine { - // Machine base members. - base: MachineBase, - /// PCI/PCIe host bridge. - pci_host: Arc>, - /// Reset request, handle VM `Reset` event. - reset_req: Arc, - /// Shutdown_req, handle VM 'ShutDown' event. - shutdown_req: Arc, - /// VM power button, handle VM `Powerdown` event. - power_button: Arc, - /// CPU Resize request, handle vm cpu hot(un)plug event. - cpu_resize_req: Arc, - /// List contains the boot order of boot devices. - boot_order_list: Arc>>, - /// Cpu Controller. - cpu_controller: Option>>, -} - impl StdMachine { pub fn new(vm_config: &VmConfig) -> Result { let free_irqs = ( @@ -208,27 +178,6 @@ impl StdMachine { Ok(()) } - pub fn handle_destroy_request(vm: &Arc>) -> bool { - let locked_vm = vm.lock().unwrap(); - let vmstate = { - let state = locked_vm.base.vm_state.deref().0.lock().unwrap(); - *state - }; - - if !locked_vm.notify_lifecycle(vmstate, VmState::Shutdown) { - warn!("Failed to destroy guest, destroy continue."); - if locked_vm.shutdown_req.write(1).is_err() { - error!("Failed to send shutdown request.") - } - return false; - } - - EventLoop::kick_all(); - info!("vm destroy"); - - true - } - fn init_ich9_lpc(&self, vm: Arc>) -> Result<()> { let clone_vm = vm.clone(); let root_bus = Arc::downgrade(&self.pci_host.lock().unwrap().root_bus); @@ -970,90 +919,3 @@ impl AcpiBuilder for StdMachine { Ok(srat_begin) } } - -impl MachineLifecycle for StdMachine { - fn pause(&self) -> bool { - if self.notify_lifecycle(VmState::Running, VmState::Paused) { - event!(Stop); - true - } else { - false - } - } - - fn resume(&self) -> bool { - if !self.notify_lifecycle(VmState::Paused, VmState::Running) { - return false; - } - event!(Resume); - true - } - - fn destroy(&self) -> bool { - if self.shutdown_req.write(1).is_err() { - error!("Failed to send shutdown request."); - return false; - } - - true - } - - fn reset(&mut self) -> bool { - if self.reset_req.write(1).is_err() { - error!("X86 standard vm write reset request failed"); - return false; - } - true - } - - fn notify_lifecycle(&self, old: VmState, new: VmState) -> bool { - if let Err(e) = self.vm_state_transfer( - &self.base.cpus, - &mut self.base.vm_state.0.lock().unwrap(), - old, - new, - ) { - error!("VM state transfer failed: {:?}", e); - return false; - } - true - } -} - -impl MigrateInterface for StdMachine { - fn migrate(&self, uri: String) -> Response { - match parse_incoming_uri(&uri) { - Ok((MigrateMode::File, path)) => migration::snapshot(path), - Ok((MigrateMode::Unix, path)) => migration::migration_unix_mode(path), - Ok((MigrateMode::Tcp, path)) => migration::migration_tcp_mode(path), - _ => Response::create_error_response( - qmp_schema::QmpErrorClass::GenericError(format!("Invalid uri: {}", uri)), - None, - ), - } - } - - fn query_migrate(&self) -> Response { - migration::query_migrate() - } - - fn cancel_migrate(&self) -> Response { - migration::cancel_migrate() - } -} - -impl MachineInterface for StdMachine {} -impl MachineExternalInterface for StdMachine {} -impl MachineTestInterface for StdMachine {} - -impl EventLoopManager for StdMachine { - fn loop_should_exit(&self) -> bool { - let vmstate = self.base.vm_state.deref().0.lock().unwrap(); - *vmstate == VmState::Shutdown - } - - fn loop_cleanup(&self) -> Result<()> { - set_termi_canon_mode().with_context(|| "Failed to set terminal to canonical mode")?; - Ok(()) - } -} -- Gitee From 62c8084ae4aca4e1088e3887d59435471460453e Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sun, 16 Jun 2024 08:03:37 +0800 Subject: [PATCH 138/489] micro_vm: execute the shutdown action in the main thread In Hongmeng, the VCPU status is queried when the virtual machine shuts down. In micro VM, the VCPU is already trapped for executing a shutdown action and will not change the state of the VCPU, while shutting down will keep querying for state changes, resulting in a loop timeout. This leads to the micro vm getting stuck when shutting down on hongmeng. Move the shutdown action of the micro VM to the main thread, so that the VCPU thread will not get stuck by itself and the shutdown can proceed normally. Signed-off-by: liuxiangdong --- machine/src/aarch64/micro.rs | 4 +- machine/src/aarch64/standard.rs | 7 ++-- machine/src/lib.rs | 60 ++++++++++++++++++++++++++---- machine/src/micro_common/mod.rs | 24 ++++++------ machine/src/standard_common/mod.rs | 52 +------------------------- machine/src/x86_64/micro.rs | 7 ++-- machine/src/x86_64/standard.rs | 10 ++--- 7 files changed, 80 insertions(+), 84 deletions(-) diff --git a/machine/src/aarch64/micro.rs b/machine/src/aarch64/micro.rs index 39fed7e4..e43cf5eb 100644 --- a/machine/src/aarch64/micro.rs +++ b/machine/src/aarch64/micro.rs @@ -15,7 +15,7 @@ use std::sync::{Arc, Mutex}; use anyhow::{bail, Context, Result}; use crate::{micro_common::syscall::syscall_whitelist, MachineBase, MachineError}; -use crate::{LightMachine, MachineOps}; +use crate::{register_shutdown_event, LightMachine, MachineOps}; use address_space::{AddressSpace, GuestAddress, Region}; use cpu::CPUTopology; use devices::{legacy::PL031, ICGICConfig, ICGICv2Config, ICGICv3Config, GIC_IRQ_MAX}; @@ -193,6 +193,8 @@ impl MachineOps for LightMachine { fdt_vec.len() as u64, ) .with_context(|| MachineError::WrtFdtErr(boot_config.fdt_addr, fdt_vec.len()))?; + register_shutdown_event(locked_vm.shutdown_req.clone(), vm.clone()) + .with_context(|| "Failed to register shutdown event")?; MigrationManager::register_vm_instance(vm.clone()); MigrationManager::register_migration_instance(locked_vm.base.migration_hypervisor.clone()); diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index a3cb4dbd..b731c0d3 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -24,7 +24,7 @@ use clap::Parser; use super::pci_host_root::PciHostRoot; use crate::standard_common::syscall::syscall_whitelist; use crate::standard_common::{AcpiBuilder, StdMachineOps}; -use crate::{MachineBase, MachineOps, StdMachine}; +use crate::{register_shutdown_event, MachineBase, MachineOps, StdMachine}; use acpi::{ processor_append_priv_res, AcpiGicCpu, AcpiGicDistributor, AcpiGicIts, AcpiGicRedistributor, AcpiSratGiccAffinity, AcpiSratMemoryAffinity, AcpiTable, AmlBuilder, AmlDevice, AmlInteger, @@ -524,9 +524,8 @@ impl MachineOps for StdMachine { let nr_cpus = vm_config.machine_config.nr_cpus; let mut locked_vm = vm.lock().unwrap(); locked_vm.init_global_config(vm_config)?; - locked_vm - .register_shutdown_event(locked_vm.shutdown_req.clone(), vm.clone()) - .with_context(|| "Fail to register shutdown event")?; + register_shutdown_event(locked_vm.shutdown_req.clone(), vm.clone()) + .with_context(|| "Failed to register shutdown event")?; locked_vm .register_reset_event(locked_vm.reset_req.clone(), vm.clone()) .with_context(|| "Fail to register reset event")?; diff --git a/machine/src/lib.rs b/machine/src/lib.rs index a956e1f9..7dccd8f2 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -27,16 +27,18 @@ use std::collections::{BTreeMap, HashMap}; use std::fs::{remove_file, File}; use std::net::TcpListener; use std::ops::Deref; +use std::os::unix::io::AsRawFd; use std::os::unix::net::UnixListener; use std::path::Path; +use std::rc::Rc; use std::sync::{Arc, Barrier, Condvar, Mutex, RwLock, Weak}; #[cfg(feature = "windows_emu_pid")] use std::time::Duration; use anyhow::{anyhow, bail, Context, Result}; use clap::Parser; -use log::warn; -#[cfg(feature = "windows_emu_pid")] +use log::{info, warn}; +use vmm_sys_util::epoll::EventSet; use vmm_sys_util::eventfd::EventFd; #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] @@ -83,16 +85,19 @@ use machine_manager::config::{ VirtioSerialPortCfg, VmConfig, FAST_UNPLUG_ON, MAX_VIRTIO_QUEUE, }; use machine_manager::event_loop::EventLoop; -use machine_manager::machine::{HypervisorType, MachineInterface, PauseNotify, VmState}; +use machine_manager::machine::{ + HypervisorType, MachineInterface, MachineLifecycle, PauseNotify, VmState, +}; use machine_manager::{check_arg_exist, check_arg_nonexist}; use migration::{MigrateOps, MigrationManager}; #[cfg(feature = "windows_emu_pid")] use ui::console::{get_run_stage, VmRunningStage}; +use util::arg_parser; use util::file::{clear_file, lock_file, unlock_file}; -use util::{ - arg_parser, - seccomp::{BpfRule, SeccompOpt, SyscallFilter}, +use util::loop_context::{ + gen_delete_notifiers, EventNotifier, NotifierCallback, NotifierOperation, }; +use util::seccomp::{BpfRule, SeccompOpt, SyscallFilter}; use vfio::{vfio_register_pcidevops_type, VfioConfig, VfioDevice, VfioPciDevice, KVM_DEVICE_FD}; #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] use virtio::VirtioDeviceQuirk; @@ -304,7 +309,7 @@ macro_rules! create_device_add_matches { }; } -pub trait MachineOps { +pub trait MachineOps: MachineLifecycle { fn machine_base(&self) -> &MachineBase; fn machine_base_mut(&mut self) -> &mut MachineBase; @@ -2251,6 +2256,47 @@ pub trait MachineOps { } } +fn register_shutdown_event( + shutdown_req: Arc, + vm: Arc>, +) -> Result<()> { + let shutdown_req_fd = shutdown_req.as_raw_fd(); + let shutdown_req_handler: Rc = Rc::new(move |_, _| { + let _ret = shutdown_req.read(); + if handle_destroy_request(&vm) { + Some(gen_delete_notifiers(&[shutdown_req_fd])) + } else { + None + } + }); + let notifier = EventNotifier::new( + NotifierOperation::AddShared, + shutdown_req_fd, + None, + EventSet::IN, + vec![shutdown_req_handler], + ); + EventLoop::update_event(vec![notifier], None) + .with_context(|| "Failed to register event notifier.") +} + +fn handle_destroy_request(vm: &Arc>) -> bool { + let locked_vm = vm.lock().unwrap(); + let vmstate: VmState = { + let state = locked_vm.machine_base().vm_state.deref().0.lock().unwrap(); + *state + }; + + if !locked_vm.notify_lifecycle(vmstate, VmState::Shutdown) { + return false; + } + + info!("vm destroy"); + EventLoop::kick_all(); + + true +} + /// Normal run or resume virtual machine from migration/snapshot. /// /// # Arguments diff --git a/machine/src/micro_common/mod.rs b/machine/src/micro_common/mod.rs index 8aee4003..03dd0356 100644 --- a/machine/src/micro_common/mod.rs +++ b/machine/src/micro_common/mod.rs @@ -39,7 +39,8 @@ use std::vec::Vec; use anyhow::{anyhow, bail, Context, Result}; use clap::Parser; -use log::{error, info}; +use log::error; +use vmm_sys_util::eventfd::EventFd; #[cfg(target_arch = "aarch64")] use crate::aarch64::micro::{LayoutEntryType, MEM_LAYOUT}; @@ -52,7 +53,6 @@ use machine_manager::config::{ get_chardev_socket_path, parse_incoming_uri, str_slip_to_clap, ConfigCheck, DriveConfig, MigrateMode, NetDevcfg, NetworkInterfaceConfig, VmConfig, }; -use machine_manager::event_loop::EventLoop; use machine_manager::machine::{ DeviceInterface, MachineAddressInterface, MachineExternalInterface, MachineInterface, MachineLifecycle, MigrateInterface, VmState, @@ -62,7 +62,8 @@ use machine_manager::qmp::{ }; use machine_manager::{check_arg_nonexist, event}; use migration::MigrationManager; -use util::{loop_context::EventLoopManager, num_ops::str_to_num, set_termi_canon_mode}; +use util::loop_context::{create_new_eventfd, EventLoopManager}; +use util::{num_ops::str_to_num, set_termi_canon_mode}; use virtio::device::block::VirtioBlkDevConfig; use virtio::{ create_tap, qmp_balloon, qmp_query_balloon, Block, BlockState, Net, VhostKern, VhostUser, @@ -134,6 +135,8 @@ pub struct LightMachine { pub(crate) base: MachineBase, // All replaceable device information. pub(crate) replaceable_info: MmioReplaceableInfo, + /// Shutdown request, handle VM `shutdown` event. + pub(crate) shutdown_req: Arc, } impl LightMachine { @@ -153,6 +156,10 @@ impl LightMachine { Ok(LightMachine { base, replaceable_info: MmioReplaceableInfo::new(), + shutdown_req: Arc::new( + create_new_eventfd() + .with_context(|| MachineError::InitEventFdErr("shutdown_req".to_string()))?, + ), }) } @@ -514,18 +521,11 @@ impl MachineLifecycle for LightMachine { } fn destroy(&self) -> bool { - let vmstate = { - let state = self.base.vm_state.deref().0.lock().unwrap(); - *state - }; - - if !self.notify_lifecycle(vmstate, VmState::Shutdown) { + if self.shutdown_req.write(1).is_err() { + error!("Failed to send shutdown request."); return false; } - info!("vm destroy"); - EventLoop::kick_all(); - true } diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index c8617ef9..d34df77a 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -24,7 +24,7 @@ use std::sync::{Arc, Mutex}; use std::u64; use anyhow::{bail, Context, Result}; -use log::{error, info, warn}; +use log::error; use util::set_termi_canon_mode; use vmm_sys_util::epoll::EventSet; use vmm_sys_util::eventfd::EventFd; @@ -123,29 +123,6 @@ pub struct StdMachine { pub(crate) ohui_server: Option>, } -impl StdMachine { - pub fn handle_destroy_request(vm: &Arc>) -> bool { - let locked_vm = vm.lock().unwrap(); - let vmstate = { - let state = locked_vm.base.vm_state.deref().0.lock().unwrap(); - *state - }; - - if !locked_vm.notify_lifecycle(vmstate, VmState::Shutdown) { - warn!("Failed to destroy guest, destroy continue."); - if locked_vm.shutdown_req.write(1).is_err() { - error!("Failed to send shutdown request.") - } - return false; - } - - EventLoop::kick_all(); - info!("vm destroy"); - - true - } -} - pub(crate) trait StdMachineOps: AcpiBuilder + MachineOps { fn init_pci_host(&self) -> Result<()>; @@ -392,33 +369,6 @@ pub(crate) trait StdMachineOps: AcpiBuilder + MachineOps { EventLoop::update_event(vec![notifier], None) .with_context(|| "Failed to register event notifier.") } - - fn register_shutdown_event( - &self, - shutdown_req: Arc, - clone_vm: Arc>, - ) -> Result<()> { - use util::loop_context::gen_delete_notifiers; - - let shutdown_req_fd = shutdown_req.as_raw_fd(); - let shutdown_req_handler: Rc = Rc::new(move |_, _| { - let _ret = shutdown_req.read(); - if StdMachine::handle_destroy_request(&clone_vm) { - Some(gen_delete_notifiers(&[shutdown_req_fd])) - } else { - None - } - }); - let notifier = EventNotifier::new( - NotifierOperation::AddShared, - shutdown_req_fd, - None, - EventSet::IN, - vec![shutdown_req_handler], - ); - EventLoop::update_event(vec![notifier], None) - .with_context(|| "Failed to register event notifier.") - } } /// Trait that helps to build ACPI tables. diff --git a/machine/src/x86_64/micro.rs b/machine/src/x86_64/micro.rs index 219df0bd..f5b19b7f 100644 --- a/machine/src/x86_64/micro.rs +++ b/machine/src/x86_64/micro.rs @@ -14,9 +14,8 @@ use std::sync::{Arc, Mutex}; use anyhow::{bail, Context, Result}; -use crate::{ - micro_common::syscall::syscall_whitelist, LightMachine, MachineBase, MachineError, MachineOps, -}; +use crate::micro_common::syscall::syscall_whitelist; +use crate::{register_shutdown_event, LightMachine, MachineBase, MachineError, MachineOps}; use address_space::{AddressSpace, Region}; use cpu::{CPUBootConfig, CPUTopology}; use devices::legacy::FwCfgOps; @@ -179,6 +178,8 @@ impl MachineOps for LightMachine { &topology, &boot_config, )?); + register_shutdown_event(locked_vm.shutdown_req.clone(), vm.clone()) + .with_context(|| "Failed to register shutdown event")?; MigrationManager::register_vm_instance(vm.clone()); let migration_hyp = locked_vm.base.migration_hypervisor.clone(); diff --git a/machine/src/x86_64/standard.rs b/machine/src/x86_64/standard.rs index 2deb4738..089cca50 100644 --- a/machine/src/x86_64/standard.rs +++ b/machine/src/x86_64/standard.rs @@ -21,7 +21,7 @@ use super::mch::Mch; use crate::error::MachineError; use crate::standard_common::syscall::syscall_whitelist; use crate::standard_common::{AcpiBuilder, StdMachineOps}; -use crate::{MachineBase, MachineOps, StdMachine}; +use crate::{register_shutdown_event, MachineBase, MachineOps, StdMachine}; use acpi::{ AcpiIoApic, AcpiLocalApic, AcpiSratMemoryAffinity, AcpiSratProcessorAffinity, AcpiTable, AmlBuilder, AmlInteger, AmlNameDecl, AmlPackage, AmlScope, AmlScopeBuilder, TableLoader, @@ -179,7 +179,6 @@ impl StdMachine { } fn init_ich9_lpc(&self, vm: Arc>) -> Result<()> { - let clone_vm = vm.clone(); let root_bus = Arc::downgrade(&self.pci_host.lock().unwrap().root_bus); let ich = ich9_lpc::LPCBridge::new( root_bus, @@ -187,9 +186,9 @@ impl StdMachine { self.reset_req.clone(), self.shutdown_req.clone(), )?; - self.register_reset_event(self.reset_req.clone(), vm) + self.register_reset_event(self.reset_req.clone(), vm.clone()) .with_context(|| "Fail to register reset event in LPC")?; - self.register_shutdown_event(ich.shutdown_req.clone(), clone_vm) + register_shutdown_event(ich.shutdown_req.clone(), vm) .with_context(|| "Fail to register shutdown event in LPC")?; ich.realize() } @@ -483,7 +482,6 @@ impl MachineOps for StdMachine { fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> { let nr_cpus = vm_config.machine_config.nr_cpus; let max_cpus = vm_config.machine_config.max_cpus; - let clone_vm = vm.clone(); let mut locked_vm = vm.lock().unwrap(); locked_vm.init_global_config(vm_config)?; locked_vm.base.numa_nodes = locked_vm.add_numa_nodes(vm_config)?; @@ -501,7 +499,7 @@ impl MachineOps for StdMachine { .init_pci_host() .with_context(|| MachineError::InitPCIeHostErr)?; locked_vm - .init_ich9_lpc(clone_vm) + .init_ich9_lpc(vm.clone()) .with_context(|| "Fail to init LPC bridge")?; locked_vm.add_devices(vm_config)?; -- Gitee From 6754fe8d1733528694e2a86a54511e2aa8917551 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=BA=A2=E5=8D=8E?= Date: Thu, 20 Jun 2024 13:03:58 +0800 Subject: [PATCH 139/489] Acpi: Disable s0 idle sleep Remove the s0 idle sleep capability. Signed-off-by: Yihua Jin --- machine/src/standard_common/mod.rs | 4 ++-- tests/mod_test/tests/aarch64/acpi_test.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index d34df77a..e8ddab4f 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -616,8 +616,8 @@ pub(crate) trait AcpiBuilder { fadt.set_field(91, 4); #[cfg(target_arch = "aarch64")] { - // FADT flag: enable HW_REDUCED_ACPI and LOW_POWER_S0_IDLE_CAPABLE bit on aarch64 plantform. - fadt.set_field(112, 1 << 21 | 1 << 20 | 1 << 10 | 1 << 8); + // FADT flag: enable HW_REDUCED_ACPI bit on aarch64 plantform. + fadt.set_field(112, 1 << 20 | 1 << 10 | 1 << 8); // ARM Boot Architecture Flags fadt.set_field(129, 0x3_u16); } diff --git a/tests/mod_test/tests/aarch64/acpi_test.rs b/tests/mod_test/tests/aarch64/acpi_test.rs index d28c8221..6ef32b64 100644 --- a/tests/mod_test/tests/aarch64/acpi_test.rs +++ b/tests/mod_test/tests/aarch64/acpi_test.rs @@ -103,8 +103,8 @@ fn check_fadt(data: &[u8]) -> (u32, u64) { assert_eq!(String::from_utf8_lossy(&data[..4]), "FACP"); assert_eq!(LittleEndian::read_u32(&data[4..]), FADT_TABLE_DATA_LENGTH); // Check length - // Enable HW_REDUCED_ACPI and LOW_POWER_S0_IDLE_CAPABLE bit - assert_eq!(LittleEndian::read_i32(&data[112..]), 0x30_0500); + // Enable HW_REDUCED_ACPI bit + assert_eq!(LittleEndian::read_i32(&data[112..]), 0x10_0500); assert_eq!(LittleEndian::read_u16(&data[129..]), 0x3); // ARM Boot Architecture Flags assert_eq!(LittleEndian::read_i32(&data[131..]), 3); // FADT minor revision -- Gitee From c76f92453325fe758b079cf8530671995f477c6d Mon Sep 17 00:00:00 2001 From: yexiao Date: Wed, 12 Jun 2024 21:22:58 +0800 Subject: [PATCH 140/489] ThreadPool: modify the upper limit of threads in pool. Set the upper limit of threads to 10 in thread pool. Signed-off-by: Xiao Ye --- util/src/thread_pool.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/src/thread_pool.rs b/util/src/thread_pool.rs index db059a80..570d4256 100644 --- a/util/src/thread_pool.rs +++ b/util/src/thread_pool.rs @@ -20,7 +20,7 @@ use log::error; use crate::link_list::{List, Node}; const MIN_THREADS: u64 = 1; -const MAX_THREADS: u64 = 64; +const MAX_THREADS: u64 = 10; type PoolTask = Box; pub trait TaskOperation: Sync + Send { -- Gitee From ed068ea088df489ba5886fbc2151e4f5adb058be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=BA=A2=E5=8D=8E?= Date: Wed, 19 Jun 2024 15:54:52 +0800 Subject: [PATCH 141/489] Main: Remove redundant branch When display log is not set, logs are output to stderr by default. So just let it handle by default. Signed-off-by: Yihua Jin --- src/main.rs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/main.rs b/src/main.rs index f97a395b..cff73cbe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -121,12 +121,7 @@ fn run() -> Result<()> { } Err(ref e) => { set_termi_canon_mode().expect("Failed to set terminal to canonical mode."); - if cmd_args.is_present("display log") { - error!("{}", format!("{:?}\r\n", e)); - } else { - write!(&mut std::io::stderr(), "{}", format_args!("{:?}\r\n", e)) - .expect("Failed to write to stderr"); - } + error!("{}", format!("{:?}\r\n", e)); // clean temporary file TempCleaner::clean(); exit_with_code(VM_EXIT_GENE_ERR); -- Gitee From daa4b907fb77b912c00c053b5003fd38c33ea1ff Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 23 May 2024 15:14:49 +0800 Subject: [PATCH 142/489] devices: delete parameters in funtion `realize` for all devices Delete parameters(except `bus`) in funtion `realize` for all devices, and move them to function `new`. This is the first step to unify the use of the `realize` function which will be moved to `device` trait. Note: the `bus` parameter in function `realize` was not deleted as it will be removed in subsequent patches. Signed-off-by: liuxiangdong --- devices/src/acpi/cpu_controller.rs | 26 ++++--- devices/src/acpi/ged.rs | 37 +++++----- devices/src/acpi/power.rs | 26 ++++--- devices/src/interrupt_controller/mod.rs | 4 ++ devices/src/legacy/fwcfg.rs | 46 ++++++------ devices/src/legacy/pflash.rs | 91 ++++++++++++------------ devices/src/legacy/pl011.rs | 46 ++++++------ devices/src/legacy/pl031.rs | 34 +++++---- devices/src/legacy/rtc.rs | 27 ++++--- devices/src/legacy/serial.rs | 41 ++++++----- devices/src/misc/scream/mod.rs | 31 ++++---- devices/src/scsi/disk.rs | 7 +- devices/src/usb/storage.rs | 3 +- devices/src/usb/uas.rs | 3 +- machine/src/aarch64/micro.rs | 40 ++++++----- machine/src/aarch64/standard.rs | 94 +++++++++++++++---------- machine/src/lib.rs | 27 ++++--- machine/src/micro_common/mod.rs | 31 +++++--- machine/src/x86_64/micro.rs | 9 ++- machine/src/x86_64/standard.rs | 70 +++++++++--------- virtio/src/lib.rs | 26 +++++++ virtio/src/transport/virtio_mmio.rs | 59 ++++++---------- 22 files changed, 425 insertions(+), 353 deletions(-) diff --git a/devices/src/acpi/cpu_controller.rs b/devices/src/acpi/cpu_controller.rs index c3052f61..9e2383d5 100644 --- a/devices/src/acpi/cpu_controller.rs +++ b/devices/src/acpi/cpu_controller.rs @@ -88,20 +88,30 @@ pub struct CpuController { } impl CpuController { - pub fn realize( - mut self, - sysbus: &mut SysBus, + pub fn new( max_cpus: u8, + sysbus: &mut SysBus, region_base: u64, region_size: u64, cpu_config: CpuConfig, hotplug_cpu_req: Arc, - ) -> Result>> { - self.max_cpus = max_cpus; - self.cpu_config = Some(cpu_config); - self.hotplug_cpu_req = Some(hotplug_cpu_req); - self.set_sys_resource(sysbus, region_base, region_size, "CPUController") + boot_vcpus: Vec>, + ) -> Result { + let mut cpu_controller = CpuController { + max_cpus, + cpu_config: Some(cpu_config), + hotplug_cpu_req: Some(hotplug_cpu_req), + ..Default::default() + }; + cpu_controller + .set_sys_resource(sysbus, region_base, region_size, "CPUController") .with_context(|| AcpiError::Alignment(region_size.try_into().unwrap()))?; + cpu_controller.set_boot_vcpu(boot_vcpus)?; + + Ok(cpu_controller) + } + + pub fn realize(self, sysbus: &mut SysBus) -> Result>> { let dev = Arc::new(Mutex::new(self)); let ret_dev = dev.clone(); sysbus.attach_device(&dev)?; diff --git a/devices/src/acpi/ged.rs b/devices/src/acpi/ged.rs index fe153842..7c3c92a4 100644 --- a/devices/src/acpi/ged.rs +++ b/devices/src/acpi/ged.rs @@ -54,6 +54,7 @@ pub enum AcpiEvent { const AML_GED_EVT_REG: &str = "EREG"; const AML_GED_EVT_SEL: &str = "ESEL"; +#[derive(Clone)] pub struct GedEvent { power_button: Arc, #[cfg(target_arch = "x86_64")] @@ -78,32 +79,32 @@ pub struct Ged { base: SysBusDevBase, notification_type: Arc, battery_present: bool, -} - -impl Default for Ged { - fn default() -> Self { - Self { - base: SysBusDevBase::default(), - notification_type: Arc::new(AtomicU32::new(AcpiEvent::Nothing as u32)), - battery_present: false, - } - } + ged_event: GedEvent, } impl Ged { - pub fn realize( - mut self, - sysbus: &mut SysBus, - ged_event: GedEvent, + pub fn new( battery_present: bool, + sysbus: &mut SysBus, region_base: u64, region_size: u64, - ) -> Result>> { - self.base.interrupt_evt = Some(Arc::new(create_new_eventfd()?)); - self.set_sys_resource(sysbus, region_base, region_size, "Ged") + ged_event: GedEvent, + ) -> Result { + let mut ged = Self { + base: SysBusDevBase::default(), + notification_type: Arc::new(AtomicU32::new(AcpiEvent::Nothing as u32)), + battery_present, + ged_event, + }; + ged.base.interrupt_evt = Some(Arc::new(create_new_eventfd()?)); + ged.set_sys_resource(sysbus, region_base, region_size, "Ged") .with_context(|| AcpiError::Alignment(region_size as u32))?; - self.battery_present = battery_present; + Ok(ged) + } + + pub fn realize(self, sysbus: &mut SysBus) -> Result>> { + let ged_event = self.ged_event.clone(); let dev = Arc::new(Mutex::new(self)); sysbus.attach_device(&dev)?; diff --git a/devices/src/acpi/power.rs b/devices/src/acpi/power.rs index 8669e8b3..1da56062 100644 --- a/devices/src/acpi/power.rs +++ b/devices/src/acpi/power.rs @@ -81,8 +81,13 @@ pub struct PowerDev { } impl PowerDev { - pub fn new(ged_dev: Arc>) -> Self { - Self { + pub fn new( + ged_dev: Arc>, + sysbus: &mut SysBus, + region_base: u64, + region_size: u64, + ) -> Result { + let mut pdev = Self { base: SysBusDevBase::default(), regs: vec![0; POWERDEV_REGS_SIZE], state: PowerDevState { @@ -91,7 +96,10 @@ impl PowerDev { last_bat_lvl: 0xffffffff, }, ged: ged_dev, - } + }; + pdev.set_sys_resource(sysbus, region_base, region_size, "PowerDev") + .with_context(|| AcpiError::Alignment(region_size as u32))?; + Ok(pdev) } fn read_sysfs_power_props( @@ -175,18 +183,8 @@ impl PowerDev { fn send_power_event(&self, evt: AcpiEvent) { self.ged.lock().unwrap().inject_acpi_event(evt); } -} - -impl PowerDev { - pub fn realize( - mut self, - sysbus: &mut SysBus, - region_base: u64, - region_size: u64, - ) -> Result<()> { - self.set_sys_resource(sysbus, region_base, region_size, "PowerDev") - .with_context(|| AcpiError::Alignment(region_size as u32))?; + pub fn realize(self, sysbus: &mut SysBus) -> Result<()> { let dev = Arc::new(Mutex::new(self)); sysbus.attach_device(&dev)?; diff --git a/devices/src/interrupt_controller/mod.rs b/devices/src/interrupt_controller/mod.rs index a1fb65d2..d1b04a16 100644 --- a/devices/src/interrupt_controller/mod.rs +++ b/devices/src/interrupt_controller/mod.rs @@ -142,6 +142,10 @@ impl IrqState { } pub fn register_irq(&mut self) -> Result<()> { + if self.irq_handler.is_none() { + return Ok(()); + } + let irq_handler = self.irq_handler.as_ref().unwrap(); if !irq_handler.irqfd_enable() { self.irq_fd = None; diff --git a/devices/src/legacy/fwcfg.rs b/devices/src/legacy/fwcfg.rs index 5e587f6e..3f18833d 100644 --- a/devices/src/legacy/fwcfg.rs +++ b/devices/src/legacy/fwcfg.rs @@ -842,23 +842,25 @@ pub struct FwCfgMem { #[cfg(target_arch = "aarch64")] impl FwCfgMem { - pub fn new(sys_mem: Arc) -> Self { - FwCfgMem { - base: SysBusDevBase::new(SysBusDevType::FwCfg), - fwcfg: FwCfgCommon::new(sys_mem), - } - } - - pub fn realize( - mut self, + pub fn new( + sys_mem: Arc, sysbus: &mut SysBus, region_base: u64, region_size: u64, - ) -> Result>> { - self.fwcfg.common_realize()?; - self.set_sys_resource(sysbus, region_base, region_size, "FwCfgMem") + ) -> Result { + let mut fwcfgmem = FwCfgMem { + base: SysBusDevBase::new(SysBusDevType::FwCfg), + fwcfg: FwCfgCommon::new(sys_mem), + }; + fwcfgmem + .set_sys_resource(sysbus, region_base, region_size, "FwCfgMem") .with_context(|| "Failed to allocate system resource for FwCfg.")?; + Ok(fwcfgmem) + } + + pub fn realize(mut self, sysbus: &mut SysBus) -> Result>> { + self.fwcfg.common_realize()?; let dev = Arc::new(Mutex::new(self)); sysbus .attach_device(&dev) @@ -1004,18 +1006,20 @@ pub struct FwCfgIO { #[cfg(target_arch = "x86_64")] impl FwCfgIO { - pub fn new(sys_mem: Arc) -> Self { - FwCfgIO { + pub fn new(sys_mem: Arc, sysbus: &mut SysBus) -> Result { + let mut fwcfg = FwCfgIO { base: SysBusDevBase::new(SysBusDevType::FwCfg), fwcfg: FwCfgCommon::new(sys_mem), - } + }; + fwcfg + .set_sys_resource(sysbus, FW_CFG_IO_BASE, FW_CFG_IO_SIZE, "FwCfgIO") + .with_context(|| "Failed to allocate system resource for FwCfg.")?; + + Ok(fwcfg) } pub fn realize(mut self, sysbus: &mut SysBus) -> Result>> { self.fwcfg.common_realize()?; - self.set_sys_resource(sysbus, FW_CFG_IO_BASE, FW_CFG_IO_SIZE, "FwCfgIO") - .with_context(|| "Failed to allocate system resource for FwCfg.")?; - let dev = Arc::new(Mutex::new(self)); sysbus .attach_device(&dev) @@ -1478,9 +1482,9 @@ mod test { fn test_read_write_aarch64() { let mut sys_bus = sysbus_init(); let sys_mem = address_space_init(); - let fwcfg = FwCfgMem::new(sys_mem); + let fwcfg = FwCfgMem::new(sys_mem, &mut sys_bus, 0x0902_0000, 0x0000_0018).unwrap(); - let fwcfg_dev = FwCfgMem::realize(fwcfg, &mut sys_bus, 0x0902_0000, 0x0000_0018).unwrap(); + let fwcfg_dev = fwcfg.realize(&mut sys_bus).unwrap(); // Read FW_CFG_DMA_SIGNATURE entry. let base = GuestAddress(0x0000); let mut read_data = vec![0xff_u8, 0xff, 0xff, 0xff]; @@ -1518,7 +1522,7 @@ mod test { fn test_read_write_x86_64() { let mut sys_bus = sysbus_init(); let sys_mem = address_space_init(); - let fwcfg = FwCfgIO::new(sys_mem); + let fwcfg = FwCfgIO::new(sys_mem, &mut sys_bus).unwrap(); let fwcfg_dev = FwCfgIO::realize(fwcfg, &mut sys_bus).unwrap(); // Read FW_CFG_DMA_SIGNATURE entry. diff --git a/devices/src/legacy/pflash.rs b/devices/src/legacy/pflash.rs index 2db2ce22..7eec7cca 100644 --- a/devices/src/legacy/pflash.rs +++ b/devices/src/legacy/pflash.rs @@ -58,6 +58,8 @@ pub struct PFlash { write_blk_size: u32, /// ROM region of PFlash. rom: Option, + /// backend: Option, + host_mmap: Arc, } impl PFlash { @@ -99,18 +101,21 @@ impl PFlash { /// * block-length is zero. /// * PFlash size is zero. /// * flash is writable and file size is smaller than region_max_size. + #[allow(clippy::too_many_arguments)] pub fn new( region_max_size: u64, - backend: &Option, + backend: Option, block_len: u32, bank_width: u32, device_width: u32, read_only: bool, + sysbus: &mut SysBus, + region_base: u64, ) -> Result { if block_len == 0 { bail!("PFlash: block-length is zero which is invalid."); } - let size = Self::flash_region_size(region_max_size, backend, read_only)?; + let size = Self::flash_region_size(region_max_size, &backend, read_only)?; let blocks_per_device: u32 = size as u32 / block_len; if blocks_per_device == 0 { bail!("PFlash: num-blocks is zero which is invalid."); @@ -187,9 +192,21 @@ impl PFlash { // Number of protection fields. cfi_table[0x3f] = 0x01; - Ok(PFlash { + let has_backend = backend.is_some(); + let region_size = Self::flash_region_size(region_max_size, &backend, read_only)?; + let host_mmap = Arc::new(HostMemMapping::new( + GuestAddress(region_base), + None, + region_size, + backend.map(FileBackend::new_common), + false, + true, + read_only, + )?); + + let mut pflash = PFlash { base: SysBusDevBase::new(SysBusDevType::Flash), - has_backend: backend.is_some(), + has_backend, block_len, bank_width, // device id for Intel PFlash. @@ -204,33 +221,20 @@ impl PFlash { counter: 0, write_blk_size, rom: None, - }) - } + host_mmap, + }; - pub fn realize( - mut self, - sysbus: &mut SysBus, - region_base: u64, - region_max_size: u64, - backend: Option, - ) -> Result<()> { - let region_size = Self::flash_region_size(region_max_size, &backend, self.read_only)?; - self.set_sys_resource(sysbus, region_base, region_size, "PflashRom") + pflash + .set_sys_resource(sysbus, region_base, region_size, "PflashRom") .with_context(|| "Failed to allocate system resource for PFlash.")?; + Ok(pflash) + } - let host_mmap = Arc::new(HostMemMapping::new( - GuestAddress(region_base), - None, - region_size, - backend.map(FileBackend::new_common), - false, - true, - self.read_only, - )?); - + pub fn realize(self, sysbus: &mut SysBus) -> Result>> { + let region_base = self.base.res.region_base; + let host_mmap = self.host_mmap.clone(); let dev = Arc::new(Mutex::new(self)); let region_ops = sysbus.build_region_ops(&dev); - let rom_region = Region::init_rom_device_region(host_mmap, region_ops, "PflashRom"); dev.lock().unwrap().rom = Some(rom_region.clone()); sysbus @@ -238,9 +242,9 @@ impl PFlash { .root() .add_subregion(rom_region, region_base) .with_context(|| "Failed to attach PFlash to system bus")?; - sysbus.devices.push(dev); + sysbus.devices.push(dev.clone()); - Ok(()) + Ok(dev) } fn set_read_array_mode(&mut self, is_illegal_cmd: bool) -> Result<()> { @@ -938,25 +942,20 @@ mod test { .open(file_name) .unwrap(), ); - let pflash = PFlash::new(flash_size, &fd, sector_len, 4, 2, read_only).unwrap(); - let sysbus = sysbus_init(); - let dev = Arc::new(Mutex::new(pflash)); - let region_ops = sysbus.build_region_ops(&dev); - let host_mmap = Arc::new( - HostMemMapping::new( - GuestAddress(flash_base), - None, - flash_size, - fd.map(FileBackend::new_common), - false, - true, - false, - ) - .unwrap(), - ); + let mut sysbus = sysbus_init(); + let pflash = PFlash::new( + flash_size, + fd, + sector_len, + 4, + 2, + read_only, + &mut sysbus, + flash_base, + ) + .unwrap(); + let dev = pflash.realize(&mut sysbus).unwrap(); - let rom_region = Region::init_rom_device_region(host_mmap, region_ops, "pflash-dev"); - dev.lock().unwrap().rom = Some(rom_region); dev } diff --git a/devices/src/legacy/pl011.rs b/devices/src/legacy/pl011.rs index 2a6cab1c..293ec750 100644 --- a/devices/src/legacy/pl011.rs +++ b/devices/src/legacy/pl011.rs @@ -25,10 +25,8 @@ use acpi::{ }; use address_space::GuestAddress; use chardev_backend::chardev::{Chardev, InputReceiver}; -use machine_manager::{ - config::{BootSource, Param, SerialConfig}, - event_loop::EventLoop, -}; +use machine_manager::config::SerialConfig; +use machine_manager::event_loop::EventLoop; use migration::{ snapshot::PL011_SNAPSHOT_ID, DeviceStateDesc, FieldDesc, MigrationError, MigrationHook, MigrationManager, StateTransfer, @@ -131,8 +129,13 @@ pub struct PL011 { impl PL011 { /// Create a new `PL011` instance with default parameters. - pub fn new(cfg: SerialConfig) -> Result { - Ok(PL011 { + pub fn new( + cfg: SerialConfig, + sysbus: &mut SysBus, + region_base: u64, + region_size: u64, + ) -> Result { + let mut pl011 = PL011 { base: SysBusDevBase { dev_type: SysBusDevType::PL011, interrupt_evt: Some(Arc::new(create_new_eventfd()?)), @@ -141,7 +144,12 @@ impl PL011 { paused: false, state: PL011State::new(), chardev: Arc::new(Mutex::new(Chardev::new(cfg.chardev))), - }) + }; + pl011 + .set_sys_resource(sysbus, region_base, region_size, "PL011") + .with_context(|| "Failed to set system resource for PL011.")?; + + Ok(pl011) } fn interrupt(&mut self) { @@ -154,30 +162,16 @@ impl PL011 { } } - pub fn realize( - mut self, - sysbus: &mut SysBus, - region_base: u64, - region_size: u64, - bs: &Arc>, - ) -> Result<()> { + pub fn realize(self, sysbus: &mut SysBus) -> Result<()> { self.chardev .lock() .unwrap() .realize() .with_context(|| "Failed to realize chardev")?; - self.set_sys_resource(sysbus, region_base, region_size, "PL011") - .with_context(|| "Failed to set system resource for PL011.")?; - let dev = Arc::new(Mutex::new(self)); sysbus .attach_device(&dev) .with_context(|| "Failed to attach PL011 to system bus.")?; - - bs.lock().unwrap().kernel_cmdline.push(Param { - param_type: "earlycon".to_string(), - value: format!("pl011,mmio,0x{:08x}", region_base), - }); MigrationManager::register_device_instance( PL011State::descriptor(), dev.clone(), @@ -455,6 +449,7 @@ impl AmlBuilder for PL011 { #[cfg(test)] mod test { use super::*; + use crate::sysbus::sysbus_init; use machine_manager::config::{ChardevConfig, ChardevType}; #[test] @@ -464,10 +459,11 @@ mod test { id: "chardev".to_string(), }, }; - let mut pl011_dev = PL011::new(SerialConfig { + let config = SerialConfig { chardev: chardev_cfg, - }) - .unwrap(); + }; + let mut sysbus = sysbus_init(); + let mut pl011_dev = PL011::new(config, &mut sysbus, 0x0900_0000, 0x0000_1000).unwrap(); assert_eq!(pl011_dev.state.rfifo, [0; PL011_FIFO_SIZE]); assert_eq!(pl011_dev.state.flags, 0x90); assert_eq!(pl011_dev.state.lcr, 0); diff --git a/devices/src/legacy/pl031.rs b/devices/src/legacy/pl031.rs index 98a35196..f1d330c7 100644 --- a/devices/src/legacy/pl031.rs +++ b/devices/src/legacy/pl031.rs @@ -79,9 +79,9 @@ pub struct PL031 { base_time: Instant, } -impl Default for PL031 { - fn default() -> Self { - Self { +impl PL031 { + pub fn new(sysbus: &mut SysBus, region_base: u64, region_size: u64) -> Result { + let mut pl031 = Self { base: SysBusDevBase::new(SysBusDevType::Rtc), state: PL031State::default(), // since 1970-01-01 00:00:00,it never cause overflow. @@ -90,21 +90,16 @@ impl Default for PL031 { .expect("time wrong") .as_secs() as u32, base_time: Instant::now(), - } - } -} - -impl PL031 { - pub fn realize( - mut self, - sysbus: &mut SysBus, - region_base: u64, - region_size: u64, - ) -> Result<()> { - self.base.interrupt_evt = Some(Arc::new(create_new_eventfd()?)); - self.set_sys_resource(sysbus, region_base, region_size, "PL031") + }; + pl031.base.interrupt_evt = Some(Arc::new(create_new_eventfd()?)); + pl031 + .set_sys_resource(sysbus, region_base, region_size, "PL031") .with_context(|| LegacyError::SetSysResErr)?; + Ok(pl031) + } + + pub fn realize(self, sysbus: &mut SysBus) -> Result<()> { let dev = Arc::new(Mutex::new(self)); sysbus.attach_device(&dev)?; @@ -219,13 +214,15 @@ impl MigrationHook for PL031 {} #[cfg(test)] mod test { use super::*; + use crate::sysbus::sysbus_init; use util::time::mktime64; const WIGGLE: u32 = 2; #[test] fn test_set_year_20xx() { - let mut rtc = PL031::default(); + let mut sysbus = sysbus_init(); + let mut rtc = PL031::new(&mut sysbus, 0x0901_0000, 0x0000_1000).unwrap(); // Set rtc time: 2013-11-13 02:04:56. let mut wtick = mktime64(2013, 11, 13, 2, 4, 56) as u32; let mut data = [0; 4]; @@ -251,7 +248,8 @@ mod test { #[test] fn test_set_year_1970() { - let mut rtc = PL031::default(); + let mut sysbus = sysbus_init(); + let mut rtc = PL031::new(&mut sysbus, 0x0901_0000, 0x0000_1000).unwrap(); // Set rtc time (min): 1970-01-01 00:00:00. let wtick = mktime64(1970, 1, 1, 0, 0, 0) as u32; let mut data = [0; 4]; diff --git a/devices/src/legacy/rtc.rs b/devices/src/legacy/rtc.rs index 259ac981..d60b870f 100644 --- a/devices/src/legacy/rtc.rs +++ b/devices/src/legacy/rtc.rs @@ -16,7 +16,7 @@ use std::time::{Instant, SystemTime, UNIX_EPOCH}; use anyhow::Result; use log::{debug, error, warn}; -use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType, SysRes}; +use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; use crate::{Device, DeviceBase}; use acpi::{ AmlBuilder, AmlDevice, AmlEisaId, AmlIoDecode, AmlIoResource, AmlIrqNoFlags, AmlNameDecl, @@ -118,15 +118,10 @@ pub struct RTC { impl RTC { /// Construct function of RTC device. - pub fn new() -> Result { + pub fn new(sysbus: &mut SysBus) -> Result { let mut rtc = RTC { base: SysBusDevBase { dev_type: SysBusDevType::Rtc, - res: SysRes { - region_base: RTC_PORT_INDEX, - region_size: 8, - ..Default::default() - }, interrupt_evt: Some(Arc::new(create_new_eventfd()?)), ..Default::default() }, @@ -147,6 +142,8 @@ impl RTC { rtc.init_rtc_reg(); + rtc.set_sys_resource(sysbus, RTC_PORT_INDEX, 8, "RTC")?; + Ok(rtc) } @@ -267,11 +264,7 @@ impl RTC { true } - pub fn realize(mut self, sysbus: &mut SysBus) -> Result<()> { - let region_base = self.base.res.region_base; - let region_size = self.base.res.region_size; - self.set_sys_resource(sysbus, region_base, region_size, "RTC")?; - + pub fn realize(self, sysbus: &mut SysBus) -> Result<()> { let dev = Arc::new(Mutex::new(self)); sysbus.attach_device(&dev)?; Ok(()) @@ -413,6 +406,7 @@ mod test { use anyhow::Context; use super::*; + use crate::sysbus::sysbus_init; use address_space::GuestAddress; const WIGGLE: u8 = 2; @@ -433,7 +427,8 @@ mod test { #[test] fn test_set_year_20xx() -> Result<()> { - let mut rtc = RTC::new().with_context(|| "Failed to create RTC device")?; + let mut sysbus = sysbus_init(); + let mut rtc = RTC::new(&mut sysbus).with_context(|| "Failed to create RTC device")?; // Set rtc time: 2013-11-13 02:04:56 cmos_write(&mut rtc, RTC_CENTURY_BCD, 0x20); cmos_write(&mut rtc, RTC_YEAR, 0x13); @@ -467,7 +462,8 @@ mod test { #[test] fn test_set_year_1970() -> Result<()> { - let mut rtc = RTC::new().with_context(|| "Failed to create RTC device")?; + let mut sysbus = sysbus_init(); + let mut rtc = RTC::new(&mut sysbus).with_context(|| "Failed to create RTC device")?; // Set rtc time (min): 1970-01-01 00:00:00 cmos_write(&mut rtc, RTC_CENTURY_BCD, 0x19); cmos_write(&mut rtc, RTC_YEAR, 0x70); @@ -490,7 +486,8 @@ mod test { #[test] fn test_invalid_rtc_time() -> Result<()> { - let mut rtc = RTC::new().with_context(|| "Failed to create RTC device")?; + let mut sysbus = sysbus_init(); + let mut rtc = RTC::new(&mut sysbus).with_context(|| "Failed to create RTC device")?; // Set rtc year: 1969 cmos_write(&mut rtc, RTC_CENTURY_BCD, 0x19); cmos_write(&mut rtc, RTC_YEAR, 0x69); diff --git a/devices/src/legacy/serial.rs b/devices/src/legacy/serial.rs index 3386f7ff..05d6929c 100644 --- a/devices/src/legacy/serial.rs +++ b/devices/src/legacy/serial.rs @@ -124,30 +124,32 @@ pub struct Serial { } impl Serial { - pub fn new(cfg: SerialConfig) -> Self { - Serial { + pub fn new( + cfg: SerialConfig, + sysbus: &mut SysBus, + region_base: u64, + region_size: u64, + ) -> Result { + let mut serial = Serial { base: SysBusDevBase::new(SysBusDevType::Serial), paused: false, rbr: VecDeque::new(), state: SerialState::new(), chardev: Arc::new(Mutex::new(Chardev::new(cfg.chardev))), - } + }; + serial.base.interrupt_evt = Some(Arc::new(create_new_eventfd()?)); + serial + .set_sys_resource(sysbus, region_base, region_size, "Serial") + .with_context(|| LegacyError::SetSysResErr)?; + Ok(serial) } - pub fn realize( - mut self, - sysbus: &mut SysBus, - region_base: u64, - region_size: u64, - ) -> Result<()> { + + pub fn realize(self, sysbus: &mut SysBus) -> Result<()> { self.chardev .lock() .unwrap() .realize() .with_context(|| "Failed to realize chardev")?; - self.base.interrupt_evt = Some(Arc::new(create_new_eventfd()?)); - self.set_sys_resource(sysbus, region_base, region_size, "Serial") - .with_context(|| LegacyError::SetSysResErr)?; - let dev = Arc::new(Mutex::new(self)); sysbus.attach_device(&dev)?; @@ -459,6 +461,7 @@ impl MigrationHook for Serial {} #[cfg(test)] mod test { use super::*; + use crate::sysbus::sysbus_init; use machine_manager::config::{ChardevConfig, ChardevType}; #[test] @@ -469,9 +472,11 @@ mod test { id: "chardev".to_string(), }, }; - let mut usart = Serial::new(SerialConfig { + let mut sysbus = sysbus_init(); + let config = SerialConfig { chardev: chardev_cfg.clone(), - }); + }; + let mut usart = Serial::new(config, &mut sysbus, SERIAL_ADDR, 8).unwrap(); assert_eq!(usart.state.ier, 0); assert_eq!(usart.state.iir, 1); assert_eq!(usart.state.lcr, 3); @@ -525,9 +530,11 @@ mod test { id: "chardev".to_string(), }, }; - let mut usart = Serial::new(SerialConfig { + let config = SerialConfig { chardev: chardev_cfg, - }); + }; + let mut sysbus = sysbus_init(); + let mut usart = Serial::new(config, &mut sysbus, SERIAL_ADDR, 8).unwrap(); // Get state vector for usart let serial_state_result = usart.get_state_vec(); assert!(serial_state_result.is_ok()); diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index d9c8c5cb..a583b6c3 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -446,15 +446,27 @@ impl PauseNotify for Scream { } impl Scream { - pub fn new(size: u64, config: ScreamConfig, token_id: Option>>) -> Self { + pub fn new( + size: u64, + config: ScreamConfig, + token_id: Option>>, + ) -> Result { set_record_authority(config.record_auth); - Self { + let header_size = mem::size_of::() as u64; + if size < header_size { + bail!( + "The size {} of the shared memory is smaller than audio header {}", + size, + header_size + ); + } + Ok(Self { hva: 0, size, config, token_id, interface_resource: RwLock::new(Vec::new()), - } + }) } #[allow(unused_variables)] @@ -538,16 +550,7 @@ impl Scream { Ok(()) } - pub fn realize(&mut self, devfn: u8, parent_bus: Weak>) -> Result<()> { - let header_size = mem::size_of::() as u64; - if self.size < header_size { - bail!( - "The size {} of the shared memory is smaller then audio header {}", - self.size, - header_size - ); - } - + pub fn realize(&mut self, parent_bus: Weak>) -> Result<()> { let host_mmap = Arc::new(HostMemMapping::new( GuestAddress(0), None, @@ -559,8 +562,8 @@ impl Scream { )?); self.hva = host_mmap.host_address(); + let devfn = (self.config.addr.0 << 3) + self.config.addr.1; let mem_region = Region::init_ram_region(host_mmap, "ivshmem_ram"); - let ivshmem = Ivshmem::new("ivshmem".to_string(), devfn, parent_bus, mem_region); ivshmem.realize()?; diff --git a/devices/src/scsi/disk.rs b/devices/src/scsi/disk.rs index 178250a4..1f88cf0a 100644 --- a/devices/src/scsi/disk.rs +++ b/devices/src/scsi/disk.rs @@ -161,6 +161,7 @@ pub struct ScsiDevice { drive_files: Arc>>, /// Aio context. pub aio: Option>>>, + pub iothread: Option, } // SAFETY: the devices attached in one scsi controller will process IO in the same thread. @@ -173,6 +174,7 @@ impl ScsiDevice { dev_cfg: ScsiDevConfig, drive_cfg: DriveConfig, drive_files: Arc>>, + iothread: Option, ) -> ScsiDevice { let scsi_type = match dev_cfg.classtype.as_str() { "scsi-hd" => SCSI_TYPE_DISK, @@ -193,10 +195,11 @@ impl ScsiDevice { parent_bus: Weak::new(), drive_files, aio: None, + iothread, } } - pub fn realize(&mut self, iothread: Option) -> Result<()> { + pub fn realize(&mut self) -> Result<()> { match self.scsi_type { SCSI_TYPE_DISK => { self.block_size = SCSI_DISK_DEFAULT_BLOCK_SIZE; @@ -232,7 +235,7 @@ impl ScsiDevice { let conf = BlockProperty { id: drive_id, format: self.drive_cfg.format, - iothread, + iothread: self.iothread.clone(), direct: self.drive_cfg.direct, req_align: self.req_align, buf_align: self.buf_align, diff --git a/devices/src/usb/storage.rs b/devices/src/usb/storage.rs index 67c03488..429c7b9b 100644 --- a/devices/src/usb/storage.rs +++ b/devices/src/usb/storage.rs @@ -354,6 +354,7 @@ impl UsbStorage { scsi_dev_cfg, drive_cfg, drive_files, + None, ))), }) } @@ -555,7 +556,7 @@ impl UsbDevice for UsbStorage { // NOTE: "aio=off,direct=false" must be configured and other aio/direct values are not // supported. let mut locked_scsi_dev = self.scsi_dev.lock().unwrap(); - locked_scsi_dev.realize(None)?; + locked_scsi_dev.realize()?; drop(locked_scsi_dev); self.scsi_bus .lock() diff --git a/devices/src/usb/uas.rs b/devices/src/usb/uas.rs index e913ca5c..e0104272 100644 --- a/devices/src/usb/uas.rs +++ b/devices/src/usb/uas.rs @@ -621,6 +621,7 @@ impl UsbUas { scsi_dev_cfg, drive_cfg, drive_files, + None, ))), commands_high: VecDeque::new(), commands_super: array::from_fn(|_| None), @@ -1050,7 +1051,7 @@ impl UsbDevice for UsbUas { // NOTE: "aio=off,direct=false" must be configured and other aio/direct values are not // supported. let mut locked_scsi_device = self.scsi_device.lock().unwrap(); - locked_scsi_device.realize(None)?; + locked_scsi_device.realize()?; locked_scsi_device.parent_bus = Arc::downgrade(&self.scsi_bus); drop(locked_scsi_device); self.scsi_bus diff --git a/machine/src/aarch64/micro.rs b/machine/src/aarch64/micro.rs index e43cf5eb..6b019d94 100644 --- a/machine/src/aarch64/micro.rs +++ b/machine/src/aarch64/micro.rs @@ -18,9 +18,10 @@ use crate::{micro_common::syscall::syscall_whitelist, MachineBase, MachineError} use crate::{register_shutdown_event, LightMachine, MachineOps}; use address_space::{AddressSpace, GuestAddress, Region}; use cpu::CPUTopology; -use devices::{legacy::PL031, ICGICConfig, ICGICv2Config, ICGICv3Config, GIC_IRQ_MAX}; +use devices::legacy::{PL011, PL031}; +use devices::{ICGICConfig, ICGICv2Config, ICGICv3Config, GIC_IRQ_MAX}; use hypervisor::kvm::aarch64::*; -use machine_manager::config::{SerialConfig, VmConfig}; +use machine_manager::config::{Param, SerialConfig, VmConfig}; use migration::{MigrationManager, MigrationStatus}; use util::device_tree::{self, CompileFDT, FdtBuilder}; use util::gen_base_func; @@ -105,30 +106,35 @@ impl MachineOps for LightMachine { } fn add_rtc_device(&mut self) -> Result<()> { - PL031::realize( - PL031::default(), + let pl031 = PL031::new( &mut self.base.sysbus, MEM_LAYOUT[LayoutEntryType::Rtc as usize].0, MEM_LAYOUT[LayoutEntryType::Rtc as usize].1, - ) - .with_context(|| "Failed to realize pl031.") + )?; + pl031 + .realize(&mut self.base.sysbus) + .with_context(|| "Failed to realize pl031.") } fn add_serial_device(&mut self, config: &SerialConfig) -> Result<()> { - use devices::legacy::PL011; - let region_base: u64 = MEM_LAYOUT[LayoutEntryType::Uart as usize].0; let region_size: u64 = MEM_LAYOUT[LayoutEntryType::Uart as usize].1; - - let pl011 = PL011::new(config.clone()).with_context(|| "Failed to create PL011")?; + let pl011 = PL011::new( + config.clone(), + &mut self.base.sysbus, + region_base, + region_size, + ) + .with_context(|| "Failed to create PL011")?; pl011 - .realize( - &mut self.base.sysbus, - region_base, - region_size, - &self.base.boot_source, - ) - .with_context(|| "Failed to realize PL011") + .realize(&mut self.base.sysbus) + .with_context(|| "Failed to realize PL011")?; + let mut bs = self.base.boot_source.lock().unwrap(); + bs.kernel_cmdline.push(Param { + param_type: "earlycon".to_string(), + value: format!("pl011,mmio,0x{:08x}", region_base), + }); + Ok(()) } fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> { diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index b731c0d3..fe8e6a02 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -57,7 +57,9 @@ use hypervisor::kvm::*; use machine_manager::config::str_slip_to_clap; #[cfg(feature = "gtk")] use machine_manager::config::UiContext; -use machine_manager::config::{BootIndexInfo, DriveConfig, NumaNode, SerialConfig, VmConfig}; +use machine_manager::config::{ + BootIndexInfo, DriveConfig, NumaNode, Param, SerialConfig, VmConfig, +}; use machine_manager::event; use machine_manager::machine::{MachineLifecycle, PauseNotify}; use machine_manager::qmp::{qmp_channel::QmpChannel, qmp_schema}; @@ -343,7 +345,12 @@ impl StdMachineOps for StdMachine { return Ok(None); } - let mut fwcfg = FwCfgMem::new(self.base.sys_mem.clone()); + let mut fwcfg = FwCfgMem::new( + self.base.sys_mem.clone(), + &mut self.base.sysbus, + MEM_LAYOUT[LayoutEntryType::FwCfg as usize].0, + MEM_LAYOUT[LayoutEntryType::FwCfg as usize].1, + )?; fwcfg .add_data_entry(FwCfgEntryType::NbCpus, nr_cpus.as_bytes().to_vec()) .with_context(|| DevErrorKind::AddEntryErr("NbCpus".to_string()))?; @@ -375,13 +382,9 @@ impl StdMachineOps for StdMachine { .add_file_entry("bios-geometry", bios_geometry) .with_context(|| DevErrorKind::AddEntryErr("bios-geometry".to_string()))?; - let fwcfg_dev = FwCfgMem::realize( - fwcfg, - &mut self.base.sysbus, - MEM_LAYOUT[LayoutEntryType::FwCfg as usize].0, - MEM_LAYOUT[LayoutEntryType::FwCfg as usize].1, - ) - .with_context(|| "Failed to realize fwcfg device")?; + let fwcfg_dev = fwcfg + .realize(&mut self.base.sysbus) + .with_context(|| "Failed to realize fwcfg device")?; self.base.fwcfg_dev = Some(fwcfg_dev.clone()); Ok(Some(fwcfg_dev)) @@ -454,36 +457,36 @@ impl MachineOps for StdMachine { } fn add_rtc_device(&mut self) -> Result<()> { - let rtc = PL031::default(); - PL031::realize( - rtc, + let rtc = PL031::new( &mut self.base.sysbus, MEM_LAYOUT[LayoutEntryType::Rtc as usize].0, MEM_LAYOUT[LayoutEntryType::Rtc as usize].1, - ) - .with_context(|| "Failed to realize PL031") + )?; + rtc.realize(&mut self.base.sysbus) + .with_context(|| "Failed to realize PL031") } fn add_ged_device(&mut self) -> Result<()> { let battery_present = self.base.vm_config.lock().unwrap().machine_config.battery; - let ged = Ged::default(); + let ged = Ged::new( + battery_present, + &mut self.base.sysbus, + MEM_LAYOUT[LayoutEntryType::Ged as usize].0, + MEM_LAYOUT[LayoutEntryType::Ged as usize].1, + GedEvent::new(self.power_button.clone()), + )?; let ged_dev = ged - .realize( - &mut self.base.sysbus, - GedEvent::new(self.power_button.clone()), - battery_present, - MEM_LAYOUT[LayoutEntryType::Ged as usize].0, - MEM_LAYOUT[LayoutEntryType::Ged as usize].1, - ) + .realize(&mut self.base.sysbus) .with_context(|| "Failed to realize Ged")?; if battery_present { - let pdev = PowerDev::new(ged_dev); - pdev.realize( + let pdev = PowerDev::new( + ged_dev, &mut self.base.sysbus, MEM_LAYOUT[LayoutEntryType::PowerDev as usize].0, MEM_LAYOUT[LayoutEntryType::PowerDev as usize].1, - ) - .with_context(|| "Failed to realize PowerDev")?; + )?; + pdev.realize(&mut self.base.sysbus) + .with_context(|| "Failed to realize PowerDev")?; } Ok(()) } @@ -491,16 +494,22 @@ impl MachineOps for StdMachine { fn add_serial_device(&mut self, config: &SerialConfig) -> Result<()> { let region_base: u64 = MEM_LAYOUT[LayoutEntryType::Uart as usize].0; let region_size: u64 = MEM_LAYOUT[LayoutEntryType::Uart as usize].1; - - let pl011 = PL011::new(config.clone()).with_context(|| "Failed to create PL011")?; + let pl011 = PL011::new( + config.clone(), + &mut self.base.sysbus, + region_base, + region_size, + ) + .with_context(|| "Failed to create PL011")?; pl011 - .realize( - &mut self.base.sysbus, - region_base, - region_size, - &self.base.boot_source, - ) - .with_context(|| "Failed to realize PL011") + .realize(&mut self.base.sysbus) + .with_context(|| "Failed to realize PL011")?; + let mut bs = self.base.boot_source.lock().unwrap(); + bs.kernel_cmdline.push(Param { + param_type: "earlycon".to_string(), + value: format!("pl011,mmio,0x{:08x}", region_base), + }); + Ok(()) } fn syscall_whitelist(&self) -> Vec { @@ -646,9 +655,18 @@ impl MachineOps for StdMachine { (None, false) }; - let pflash = PFlash::new(flash_size, &fd, sector_len, 4, 2, read_only) - .with_context(|| MachineError::InitPflashErr)?; - PFlash::realize(pflash, &mut self.base.sysbus, flash_base, flash_size, fd) + let pflash = PFlash::new( + flash_size, + fd, + sector_len, + 4, + 2, + read_only, + &mut self.base.sysbus, + flash_base, + ) + .with_context(|| MachineError::InitPflashErr)?; + PFlash::realize(pflash, &mut self.base.sysbus) .with_context(|| MachineError::RlzPflashErr)?; flash_base += flash_size; } diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 7dccd8f2..c02f54ab 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -1199,16 +1199,10 @@ pub trait MachineOps: MachineLifecycle { .drives .remove(&device_cfg.drive) .with_context(|| "No drive configured matched for scsi device")?; - if let Some(bootindex) = device_cfg.bootindex { self.check_bootindex(bootindex) .with_context(|| "Failed to add scsi device for invalid bootindex")?; } - let device = Arc::new(Mutex::new(ScsiDevice::new( - device_cfg.clone(), - drive_arg, - self.get_drive_files(), - ))); // Bus name `$parent_cntlr_name.0` is checked when parsing by clap. let cntlr = device_cfg.bus.split('.').collect::>()[0].to_string(); @@ -1223,7 +1217,6 @@ pub trait MachineOps: MachineLifecycle { .unwrap(); let virtio_device = virtio_pcidev.get_virtio_device().lock().unwrap(); let cntlr = virtio_device.as_any().downcast_ref::().unwrap(); - let bus = cntlr.bus.as_ref().unwrap(); if bus .lock() @@ -1234,7 +1227,14 @@ pub trait MachineOps: MachineLifecycle { bail!("Wrong! Two scsi devices have the same scsi-id and lun"); } let iothread = cntlr.config.iothread.clone(); - device.lock().unwrap().realize(iothread)?; + + let device = Arc::new(Mutex::new(ScsiDevice::new( + device_cfg.clone(), + drive_arg, + self.get_drive_files(), + iothread, + ))); + device.lock().unwrap().realize()?; bus.lock() .unwrap() .devices @@ -1670,11 +1670,8 @@ pub trait MachineOps: MachineLifecycle { token_id: Option>>, ) -> Result<()> { let config = ScreamConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; - let bdf = PciBdf { - bus: config.bus.clone(), - addr: config.addr, - }; - let (devfn, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?; + let bdf = PciBdf::new(config.bus.clone(), config.addr); + let (_, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?; let mem_cfg = vm_config .object @@ -1691,9 +1688,9 @@ pub trait MachineOps: MachineLifecycle { bail!("Object for share config is not on"); } - let mut scream = Scream::new(mem_cfg.size, config, token_id); + let mut scream = Scream::new(mem_cfg.size, config, token_id)?; scream - .realize(devfn, parent_bus) + .realize(parent_bus) .with_context(|| "Failed to realize scream device")?; self.register_vm_pause_notifier(Arc::new(scream)); Ok(()) diff --git a/machine/src/micro_common/mod.rs b/machine/src/micro_common/mod.rs index 03dd0356..349efe21 100644 --- a/machine/src/micro_common/mod.rs +++ b/machine/src/micro_common/mod.rs @@ -48,7 +48,11 @@ use crate::aarch64::micro::{LayoutEntryType, MEM_LAYOUT}; use crate::x86_64::micro::{LayoutEntryType, MEM_LAYOUT}; use crate::{MachineBase, MachineError, MachineOps}; use cpu::CpuLifecycleState; +#[cfg(target_arch = "x86_64")] +use devices::sysbus::SysBusDevOps; use devices::sysbus::{IRQ_BASE, IRQ_MAX}; +#[cfg(target_arch = "x86_64")] +use machine_manager::config::Param; use machine_manager::config::{ get_chardev_socket_path, parse_incoming_uri, str_slip_to_clap, ConfigCheck, DriveConfig, MigrateMode, NetDevcfg, NetworkInterfaceConfig, VmConfig, @@ -483,21 +487,30 @@ impl LightMachine { device: Arc>, ) -> Result>> { let sys_mem = self.get_sys_mem().clone(); - let dev = VirtioMmioDevice::new(&sys_mem, name, device); - let region_base = self.base.sysbus.min_free_base; let region_size = MEM_LAYOUT[LayoutEntryType::Mmio as usize].1; - let realized_virtio_mmio_device = VirtioMmioDevice::realize( - dev, + let dev = VirtioMmioDevice::new( + &sys_mem, + name, + device, &mut self.base.sysbus, region_base, region_size, - #[cfg(target_arch = "x86_64")] - &self.base.boot_source, - ) - .with_context(|| MachineError::RlzVirtioMmioErr)?; + )?; + let mmio_device = dev + .realize(&mut self.base.sysbus) + .with_context(|| MachineError::RlzVirtioMmioErr)?; + #[cfg(target_arch = "x86_64")] + { + let res = mmio_device.lock().unwrap().get_sys_resource().clone(); + let mut bs = self.base.boot_source.lock().unwrap(); + bs.kernel_cmdline.push(Param { + param_type: "virtio_mmio.device".to_string(), + value: format!("{}@0x{:08x}:{}", res.region_size, res.region_base, res.irq), + }); + } self.base.sysbus.min_free_base += region_size; - Ok(realized_virtio_mmio_device) + Ok(mmio_device) } } diff --git a/machine/src/x86_64/micro.rs b/machine/src/x86_64/micro.rs index f5b19b7f..0d88aaec 100644 --- a/machine/src/x86_64/micro.rs +++ b/machine/src/x86_64/micro.rs @@ -132,9 +132,14 @@ impl MachineOps for LightMachine { let region_base: u64 = SERIAL_ADDR; let region_size: u64 = 8; - let serial = Serial::new(config.clone()); + let serial = Serial::new( + config.clone(), + &mut self.base.sysbus, + region_base, + region_size, + )?; serial - .realize(&mut self.base.sysbus, region_base, region_size) + .realize(&mut self.base.sysbus) .with_context(|| "Failed to realize serial device.") } diff --git a/machine/src/x86_64/standard.rs b/machine/src/x86_64/standard.rs index 089cca50..dc970a33 100644 --- a/machine/src/x86_64/standard.rs +++ b/machine/src/x86_64/standard.rs @@ -208,8 +208,6 @@ impl StdMachine { cpu_topology: CPUTopology, vm: Arc>, ) -> Result<()> { - let cpu_controller: CpuController = Default::default(); - let region_base: u64 = MEM_LAYOUT[LayoutEntryType::CpuController as usize].0; let region_size: u64 = MEM_LAYOUT[LayoutEntryType::CpuController as usize].1; let cpu_config = CpuConfig::new(boot_config, cpu_topology); @@ -217,22 +215,18 @@ impl StdMachine { create_new_eventfd() .with_context(|| MachineError::InitEventFdErr("hotplug cpu".to_string()))?, ); - + let cpu_controller = CpuController::new( + self.base.cpu_topo.max_cpus, + &mut self.base.sysbus, + region_base, + region_size, + cpu_config, + hotplug_cpu_req.clone(), + self.base.cpus.clone(), + )?; let realize_controller = cpu_controller - .realize( - &mut self.base.sysbus, - self.base.cpu_topo.max_cpus, - region_base, - region_size, - cpu_config, - hotplug_cpu_req.clone(), - ) + .realize(&mut self.base.sysbus) .with_context(|| "Failed to realize Cpu Controller")?; - - let mut lock_controller = realize_controller.lock().unwrap(); - lock_controller.set_boot_vcpu(self.base.cpus.clone())?; - drop(lock_controller); - self.register_hotplug_vcpu_event(hotplug_cpu_req, vm)?; self.cpu_controller = Some(realize_controller); Ok(()) @@ -281,7 +275,7 @@ impl StdMachineOps for StdMachine { nr_cpus: u8, max_cpus: u8, ) -> Result>>> { - let mut fwcfg = FwCfgIO::new(self.base.sys_mem.clone()); + let mut fwcfg = FwCfgIO::new(self.base.sys_mem.clone(), &mut self.base.sysbus)?; fwcfg.add_data_entry(FwCfgEntryType::NbCpus, nr_cpus.as_bytes().to_vec())?; fwcfg.add_data_entry(FwCfgEntryType::MaxCpus, max_cpus.as_bytes().to_vec())?; fwcfg.add_data_entry(FwCfgEntryType::Irq0Override, 1_u32.as_bytes().to_vec())?; @@ -439,38 +433,45 @@ impl MachineOps for StdMachine { } fn add_rtc_device(&mut self, mem_size: u64) -> Result<()> { - let mut rtc = RTC::new().with_context(|| "Failed to create RTC device")?; + let mut rtc = + RTC::new(&mut self.base.sysbus).with_context(|| "Failed to create RTC device")?; rtc.set_memory( mem_size, MEM_LAYOUT[LayoutEntryType::MemBelow4g as usize].0 + MEM_LAYOUT[LayoutEntryType::MemBelow4g as usize].1, ); - RTC::realize(rtc, &mut self.base.sysbus).with_context(|| "Failed to realize RTC device") + rtc.realize(&mut self.base.sysbus) + .with_context(|| "Failed to realize RTC device") } fn add_ged_device(&mut self) -> Result<()> { - let ged = Ged::default(); let region_base: u64 = MEM_LAYOUT[LayoutEntryType::GedMmio as usize].0; let region_size: u64 = MEM_LAYOUT[LayoutEntryType::GedMmio as usize].1; - let ged_event = GedEvent::new(self.power_button.clone(), self.cpu_resize_req.clone()); - ged.realize( - &mut self.base.sysbus, - ged_event, + let ged = Ged::new( false, + &mut self.base.sysbus, region_base, region_size, - ) - .with_context(|| "Failed to realize Ged")?; + ged_event, + )?; + + ged.realize(&mut self.base.sysbus) + .with_context(|| "Failed to realize Ged")?; Ok(()) } fn add_serial_device(&mut self, config: &SerialConfig) -> Result<()> { let region_base: u64 = SERIAL_ADDR; let region_size: u64 = 8; - let serial = Serial::new(config.clone()); + let serial = Serial::new( + config.clone(), + &mut self.base.sysbus, + region_base, + region_size, + )?; serial - .realize(&mut self.base.sysbus, region_base, region_size) + .realize(&mut self.base.sysbus) .with_context(|| "Failed to realize serial device.")?; Ok(()) } @@ -615,21 +616,18 @@ impl MachineOps for StdMachine { let backend = Some(fd); let pflash = PFlash::new( pfl_size, - &backend, + backend, sector_len, 4_u32, 1_u32, config.readonly, - ) - .with_context(|| MachineError::InitPflashErr)?; - PFlash::realize( - pflash, &mut self.base.sysbus, flash_end - pfl_size, - pfl_size, - backend, ) - .with_context(|| MachineError::RlzPflashErr)?; + .with_context(|| MachineError::InitPflashErr)?; + pflash + .realize(&mut self.base.sysbus) + .with_context(|| MachineError::RlzPflashErr)?; flash_end -= pfl_size; } diff --git a/virtio/src/lib.rs b/virtio/src/lib.rs index 9fc5cd59..6e89dd95 100644 --- a/virtio/src/lib.rs +++ b/virtio/src/lib.rs @@ -883,9 +883,35 @@ mod tests { use std::sync::Arc; use address_space::{AddressSpace, GuestAddress, HostMemMapping, Region}; + use devices::sysbus::{SysBus, IRQ_BASE, IRQ_MAX}; pub const MEMORY_SIZE: u64 = 1024 * 1024; + pub fn sysbus_init() -> SysBus { + let sys_mem = AddressSpace::new( + Region::init_container_region(u64::max_value(), "sys_mem"), + "sys_mem", + None, + ) + .unwrap(); + #[cfg(target_arch = "x86_64")] + let sys_io = AddressSpace::new( + Region::init_container_region(1 << 16, "sys_io"), + "sys_io", + None, + ) + .unwrap(); + let free_irqs: (i32, i32) = (IRQ_BASE, IRQ_MAX); + let mmio_region: (u64, u64) = (0x0A00_0000, 0x1000_0000); + SysBus::new( + #[cfg(target_arch = "x86_64")] + &sys_io, + &sys_mem, + free_irqs, + mmio_region, + ) + } + pub fn address_space_init() -> Arc { let root = Region::init_container_region(1 << 36, "root"); let sys_space = AddressSpace::new(root, "sys_space", None).unwrap(); diff --git a/virtio/src/transport/virtio_mmio.rs b/virtio/src/transport/virtio_mmio.rs index c538f958..ebde7c0c 100644 --- a/virtio/src/transport/virtio_mmio.rs +++ b/virtio/src/transport/virtio_mmio.rs @@ -28,8 +28,6 @@ use crate::{ use address_space::{AddressRange, AddressSpace, GuestAddress, RegionIoEventFd}; use devices::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; use devices::{Device, DeviceBase}; -#[cfg(target_arch = "x86_64")] -use machine_manager::config::{BootSource, Param}; use migration::{DeviceStateDesc, FieldDesc, MigrationHook, MigrationManager, StateTransfer}; use migration_derive::{ByteCode, Desc}; use util::byte_code::ByteCode; @@ -140,38 +138,32 @@ impl VirtioMmioDevice { mem_space: &Arc, name: String, device: Arc>, - ) -> Self { - let device_clone = device.clone(); - let queue_num = device_clone.lock().unwrap().queue_num(); - - VirtioMmioDevice { + sysbus: &mut SysBus, + region_base: u64, + region_size: u64, + ) -> Result { + if region_base >= sysbus.mmio_region.1 { + bail!("Mmio region space exhausted."); + } + let queue_num = device.lock().unwrap().queue_num(); + let mut mmio_device = VirtioMmioDevice { base: SysBusDevBase { - base: DeviceBase { - id: name, - hotpluggable: false, - }, + base: DeviceBase::new(name, false), dev_type: SysBusDevType::VirtioMmio, - interrupt_evt: Some(Arc::new(create_new_eventfd().unwrap())), + interrupt_evt: Some(Arc::new(create_new_eventfd()?)), ..Default::default() }, device, host_notify_info: HostNotifyInfo::new(queue_num), mem_space: mem_space.clone(), interrupt_cb: None, - } + }; + mmio_device.set_sys_resource(sysbus, region_base, region_size, "VirtioMmio")?; + + Ok(mmio_device) } - pub fn realize( - mut self, - sysbus: &mut SysBus, - region_base: u64, - region_size: u64, - #[cfg(target_arch = "x86_64")] bs: &Arc>, - ) -> Result>> { - if region_base >= sysbus.mmio_region.1 { - bail!("Mmio region space exhausted."); - } - self.set_sys_resource(sysbus, region_base, region_size, "VirtioMmio")?; + pub fn realize(mut self, sysbus: &mut SysBus) -> Result>> { self.assign_interrupt_cb(); self.device .lock() @@ -182,16 +174,6 @@ impl VirtioMmioDevice { let dev = Arc::new(Mutex::new(self)); sysbus.attach_device(&dev)?; - #[cfg(target_arch = "x86_64")] - bs.lock().unwrap().kernel_cmdline.push(Param { - param_type: "virtio_mmio.device".to_string(), - value: format!( - "{}@0x{:08x}:{}", - region_size, - region_base, - dev.lock().unwrap().base.res.irq - ), - }); Ok(dev) } @@ -585,7 +567,7 @@ impl MigrationHook for VirtioMmioDevice { #[cfg(test)] mod tests { use super::*; - use crate::tests::address_space_init; + use crate::tests::{address_space_init, sysbus_init}; use crate::{ check_config_space_rw, read_config_default, VirtioBase, QUEUE_TYPE_SPLIT_VRING, VIRTIO_TYPE_BLOCK, @@ -659,11 +641,16 @@ mod tests { let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); let sys_space = address_space_init(); + let mut sysbus = sysbus_init(); let virtio_mmio_device = VirtioMmioDevice::new( &sys_space, "test_virtio_mmio_device".to_string(), virtio_device.clone(), - ); + &mut sysbus, + 0x0A00_0000, + 0x0000_0200, + ) + .unwrap(); (virtio_device, virtio_mmio_device) } -- Gitee From e7a2982b0cac4fde78e2b959c10c552cef415657 Mon Sep 17 00:00:00 2001 From: Huxiaohang Date: Mon, 24 Jun 2024 12:09:10 +0800 Subject: [PATCH 143/489] fix mst compile error This error was introduced by commit 75ed42cc79e376c4757f907cef1bab2e1e7e43c4, it deleted the Copy trait of ByteCode, which will cause errors in mst, so change Copy to Clone should be better modification. --- util/src/byte_code.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/src/byte_code.rs b/util/src/byte_code.rs index 5c45ade0..29d82c68 100644 --- a/util/src/byte_code.rs +++ b/util/src/byte_code.rs @@ -15,7 +15,7 @@ use std::slice::{from_raw_parts, from_raw_parts_mut}; /// A trait bound defined for types which are safe to convert to a byte slice and /// to create from a byte slice. -pub trait ByteCode: Default + Send + Sync { +pub trait ByteCode: Clone + Default + Send + Sync { /// Return the contents of an object (impl trait `ByteCode`) as a slice of bytes. /// the inverse of this function is "from_bytes" fn as_bytes(&self) -> &[u8] { -- Gitee From 745b0a683fe4fafc44ec3c6d76184e58c29e5d79 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Fri, 21 Jun 2024 12:22:21 +0800 Subject: [PATCH 144/489] machine_manager: introduce NotifierManager to notify vm pause/resume This commit introduces NotifierManager to manage all notifiers and notify them when VM is paused or resumed. Signed-off-by: Zhao Yi Min --- devices/src/misc/scream/mod.rs | 43 +++++++++---------- machine/src/aarch64/standard.rs | 6 +-- machine/src/lib.rs | 30 ++++---------- machine_manager/src/lib.rs | 1 + machine_manager/src/machine.rs | 4 -- machine_manager/src/notifier.rs | 73 +++++++++++++++++++++++++++++++++ 6 files changed, 102 insertions(+), 55 deletions(-) create mode 100644 machine_manager/src/notifier.rs diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index a583b6c3..cf96e3ac 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -40,7 +40,7 @@ use super::ivshmem::Ivshmem; use crate::pci::{PciBus, PciDevOps}; use address_space::{GuestAddress, HostMemMapping, Region}; use machine_manager::config::{get_pci_df, parse_bool, valid_id}; -use machine_manager::machine::PauseNotify; +use machine_manager::notifier::register_vm_pause_notifier; #[cfg(all(target_env = "ohos", feature = "scream_ohaudio"))] use ohaudio::OhAudio; #[cfg(feature = "scream_pulseaudio")] @@ -433,16 +433,8 @@ pub struct Scream { size: u64, config: ScreamConfig, token_id: Option>>, - interface_resource: RwLock>>>, -} - -impl PauseNotify for Scream { - fn notify(&self, paused: bool) { - let interfaces = self.interface_resource.read().unwrap(); - for interface in interfaces.iter() { - interface.lock().unwrap().pause(paused); - } - } + interface_resource: Vec>>, + notify_id: u64, } impl Scream { @@ -465,7 +457,8 @@ impl Scream { size, config, token_id, - interface_resource: RwLock::new(Vec::new()), + interface_resource: Vec::new(), + notify_id: 0, }) } @@ -486,14 +479,11 @@ impl Scream { } } - fn start_play_thread_fn(&self) -> Result<()> { + fn start_play_thread_fn(&mut self) -> Result<()> { let hva = self.hva; let shmem_size = self.size; let interface = self.interface_init("ScreamPlay", ScreamDirection::Playback); - self.interface_resource - .write() - .unwrap() - .push(interface.clone()); + self.interface_resource.push(interface.clone()); thread::Builder::new() .name("scream audio play worker".to_string()) .spawn(move || { @@ -515,15 +505,12 @@ impl Scream { Ok(()) } - fn start_record_thread_fn(&self) -> Result<()> { + fn start_record_thread_fn(&mut self) -> Result<()> { let hva = self.hva; let shmem_size = self.size; let interface = self.interface_init("ScreamCapt", ScreamDirection::Record); let _ti = self.token_id.clone(); - self.interface_resource - .write() - .unwrap() - .push(interface.clone()); + self.interface_resource.push(interface.clone()); thread::Builder::new() .name("scream audio capt worker".to_string()) .spawn(move || { @@ -568,7 +555,17 @@ impl Scream { ivshmem.realize()?; self.start_play_thread_fn()?; - self.start_record_thread_fn() + self.start_record_thread_fn()?; + + let cloned_interfaces = self.interface_resource.clone(); + let pause_notify = Arc::new(move |paused: bool| { + for interface in cloned_interfaces.iter() { + interface.lock().unwrap().pause(paused); + } + }); + self.notify_id = register_vm_pause_notifier(pause_notify); + + Ok(()) } } diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index fe8e6a02..289083cf 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -61,7 +61,7 @@ use machine_manager::config::{ BootIndexInfo, DriveConfig, NumaNode, Param, SerialConfig, VmConfig, }; use machine_manager::event; -use machine_manager::machine::{MachineLifecycle, PauseNotify}; +use machine_manager::machine::MachineLifecycle; use machine_manager::qmp::{qmp_channel::QmpChannel, qmp_schema}; use migration::{MigrationManager, MigrationStatus}; #[cfg(feature = "gtk")] @@ -409,10 +409,6 @@ impl MachineOps for StdMachine { .add_subregion(ram, MEM_LAYOUT[LayoutEntryType::Mem as usize].0) } - fn register_vm_pause_notifier(&mut self, notifier: Arc) { - self.base.pause_notifiers.push(notifier); - } - fn init_interrupt_controller(&mut self, vcpu_count: u64) -> Result<()> { let v3 = ICGICv3Config { msi: true, diff --git a/machine/src/lib.rs b/machine/src/lib.rs index c02f54ab..f331c60e 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -85,9 +85,8 @@ use machine_manager::config::{ VirtioSerialPortCfg, VmConfig, FAST_UNPLUG_ON, MAX_VIRTIO_QUEUE, }; use machine_manager::event_loop::EventLoop; -use machine_manager::machine::{ - HypervisorType, MachineInterface, MachineLifecycle, PauseNotify, VmState, -}; +use machine_manager::machine::{HypervisorType, MachineInterface, MachineLifecycle, VmState}; +use machine_manager::notifier::pause_notify; use machine_manager::{check_arg_exist, check_arg_nonexist}; use migration::{MigrateOps, MigrationManager}; #[cfg(feature = "windows_emu_pid")] @@ -153,8 +152,6 @@ pub struct MachineBase { hypervisor: Arc>, /// migrate hypervisor. migration_hypervisor: Arc>, - /// vm pause notifiers. - pause_notifiers: Vec>, } impl MachineBase { @@ -231,7 +228,6 @@ impl MachineBase { machine_ram, hypervisor, migration_hypervisor, - pause_notifiers: Vec::new(), }) } @@ -1654,9 +1650,6 @@ pub trait MachineOps: MachineLifecycle { Ok(()) } - /// Register vm pause listener. - fn register_vm_pause_notifier(&mut self, _listener: Arc) {} - /// Add scream sound based on ivshmem. /// /// # Arguments @@ -1691,9 +1684,7 @@ pub trait MachineOps: MachineLifecycle { let mut scream = Scream::new(mem_cfg.size, config, token_id)?; scream .realize(parent_bus) - .with_context(|| "Failed to realize scream device")?; - self.register_vm_pause_notifier(Arc::new(scream)); - Ok(()) + .with_context(|| "Failed to realize scream device") } /// Get the corresponding device from the PCI bus based on the device id and device type name. @@ -1992,13 +1983,6 @@ pub trait MachineOps: MachineLifecycle { self.machine_base().drive_files.clone() } - //// Trigger vm pause notifiers. - fn notify_vm_pause_notifiers(&self, paused: bool) { - for notifier in self.machine_base().pause_notifiers.iter() { - notifier.notify(paused); - } - } - /// Fetch a cloned file from drive backend files. fn fetch_drive_file(&self, path: &str) -> Result { let files = self.get_drive_files(); @@ -2148,7 +2132,7 @@ pub trait MachineOps: MachineLifecycle { *vm_state = VmState::Paused; // Notify VM paused. - self.notify_vm_pause_notifiers(true); + pause_notify(true); Ok(()) } @@ -2164,6 +2148,9 @@ pub trait MachineOps: MachineLifecycle { self.active_drive_files()?; + // Notify VM resumed. + pause_notify(false); + for (cpu_index, cpu) in cpus.iter().enumerate() { if let Err(e) = cpu.resume() { self.deactive_drive_files()?; @@ -2173,9 +2160,6 @@ pub trait MachineOps: MachineLifecycle { *vm_state = VmState::Running; - // Notify VM resumed. - self.notify_vm_pause_notifiers(false); - Ok(()) } diff --git a/machine_manager/src/lib.rs b/machine_manager/src/lib.rs index 78c6a77e..b1475fce 100644 --- a/machine_manager/src/lib.rs +++ b/machine_manager/src/lib.rs @@ -26,6 +26,7 @@ pub mod config; pub mod error; pub mod event_loop; pub mod machine; +pub mod notifier; pub mod qmp; pub mod signal_handler; pub mod socket; diff --git a/machine_manager/src/machine.rs b/machine_manager/src/machine.rs index cd37eefd..a040d6ef 100644 --- a/machine_manager/src/machine.rs +++ b/machine_manager/src/machine.rs @@ -67,10 +67,6 @@ impl FromStr for HypervisorType { } } -pub trait PauseNotify: Send + Sync { - fn notify(&self, paused: bool); -} - /// Trait to handle virtual machine lifecycle. /// /// # Notes diff --git a/machine_manager/src/notifier.rs b/machine_manager/src/notifier.rs new file mode 100644 index 00000000..36285f36 --- /dev/null +++ b/machine_manager/src/notifier.rs @@ -0,0 +1,73 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::collections::HashMap; +use std::sync::{Arc, RwLock}; + +use log::error; +use once_cell::sync::Lazy; + +static NOTIFIER_MANAGER: Lazy> = + Lazy::new(|| RwLock::new(NotifierManager::new())); + +pub type PauseNOtifyCallback = dyn Fn(bool) + Send + Sync; + +struct NotifierManager { + pause_notifiers: HashMap>, + next_id: u64, +} + +impl NotifierManager { + fn new() -> Self { + Self { + pause_notifiers: HashMap::new(), + next_id: 1, + } + } + + fn register_pause_notifier(&mut self, notifier: Arc) -> u64 { + let id = self.next_id; + self.pause_notifiers.insert(id, notifier); + self.next_id += 1; + id + } + + fn unregister_pause_notifier(&mut self, id: u64) { + if self.pause_notifiers.remove(&id).is_none() { + error!("There is no pause notifier with id {}", id); + } + } + + fn pause_notify(&self, paused: bool) { + for (_, notify) in self.pause_notifiers.iter() { + notify(paused); + } + } +} + +pub fn register_vm_pause_notifier(notifier: Arc) -> u64 { + NOTIFIER_MANAGER + .write() + .unwrap() + .register_pause_notifier(notifier) +} + +pub fn unregister_vm_pause_notifier(id: u64) { + NOTIFIER_MANAGER + .write() + .unwrap() + .unregister_pause_notifier(id) +} + +pub fn pause_notify(paused: bool) { + NOTIFIER_MANAGER.read().unwrap().pause_notify(paused); +} -- Gitee From 98ad7beaca90d64356054569458ba9fa1dfc485f Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Sat, 22 Jun 2024 11:28:41 +0800 Subject: [PATCH 145/489] ohcam: stop/start camera stream when VM is paused/resumed This patch adds an new interface to CameraBackend trait that is used to monitor VM paused/resumed. This can solve the issue that camera keeps being used after VM paused. Signed-off-by: Zhao Yi Min --- devices/src/camera_backend/mod.rs | 3 +++ devices/src/camera_backend/ohcam.rs | 33 ++++++++++++++++++++++++++++- devices/src/usb/camera.rs | 12 +++++++++++ 3 files changed, 47 insertions(+), 1 deletion(-) diff --git a/devices/src/camera_backend/mod.rs b/devices/src/camera_backend/mod.rs index 00723e5e..6e67d762 100644 --- a/devices/src/camera_backend/mod.rs +++ b/devices/src/camera_backend/mod.rs @@ -184,6 +184,9 @@ pub trait CameraBackend: Send + Sync { /// Register broken callback which is called when backend is broken. fn register_broken_cb(&mut self, cb: CameraBrokenCallback); + + /// Pause/resume stream. + fn pause(&mut self, _paused: bool) {} } #[allow(unused_variables)] diff --git a/devices/src/camera_backend/ohcam.rs b/devices/src/camera_backend/ohcam.rs index 55b6a80a..096f24b1 100755 --- a/devices/src/camera_backend/ohcam.rs +++ b/devices/src/camera_backend/ohcam.rs @@ -120,6 +120,8 @@ pub struct OhCameraBackend { ctx: OhCamera, fmt_list: Vec, selected_profile: u8, + stream_on: bool, + paused: bool, #[cfg(any( feature = "trace_to_logger", feature = "trace_to_ftrace", @@ -160,6 +162,8 @@ impl OhCameraBackend { ctx, fmt_list: vec![], selected_profile: 0, + stream_on: false, + paused: false, #[cfg(any( feature = "trace_to_logger", feature = "trace_to_ftrace", @@ -202,12 +206,15 @@ impl CameraBackend for OhCameraBackend { } fn video_stream_on(&mut self) -> Result<()> { - self.ctx.start_stream(on_buffer_available, on_broken) + self.ctx.start_stream(on_buffer_available, on_broken)?; + self.stream_on = true; + Ok(()) } fn video_stream_off(&mut self) -> Result<()> { self.ctx.stop_stream(); OHCAM_CALLBACK.write().unwrap().clear_buffer(); + self.stream_on = false; #[cfg(any( feature = "trace_to_logger", feature = "trace_to_ftrace", @@ -343,6 +350,30 @@ impl CameraBackend for OhCameraBackend { fn register_broken_cb(&mut self, cb: CameraBrokenCallback) { OHCAM_CALLBACK.write().unwrap().set_broken_cb(cb); } + + fn pause(&mut self, paused: bool) { + if self.paused == paused { + return; + } + + if paused { + // If stream is off, we don't need to set self.paused. + // Because it's not required to re-open stream while + // vm is resuming. + if !self.stream_on { + return; + } + self.paused = true; + self.video_stream_off().unwrap_or_else(|e| { + error!("ohcam pause: failed to pause stream {:?}", e); + }); + } else { + self.paused = false; + self.video_stream_on().unwrap_or_else(|e| { + error!("ohcam resume: failed to resume stream {:?}", e); + }) + } + } } // SAFETY: use RW lock to ensure the security of resources. diff --git a/devices/src/usb/camera.rs b/devices/src/usb/camera.rs index fccd0a17..a8807318 100644 --- a/devices/src/usb/camera.rs +++ b/devices/src/usb/camera.rs @@ -38,6 +38,7 @@ use crate::usb::{ use machine_manager::config::camera::CameraDevConfig; use machine_manager::config::valid_id; use machine_manager::event_loop::{register_event_helper, unregister_event_helper}; +use machine_manager::notifier::{register_vm_pause_notifier, unregister_vm_pause_notifier}; use util::aio::{iov_discard_front_direct, Iovec}; use util::byte_code::ByteCode; use util::gen_base_func; @@ -115,6 +116,7 @@ pub struct UsbCamera { broken: Arc, // if the device broken or not iothread: Option, delete_evts: Vec, + notifier_id: u64, } #[derive(Debug)] @@ -515,6 +517,7 @@ impl UsbCamera { broken: Arc::new(AtomicBool::new(false)), iothread: config.iothread, delete_evts: Vec::new(), + notifier_id: 0, }) } @@ -767,6 +770,13 @@ impl UsbDevice for UsbCamera { self.register_cb(); let camera = Arc::new(Mutex::new(self)); + let cloned_camera = camera.clone(); + let pause_notify = Arc::new(move |paused: bool| { + let locked_cam = cloned_camera.lock().unwrap(); + locked_cam.camera_backend.lock().unwrap().pause(paused); + }); + camera.lock().unwrap().notifier_id = register_vm_pause_notifier(pause_notify); + Ok(camera) } @@ -774,6 +784,8 @@ impl UsbDevice for UsbCamera { info!("Camera {} unrealize", self.device_id()); self.unregister_camera_fd()?; self.camera_backend.lock().unwrap().reset(); + unregister_vm_pause_notifier(self.notifier_id); + self.notifier_id = 0; Ok(()) } -- Gitee From 20cd0a5ccfebda7bd9520ae0d86b99261e6ed3b2 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Mon, 17 Jun 2024 08:33:02 +0800 Subject: [PATCH 146/489] virtio: move `get_libc_iovecs` to virtio lib Move `get_libc_iovecs` to virtio lib for it will be used by virto-net and the next submitted virtio-vsock. No functional change. Signed-off-by: liuxiangdong --- virtio/src/device/net.rs | 58 +++++++--------------------------------- virtio/src/lib.rs | 29 ++++++++++++++++++++ 2 files changed, 38 insertions(+), 49 deletions(-) diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index 4101ec9c..c4053f06 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -27,10 +27,10 @@ use once_cell::sync::Lazy; use vmm_sys_util::{epoll::EventSet, eventfd::EventFd}; use crate::{ - check_config_space_rw, iov_discard_front, iov_to_buf, mem_to_buf, read_config_default, - report_virtio_error, virtio_has_feature, ElemIovec, Element, Queue, VirtioBase, VirtioDevice, - VirtioError, VirtioInterrupt, VirtioInterruptType, VirtioNetHdr, VIRTIO_F_RING_EVENT_IDX, - VIRTIO_F_RING_INDIRECT_DESC, VIRTIO_F_VERSION_1, VIRTIO_NET_CTRL_MAC, + check_config_space_rw, get_libc_iovecs, iov_discard_front, iov_to_buf, mem_to_buf, + read_config_default, report_virtio_error, virtio_has_feature, ElemIovec, Element, Queue, + VirtioBase, VirtioDevice, VirtioError, VirtioInterrupt, VirtioInterruptType, VirtioNetHdr, + VIRTIO_F_RING_EVENT_IDX, VIRTIO_F_RING_INDIRECT_DESC, VIRTIO_F_VERSION_1, VIRTIO_NET_CTRL_MAC, VIRTIO_NET_CTRL_MAC_ADDR_SET, VIRTIO_NET_CTRL_MAC_TABLE_SET, VIRTIO_NET_CTRL_MQ, VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MAX, VIRTIO_NET_CTRL_MQ_VQ_PAIRS_MIN, VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET, VIRTIO_NET_CTRL_RX, VIRTIO_NET_CTRL_RX_ALLMULTI, @@ -43,12 +43,9 @@ use crate::{ VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_TSO6, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_MAC, VIRTIO_NET_F_MQ, VIRTIO_NET_OK, VIRTIO_TYPE_NET, }; -use address_space::{AddressSpace, RegionCache}; -use machine_manager::event_loop::{register_event_helper, unregister_event_helper}; -use machine_manager::{ - config::{ConfigCheck, NetDevcfg, NetworkInterfaceConfig}, - event_loop::EventLoop, -}; +use address_space::AddressSpace; +use machine_manager::config::{ConfigCheck, NetDevcfg, NetworkInterfaceConfig}; +use machine_manager::event_loop::{register_event_helper, unregister_event_helper, EventLoop}; use migration::{ migration::Migratable, DeviceStateDesc, FieldDesc, MigrationHook, MigrationManager, StateTransfer, @@ -753,35 +750,6 @@ impl NetIoHandler { size } - fn get_libc_iovecs( - mem_space: &Arc, - cache: &Option, - elem_iovecs: &[ElemIovec], - ) -> Vec { - let mut iovecs = Vec::new(); - for elem_iov in elem_iovecs.iter() { - // elem_iov.addr has been checked in pop_avail(). - let mut len = elem_iov.len; - let mut start = elem_iov.addr; - loop { - let io_vec = mem_space - .get_host_address_from_cache(start, cache) - .map(|(hva, fr_len)| libc::iovec { - iov_base: hva as *mut libc::c_void, - iov_len: std::cmp::min(elem_iov.len, fr_len as u32) as libc::size_t, - }) - .unwrap(); - start = start.unchecked_add(io_vec.iov_len as u64); - len -= io_vec.iov_len as u32; - iovecs.push(io_vec); - if len == 0 { - break; - } - } - } - iovecs - } - fn handle_rx(&mut self) -> Result<()> { trace::virtio_receive_request("Net".to_string(), "to rx".to_string()); if self.tap.is_none() { @@ -805,11 +773,7 @@ impl NetIoHandler { } else if elem.in_iovec.is_empty() { bail!("The length of in iovec is 0"); } - let iovecs = NetIoHandler::get_libc_iovecs( - &self.mem_space, - queue.vring.get_cache(), - &elem.in_iovec, - ); + let iovecs = get_libc_iovecs(&self.mem_space, queue.vring.get_cache(), &elem.in_iovec); if MigrationManager::is_active() { // FIXME: mark dirty page needs to be managed by `AddressSpace` crate. @@ -921,11 +885,7 @@ impl NetIoHandler { bail!("The length of out iovec is 0"); } - let iovecs = NetIoHandler::get_libc_iovecs( - &self.mem_space, - queue.vring.get_cache(), - &elem.out_iovec, - ); + let iovecs = get_libc_iovecs(&self.mem_space, queue.vring.get_cache(), &elem.out_iovec); let tap_fd = if let Some(tap) = self.tap.as_mut() { tap.as_raw_fd() as libc::c_int } else { diff --git a/virtio/src/lib.rs b/virtio/src/lib.rs index 6e89dd95..61ee3ead 100644 --- a/virtio/src/lib.rs +++ b/virtio/src/lib.rs @@ -870,6 +870,35 @@ fn gpa_hva_iovec_map_by_cache( Ok((iov_size, hva_iovec)) } +fn get_libc_iovecs( + mem_space: &Arc, + cache: &Option, + elem_iovecs: &[ElemIovec], +) -> Vec { + let mut iovecs = Vec::new(); + for elem_iov in elem_iovecs.iter() { + // elem_iov.addr has been checked in pop_avail(). + let mut len = elem_iov.len; + let mut start = elem_iov.addr; + loop { + let io_vec = mem_space + .get_host_address_from_cache(start, cache) + .map(|(hva, fr_len)| libc::iovec { + iov_base: hva as *mut libc::c_void, + iov_len: std::cmp::min(elem_iov.len, fr_len as u32) as libc::size_t, + }) + .unwrap(); + start = start.unchecked_add(io_vec.iov_len as u64); + len -= io_vec.iov_len as u32; + iovecs.push(io_vec); + if len == 0 { + break; + } + } + } + iovecs +} + pub fn virtio_register_sysbusdevops_type() -> Result<()> { register_sysbusdevops_type::() } -- Gitee From c7c75efaee8d2d14d131c962967ff071a08125f2 Mon Sep 17 00:00:00 2001 From: Gan Qixin Date: Wed, 27 Mar 2024 00:55:23 +0800 Subject: [PATCH 147/489] Trace: Load libhitrace_meter.so dynamically Signed-off-by: Gan Qixin --- Cargo.lock | 1 + trace/Cargo.toml | 1 + trace/src/hitrace.rs | 85 ++++++++++++++++++++++++++++++++++++++------ 3 files changed, 77 insertions(+), 10 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bc1a59a9..90552e41 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1736,6 +1736,7 @@ version = "2.4.0" dependencies = [ "anyhow", "lazy_static", + "libloading", "log", "regex", "trace_generator", diff --git a/trace/Cargo.toml b/trace/Cargo.toml index ad6cf1bc..4fd31409 100644 --- a/trace/Cargo.toml +++ b/trace/Cargo.toml @@ -13,6 +13,7 @@ regex = "1" anyhow = "1.0" trace_generator = { path = "trace_generator" } vmm-sys-util = "0.12.1" +libloading = "0.7.4" [features] trace_to_logger = [] diff --git a/trace/src/hitrace.rs b/trace/src/hitrace.rs index 1cff1cd7..625ea620 100644 --- a/trace/src/hitrace.rs +++ b/trace/src/hitrace.rs @@ -10,27 +10,84 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. +use std::ffi::OsStr; + +use anyhow::{Context, Result}; +use lazy_static::lazy_static; +use libloading::os::unix::Symbol; +use libloading::Library; +use log::error; + const HITRACE_TAG_VIRSE: u64 = 1u64 << 11; -#[link(name = "hitrace_meter")] -extern "C" { - fn StartTraceWrapper(label: u64, value: *const u8); - fn FinishTrace(label: u64); - fn StartAsyncTraceWrapper(label: u64, value: *const u8, taskId: i32); - fn FinishAsyncTraceWrapper(label: u64, value: *const u8, taskId: i32); +lazy_static! { + static ref HITRACE_FUNC_TABLE: HitraceFuncTable = + // SAFETY: The dynamic library should be always existing. + unsafe { + HitraceFuncTable::new(OsStr::new("libhitrace_meter.so")) + .map_err(|e| { + error!("failed to init HitraceFuncTable with error: {:?}", e); + e + }) + .unwrap() + }; +} + +macro_rules! get_libfn { + ( $lib: ident, $tname: ident, $fname: ident ) => { + $lib.get::<$tname>(stringify!($fname).as_bytes()) + .with_context(|| format!("failed to get function {}", stringify!($fname)))? + .into_raw() + }; +} + +type StartTraceWrapperFn = unsafe extern "C" fn(u64, *const u8); +type FinishTraceFn = unsafe extern "C" fn(u64); +type StartAsyncTraceWrapperFn = unsafe extern "C" fn(u64, *const u8, i32); +type FinishAsyncTraceWrapperFn = unsafe extern "C" fn(u64, *const u8, i32); + +struct HitraceFuncTable { + pub start_trace: Symbol, + pub finish_trace: Symbol, + pub start_trace_async: Symbol, + pub finish_trace_async: Symbol, +} + +impl HitraceFuncTable { + unsafe fn new(library_name: &OsStr) -> Result { + let library = + Library::new(library_name).with_context(|| "failed to load hitrace_meter library")?; + + Ok(Self { + start_trace: get_libfn!(library, StartTraceWrapperFn, StartTraceWrapper), + finish_trace: get_libfn!(library, FinishTraceFn, FinishTrace), + start_trace_async: get_libfn!( + library, + StartAsyncTraceWrapperFn, + StartAsyncTraceWrapper + ), + finish_trace_async: get_libfn!( + library, + FinishAsyncTraceWrapperFn, + FinishAsyncTraceWrapper + ), + }) + } } pub fn start_trace(value: &str) { if let Ok(value_ptr) = std::ffi::CString::new(value) { // SAFETY: All parameters have been checked. - unsafe { StartTraceWrapper(HITRACE_TAG_VIRSE, value_ptr.as_ptr() as *const u8) } + unsafe { + (HITRACE_FUNC_TABLE.start_trace)(HITRACE_TAG_VIRSE, value_ptr.as_ptr() as *const u8) + } } } pub fn finish_trace() { // SAFETY: All parameters have been checked. unsafe { - FinishTrace(HITRACE_TAG_VIRSE); + (HITRACE_FUNC_TABLE.finish_trace)(HITRACE_TAG_VIRSE); } } @@ -38,7 +95,11 @@ pub fn start_trace_async(value: &str, task_id: i32) { if let Ok(value_ptr) = std::ffi::CString::new(value) { // SAFETY: All parameters have been checked. unsafe { - StartAsyncTraceWrapper(HITRACE_TAG_VIRSE, value_ptr.as_ptr() as *const u8, task_id) + (HITRACE_FUNC_TABLE.start_trace_async)( + HITRACE_TAG_VIRSE, + value_ptr.as_ptr() as *const u8, + task_id, + ) } } } @@ -47,7 +108,11 @@ pub fn finish_trace_async(value: &str, task_id: i32) { if let Ok(value_ptr) = std::ffi::CString::new(value) { // SAFETY: All parameters have been checked. unsafe { - FinishAsyncTraceWrapper(HITRACE_TAG_VIRSE, value_ptr.as_ptr() as *const u8, task_id) + (HITRACE_FUNC_TABLE.finish_trace_async)( + HITRACE_TAG_VIRSE, + value_ptr.as_ptr() as *const u8, + task_id, + ) } } } -- Gitee From 728be7f6fe86a31bb734196ae08c85113bb257f6 Mon Sep 17 00:00:00 2001 From: Gan Qixin Date: Wed, 27 Mar 2024 03:27:09 +0800 Subject: [PATCH 148/489] Trace: Add new option to enable an certain type of trace Signed-off-by: Gan Qixin --- docs/config_guidebook.md | 7 +++-- machine_manager/src/cmdline.rs | 4 +-- machine_manager/src/config/mod.rs | 46 ++++++++++++++++++++++++++++--- trace/src/lib.rs | 33 +++++++++++++++++++++- trace/trace_generator/src/lib.rs | 10 +++---- 5 files changed, 85 insertions(+), 15 deletions(-) diff --git a/docs/config_guidebook.md b/docs/config_guidebook.md index 16195406..97665ec7 100644 --- a/docs/config_guidebook.md +++ b/docs/config_guidebook.md @@ -1181,14 +1181,15 @@ Please see the [4. Build with features](docs/build_guide.md) if you want to enab ## 3. Trace -Users can specify the configuration file which lists events to trace. +Users can specify a configuration file which lists the traces that needs to be enabled, or specify the trace type that needs to be enabled. Setting both file and type is also allowed, so that traces with the specified type and traces listed in the file will all be enabled. One property can be set: -* events: file lists events to trace. +* file: specify the file containing the traces that needs to be enabled. +* type: specify the traces type that needs to be enabled. ```shell --trace file= +-trace file=|type= ``` ## 4. Seccomp diff --git a/machine_manager/src/cmdline.rs b/machine_manager/src/cmdline.rs index 619a7c2b..fc7304b9 100644 --- a/machine_manager/src/cmdline.rs +++ b/machine_manager/src/cmdline.rs @@ -447,8 +447,8 @@ pub fn create_args_parser<'a>() -> ArgParser<'a> { Arg::with_name("trace") .multiple(false) .long("trace") - .value_name("file=") - .help("specify the file lists trace state to enable") + .value_name("file=|type=") + .help("specify the trace state to enable") .takes_value(true), ) .arg( diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index ca1281a6..3fbc5818 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -70,7 +70,7 @@ use clap::Parser; use log::error; use serde::{Deserialize, Serialize}; -use trace::set_state_by_pattern; +use trace::{enable_state_by_type, set_state_by_pattern, TraceType}; #[cfg(target_arch = "aarch64")] use util::device_tree::{self, FdtBuilder}; use util::{ @@ -447,7 +447,7 @@ pub fn parse_bool(s: &str) -> Result { } } -fn enable_trace_state(path: &str) -> Result<()> { +fn enable_trace_state_from_file(path: &str) -> Result<()> { let mut file = File::open(path).with_context(|| format!("Failed to open {}", path))?; let mut buf = String::new(); file.read_to_string(&mut buf) @@ -466,16 +466,41 @@ fn enable_trace_state(path: &str) -> Result<()> { Ok(()) } +fn enable_trace_state_from_type(type_str: &str) -> Result<()> { + match type_str { + "events" => enable_state_by_type(TraceType::Event)?, + "scopes" => enable_state_by_type(TraceType::Scope)?, + "all" => { + enable_state_by_type(TraceType::Event)?; + enable_state_by_type(TraceType::Scope)?; + } + _ => bail!("Unknown trace type {}", type_str), + }; + + Ok(()) +} + #[derive(Parser)] #[command(no_binary_name(true))] struct TraceConfig { #[arg(long)] - file: String, + file: Option, + #[arg(long, alias = "type")] + type_str: Option, } pub fn add_trace(opt: &str) -> Result<()> { let trace_cfg = TraceConfig::try_parse_from(str_slip_to_clap(opt, false, false))?; - enable_trace_state(&trace_cfg.file)?; + if trace_cfg.type_str.is_none() && trace_cfg.file.is_none() { + bail!("No type or file after -trace"); + } + + if let Some(type_str) = trace_cfg.type_str { + enable_trace_state_from_type(&type_str)?; + } + if let Some(file) = trace_cfg.file { + enable_trace_state_from_file(&file)?; + } Ok(()) } @@ -747,9 +772,22 @@ mod tests { #[test] fn test_add_trace() { + assert!(std::fs::File::create("/tmp/trace_file").is_ok()); + + assert!(add_trace("file=/tmp/trace_file,type=all").is_ok()); assert!(add_trace("fil=test_trace").is_err()); assert!(add_trace("file").is_err()); assert!(add_trace("file=test_trace").is_err()); + + assert!(add_trace("type=events").is_ok()); + assert!(add_trace("type=scopes").is_ok()); + assert!(add_trace("type=all").is_ok()); + assert!(add_trace("type=xxxxx").is_err()); + + assert!(add_trace("").is_err()); + assert!(add_trace("file=/tmp/trace_file,type=all").is_ok()); + + assert!(std::fs::remove_file("/tmp/trace_file").is_ok()); } #[test] diff --git a/trace/src/lib.rs b/trace/src/lib.rs index 32646d2f..ba8aa2ab 100644 --- a/trace/src/lib.rs +++ b/trace/src/lib.rs @@ -30,6 +30,7 @@ use std::{ use anyhow::{Ok, Result}; use lazy_static::lazy_static; +use log::warn; use regex::Regex; use vmm_sys_util::eventfd::EventFd; @@ -37,16 +38,33 @@ use trace_generator::{ add_trace_state_to, gen_trace_event_func, gen_trace_scope_func, gen_trace_state, }; +#[derive(PartialEq, Eq)] +pub enum TraceType { + Event, + Scope, + Unknown, +} + struct TraceState { name: String, + trace_type: TraceType, get_state: fn() -> bool, set_state: fn(bool), } impl TraceState { - fn new(name: String, get_state: fn() -> bool, set_state: fn(bool)) -> Self { + fn new(name: String, type_str: &str, get_state: fn() -> bool, set_state: fn(bool)) -> Self { + let trace_type = match type_str { + "event" => TraceType::Event, + "scope" => TraceType::Scope, + _ => { + warn!("The type of {} is Unknown: {}", name, type_str); + TraceType::Unknown + } + }; TraceState { name, + trace_type, get_state, set_state, } @@ -73,6 +91,15 @@ impl TraceStateSet { Ok(()) } + fn enable_state_by_type(&self, trace_type: TraceType) -> Result<()> { + for state in &self.state_list { + if state.trace_type == trace_type { + (state.set_state)(true); + } + } + Ok(()) + } + fn get_state_by_pattern(&self, pattern: String) -> Result> { let re = Regex::new(&pattern)?; let mut ret: Vec<(String, bool)> = Vec::new(); @@ -126,3 +153,7 @@ pub fn get_state_by_pattern(pattern: String) -> Result> { pub fn set_state_by_pattern(pattern: String, state: bool) -> Result<()> { TRACE_STATE_SET.set_state_by_pattern(pattern, state) } + +pub fn enable_state_by_type(trace_type: TraceType) -> Result<()> { + TRACE_STATE_SET.enable_state_by_type(trace_type) +} diff --git a/trace/trace_generator/src/lib.rs b/trace/trace_generator/src/lib.rs index 4d1a80a4..ce6ce126 100644 --- a/trace/trace_generator/src/lib.rs +++ b/trace/trace_generator/src/lib.rs @@ -56,24 +56,24 @@ fn get_trace_desc() -> TraceConf { #[proc_macro] pub fn add_trace_state_to(input: TokenStream) -> TokenStream { let trace_conf = get_trace_desc(); - let mut state_name = Vec::new(); + let mut state = Vec::new(); for desc in trace_conf.events.unwrap_or_default() { if desc.enabled { - state_name.push(desc.name.trim().to_string()); + state.push((desc.name.trim().to_string(), "event")); } } for desc in trace_conf.scopes.unwrap_or_default() { if desc.enabled { - state_name.push(desc.name.trim().to_string()); + state.push((desc.name.trim().to_string(), "scope")); } } let set = parse_macro_input!(input as Ident); - let init_code = state_name.iter().map(|name| { + let init_code = state.iter().map(|(name, type_str)| { let get_func = parse_str::(format!("get_{}_state", name).as_str()).unwrap(); let set_func = parse_str::(format!("set_{}_state", name).as_str()).unwrap(); quote!( - #set.add_trace_state(TraceState::new(#name.to_string(), #get_func, #set_func)); + #set.add_trace_state(TraceState::new(#name.to_string(), #type_str, #get_func, #set_func)); ) }); TokenStream::from(quote! { #( #init_code )* }) -- Gitee From e351fba98784b48fb254cd7bc050b6c13019e006 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Mon, 17 Jun 2024 10:54:18 +0800 Subject: [PATCH 149/489] power: fix clippy warnings Fix clippy warnings: error: redundant clone --> devices/src/acpi/power.rs:200:37 | 200 | power_status_update(&dev.clone()); | ^^^^^^^^ help: remove this | = note: `-D clippy::redundant-clone` implied by `-D warnings` Signed-off-by: liuxiangdong --- devices/src/acpi/power.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devices/src/acpi/power.rs b/devices/src/acpi/power.rs index 1da56062..ae193987 100644 --- a/devices/src/acpi/power.rs +++ b/devices/src/acpi/power.rs @@ -197,7 +197,7 @@ impl PowerDev { } } if pdev_available { - power_status_update(&dev.clone()); + power_status_update(&dev); } else { let mut pdev = dev.lock().unwrap(); pdev.power_load_static_status(); -- Gitee From 6dc8d9100abf50e6ff152d06218ef808d6b7168e Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sun, 16 Jun 2024 18:31:39 +0800 Subject: [PATCH 150/489] sysbus: add sysbus error type `AddRegionErr` Add sysbus error type `AddRegionErr` to optimize duplicate code in `attach_device`. Signed-off-by: liuxiangdong --- devices/src/sysbus/error.rs | 2 ++ devices/src/sysbus/mod.rs | 38 ++++--------------------------------- 2 files changed, 6 insertions(+), 34 deletions(-) diff --git a/devices/src/sysbus/error.rs b/devices/src/sysbus/error.rs index da1c8909..1d233b6b 100644 --- a/devices/src/sysbus/error.rs +++ b/devices/src/sysbus/error.rs @@ -19,4 +19,6 @@ pub enum SysBusError { #[from] source: address_space::error::AddressSpaceError, }, + #[error("Failed to register region in {0} space: offset={1:#x},size={2:#x}")] + AddRegionErr(&'static str, u64, u64), } diff --git a/devices/src/sysbus/mod.rs b/devices/src/sysbus/mod.rs index f9bbeb5a..4ca00be1 100644 --- a/devices/src/sysbus/mod.rs +++ b/devices/src/sysbus/mod.rs @@ -133,40 +133,13 @@ impl SysBus { region.set_ioeventfds(&locked_dev.ioeventfds()); match locked_dev.sysbusdev_base().dev_type { - SysBusDevType::Serial if cfg!(target_arch = "x86_64") => { - #[cfg(target_arch = "x86_64")] + #[cfg(target_arch = "x86_64")] + SysBusDevType::Serial | SysBusDevType::FwCfg | SysBusDevType::Rtc => { self.sys_io .root() .add_subregion(region, region_base) .with_context(|| { - format!( - "Failed to register region in I/O space: offset={},size={}", - region_base, region_size - ) - })?; - } - SysBusDevType::FwCfg if cfg!(target_arch = "x86_64") => { - #[cfg(target_arch = "x86_64")] - self.sys_io - .root() - .add_subregion(region, region_base) - .with_context(|| { - format!( - "Failed to register region in I/O space: offset 0x{:x}, size {}", - region_base, region_size - ) - })?; - } - SysBusDevType::Rtc if cfg!(target_arch = "x86_64") => { - #[cfg(target_arch = "x86_64")] - self.sys_io - .root() - .add_subregion(region, region_base) - .with_context(|| { - format!( - "Failed to register region in I/O space: offset 0x{:x}, size {}", - region_base, region_size - ) + SysBusError::AddRegionErr("I/O", region_base, region_size) })?; } _ => self @@ -174,10 +147,7 @@ impl SysBus { .root() .add_subregion(region, region_base) .with_context(|| { - format!( - "Failed to register region in memory space: offset={},size={}", - region_base, region_size - ) + SysBusError::AddRegionErr("memory", region_base, region_size) })?, } } -- Gitee From 48facc6525b3940a86c1e9a7ef83831b770742b2 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sun, 16 Jun 2024 11:27:38 +0800 Subject: [PATCH 151/489] sysbus: change `sysbus` in machine to Arc We will use `Week>` to represent the parent bus of a device. So, sysbus needs to be modified to be of the same type as other buses. Change `sysbus` in machine to Arc. Signed-off-by: liuxiangdong --- devices/src/acpi/cpu_controller.rs | 6 ++--- devices/src/acpi/ged.rs | 6 ++--- devices/src/acpi/power.rs | 6 ++--- devices/src/legacy/fwcfg.rs | 16 +++++++----- devices/src/legacy/pflash.rs | 25 ++++++++---------- devices/src/legacy/pl011.rs | 10 +++++--- devices/src/legacy/pl031.rs | 14 +++++----- devices/src/legacy/ramfb.rs | 4 +-- devices/src/legacy/rtc.rs | 18 ++++++------- devices/src/legacy/serial.rs | 14 +++++----- devices/src/sysbus/mod.rs | 14 +++++----- machine/src/aarch64/fdt.rs | 3 ++- machine/src/aarch64/micro.rs | 19 +++++--------- machine/src/aarch64/standard.rs | 40 +++++++++++++---------------- machine/src/lib.rs | 13 +++++----- machine/src/micro_common/mod.rs | 8 +++--- machine/src/x86_64/micro.rs | 11 +++----- machine/src/x86_64/standard.rs | 34 ++++++++++-------------- virtio/src/lib.rs | 8 +++--- virtio/src/transport/virtio_mmio.rs | 12 ++++----- 20 files changed, 132 insertions(+), 149 deletions(-) diff --git a/devices/src/acpi/cpu_controller.rs b/devices/src/acpi/cpu_controller.rs index 9e2383d5..70d0866a 100644 --- a/devices/src/acpi/cpu_controller.rs +++ b/devices/src/acpi/cpu_controller.rs @@ -90,7 +90,7 @@ pub struct CpuController { impl CpuController { pub fn new( max_cpus: u8, - sysbus: &mut SysBus, + sysbus: &Arc>, region_base: u64, region_size: u64, cpu_config: CpuConfig, @@ -111,10 +111,10 @@ impl CpuController { Ok(cpu_controller) } - pub fn realize(self, sysbus: &mut SysBus) -> Result>> { + pub fn realize(self, sysbus: &Arc>) -> Result>> { let dev = Arc::new(Mutex::new(self)); let ret_dev = dev.clone(); - sysbus.attach_device(&dev)?; + sysbus.lock().unwrap().attach_device(&dev)?; Ok(ret_dev) } diff --git a/devices/src/acpi/ged.rs b/devices/src/acpi/ged.rs index 7c3c92a4..cfe072e2 100644 --- a/devices/src/acpi/ged.rs +++ b/devices/src/acpi/ged.rs @@ -85,7 +85,7 @@ pub struct Ged { impl Ged { pub fn new( battery_present: bool, - sysbus: &mut SysBus, + sysbus: &Arc>, region_base: u64, region_size: u64, ged_event: GedEvent, @@ -103,10 +103,10 @@ impl Ged { Ok(ged) } - pub fn realize(self, sysbus: &mut SysBus) -> Result>> { + pub fn realize(self, sysbus: &Arc>) -> Result>> { let ged_event = self.ged_event.clone(); let dev = Arc::new(Mutex::new(self)); - sysbus.attach_device(&dev)?; + sysbus.lock().unwrap().attach_device(&dev)?; let ged = dev.lock().unwrap(); ged.register_acpi_powerdown_event(ged_event.power_button) diff --git a/devices/src/acpi/power.rs b/devices/src/acpi/power.rs index ae193987..ca401127 100644 --- a/devices/src/acpi/power.rs +++ b/devices/src/acpi/power.rs @@ -83,7 +83,7 @@ pub struct PowerDev { impl PowerDev { pub fn new( ged_dev: Arc>, - sysbus: &mut SysBus, + sysbus: &Arc>, region_base: u64, region_size: u64, ) -> Result { @@ -184,9 +184,9 @@ impl PowerDev { self.ged.lock().unwrap().inject_acpi_event(evt); } - pub fn realize(self, sysbus: &mut SysBus) -> Result<()> { + pub fn realize(self, sysbus: &Arc>) -> Result<()> { let dev = Arc::new(Mutex::new(self)); - sysbus.attach_device(&dev)?; + sysbus.lock().unwrap().attach_device(&dev)?; let pdev_available: bool; { diff --git a/devices/src/legacy/fwcfg.rs b/devices/src/legacy/fwcfg.rs index 3f18833d..dfd20dfb 100644 --- a/devices/src/legacy/fwcfg.rs +++ b/devices/src/legacy/fwcfg.rs @@ -844,7 +844,7 @@ pub struct FwCfgMem { impl FwCfgMem { pub fn new( sys_mem: Arc, - sysbus: &mut SysBus, + sysbus: &Arc>, region_base: u64, region_size: u64, ) -> Result { @@ -859,10 +859,12 @@ impl FwCfgMem { Ok(fwcfgmem) } - pub fn realize(mut self, sysbus: &mut SysBus) -> Result>> { + pub fn realize(mut self, sysbus: &Arc>) -> Result>> { self.fwcfg.common_realize()?; let dev = Arc::new(Mutex::new(self)); sysbus + .lock() + .unwrap() .attach_device(&dev) .with_context(|| "Failed to attach FwCfg device to system bus.")?; Ok(dev) @@ -981,7 +983,7 @@ impl SysBusDevOps for FwCfgMem { fn set_sys_resource( &mut self, - _sysbus: &mut SysBus, + _sysbus: &Arc>, region_base: u64, region_size: u64, region_name: &str, @@ -1006,7 +1008,7 @@ pub struct FwCfgIO { #[cfg(target_arch = "x86_64")] impl FwCfgIO { - pub fn new(sys_mem: Arc, sysbus: &mut SysBus) -> Result { + pub fn new(sys_mem: Arc, sysbus: &Arc>) -> Result { let mut fwcfg = FwCfgIO { base: SysBusDevBase::new(SysBusDevType::FwCfg), fwcfg: FwCfgCommon::new(sys_mem), @@ -1018,10 +1020,12 @@ impl FwCfgIO { Ok(fwcfg) } - pub fn realize(mut self, sysbus: &mut SysBus) -> Result>> { + pub fn realize(mut self, sysbus: &Arc>) -> Result>> { self.fwcfg.common_realize()?; let dev = Arc::new(Mutex::new(self)); sysbus + .lock() + .unwrap() .attach_device(&dev) .with_context(|| "Failed to attach FwCfg device to system bus.")?; Ok(dev) @@ -1141,7 +1145,7 @@ impl SysBusDevOps for FwCfgIO { fn set_sys_resource( &mut self, - _sysbus: &mut SysBus, + _sysbus: &Arc>, region_base: u64, region_size: u64, region_name: &str, diff --git a/devices/src/legacy/pflash.rs b/devices/src/legacy/pflash.rs index 7eec7cca..b2f8d616 100644 --- a/devices/src/legacy/pflash.rs +++ b/devices/src/legacy/pflash.rs @@ -109,7 +109,7 @@ impl PFlash { bank_width: u32, device_width: u32, read_only: bool, - sysbus: &mut SysBus, + sysbus: &Arc>, region_base: u64, ) -> Result { if block_len == 0 { @@ -230,19 +230,21 @@ impl PFlash { Ok(pflash) } - pub fn realize(self, sysbus: &mut SysBus) -> Result>> { + pub fn realize(self, sysbus: &Arc>) -> Result>> { let region_base = self.base.res.region_base; let host_mmap = self.host_mmap.clone(); let dev = Arc::new(Mutex::new(self)); - let region_ops = sysbus.build_region_ops(&dev); + let region_ops = sysbus.lock().unwrap().build_region_ops(&dev); let rom_region = Region::init_rom_device_region(host_mmap, region_ops, "PflashRom"); dev.lock().unwrap().rom = Some(rom_region.clone()); sysbus + .lock() + .unwrap() .sys_mem .root() .add_subregion(rom_region, region_base) .with_context(|| "Failed to attach PFlash to system bus")?; - sysbus.devices.push(dev.clone()); + sysbus.lock().unwrap().devices.push(dev.clone()); Ok(dev) } @@ -888,7 +890,7 @@ impl SysBusDevOps for PFlash { fn set_sys_resource( &mut self, - _sysbus: &mut SysBus, + _sysbus: &Arc>, region_base: u64, region_size: u64, region_name: &str, @@ -942,19 +944,12 @@ mod test { .open(file_name) .unwrap(), ); - let mut sysbus = sysbus_init(); + let sysbus = sysbus_init(); let pflash = PFlash::new( - flash_size, - fd, - sector_len, - 4, - 2, - read_only, - &mut sysbus, - flash_base, + flash_size, fd, sector_len, 4, 2, read_only, &sysbus, flash_base, ) .unwrap(); - let dev = pflash.realize(&mut sysbus).unwrap(); + let dev = pflash.realize(&sysbus).unwrap(); dev } diff --git a/devices/src/legacy/pl011.rs b/devices/src/legacy/pl011.rs index 293ec750..164f4b43 100644 --- a/devices/src/legacy/pl011.rs +++ b/devices/src/legacy/pl011.rs @@ -131,7 +131,7 @@ impl PL011 { /// Create a new `PL011` instance with default parameters. pub fn new( cfg: SerialConfig, - sysbus: &mut SysBus, + sysbus: &Arc>, region_base: u64, region_size: u64, ) -> Result { @@ -162,7 +162,7 @@ impl PL011 { } } - pub fn realize(self, sysbus: &mut SysBus) -> Result<()> { + pub fn realize(self, sysbus: &Arc>) -> Result<()> { self.chardev .lock() .unwrap() @@ -170,6 +170,8 @@ impl PL011 { .with_context(|| "Failed to realize chardev")?; let dev = Arc::new(Mutex::new(self)); sysbus + .lock() + .unwrap() .attach_device(&dev) .with_context(|| "Failed to attach PL011 to system bus.")?; MigrationManager::register_device_instance( @@ -462,8 +464,8 @@ mod test { let config = SerialConfig { chardev: chardev_cfg, }; - let mut sysbus = sysbus_init(); - let mut pl011_dev = PL011::new(config, &mut sysbus, 0x0900_0000, 0x0000_1000).unwrap(); + let sysbus = sysbus_init(); + let mut pl011_dev = PL011::new(config, &sysbus, 0x0900_0000, 0x0000_1000).unwrap(); assert_eq!(pl011_dev.state.rfifo, [0; PL011_FIFO_SIZE]); assert_eq!(pl011_dev.state.flags, 0x90); assert_eq!(pl011_dev.state.lcr, 0); diff --git a/devices/src/legacy/pl031.rs b/devices/src/legacy/pl031.rs index f1d330c7..ab41fb2a 100644 --- a/devices/src/legacy/pl031.rs +++ b/devices/src/legacy/pl031.rs @@ -80,7 +80,7 @@ pub struct PL031 { } impl PL031 { - pub fn new(sysbus: &mut SysBus, region_base: u64, region_size: u64) -> Result { + pub fn new(sysbus: &Arc>, region_base: u64, region_size: u64) -> Result { let mut pl031 = Self { base: SysBusDevBase::new(SysBusDevType::Rtc), state: PL031State::default(), @@ -99,9 +99,9 @@ impl PL031 { Ok(pl031) } - pub fn realize(self, sysbus: &mut SysBus) -> Result<()> { + pub fn realize(self, sysbus: &Arc>) -> Result<()> { let dev = Arc::new(Mutex::new(self)); - sysbus.attach_device(&dev)?; + sysbus.lock().unwrap().attach_device(&dev)?; MigrationManager::register_device_instance( PL031State::descriptor(), @@ -221,8 +221,8 @@ mod test { #[test] fn test_set_year_20xx() { - let mut sysbus = sysbus_init(); - let mut rtc = PL031::new(&mut sysbus, 0x0901_0000, 0x0000_1000).unwrap(); + let sysbus = sysbus_init(); + let mut rtc = PL031::new(&sysbus, 0x0901_0000, 0x0000_1000).unwrap(); // Set rtc time: 2013-11-13 02:04:56. let mut wtick = mktime64(2013, 11, 13, 2, 4, 56) as u32; let mut data = [0; 4]; @@ -248,8 +248,8 @@ mod test { #[test] fn test_set_year_1970() { - let mut sysbus = sysbus_init(); - let mut rtc = PL031::new(&mut sysbus, 0x0901_0000, 0x0000_1000).unwrap(); + let sysbus = sysbus_init(); + let mut rtc = PL031::new(&sysbus, 0x0901_0000, 0x0000_1000).unwrap(); // Set rtc time (min): 1970-01-01 00:00:00. let wtick = mktime64(1970, 1, 1, 0, 0, 0) as u32; let mut data = [0; 4]; diff --git a/devices/src/legacy/ramfb.rs b/devices/src/legacy/ramfb.rs index 278fd8e7..0394c7b2 100644 --- a/devices/src/legacy/ramfb.rs +++ b/devices/src/legacy/ramfb.rs @@ -251,9 +251,9 @@ impl Ramfb { } } - pub fn realize(self, sysbus: &mut SysBus) -> Result<()> { + pub fn realize(self, sysbus: &Arc>) -> Result<()> { let dev = Arc::new(Mutex::new(self)); - sysbus.attach_device(&dev)?; + sysbus.lock().unwrap().attach_device(&dev)?; Ok(()) } } diff --git a/devices/src/legacy/rtc.rs b/devices/src/legacy/rtc.rs index d60b870f..c24e2752 100644 --- a/devices/src/legacy/rtc.rs +++ b/devices/src/legacy/rtc.rs @@ -118,7 +118,7 @@ pub struct RTC { impl RTC { /// Construct function of RTC device. - pub fn new(sysbus: &mut SysBus) -> Result { + pub fn new(sysbus: &Arc>) -> Result { let mut rtc = RTC { base: SysBusDevBase { dev_type: SysBusDevType::Rtc, @@ -264,9 +264,9 @@ impl RTC { true } - pub fn realize(self, sysbus: &mut SysBus) -> Result<()> { + pub fn realize(self, sysbus: &Arc>) -> Result<()> { let dev = Arc::new(Mutex::new(self)); - sysbus.attach_device(&dev)?; + sysbus.lock().unwrap().attach_device(&dev)?; Ok(()) } @@ -427,8 +427,8 @@ mod test { #[test] fn test_set_year_20xx() -> Result<()> { - let mut sysbus = sysbus_init(); - let mut rtc = RTC::new(&mut sysbus).with_context(|| "Failed to create RTC device")?; + let sysbus = sysbus_init(); + let mut rtc = RTC::new(&sysbus).with_context(|| "Failed to create RTC device")?; // Set rtc time: 2013-11-13 02:04:56 cmos_write(&mut rtc, RTC_CENTURY_BCD, 0x20); cmos_write(&mut rtc, RTC_YEAR, 0x13); @@ -462,8 +462,8 @@ mod test { #[test] fn test_set_year_1970() -> Result<()> { - let mut sysbus = sysbus_init(); - let mut rtc = RTC::new(&mut sysbus).with_context(|| "Failed to create RTC device")?; + let sysbus = sysbus_init(); + let mut rtc = RTC::new(&sysbus).with_context(|| "Failed to create RTC device")?; // Set rtc time (min): 1970-01-01 00:00:00 cmos_write(&mut rtc, RTC_CENTURY_BCD, 0x19); cmos_write(&mut rtc, RTC_YEAR, 0x70); @@ -486,8 +486,8 @@ mod test { #[test] fn test_invalid_rtc_time() -> Result<()> { - let mut sysbus = sysbus_init(); - let mut rtc = RTC::new(&mut sysbus).with_context(|| "Failed to create RTC device")?; + let sysbus = sysbus_init(); + let mut rtc = RTC::new(&sysbus).with_context(|| "Failed to create RTC device")?; // Set rtc year: 1969 cmos_write(&mut rtc, RTC_CENTURY_BCD, 0x19); cmos_write(&mut rtc, RTC_YEAR, 0x69); diff --git a/devices/src/legacy/serial.rs b/devices/src/legacy/serial.rs index 05d6929c..dc7e25fb 100644 --- a/devices/src/legacy/serial.rs +++ b/devices/src/legacy/serial.rs @@ -126,7 +126,7 @@ pub struct Serial { impl Serial { pub fn new( cfg: SerialConfig, - sysbus: &mut SysBus, + sysbus: &Arc>, region_base: u64, region_size: u64, ) -> Result { @@ -144,14 +144,14 @@ impl Serial { Ok(serial) } - pub fn realize(self, sysbus: &mut SysBus) -> Result<()> { + pub fn realize(self, sysbus: &Arc>) -> Result<()> { self.chardev .lock() .unwrap() .realize() .with_context(|| "Failed to realize chardev")?; let dev = Arc::new(Mutex::new(self)); - sysbus.attach_device(&dev)?; + sysbus.lock().unwrap().attach_device(&dev)?; MigrationManager::register_device_instance( SerialState::descriptor(), @@ -472,11 +472,11 @@ mod test { id: "chardev".to_string(), }, }; - let mut sysbus = sysbus_init(); + let sysbus = sysbus_init(); let config = SerialConfig { chardev: chardev_cfg.clone(), }; - let mut usart = Serial::new(config, &mut sysbus, SERIAL_ADDR, 8).unwrap(); + let mut usart = Serial::new(config, &sysbus, SERIAL_ADDR, 8).unwrap(); assert_eq!(usart.state.ier, 0); assert_eq!(usart.state.iir, 1); assert_eq!(usart.state.lcr, 3); @@ -533,8 +533,8 @@ mod test { let config = SerialConfig { chardev: chardev_cfg, }; - let mut sysbus = sysbus_init(); - let mut usart = Serial::new(config, &mut sysbus, SERIAL_ADDR, 8).unwrap(); + let sysbus = sysbus_init(); + let mut usart = Serial::new(config, &sysbus, SERIAL_ADDR, 8).unwrap(); // Get state vector for usart let serial_state_result = usart.get_state_vec(); assert!(serial_state_result.is_ok()); diff --git a/devices/src/sysbus/mod.rs b/devices/src/sysbus/mod.rs index 4ca00be1..1e56f363 100644 --- a/devices/src/sysbus/mod.rs +++ b/devices/src/sysbus/mod.rs @@ -282,14 +282,16 @@ pub trait SysBusDevOps: Device + Send + AmlBuilder { fn set_sys_resource( &mut self, - sysbus: &mut SysBus, + sysbus: &Arc>, region_base: u64, region_size: u64, region_name: &str, ) -> Result<()> { - let irq = self.get_irq(sysbus)?; + let mut locked_sysbus = sysbus.lock().unwrap(); + let irq = self.get_irq(&mut locked_sysbus)?; let interrupt_evt = self.sysbusdev_base().interrupt_evt.clone(); - let irq_manager = sysbus.irq_manager.clone(); + let irq_manager = locked_sysbus.irq_manager.clone(); + drop(locked_sysbus); self.sysbusdev_base_mut().irq_state = IrqState::new(irq as u32, interrupt_evt, irq_manager, TriggerMode::Edge); @@ -391,7 +393,7 @@ pub fn to_sysbusdevops(dev: &dyn Device) -> Option<&dyn SysBusDevOps> { } #[cfg(test)] -pub fn sysbus_init() -> SysBus { +pub fn sysbus_init() -> Arc> { let sys_mem = AddressSpace::new( Region::init_container_region(u64::max_value(), "sys_mem"), "sys_mem", @@ -407,11 +409,11 @@ pub fn sysbus_init() -> SysBus { .unwrap(); let free_irqs: (i32, i32) = (IRQ_BASE, IRQ_MAX); let mmio_region: (u64, u64) = (0x0A00_0000, 0x1000_0000); - SysBus::new( + Arc::new(Mutex::new(SysBus::new( #[cfg(target_arch = "x86_64")] &sys_io, &sys_mem, free_irqs, mmio_region, - ) + ))) } diff --git a/machine/src/aarch64/fdt.rs b/machine/src/aarch64/fdt.rs index 76815b17..c08822c3 100644 --- a/machine/src/aarch64/fdt.rs +++ b/machine/src/aarch64/fdt.rs @@ -265,7 +265,8 @@ impl CompileFDTHelper for MachineBase { fdt.set_property_string("method", "hvc")?; fdt.end_node(psci_node_dep)?; - for dev in self.sysbus.devices.iter() { + let devices = self.sysbus.lock().unwrap().devices.clone(); + for dev in devices.iter() { let locked_dev = dev.lock().unwrap(); match locked_dev.sysbusdev_base().dev_type { SysBusDevType::PL011 => { diff --git a/machine/src/aarch64/micro.rs b/machine/src/aarch64/micro.rs index 6b019d94..51cc2de4 100644 --- a/machine/src/aarch64/micro.rs +++ b/machine/src/aarch64/micro.rs @@ -101,33 +101,28 @@ impl MachineOps for LightMachine { self.base.irq_chip.as_ref().unwrap().realize()?; let irq_manager = locked_hypervisor.create_irq_manager()?; - self.base.sysbus.irq_manager = irq_manager.line_irq_manager; + self.base.sysbus.lock().unwrap().irq_manager = irq_manager.line_irq_manager; Ok(()) } fn add_rtc_device(&mut self) -> Result<()> { let pl031 = PL031::new( - &mut self.base.sysbus, + &self.base.sysbus, MEM_LAYOUT[LayoutEntryType::Rtc as usize].0, MEM_LAYOUT[LayoutEntryType::Rtc as usize].1, )?; pl031 - .realize(&mut self.base.sysbus) + .realize(&self.base.sysbus) .with_context(|| "Failed to realize pl031.") } fn add_serial_device(&mut self, config: &SerialConfig) -> Result<()> { let region_base: u64 = MEM_LAYOUT[LayoutEntryType::Uart as usize].0; let region_size: u64 = MEM_LAYOUT[LayoutEntryType::Uart as usize].1; - let pl011 = PL011::new( - config.clone(), - &mut self.base.sysbus, - region_base, - region_size, - ) - .with_context(|| "Failed to create PL011")?; + let pl011 = PL011::new(config.clone(), &self.base.sysbus, region_base, region_size) + .with_context(|| "Failed to create PL011")?; pl011 - .realize(&mut self.base.sysbus) + .realize(&self.base.sysbus) .with_context(|| "Failed to realize PL011")?; let mut bs = self.base.boot_source.lock().unwrap(); bs.kernel_cmdline.push(Param { @@ -140,7 +135,7 @@ impl MachineOps for LightMachine { fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> { let mut locked_vm = vm.lock().unwrap(); - trace::sysbus(&locked_vm.base.sysbus); + trace::sysbus(&locked_vm.base.sysbus.lock().unwrap()); trace::vm_state(&locked_vm.base.vm_state); let topology = CPUTopology::new().set_topology(( diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index 289083cf..a5a99aef 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -347,7 +347,7 @@ impl StdMachineOps for StdMachine { let mut fwcfg = FwCfgMem::new( self.base.sys_mem.clone(), - &mut self.base.sysbus, + &self.base.sysbus, MEM_LAYOUT[LayoutEntryType::FwCfg as usize].0, MEM_LAYOUT[LayoutEntryType::FwCfg as usize].1, )?; @@ -383,7 +383,7 @@ impl StdMachineOps for StdMachine { .with_context(|| DevErrorKind::AddEntryErr("bios-geometry".to_string()))?; let fwcfg_dev = fwcfg - .realize(&mut self.base.sysbus) + .realize(&self.base.sysbus) .with_context(|| "Failed to realize fwcfg device")?; self.base.fwcfg_dev = Some(fwcfg_dev.clone()); @@ -447,18 +447,18 @@ impl MachineOps for StdMachine { "Failed to create intx state: legacy irq manager is none." )); } - self.base.sysbus.irq_manager = line_irq_manager; + self.base.sysbus.lock().unwrap().irq_manager = line_irq_manager; Ok(()) } fn add_rtc_device(&mut self) -> Result<()> { let rtc = PL031::new( - &mut self.base.sysbus, + &self.base.sysbus, MEM_LAYOUT[LayoutEntryType::Rtc as usize].0, MEM_LAYOUT[LayoutEntryType::Rtc as usize].1, )?; - rtc.realize(&mut self.base.sysbus) + rtc.realize(&self.base.sysbus) .with_context(|| "Failed to realize PL031") } @@ -466,22 +466,22 @@ impl MachineOps for StdMachine { let battery_present = self.base.vm_config.lock().unwrap().machine_config.battery; let ged = Ged::new( battery_present, - &mut self.base.sysbus, + &self.base.sysbus, MEM_LAYOUT[LayoutEntryType::Ged as usize].0, MEM_LAYOUT[LayoutEntryType::Ged as usize].1, GedEvent::new(self.power_button.clone()), )?; let ged_dev = ged - .realize(&mut self.base.sysbus) + .realize(&self.base.sysbus) .with_context(|| "Failed to realize Ged")?; if battery_present { let pdev = PowerDev::new( ged_dev, - &mut self.base.sysbus, + &self.base.sysbus, MEM_LAYOUT[LayoutEntryType::PowerDev as usize].0, MEM_LAYOUT[LayoutEntryType::PowerDev as usize].1, )?; - pdev.realize(&mut self.base.sysbus) + pdev.realize(&self.base.sysbus) .with_context(|| "Failed to realize PowerDev")?; } Ok(()) @@ -490,15 +490,10 @@ impl MachineOps for StdMachine { fn add_serial_device(&mut self, config: &SerialConfig) -> Result<()> { let region_base: u64 = MEM_LAYOUT[LayoutEntryType::Uart as usize].0; let region_size: u64 = MEM_LAYOUT[LayoutEntryType::Uart as usize].1; - let pl011 = PL011::new( - config.clone(), - &mut self.base.sysbus, - region_base, - region_size, - ) - .with_context(|| "Failed to create PL011")?; + let pl011 = PL011::new(config.clone(), &self.base.sysbus, region_base, region_size) + .with_context(|| "Failed to create PL011")?; pl011 - .realize(&mut self.base.sysbus) + .realize(&self.base.sysbus) .with_context(|| "Failed to realize PL011")?; let mut bs = self.base.boot_source.lock().unwrap(); bs.kernel_cmdline.push(Param { @@ -658,11 +653,11 @@ impl MachineOps for StdMachine { 4, 2, read_only, - &mut self.base.sysbus, + &self.base.sysbus, flash_base, ) .with_context(|| MachineError::InitPflashErr)?; - PFlash::realize(pflash, &mut self.base.sysbus) + PFlash::realize(pflash, &self.base.sysbus) .with_context(|| MachineError::RlzPflashErr)?; flash_base += flash_size; } @@ -714,7 +709,7 @@ impl MachineOps for StdMachine { let mut ramfb = Ramfb::new(sys_mem.clone(), config.install); ramfb.ramfb_state.setup(&fwcfg_dev)?; - ramfb.realize(&mut self.base.sysbus) + ramfb.realize(&self.base.sysbus) } fn get_pci_host(&mut self) -> Result<&Arc>> { @@ -958,7 +953,8 @@ impl AcpiBuilder for StdMachine { spcr.set_field(52, 1_u8 << 3); // Irq number used by the UART let mut uart_irq: u32 = 0; - for dev in self.base.sysbus.devices.iter() { + let devices = self.base.sysbus.lock().unwrap().devices.clone(); + for dev in devices.iter() { let locked_dev = dev.lock().unwrap(); if locked_dev.sysbusdev_base().dev_type == SysBusDevType::PL011 { uart_irq = locked_dev.sysbusdev_base().irq_state.irq as _; @@ -1007,7 +1003,7 @@ impl AcpiBuilder for StdMachine { dsdt.append_child(sb_scope.aml_bytes().as_slice()); // 3. Info of devices attached to system bus. - dsdt.append_child(self.base.sysbus.aml_bytes().as_slice()); + dsdt.append_child(self.base.sysbus.lock().unwrap().aml_bytes().as_slice()); let dsdt_begin = StdMachine::add_table_to_loader(acpi_data, loader, &dsdt) .with_context(|| "Fail to add DSDT table to loader")?; diff --git a/machine/src/lib.rs b/machine/src/lib.rs index f331c60e..ecb96e2c 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -133,7 +133,7 @@ pub struct MachineBase { #[cfg(target_arch = "x86_64")] sys_io: Arc, /// System bus. - sysbus: SysBus, + sysbus: Arc>, /// VM running state. vm_state: Arc<(Mutex, Condvar)>, /// Vm boot_source config. @@ -218,7 +218,7 @@ impl MachineBase { sys_mem, #[cfg(target_arch = "x86_64")] sys_io, - sysbus, + sysbus: Arc::new(Mutex::new(sysbus)), vm_state: Arc::new((Mutex::new(VmState::Created), Condvar::new())), boot_source: Arc::new(Mutex::new(vm_config.clone().boot_source)), vm_config: Arc::new(Mutex::new(vm_config.clone())), @@ -776,7 +776,7 @@ pub trait MachineOps: MachineLifecycle { let mut virtio_device = None; if serial_cfg.bus.is_none() { // Micro_vm. - for dev in self.get_sys_bus().devices.iter() { + for dev in self.get_sysbus_devices().iter() { let locked_busdev = dev.lock().unwrap(); if locked_busdev.sysbusdev_base().dev_type == SysBusDevType::VirtioMmio { let virtio_mmio_dev = locked_busdev @@ -938,8 +938,8 @@ pub trait MachineOps: MachineLifecycle { Ok(()) } - fn get_sys_bus(&mut self) -> &SysBus { - &self.machine_base().sysbus + fn get_sysbus_devices(&mut self) -> Vec>> { + self.machine_base().sysbus.lock().unwrap().devices.clone() } fn get_fwcfg_dev(&mut self) -> Option>> { @@ -951,8 +951,7 @@ pub trait MachineOps: MachineLifecycle { } fn reset_all_devices(&mut self) -> Result<()> { - let sysbus = self.get_sys_bus(); - for dev in sysbus.devices.iter() { + for dev in self.get_sysbus_devices().iter() { dev.lock() .unwrap() .reset() diff --git a/machine/src/micro_common/mod.rs b/machine/src/micro_common/mod.rs index 349efe21..e7d08ae6 100644 --- a/machine/src/micro_common/mod.rs +++ b/machine/src/micro_common/mod.rs @@ -487,18 +487,18 @@ impl LightMachine { device: Arc>, ) -> Result>> { let sys_mem = self.get_sys_mem().clone(); - let region_base = self.base.sysbus.min_free_base; + let region_base = self.base.sysbus.lock().unwrap().min_free_base; let region_size = MEM_LAYOUT[LayoutEntryType::Mmio as usize].1; let dev = VirtioMmioDevice::new( &sys_mem, name, device, - &mut self.base.sysbus, + &self.base.sysbus, region_base, region_size, )?; let mmio_device = dev - .realize(&mut self.base.sysbus) + .realize(&self.base.sysbus) .with_context(|| MachineError::RlzVirtioMmioErr)?; #[cfg(target_arch = "x86_64")] { @@ -509,7 +509,7 @@ impl LightMachine { value: format!("{}@0x{:08x}:{}", res.region_size, res.region_base, res.irq), }); } - self.base.sysbus.min_free_base += region_size; + self.base.sysbus.lock().unwrap().min_free_base += region_size; Ok(mmio_device) } } diff --git a/machine/src/x86_64/micro.rs b/machine/src/x86_64/micro.rs index 0d88aaec..dad7e7b7 100644 --- a/machine/src/x86_64/micro.rs +++ b/machine/src/x86_64/micro.rs @@ -83,7 +83,7 @@ impl MachineOps for LightMachine { locked_hypervisor.create_interrupt_controller()?; let irq_manager = locked_hypervisor.create_irq_manager()?; - self.base.sysbus.irq_manager = irq_manager.line_irq_manager; + self.base.sysbus.lock().unwrap().irq_manager = irq_manager.line_irq_manager; Ok(()) } @@ -132,14 +132,9 @@ impl MachineOps for LightMachine { let region_base: u64 = SERIAL_ADDR; let region_size: u64 = 8; - let serial = Serial::new( - config.clone(), - &mut self.base.sysbus, - region_base, - region_size, - )?; + let serial = Serial::new(config.clone(), &self.base.sysbus, region_base, region_size)?; serial - .realize(&mut self.base.sysbus) + .realize(&self.base.sysbus) .with_context(|| "Failed to realize serial device.") } diff --git a/machine/src/x86_64/standard.rs b/machine/src/x86_64/standard.rs index dc970a33..e61d5589 100644 --- a/machine/src/x86_64/standard.rs +++ b/machine/src/x86_64/standard.rs @@ -217,7 +217,7 @@ impl StdMachine { ); let cpu_controller = CpuController::new( self.base.cpu_topo.max_cpus, - &mut self.base.sysbus, + &self.base.sysbus, region_base, region_size, cpu_config, @@ -225,7 +225,7 @@ impl StdMachine { self.base.cpus.clone(), )?; let realize_controller = cpu_controller - .realize(&mut self.base.sysbus) + .realize(&self.base.sysbus) .with_context(|| "Failed to realize Cpu Controller")?; self.register_hotplug_vcpu_event(hotplug_cpu_req, vm)?; self.cpu_controller = Some(realize_controller); @@ -275,7 +275,7 @@ impl StdMachineOps for StdMachine { nr_cpus: u8, max_cpus: u8, ) -> Result>>> { - let mut fwcfg = FwCfgIO::new(self.base.sys_mem.clone(), &mut self.base.sysbus)?; + let mut fwcfg = FwCfgIO::new(self.base.sys_mem.clone(), &self.base.sysbus)?; fwcfg.add_data_entry(FwCfgEntryType::NbCpus, nr_cpus.as_bytes().to_vec())?; fwcfg.add_data_entry(FwCfgEntryType::MaxCpus, max_cpus.as_bytes().to_vec())?; fwcfg.add_data_entry(FwCfgEntryType::Irq0Override, 1_u32.as_bytes().to_vec())?; @@ -285,7 +285,7 @@ impl StdMachineOps for StdMachine { .add_file_entry("bootorder", boot_order) .with_context(|| DevErrorKind::AddEntryErr("bootorder".to_string()))?; - let fwcfg_dev = FwCfgIO::realize(fwcfg, &mut self.base.sysbus) + let fwcfg_dev = FwCfgIO::realize(fwcfg, &self.base.sysbus) .with_context(|| "Failed to realize fwcfg device")?; self.base.fwcfg_dev = Some(fwcfg_dev.clone()); @@ -397,7 +397,7 @@ impl MachineOps for StdMachine { let root_bus = &self.pci_host.lock().unwrap().root_bus; let irq_manager = locked_hypervisor.create_irq_manager()?; root_bus.lock().unwrap().msi_irq_manager = irq_manager.msi_irq_manager; - self.base.sysbus.irq_manager = irq_manager.line_irq_manager; + self.base.sysbus.lock().unwrap().irq_manager = irq_manager.line_irq_manager; Ok(()) } @@ -433,14 +433,13 @@ impl MachineOps for StdMachine { } fn add_rtc_device(&mut self, mem_size: u64) -> Result<()> { - let mut rtc = - RTC::new(&mut self.base.sysbus).with_context(|| "Failed to create RTC device")?; + let mut rtc = RTC::new(&self.base.sysbus).with_context(|| "Failed to create RTC device")?; rtc.set_memory( mem_size, MEM_LAYOUT[LayoutEntryType::MemBelow4g as usize].0 + MEM_LAYOUT[LayoutEntryType::MemBelow4g as usize].1, ); - rtc.realize(&mut self.base.sysbus) + rtc.realize(&self.base.sysbus) .with_context(|| "Failed to realize RTC device") } @@ -450,13 +449,13 @@ impl MachineOps for StdMachine { let ged_event = GedEvent::new(self.power_button.clone(), self.cpu_resize_req.clone()); let ged = Ged::new( false, - &mut self.base.sysbus, + &self.base.sysbus, region_base, region_size, ged_event, )?; - ged.realize(&mut self.base.sysbus) + ged.realize(&self.base.sysbus) .with_context(|| "Failed to realize Ged")?; Ok(()) } @@ -464,14 +463,9 @@ impl MachineOps for StdMachine { fn add_serial_device(&mut self, config: &SerialConfig) -> Result<()> { let region_base: u64 = SERIAL_ADDR; let region_size: u64 = 8; - let serial = Serial::new( - config.clone(), - &mut self.base.sysbus, - region_base, - region_size, - )?; + let serial = Serial::new(config.clone(), &self.base.sysbus, region_base, region_size)?; serial - .realize(&mut self.base.sysbus) + .realize(&self.base.sysbus) .with_context(|| "Failed to realize serial device.")?; Ok(()) } @@ -621,12 +615,12 @@ impl MachineOps for StdMachine { 4_u32, 1_u32, config.readonly, - &mut self.base.sysbus, + &self.base.sysbus, flash_end - pfl_size, ) .with_context(|| MachineError::InitPflashErr)?; pflash - .realize(&mut self.base.sysbus) + .realize(&self.base.sysbus) .with_context(|| MachineError::RlzPflashErr)?; flash_end -= pfl_size; } @@ -736,7 +730,7 @@ impl AcpiBuilder for StdMachine { dsdt.append_child(sb_scope.aml_bytes().as_slice()); // 2. Info of devices attached to system bus. - dsdt.append_child(self.base.sysbus.aml_bytes().as_slice()); + dsdt.append_child(self.base.sysbus.lock().unwrap().aml_bytes().as_slice()); // 3. Add _S5 sleep state. let mut package = AmlPackage::new(4); diff --git a/virtio/src/lib.rs b/virtio/src/lib.rs index 61ee3ead..54bc5256 100644 --- a/virtio/src/lib.rs +++ b/virtio/src/lib.rs @@ -909,14 +909,14 @@ pub fn virtio_register_pcidevops_type() -> Result<()> { #[cfg(test)] mod tests { - use std::sync::Arc; + use std::sync::{Arc, Mutex}; use address_space::{AddressSpace, GuestAddress, HostMemMapping, Region}; use devices::sysbus::{SysBus, IRQ_BASE, IRQ_MAX}; pub const MEMORY_SIZE: u64 = 1024 * 1024; - pub fn sysbus_init() -> SysBus { + pub fn sysbus_init() -> Arc> { let sys_mem = AddressSpace::new( Region::init_container_region(u64::max_value(), "sys_mem"), "sys_mem", @@ -932,13 +932,13 @@ mod tests { .unwrap(); let free_irqs: (i32, i32) = (IRQ_BASE, IRQ_MAX); let mmio_region: (u64, u64) = (0x0A00_0000, 0x1000_0000); - SysBus::new( + Arc::new(Mutex::new(SysBus::new( #[cfg(target_arch = "x86_64")] &sys_io, &sys_mem, free_irqs, mmio_region, - ) + ))) } pub fn address_space_init() -> Arc { diff --git a/virtio/src/transport/virtio_mmio.rs b/virtio/src/transport/virtio_mmio.rs index ebde7c0c..5d07ce77 100644 --- a/virtio/src/transport/virtio_mmio.rs +++ b/virtio/src/transport/virtio_mmio.rs @@ -138,11 +138,11 @@ impl VirtioMmioDevice { mem_space: &Arc, name: String, device: Arc>, - sysbus: &mut SysBus, + sysbus: &Arc>, region_base: u64, region_size: u64, ) -> Result { - if region_base >= sysbus.mmio_region.1 { + if region_base >= sysbus.lock().unwrap().mmio_region.1 { bail!("Mmio region space exhausted."); } let queue_num = device.lock().unwrap().queue_num(); @@ -163,7 +163,7 @@ impl VirtioMmioDevice { Ok(mmio_device) } - pub fn realize(mut self, sysbus: &mut SysBus) -> Result>> { + pub fn realize(mut self, sysbus: &Arc>) -> Result>> { self.assign_interrupt_cb(); self.device .lock() @@ -172,7 +172,7 @@ impl VirtioMmioDevice { .with_context(|| "Failed to realize virtio.")?; let dev = Arc::new(Mutex::new(self)); - sysbus.attach_device(&dev)?; + sysbus.lock().unwrap().attach_device(&dev)?; Ok(dev) } @@ -641,12 +641,12 @@ mod tests { let virtio_device = Arc::new(Mutex::new(VirtioDeviceTest::new())); let sys_space = address_space_init(); - let mut sysbus = sysbus_init(); + let sysbus = sysbus_init(); let virtio_mmio_device = VirtioMmioDevice::new( &sys_space, "test_virtio_mmio_device".to_string(), virtio_device.clone(), - &mut sysbus, + &sysbus, 0x0A00_0000, 0x0000_0200, ) -- Gitee From fe8edfdb5a5416a5425fb90b2855990e44244731 Mon Sep 17 00:00:00 2001 From: yexiao Date: Thu, 13 Jun 2024 14:21:13 +0800 Subject: [PATCH 152/489] virtio-net: fix an error of virtio-net If the virtio queue is not ready, then report virtio error. this error was introduced in 93994cfeda19a3c5918e45c580e585a1e285cbf7. Signed-off-by: Xiao Ye --- tests/mod_test/tests/net_test.rs | 5 ++++- virtio/src/queue/split.rs | 4 ++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/tests/mod_test/tests/net_test.rs b/tests/mod_test/tests/net_test.rs index 3ec79a1e..4062ce83 100644 --- a/tests/mod_test/tests/net_test.rs +++ b/tests/mod_test/tests/net_test.rs @@ -2083,7 +2083,10 @@ fn virtio_net_abnormal_rx_tx_test_3() { vqs.push(vq); } fill_rx_vq(test_state.clone(), alloc.clone(), vqs[0].clone()); - net.borrow().set_driver_ok(); + + // Set driver ok without check. + let status = net.borrow().get_status() | VIRTIO_CONFIG_S_DRIVER_OK; + net.borrow().set_status(status); let request = get_arp_request(id); let length = request.as_bytes().len() as u64; diff --git a/virtio/src/queue/split.rs b/virtio/src/queue/split.rs index 302c258d..643693b5 100644 --- a/virtio/src/queue/split.rs +++ b/virtio/src/queue/split.rs @@ -892,6 +892,10 @@ impl VringOps for SplitVring { features: u64, suppress: bool, ) -> Result<()> { + if !self.is_enabled() { + bail!("queue is not ready"); + } + if virtio_has_feature(features, VIRTIO_F_RING_EVENT_IDX) { self.set_avail_event(sys_mem, self.get_avail_idx(sys_mem)?)?; } else { -- Gitee From 374ff8dd84f4cd86fd6650a3cafaf61f5a3c3a4c Mon Sep 17 00:00:00 2001 From: yexiao Date: Thu, 13 Jun 2024 14:30:30 +0800 Subject: [PATCH 153/489] virtio-net: fix an error of virtio-net The default value of queue_avail should be true, this error was introduced in 93994cfeda19a3c5918e45c580e585a1e285cbf7. Signed-off-by: Xiao Ye --- virtio/src/device/net.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index c4053f06..25abc345 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -694,7 +694,7 @@ struct RxVirtio { impl RxVirtio { fn new(queue: Arc>, queue_evt: Arc) -> Self { RxVirtio { - queue_avail: false, + queue_avail: true, queue, queue_evt, } -- Gitee From daa1bdc5ce3bc8379ca557f5fed46e431cc95ebc Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Tue, 18 Jun 2024 21:42:07 +0800 Subject: [PATCH 154/489] stratovirt-img: Fix all clippy warnings Fix all clippy warnings. Signed-off-by: liuxiangdong --- image/src/cmdline.rs | 16 +++++------ image/src/img.rs | 63 ++++++++++++++++++++++++++------------------ 2 files changed, 45 insertions(+), 34 deletions(-) diff --git a/image/src/cmdline.rs b/image/src/cmdline.rs index a2f6079b..8cf7c392 100644 --- a/image/src/cmdline.rs +++ b/image/src/cmdline.rs @@ -71,15 +71,15 @@ impl ArgsParse { for idx in 0..len { let str = args[idx as usize].clone(); - if str.starts_with("-") && str.len() > 1 { - if pre_opt.1.len() != 0 { + if str.starts_with('-') && str.len() > 1 { + if !pre_opt.1.is_empty() { bail!("missing argument for option '{}'", pre_opt.1); } let name = if str.starts_with("--") && str.len() > 2 { - (&str[2..]).to_string() - } else if str.starts_with("-") && str.len() > 1 { - (&str[1..]).to_string() + str[2..].to_string() + } else if str.starts_with('-') && str.len() > 1 { + str[1..].to_string() } else { bail!("unrecognized option '{}'", str); }; @@ -100,7 +100,7 @@ impl ArgsParse { continue; } - if pre_opt.0 + 1 == idx && pre_opt.1.len() != 0 { + if pre_opt.0 + 1 == idx && !pre_opt.1.is_empty() { let name = pre_opt.1.to_string(); let value = str.to_string(); if let Some(arg) = self.args.get_mut(&name) { @@ -117,14 +117,14 @@ impl ArgsParse { } } pre_opt = (0, "".to_string()); - } else if pre_opt.1.len() == 0 { + } else if pre_opt.1.is_empty() { self.free.push(str.to_string()); } else { bail!("unrecognized option '{}'", pre_opt.1); } } - if pre_opt.0 == 0 && pre_opt.1.len() != 0 { + if pre_opt.0 == 0 && !pre_opt.1.is_empty() { bail!("unrecognized option '{}'", pre_opt.1); } diff --git a/image/src/img.rs b/image/src/img.rs index e106b70e..d37b5f39 100644 --- a/image/src/img.rs +++ b/image/src/img.rs @@ -115,7 +115,7 @@ impl Drop for ImageFile { pub(crate) fn image_create(args: Vec) -> Result<()> { let mut create_options = CreateOptions::default(); let mut arg_parser = ArgsParse::create(vec!["h", "help"], vec!["f"], vec!["o"]); - arg_parser.parse(args.clone())?; + arg_parser.parse(args)?; if arg_parser.opt_present("h") || arg_parser.opt_present("help") { print_help(); @@ -170,7 +170,7 @@ pub(crate) fn image_create(args: Vec) -> Result<()> { .write(true) .custom_flags(libc::O_CREAT | libc::O_TRUNC) .mode(0o660) - .open(path.clone())?; + .open(path)?; let aio = Aio::new(Arc::new(SyncAioInfo::complete_func), AioEngine::Off, None)?; let image_info = match disk_fmt { @@ -191,7 +191,7 @@ pub(crate) fn image_create(args: Vec) -> Result<()> { } pub(crate) fn image_info(args: Vec) -> Result<()> { - if args.len() < 1 { + if args.is_empty() { bail!("Not enough arguments"); } let mut arg_parser = ArgsParse::create(vec!["h", "help"], vec![], vec![]); @@ -216,9 +216,10 @@ pub(crate) fn image_info(args: Vec) -> Result<()> { let aio = Aio::new(Arc::new(SyncAioInfo::complete_func), AioEngine::Off, None)?; let image_file = ImageFile::create(&img_path, false)?; let detect_fmt = image_file.detect_img_format()?; - - let mut conf = BlockProperty::default(); - conf.format = detect_fmt; + let conf = BlockProperty { + format: detect_fmt, + ..Default::default() + }; let mut driver: Box> = match detect_fmt { DiskFormat::Raw => Box::new(RawDriver::new(image_file.file.try_clone()?, aio, conf)), DiskFormat::Qcow2 => { @@ -229,8 +230,10 @@ pub(crate) fn image_info(args: Vec) -> Result<()> { } }; - let mut image_info = ImageInfo::default(); - image_info.path = img_path; + let mut image_info = ImageInfo { + path: img_path, + ..Default::default() + }; driver.query_image(&mut image_info)?; print!("{}", image_info); Ok(()) @@ -258,9 +261,9 @@ pub(crate) fn image_check(args: Vec) -> Result<()> { } if let Some(kind) = arg_parser.opt_str("r") { - if kind == "leaks".to_string() { + if kind == *"leaks" { fix |= FIX_LEAKS; - } else if kind == "all".to_string() { + } else if kind == *"all" { fix |= FIX_LEAKS; fix |= FIX_ERRORS; } else { @@ -294,8 +297,10 @@ pub(crate) fn image_check(args: Vec) -> Result<()> { bail!("stratovirt-img: This image format does not support checks"); } DiskFormat::Qcow2 => { - let mut conf = BlockProperty::default(); - conf.format = DiskFormat::Qcow2; + let conf = BlockProperty { + format: DiskFormat::Qcow2, + ..Default::default() + }; let mut qcow2_driver = create_qcow2_driver_for_check(file, conf)?; let ret = qcow2_driver.check_image(&mut check_res, quite, fix); let check_message = check_res.collect_check_message(); @@ -337,9 +342,10 @@ pub(crate) fn image_resize(mut args: Vec) -> Result<()> { let image_file = ImageFile::create(&img_path, false)?; let detect_fmt = image_file.detect_img_format()?; let real_fmt = image_file.check_img_format(disk_fmt, detect_fmt)?; - - let mut conf = BlockProperty::default(); - conf.format = real_fmt; + let conf = BlockProperty { + format: real_fmt, + ..Default::default() + }; let mut driver: Box> = match real_fmt { DiskFormat::Raw => Box::new(RawDriver::new(image_file.file.try_clone()?, aio, conf)), DiskFormat::Qcow2 => { @@ -352,12 +358,12 @@ pub(crate) fn image_resize(mut args: Vec) -> Result<()> { let old_size = driver.disk_size()?; // Only expansion is supported currently. - let new_size = if size_str.starts_with("+") { + let new_size = if size_str.starts_with('+') { let size = memory_unit_conversion(&size_str, 1)?; old_size .checked_add(size) .ok_or_else(|| anyhow!("Disk size is too large for chosen offset"))? - } else if size_str.starts_with("-") { + } else if size_str.starts_with('-') { bail!("The shrink operation is not supported"); } else { let new_size = memory_unit_conversion(&size_str, 1)?; @@ -443,10 +449,12 @@ pub(crate) fn image_snapshot(args: Vec) -> Result<()> { } // Create qcow2 driver. - let mut qcow2_conf = BlockProperty::default(); - qcow2_conf.format = DiskFormat::Qcow2; - qcow2_conf.discard = true; - qcow2_conf.write_zeroes = WriteZeroesState::Unmap; + let qcow2_conf = BlockProperty { + format: DiskFormat::Qcow2, + discard: true, + write_zeroes: WriteZeroesState::Unmap, + ..Default::default() + }; let aio = Aio::new(Arc::new(SyncAioInfo::complete_func), AioEngine::Off, None).unwrap(); let mut qcow2_driver = Qcow2Driver::new(image_file.file.try_clone()?, aio, qcow2_conf.clone())?; @@ -603,8 +611,10 @@ mod test { } fn create_driver(&self) -> Qcow2Driver<()> { - let mut conf = BlockProperty::default(); - conf.format = DiskFormat::Qcow2; + let conf = BlockProperty { + format: DiskFormat::Qcow2, + ..Default::default() + }; let aio = Aio::new(Arc::new(SyncAioInfo::complete_func), AioEngine::Off, None).unwrap(); let mut qcow2_driver = Qcow2Driver::new(self.file.try_clone().unwrap(), aio, conf.clone()).unwrap(); @@ -614,8 +624,10 @@ mod test { fn create_driver_for_check(&self) -> Qcow2Driver<()> { let file = self.file.try_clone().unwrap(); - let mut conf = BlockProperty::default(); - conf.format = DiskFormat::Qcow2; + let conf = BlockProperty { + format: DiskFormat::Qcow2, + ..Default::default() + }; let qcow2_driver = create_qcow2_driver_for_check(file, conf).unwrap(); qcow2_driver } @@ -695,7 +707,6 @@ mod test { fn create_driver(&mut self) -> RawDriver<()> { let mut conf = BlockProperty::default(); - conf.format = DiskFormat::Raw; let aio = Aio::new(Arc::new(SyncAioInfo::complete_func), AioEngine::Off, None).unwrap(); -- Gitee From ad99d14c7c89e6e6e96b1ba706806b2db9c6850a Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Tue, 18 Jun 2024 18:00:46 +0800 Subject: [PATCH 155/489] drive: use `Arc` to avoid generating actual copy actions We don't need to copy multiple File instances, Using Arc to avoid generating actual copy actions. Signed-off-by: liuxiangdong --- address_space/src/host_mmap.rs | 4 +-- block_backend/src/file.rs | 7 +++-- block_backend/src/lib.rs | 2 +- block_backend/src/qcow2/mod.rs | 48 +++++++++++++++++----------- block_backend/src/qcow2/refcount.rs | 17 ++++++---- block_backend/src/raw.rs | 2 +- devices/src/legacy/pflash.rs | 10 +++--- image/src/img.rs | 49 ++++++++++++++--------------- machine/src/lib.rs | 2 +- machine/src/standard_common/mod.rs | 4 +-- machine/src/x86_64/standard.rs | 12 +++---- machine_manager/src/config/drive.rs | 3 +- machine_manager/src/config/mod.rs | 13 ++++---- 13 files changed, 95 insertions(+), 78 deletions(-) diff --git a/address_space/src/host_mmap.rs b/address_space/src/host_mmap.rs index ca309770..d2012e6f 100644 --- a/address_space/src/host_mmap.rs +++ b/address_space/src/host_mmap.rs @@ -59,9 +59,9 @@ impl FileBackend { /// # Arguments /// /// * `fd` - Opened backend file. - pub fn new_common(fd: File) -> Self { + pub fn new_common(fd: Arc) -> Self { Self { - file: Arc::new(fd), + file: fd, offset: 0, page_size: 0, } diff --git a/block_backend/src/file.rs b/block_backend/src/file.rs index 45ea1549..3acef038 100644 --- a/block_backend/src/file.rs +++ b/block_backend/src/file.rs @@ -55,7 +55,7 @@ impl CombineRequest { } pub struct FileDriver { - pub file: File, + pub file: Arc, aio: Rc>>, pub incomplete: Arc, delete_evts: Vec, @@ -63,7 +63,7 @@ pub struct FileDriver { } impl FileDriver { - pub fn new(file: File, aio: Aio, block_prop: BlockProperty) -> Self { + pub fn new(file: Arc, aio: Aio, block_prop: BlockProperty) -> Self { Self { file, incomplete: aio.incomplete_cnt.clone(), @@ -199,13 +199,14 @@ impl FileDriver { pub fn disk_size(&mut self) -> Result { let disk_size = self .file + .as_ref() .seek(SeekFrom::End(0)) .with_context(|| "Failed to seek the end for file")?; Ok(disk_size) } pub fn extend_to_len(&mut self, len: u64) -> Result<()> { - let file_end = self.file.seek(SeekFrom::End(0))?; + let file_end = self.file.as_ref().seek(SeekFrom::End(0))?; if len > file_end { self.file.set_len(len)?; } diff --git a/block_backend/src/lib.rs b/block_backend/src/lib.rs index b6f42513..b4de1fc9 100644 --- a/block_backend/src/lib.rs +++ b/block_backend/src/lib.rs @@ -394,7 +394,7 @@ pub trait BlockDriverOps: Send { } pub fn create_block_backend( - file: File, + file: Arc, aio: Aio, prop: BlockProperty, ) -> Result>>> { diff --git a/block_backend/src/qcow2/mod.rs b/block_backend/src/qcow2/mod.rs index 1b5a3dfb..c8296d21 100644 --- a/block_backend/src/qcow2/mod.rs +++ b/block_backend/src/qcow2/mod.rs @@ -269,7 +269,7 @@ pub fn qcow2_flush_metadata( } impl Qcow2Driver { - pub fn new(file: File, aio: Aio, conf: BlockProperty) -> Result { + pub fn new(file: Arc, aio: Aio, conf: BlockProperty) -> Result { let fd = file.as_raw_fd(); let sync_aio = Rc::new(RefCell::new(SyncAioInfo::new(fd, conf.clone())?)); Ok(Self { @@ -1614,19 +1614,25 @@ impl BlockDriverOps for Qcow2Driver { // Write zero. for i in 0..3 { let offset = i * cluster_size; - self.driver.file.seek(SeekFrom::Start(offset))?; - self.driver.file.write_all(&zero_buf.to_vec())? + self.driver.file.as_ref().seek(SeekFrom::Start(offset))?; + self.driver.file.as_ref().write_all(&zero_buf.to_vec())? } - self.driver.file.rewind()?; - self.driver.file.write_all(&self.header.to_vec())?; + self.driver.file.as_ref().rewind()?; + self.driver.file.as_ref().write_all(&self.header.to_vec())?; // Refcount table. - self.driver.file.seek(SeekFrom::Start(cluster_size))?; - self.driver.file.write_all(&rc_table)?; + self.driver + .file + .as_ref() + .seek(SeekFrom::Start(cluster_size))?; + self.driver.file.as_ref().write_all(&rc_table)?; // Refcount block table. - self.driver.file.seek(SeekFrom::Start(cluster_size * 2))?; - self.driver.file.write_all(&rc_block)?; + self.driver + .file + .as_ref() + .seek(SeekFrom::Start(cluster_size * 2))?; + self.driver.file.as_ref().write_all(&rc_block)?; // Create qcow2 driver. self.load_refcount_table()?; @@ -2015,11 +2021,13 @@ mod test { } fn create_qcow2_driver(&self, conf: BlockProperty) -> Qcow2Driver<()> { - let file = std::fs::OpenOptions::new() - .read(true) - .write(true) - .open(&self.path) - .unwrap(); + let file = Arc::new( + std::fs::OpenOptions::new() + .read(true) + .write(true) + .open(&self.path) + .unwrap(), + ); let aio = Aio::new( Arc::new(SyncAioInfo::complete_func), util::aio::AioEngine::Off, @@ -2090,11 +2098,13 @@ mod test { pub fn create_qcow2(path: &str) -> (TestImage, Qcow2Driver<()>) { let mut image = TestImage::new(path, 30, 16); - let file = std::fs::OpenOptions::new() - .read(true) - .write(true) - .open(path) - .unwrap(); + let file = Arc::new( + std::fs::OpenOptions::new() + .read(true) + .write(true) + .open(path) + .unwrap(), + ); let aio = Aio::new( Arc::new(SyncAioInfo::complete_func), util::aio::AioEngine::Off, diff --git a/block_backend/src/qcow2/refcount.rs b/block_backend/src/qcow2/refcount.rs index b58e3718..0318d7e9 100644 --- a/block_backend/src/qcow2/refcount.rs +++ b/block_backend/src/qcow2/refcount.rs @@ -791,8 +791,8 @@ mod test { path: &str, img_bits: u32, cluster_bits: u32, - ) -> (Qcow2Driver<()>, File) { - let file = image_create(path, img_bits, cluster_bits); + ) -> (Qcow2Driver<()>, Arc) { + let file = Arc::new(image_create(path, img_bits, cluster_bits)); let aio = Aio::new( Arc::new(SyncAioInfo::complete_func), util::aio::AioEngine::Off, @@ -811,10 +811,9 @@ mod test { l2_cache_size: None, refcount_cache_size: None, }; - let cloned_file = file.try_clone().unwrap(); - let mut qcow2_driver = Qcow2Driver::new(file, aio, conf.clone()).unwrap(); + let mut qcow2_driver = Qcow2Driver::new(file.clone(), aio, conf.clone()).unwrap(); qcow2_driver.load_metadata(conf).unwrap(); - (qcow2_driver, cloned_file) + (qcow2_driver, file) } #[test] @@ -835,6 +834,7 @@ mod test { // Check if the refcount of the cluster is updated to the disk. let mut rc_value = [0_u8; 2]; cloned_file + .as_ref() .read_at( &mut rc_value, cluster_sz * 2 + 2 * free_cluster_index as u64, @@ -873,6 +873,7 @@ mod test { let table_size = div_round_up(image_size, block_size * cluster_size).unwrap(); let mut refcount_table = vec![0_u8; table_size as usize * ENTRY_SIZE as usize]; assert!(cloned_file + .as_ref() .read_at(&mut refcount_table, table_offset) .is_ok()); for i in 0..table_size { @@ -928,9 +929,13 @@ mod test { let old_rct_size = cluster_sz as usize * rct_clusters as usize; let new_rct_size = cluster_sz as usize * new_rct_clusters as usize; let mut old_rc_table = vec![0_u8; old_rct_size]; - cloned_file.read_at(&mut old_rc_table, rct_offset).unwrap(); + cloned_file + .as_ref() + .read_at(&mut old_rc_table, rct_offset) + .unwrap(); let mut new_rc_table = vec![0_u8; new_rct_size]; cloned_file + .as_ref() .read_at(&mut new_rc_table, new_rct_offset as u64) .unwrap(); for i in 0..old_rct_size { diff --git a/block_backend/src/raw.rs b/block_backend/src/raw.rs index d8622d5a..056d0643 100644 --- a/block_backend/src/raw.rs +++ b/block_backend/src/raw.rs @@ -45,7 +45,7 @@ unsafe impl Send for RawDriver {} unsafe impl Sync for RawDriver {} impl RawDriver { - pub fn new(file: File, aio: Aio, prop: BlockProperty) -> Self { + pub fn new(file: Arc, aio: Aio, prop: BlockProperty) -> Self { Self { driver: FileDriver::new(file, aio, prop), status: Arc::new(Mutex::new(BlockStatus::Init)), diff --git a/devices/src/legacy/pflash.rs b/devices/src/legacy/pflash.rs index b2f8d616..db9929a3 100644 --- a/devices/src/legacy/pflash.rs +++ b/devices/src/legacy/pflash.rs @@ -65,14 +65,14 @@ pub struct PFlash { impl PFlash { fn flash_region_size( region_max_size: u64, - backend: &Option, + backend: &Option>, read_only: bool, ) -> Result { // We don't have to occupy the whole memory region. // If flash is read-only, expose just real data size, // rounded up to page_size if let Some(fd) = backend.as_ref() { - let len = fd.metadata().unwrap().len(); + let len = fd.as_ref().metadata().unwrap().len(); if len > region_max_size || len == 0 || (!read_only && len != region_max_size) { bail!( "Invalid flash file: Region size 0x{region_max_size:X}, file size 0x{len:X}; read_only {read_only}" @@ -104,7 +104,7 @@ impl PFlash { #[allow(clippy::too_many_arguments)] pub fn new( region_max_size: u64, - backend: Option, + backend: Option>, block_len: u32, bank_width: u32, device_width: u32, @@ -937,13 +937,13 @@ mod test { fd.set_len(flash_size).unwrap(); drop(fd); - let fd = Some( + let fd = Some(Arc::new( std::fs::OpenOptions::new() .read(true) .write(true) .open(file_name) .unwrap(), - ); + )); let sysbus = sysbus_init(); let pflash = PFlash::new( flash_size, fd, sector_len, 4, 2, read_only, &sysbus, flash_base, diff --git a/image/src/img.rs b/image/src/img.rs index d37b5f39..3d4738a4 100644 --- a/image/src/img.rs +++ b/image/src/img.rs @@ -40,7 +40,7 @@ enum SnapshotOperation { } pub struct ImageFile { - file: File, + file: Arc, path: String, } @@ -58,7 +58,7 @@ impl ImageFile { })?; Ok(Self { - file, + file: Arc::new(file), path: path.to_string(), }) } @@ -165,12 +165,14 @@ pub(crate) fn image_create(args: Vec) -> Result<()> { } let path = create_options.path.clone(); - let file = std::fs::OpenOptions::new() - .read(true) - .write(true) - .custom_flags(libc::O_CREAT | libc::O_TRUNC) - .mode(0o660) - .open(path)?; + let file = Arc::new( + std::fs::OpenOptions::new() + .read(true) + .write(true) + .custom_flags(libc::O_CREAT | libc::O_TRUNC) + .mode(0o660) + .open(path)?, + ); let aio = Aio::new(Arc::new(SyncAioInfo::complete_func), AioEngine::Off, None)?; let image_info = match disk_fmt { @@ -221,10 +223,9 @@ pub(crate) fn image_info(args: Vec) -> Result<()> { ..Default::default() }; let mut driver: Box> = match detect_fmt { - DiskFormat::Raw => Box::new(RawDriver::new(image_file.file.try_clone()?, aio, conf)), + DiskFormat::Raw => Box::new(RawDriver::new(image_file.file.clone(), aio, conf)), DiskFormat::Qcow2 => { - let mut qocw2_driver = - Qcow2Driver::new(image_file.file.try_clone()?, aio, conf.clone())?; + let mut qocw2_driver = Qcow2Driver::new(image_file.file.clone(), aio, conf.clone())?; qocw2_driver.load_metadata(conf)?; Box::new(qocw2_driver) } @@ -291,7 +292,7 @@ pub(crate) fn image_check(args: Vec) -> Result<()> { let real_fmt = image_file.check_img_format(disk_fmt, detect_fmt)?; let mut check_res = CheckResult::default(); - let file = image_file.file.try_clone()?; + let file = image_file.file.clone(); match real_fmt { DiskFormat::Raw => { bail!("stratovirt-img: This image format does not support checks"); @@ -347,10 +348,9 @@ pub(crate) fn image_resize(mut args: Vec) -> Result<()> { ..Default::default() }; let mut driver: Box> = match real_fmt { - DiskFormat::Raw => Box::new(RawDriver::new(image_file.file.try_clone()?, aio, conf)), + DiskFormat::Raw => Box::new(RawDriver::new(image_file.file.clone(), aio, conf)), DiskFormat::Qcow2 => { - let mut qocw2_driver = - Qcow2Driver::new(image_file.file.try_clone()?, aio, conf.clone())?; + let mut qocw2_driver = Qcow2Driver::new(image_file.file.clone(), aio, conf.clone())?; qocw2_driver.load_metadata(conf)?; Box::new(qocw2_driver) } @@ -457,7 +457,7 @@ pub(crate) fn image_snapshot(args: Vec) -> Result<()> { }; let aio = Aio::new(Arc::new(SyncAioInfo::complete_func), AioEngine::Off, None).unwrap(); - let mut qcow2_driver = Qcow2Driver::new(image_file.file.try_clone()?, aio, qcow2_conf.clone())?; + let mut qcow2_driver = Qcow2Driver::new(image_file.file.clone(), aio, qcow2_conf.clone())?; qcow2_driver.load_metadata(qcow2_conf)?; match snapshot_operation { @@ -482,7 +482,7 @@ pub(crate) fn image_snapshot(args: Vec) -> Result<()> { } pub(crate) fn create_qcow2_driver_for_check( - file: File, + file: Arc, conf: BlockProperty, ) -> Result> { let aio = Aio::new(Arc::new(SyncAioInfo::complete_func), AioEngine::Off, None).unwrap(); @@ -577,7 +577,7 @@ mod test { pub header: QcowHeader, pub cluster_bits: u64, pub path: String, - pub file: File, + pub file: Arc, } impl TestQcow2Image { @@ -606,7 +606,7 @@ mod test { header, cluster_bits, path: path.to_string(), - file, + file: Arc::new(file), } } @@ -616,14 +616,13 @@ mod test { ..Default::default() }; let aio = Aio::new(Arc::new(SyncAioInfo::complete_func), AioEngine::Off, None).unwrap(); - let mut qcow2_driver = - Qcow2Driver::new(self.file.try_clone().unwrap(), aio, conf.clone()).unwrap(); + let mut qcow2_driver = Qcow2Driver::new(self.file.clone(), aio, conf.clone()).unwrap(); qcow2_driver.load_metadata(conf).unwrap(); qcow2_driver } fn create_driver_for_check(&self) -> Qcow2Driver<()> { - let file = self.file.try_clone().unwrap(); + let file = self.file.clone(); let conf = BlockProperty { format: DiskFormat::Qcow2, ..Default::default() @@ -669,7 +668,7 @@ mod test { } fn file_len(&mut self) -> u64 { - let file_len = self.file.seek(SeekFrom::End(0)).unwrap(); + let file_len = self.file.as_ref().seek(SeekFrom::End(0)).unwrap(); file_len } @@ -706,12 +705,12 @@ mod test { } fn create_driver(&mut self) -> RawDriver<()> { - let mut conf = BlockProperty::default(); + let conf = BlockProperty::default(); let aio = Aio::new(Arc::new(SyncAioInfo::complete_func), AioEngine::Off, None).unwrap(); let file = open_file(&self.path, false, false).unwrap(); - let raw_driver = RawDriver::new(file, aio, conf); + let raw_driver = RawDriver::new(Arc::new(file), aio, conf); raw_driver } } diff --git a/machine/src/lib.rs b/machine/src/lib.rs index ecb96e2c..6b9a80a6 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -1983,7 +1983,7 @@ pub trait MachineOps: MachineLifecycle { } /// Fetch a cloned file from drive backend files. - fn fetch_drive_file(&self, path: &str) -> Result { + fn fetch_drive_file(&self, path: &str) -> Result> { let files = self.get_drive_files(); let drive_files = files.lock().unwrap(); VmConfig::fetch_drive_file(&drive_files, path) diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index e8ddab4f..60944fb9 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -1653,13 +1653,13 @@ impl DeviceInterface for StdMachine { let mut fd = None; if args.region_type.eq("rom_device_region") || args.region_type.eq("ram_device_region") { if let Some(file_name) = args.device_fd_path { - fd = Some( + fd = Some(Arc::new( std::fs::OpenOptions::new() .read(true) .write(true) .open(file_name) .unwrap(), - ); + )); } } diff --git a/machine/src/x86_64/standard.rs b/machine/src/x86_64/standard.rs index e61d5589..3a116911 100644 --- a/machine/src/x86_64/standard.rs +++ b/machine/src/x86_64/standard.rs @@ -575,8 +575,8 @@ impl MachineOps for StdMachine { // of current PFlash device. let mut flash_end: u64 = MEM_LAYOUT[LayoutEntryType::MemAbove4g as usize].0; for config in configs_vec { - let mut fd = self.fetch_drive_file(&config.path_on_host)?; - let pfl_size = fd.metadata().unwrap().len(); + let file = self.fetch_drive_file(&config.path_on_host)?; + let pfl_size = file.as_ref().metadata()?.len(); if config.unit.unwrap() == 0 { // According to the Linux/x86 boot protocol, the memory region of @@ -584,7 +584,7 @@ impl MachineOps for StdMachine { // KiB is for BIOS code which is stored in the first PFlash. let rom_base = 0xe0000; let rom_size = 0x20000; - fd.seek(SeekFrom::Start(pfl_size - rom_size))?; + file.as_ref().seek(SeekFrom::Start(pfl_size - rom_size))?; let ram1 = Arc::new(HostMemMapping::new( GuestAddress(rom_base), @@ -596,18 +596,18 @@ impl MachineOps for StdMachine { false, )?); let rom_region = Region::init_ram_region(ram1, "PflashRam"); - rom_region.write(&mut fd, GuestAddress(rom_base), 0, rom_size)?; + rom_region.write(&mut file.as_ref(), GuestAddress(rom_base), 0, rom_size)?; rom_region.set_priority(10); self.base .sys_mem .root() .add_subregion(rom_region, rom_base)?; - fd.rewind()? + file.as_ref().rewind()? } let sector_len: u32 = 1024 * 4; - let backend = Some(fd); + let backend = Some(file); let pflash = PFlash::new( pfl_size, backend, diff --git a/machine_manager/src/config/drive.rs b/machine_manager/src/config/drive.rs index e8e1a60c..a6f9fd75 100644 --- a/machine_manager/src/config/drive.rs +++ b/machine_manager/src/config/drive.rs @@ -14,6 +14,7 @@ use std::fs::{metadata, File}; use std::os::linux::fs::MetadataExt; use std::path::Path; use std::str::FromStr; +use std::sync::Arc; use anyhow::{anyhow, bail, Context, Result}; use clap::{ArgAction, Parser}; @@ -37,7 +38,7 @@ pub struct DriveFile { /// Drive id. pub id: String, /// The opened file. - pub file: File, + pub file: Arc, /// The num of drives share same file. pub count: u32, /// File path. diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index 3fbc5818..e172f7d5 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -64,6 +64,7 @@ use std::fs::{canonicalize, File}; use std::io::Read; use std::path::Path; use std::str::FromStr; +use std::sync::Arc; use anyhow::{anyhow, bail, Context, Result}; use clap::Parser; @@ -305,7 +306,7 @@ impl VmConfig { } let drive_file = DriveFile { id: id.to_string(), - file, + file: Arc::new(file), count: 1, read_only, path: path.to_string(), @@ -337,12 +338,12 @@ impl VmConfig { } /// Get a file from drive file store. - pub fn fetch_drive_file(drive_files: &HashMap, path: &str) -> Result { + pub fn fetch_drive_file( + drive_files: &HashMap, + path: &str, + ) -> Result> { match drive_files.get(path) { - Some(drive_file) => drive_file - .file - .try_clone() - .with_context(|| format!("Failed to clone drive backend file {}", path)), + Some(drive_file) => Ok(drive_file.file.clone()), None => Err(anyhow!("The file {} is not in drive backend", path)), } } -- Gitee From 37efbb4155eb0b05ca56a375e5d8b5a88a70d6a7 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Tue, 18 Jun 2024 05:26:40 +0800 Subject: [PATCH 156/489] address_space: optimize the process from gpa iovecs to hva iovecs Optimize the process from gpa iovecs to hva iovecs: 1) libc::iovec is pub struct iovec { pub iov_base: *mut ::c_void, pub iov_len: ::size_t, } and it equals to util::aio::Iovec pub struct Iovec { pub iov_base: u64, pub iov_len: u64, } On 64 bit platforms. At present, we are already mixing libc::iovec and util::aio::Iovec, So, just convert from GPA to HVA with unified util::aio::Iovec type. Use `gpa_hva_iovec_map` to do this. 2) add cache in parameters to improve performance and remove meaningless encapsulation functions. Signed-off-by: liuxiangdong --- virtio/src/device/block.rs | 5 ++--- virtio/src/device/gpu.rs | 6 +++--- virtio/src/device/net.rs | 17 +++++++++------- virtio/src/device/scsi_cntlr.rs | 9 ++++++--- virtio/src/device/serial.rs | 3 ++- virtio/src/lib.rs | 36 --------------------------------- 6 files changed, 23 insertions(+), 53 deletions(-) diff --git a/virtio/src/device/block.rs b/virtio/src/device/block.rs index 26fa748f..a8515cd7 100644 --- a/virtio/src/device/block.rs +++ b/virtio/src/device/block.rs @@ -26,7 +26,7 @@ use log::{error, warn}; use vmm_sys_util::{epoll::EventSet, eventfd::EventFd}; use crate::{ - check_config_space_rw, gpa_hva_iovec_map_by_cache, iov_discard_back, iov_discard_front, + check_config_space_rw, gpa_hva_iovec_map, iov_discard_back, iov_discard_front, iov_to_buf_by_cache, read_config_default, report_virtio_error, virtio_has_feature, Element, Queue, VirtioBase, VirtioDevice, VirtioError, VirtioInterrupt, VirtioInterruptType, VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_RO, @@ -345,8 +345,7 @@ impl Request { } .with_context(|| "Empty data for block request")?; - let (data_len, iovec) = - gpa_hva_iovec_map_by_cache(data_iovec, &handler.mem_space, cache)?; + let (data_len, iovec) = gpa_hva_iovec_map(data_iovec, &handler.mem_space, cache)?; request.data_len = data_len; request.iovec = iovec; } diff --git a/virtio/src/device/gpu.rs b/virtio/src/device/gpu.rs index acd74d0a..3b38d2ad 100644 --- a/virtio/src/device/gpu.rs +++ b/virtio/src/device/gpu.rs @@ -432,8 +432,8 @@ impl VirtioGpuRequest { iov_discard_front(&mut elem.out_iovec, size_of::() as u64) .unwrap_or_default(); - let (out_len, out_iovec) = gpa_hva_iovec_map(data_iovec, mem_space)?; - let (in_len, in_iovec) = gpa_hva_iovec_map(&elem.in_iovec, mem_space)?; + let (out_len, out_iovec) = gpa_hva_iovec_map(data_iovec, mem_space, &None)?; + let (in_len, in_iovec) = gpa_hva_iovec_map(&elem.in_iovec, mem_space, &None)?; // Note: in_iov and out_iov total len is no more than 1<<32, and // out_iov is more than 1, so in_len and out_len will not overflow. @@ -1491,7 +1491,7 @@ impl GpuIoHandler { len: ent.length, }); } - match gpa_hva_iovec_map(&elemiovec, &self.mem_space) { + match gpa_hva_iovec_map(&elemiovec, &self.mem_space, &None) { Ok((_, iov)) => { res.iov = iov; self.response_nodata(VIRTIO_GPU_RESP_OK_NODATA, req) diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index 25abc345..79d5e0c2 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -24,10 +24,11 @@ use anyhow::{bail, Context, Result}; use byteorder::{ByteOrder, LittleEndian}; use log::{error, warn}; use once_cell::sync::Lazy; +use util::aio::Iovec; use vmm_sys_util::{epoll::EventSet, eventfd::EventFd}; use crate::{ - check_config_space_rw, get_libc_iovecs, iov_discard_front, iov_to_buf, mem_to_buf, + check_config_space_rw, gpa_hva_iovec_map, iov_discard_front, iov_to_buf, mem_to_buf, read_config_default, report_virtio_error, virtio_has_feature, ElemIovec, Element, Queue, VirtioBase, VirtioDevice, VirtioError, VirtioInterrupt, VirtioInterruptType, VirtioNetHdr, VIRTIO_F_RING_EVENT_IDX, VIRTIO_F_RING_INDIRECT_DESC, VIRTIO_F_VERSION_1, VIRTIO_NET_CTRL_MAC, @@ -718,7 +719,7 @@ struct NetIoHandler { } impl NetIoHandler { - fn read_from_tap(iovecs: &[libc::iovec], tap: &mut Tap) -> i32 { + fn read_from_tap(iovecs: &[Iovec], tap: &mut Tap) -> i32 { // SAFETY: the arguments of readv has been checked and is correct. let size = unsafe { libc::readv( @@ -773,7 +774,8 @@ impl NetIoHandler { } else if elem.in_iovec.is_empty() { bail!("The length of in iovec is 0"); } - let iovecs = get_libc_iovecs(&self.mem_space, queue.vring.get_cache(), &elem.in_iovec); + let (_, iovecs) = + gpa_hva_iovec_map(&elem.in_iovec, &self.mem_space, queue.vring.get_cache())?; if MigrationManager::is_active() { // FIXME: mark dirty page needs to be managed by `AddressSpace` crate. @@ -845,7 +847,7 @@ impl NetIoHandler { Ok(()) } - fn send_packets(&self, tap_fd: libc::c_int, iovecs: &[libc::iovec]) -> i8 { + fn send_packets(&self, tap_fd: libc::c_int, iovecs: &[Iovec]) -> i8 { loop { // SAFETY: the arguments of writev has been checked and is correct. let size = unsafe { @@ -885,7 +887,8 @@ impl NetIoHandler { bail!("The length of out iovec is 0"); } - let iovecs = get_libc_iovecs(&self.mem_space, queue.vring.get_cache(), &elem.out_iovec); + let (_, iovecs) = + gpa_hva_iovec_map(&elem.out_iovec, &self.mem_space, queue.vring.get_cache())?; let tap_fd = if let Some(tap) = self.tap.as_mut() { tap.as_raw_fd() as libc::c_int } else { @@ -1004,13 +1007,13 @@ impl NetIoHandler { } } -fn get_net_header(iovec: &[libc::iovec], buf: &mut [u8]) -> Result { +fn get_net_header(iovec: &[Iovec], buf: &mut [u8]) -> Result { let mut start: usize = 0; let mut end: usize = 0; for elem in iovec { end = start - .checked_add(elem.iov_len) + .checked_add(elem.iov_len as usize) .with_context(|| "Overflow when getting the net header")?; end = cmp::min(end, buf.len()); mem_to_buf(&mut buf[start..end], elem.iov_base as u64)?; diff --git a/virtio/src/device/scsi_cntlr.rs b/virtio/src/device/scsi_cntlr.rs index 26db5f13..3c77e41c 100644 --- a/virtio/src/device/scsi_cntlr.rs +++ b/virtio/src/device/scsi_cntlr.rs @@ -508,7 +508,7 @@ impl VirtioScsiReq let mut request = VirtioScsiRequest { mem_space: mem_space.clone(), - queue, + queue: queue.clone(), desc_index: elem.index, iovec: Vec::with_capacity(elem.desc_num as usize), data_len: 0, @@ -521,15 +521,18 @@ impl VirtioScsiReq resp, }; + let locked_queue = queue.lock().unwrap(); + let cache = locked_queue.vring.get_cache(); + // Get possible dataout buffer from virtqueue Element. let mut iovec = elem.out_iovec.clone(); let elemiov = iov_discard_front(&mut iovec, size_of::() as u64).unwrap_or_default(); - let (out_len, out_iovec) = gpa_hva_iovec_map(elemiov, mem_space)?; + let (out_len, out_iovec) = gpa_hva_iovec_map(elemiov, mem_space, cache)?; // Get possible dataout buffer from virtqueue Element. let mut iovec = elem.in_iovec.clone(); let elemiov = iov_discard_front(&mut iovec, size_of::() as u64).unwrap_or_default(); - let (in_len, in_iovec) = gpa_hva_iovec_map(elemiov, mem_space)?; + let (in_len, in_iovec) = gpa_hva_iovec_map(elemiov, mem_space, cache)?; if out_len > 0 && in_len > 0 { warn!("Wrong scsi request! Don't support both datain and dataout buffer"); diff --git a/virtio/src/device/serial.rs b/virtio/src/device/serial.rs index 73aa4ac6..9ad7b3a2 100644 --- a/virtio/src/device/serial.rs +++ b/virtio/src/device/serial.rs @@ -889,7 +889,8 @@ impl SerialControlHandler { return Ok(()); } - let (in_size, ctrl_vec) = gpa_hva_iovec_map(&elem.in_iovec, &self.mem_space)?; + let cache = queue_lock.vring.get_cache(); + let (in_size, ctrl_vec) = gpa_hva_iovec_map(&elem.in_iovec, &self.mem_space, cache)?; let len = size_of::() + extra.len(); if in_size < len as u64 { bail!( diff --git a/virtio/src/lib.rs b/virtio/src/lib.rs index 54bc5256..a3aa5023 100644 --- a/virtio/src/lib.rs +++ b/virtio/src/lib.rs @@ -850,13 +850,6 @@ pub fn iov_discard_back(iovec: &mut [ElemIovec], mut size: u64) -> Option<&mut [ fn gpa_hva_iovec_map( gpa_elemiovec: &[ElemIovec], mem_space: &AddressSpace, -) -> Result<(u64, Vec)> { - gpa_hva_iovec_map_by_cache(gpa_elemiovec, mem_space, &None) -} - -fn gpa_hva_iovec_map_by_cache( - gpa_elemiovec: &[ElemIovec], - mem_space: &AddressSpace, cache: &Option, ) -> Result<(u64, Vec)> { let mut iov_size = 0; @@ -870,35 +863,6 @@ fn gpa_hva_iovec_map_by_cache( Ok((iov_size, hva_iovec)) } -fn get_libc_iovecs( - mem_space: &Arc, - cache: &Option, - elem_iovecs: &[ElemIovec], -) -> Vec { - let mut iovecs = Vec::new(); - for elem_iov in elem_iovecs.iter() { - // elem_iov.addr has been checked in pop_avail(). - let mut len = elem_iov.len; - let mut start = elem_iov.addr; - loop { - let io_vec = mem_space - .get_host_address_from_cache(start, cache) - .map(|(hva, fr_len)| libc::iovec { - iov_base: hva as *mut libc::c_void, - iov_len: std::cmp::min(elem_iov.len, fr_len as u32) as libc::size_t, - }) - .unwrap(); - start = start.unchecked_add(io_vec.iov_len as u64); - len -= io_vec.iov_len as u32; - iovecs.push(io_vec); - if len == 0 { - break; - } - } - } - iovecs -} - pub fn virtio_register_sysbusdevops_type() -> Result<()> { register_sysbusdevops_type::() } -- Gitee From c3549584053994a68e53d0d958ed6a3cdfd49a88 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Tue, 18 Jun 2024 16:07:46 +0800 Subject: [PATCH 157/489] virtio: add `iov_read_object` function to obtain a specific type from iov We need to read some specific type objects from iov in virtio message. Add function `iov_read_object` to do this. Signed-off-by: liuxiangdong --- virtio/src/device/block.rs | 29 ++++++++---------------- virtio/src/device/gpu.rs | 18 +++++---------- virtio/src/device/net.rs | 2 +- virtio/src/device/scsi_cntlr.rs | 40 ++++++++------------------------- virtio/src/device/serial.rs | 23 ++++++++----------- virtio/src/lib.rs | 21 +++++++++++++---- 6 files changed, 51 insertions(+), 82 deletions(-) diff --git a/virtio/src/device/block.rs b/virtio/src/device/block.rs index a8515cd7..601b41d7 100644 --- a/virtio/src/device/block.rs +++ b/virtio/src/device/block.rs @@ -26,13 +26,13 @@ use log::{error, warn}; use vmm_sys_util::{epoll::EventSet, eventfd::EventFd}; use crate::{ - check_config_space_rw, gpa_hva_iovec_map, iov_discard_back, iov_discard_front, - iov_to_buf_by_cache, read_config_default, report_virtio_error, virtio_has_feature, Element, - Queue, VirtioBase, VirtioDevice, VirtioError, VirtioInterrupt, VirtioInterruptType, - VIRTIO_BLK_F_DISCARD, VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_RO, - VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_WRITE_ZEROES, VIRTIO_BLK_ID_BYTES, VIRTIO_BLK_S_IOERR, - VIRTIO_BLK_S_OK, VIRTIO_BLK_S_UNSUPP, VIRTIO_BLK_T_DISCARD, VIRTIO_BLK_T_FLUSH, - VIRTIO_BLK_T_GET_ID, VIRTIO_BLK_T_IN, VIRTIO_BLK_T_OUT, VIRTIO_BLK_T_WRITE_ZEROES, + check_config_space_rw, gpa_hva_iovec_map, iov_discard_back, iov_discard_front, iov_read_object, + read_config_default, report_virtio_error, virtio_has_feature, Element, Queue, VirtioBase, + VirtioDevice, VirtioError, VirtioInterrupt, VirtioInterruptType, VIRTIO_BLK_F_DISCARD, + VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_MQ, VIRTIO_BLK_F_RO, VIRTIO_BLK_F_SEG_MAX, + VIRTIO_BLK_F_WRITE_ZEROES, VIRTIO_BLK_ID_BYTES, VIRTIO_BLK_S_IOERR, VIRTIO_BLK_S_OK, + VIRTIO_BLK_S_UNSUPP, VIRTIO_BLK_T_DISCARD, VIRTIO_BLK_T_FLUSH, VIRTIO_BLK_T_GET_ID, + VIRTIO_BLK_T_IN, VIRTIO_BLK_T_OUT, VIRTIO_BLK_T_WRITE_ZEROES, VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP, VIRTIO_F_RING_EVENT_IDX, VIRTIO_F_RING_INDIRECT_DESC, VIRTIO_F_VERSION_1, VIRTIO_TYPE_BLOCK, }; @@ -286,19 +286,8 @@ impl Request { ); } - let mut out_header = RequestOutHeader::default(); - iov_to_buf_by_cache( - &handler.mem_space, - cache, - &elem.out_iovec, - out_header.as_mut_bytes(), - ) - .and_then(|size| { - if size < size_of::() { - bail!("Invalid out header for block request: length {}", size); - } - Ok(()) - })?; + let mut out_header = + iov_read_object::(&handler.mem_space, &elem.out_iovec, cache)?; out_header.request_type = LittleEndian::read_u32(out_header.request_type.as_bytes()); out_header.sector = LittleEndian::read_u64(out_header.sector.as_bytes()); diff --git a/virtio/src/device/gpu.rs b/virtio/src/device/gpu.rs index 3b38d2ad..d2c1078b 100644 --- a/virtio/src/device/gpu.rs +++ b/virtio/src/device/gpu.rs @@ -23,11 +23,11 @@ use log::{error, info, warn}; use vmm_sys_util::{epoll::EventSet, eventfd::EventFd}; use crate::{ - check_config_space_rw, gpa_hva_iovec_map, iov_discard_front, iov_to_buf, read_config_default, - ElemIovec, Element, Queue, VirtioBase, VirtioDevice, VirtioDeviceQuirk, VirtioError, - VirtioInterrupt, VirtioInterruptType, VIRTIO_F_RING_EVENT_IDX, VIRTIO_F_RING_INDIRECT_DESC, - VIRTIO_F_VERSION_1, VIRTIO_GPU_CMD_GET_DISPLAY_INFO, VIRTIO_GPU_CMD_GET_EDID, - VIRTIO_GPU_CMD_MOVE_CURSOR, VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING, + check_config_space_rw, gpa_hva_iovec_map, iov_discard_front, iov_read_object, + read_config_default, ElemIovec, Element, Queue, VirtioBase, VirtioDevice, VirtioDeviceQuirk, + VirtioError, VirtioInterrupt, VirtioInterruptType, VIRTIO_F_RING_EVENT_IDX, + VIRTIO_F_RING_INDIRECT_DESC, VIRTIO_F_VERSION_1, VIRTIO_GPU_CMD_GET_DISPLAY_INFO, + VIRTIO_GPU_CMD_GET_EDID, VIRTIO_GPU_CMD_MOVE_CURSOR, VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING, VIRTIO_GPU_CMD_RESOURCE_CREATE_2D, VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING, VIRTIO_GPU_CMD_RESOURCE_FLUSH, VIRTIO_GPU_CMD_RESOURCE_UNREF, VIRTIO_GPU_CMD_SET_SCANOUT, VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D, VIRTIO_GPU_CMD_UPDATE_CURSOR, VIRTIO_GPU_FLAG_FENCE, @@ -418,13 +418,7 @@ impl VirtioGpuRequest { ); } - let mut header = VirtioGpuCtrlHdr::default(); - iov_to_buf(mem_space, &elem.out_iovec, header.as_mut_bytes()).and_then(|size| { - if size < size_of::() { - bail!("Invalid header for gpu request: len {}.", size) - } - Ok(()) - })?; + let header = iov_read_object::(mem_space, &elem.out_iovec, &None)?; // Size of out_iovec is no less than size of VirtioGpuCtrlHdr, so // it is possible to get none back. diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index 79d5e0c2..fde5613e 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -466,7 +466,7 @@ fn get_buf_and_discard( iovec: &mut [ElemIovec], buf: &mut [u8], ) -> Result> { - iov_to_buf(mem_space, iovec, buf).and_then(|size| { + iov_to_buf(mem_space, &None, iovec, buf).and_then(|size| { if size < buf.len() { error!("Invalid length {}, expected length {}", size, buf.len()); bail!("Invalid length {}, expected length {}", size, buf.len()); diff --git a/virtio/src/device/scsi_cntlr.rs b/virtio/src/device/scsi_cntlr.rs index 3c77e41c..fa31c9b9 100644 --- a/virtio/src/device/scsi_cntlr.rs +++ b/virtio/src/device/scsi_cntlr.rs @@ -22,10 +22,10 @@ use log::{error, info, warn}; use vmm_sys_util::{epoll::EventSet, eventfd::EventFd}; use crate::{ - check_config_space_rw, gpa_hva_iovec_map, iov_discard_front, iov_to_buf, read_config_default, - report_virtio_error, Element, Queue, VirtioBase, VirtioDevice, VirtioError, VirtioInterrupt, - VirtioInterruptType, VIRTIO_F_RING_EVENT_IDX, VIRTIO_F_RING_INDIRECT_DESC, VIRTIO_F_VERSION_1, - VIRTIO_TYPE_SCSI, + check_config_space_rw, gpa_hva_iovec_map, iov_discard_front, iov_read_object, + read_config_default, report_virtio_error, Element, Queue, VirtioBase, VirtioDevice, + VirtioError, VirtioInterrupt, VirtioInterruptType, VIRTIO_F_RING_EVENT_IDX, + VIRTIO_F_RING_INDIRECT_DESC, VIRTIO_F_VERSION_1, VIRTIO_TYPE_SCSI, }; use address_space::{AddressSpace, GuestAddress}; use block_backend::BlockIoErrorCallback; @@ -479,32 +479,13 @@ impl VirtioScsiReq elem.desc_num ); } + let locked_queue = queue.lock().unwrap(); + let cache = locked_queue.vring.get_cache(); // Get request from virtqueue Element. - let mut req = T::default(); - iov_to_buf(mem_space, &elem.out_iovec, req.as_mut_bytes()).and_then(|size| { - if size < size_of::() { - bail!( - "Invalid length for request: get {}, expected {}", - size, - size_of::(), - ); - } - Ok(()) - })?; - + let req = iov_read_object::(mem_space, &elem.out_iovec, cache)?; // Get response from virtqueue Element. - let mut resp = U::default(); - iov_to_buf(mem_space, &elem.in_iovec, resp.as_mut_bytes()).and_then(|size| { - if size < size_of::() { - bail!( - "Invalid length for response: get {}, expected {}", - size, - size_of::(), - ); - } - Ok(()) - })?; + let resp = iov_read_object::(mem_space, &elem.in_iovec, cache)?; let mut request = VirtioScsiRequest { mem_space: mem_space.clone(), @@ -515,15 +496,12 @@ impl VirtioScsiReq mode: ScsiXferMode::ScsiXferNone, interrupt_cb, driver_features, - // Safety: in_iovec will not be empty since it has been checked after "iov_to_buf". + // Safety: in_iovec will not be empty since it has been checked after "iov_read_object". resp_addr: elem.in_iovec[0].addr, req, resp, }; - let locked_queue = queue.lock().unwrap(); - let cache = locked_queue.vring.get_cache(); - // Get possible dataout buffer from virtqueue Element. let mut iovec = elem.out_iovec.clone(); let elemiov = iov_discard_front(&mut iovec, size_of::() as u64).unwrap_or_default(); diff --git a/virtio/src/device/serial.rs b/virtio/src/device/serial.rs index 9ad7b3a2..f8a1e35f 100644 --- a/virtio/src/device/serial.rs +++ b/virtio/src/device/serial.rs @@ -25,8 +25,8 @@ use vmm_sys_util::epoll::EventSet; use vmm_sys_util::eventfd::EventFd; use crate::{ - gpa_hva_iovec_map, iov_to_buf, read_config_default, report_virtio_error, Element, Queue, - VirtioBase, VirtioDevice, VirtioError, VirtioInterrupt, VirtioInterruptType, + gpa_hva_iovec_map, iov_read_object, iov_to_buf, read_config_default, report_virtio_error, + Element, Queue, VirtioBase, VirtioDevice, VirtioError, VirtioInterrupt, VirtioInterruptType, VIRTIO_CONSOLE_F_MULTIPORT, VIRTIO_CONSOLE_F_SIZE, VIRTIO_F_VERSION_1, VIRTIO_TYPE_CONSOLE, }; use address_space::AddressSpace; @@ -476,7 +476,8 @@ impl SerialPortHandler { let iovec = elem.out_iovec; let iovec_size = Element::iovec_size(&iovec); let mut buf = vec![0u8; iovec_size as usize]; - let size = iov_to_buf(&self.mem_space, &iovec, &mut buf[..])? as u64; + let cache = queue_lock.vring.get_cache(); + let size = iov_to_buf(&self.mem_space, cache, &iovec, &mut buf[..])? as u64; let locked_port = port.lock().unwrap(); if locked_port.host_connected { @@ -739,17 +740,11 @@ impl SerialControlHandler { break; } - let mut req = VirtioConsoleControl::default(); - iov_to_buf(&self.mem_space, &elem.out_iovec, req.as_mut_bytes()).and_then(|size| { - if size < size_of::() { - bail!( - "Invalid length for request: get {}, expected {}", - size, - size_of::(), - ); - } - Ok(()) - })?; + let mut req = iov_read_object::( + &self.mem_space, + &elem.out_iovec, + queue_lock.vring.get_cache(), + )?; req.id = LittleEndian::read_u32(req.id.as_bytes()); req.event = LittleEndian::read_u16(req.event.as_bytes()); req.value = LittleEndian::read_u16(req.value.as_bytes()); diff --git a/virtio/src/lib.rs b/virtio/src/lib.rs index a3aa5023..4c3e8e87 100644 --- a/virtio/src/lib.rs +++ b/virtio/src/lib.rs @@ -49,6 +49,7 @@ pub use vhost::user as VhostUser; use std::cmp; use std::io::Write; +use std::mem::size_of; use std::os::unix::prelude::RawFd; use std::sync::atomic::{AtomicBool, AtomicU16, AtomicU32, AtomicU8, Ordering}; use std::sync::{Arc, Mutex}; @@ -63,6 +64,7 @@ use devices::sysbus::register_sysbusdevops_type; use machine_manager::config::ConfigCheck; use migration_derive::ByteCode; use util::aio::{mem_to_buf, Iovec}; +use util::byte_code::ByteCode; use util::num_ops::{read_u32, write_u32}; use util::AsAny; @@ -790,12 +792,23 @@ pub fn report_virtio_error( broken.store(true, Ordering::SeqCst); } -/// Read iovec to buf and return the read number of bytes. -pub fn iov_to_buf(mem_space: &AddressSpace, iovec: &[ElemIovec], buf: &mut [u8]) -> Result { - iov_to_buf_by_cache(mem_space, &None, iovec, buf) +/// Read object typed `T` from iovec. +pub fn iov_read_object( + mem_space: &Arc, + iovec: &[ElemIovec], + cache: &Option, +) -> Result { + let mut obj = T::default(); + let count = iov_to_buf(mem_space, cache, iovec, obj.as_mut_bytes())?; + let size = size_of::(); + if count < size { + bail!("Read length error: expected {}, read {}.", size, count); + } + Ok(obj) } -pub fn iov_to_buf_by_cache( +/// Read iovec to buf and return the read number of bytes. +pub fn iov_to_buf( mem_space: &AddressSpace, cache: &Option, iovec: &[ElemIovec], -- Gitee From d9d2159433bbbb122c0ef971ccb1cd9d48a81f33 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Wed, 19 Jun 2024 12:18:56 +0800 Subject: [PATCH 158/489] net: fix some clippy warnings fix some clippy warnings. Signed-off-by: liuxiangdong --- virtio/src/device/net.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index fde5613e..ccf5e6c4 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -781,7 +781,7 @@ impl NetIoHandler { // FIXME: mark dirty page needs to be managed by `AddressSpace` crate. for iov in iovecs.iter() { // Mark vmm dirty page manually if live migration is active. - MigrationManager::mark_dirty_log(iov.iov_base as u64, iov.iov_len as u64); + MigrationManager::mark_dirty_log(iov.iov_base, iov.iov_len); } } @@ -1016,7 +1016,7 @@ fn get_net_header(iovec: &[Iovec], buf: &mut [u8]) -> Result { .checked_add(elem.iov_len as usize) .with_context(|| "Overflow when getting the net header")?; end = cmp::min(end, buf.len()); - mem_to_buf(&mut buf[start..end], elem.iov_base as u64)?; + mem_to_buf(&mut buf[start..end], elem.iov_base)?; if end >= buf.len() { break; } -- Gitee From 5997a56be5f8706d725a5627b764a77e428ab48b Mon Sep 17 00:00:00 2001 From: yexiao Date: Thu, 13 Jun 2024 06:28:21 +0800 Subject: [PATCH 159/489] virtio-net: add configuration options for virtio-net By this configuration, the sending and receiving tasks will be execute on rx_iothread and tx_iothread separately, thereby improving the performance of virtio-net. the example is as follows: -object iothread,id=rx-iothread \ -object iothread,id=tx-iothread \ -device virtio-net-pci,netdev=net0,XXX,rx-iothread=rx-iothread,tx-iothread=tx-iothread \ -netdev tap,id=net0,ifname=VMEngineTap\ Signed-off-by: Xiao Ye --- machine/src/lib.rs | 3 ++- machine/src/micro_common/mod.rs | 6 ++++-- machine_manager/src/config/network.rs | 18 ++++++++++++++++++ virtio/src/device/net.rs | 12 ++++++++++++ 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 6b9a80a6..19d4ba6c 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -1257,8 +1257,9 @@ pub trait MachineOps: MachineLifecycle { cfg_args: &str, hotplug: bool, ) -> Result<()> { - let net_cfg = + let mut net_cfg = NetworkInterfaceConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + net_cfg.auto_iothread(); let netdev_cfg = vm_config .netdevs .remove(&net_cfg.netdev) diff --git a/machine/src/micro_common/mod.rs b/machine/src/micro_common/mod.rs index e7d08ae6..076af9c5 100644 --- a/machine/src/micro_common/mod.rs +++ b/machine/src/micro_common/mod.rs @@ -302,7 +302,7 @@ impl LightMachine { if cfg_any.downcast_ref::().is_none() { return Err(anyhow!(MachineError::DevTypeErr("net".to_string()))); } - let net_config = NetworkInterfaceConfig { + let mut net_config = NetworkInterfaceConfig { classtype: driver, id: id.clone(), netdev: args.chardev.with_context(|| "No chardev set")?, @@ -310,6 +310,7 @@ impl LightMachine { iothread: args.iothread, ..Default::default() }; + net_config.auto_iothread(); configs.push(Arc::new(net_config)); slot + MMIO_REPLACEABLE_BLK_NR } else if driver.contains("blk") { @@ -399,8 +400,9 @@ impl LightMachine { vm_config: &mut VmConfig, cfg_args: &str, ) -> Result<()> { - let net_cfg = + let mut net_cfg = NetworkInterfaceConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + net_cfg.auto_iothread(); check_arg_nonexist!( ("bus", net_cfg.bus), ("addr", net_cfg.addr), diff --git a/machine_manager/src/config/network.rs b/machine_manager/src/config/network.rs index c9e58976..9f203010 100644 --- a/machine_manager/src/config/network.rs +++ b/machine_manager/src/config/network.rs @@ -151,6 +151,10 @@ pub struct NetworkInterfaceConfig { pub mac: Option, #[arg(long)] pub iothread: Option, + #[arg(long)] + pub rx_iothread: Option, + #[arg(long)] + pub tx_iothread: Option, #[arg(long, default_value="off", value_parser = parse_bool, action = ArgAction::Append)] pub mq: bool, // All queues of a net device have the same queue size now. @@ -172,6 +176,8 @@ impl Default for NetworkInterfaceConfig { multifunction: None, mac: None, iothread: None, + rx_iothread: None, + tx_iothread: None, mq: false, queue_size: DEFAULT_VIRTQUEUE_SIZE, vectors: 0, @@ -179,6 +185,18 @@ impl Default for NetworkInterfaceConfig { } } +impl NetworkInterfaceConfig { + pub fn auto_iothread(&mut self) { + // If rx_iothread or tx_iothread is not configured, the default iothread will be used. + if self.rx_iothread.is_none() { + self.rx_iothread = self.iothread.clone(); + } + if self.tx_iothread.is_none() { + self.tx_iothread = self.iothread.clone(); + } + } +} + fn valid_network_queue_size(s: &str) -> Result { let size: u64 = s.parse()?; valid_virtqueue_size(size, DEFAULT_VIRTQUEUE_SIZE as u64, MAX_QUEUE_SIZE_NET)?; diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index ccf5e6c4..65adb952 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -1246,6 +1246,10 @@ pub struct Net { update_evts: Vec>, /// The information about control command. ctrl_info: Option>>, + /// The deactivate events for receiving. + rx_deactivate_evts: Vec, + /// The deactivate events for transporting. + tx_deactivate_evts: Vec, } impl Net { @@ -1699,6 +1703,14 @@ impl VirtioDevice for Net { self.net_cfg.iothread.as_ref(), &mut self.base.deactivate_evts, )?; + unregister_event_helper( + self.net_cfg.rx_iothread.as_ref(), + &mut self.rx_deactivate_evts, + )?; + unregister_event_helper( + self.net_cfg.tx_iothread.as_ref(), + &mut self.tx_deactivate_evts, + )?; self.update_evts.clear(); self.ctrl_info = None; Ok(()) -- Gitee From 989b0178c70ad2dcbff0957a99cb516cd724c32d Mon Sep 17 00:00:00 2001 From: yexiao Date: Thu, 13 Jun 2024 21:17:09 +0800 Subject: [PATCH 160/489] virtio-net: remove the tap_fd 1. Remove the tap_fd from NetIoHandler, as it is equal with Tap. 2. Move the function of send_packets adn read_from_tap to tap.rs, and rename the function of read_from_tap with receive_packets. Signed-off-by: Xiao Ye --- util/src/tap.rs | 64 ++++++++++++++++++++++++++-- virtio/src/device/net.rs | 91 +++++++--------------------------------- 2 files changed, 75 insertions(+), 80 deletions(-) diff --git a/util/src/tap.rs b/util/src/tap.rs index d59e20a2..1c8039cf 100644 --- a/util/src/tap.rs +++ b/util/src/tap.rs @@ -11,7 +11,7 @@ // See the Mulan PSL v2 for more details. use std::fs::{File, OpenOptions}; -use std::io::{Read, Result as IoResult, Write}; +use std::io::{ErrorKind, Read, Result as IoResult, Write}; use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; use std::sync::Arc; @@ -22,6 +22,8 @@ use nix::fcntl::{fcntl, FcntlArg, OFlag}; use vmm_sys_util::ioctl::{ioctl_with_mut_ref, ioctl_with_ref, ioctl_with_val}; use vmm_sys_util::{ioctl_ioc_nr, ioctl_ior_nr, ioctl_iow_nr}; +use crate::aio::Iovec; + const IFF_ATTACH_QUEUE: u16 = 0x0200; const IFF_DETACH_QUEUE: u16 = 0x0400; @@ -185,11 +187,67 @@ impl Tap { ret } - pub fn read(&mut self, buf: &mut [u8]) -> IoResult { + pub fn receive_packets(&self, iovecs: &[Iovec]) -> i32 { + // SAFETY: the arguments of readv has been checked and is correct. + let size = unsafe { + libc::readv( + self.as_raw_fd() as libc::c_int, + iovecs.as_ptr() as *const libc::iovec, + iovecs.len() as libc::c_int, + ) + } as i32; + if size < 0 { + let e = std::io::Error::last_os_error(); + if e.kind() == std::io::ErrorKind::WouldBlock { + return size; + } + + // If the backend tap device is removed, readv returns less than 0. + // At this time, the content in the tap needs to be cleaned up. + // Here, read is called to process, otherwise handle_rx may be triggered all the time. + let mut buf = [0; 1024]; + match self.read(&mut buf) { + Ok(cnt) => error!("Failed to call readv but tap read is ok: cnt {}", cnt), + Err(e) => { + // When the backend tap device is abnormally removed, read return EBADFD. + error!("Failed to read tap: {:?}", e); + } + } + error!("Failed to call readv for net handle_rx: {:?}", e); + } + + size + } + + pub fn send_packets(&self, iovecs: &[Iovec]) -> i8 { + loop { + // SAFETY: the arguments of writev has been checked and is correct. + let size = unsafe { + libc::writev( + self.as_raw_fd(), + iovecs.as_ptr() as *const libc::iovec, + iovecs.len() as libc::c_int, + ) + }; + if size < 0 { + let e = std::io::Error::last_os_error(); + match e.kind() { + ErrorKind::Interrupted => continue, + ErrorKind::WouldBlock => return -1_i8, + // Ignore other errors which can not be handled. + _ => error!("Failed to call writev for net handle_tx: {:?}", e), + } + } + break; + } + 0_i8 + } + + pub fn read(&self, buf: &mut [u8]) -> IoResult { self.file.as_ref().read(buf) } - pub fn write(&mut self, buf: &[u8]) -> IoResult { + pub fn write(&self, buf: &[u8]) -> IoResult { self.file.as_ref().write(buf) } diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index 65adb952..74a498f2 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -11,7 +11,6 @@ // See the Mulan PSL v2 for more details. use std::collections::HashMap; -use std::io::ErrorKind; use std::os::unix::io::{AsRawFd, RawFd}; use std::path::Path; use std::rc::Rc; @@ -706,7 +705,6 @@ struct NetIoHandler { rx: RxVirtio, tx: TxVirtio, tap: Option, - tap_fd: RawFd, mem_space: Arc, interrupt_cb: Arc, driver_features: u64, @@ -719,38 +717,6 @@ struct NetIoHandler { } impl NetIoHandler { - fn read_from_tap(iovecs: &[Iovec], tap: &mut Tap) -> i32 { - // SAFETY: the arguments of readv has been checked and is correct. - let size = unsafe { - libc::readv( - tap.as_raw_fd() as libc::c_int, - iovecs.as_ptr() as *const libc::iovec, - iovecs.len() as libc::c_int, - ) - } as i32; - if size < 0 { - let e = std::io::Error::last_os_error(); - if e.kind() == std::io::ErrorKind::WouldBlock { - return size; - } - - // If the backend tap device is removed, readv returns less than 0. - // At this time, the content in the tap needs to be cleaned up. - // Here, read is called to process, otherwise handle_rx may be triggered all the time. - let mut buf = [0; 1024]; - match tap.read(&mut buf) { - Ok(cnt) => error!("Failed to call readv but tap read is ok: cnt {}", cnt), - Err(e) => { - // When the backend tap device is abnormally removed, read return EBADFD. - error!("Failed to read tap: {:?}", e); - } - } - error!("Failed to call readv for net handle_rx: {:?}", e); - } - - size - } - fn handle_rx(&mut self) -> Result<()> { trace::virtio_receive_request("Net".to_string(), "to rx".to_string()); if self.tap.is_none() { @@ -786,7 +752,7 @@ impl NetIoHandler { } // Read the data from the tap device. - let size = NetIoHandler::read_from_tap(&iovecs, self.tap.as_mut().unwrap()); + let size = self.tap.as_ref().unwrap().receive_packets(&iovecs); if size < (NET_HDR_LENGTH + ETHERNET_HDR_LENGTH + VLAN_TAG_LENGTH) as i32 { queue.vring.push_back(); break; @@ -847,30 +813,6 @@ impl NetIoHandler { Ok(()) } - fn send_packets(&self, tap_fd: libc::c_int, iovecs: &[Iovec]) -> i8 { - loop { - // SAFETY: the arguments of writev has been checked and is correct. - let size = unsafe { - libc::writev( - tap_fd, - iovecs.as_ptr() as *const libc::iovec, - iovecs.len() as libc::c_int, - ) - }; - if size < 0 { - let e = std::io::Error::last_os_error(); - match e.kind() { - ErrorKind::Interrupted => continue, - ErrorKind::WouldBlock => return -1_i8, - // Ignore other errors which can not be handled. - _ => error!("Failed to call writev for net handle_tx: {:?}", e), - } - } - break; - } - 0_i8 - } - fn handle_tx(&mut self) -> Result<()> { trace::virtio_receive_request("Net".to_string(), "to tx".to_string()); let mut queue = self.tx.queue.lock().unwrap(); @@ -889,12 +831,7 @@ impl NetIoHandler { let (_, iovecs) = gpa_hva_iovec_map(&elem.out_iovec, &self.mem_space, queue.vring.get_cache())?; - let tap_fd = if let Some(tap) = self.tap.as_mut() { - tap.as_raw_fd() as libc::c_int - } else { - -1_i32 - }; - if tap_fd != -1 && self.send_packets(tap_fd, &iovecs) == -1 { + if self.tap.is_none() || self.tap.as_ref().unwrap().send_packets(&iovecs) == -1 { queue.vring.push_back(); queue .vring @@ -934,11 +871,15 @@ impl NetIoHandler { fn tap_fd_handler(net_io: &mut Self) -> Vec { let mut notifiers = Vec::new(); + if net_io.tap.is_none() { + return notifiers; + } + let tap_fd = net_io.tap.as_ref().unwrap().as_raw_fd(); if !net_io.is_listening && (net_io.rx.queue_avail || net_io.tx.tap_full) { notifiers.push(EventNotifier::new( NotifierOperation::Resume, - net_io.tap_fd, + tap_fd, None, EventSet::empty(), Vec::new(), @@ -968,7 +909,7 @@ impl NetIoHandler { notifiers.push(EventNotifier::new( tap_operation, - net_io.tap_fd, + tap_fd, None, tap_events, Vec::new(), @@ -978,6 +919,11 @@ impl NetIoHandler { fn update_evt_handler(net_io: &Arc>) -> Vec { let mut locked_net_io = net_io.lock().unwrap(); + let old_tap_fd = if locked_net_io.tap.is_some() { + locked_net_io.tap.as_ref().unwrap().as_raw_fd() + } else { + -1 + }; locked_net_io.tap = match locked_net_io.receiver.recv() { Ok(tap) => tap, Err(e) => { @@ -985,11 +931,6 @@ impl NetIoHandler { None } }; - let old_tap_fd = locked_net_io.tap_fd; - locked_net_io.tap_fd = -1; - if let Some(tap) = locked_net_io.tap.as_ref() { - locked_net_io.tap_fd = tap.as_raw_fd(); - } let mut notifiers_fds = vec![ locked_net_io.update_evt.as_raw_fd(), @@ -1607,11 +1548,10 @@ impl VirtioDevice for Net { } let update_evt = Arc::new(create_new_eventfd()?); - let mut handler = NetIoHandler { + let handler = NetIoHandler { rx: RxVirtio::new(rx_queue, rx_queue_evt), tx: TxVirtio::new(tx_queue, tx_queue_evt), tap: self.taps.as_ref().map(|t| t[index].clone()), - tap_fd: -1, mem_space: mem_space.clone(), interrupt_cb: interrupt_cb.clone(), driver_features, @@ -1622,9 +1562,6 @@ impl VirtioDevice for Net { ctrl_info: ctrl_info.clone(), queue_size: self.queue_size_max(), }; - if let Some(tap) = &handler.tap { - handler.tap_fd = tap.as_raw_fd(); - } let notifiers = EventNotifierHelper::internal_notifiers(Arc::new(Mutex::new(handler))); register_event_helper( -- Gitee From 2285ad083c6c455359c6108dbe7a808f0debebca Mon Sep 17 00:00:00 2001 From: yexiao Date: Thu, 13 Jun 2024 07:40:34 +0800 Subject: [PATCH 161/489] virtio-net: set virtio-net's handlers listened on different threads Set virtio-net's handlers listened on different threads: 1. iothread: update_evt_fd and CtrlVirtio queue. 2. rx_iothread: tap_fd and RxVirtio queue. 3. tx_iothread: TxVirtio queue. Signed-off-by: Xiao Ye --- virtio/src/device/net.rs | 501 +++++++++++++++++++++++---------------- 1 file changed, 302 insertions(+), 199 deletions(-) diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index 74a498f2..ef952304 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -16,7 +16,7 @@ use std::path::Path; use std::rc::Rc; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::mpsc::{channel, Receiver, Sender}; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, RwLock}; use std::{cmp, fs, mem}; use anyhow::{bail, Context, Result}; @@ -54,8 +54,8 @@ use migration_derive::{ByteCode, Desc}; use util::byte_code::ByteCode; use util::gen_base_func; use util::loop_context::{ - create_new_eventfd, gen_delete_notifiers, read_fd, EventNotifier, EventNotifierHelper, - NotifierCallback, NotifierOperation, + create_new_eventfd, read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, + NotifierOperation, }; use util::num_ops::str_to_num; use util::tap::{ @@ -669,57 +669,35 @@ impl EventNotifierHelper for NetCtrlHandler { } } -struct TxVirtio { - tap_full: bool, +struct RTxVirtio { queue: Arc>, queue_evt: Arc, } -impl TxVirtio { +impl RTxVirtio { fn new(queue: Arc>, queue_evt: Arc) -> Self { - TxVirtio { - tap_full: false, - queue, - queue_evt, - } + TxVirtio { queue, queue_evt } } } -struct RxVirtio { - queue_avail: bool, - queue: Arc>, - queue_evt: Arc, -} - -impl RxVirtio { - fn new(queue: Arc>, queue_evt: Arc) -> Self { - RxVirtio { - queue_avail: true, - queue, - queue_evt, - } - } -} +type RxVirtio = RTxVirtio; +type TxVirtio = RTxVirtio; -struct NetIoHandler { +struct NetIoQueue { rx: RxVirtio, tx: TxVirtio, - tap: Option, + ctrl_info: Arc>, mem_space: Arc, interrupt_cb: Arc, + listen_state: Arc>, driver_features: u64, - receiver: Receiver, - update_evt: Arc, - device_broken: Arc, - is_listening: bool, - ctrl_info: Arc>, queue_size: u16, } -impl NetIoHandler { - fn handle_rx(&mut self) -> Result<()> { +impl NetIoQueue { + fn handle_rx(&self, tap: &Arc>>) -> Result<()> { trace::virtio_receive_request("Net".to_string(), "to rx".to_string()); - if self.tap.is_none() { + if tap.read().unwrap().is_none() { return Ok(()); } @@ -735,7 +713,7 @@ impl NetIoHandler { .vring .suppress_queue_notify(&self.mem_space, self.driver_features, false) .with_context(|| "Failed to enable rx queue notify")?; - self.rx.queue_avail = false; + self.listen_state.lock().unwrap().set_queue_avail(false); break; } else if elem.in_iovec.is_empty() { bail!("The length of in iovec is 0"); @@ -752,7 +730,13 @@ impl NetIoHandler { } // Read the data from the tap device. - let size = self.tap.as_ref().unwrap().receive_packets(&iovecs); + let locked_tap = tap.read().unwrap(); + let size = if locked_tap.is_some() { + locked_tap.as_ref().unwrap().receive_packets(&iovecs) + } else { + -1 + }; + drop(locked_tap); if size < (NET_HDR_LENGTH + ETHERNET_HDR_LENGTH + VLAN_TAG_LENGTH) as i32 { queue.vring.push_back(); break; @@ -813,7 +797,7 @@ impl NetIoHandler { Ok(()) } - fn handle_tx(&mut self) -> Result<()> { + fn handle_tx(&self, tap: &Arc>>) -> Result<()> { trace::virtio_receive_request("Net".to_string(), "to tx".to_string()); let mut queue = self.tx.queue.lock().unwrap(); @@ -831,15 +815,17 @@ impl NetIoHandler { let (_, iovecs) = gpa_hva_iovec_map(&elem.out_iovec, &self.mem_space, queue.vring.get_cache())?; - if self.tap.is_none() || self.tap.as_ref().unwrap().send_packets(&iovecs) == -1 { + let locked_tap = tap.read().unwrap(); + if locked_tap.is_none() || locked_tap.as_ref().unwrap().send_packets(&iovecs) == -1 { queue.vring.push_back(); queue .vring .suppress_queue_notify(&self.mem_space, self.driver_features, true) .with_context(|| "Failed to suppress tx queue notify")?; - self.tx.tap_full = true; + self.listen_state.lock().unwrap().set_tap_full(true); break; } + drop(locked_tap); queue .vring @@ -868,32 +854,62 @@ impl NetIoHandler { Ok(()) } +} - fn tap_fd_handler(net_io: &mut Self) -> Vec { - let mut notifiers = Vec::new(); - if net_io.tap.is_none() { - return notifiers; +struct ListenState { + queue_avail: bool, + tap_full: bool, + is_listening: bool, + has_changed: bool, +} + +impl ListenState { + fn new() -> Self { + Self { + queue_avail: true, + tap_full: false, + is_listening: true, + has_changed: false, + } + } + + fn set_tap_full(&mut self, value: bool) { + if self.tap_full == value { + return; } - let tap_fd = net_io.tap.as_ref().unwrap().as_raw_fd(); + self.tap_full = value; + self.has_changed = true; + } + + fn set_queue_avail(&mut self, value: bool) { + if self.queue_avail == value { + return; + } + self.queue_avail = value; + self.has_changed = true; + } + + fn tap_fd_handler(&mut self, tap: &Tap) -> Vec { + let mut notifiers = Vec::new(); - if !net_io.is_listening && (net_io.rx.queue_avail || net_io.tx.tap_full) { + if !self.is_listening && (self.queue_avail || self.tap_full) { notifiers.push(EventNotifier::new( NotifierOperation::Resume, - tap_fd, + tap.as_raw_fd(), None, EventSet::empty(), Vec::new(), )); - net_io.is_listening = true; + self.is_listening = true; } - if !net_io.is_listening { + if !self.is_listening { return notifiers; } // NOTE: We want to poll for OUT event when the tap is full, and for IN event when the // virtio queue is available. - let tap_events = match (net_io.rx.queue_avail, net_io.tx.tap_full) { + let tap_events = match (self.queue_avail, self.tap_full) { (true, true) => EventSet::OUT | EventSet::IN | EventSet::EDGE_TRIGGERED, (false, true) => EventSet::OUT | EventSet::EDGE_TRIGGERED, (true, false) => EventSet::IN | EventSet::EDGE_TRIGGERED, @@ -901,7 +917,7 @@ impl NetIoHandler { }; let tap_operation = if tap_events.is_empty() { - net_io.is_listening = false; + self.is_listening = false; NotifierOperation::Park } else { NotifierOperation::Modify @@ -909,43 +925,13 @@ impl NetIoHandler { notifiers.push(EventNotifier::new( tap_operation, - tap_fd, + tap.as_raw_fd(), None, tap_events, Vec::new(), )); notifiers } - - fn update_evt_handler(net_io: &Arc>) -> Vec { - let mut locked_net_io = net_io.lock().unwrap(); - let old_tap_fd = if locked_net_io.tap.is_some() { - locked_net_io.tap.as_ref().unwrap().as_raw_fd() - } else { - -1 - }; - locked_net_io.tap = match locked_net_io.receiver.recv() { - Ok(tap) => tap, - Err(e) => { - error!("Failed to receive the tap {:?}", e); - None - } - }; - - let mut notifiers_fds = vec![ - locked_net_io.update_evt.as_raw_fd(), - locked_net_io.rx.queue_evt.as_raw_fd(), - locked_net_io.tx.queue_evt.as_raw_fd(), - ]; - if old_tap_fd != -1 { - notifiers_fds.push(old_tap_fd); - } - let mut notifiers = gen_delete_notifiers(¬ifiers_fds); - drop(locked_net_io); - - notifiers.append(&mut EventNotifierHelper::internal_notifiers(net_io.clone())); - notifiers - } } fn get_net_header(iovec: &[Iovec], buf: &mut [u8]) -> Result { @@ -979,175 +965,267 @@ fn build_event_notifier( EventNotifier::new(op, fd, None, event, handlers) } -impl EventNotifierHelper for NetIoHandler { - fn internal_notifiers(net_io: Arc>) -> Vec { - // Register event notifier for update_evt. - let locked_net_io = net_io.lock().unwrap(); - let cloned_net_io = net_io.clone(); +struct NetIoHandler { + /// The context name of iothread for tap and rx virtio queue. + /// Since we placed the handlers of RxVirtio, TxVirtio and tap_fd in different threads, + /// thread name is needed to change the monitoring status of tap_fd. + rx_iothread: Option, + /// Virtio queue used for net io. + net_queue: Arc, + /// The context of tap device. + tap: Arc>>, + /// Device is broken or not. + device_broken: Arc, + /// The receiver half of Rust's channel to recv tap information. + receiver: Receiver, + /// Eventfd for config space update. + update_evt: Arc, +} + +impl NetIoHandler { + fn update_evt_handler(&mut self) -> Result<()> { + let mut locked_tap = self.tap.write().unwrap(); + let old_tap_fd = if locked_tap.is_some() { + locked_tap.as_ref().unwrap().as_raw_fd() + } else { + -1 + }; + + *locked_tap = match self.receiver.recv() { + Ok(tap) => tap, + Err(e) => { + error!("Failed to receive the tap {:?}", e); + None + } + }; + drop(locked_tap); + + if old_tap_fd != -1 { + unregister_event_helper(self.rx_iothread.as_ref(), &mut vec![old_tap_fd])?; + } + if self.tap.read().unwrap().is_some() { + EventLoop::update_event(self.tap_notifier(), self.rx_iothread.as_ref())?; + } + Ok(()) + } + + /// Register event notifier for update_evt. + fn update_evt_notifier(&self, net_io: Arc>) -> Vec { + let device_broken = self.device_broken.clone(); let handler: Rc = Rc::new(move |_, fd: RawFd| { read_fd(fd); - if cloned_net_io - .lock() - .unwrap() - .device_broken - .load(Ordering::SeqCst) - { + + if device_broken.load(Ordering::SeqCst) { return None; } - Some(NetIoHandler::update_evt_handler(&cloned_net_io)) + + if let Err(e) = net_io.lock().unwrap().update_evt_handler() { + error!("Update net events failed: {:?}", e); + } + + None }); - let mut notifiers = vec![build_event_notifier( - locked_net_io.update_evt.as_raw_fd(), + let notifiers = vec![build_event_notifier( + self.update_evt.as_raw_fd(), Some(handler), NotifierOperation::AddShared, EventSet::IN, )]; + notifiers + } - // Register event notifier for rx. - let cloned_net_io = net_io.clone(); + /// Register event notifier for rx. + fn rx_virtio_notifier(&self) -> Vec { + let net_queue = self.net_queue.clone(); + let device_broken = self.device_broken.clone(); + let tap = self.tap.clone(); + let rx_iothread = self.rx_iothread.as_ref().cloned(); let handler: Rc = Rc::new(move |_, fd: RawFd| { read_fd(fd); - let mut locked_net_io = cloned_net_io.lock().unwrap(); - if locked_net_io.device_broken.load(Ordering::SeqCst) { + + if device_broken.load(Ordering::SeqCst) { return None; } - locked_net_io.rx.queue_avail = true; - let mut locked_queue = locked_net_io.rx.queue.lock().unwrap(); + net_queue.listen_state.lock().unwrap().set_queue_avail(true); + let mut locked_queue = net_queue.rx.queue.lock().unwrap(); if let Err(ref err) = locked_queue.vring.suppress_queue_notify( - &locked_net_io.mem_space, - locked_net_io.driver_features, + &net_queue.mem_space, + net_queue.driver_features, true, ) { error!("Failed to suppress rx queue notify: {:?}", err); report_virtio_error( - locked_net_io.interrupt_cb.clone(), - locked_net_io.driver_features, - &locked_net_io.device_broken, + net_queue.interrupt_cb.clone(), + net_queue.driver_features, + &device_broken, ); return None; }; drop(locked_queue); - if let Err(ref err) = locked_net_io.handle_rx() { + if let Err(ref err) = net_queue.handle_rx(&tap) { error!("Failed to handle receive queue event: {:?}", err); report_virtio_error( - locked_net_io.interrupt_cb.clone(), - locked_net_io.driver_features, - &locked_net_io.device_broken, + net_queue.interrupt_cb.clone(), + net_queue.driver_features, + &device_broken, ); return None; } - if locked_net_io.tap.is_some() { - Some(NetIoHandler::tap_fd_handler(&mut locked_net_io)) - } else { - None + let mut locked_listen = net_queue.listen_state.lock().unwrap(); + let locked_tap = tap.read().unwrap(); + if locked_tap.is_none() || !locked_listen.has_changed { + return None; } + + let notifiers = locked_listen.tap_fd_handler(locked_tap.as_ref().unwrap()); + locked_listen.has_changed = false; + drop(locked_tap); + drop(locked_listen); + + if let Err(e) = EventLoop::update_event(notifiers, rx_iothread.as_ref()) { + error!("Update tap notifiers failed in handle rx: {:?}", e); + } + None }); - let rx_fd = locked_net_io.rx.queue_evt.as_raw_fd(); - notifiers.push(build_event_notifier( + let rx_fd = self.net_queue.rx.queue_evt.as_raw_fd(); + let notifiers = vec![build_event_notifier( rx_fd, Some(handler), NotifierOperation::AddShared, EventSet::IN, - )); + )]; + notifiers + } - // Register event notifier for tx. - let cloned_net_io = net_io.clone(); + /// Register event notifier for tx. + fn tx_virtio_notifier(&self) -> Vec { + let net_queue = self.net_queue.clone(); + let device_broken = self.device_broken.clone(); + let tap = self.tap.clone(); + let rx_iothread = self.rx_iothread.as_ref().cloned(); let handler: Rc = Rc::new(move |_, fd: RawFd| { read_fd(fd); - let mut locked_net_io = cloned_net_io.lock().unwrap(); - if locked_net_io.device_broken.load(Ordering::SeqCst) { + + if device_broken.load(Ordering::SeqCst) { return None; } - if let Err(ref e) = locked_net_io.handle_tx() { + if let Err(ref e) = net_queue.handle_tx(&tap) { error!("Failed to handle tx(tx event) for net, {:?}", e); report_virtio_error( - locked_net_io.interrupt_cb.clone(), - locked_net_io.driver_features, - &locked_net_io.device_broken, + net_queue.interrupt_cb.clone(), + net_queue.driver_features, + &device_broken, ); } - if locked_net_io.tap.is_some() { - Some(NetIoHandler::tap_fd_handler(&mut locked_net_io)) - } else { - None + let mut locked_listen = net_queue.listen_state.lock().unwrap(); + let locked_tap = tap.read().unwrap(); + if locked_tap.is_none() || !locked_listen.has_changed { + return None; } + + let notifiers = locked_listen.tap_fd_handler(locked_tap.as_ref().unwrap()); + locked_listen.has_changed = false; + drop(locked_tap); + drop(locked_listen); + + if let Err(e) = EventLoop::update_event(notifiers, rx_iothread.as_ref()) { + error!("Update tap notifiers failed in handle tx: {:?}", e); + } + + None }); - let tx_fd = locked_net_io.tx.queue_evt.as_raw_fd(); - notifiers.push(build_event_notifier( + let tx_fd = self.net_queue.tx.queue_evt.as_raw_fd(); + let notifiers = vec![build_event_notifier( tx_fd, Some(handler), NotifierOperation::AddShared, EventSet::IN, - )); + )]; + notifiers + } - // Register event notifier for tap. - let cloned_net_io = net_io.clone(); - if let Some(tap) = locked_net_io.tap.as_ref() { - let handler: Rc = Rc::new(move |events: EventSet, _| { - let mut locked_net_io = cloned_net_io.lock().unwrap(); - if locked_net_io.device_broken.load(Ordering::SeqCst) { + /// Register event notifier for tap. + fn tap_notifier(&self) -> Vec { + let tap = self.tap.clone(); + let net_queue = self.net_queue.clone(); + let device_broken = self.device_broken.clone(); + let locked_tap = self.tap.read().unwrap(); + if locked_tap.is_none() { + return vec![]; + } + let handler: Rc = Rc::new(move |events: EventSet, _| { + if device_broken.load(Ordering::SeqCst) { + return None; + } + + if events.contains(EventSet::OUT) { + net_queue.listen_state.lock().unwrap().set_tap_full(false); + let mut locked_queue = net_queue.tx.queue.lock().unwrap(); + + if let Err(ref err) = locked_queue.vring.suppress_queue_notify( + &net_queue.mem_space, + net_queue.driver_features, + false, + ) { + error!("Failed to enable tx queue notify: {:?}", err); + report_virtio_error( + net_queue.interrupt_cb.clone(), + net_queue.driver_features, + &device_broken, + ); return None; - } + }; - if events.contains(EventSet::OUT) { - locked_net_io.tx.tap_full = false; - let mut locked_queue = locked_net_io.tx.queue.lock().unwrap(); - - if let Err(ref err) = locked_queue.vring.suppress_queue_notify( - &locked_net_io.mem_space, - locked_net_io.driver_features, - false, - ) { - error!("Failed to enable tx queue notify: {:?}", err); - report_virtio_error( - locked_net_io.interrupt_cb.clone(), - locked_net_io.driver_features, - &locked_net_io.device_broken, - ); - return None; - }; - - drop(locked_queue); - - if let Err(ref e) = locked_net_io.handle_tx() { - error!("Failed to handle tx(tx event) for net, {:?}", e); - report_virtio_error( - locked_net_io.interrupt_cb.clone(), - locked_net_io.driver_features, - &locked_net_io.device_broken, - ); - } + drop(locked_queue); + + if let Err(ref e) = net_queue.handle_tx(&tap) { + error!("Failed to handle tx(tx event) for net, {:?}", e); + report_virtio_error( + net_queue.interrupt_cb.clone(), + net_queue.driver_features, + &device_broken, + ); } + } - if events.contains(EventSet::IN) { - if let Err(ref err) = locked_net_io.handle_rx() { - error!("Failed to handle receive queue event: {:?}", err); - report_virtio_error( - locked_net_io.interrupt_cb.clone(), - locked_net_io.driver_features, - &locked_net_io.device_broken, - ); - return None; - } + if events.contains(EventSet::IN) { + if let Err(ref err) = net_queue.handle_rx(&tap) { + error!("Failed to handle receive queue event: {:?}", err); + report_virtio_error( + net_queue.interrupt_cb.clone(), + net_queue.driver_features, + &device_broken, + ); + return None; } + } - Some(NetIoHandler::tap_fd_handler(&mut locked_net_io)) - }); - let tap_fd = tap.as_raw_fd(); - notifiers.push(build_event_notifier( - tap_fd, - Some(handler.clone()), - NotifierOperation::AddShared, - EventSet::OUT | EventSet::IN | EventSet::EDGE_TRIGGERED, - )); - } + let mut locked_listen = net_queue.listen_state.lock().unwrap(); + let locked_tap = tap.read().unwrap(); + if !locked_listen.has_changed || locked_tap.is_none() { + return None; + } + let tap_notifiers = locked_listen.tap_fd_handler(locked_tap.as_ref().unwrap()); + locked_listen.has_changed = false; + drop(locked_tap); + drop(locked_listen); + + Some(tap_notifiers) + }); + let tap_fd = locked_tap.as_ref().unwrap().as_raw_fd(); + let notifiers = vec![build_event_notifier( + tap_fd, + Some(handler), + NotifierOperation::AddShared, + EventSet::OUT | EventSet::IN | EventSet::EDGE_TRIGGERED, + )]; notifiers } @@ -1548,27 +1626,52 @@ impl VirtioDevice for Net { } let update_evt = Arc::new(create_new_eventfd()?); - let handler = NetIoHandler { + let net_queue = Arc::new(NetIoQueue { rx: RxVirtio::new(rx_queue, rx_queue_evt), tx: TxVirtio::new(tx_queue, tx_queue_evt), - tap: self.taps.as_ref().map(|t| t[index].clone()), + ctrl_info: ctrl_info.clone(), mem_space: mem_space.clone(), interrupt_cb: interrupt_cb.clone(), driver_features, + listen_state: Arc::new(Mutex::new(ListenState::new())), + queue_size: self.queue_size_max(), + }); + let tap = Arc::new(RwLock::new(self.taps.as_ref().map(|t| t[index].clone()))); + let net_io = Arc::new(Mutex::new(NetIoHandler { + rx_iothread: self.net_cfg.rx_iothread.as_ref().cloned(), + net_queue, + tap, + device_broken: self.base.broken.clone(), receiver, update_evt: update_evt.clone(), - device_broken: self.base.broken.clone(), - is_listening: true, - ctrl_info: ctrl_info.clone(), - queue_size: self.queue_size_max(), - }; - - let notifiers = EventNotifierHelper::internal_notifiers(Arc::new(Mutex::new(handler))); + })); + let cloned_net_io = net_io.clone(); + let locked_net_io = net_io.lock().unwrap(); + let update_evt_notifiers = locked_net_io.update_evt_notifier(cloned_net_io); + let rx_notifiers = locked_net_io.rx_virtio_notifier(); + let tx_notifiers = locked_net_io.tx_virtio_notifier(); + let tap_notifiers = locked_net_io.tap_notifier(); + drop(locked_net_io); register_event_helper( - notifiers, + update_evt_notifiers, self.net_cfg.iothread.as_ref(), &mut self.base.deactivate_evts, )?; + register_event_helper( + rx_notifiers, + self.net_cfg.rx_iothread.as_ref(), + &mut self.rx_deactivate_evts, + )?; + register_event_helper( + tap_notifiers, + self.net_cfg.rx_iothread.as_ref(), + &mut self.rx_deactivate_evts, + )?; + register_event_helper( + tx_notifiers, + self.net_cfg.tx_iothread.as_ref(), + &mut self.tx_deactivate_evts, + )?; self.update_evts.push(update_evt); } self.senders = Some(senders); -- Gitee From e2eacc5cdd28fb5670bd8e5b7ea6c68bad9234b0 Mon Sep 17 00:00:00 2001 From: yexiao Date: Thu, 13 Jun 2024 09:43:08 +0800 Subject: [PATCH 162/489] virtio-net: modif the config_guidebook for virtio-net Add the configuration of rx-iothread and tx-iothread for virtio-net in config_guidebook. Signed-off-by: Xiao Ye --- docs/config_guidebook.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/config_guidebook.md b/docs/config_guidebook.md index 97665ec7..a836f704 100644 --- a/docs/config_guidebook.md +++ b/docs/config_guidebook.md @@ -444,6 +444,8 @@ Eight properties are supported for virtio-net-device or virtio-net-pci. * id: unique net device id. * iothread: indicate which iothread will be used, if not specified the main thread will be used. It has no effect when vhost is set. +* rx-iothread: set the receiving task in this iothread, if not specified the former parameter iothread will be used. +* tx-iothread: set the sending task in this iothread, if not specified the former parameter iothread will be used. * netdev: netdev of net device. * vhost: whether to run as a vhost-net device. * vhostfd: the file descriptor of opened tap device. @@ -462,10 +464,10 @@ is a single function device, the function number should be set to zero. ```shell # virtio mmio net device -netdev tap,id=,ifname= --device virtio-net-device,id=,netdev=[,iothread=][,mac=] +-device virtio-net-device,id=,netdev=[,iothread=][,rx-iothread=][,tx-iothread=][,mac=] # virtio pci net device -netdev tap,id=,ifname=[,queues=] --device virtio-net-pci,id=,netdev=,bus=,addr=<0x2>[,multifunction={on|off}][,iothread=][,mac=][,mq={on|off}][,queue-size=] +-device virtio-net-pci,id=,netdev=,bus=,addr=<0x2>[,multifunction={on|off}][,iothread=][,rx-iothread=][,tx-iothread=][,mac=][,mq={on|off}][,queue-size=] ``` StratoVirt also supports vhost-net to get a higher performance in network. It can be set by -- Gitee From 194a00572d47a507c58000e7e4ec65ddf0f108d4 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Tue, 2 Jul 2024 11:03:25 +0800 Subject: [PATCH 163/489] ohaudio: fixup errors triggerred by audio server died This patch introduces a new enum to indicate ohaudio processor's current status. When the vm is paused/resumed or audio server was died, we should recreate audio context later. When audio server is died, on_error callback should be called. But currently audio server has bug so our on_error callback can't be called. So we have to check the duration since last on_write/read called. If the duration is larger than 1000ms, we can think there's error occurred in audio server. This patch also fixes HAP crash issue made by stratovirt. The reason is that stratovirt takes long time while Windows guest is capturing audio. So let's move pause notifier from scream to its backend ohaudio. This will avoid main loop waiting for long time to get scream interface lock. Signed-off-by: Zhao Yi Min --- devices/src/misc/scream/mod.rs | 16 +- devices/src/misc/scream/ohaudio.rs | 232 +++++++++++++++++++++-------- 2 files changed, 170 insertions(+), 78 deletions(-) diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index cf96e3ac..0c5be725 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -40,7 +40,6 @@ use super::ivshmem::Ivshmem; use crate::pci::{PciBus, PciDevOps}; use address_space::{GuestAddress, HostMemMapping, Region}; use machine_manager::config::{get_pci_df, parse_bool, valid_id}; -use machine_manager::notifier::register_vm_pause_notifier; #[cfg(all(target_env = "ohos", feature = "scream_ohaudio"))] use ohaudio::OhAudio; #[cfg(feature = "scream_pulseaudio")] @@ -434,7 +433,6 @@ pub struct Scream { config: ScreamConfig, token_id: Option>>, interface_resource: Vec>>, - notify_id: u64, } impl Scream { @@ -458,7 +456,6 @@ impl Scream { config, token_id, interface_resource: Vec::new(), - notify_id: 0, }) } @@ -555,17 +552,7 @@ impl Scream { ivshmem.realize()?; self.start_play_thread_fn()?; - self.start_record_thread_fn()?; - - let cloned_interfaces = self.interface_resource.clone(); - let pause_notify = Arc::new(move |paused: bool| { - for interface in cloned_interfaces.iter() { - interface.lock().unwrap().pause(paused); - } - }); - self.notify_id = register_vm_pause_notifier(pause_notify); - - Ok(()) + self.start_record_thread_fn() } } @@ -576,5 +563,4 @@ pub trait AudioInterface: Send { fn pre_receive(&mut self, start_addr: u64, sh_header: &ShmemStreamHeader) {} fn receive(&mut self, recv_data: &StreamData) -> i32; fn destroy(&mut self); - fn pause(&mut self, _paused: bool) {} } diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index 990648ef..9c960875 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -13,13 +13,17 @@ use std::os::raw::c_void; use std::sync::{ atomic::{fence, AtomicBool, AtomicI32, Ordering}, - Arc, Mutex, + Arc, Mutex, RwLock, +}; +use std::{ + cmp, ptr, thread, + time::{Duration, Instant}, }; -use std::{cmp, ptr, thread, time}; -use log::error; +use log::{error, warn}; use crate::misc::scream::{AudioInterface, ScreamDirection, ShmemStreamHeader, StreamData}; +use machine_manager::notifier::register_vm_pause_notifier; use util::ohos_binding::audio::*; trait OhAudioProcess { @@ -27,7 +31,6 @@ trait OhAudioProcess { fn destroy(&mut self); fn preprocess(&mut self, _start_addr: u64, _sh_header: &ShmemStreamHeader) {} fn process(&mut self, recv_data: &StreamData) -> i32; - fn pause(&mut self, paused: bool); } #[derive(Debug, Clone, Copy)] @@ -41,13 +44,27 @@ const FLUSH_DELAY_THRESHOLD_MS: u64 = 100; const FLUSH_DELAY_MS: u64 = 5; const FLUSH_DELAY_CNT: u64 = 200; +#[derive(Copy, Clone, Default, PartialEq, PartialOrd)] +enum OhAudioStatus { + // Processor is ready and waiting for play/capture. + #[default] + READY, + // Processor is started and doing job. + STARTED, + // Processor is paused. + PAUSED, + // OH audio framework error occurred. + ERROR, +} + struct OhAudioRender { ctx: Option, stream_data: Arc>>, data_size: AtomicI32, - start: bool, - pause: bool, flushing: AtomicBool, + status: Arc>, + last_called_time: Option, + pause_notifier_id: u64, } impl Default for OhAudioRender { @@ -56,9 +73,10 @@ impl Default for OhAudioRender { ctx: None, stream_data: Arc::new(Mutex::new(Vec::with_capacity(STREAM_DATA_VEC_CAPACITY))), data_size: AtomicI32::new(0), - start: false, - pause: false, flushing: AtomicBool::new(false), + status: Arc::new(RwLock::new(OhAudioStatus::default())), + last_called_time: None, + pause_notifier_id: 0, } } } @@ -80,14 +98,40 @@ impl OhAudioRender { self.flushing.store(true, Ordering::Release); let mut cnt = 0; while (cnt < FLUSH_DELAY_CNT) && (self.flushing.load(Ordering::Acquire)) { - thread::sleep(time::Duration::from_millis(FLUSH_DELAY_MS)); + thread::sleep(Duration::from_millis(FLUSH_DELAY_MS)); cnt += 1; } // We need to wait for 100ms to ensure the audio data has // been flushed before stop renderer. - thread::sleep(time::Duration::from_millis(FLUSH_DELAY_THRESHOLD_MS)); + thread::sleep(Duration::from_millis(FLUSH_DELAY_THRESHOLD_MS)); let _ = self.ctx.as_ref().unwrap().flush_renderer(); } + + #[inline(always)] + fn get_status(&self) -> OhAudioStatus { + *self.status.read().unwrap() + } + + #[inline(always)] + fn set_status(&self, status: OhAudioStatus) { + *self.status.write().unwrap() = status; + } + + fn register_pause_notifier(&mut self) { + let status = self.status.clone(); + let pause_notify = Arc::new(move |paused: bool| { + let s = *status.read().unwrap(); + if paused { + if s == OhAudioStatus::PAUSED { + return; + } + *status.write().unwrap() = OhAudioStatus::PAUSED; + } else { + *status.write().unwrap() = OhAudioStatus::ERROR; + } + }); + self.pause_notifier_id = register_vm_pause_notifier(pause_notify); + } } impl OhAudioProcess for OhAudioRender { @@ -110,47 +154,43 @@ impl OhAudioProcess for OhAudioRender { } match self.ctx.as_ref().unwrap().start() { Ok(()) => { - self.start = true; + self.set_status(OhAudioStatus::STARTED); trace::oh_scream_render_init(&self.ctx); } Err(e) => { error!("failed to start oh audio renderer: {}", e); } } - self.start - } - - fn pause(&mut self, paused: bool) { - self.pause = paused; - if paused { - self.destroy(); - } + self.last_called_time = None; + self.get_status() == OhAudioStatus::STARTED } fn destroy(&mut self) { - if self.ctx.is_some() { - if self.start { - if !self.pause { - self.flush(); - } - self.ctx.as_mut().unwrap().stop(); - self.start = false; + let status = self.get_status(); + + match status { + OhAudioStatus::PAUSED => return, + OhAudioStatus::ERROR => { + self.ctx = None; + self.set_status(OhAudioStatus::READY); + return; } - self.ctx = None; - } - if self.pause { - return; + OhAudioStatus::STARTED => self.flush(), + _ => {} } - let mut locked_data = self.stream_data.lock().unwrap(); - locked_data.clear(); + self.ctx = None; + self.stream_data.lock().unwrap().clear(); self.data_size.store(0, Ordering::Relaxed); + self.set_status(OhAudioStatus::READY); trace::oh_scream_render_destroy(); } fn process(&mut self, recv_data: &StreamData) -> i32 { - if self.pause { + let mut status = self.get_status(); + if status == OhAudioStatus::PAUSED { return 0; } + self.check_fmt_update(recv_data); fence(Ordering::Acquire); @@ -176,7 +216,13 @@ impl OhAudioProcess for OhAudioRender { .fetch_add(recv_data.audio_size as i32, Ordering::Relaxed); drop(locked_data); - if !self.start && !self.init(recv_data) { + if status == OhAudioStatus::ERROR { + error!("Audio server error occurred. Destroy and reconnect it."); + self.destroy(); + status = self.get_status(); + } + + if status == OhAudioStatus::READY && !self.init(recv_data) { error!("failed to init oh audio"); self.destroy(); } @@ -192,8 +238,9 @@ struct OhAudioCapture { shm_addr: u64, shm_len: u64, cur_pos: u64, - start: bool, - pause: bool, + status: Arc>, + last_called_time: Option, + pause_notifier_id: u64, } impl OhAudioCapture { @@ -208,6 +255,33 @@ impl OhAudioCapture { self.destroy(); } } + + #[inline(always)] + fn get_status(&self) -> OhAudioStatus { + *self.status.write().unwrap() + } + + #[inline(always)] + fn set_status(&self, status: OhAudioStatus) { + *self.status.write().unwrap() = status; + } + + fn register_pause_notifier(&mut self) { + let status = self.status.clone(); + let pause_notify = Arc::new(move |paused: bool| { + let s = *status.read().unwrap(); + if paused { + if s == OhAudioStatus::PAUSED { + return; + } + *status.write().unwrap() = OhAudioStatus::PAUSED; + } else { + // Set error status to recreate capture context. + *status.write().unwrap() = OhAudioStatus::ERROR; + } + }); + self.pause_notifier_id = register_vm_pause_notifier(pause_notify); + } } impl OhAudioProcess for OhAudioCapture { @@ -228,7 +302,8 @@ impl OhAudioProcess for OhAudioCapture { } match self.ctx.as_ref().unwrap().start() { Ok(()) => { - self.start = true; + self.last_called_time = None; + self.set_status(OhAudioStatus::STARTED); trace::oh_scream_capture_init(&self.ctx); true } @@ -239,20 +314,14 @@ impl OhAudioProcess for OhAudioCapture { } } - fn pause(&mut self, paused: bool) { - self.pause = paused; - if paused { - self.destroy(); - } - } - fn destroy(&mut self) { - if self.ctx.is_some() { - if self.start { - self.start = false; - self.ctx.as_mut().unwrap().stop(); + let status = self.get_status(); + match status { + OhAudioStatus::PAUSED => return, + _ => { + self.ctx = None; + self.set_status(OhAudioStatus::READY); } - self.ctx = None; } trace::oh_scream_capture_destroy(); } @@ -266,20 +335,30 @@ impl OhAudioProcess for OhAudioCapture { } fn process(&mut self, recv_data: &StreamData) -> i32 { - if self.pause { + let mut status = self.get_status(); + if status == OhAudioStatus::PAUSED { return -1; } self.check_fmt_update(recv_data); trace::trace_scope_start!(ohaudio_capturer_process, args = (recv_data)); - if !self.start && !self.init(recv_data) { + if status == OhAudioStatus::ERROR { + self.destroy(); + status = self.get_status(); + } + + if status == OhAudioStatus::READY && !self.init(recv_data) { self.destroy(); return -1; } self.new_chunks.store(0, Ordering::Release); while self.new_chunks.load(Ordering::Acquire) == 0 { - thread::sleep(time::Duration::from_millis(10)); + status = self.get_status(); + if status == OhAudioStatus::PAUSED || status == OhAudioStatus::ERROR { + return -1; + } + thread::sleep(Duration::from_millis(10)); } self.new_chunks.load(Ordering::Acquire) @@ -298,6 +377,20 @@ extern "C" fn on_write_data_cb( .as_mut() .unwrap_unchecked() }; + + match &render.last_called_time { + None => render.last_called_time = Some(Instant::now()), + Some(last) => { + let elapsed = last.elapsed().as_millis(); + if elapsed >= 1000 { + warn!("{elapsed}ms elapsed after last on_write called. Will restart render."); + render.set_status(OhAudioStatus::ERROR); + return 0; + } + render.last_called_time = Some(Instant::now()); + } + } + let data_size = render.data_size.load(Ordering::Relaxed); trace::trace_scope_start!(ohaudio_write_cb, args = (length, data_size)); @@ -358,10 +451,23 @@ extern "C" fn on_read_data_cb( .unwrap_unchecked() }; + match &capture.last_called_time { + None => capture.last_called_time = Some(Instant::now()), + Some(last) => { + let elapsed = last.elapsed().as_millis(); + if elapsed >= 1000 { + warn!("{elapsed}ms elapsed after last on_read called. Will restart capture."); + capture.set_status(OhAudioStatus::ERROR); + return 0; + } + capture.last_called_time = Some(Instant::now()); + } + } + trace::trace_scope_start!(ohaudio_read_cb, args = (length)); loop { - if !capture.start { + if capture.get_status() != OhAudioStatus::STARTED { return 0; } if capture.new_chunks.load(Ordering::Acquire) == 0 { @@ -411,12 +517,16 @@ unsafe impl Send for OhAudio {} impl OhAudio { pub fn init(dir: ScreamDirection) -> Self { match dir { - ScreamDirection::Playback => Self { - processor: Box::::default(), - }, - ScreamDirection::Record => Self { - processor: Box::::default(), - }, + ScreamDirection::Playback => { + let mut processor = Box::::default(); + processor.register_pause_notifier(); + Self { processor } + } + ScreamDirection::Record => { + let mut processor = Box::::default(); + processor.register_pause_notifier(); + Self { processor } + } } } } @@ -437,10 +547,6 @@ impl AudioInterface for OhAudio { fn destroy(&mut self) { self.processor.destroy(); } - - fn pause(&mut self, paused: bool) { - self.processor.pause(paused); - } } #[cfg(test)] -- Gitee From 111587fabf595bddc80d0d667ac97ea051459c71 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Tue, 2 Jul 2024 17:59:52 +0800 Subject: [PATCH 164/489] ohaudio: fixup clippy error Use the acronym lowercase to fixup clippy error. Signed-off-by: Zhao Yi Min --- devices/src/misc/scream/ohaudio.rs | 60 +++++++++++++++--------------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index 9c960875..fdc5f481 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -48,13 +48,13 @@ const FLUSH_DELAY_CNT: u64 = 200; enum OhAudioStatus { // Processor is ready and waiting for play/capture. #[default] - READY, + Ready, // Processor is started and doing job. - STARTED, + Started, // Processor is paused. - PAUSED, + Paused, // OH audio framework error occurred. - ERROR, + Error, } struct OhAudioRender { @@ -122,12 +122,12 @@ impl OhAudioRender { let pause_notify = Arc::new(move |paused: bool| { let s = *status.read().unwrap(); if paused { - if s == OhAudioStatus::PAUSED { + if s == OhAudioStatus::Paused { return; } - *status.write().unwrap() = OhAudioStatus::PAUSED; + *status.write().unwrap() = OhAudioStatus::Paused; } else { - *status.write().unwrap() = OhAudioStatus::ERROR; + *status.write().unwrap() = OhAudioStatus::Error; } }); self.pause_notifier_id = register_vm_pause_notifier(pause_notify); @@ -154,7 +154,7 @@ impl OhAudioProcess for OhAudioRender { } match self.ctx.as_ref().unwrap().start() { Ok(()) => { - self.set_status(OhAudioStatus::STARTED); + self.set_status(OhAudioStatus::Started); trace::oh_scream_render_init(&self.ctx); } Err(e) => { @@ -162,32 +162,32 @@ impl OhAudioProcess for OhAudioRender { } } self.last_called_time = None; - self.get_status() == OhAudioStatus::STARTED + self.get_status() == OhAudioStatus::Started } fn destroy(&mut self) { let status = self.get_status(); match status { - OhAudioStatus::PAUSED => return, - OhAudioStatus::ERROR => { + OhAudioStatus::Paused => return, + OhAudioStatus::Error => { self.ctx = None; - self.set_status(OhAudioStatus::READY); + self.set_status(OhAudioStatus::Ready); return; } - OhAudioStatus::STARTED => self.flush(), + OhAudioStatus::Started => self.flush(), _ => {} } self.ctx = None; self.stream_data.lock().unwrap().clear(); self.data_size.store(0, Ordering::Relaxed); - self.set_status(OhAudioStatus::READY); + self.set_status(OhAudioStatus::Ready); trace::oh_scream_render_destroy(); } fn process(&mut self, recv_data: &StreamData) -> i32 { let mut status = self.get_status(); - if status == OhAudioStatus::PAUSED { + if status == OhAudioStatus::Paused { return 0; } @@ -216,13 +216,13 @@ impl OhAudioProcess for OhAudioRender { .fetch_add(recv_data.audio_size as i32, Ordering::Relaxed); drop(locked_data); - if status == OhAudioStatus::ERROR { + if status == OhAudioStatus::Error { error!("Audio server error occurred. Destroy and reconnect it."); self.destroy(); status = self.get_status(); } - if status == OhAudioStatus::READY && !self.init(recv_data) { + if status == OhAudioStatus::Ready && !self.init(recv_data) { error!("failed to init oh audio"); self.destroy(); } @@ -271,13 +271,13 @@ impl OhAudioCapture { let pause_notify = Arc::new(move |paused: bool| { let s = *status.read().unwrap(); if paused { - if s == OhAudioStatus::PAUSED { + if s == OhAudioStatus::Paused { return; } - *status.write().unwrap() = OhAudioStatus::PAUSED; + *status.write().unwrap() = OhAudioStatus::Paused; } else { // Set error status to recreate capture context. - *status.write().unwrap() = OhAudioStatus::ERROR; + *status.write().unwrap() = OhAudioStatus::Error; } }); self.pause_notifier_id = register_vm_pause_notifier(pause_notify); @@ -303,7 +303,7 @@ impl OhAudioProcess for OhAudioCapture { match self.ctx.as_ref().unwrap().start() { Ok(()) => { self.last_called_time = None; - self.set_status(OhAudioStatus::STARTED); + self.set_status(OhAudioStatus::Started); trace::oh_scream_capture_init(&self.ctx); true } @@ -317,10 +317,10 @@ impl OhAudioProcess for OhAudioCapture { fn destroy(&mut self) { let status = self.get_status(); match status { - OhAudioStatus::PAUSED => return, + OhAudioStatus::Paused => return, _ => { self.ctx = None; - self.set_status(OhAudioStatus::READY); + self.set_status(OhAudioStatus::Ready); } } trace::oh_scream_capture_destroy(); @@ -336,26 +336,26 @@ impl OhAudioProcess for OhAudioCapture { fn process(&mut self, recv_data: &StreamData) -> i32 { let mut status = self.get_status(); - if status == OhAudioStatus::PAUSED { + if status == OhAudioStatus::Paused { return -1; } self.check_fmt_update(recv_data); trace::trace_scope_start!(ohaudio_capturer_process, args = (recv_data)); - if status == OhAudioStatus::ERROR { + if status == OhAudioStatus::Error { self.destroy(); status = self.get_status(); } - if status == OhAudioStatus::READY && !self.init(recv_data) { + if status == OhAudioStatus::Ready && !self.init(recv_data) { self.destroy(); return -1; } self.new_chunks.store(0, Ordering::Release); while self.new_chunks.load(Ordering::Acquire) == 0 { status = self.get_status(); - if status == OhAudioStatus::PAUSED || status == OhAudioStatus::ERROR { + if status == OhAudioStatus::Paused || status == OhAudioStatus::Error { return -1; } thread::sleep(Duration::from_millis(10)); @@ -384,7 +384,7 @@ extern "C" fn on_write_data_cb( let elapsed = last.elapsed().as_millis(); if elapsed >= 1000 { warn!("{elapsed}ms elapsed after last on_write called. Will restart render."); - render.set_status(OhAudioStatus::ERROR); + render.set_status(OhAudioStatus::Error); return 0; } render.last_called_time = Some(Instant::now()); @@ -457,7 +457,7 @@ extern "C" fn on_read_data_cb( let elapsed = last.elapsed().as_millis(); if elapsed >= 1000 { warn!("{elapsed}ms elapsed after last on_read called. Will restart capture."); - capture.set_status(OhAudioStatus::ERROR); + capture.set_status(OhAudioStatus::Error); return 0; } capture.last_called_time = Some(Instant::now()); @@ -467,7 +467,7 @@ extern "C" fn on_read_data_cb( trace::trace_scope_start!(ohaudio_read_cb, args = (length)); loop { - if capture.get_status() != OhAudioStatus::STARTED { + if capture.get_status() != OhAudioStatus::Started { return 0; } if capture.new_chunks.load(Ordering::Acquire) == 0 { -- Gitee From 009e1ab11a1ce99d38f0e4ed32e8efdeab8afc65 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Fri, 5 Jul 2024 12:00:31 +0800 Subject: [PATCH 165/489] ohaudio: optimize render logic Reimplement the render logic to make the code more clean and readable. Signed-off-by: Zhao Yi Min --- devices/src/misc/scream/ohaudio.rs | 232 +++++++++++++++++++---------- trace/trace_info/misc.toml | 4 +- 2 files changed, 158 insertions(+), 78 deletions(-) diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index fdc5f481..d15303ae 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -10,13 +10,16 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. +use std::collections::VecDeque; use std::os::raw::c_void; use std::sync::{ atomic::{fence, AtomicBool, AtomicI32, Ordering}, Arc, Mutex, RwLock, }; use std::{ - cmp, ptr, thread, + cmp, + io::Read, + ptr, thread, time::{Duration, Instant}, }; @@ -26,6 +29,10 @@ use crate::misc::scream::{AudioInterface, ScreamDirection, ShmemStreamHeader, St use machine_manager::notifier::register_vm_pause_notifier; use util::ohos_binding::audio::*; +const STREAM_DATA_VEC_CAPACITY: usize = 15; +const FLUSH_DELAY_MS: u64 = 5; +const FLUSH_DELAY_CNT: u64 = 200; + trait OhAudioProcess { fn init(&mut self, stream: &StreamData) -> bool; fn destroy(&mut self); @@ -35,14 +42,121 @@ trait OhAudioProcess { #[derive(Debug, Clone, Copy)] struct StreamUnit { - pub addr: u64, - pub len: u64, + addr: usize, + len: usize, } -const STREAM_DATA_VEC_CAPACITY: usize = 15; -const FLUSH_DELAY_THRESHOLD_MS: u64 = 100; -const FLUSH_DELAY_MS: u64 = 5; -const FLUSH_DELAY_CNT: u64 = 200; +impl Read for StreamUnit { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + let len = cmp::min(self.len, buf.len()); + // SAFETY: all the source data are in scream BAR. + unsafe { ptr::copy_nonoverlapping(self.addr as *const u8, buf.as_mut_ptr(), len) }; + self.len -= len; + self.addr += len; + Ok(len) + } +} + +impl StreamUnit { + #[inline] + fn is_empty(&self) -> bool { + self.len == 0 + } + + fn new(addr: usize, len: usize) -> Self { + Self { addr, len } + } + + #[inline] + fn len(&self) -> usize { + self.len + } +} + +struct StreamQueue { + queue: VecDeque, + data_size: usize, +} + +impl Read for StreamQueue { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + let len = buf.len(); + let mut ret = 0; + while ret < len { + if self.queue.len() == 0 { + break; + } + let unit = match self.queue.front_mut() { + Some(u) => u, + None => break, + }; + ret += unit.read(&mut buf[ret..len]).unwrap(); + self.data_size -= ret; + if unit.is_empty() { + self.pop_front(); + } + } + Ok(ret) + } + + // If there's no enough data, let's fill the whole buffer with 0. + fn read_exact(&mut self, buf: &mut [u8]) -> std::io::Result<()> { + let len = buf.len(); + match self.read(buf) { + Ok(ret) => { + if ret < len { + self.read_zero(&mut buf[ret..len]); + } + Ok(()) + } + Err(e) => Err(e), + } + } +} + +impl StreamQueue { + fn new(capacity: usize) -> Self { + Self { + queue: VecDeque::with_capacity(capacity), + data_size: 0, + } + } + + fn clear(&mut self) { + self.queue.clear(); + } + + #[inline] + fn data_size(&self) -> usize { + self.data_size + } + + fn pop_front(&mut self) { + if let Some(elem) = self.queue.pop_front() { + self.data_size -= elem.len(); + } + } + + fn push_back(&mut self, unit: StreamUnit) { + // When audio data is not consumed in time, this buffer + // might be full. So let's keep the max size by dropping + // the old data. This can guarantee sound playing can't + // be delayed too much and the buffer won't become too + // large. + if self.queue.len() == self.queue.capacity() { + self.pop_front(); + } + self.data_size += unit.len; + self.queue.push_back(unit); + } + + fn read_zero(&mut self, buf: &mut [u8]) { + // SAFETY: the buffer is guaranteed by the caller. + unsafe { + ptr::write_bytes(buf.as_mut_ptr(), 0, buf.len()); + } + } +} #[derive(Copy, Clone, Default, PartialEq, PartialOrd)] enum OhAudioStatus { @@ -59,8 +173,7 @@ enum OhAudioStatus { struct OhAudioRender { ctx: Option, - stream_data: Arc>>, - data_size: AtomicI32, + stream_data: Arc>, flushing: AtomicBool, status: Arc>, last_called_time: Option, @@ -71,8 +184,7 @@ impl Default for OhAudioRender { fn default() -> OhAudioRender { OhAudioRender { ctx: None, - stream_data: Arc::new(Mutex::new(Vec::with_capacity(STREAM_DATA_VEC_CAPACITY))), - data_size: AtomicI32::new(0), + stream_data: Arc::new(Mutex::new(StreamQueue::new(STREAM_DATA_VEC_CAPACITY))), flushing: AtomicBool::new(false), status: Arc::new(RwLock::new(OhAudioStatus::default())), last_called_time: None, @@ -95,18 +207,31 @@ impl OhAudioRender { } fn flush(&mut self) { - self.flushing.store(true, Ordering::Release); + self.set_flushing(true); let mut cnt = 0; - while (cnt < FLUSH_DELAY_CNT) && (self.flushing.load(Ordering::Acquire)) { + while cnt < FLUSH_DELAY_CNT { thread::sleep(Duration::from_millis(FLUSH_DELAY_MS)); cnt += 1; + if self.stream_data.lock().unwrap().data_size() == 0 { + break; + } } - // We need to wait for 100ms to ensure the audio data has - // been flushed before stop renderer. - thread::sleep(Duration::from_millis(FLUSH_DELAY_THRESHOLD_MS)); + } + + fn flush_renderer(&self) { let _ = self.ctx.as_ref().unwrap().flush_renderer(); } + #[inline(always)] + fn is_flushing(&self) -> bool { + self.flushing.load(Ordering::Acquire) + } + + #[inline(always)] + fn set_flushing(&mut self, flush: bool) { + self.flushing.store(flush, Ordering::Release); + } + #[inline(always)] fn get_status(&self) -> OhAudioStatus { *self.status.read().unwrap() @@ -180,7 +305,7 @@ impl OhAudioProcess for OhAudioRender { } self.ctx = None; self.stream_data.lock().unwrap().clear(); - self.data_size.store(0, Ordering::Relaxed); + self.set_flushing(false); self.set_status(OhAudioStatus::Ready); trace::oh_scream_render_destroy(); } @@ -197,24 +322,10 @@ impl OhAudioProcess for OhAudioRender { trace::trace_scope_start!(ohaudio_render_process, args = (recv_data)); - let su = StreamUnit { - addr: recv_data.audio_base, - len: recv_data.audio_size as u64, - }; - let mut locked_data = self.stream_data.lock().unwrap(); - // When audio data is not consumed in time, we remove old chunk - // and push new one. So audio-playing won't delay. One chunk means - // 20 ms data. - if locked_data.len() >= STREAM_DATA_VEC_CAPACITY { - let remove_size = locked_data[0].len; - locked_data.remove(0); - self.data_size - .fetch_sub(remove_size as i32, Ordering::Relaxed); - } - locked_data.push(su); - self.data_size - .fetch_add(recv_data.audio_size as i32, Ordering::Relaxed); - drop(locked_data); + self.stream_data.lock().unwrap().push_back(StreamUnit::new( + recv_data.audio_base as usize, + recv_data.audio_size as usize, + )); if status == OhAudioStatus::Error { error!("Audio server error occurred. Destroy and reconnect it."); @@ -391,49 +502,18 @@ extern "C" fn on_write_data_cb( } } - let data_size = render.data_size.load(Ordering::Relaxed); - - trace::trace_scope_start!(ohaudio_write_cb, args = (length, data_size)); - - if !render.flushing.load(Ordering::Acquire) && data_size < length { - // SAFETY: we checked len. - unsafe { ptr::write_bytes(buffer as *mut u8, 0, length as usize) }; - return 0; - } - - // Copy stream data from shared memory to buffer. - let mut dst_addr = buffer as u64; - let mut left = length as u64; - let mut su_list = render.stream_data.lock().unwrap(); - while left > 0 && su_list.len() > 0 { - let su = &mut su_list[0]; - let len = cmp::min(left, su.len); + let len = length as usize; + // SAFETY: the buffer is guaranteed by OH audio framework. + let wbuf = unsafe { std::slice::from_raw_parts_mut(buffer as *mut u8, len) }; - // SAFETY: we checked len. - unsafe { - ptr::copy_nonoverlapping(su.addr as *const u8, dst_addr as *mut u8, len as usize) - }; - trace::oh_scream_on_write_data_cb(len as usize); - - dst_addr += len; - left -= len; - su.len -= len; - if su.len == 0 { - su_list.remove(0); - } else { - su.addr += len; + trace::trace_scope_start!(ohaudio_write_cb, args = (len)); + match render.stream_data.lock().unwrap().read_exact(wbuf) { + Ok(()) => { + if render.is_flushing() { + render.flush_renderer(); + } } - } - render - .data_size - .fetch_sub(length - left as i32, Ordering::Relaxed); - - if left > 0 { - // SAFETY: we checked len. - unsafe { ptr::write_bytes(dst_addr as *mut u8, 0, left as usize) }; - } - if render.flushing.load(Ordering::Acquire) && su_list.is_empty() { - render.flushing.store(false, Ordering::Release); + Err(e) => error!("Failed to read stream data {:?}", e), } 0 } diff --git a/trace/trace_info/misc.toml b/trace/trace_info/misc.toml index 897a6bc0..0a2a2ac6 100644 --- a/trace/trace_info/misc.toml +++ b/trace/trace_info/misc.toml @@ -78,8 +78,8 @@ enabled = true [[scopes]] name = "ohaudio_write_cb" -args = "to_copy: i32, len: i32" -message = "OH audio expect audio data {} bytes, we have {} bytes" +args = "to_copy: i32" +message = "OH audio expect audio data {} bytes" enabled = true [[scopes]] -- Gitee From c0798490f70ef7ad798019b11b84ee15781c8c49 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Fri, 5 Jul 2024 18:50:04 +0800 Subject: [PATCH 166/489] ohaudio: fixup the caculation error Now data size is caculated wrong. Let's fixup it. Signed-off-by: Zhao Yi Min --- devices/src/misc/scream/ohaudio.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index d15303ae..8858dfda 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -90,8 +90,9 @@ impl Read for StreamQueue { Some(u) => u, None => break, }; - ret += unit.read(&mut buf[ret..len]).unwrap(); - self.data_size -= ret; + let rlen = unit.read(&mut buf[ret..len]).unwrap(); + ret += rlen; + self.data_size -= rlen; if unit.is_empty() { self.pop_front(); } -- Gitee From e3038c365a86d49fbf97719733ea7a3757018a28 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Mon, 8 Jul 2024 12:44:47 +0800 Subject: [PATCH 167/489] ohaudio: add OH trace back for audio write callback Add OH traces of event and scope back for audio write callback. Signed-off-by: Zhao Yi Min --- devices/src/misc/scream/ohaudio.rs | 1 + trace/trace_info/misc.toml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index 8858dfda..6e053965 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -507,6 +507,7 @@ extern "C" fn on_write_data_cb( // SAFETY: the buffer is guaranteed by OH audio framework. let wbuf = unsafe { std::slice::from_raw_parts_mut(buffer as *mut u8, len) }; + trace::oh_scream_on_write_data_cb(len); trace::trace_scope_start!(ohaudio_write_cb, args = (len)); match render.stream_data.lock().unwrap().read_exact(wbuf) { Ok(()) => { diff --git a/trace/trace_info/misc.toml b/trace/trace_info/misc.toml index 0a2a2ac6..28cf5132 100644 --- a/trace/trace_info/misc.toml +++ b/trace/trace_info/misc.toml @@ -78,7 +78,7 @@ enabled = true [[scopes]] name = "ohaudio_write_cb" -args = "to_copy: i32" +args = "to_copy: usize" message = "OH audio expect audio data {} bytes" enabled = true -- Gitee From 3770d49f1994f98fb22ce08cd7e25a88cbbb85df Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Mon, 8 Jul 2024 12:57:24 +0800 Subject: [PATCH 168/489] ohaudio: use is_empty() to make code clearer and more explicit Signed-off-by: Zhao Yi Min --- devices/src/misc/scream/ohaudio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index 6e053965..6fcee525 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -83,7 +83,7 @@ impl Read for StreamQueue { let len = buf.len(); let mut ret = 0; while ret < len { - if self.queue.len() == 0 { + if self.queue.is_empty() { break; } let unit = match self.queue.front_mut() { -- Gitee From 5b44acb9a82318b13ff68b2e28175b90dd384f7b Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Fri, 16 Feb 2024 11:46:40 +0300 Subject: [PATCH 169/489] usb: Start adding support for USB streams Add stream_id to kick_endpoint() and wakeup_endpoint() signatures. Default it to always be zero for now. Also add streamid to XhciTransfer structure. Signed-off-by: Stanislav Goriainov --- devices/src/usb/mod.rs | 9 +++++---- devices/src/usb/xhci/xhci_controller.rs | 18 ++++++++++++++---- devices/src/usb/xhci/xhci_regs.rs | 2 +- 3 files changed, 20 insertions(+), 9 deletions(-) diff --git a/devices/src/usb/mod.rs b/devices/src/usb/mod.rs index 44f5d88e..d8e2e3d8 100644 --- a/devices/src/usb/mod.rs +++ b/devices/src/usb/mod.rs @@ -482,7 +482,7 @@ pub fn notify_controller(dev: &Arc>) -> Result<()> { locked_xhci.port_notify(&usb_port, PORTSC_PLC)?; } } - if let Err(e) = locked_xhci.wakeup_endpoint(slot_id as u32, &ep) { + if let Err(e) = locked_xhci.wakeup_endpoint(slot_id as u32, &ep, 0) { error!("Failed to wakeup endpoint {:?}", e); } Ok(()) @@ -510,12 +510,12 @@ pub struct UsbPacket { pub actual_length: u32, /// Endpoint number. pub ep_number: u8, + /// Stream id. + pub stream: u32, /// Transfer for complete packet. pub xfer_ops: Option>>, /// Target USB device for this packet. pub target_dev: Option>>, - /// Stream id. - pub stream: u32, } impl std::fmt::Display for UsbPacket { @@ -533,6 +533,7 @@ impl UsbPacket { packet_id: u32, pid: u32, ep_number: u8, + stream: u32, iovecs: Vec, xfer_ops: Option>>, target_dev: Option>>, @@ -546,9 +547,9 @@ impl UsbPacket { status: UsbPacketStatus::Success, actual_length: 0, ep_number, + stream, xfer_ops, target_dev, - stream: 0, } } diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index a5887719..e914ce021 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -120,6 +120,7 @@ pub struct XhciTransfer { td: Vec, complete: bool, slotid: u32, + streamid: u32, epid: u32, in_xfer: bool, iso_xfer: bool, @@ -149,6 +150,7 @@ impl XhciTransfer { complete: false, slotid: ep_info.0, epid: ep_info.1, + streamid: 0, in_xfer, iso_xfer: false, timed_xfer: false, @@ -1195,6 +1197,7 @@ impl XhciDevice { packet_id, USB_TOKEN_OUT as u32, 0, + 0, Vec::new(), None, Some(target_dev), @@ -1558,7 +1561,7 @@ impl XhciDevice { } /// Data plane - pub(crate) fn kick_endpoint(&mut self, slot_id: u32, ep_id: u32) -> Result<()> { + pub(crate) fn kick_endpoint(&mut self, slot_id: u32, ep_id: u32, _stream_id: u32) -> Result<()> { let epctx = match self.get_endpoint_ctx(slot_id, ep_id) { Ok(epctx) => epctx, Err(e) => { @@ -1839,7 +1842,7 @@ impl XhciDevice { if ep_state == EP_STOPPED && ep_state == EP_ERROR { return; } - if let Err(e) = locked_xhci.kick_endpoint(slotid, epid) { + if let Err(e) = locked_xhci.kick_endpoint(slotid, epid, 0) { error!("Failed to kick endpoint: {:?}", e); } }); @@ -1954,11 +1957,13 @@ impl XhciDevice { let packet_id = self.generate_packet_id(); let (_, ep_number) = endpoint_id_to_number(locked_xfer.epid as u8); + let stream = locked_xfer.streamid; let xfer_ops = Arc::downgrade(xfer) as Weak>; let packet = UsbPacket::new( packet_id, dir as u32, ep_number, + stream, vec, Some(xfer_ops), target_dev, @@ -2068,7 +2073,12 @@ impl XhciDevice { } /// Used for device to wakeup endpoint - pub fn wakeup_endpoint(&mut self, slot_id: u32, ep: &UsbEndpoint) -> Result<()> { + pub fn wakeup_endpoint( + &mut self, + slot_id: u32, + ep: &UsbEndpoint, + _stream_id: u32, + ) -> Result<()> { let ep_id = endpoint_number_to_id(ep.in_direction, ep.ep_number); if let Err(e) = self.get_endpoint_ctx(slot_id, ep_id as u32) { trace::usb_xhci_unimplemented(&format!( @@ -2077,7 +2087,7 @@ impl XhciDevice { )); return Ok(()); } - self.kick_endpoint(slot_id, ep_id as u32)?; + self.kick_endpoint(slot_id, ep_id as u32, 0)?; Ok(()) } diff --git a/devices/src/usb/xhci/xhci_regs.rs b/devices/src/usb/xhci/xhci_regs.rs index 102b87f1..98796e2a 100644 --- a/devices/src/usb/xhci/xhci_regs.rs +++ b/devices/src/usb/xhci/xhci_regs.rs @@ -703,7 +703,7 @@ pub fn build_doorbell_ops(xhci_dev: &Arc>) -> RegionOps { return false; } else { let ep_id = value & DB_TARGET_MASK; - if let Err(e) = xhci.kick_endpoint(slot_id, ep_id) { + if let Err(e) = xhci.kick_endpoint(slot_id, ep_id, 0) { error!("Failed to kick endpoint: {:?}", e); xhci.host_controller_error(); return false; -- Gitee From 6917f33fc9fdd7bfd453399cd8f75ef1214fe6ad Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Fri, 16 Feb 2024 12:37:02 +0300 Subject: [PATCH 170/489] xhci: Add streams to doorbell ops Deduce stream id from doorbell value and pass it to kick_endpoint(). Signed-off-by: Stanislav Goriainov --- devices/src/usb/xhci/xhci_controller.rs | 4 ++-- devices/src/usb/xhci/xhci_regs.rs | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index e914ce021..87e13929 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -2077,7 +2077,7 @@ impl XhciDevice { &mut self, slot_id: u32, ep: &UsbEndpoint, - _stream_id: u32, + stream_id: u32, ) -> Result<()> { let ep_id = endpoint_number_to_id(ep.in_direction, ep.ep_number); if let Err(e) = self.get_endpoint_ctx(slot_id, ep_id as u32) { @@ -2087,7 +2087,7 @@ impl XhciDevice { )); return Ok(()); } - self.kick_endpoint(slot_id, ep_id as u32, 0)?; + self.kick_endpoint(slot_id, ep_id as u32, stream_id)?; Ok(()) } diff --git a/devices/src/usb/xhci/xhci_regs.rs b/devices/src/usb/xhci/xhci_regs.rs index 98796e2a..23c0b9a9 100644 --- a/devices/src/usb/xhci/xhci_regs.rs +++ b/devices/src/usb/xhci/xhci_regs.rs @@ -103,6 +103,9 @@ const XHCI_INTR_REG_SHIFT: u64 = 5; /// Doorbell Register Bit Field. /// DB Target. const DB_TARGET_MASK: u32 = 0xff; +/// DB Stream. +const DB_STREAM_ID_SHIFT: u32 = 16; +const DB_STREAM_ID_MASK: u32 = 0xffff; /// Port Registers. const XHCI_PORTSC: u64 = 0x0; const XHCI_PORTPMSC: u64 = 0x4; @@ -703,7 +706,8 @@ pub fn build_doorbell_ops(xhci_dev: &Arc>) -> RegionOps { return false; } else { let ep_id = value & DB_TARGET_MASK; - if let Err(e) = xhci.kick_endpoint(slot_id, ep_id, 0) { + let stream_id = (value >> DB_STREAM_ID_SHIFT) & DB_STREAM_ID_MASK; + if let Err(e) = xhci.kick_endpoint(slot_id, ep_id, stream_id) { error!("Failed to kick endpoint: {:?}", e); xhci.host_controller_error(); return false; -- Gitee From ac4ea7d126b6530e6576ee22cd540b9e4c713a08 Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Thu, 22 Feb 2024 18:19:47 +0300 Subject: [PATCH 171/489] xhci: Add structures and methods related to XHCI Streams Continue working on streams support. Add StreamContext related data structures, implement some useful methods. This patch doesn't influence the work of stratovirt since streams are still disabled in HCCPARAMS1. Signed-off-by: Stanislav Goriainov --- devices/src/usb/xhci/xhci_controller.rs | 155 +++++++++++++++++++++++- 1 file changed, 151 insertions(+), 4 deletions(-) diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index 87e13929..4bdf8404 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -64,6 +64,10 @@ const TRB_CR_DC: u32 = 1 << 9; const TRB_CR_SLOTID_SHIFT: u32 = 24; const TRB_CR_SLOTID_MASK: u32 = 0xff; const COMMAND_LIMIT: u32 = 256; +const EP_CTX_MAX_PSTREAMS_SHIFT: u32 = 10; +const EP_CTX_MAX_PSTREAMS_MASK: u32 = 0xf; +const EP_CTX_LSA_SHIFT: u32 = 15; +const EP_CTX_LSA_MASK: u32 = 0x01; const EP_CTX_INTERVAL_SHIFT: u32 = 16; const EP_CTX_INTERVAL_MASK: u32 = 0xff; const EVENT_TRB_CCODE_SHIFT: u32 = 24; @@ -110,6 +114,17 @@ const EP_CONTEXT_EP_TYPE_MASK: u32 = 0x7; const EP_CONTEXT_EP_TYPE_SHIFT: u32 = 3; const ISO_BASE_TIME_INTERVAL: u64 = 125000; const MFINDEX_WRAP_NUM: u64 = 0x4000; +/// Stream Context. +const STREAM_CTX_SCT_SHIFT: u32 = 1; +const STREAM_CTX_SCT_MASK: u32 = 0x7; +const _STREAM_CTX_SCT_SECONDARY_TR: u32 = 0; +const STREAM_CTX_SCT_PRIMARY_TR: u32 = 1; +const _STREAM_CTX_SCT_PRIMARY_SSA_8: u32 = 2; +const _STREAM_CTX_SCT_PRIMARY_SSA_16: u32 = 3; +const _STREAM_CTX_SCT_PRIMARY_SSA_32: u32 = 4; +const _STREAM_CTX_SCT_PRIMARY_SSA_64: u32 = 5; +const _STREAM_CTX_SCT_PRIMARY_SSA_128: u32 = 6; +const _STREAM_CTX_SCT_PRIMARY_SSA_256: u32 = 7; type DmaAddr = u64; @@ -286,6 +301,10 @@ pub struct XhciEpContext { mfindex_last: u64, transfers: LinkedList>>, retry: Option>>, + mem: Arc, + max_pstreams: u32, + lsa: bool, + stream_array: Option>, } impl XhciEpContext { @@ -302,17 +321,33 @@ impl XhciEpContext { mfindex_last: 0, transfers: LinkedList::new(), retry: None, + mem: Arc::clone(mem), + max_pstreams: 0, + lsa: false, + stream_array: None, } } /// Init the endpoint context used the context read from memory. - fn init_ctx(&mut self, output_ctx: DmaAddr, ctx: &XhciEpCtx) { + fn init_ctx(&mut self, output_ctx: DmaAddr, ctx: &XhciEpCtx) -> Result<()> { let dequeue: DmaAddr = addr64_from_u32(ctx.deq_lo & !0xf, ctx.deq_hi); self.ep_type = ((ctx.ep_info2 >> EP_TYPE_SHIFT) & EP_TYPE_MASK).into(); self.output_ctx_addr.store(output_ctx, Ordering::SeqCst); - self.ring.init(dequeue); - self.ring.set_cycle_bit((ctx.deq_lo & 1) == 1); + self.max_pstreams = (ctx.ep_info >> EP_CTX_MAX_PSTREAMS_SHIFT) & EP_CTX_MAX_PSTREAMS_MASK; + self.lsa = ((ctx.ep_info >> EP_CTX_LSA_SHIFT) & EP_CTX_LSA_MASK) != 0; self.interval = 1 << ((ctx.ep_info >> EP_CTX_INTERVAL_SHIFT) & EP_CTX_INTERVAL_MASK); + + if self.max_pstreams == 0 { + self.ring.init(dequeue); + self.ring.set_cycle_bit((ctx.deq_lo & 1) == 1); + } else { + let mut stream_array = + XhciStreamArray::new(&self.mem, &self.output_ctx_addr, self.max_pstreams); + stream_array.init(dequeue)?; + self.stream_array = Some(Arc::new(stream_array)); + } + + Ok(()) } fn get_ep_state(&self) -> u32 { @@ -354,6 +389,41 @@ impl XhciEpContext { } self.transfers = undo; } + + fn _get_stream_context(&self, stream_id: u32) -> Result<&XhciStreamContext> { + if self.stream_array.is_none() { + bail!("Endpoint {} does not support streams.", self.epid); + } + + if !self.lsa { + bail!("Only Linear Streams Array (LSA) is supported.") + } + + // SAFETY: Stream Array was checked to be not None. + let pstreams = &self.stream_array.as_ref().unwrap().0; + let pstreams_num = pstreams.len() as u32; + + if stream_id >= pstreams_num || stream_id == 0 { + bail!( + "Stream ID {} is either invalid or reserved, max number of streams is {}.", + stream_id, + pstreams_num + ); + } + + let stream_context = &pstreams[stream_id as usize]; + + if self.lsa && (stream_context.sct != STREAM_CTX_SCT_PRIMARY_TR) { + bail!( + "Invalid SCT {} on stream {}, LSA is {}", + stream_context.sct, + stream_id, + self.lsa + ); + } + + Ok(stream_context) + } } fn set_ep_state_helper( @@ -679,6 +749,83 @@ pub trait DwordOrder: Default + Copy + Send + Sync { } } +#[repr(transparent)] +pub struct XhciStreamArray(Vec); + +impl XhciStreamArray { + fn new(mem: &Arc, addr: &Arc, max_pstreams: u32) -> Self { + let pstreams_num = 1 << (max_pstreams + 1); + let pstreams = (0..pstreams_num) + .map(|_| XhciStreamContext::new(mem, addr)) + .collect(); + XhciStreamArray(pstreams) + } + + fn init(&mut self, mut dequeue: u64) -> Result<()> { + for stream_context in self.0.iter_mut() { + stream_context.init(dequeue)?; + dequeue += std::mem::size_of::() as u64; + } + + Ok(()) + } +} + +pub struct XhciStreamContext { + /// Memory address space. + mem: Arc, + /// Address of this Stream Context. + dequeue: AtomicU64, + /// Stream Context Type (SCT). + sct: u32, + /// Secondary Stream Array. + _secondary_streams: Option>, + /// Transfer Ring. + ring: Option>, +} + +impl XhciStreamContext { + fn new(mem: &Arc, addr: &Arc) -> Self { + // NOTE: No Secondary Stream Array support yet. + Self { + mem: Arc::clone(mem), + dequeue: AtomicU64::new(0), + sct: STREAM_CTX_SCT_PRIMARY_TR, + _secondary_streams: None, + ring: Some(Arc::new(XhciTransferRing::new(mem, addr))), + } + } + + fn init(&mut self, addr: u64) -> Result<()> { + let mut stream_ctx = XhciStreamCtx::default(); + dma_read_u32(&self.mem, GuestAddress(addr), stream_ctx.as_mut_dwords())?; + let dequeue = addr64_from_u32(stream_ctx.deq_lo & !0xf, stream_ctx.deq_hi); + self.set_dequeue_ptr(addr); + self.sct = (stream_ctx.deq_lo >> STREAM_CTX_SCT_SHIFT) & STREAM_CTX_SCT_MASK; + self.ring.as_ref().unwrap().init(dequeue); + Ok(()) + } + + pub fn get_dequeue_ptr(&self) -> u64 { + self.dequeue.load(Ordering::Acquire) + } + + pub fn set_dequeue_ptr(&self, addr: u64) { + self.dequeue.store(addr, Ordering::Release); + } +} + +#[repr(C, packed)] +#[derive(Debug, Default, Clone, Copy)] +pub struct XhciStreamCtx { + pub deq_lo: u32, + pub deq_hi: u32, + pub stopped_edtla: u32, + pub reserved: u32, +} + +impl DwordOrder for XhciStreamCtx {} + /// Xhci controller device. pub struct XhciDevice { pub numports_2: u8, @@ -1422,7 +1569,7 @@ impl XhciDevice { epctx.epid = ep_id; epctx.enabled = true; // It is safe to use plus here because we previously verify the address on the outer layer. - epctx.init_ctx(output_ctx + EP_CTX_OFFSET + entry_offset, &ep_ctx); + epctx.init_ctx(output_ctx + EP_CTX_OFFSET + entry_offset, &ep_ctx)?; epctx.set_ep_state(EP_RUNNING); ep_ctx.ep_info &= !EP_STATE_MASK; ep_ctx.ep_info |= EP_RUNNING; -- Gitee From e9ced338a9cc8f27481acb73e3daf3b1fdcf64a8 Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Tue, 27 Feb 2024 17:32:30 +0300 Subject: [PATCH 172/489] xhci: Add stream support for update_dequeue This patch doesn't break Stratovirt runtime as streams are disabled on XHCI Controller level. Alter update_dequeue function to be able to work with streams as well. Signed-off-by: Goriainov Stanislav --- devices/src/usb/xhci/xhci_controller.rs | 124 +++++++++++++++++------- devices/src/usb/xhci/xhci_ring.rs | 8 +- 2 files changed, 94 insertions(+), 38 deletions(-) diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index 4bdf8404..3774ed41 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -60,6 +60,8 @@ pub const SLOT_CONFIGURED: u32 = 3; const TRB_CR_BSR: u32 = 1 << 9; const TRB_CR_EPID_SHIFT: u32 = 16; const TRB_CR_EPID_MASK: u32 = 0x1f; +const TRB_CR_STREAMID_SHIFT: u32 = 16; +const TRB_CR_STREAMID_MASK: u32 = 0xffff; const TRB_CR_DC: u32 = 1 << 9; const TRB_CR_SLOTID_SHIFT: u32 = 24; const TRB_CR_SLOTID_MASK: u32 = 0xff; @@ -293,7 +295,7 @@ impl TransferOps for XhciTransfer { pub struct XhciEpContext { epid: u32, enabled: bool, - ring: Arc, + ring: Option>, ep_type: EpType, output_ctx_addr: Arc, state: Arc, @@ -309,13 +311,12 @@ pub struct XhciEpContext { impl XhciEpContext { pub fn new(mem: &Arc) -> Self { - let addr = Arc::new(AtomicU64::new(0)); Self { epid: 0, enabled: false, - ring: Arc::new(XhciTransferRing::new(mem, &addr)), + ring: None, ep_type: EpType::Invalid, - output_ctx_addr: addr, + output_ctx_addr: Arc::new(AtomicU64::new(0)), state: Arc::new(AtomicU32::new(0)), interval: 0, mfindex_last: 0, @@ -338,12 +339,16 @@ impl XhciEpContext { self.interval = 1 << ((ctx.ep_info >> EP_CTX_INTERVAL_SHIFT) & EP_CTX_INTERVAL_MASK); if self.max_pstreams == 0 { - self.ring.init(dequeue); - self.ring.set_cycle_bit((ctx.deq_lo & 1) == 1); + let ring = XhciTransferRing::new(&self.mem, &self.output_ctx_addr); + ring.init(dequeue); + ring.set_cycle_bit((ctx.deq_lo & 1) == 1); + self.ring = Some(Arc::new(ring)); } else { let mut stream_array = XhciStreamArray::new(&self.mem, &self.output_ctx_addr, self.max_pstreams); - stream_array.init(dequeue)?; + stream_array + .init(dequeue) + .with_context(|| "Failed to initialize Stream Array.")?; self.stream_array = Some(Arc::new(stream_array)); } @@ -360,22 +365,46 @@ impl XhciEpContext { /// Update the endpoint state and write the state to memory. fn set_state(&mut self, state: u32) -> Result<()> { - set_ep_state_helper(&self.ring, &self.state, state) + set_ep_state_helper(self.ring.as_ref().unwrap(), &self.state, state) } - /// Update the dequeue pointer in endpoint context. + /// Update the dequeue pointer in endpoint or stream context. /// If dequeue is None, only flush the dequeue pointer to memory. - fn update_dequeue(&mut self, mem: &Arc, dequeue: Option) -> Result<()> { - let mut ep_ctx = XhciEpCtx::default(); - let output_addr = self.output_ctx_addr.load(Ordering::Acquire); - dma_read_u32(mem, GuestAddress(output_addr), ep_ctx.as_mut_dwords())?; + fn update_dequeue( + &mut self, + mem: &Arc, + dequeue: Option, + stream_id: u32, + ) -> Result<()> { + let ring = self.get_ring(stream_id).with_context(|| { + format!( + "Failed to find Transfer Ring for Endpoint {}, Stream ID {}", + self.epid, stream_id + ) + })?; + if let Some(dequeue) = dequeue { - self.ring.init(dequeue & EP_CTX_TR_DEQUEUE_POINTER_MASK); - self.ring - .set_cycle_bit((dequeue & EP_CTX_DCS) == EP_CTX_DCS); + ring.init(dequeue & EP_CTX_TR_DEQUEUE_POINTER_MASK); + ring.set_cycle_bit((dequeue & EP_CTX_DCS) == EP_CTX_DCS); } - self.ring.update_dequeue_to_ctx(&mut ep_ctx); - dma_write_u32(mem, GuestAddress(output_addr), ep_ctx.as_dwords())?; + + if self.max_pstreams == 0 { + let mut ep_ctx = XhciEpCtx::default(); + let output_addr = self.output_ctx_addr.load(Ordering::Acquire); + dma_read_u32(mem, GuestAddress(output_addr), ep_ctx.as_mut_dwords())?; + ring.update_dequeue_to_ctx(&mut ep_ctx.as_mut_dwords()[2..]); + dma_write_u32(mem, GuestAddress(output_addr), ep_ctx.as_dwords())?; + } else { + let mut stream_ctx = XhciStreamCtx::default(); + let stream_context = self.get_stream(stream_id).with_context(|| { + format!("Failed to find Stream Context with Stream ID {}", stream_id) + })?; + let output_addr = stream_context.dequeue.load(Ordering::Acquire); + dma_read_u32(mem, GuestAddress(output_addr), stream_ctx.as_mut_dwords())?; + ring.update_dequeue_to_ctx(stream_ctx.as_mut_dwords()); + dma_write_u32(mem, GuestAddress(output_addr), stream_ctx.as_dwords())?; + } + Ok(()) } @@ -390,7 +419,7 @@ impl XhciEpContext { self.transfers = undo; } - fn _get_stream_context(&self, stream_id: u32) -> Result<&XhciStreamContext> { + fn get_stream(&self, stream_id: u32) -> Result<&XhciStreamContext> { if self.stream_array.is_none() { bail!("Endpoint {} does not support streams.", self.epid); } @@ -413,7 +442,7 @@ impl XhciEpContext { let stream_context = &pstreams[stream_id as usize]; - if self.lsa && (stream_context.sct != STREAM_CTX_SCT_PRIMARY_TR) { + if stream_context.sct != STREAM_CTX_SCT_PRIMARY_TR { bail!( "Invalid SCT {} on stream {}, LSA is {}", stream_context.sct, @@ -424,6 +453,18 @@ impl XhciEpContext { Ok(stream_context) } + + fn get_ring(&self, stream_id: u32) -> Result<&Arc> { + if self.max_pstreams == 0 { + Ok(self.ring.as_ref().unwrap()) + } else { + let stream_context = self.get_stream(stream_id).with_context(|| { + format!("Failed to find Stream Context with Stream ID {}", stream_id) + })?; + // SAFETY: Secondary Stream Arrays are not supported. + Ok(stream_context.ring.as_ref().unwrap()) + } + } } fn set_ep_state_helper( @@ -437,7 +478,7 @@ fn set_ep_state_helper( dma_read_u32(mem, GuestAddress(output_addr), ep_ctx.as_mut_dwords())?; ep_ctx.ep_info &= !EP_STATE_MASK; ep_ctx.ep_info |= state; - ring.update_dequeue_to_ctx(&mut ep_ctx); + ring.update_dequeue_to_ctx(&mut ep_ctx.as_mut_dwords()[2..]); dma_write_u32(mem, GuestAddress(output_addr), ep_ctx.as_dwords())?; ep_state.store(state, Ordering::SeqCst); Ok(()) @@ -800,9 +841,11 @@ impl XhciStreamContext { let mut stream_ctx = XhciStreamCtx::default(); dma_read_u32(&self.mem, GuestAddress(addr), stream_ctx.as_mut_dwords())?; let dequeue = addr64_from_u32(stream_ctx.deq_lo & !0xf, stream_ctx.deq_hi); + let ring = self.ring.as_ref().unwrap(); self.set_dequeue_ptr(addr); self.sct = (stream_ctx.deq_lo >> STREAM_CTX_SCT_SHIFT) & STREAM_CTX_SCT_MASK; - self.ring.as_ref().unwrap().init(dequeue); + ring.init(dequeue); + ring.set_cycle_bit((dequeue & 1) == 1); Ok(()) } @@ -1177,7 +1220,10 @@ impl XhciDevice { slot_id = self.get_slot_id(&mut event, &trb); if slot_id != 0 { let ep_id = trb.control >> TRB_CR_EPID_SHIFT & TRB_CR_EPID_MASK; - event.ccode = self.set_tr_dequeue_pointer(slot_id, ep_id, &trb)?; + let stream_id = + trb.control >> TRB_CR_STREAMID_SHIFT & TRB_CR_STREAMID_MASK; + event.ccode = + self.set_tr_dequeue_pointer(slot_id, ep_id, stream_id, &trb)?; } } TRBType::CrResetDevice => { @@ -1679,6 +1725,7 @@ impl XhciDevice { &mut self, slotid: u32, epid: u32, + streamid: u32, trb: &XhciTRB, ) -> Result { trace::usb_xhci_set_tr_dequeue(&slotid, &epid, &trb.parameter); @@ -1703,12 +1750,12 @@ impl XhciDevice { ); return Ok(TRBCCode::ContextStateError); } - epctx.update_dequeue(&self.mem_space, Some(trb.parameter))?; + epctx.update_dequeue(&self.mem_space, Some(trb.parameter), streamid)?; Ok(TRBCCode::Success) } /// Data plane - pub(crate) fn kick_endpoint(&mut self, slot_id: u32, ep_id: u32, _stream_id: u32) -> Result<()> { + pub(crate) fn kick_endpoint(&mut self, slot_id: u32, ep_id: u32, stream_id: u32) -> Result<()> { let epctx = match self.get_endpoint_ctx(slot_id, ep_id) { Ok(epctx) => epctx, Err(e) => { @@ -1725,11 +1772,15 @@ impl XhciDevice { return Ok(()); } - trace::usb_xhci_ep_kick(&slot_id, &ep_id, &epctx.ring.get_dequeue_ptr()); + trace::usb_xhci_ep_kick( + &slot_id, + &ep_id, + &epctx.ring.as_ref().unwrap().get_dequeue_ptr(), + ); if self.slots[(slot_id - 1) as usize].endpoints[(ep_id - 1) as usize] .retry .is_some() - && !self.endpoint_retry_transfer(slot_id, ep_id)? + && !self.endpoint_retry_transfer(slot_id, ep_id, stream_id)? { // Return directly to retry again at the next kick. return Ok(()); @@ -1744,15 +1795,15 @@ impl XhciDevice { let ep_state = epctx.state.clone(); const KICK_LIMIT: u32 = 256; let mut count = 0; - let ring = epctx.ring.clone(); + let ring = epctx.ring.as_ref().unwrap().clone(); loop { let epctx = &mut self.slots[(slot_id - 1) as usize].endpoints[(ep_id - 1) as usize]; - let td = match epctx.ring.fetch_td()? { + let td = match epctx.ring.as_ref().unwrap().fetch_td()? { Some(td) => { trace::usb_xhci_unimplemented(&format!( "fetch transfer trb {:?} ring dequeue {:?}", td, - epctx.ring.get_dequeue_ptr(), + epctx.ring.as_ref().unwrap().get_dequeue_ptr(), )); td } @@ -1765,7 +1816,7 @@ impl XhciDevice { let mut evt = XhciEvent::new(TRBType::ErTransfer, ccode); evt.slot_id = slot_id as u8; evt.ep_id = ep_id as u8; - evt.ptr = epctx.ring.dequeue.load(Ordering::Acquire); + evt.ptr = epctx.ring.as_ref().unwrap().dequeue.load(Ordering::Acquire); if let Err(e) = self.intrs[0].lock().unwrap().send_event(&evt) { error!("Failed to send event: {:?}", e); } @@ -1798,7 +1849,7 @@ impl XhciDevice { self.endpoint_do_transfer(&mut locked_xfer)?; let epctx = &mut self.slots[(slot_id - 1) as usize].endpoints[(ep_id - 1) as usize]; if locked_xfer.complete { - epctx.update_dequeue(&self.mem_space, None)?; + epctx.update_dequeue(&self.mem_space, None, stream_id)?; } else { epctx.transfers.push_back(xfer.clone()); } @@ -1847,7 +1898,12 @@ impl XhciDevice { /// Return Ok(true) if retry is done. /// Return Ok(false) if packet is need to retry again. /// Return Err() if retry failed. - fn endpoint_retry_transfer(&mut self, slot_id: u32, ep_id: u32) -> Result { + fn endpoint_retry_transfer( + &mut self, + slot_id: u32, + ep_id: u32, + stream_id: u32, + ) -> Result { let slot = &mut self.slots[(slot_id - 1) as usize]; // Safe because the retry is checked in the outer function call. let xfer = slot.endpoints[(ep_id - 1) as usize] @@ -1879,7 +1935,7 @@ impl XhciDevice { let epctx = &mut self.slots[(slot_id - 1) as usize].endpoints[(ep_id - 1) as usize]; if locked_xfer.complete { drop(locked_xfer); - epctx.update_dequeue(&self.mem_space, None)?; + epctx.update_dequeue(&self.mem_space, None, stream_id)?; epctx.flush_transfer(); } epctx.retry = None; diff --git a/devices/src/usb/xhci/xhci_ring.rs b/devices/src/usb/xhci/xhci_ring.rs index f3713572..cde8c926 100644 --- a/devices/src/usb/xhci/xhci_ring.rs +++ b/devices/src/usb/xhci/xhci_ring.rs @@ -206,15 +206,15 @@ impl XhciTransferRing { let mut ep_ctx = XhciEpCtx::default(); let output_addr = self.output_ctx_addr.load(Ordering::Acquire); dma_read_u32(&self.mem, GuestAddress(output_addr), ep_ctx.as_mut_dwords())?; - self.update_dequeue_to_ctx(&mut ep_ctx); + self.update_dequeue_to_ctx(&mut ep_ctx.as_mut_dwords()[2..]); dma_write_u32(&self.mem, GuestAddress(output_addr), ep_ctx.as_dwords())?; Ok(()) } - pub fn update_dequeue_to_ctx(&self, ep_ctx: &mut XhciEpCtx) { + pub fn update_dequeue_to_ctx(&self, ctx: &mut [u32]) { let dequeue = self.get_dequeue_ptr(); - ep_ctx.deq_lo = dequeue as u32 | self.get_cycle_bit() as u32; - ep_ctx.deq_hi = (dequeue >> 32) as u32; + ctx[0] = dequeue as u32 | self.get_cycle_bit() as u32; + ctx[1] = (dequeue >> 32) as u32; } } -- Gitee From 496cb1754813597907930cab7e80ad9012b6b028 Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Thu, 29 Feb 2024 17:52:57 +0300 Subject: [PATCH 173/489] xhci: Add reset functionality for streams Implement streams reset for endpoint context. Also make stream context sharable between threads. Signed-off-by: goriainovstanislav --- devices/src/usb/xhci/xhci_controller.rs | 115 +++++++++++++++--------- 1 file changed, 74 insertions(+), 41 deletions(-) diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index 3774ed41..c1973ca7 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -17,7 +17,7 @@ use std::sync::atomic::{AtomicU32, AtomicU64, Ordering}; use std::sync::{Arc, Mutex, Weak}; use std::time::Duration; -use anyhow::{bail, Context, Result}; +use anyhow::{anyhow, bail, Context, Result}; use byteorder::{ByteOrder, LittleEndian}; use log::{error, info, warn}; @@ -306,7 +306,7 @@ pub struct XhciEpContext { mem: Arc, max_pstreams: u32, lsa: bool, - stream_array: Option>, + stream_array: Option, } impl XhciEpContext { @@ -344,12 +344,12 @@ impl XhciEpContext { ring.set_cycle_bit((ctx.deq_lo & 1) == 1); self.ring = Some(Arc::new(ring)); } else { - let mut stream_array = + let stream_array = XhciStreamArray::new(&self.mem, &self.output_ctx_addr, self.max_pstreams); stream_array .init(dequeue) .with_context(|| "Failed to initialize Stream Array.")?; - self.stream_array = Some(Arc::new(stream_array)); + self.stream_array = Some(stream_array); } Ok(()) @@ -399,7 +399,7 @@ impl XhciEpContext { let stream_context = self.get_stream(stream_id).with_context(|| { format!("Failed to find Stream Context with Stream ID {}", stream_id) })?; - let output_addr = stream_context.dequeue.load(Ordering::Acquire); + let output_addr = stream_context.lock().unwrap().dequeue; dma_read_u32(mem, GuestAddress(output_addr), stream_ctx.as_mut_dwords())?; ring.update_dequeue_to_ctx(stream_ctx.as_mut_dwords()); dma_write_u32(mem, GuestAddress(output_addr), stream_ctx.as_dwords())?; @@ -419,7 +419,7 @@ impl XhciEpContext { self.transfers = undo; } - fn get_stream(&self, stream_id: u32) -> Result<&XhciStreamContext> { + fn get_stream(&self, stream_id: u32) -> Result>> { if self.stream_array.is_none() { bail!("Endpoint {} does not support streams.", self.epid); } @@ -441,30 +441,46 @@ impl XhciEpContext { } let stream_context = &pstreams[stream_id as usize]; + let mut locked_context = stream_context.lock().unwrap(); - if stream_context.sct != STREAM_CTX_SCT_PRIMARY_TR { + if locked_context.needs_update { + locked_context.update()?; + } + + if self.lsa && locked_context.sct != STREAM_CTX_SCT_PRIMARY_TR { bail!( "Invalid SCT {} on stream {}, LSA is {}", - stream_context.sct, + locked_context.sct, stream_id, self.lsa ); } - Ok(stream_context) + Ok(Arc::clone(stream_context)) } - fn get_ring(&self, stream_id: u32) -> Result<&Arc> { + fn get_ring(&self, stream_id: u32) -> Result> { if self.max_pstreams == 0 { - Ok(self.ring.as_ref().unwrap()) + Ok(Arc::clone(self.ring.as_ref().unwrap())) } else { - let stream_context = self.get_stream(stream_id).with_context(|| { + let stream = self.get_stream(stream_id).with_context(|| { format!("Failed to find Stream Context with Stream ID {}", stream_id) })?; - // SAFETY: Secondary Stream Arrays are not supported. - Ok(stream_context.ring.as_ref().unwrap()) + let locked_stream = stream.lock().unwrap(); + Ok(Arc::clone(&locked_stream.ring)) } } + + fn reset_streams(&self) -> Result<()> { + let stream_arr = self.stream_array.as_ref().ok_or_else(|| { + anyhow!( + "Endpoint {} does not support streams, reset aborted.", + self.epid + ) + })?; + stream_arr.reset(); + Ok(()) + } } fn set_ep_state_helper( @@ -791,70 +807,80 @@ pub trait DwordOrder: Default + Copy + Send + Sync { } #[repr(transparent)] -pub struct XhciStreamArray(Vec); +pub struct XhciStreamArray(Vec>>); impl XhciStreamArray { fn new(mem: &Arc, addr: &Arc, max_pstreams: u32) -> Self { let pstreams_num = 1 << (max_pstreams + 1); let pstreams = (0..pstreams_num) - .map(|_| XhciStreamContext::new(mem, addr)) + .map(|_| Arc::new(Mutex::new(XhciStreamContext::new(mem, addr)))) .collect(); XhciStreamArray(pstreams) } - fn init(&mut self, mut dequeue: u64) -> Result<()> { - for stream_context in self.0.iter_mut() { - stream_context.init(dequeue)?; + fn init(&self, mut dequeue: u64) -> Result<()> { + for stream_context in self.0.iter() { + stream_context.lock().unwrap().init(dequeue)?; dequeue += std::mem::size_of::() as u64; } Ok(()) } + + fn reset(&self) { + for stream_context in self.0.iter() { + stream_context.lock().unwrap().reset(); + } + } } pub struct XhciStreamContext { /// Memory address space. mem: Arc, - /// Address of this Stream Context. - dequeue: AtomicU64, + /// Output context address. + dequeue: u64, /// Stream Context Type (SCT). sct: u32, - /// Secondary Stream Array. - _secondary_streams: Option>, /// Transfer Ring. - ring: Option>, + ring: Arc, + /// Whether this Stream Context is initialized. + needs_update: bool, } impl XhciStreamContext { fn new(mem: &Arc, addr: &Arc) -> Self { - // NOTE: No Secondary Stream Array support yet. Self { mem: Arc::clone(mem), - dequeue: AtomicU64::new(0), - sct: STREAM_CTX_SCT_PRIMARY_TR, - _secondary_streams: None, - ring: Some(Arc::new(XhciTransferRing::new(mem, addr))), + dequeue: 0, + sct: 0, + ring: Arc::new(XhciTransferRing::new(mem, addr)), + needs_update: true, } } fn init(&mut self, addr: u64) -> Result<()> { + self.dequeue = addr; + self.update()?; + Ok(()) + } + + fn update(&mut self) -> Result<()> { let mut stream_ctx = XhciStreamCtx::default(); - dma_read_u32(&self.mem, GuestAddress(addr), stream_ctx.as_mut_dwords())?; + dma_read_u32( + &self.mem, + GuestAddress(self.dequeue), + stream_ctx.as_mut_dwords(), + )?; let dequeue = addr64_from_u32(stream_ctx.deq_lo & !0xf, stream_ctx.deq_hi); - let ring = self.ring.as_ref().unwrap(); - self.set_dequeue_ptr(addr); self.sct = (stream_ctx.deq_lo >> STREAM_CTX_SCT_SHIFT) & STREAM_CTX_SCT_MASK; - ring.init(dequeue); - ring.set_cycle_bit((dequeue & 1) == 1); + self.ring.init(dequeue); + self.ring.set_cycle_bit((dequeue & 1) == 1); + self.needs_update = false; Ok(()) } - pub fn get_dequeue_ptr(&self) -> u64 { - self.dequeue.load(Ordering::Acquire) - } - - pub fn set_dequeue_ptr(&self, addr: u64) { - self.dequeue.store(addr, Ordering::Release); + fn reset(&mut self) { + self.needs_update = true; } } @@ -1678,7 +1704,11 @@ impl XhciDevice { slot_id, ep_id )); } - self.slots[(slot_id - 1) as usize].endpoints[(ep_id - 1) as usize].set_state(EP_STOPPED)?; + let epctx = &mut self.slots[(slot_id - 1) as usize].endpoints[(ep_id - 1) as usize]; + epctx.set_state(EP_STOPPED)?; + if epctx.max_pstreams != 0 { + epctx.reset_streams()?; + } Ok(TRBCCode::Success) } @@ -1718,6 +1748,9 @@ impl XhciDevice { error!("Failed to found port"); return Ok(TRBCCode::UsbTransactionError); } + if epctx.max_pstreams != 0 { + epctx.reset_streams()?; + } Ok(TRBCCode::Success) } -- Gitee From 7fc86d8908505b0461100a7b1c1e57b2d827d97c Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Fri, 1 Mar 2024 10:48:54 +0300 Subject: [PATCH 174/489] xhci: Refactor existing code Remove output context address from XchiTransferRing. Store the entire endpoint context structure in XhciTransfer. Remove ep_set_state_helper. Signed-off-by: goriainovstanislav --- devices/src/usb/xhci/xhci_controller.rs | 110 +++++++++++------------- devices/src/usb/xhci/xhci_ring.rs | 15 ++-- 2 files changed, 57 insertions(+), 68 deletions(-) diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index c1973ca7..29a45dfe 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -137,28 +137,25 @@ pub struct XhciTransfer { td: Vec, complete: bool, slotid: u32, - streamid: u32, epid: u32, + streamid: u32, + ep_context: XhciEpContext, in_xfer: bool, iso_xfer: bool, timed_xfer: bool, running_retry: bool, running_async: bool, interrupter: Arc>, - ep_ring: Arc, - ep_type: EpType, - ep_state: Arc, mfindex_kick: u64, } impl XhciTransfer { fn new( - ep_info: (u32, u32, EpType), + ep_info: (u32, u32, u32), + ep_context: &XhciEpContext, in_xfer: bool, td: Vec, intr: &Arc>, - ring: &Arc, - ep_state: &Arc, ) -> Self { XhciTransfer { packet: Arc::new(Mutex::new(UsbPacket::default())), @@ -167,16 +164,14 @@ impl XhciTransfer { complete: false, slotid: ep_info.0, epid: ep_info.1, - streamid: 0, + streamid: ep_info.2, + ep_context: ep_context.clone(), in_xfer, iso_xfer: false, timed_xfer: false, running_retry: false, running_async: false, interrupter: intr.clone(), - ep_ring: ring.clone(), - ep_type: ep_info.2, - ep_state: ep_state.clone(), mfindex_kick: 0, } } @@ -190,18 +185,20 @@ impl XhciTransfer { if self.status == TRBCCode::Success { trace::usb_xhci_xfer_success(&self.packet.lock().unwrap().actual_length); self.submit_transfer()?; - self.ep_ring.refresh_dequeue_ptr()?; + let ring = self.ep_context.ring.as_ref().unwrap(); + ring.refresh_dequeue_ptr(self.ep_context.output_ctx_addr.load(Ordering::Acquire))?; return Ok(()); } trace::usb_xhci_xfer_error(&self.packet.lock().unwrap().status); self.report_transfer_error()?; + let ep_type = self.ep_context.ep_type; - if self.ep_type == EpType::IsoIn || self.ep_type == EpType::IsoOut { + if ep_type == EpType::IsoIn || ep_type == EpType::IsoOut { return Ok(()); } // Set the endpoint state to halted if an error occurs in the packet. - set_ep_state_helper(&self.ep_ring, &self.ep_state, EP_HALTED)?; + self.ep_context.set_state(EP_HALTED)?; Ok(()) } @@ -292,6 +289,7 @@ impl TransferOps for XhciTransfer { } /// Endpoint context which use the ring to transfer data. +#[derive(Clone)] pub struct XhciEpContext { epid: u32, enabled: bool, @@ -339,13 +337,12 @@ impl XhciEpContext { self.interval = 1 << ((ctx.ep_info >> EP_CTX_INTERVAL_SHIFT) & EP_CTX_INTERVAL_MASK); if self.max_pstreams == 0 { - let ring = XhciTransferRing::new(&self.mem, &self.output_ctx_addr); + let ring = XhciTransferRing::new(&self.mem); ring.init(dequeue); ring.set_cycle_bit((ctx.deq_lo & 1) == 1); self.ring = Some(Arc::new(ring)); } else { - let stream_array = - XhciStreamArray::new(&self.mem, &self.output_ctx_addr, self.max_pstreams); + let stream_array = XhciStreamArray::new(&self.mem, self.max_pstreams); stream_array .init(dequeue) .with_context(|| "Failed to initialize Stream Array.")?; @@ -360,12 +357,21 @@ impl XhciEpContext { } fn set_ep_state(&self, state: u32) { - self.state.store(state, Ordering::SeqCst); + self.state.store(state, Ordering::Release); } /// Update the endpoint state and write the state to memory. - fn set_state(&mut self, state: u32) -> Result<()> { - set_ep_state_helper(self.ring.as_ref().unwrap(), &self.state, state) + fn set_state(&self, state: u32) -> Result<()> { + let mut ep_ctx = XhciEpCtx::default(); + let output_addr = self.output_ctx_addr.load(Ordering::Acquire); + dma_read_u32(&self.mem, GuestAddress(output_addr), ep_ctx.as_mut_dwords())?; + ep_ctx.ep_info &= !EP_STATE_MASK; + ep_ctx.ep_info |= state; + let ring = self.ring.as_ref().unwrap(); + ring.update_dequeue_to_ctx(&mut ep_ctx.as_mut_dwords()[2..]); + dma_write_u32(&self.mem, GuestAddress(output_addr), ep_ctx.as_dwords())?; + self.set_ep_state(state); + Ok(()) } /// Update the dequeue pointer in endpoint or stream context. @@ -420,16 +426,16 @@ impl XhciEpContext { } fn get_stream(&self, stream_id: u32) -> Result>> { - if self.stream_array.is_none() { - bail!("Endpoint {} does not support streams.", self.epid); - } + let stream_arr = self + .stream_array + .as_ref() + .ok_or_else(|| anyhow!("Endpoint {} does not support streams.", self.epid))?; if !self.lsa { - bail!("Only Linear Streams Array (LSA) is supported.") + bail!("Only Linear Streams Array (LSA) is supported."); } - // SAFETY: Stream Array was checked to be not None. - let pstreams = &self.stream_array.as_ref().unwrap().0; + let pstreams = &stream_arr.0; let pstreams_num = pstreams.len() as u32; if stream_id >= pstreams_num || stream_id == 0 { @@ -443,8 +449,8 @@ impl XhciEpContext { let stream_context = &pstreams[stream_id as usize]; let mut locked_context = stream_context.lock().unwrap(); - if locked_context.needs_update { - locked_context.update()?; + if locked_context.needs_refresh { + locked_context.refresh()?; } if self.lsa && locked_context.sct != STREAM_CTX_SCT_PRIMARY_TR { @@ -483,23 +489,6 @@ impl XhciEpContext { } } -fn set_ep_state_helper( - ring: &Arc, - ep_state: &Arc, - state: u32, -) -> Result<()> { - let mem = &ring.mem; - let mut ep_ctx = XhciEpCtx::default(); - let output_addr = ring.output_ctx_addr.load(Ordering::Acquire); - dma_read_u32(mem, GuestAddress(output_addr), ep_ctx.as_mut_dwords())?; - ep_ctx.ep_info &= !EP_STATE_MASK; - ep_ctx.ep_info |= state; - ring.update_dequeue_to_ctx(&mut ep_ctx.as_mut_dwords()[2..]); - dma_write_u32(mem, GuestAddress(output_addr), ep_ctx.as_dwords())?; - ep_state.store(state, Ordering::SeqCst); - Ok(()) -} - /// Endpoint type, including control, bulk, interrupt and isochronous. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum EpType { @@ -807,13 +796,14 @@ pub trait DwordOrder: Default + Copy + Send + Sync { } #[repr(transparent)] +#[derive(Clone)] pub struct XhciStreamArray(Vec>>); impl XhciStreamArray { - fn new(mem: &Arc, addr: &Arc, max_pstreams: u32) -> Self { + fn new(mem: &Arc, max_pstreams: u32) -> Self { let pstreams_num = 1 << (max_pstreams + 1); let pstreams = (0..pstreams_num) - .map(|_| Arc::new(Mutex::new(XhciStreamContext::new(mem, addr)))) + .map(|_| Arc::new(Mutex::new(XhciStreamContext::new(mem)))) .collect(); XhciStreamArray(pstreams) } @@ -834,6 +824,7 @@ impl XhciStreamArray { } } +#[derive(Clone)] pub struct XhciStreamContext { /// Memory address space. mem: Arc, @@ -843,28 +834,28 @@ pub struct XhciStreamContext { sct: u32, /// Transfer Ring. ring: Arc, - /// Whether this Stream Context is initialized. - needs_update: bool, + /// Whether the context is up to date. + needs_refresh: bool, } impl XhciStreamContext { - fn new(mem: &Arc, addr: &Arc) -> Self { + fn new(mem: &Arc) -> Self { Self { mem: Arc::clone(mem), dequeue: 0, sct: 0, - ring: Arc::new(XhciTransferRing::new(mem, addr)), - needs_update: true, + ring: Arc::new(XhciTransferRing::new(mem)), + needs_refresh: true, } } fn init(&mut self, addr: u64) -> Result<()> { self.dequeue = addr; - self.update()?; + self.refresh()?; Ok(()) } - fn update(&mut self) -> Result<()> { + fn refresh(&mut self) -> Result<()> { let mut stream_ctx = XhciStreamCtx::default(); dma_read_u32( &self.mem, @@ -875,12 +866,12 @@ impl XhciStreamContext { self.sct = (stream_ctx.deq_lo >> STREAM_CTX_SCT_SHIFT) & STREAM_CTX_SCT_MASK; self.ring.init(dequeue); self.ring.set_cycle_bit((dequeue & 1) == 1); - self.needs_update = false; + self.needs_refresh = false; Ok(()) } fn reset(&mut self) { - self.needs_update = true; + self.needs_refresh = true; } } @@ -1825,10 +1816,8 @@ impl XhciDevice { return Ok(()); } epctx.set_state(EP_RUNNING)?; - let ep_state = epctx.state.clone(); const KICK_LIMIT: u32 = 256; let mut count = 0; - let ring = epctx.ring.as_ref().unwrap().clone(); loop { let epctx = &mut self.slots[(slot_id - 1) as usize].endpoints[(ep_id - 1) as usize]; let td = match epctx.ring.as_ref().unwrap().fetch_td()? { @@ -1861,12 +1850,11 @@ impl XhciDevice { let in_xfer = transfer_in_direction(ep_id as u8, &td, epctx.ep_type); // NOTE: Only support primary interrupter now. let xfer = Arc::new(Mutex::new(XhciTransfer::new( - (slot_id, ep_id, epctx.ep_type), + (slot_id, ep_id, stream_id), + epctx, in_xfer, td, &self.intrs[0], - &ring, - &ep_state, ))); let packet = match self.setup_usb_packet(&xfer) { Ok(pkt) => pkt, diff --git a/devices/src/usb/xhci/xhci_ring.rs b/devices/src/usb/xhci/xhci_ring.rs index cde8c926..6fd9d85c 100644 --- a/devices/src/usb/xhci/xhci_ring.rs +++ b/devices/src/usb/xhci/xhci_ring.rs @@ -116,16 +116,14 @@ pub struct XhciTransferRing { pub dequeue: AtomicU64, /// Consumer Cycle State pub ccs: AtomicBool, - pub output_ctx_addr: Arc, } impl XhciTransferRing { - pub fn new(mem: &Arc, addr: &Arc) -> Self { + pub fn new(mem: &Arc) -> Self { Self { mem: mem.clone(), dequeue: AtomicU64::new(0), ccs: AtomicBool::new(true), - output_ctx_addr: addr.clone(), } } @@ -202,12 +200,15 @@ impl XhciTransferRing { } /// Refresh dequeue pointer to output context. - pub fn refresh_dequeue_ptr(&self) -> Result<()> { + pub fn refresh_dequeue_ptr(&self, output_ctx_addr: u64) -> Result<()> { let mut ep_ctx = XhciEpCtx::default(); - let output_addr = self.output_ctx_addr.load(Ordering::Acquire); - dma_read_u32(&self.mem, GuestAddress(output_addr), ep_ctx.as_mut_dwords())?; + dma_read_u32( + &self.mem, + GuestAddress(output_ctx_addr), + ep_ctx.as_mut_dwords(), + )?; self.update_dequeue_to_ctx(&mut ep_ctx.as_mut_dwords()[2..]); - dma_write_u32(&self.mem, GuestAddress(output_addr), ep_ctx.as_dwords())?; + dma_write_u32(&self.mem, GuestAddress(output_ctx_addr), ep_ctx.as_dwords())?; Ok(()) } -- Gitee From 1ccc532c28ac9d4e1a4f0681b946fe1bb61116e0 Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Fri, 1 Mar 2024 13:43:32 +0300 Subject: [PATCH 175/489] xhci: Add support for XHCI Streams First version of USB Streams support. No secondary streams for now, so remove SCT checks (only ensure that LSA is enabled). Signed-off-by: goriainovstanislav --- devices/src/usb/uas.rs | 2 +- devices/src/usb/xhci/xhci_controller.rs | 172 +++++++++++++----------- devices/src/usb/xhci/xhci_regs.rs | 4 +- 3 files changed, 101 insertions(+), 77 deletions(-) diff --git a/devices/src/usb/uas.rs b/devices/src/usb/uas.rs index e0104272..df57b0ba 100644 --- a/devices/src/usb/uas.rs +++ b/devices/src/usb/uas.rs @@ -59,7 +59,7 @@ const UAS_PIPE_ID_DATA_IN: u8 = 0x03; const UAS_PIPE_ID_DATA_OUT: u8 = 0x04; // UAS Streams Attributes -const UAS_MAX_STREAMS_BM_ATTR: u8 = 0; +const UAS_MAX_STREAMS_BM_ATTR: u8 = 4; const UAS_MAX_STREAMS: usize = 1 << UAS_MAX_STREAMS_BM_ATTR; // UAS IU IDs diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index 29a45dfe..06c714af 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -117,10 +117,10 @@ const EP_CONTEXT_EP_TYPE_SHIFT: u32 = 3; const ISO_BASE_TIME_INTERVAL: u64 = 125000; const MFINDEX_WRAP_NUM: u64 = 0x4000; /// Stream Context. -const STREAM_CTX_SCT_SHIFT: u32 = 1; -const STREAM_CTX_SCT_MASK: u32 = 0x7; +const _STREAM_CTX_SCT_SHIFT: u32 = 1; +const _STREAM_CTX_SCT_MASK: u32 = 0x7; const _STREAM_CTX_SCT_SECONDARY_TR: u32 = 0; -const STREAM_CTX_SCT_PRIMARY_TR: u32 = 1; +const _STREAM_CTX_SCT_PRIMARY_TR: u32 = 1; const _STREAM_CTX_SCT_PRIMARY_SSA_8: u32 = 2; const _STREAM_CTX_SCT_PRIMARY_SSA_16: u32 = 3; const _STREAM_CTX_SCT_PRIMARY_SSA_32: u32 = 4; @@ -152,7 +152,7 @@ pub struct XhciTransfer { impl XhciTransfer { fn new( ep_info: (u32, u32, u32), - ep_context: &XhciEpContext, + ep_context: XhciEpContext, in_xfer: bool, td: Vec, intr: &Arc>, @@ -165,7 +165,7 @@ impl XhciTransfer { slotid: ep_info.0, epid: ep_info.1, streamid: ep_info.2, - ep_context: ep_context.clone(), + ep_context, in_xfer, iso_xfer: false, timed_xfer: false, @@ -185,7 +185,12 @@ impl XhciTransfer { if self.status == TRBCCode::Success { trace::usb_xhci_xfer_success(&self.packet.lock().unwrap().actual_length); self.submit_transfer()?; - let ring = self.ep_context.ring.as_ref().unwrap(); + let ring = self.ep_context.get_ring(self.streamid).with_context(|| { + format!( + "Failed to find Transfer Ring with Endpoint ID {}, Slot ID {}, Stream ID {}.", + self.epid, self.slotid, self.streamid + ) + })?; ring.refresh_dequeue_ptr(self.ep_context.output_ctx_addr.load(Ordering::Acquire))?; return Ok(()); } @@ -198,7 +203,7 @@ impl XhciTransfer { return Ok(()); } // Set the endpoint state to halted if an error occurs in the packet. - self.ep_context.set_state(EP_HALTED)?; + self.ep_context.set_state(EP_HALTED, Some(self.streamid))?; Ok(()) } @@ -361,56 +366,63 @@ impl XhciEpContext { } /// Update the endpoint state and write the state to memory. - fn set_state(&self, state: u32) -> Result<()> { + fn set_state(&self, state: u32, stream_id: Option) -> Result<()> { let mut ep_ctx = XhciEpCtx::default(); let output_addr = self.output_ctx_addr.load(Ordering::Acquire); dma_read_u32(&self.mem, GuestAddress(output_addr), ep_ctx.as_mut_dwords())?; ep_ctx.ep_info &= !EP_STATE_MASK; ep_ctx.ep_info |= state; - let ring = self.ring.as_ref().unwrap(); - ring.update_dequeue_to_ctx(&mut ep_ctx.as_mut_dwords()[2..]); dma_write_u32(&self.mem, GuestAddress(output_addr), ep_ctx.as_dwords())?; + self.flush_dequeue_to_memory(stream_id)?; self.set_ep_state(state); Ok(()) } /// Update the dequeue pointer in endpoint or stream context. /// If dequeue is None, only flush the dequeue pointer to memory. - fn update_dequeue( - &mut self, - mem: &Arc, - dequeue: Option, - stream_id: u32, - ) -> Result<()> { - let ring = self.get_ring(stream_id).with_context(|| { - format!( - "Failed to find Transfer Ring for Endpoint {}, Stream ID {}", - self.epid, stream_id - ) - })?; - + fn update_dequeue(&self, dequeue: Option, stream_id: u32) -> Result<()> { if let Some(dequeue) = dequeue { + let ring = self.get_ring(stream_id).with_context(|| { + format!( + "Failed to find Transfer Ring for Endpoint {}, Stream ID {}.", + self.epid, stream_id + ) + })?; ring.init(dequeue & EP_CTX_TR_DEQUEUE_POINTER_MASK); ring.set_cycle_bit((dequeue & EP_CTX_DCS) == EP_CTX_DCS); } + self.flush_dequeue_to_memory(Some(stream_id))?; + Ok(()) + } + + /// Flush the dequeue pointer to the memory. + /// Stream Endpoints flush ring dequeue to both Endpoint and Stream context. + fn flush_dequeue_to_memory(&self, stream_id: Option) -> Result<()> { + let mut ep_ctx = XhciEpCtx::default(); + let output_addr = self.output_ctx_addr.load(Ordering::Acquire); + dma_read_u32(&self.mem, GuestAddress(output_addr), ep_ctx.as_mut_dwords())?; + if self.max_pstreams == 0 { - let mut ep_ctx = XhciEpCtx::default(); - let output_addr = self.output_ctx_addr.load(Ordering::Acquire); - dma_read_u32(mem, GuestAddress(output_addr), ep_ctx.as_mut_dwords())?; + let ring = self.get_ring(0)?; ring.update_dequeue_to_ctx(&mut ep_ctx.as_mut_dwords()[2..]); - dma_write_u32(mem, GuestAddress(output_addr), ep_ctx.as_dwords())?; - } else { + } else if let Some(stream_id) = stream_id { let mut stream_ctx = XhciStreamCtx::default(); - let stream_context = self.get_stream(stream_id).with_context(|| { - format!("Failed to find Stream Context with Stream ID {}", stream_id) - })?; - let output_addr = stream_context.lock().unwrap().dequeue; - dma_read_u32(mem, GuestAddress(output_addr), stream_ctx.as_mut_dwords())?; + let stream = self.get_stream(stream_id)?; + let locked_stream = stream.lock().unwrap(); + let output_addr = locked_stream.dequeue; + let ring = locked_stream.ring.as_ref(); + dma_read_u32( + &self.mem, + GuestAddress(output_addr), + stream_ctx.as_mut_dwords(), + )?; ring.update_dequeue_to_ctx(stream_ctx.as_mut_dwords()); - dma_write_u32(mem, GuestAddress(output_addr), stream_ctx.as_dwords())?; + ring.update_dequeue_to_ctx(&mut ep_ctx.as_mut_dwords()[2..]); + dma_write_u32(&self.mem, GuestAddress(output_addr), stream_ctx.as_dwords())?; } + dma_write_u32(&self.mem, GuestAddress(output_addr), ep_ctx.as_dwords())?; Ok(()) } @@ -425,6 +437,8 @@ impl XhciEpContext { self.transfers = undo; } + /// Find and return a stream corresponding to the specified Stream ID. + /// Returns error if there is no stream support or LSA is not enabled. fn get_stream(&self, stream_id: u32) -> Result>> { let stream_arr = self .stream_array @@ -435,7 +449,7 @@ impl XhciEpContext { bail!("Only Linear Streams Array (LSA) is supported."); } - let pstreams = &stream_arr.0; + let XhciStreamArray(pstreams) = &stream_arr; let pstreams_num = pstreams.len() as u32; if stream_id >= pstreams_num || stream_id == 0 { @@ -448,35 +462,33 @@ impl XhciEpContext { let stream_context = &pstreams[stream_id as usize]; let mut locked_context = stream_context.lock().unwrap(); - - if locked_context.needs_refresh { - locked_context.refresh()?; - } - - if self.lsa && locked_context.sct != STREAM_CTX_SCT_PRIMARY_TR { - bail!( - "Invalid SCT {} on stream {}, LSA is {}", - locked_context.sct, - stream_id, - self.lsa - ); - } - + locked_context.try_refresh()?; Ok(Arc::clone(stream_context)) } + /// Get a ring corresponding to the specified Stream ID if stream support is enabled, + /// return the standard Transfer Ring otherwise. fn get_ring(&self, stream_id: u32) -> Result> { if self.max_pstreams == 0 { - Ok(Arc::clone(self.ring.as_ref().unwrap())) + Ok(Arc::clone(self.ring.as_ref().ok_or_else(|| { + anyhow!( + "Failed to get the Transfer Ring for Endpoint {} without streams.", + self.epid + ) + })?)) } else { let stream = self.get_stream(stream_id).with_context(|| { - format!("Failed to find Stream Context with Stream ID {}", stream_id) + format!( + "Failed to find Stream Context with Stream ID {}.", + stream_id + ) })?; let locked_stream = stream.lock().unwrap(); Ok(Arc::clone(&locked_stream.ring)) } } + /// Reset all streams on this Endpoint. fn reset_streams(&self) -> Result<()> { let stream_arr = self.stream_array.as_ref().ok_or_else(|| { anyhow!( @@ -828,13 +840,11 @@ impl XhciStreamArray { pub struct XhciStreamContext { /// Memory address space. mem: Arc, - /// Output context address. + /// Dequeue pointer. dequeue: u64, - /// Stream Context Type (SCT). - sct: u32, - /// Transfer Ring. + /// Transfer Ring (no Secondary Streams for now). ring: Arc, - /// Whether the context is up to date. + /// Whether the context is up to date after reset. needs_refresh: bool, } @@ -843,7 +853,6 @@ impl XhciStreamContext { Self { mem: Arc::clone(mem), dequeue: 0, - sct: 0, ring: Arc::new(XhciTransferRing::new(mem)), needs_refresh: true, } @@ -855,6 +864,14 @@ impl XhciStreamContext { Ok(()) } + fn try_refresh(&mut self) -> Result<()> { + if self.needs_refresh { + self.refresh()?; + } + + Ok(()) + } + fn refresh(&mut self) -> Result<()> { let mut stream_ctx = XhciStreamCtx::default(); dma_read_u32( @@ -863,9 +880,7 @@ impl XhciStreamContext { stream_ctx.as_mut_dwords(), )?; let dequeue = addr64_from_u32(stream_ctx.deq_lo & !0xf, stream_ctx.deq_hi); - self.sct = (stream_ctx.deq_lo >> STREAM_CTX_SCT_SHIFT) & STREAM_CTX_SCT_MASK; self.ring.init(dequeue); - self.ring.set_cycle_bit((dequeue & 1) == 1); self.needs_refresh = false; Ok(()) } @@ -1238,7 +1253,7 @@ impl XhciDevice { if slot_id != 0 { let ep_id = trb.control >> TRB_CR_EPID_SHIFT & TRB_CR_EPID_MASK; let stream_id = - trb.control >> TRB_CR_STREAMID_SHIFT & TRB_CR_STREAMID_MASK; + trb.status >> TRB_CR_STREAMID_SHIFT & TRB_CR_STREAMID_MASK; event.ccode = self.set_tr_dequeue_pointer(slot_id, ep_id, stream_id, &trb)?; } @@ -1659,7 +1674,7 @@ impl XhciDevice { self.cancel_all_ep_transfers(slot_id, ep_id, TRBCCode::Invalid)?; let epctx = &mut self.slots[(slot_id - 1) as usize].endpoints[(ep_id - 1) as usize]; if self.oper.dcbaap != 0 { - epctx.set_state(EP_DISABLED)?; + epctx.set_state(EP_DISABLED, None)?; } epctx.enabled = false; Ok(TRBCCode::Success) @@ -1696,7 +1711,7 @@ impl XhciDevice { )); } let epctx = &mut self.slots[(slot_id - 1) as usize].endpoints[(ep_id - 1) as usize]; - epctx.set_state(EP_STOPPED)?; + epctx.set_state(EP_STOPPED, None)?; if epctx.max_pstreams != 0 { epctx.reset_streams()?; } @@ -1730,7 +1745,7 @@ impl XhciDevice { let epctx = &mut slot.endpoints[(ep_id - 1) as usize]; if let Some(port) = &slot.usb_port { if port.lock().unwrap().dev.is_some() { - epctx.set_state(EP_STOPPED)?; + epctx.set_state(EP_STOPPED, None)?; } else { error!("Failed to found usb device"); return Ok(TRBCCode::UsbTransactionError); @@ -1774,7 +1789,7 @@ impl XhciDevice { ); return Ok(TRBCCode::ContextStateError); } - epctx.update_dequeue(&self.mem_space, Some(trb.parameter), streamid)?; + epctx.update_dequeue(Some(trb.parameter), streamid)?; Ok(TRBCCode::Success) } @@ -1789,6 +1804,13 @@ impl XhciDevice { } }; + let ring = epctx.get_ring(stream_id).with_context(|| { + format!( + "Failed to kick Endpoint {}, no Transfer ring found on Stream ID {}", + ep_id, stream_id + ) + })?; + // If the device has been detached, but the guest has not been notified. // In this case, the Transaction Error is reported when the TRB processed. // Therefore, don't continue here. @@ -1796,11 +1818,7 @@ impl XhciDevice { return Ok(()); } - trace::usb_xhci_ep_kick( - &slot_id, - &ep_id, - &epctx.ring.as_ref().unwrap().get_dequeue_ptr(), - ); + trace::usb_xhci_ep_kick(&slot_id, &ep_id, &ring.get_dequeue_ptr()); if self.slots[(slot_id - 1) as usize].endpoints[(ep_id - 1) as usize] .retry .is_some() @@ -1815,17 +1833,17 @@ impl XhciDevice { info!("xhci: endpoint halted"); return Ok(()); } - epctx.set_state(EP_RUNNING)?; + epctx.set_state(EP_RUNNING, Some(stream_id))?; const KICK_LIMIT: u32 = 256; let mut count = 0; loop { let epctx = &mut self.slots[(slot_id - 1) as usize].endpoints[(ep_id - 1) as usize]; - let td = match epctx.ring.as_ref().unwrap().fetch_td()? { + let td = match ring.fetch_td()? { Some(td) => { trace::usb_xhci_unimplemented(&format!( "fetch transfer trb {:?} ring dequeue {:?}", td, - epctx.ring.as_ref().unwrap().get_dequeue_ptr(), + ring.get_dequeue_ptr(), )); td } @@ -1838,7 +1856,7 @@ impl XhciDevice { let mut evt = XhciEvent::new(TRBType::ErTransfer, ccode); evt.slot_id = slot_id as u8; evt.ep_id = ep_id as u8; - evt.ptr = epctx.ring.as_ref().unwrap().dequeue.load(Ordering::Acquire); + evt.ptr = ring.get_dequeue_ptr(); if let Err(e) = self.intrs[0].lock().unwrap().send_event(&evt) { error!("Failed to send event: {:?}", e); } @@ -1848,6 +1866,10 @@ impl XhciDevice { } }; let in_xfer = transfer_in_direction(ep_id as u8, &td, epctx.ep_type); + let mut epctx = epctx.clone(); + // NOTE: It is necessary to clear the transfer list here because otherwise it would + // result in an infinite cycle of destructor calls, leading to a stack overflow. + epctx.transfers.clear(); // NOTE: Only support primary interrupter now. let xfer = Arc::new(Mutex::new(XhciTransfer::new( (slot_id, ep_id, stream_id), @@ -1870,7 +1892,7 @@ impl XhciDevice { self.endpoint_do_transfer(&mut locked_xfer)?; let epctx = &mut self.slots[(slot_id - 1) as usize].endpoints[(ep_id - 1) as usize]; if locked_xfer.complete { - epctx.update_dequeue(&self.mem_space, None, stream_id)?; + epctx.update_dequeue(None, stream_id)?; } else { epctx.transfers.push_back(xfer.clone()); } @@ -1956,7 +1978,7 @@ impl XhciDevice { let epctx = &mut self.slots[(slot_id - 1) as usize].endpoints[(ep_id - 1) as usize]; if locked_xfer.complete { drop(locked_xfer); - epctx.update_dequeue(&self.mem_space, None, stream_id)?; + epctx.update_dequeue(None, stream_id)?; epctx.flush_transfer(); } epctx.retry = None; diff --git a/devices/src/usb/xhci/xhci_regs.rs b/devices/src/usb/xhci/xhci_regs.rs index 23c0b9a9..d817a631 100644 --- a/devices/src/usb/xhci/xhci_regs.rs +++ b/devices/src/usb/xhci/xhci_regs.rs @@ -381,7 +381,9 @@ pub fn build_cap_ops(xhci_dev: &Arc>) -> RegionOps { } XHCI_CAP_REG_HCSPARAMS3 => 0x0, XHCI_CAP_REG_HCCPARAMS1 => { - 0x8 << CAP_HCCP_EXCP_SHIFT | (0 << CAP_HCCP_MPSAS_SHIFT) | CAP_HCCP_AC64 + // The offset of the first extended capability is (base) + (0x8 << 2) + // The primary stream array size is 1 << (0x7 + 1) + 0x8 << CAP_HCCP_EXCP_SHIFT | (0x7 << CAP_HCCP_MPSAS_SHIFT) | CAP_HCCP_AC64 } XHCI_CAP_REG_DBOFF => XHCI_OFF_DOORBELL, XHCI_CAP_REG_RTSOFF => XHCI_OFF_RUNTIME, -- Gitee From 5ccfa4d9d7c531d6898db7cababd09c02f3c259d Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Fri, 15 Mar 2024 15:34:53 +0300 Subject: [PATCH 176/489] xhci: Add trace to XHCI Streams Add trace event for update_dequeue, set_state, get_ring, get_stream and reset_streams. Signed-off-by: goriainovstanislav --- devices/src/usb/xhci/xhci_controller.rs | 5 +++++ trace/trace_info/usb.toml | 30 +++++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index 06c714af..b515130d 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -375,6 +375,7 @@ impl XhciEpContext { dma_write_u32(&self.mem, GuestAddress(output_addr), ep_ctx.as_dwords())?; self.flush_dequeue_to_memory(stream_id)?; self.set_ep_state(state); + trace::usb_xhci_set_state(self.epid, state); Ok(()) } @@ -390,6 +391,7 @@ impl XhciEpContext { })?; ring.init(dequeue & EP_CTX_TR_DEQUEUE_POINTER_MASK); ring.set_cycle_bit((dequeue & EP_CTX_DCS) == EP_CTX_DCS); + trace::usb_xhci_update_dequeue(self.epid, dequeue, stream_id); } self.flush_dequeue_to_memory(Some(stream_id))?; @@ -463,6 +465,7 @@ impl XhciEpContext { let stream_context = &pstreams[stream_id as usize]; let mut locked_context = stream_context.lock().unwrap(); locked_context.try_refresh()?; + trace::usb_xhci_get_stream(stream_id, self.epid); Ok(Arc::clone(stream_context)) } @@ -484,6 +487,7 @@ impl XhciEpContext { ) })?; let locked_stream = stream.lock().unwrap(); + trace::usb_xhci_get_ring(self.epid, stream_id); Ok(Arc::clone(&locked_stream.ring)) } } @@ -497,6 +501,7 @@ impl XhciEpContext { ) })?; stream_arr.reset(); + trace::usb_xhci_reset_streams(self.epid); Ok(()) } } diff --git a/trace/trace_info/usb.toml b/trace/trace_info/usb.toml index d94588e6..82991ed6 100644 --- a/trace/trace_info/usb.toml +++ b/trace/trace_info/usb.toml @@ -232,6 +232,36 @@ args = "str: &dyn fmt::Debug" message = "{:?}" enabled = true +[[events]] +name = "usb_xhci_set_state" +args = "ep_id: u32, new_state: u32" +message = "Endpoint {} set new state {}." +enabled = true + +[[events]] +name = "usb_xhci_update_dequeue" +args = "ep_id: u32, dequeue: u64, stream_id: u32" +message = "Endpoint {} update dequeue {} on Stream ID {}." +enabled = true + +[[events]] +name = "usb_xhci_reset_streams" +args = "ep_id: u32" +message = "Resetting streams on Endpoint {}." +enabled = true + +[[events]] +name = "usb_xhci_get_ring" +args = "ep_id: u32, stream_id: u32" +message = "Found Transfer ring on Endpoint {} Stream ID {}." +enabled = true + +[[events]] +name = "usb_xhci_get_stream" +args = "stream_id: u32, ep_id: u32" +message = "Found Stream Context {} for Endpoint {}." +enabled = true + [[events]] name = "usb_handle_control" args = "device: &str, req: &dyn fmt::Debug" -- Gitee From 9f960da9c569d8a7cd2d9528fd883f51d7713b07 Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Fri, 29 Mar 2024 13:19:52 +0300 Subject: [PATCH 177/489] usb: Imporve overall readability Fix typo in "endpoint". Simplify Default for UsbPacketStatus. Make comments more meaningful. Signed-off-by: goriainovstanislav --- devices/src/usb/mod.rs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/devices/src/usb/mod.rs b/devices/src/usb/mod.rs index d8e2e3d8..ac2e3add 100644 --- a/devices/src/usb/mod.rs +++ b/devices/src/usb/mod.rs @@ -51,9 +51,10 @@ const USB_MAX_ADDRESS: u8 = 127; pub const USB_DEVICE_BUFFER_DEFAULT_LEN: usize = 4096; /// USB packet return status. -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)] pub enum UsbPacketStatus { Success, + #[default] NoDev, Nak, Stall, @@ -61,12 +62,6 @@ pub enum UsbPacketStatus { IoError, } -impl Default for UsbPacketStatus { - fn default() -> Self { - Self::NoDev - } -} - /// USB request used to transfer to USB device. #[repr(C)] #[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] @@ -386,7 +381,7 @@ pub trait UsbDevice: Send + Sync { locked_packet.status = UsbPacketStatus::Success; let ep_nr = locked_packet.ep_number; drop(locked_packet); - debug!("handle packet endpointer number {}", ep_nr); + debug!("handle packet endpoint number {}", ep_nr); if ep_nr == 0 { if let Err(e) = self.do_parameter(packet) { error!("Failed to handle control packet {:?}", e); @@ -496,9 +491,9 @@ pub trait TransferOps: Send + Sync { /// Usb packet used for device transfer data. #[derive(Default)] pub struct UsbPacket { - /// USB packet unique identifier. + /// Unique number for packet tracking. pub packet_id: u32, - /// USB packet id. + /// USB packet id (direction of the transfer). pub pid: u32, pub is_async: bool, pub iovecs: Vec, -- Gitee From d26fcd7e69213b006bc179ce0e7c8116f5bd1f2d Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Fri, 29 Mar 2024 13:21:44 +0300 Subject: [PATCH 178/489] uas: Add support for Super Speed, remove support for High Speed Since there are now streams on Xhci, it makes much more sense to only leave support for Super Speed. Device architecture stays the same. Code becomes even simpler after removing obsolete High Speed support. Signed-off-by: goriainovstanislav --- devices/src/scsi/bus.rs | 2 +- devices/src/usb/uas.rs | 523 +++++++++----------------------------- trace/trace_info/usb.toml | 18 +- 3 files changed, 130 insertions(+), 413 deletions(-) diff --git a/devices/src/scsi/bus.rs b/devices/src/scsi/bus.rs index 0b018c65..8a222653 100644 --- a/devices/src/scsi/bus.rs +++ b/devices/src/scsi/bus.rs @@ -824,7 +824,7 @@ fn scsi_cdb_lba(cdb: &[u8; SCSI_CMD_BUF_SIZE]) -> i64 { } } -pub fn scsi_cdb_xfer_mode(cdb: &[u8; SCSI_CMD_BUF_SIZE]) -> ScsiXferMode { +fn scsi_cdb_xfer_mode(cdb: &[u8; SCSI_CMD_BUF_SIZE]) -> ScsiXferMode { match cdb[0] { WRITE_6 | WRITE_10 diff --git a/devices/src/usb/uas.rs b/devices/src/usb/uas.rs index df57b0ba..3baca6a4 100644 --- a/devices/src/usb/uas.rs +++ b/devices/src/usb/uas.rs @@ -12,7 +12,7 @@ use std::array; use std::cmp::min; -use std::collections::{HashMap, VecDeque}; +use std::collections::HashMap; use std::mem::size_of; use std::sync::{Arc, Mutex, Weak}; @@ -36,9 +36,9 @@ use super::{ }; use crate::{ ScsiBus::{ - scsi_cdb_xfer, scsi_cdb_xfer_mode, ScsiBus, ScsiRequest, ScsiRequestOps, ScsiSense, - ScsiXferMode, CHECK_CONDITION, EMULATE_SCSI_OPS, GOOD, SCSI_SENSE_INVALID_PARAM_VALUE, - SCSI_SENSE_INVALID_TAG, SCSI_SENSE_NO_SENSE, SCSI_SENSE_OVERLAPPED_COMMANDS, + scsi_cdb_xfer, ScsiBus, ScsiRequest, ScsiRequestOps, ScsiSense, ScsiXferMode, + CHECK_CONDITION, EMULATE_SCSI_OPS, GOOD, SCSI_SENSE_INVALID_PARAM_VALUE, + SCSI_SENSE_INVALID_TAG, SCSI_SENSE_NO_SENSE, }, ScsiDisk::{ScsiDevConfig, ScsiDevice}, }; @@ -67,11 +67,9 @@ const UAS_IU_ID_COMMAND: u8 = 0x01; const UAS_IU_ID_SENSE: u8 = 0x03; const UAS_IU_ID_RESPONSE: u8 = 0x04; const UAS_IU_ID_TASK_MGMT: u8 = 0x05; -const UAS_IU_ID_READ_READY: u8 = 0x06; -const UAS_IU_ID_WRITE_READY: u8 = 0x07; // UAS Response Codes -const _UAS_RC_TMF_COMPLETE: u8 = 0x00; +const UAS_RC_TMF_COMPLETE: u8 = 0x00; const _UAS_RC_INVALID_IU: u8 = 0x02; const UAS_RC_TMF_NOT_SUPPORTED: u8 = 0x04; const _UAS_RC_TMF_FAILED: u8 = 0x05; @@ -80,7 +78,7 @@ const _UAS_RC_INCORRECT_LUN: u8 = 0x09; const _UAS_RC_OVERLAPPED_TAG: u8 = 0x0A; // UAS Task Management Functions -const _UAS_TMF_ABORT_TASK: u8 = 0x01; +const UAS_TMF_ABORT_TASK: u8 = 0x01; const _UAS_TMF_ABORT_TASK_SET: u8 = 0x02; const _UAS_TMF_CLEAR_TASK_SET: u8 = 0x04; const _UAS_TMF_LOGICAL_UNIT_RESET: u8 = 0x08; @@ -111,23 +109,19 @@ pub struct UsbUas { base: UsbDeviceBase, scsi_bus: Arc>, scsi_device: Arc>, - commands_high: VecDeque, - statuses_high: VecDeque>>, - commands_super: [Option; UAS_MAX_STREAMS + 1], - statuses_super: [Option>>; UAS_MAX_STREAMS + 1], + commands: [Option; UAS_MAX_STREAMS + 1], + statuses: [Option>>; UAS_MAX_STREAMS + 1], data: [Option>>; UAS_MAX_STREAMS + 1], - data_ready_sent: bool, } -#[derive(Debug, EnumCount)] +#[derive(Debug, Default, EnumCount)] enum UsbUasStringId { - #[allow(unused)] + #[default] Invalid = 0, Manufacturer = 1, Product = 2, SerialNumber = 3, - ConfigHigh = 4, - ConfigSuper = 5, + Configuration = 4, } const UAS_DESC_STRINGS: [&str; UsbUasStringId::COUNT] = [ @@ -135,7 +129,6 @@ const UAS_DESC_STRINGS: [&str; UsbUasStringId::COUNT] = [ "StratoVirt", "StratoVirt USB Uas", "5", - "High speed config (usb 2.0)", "Super speed config (usb 3.0)", ]; @@ -154,7 +147,7 @@ impl ScsiRequestOps for UasRequest { ) -> Result<()> { let tag = u16::from_be(self.iu.header.tag); let sense = scsi_sense.unwrap_or(SCSI_SENSE_NO_SENSE); - UsbUas::fill_sense(&mut self.status.lock().unwrap(), tag, scsi_status, &sense); + UsbUas::fill_sense(&mut self.status.lock().unwrap(), tag, sense, scsi_status); self.complete(); Ok(()) } @@ -260,7 +253,7 @@ struct UasIU { impl ByteCode for UasIU {} -static DESC_DEVICE_UAS_SUPER: Lazy> = Lazy::new(|| { +static DESC_DEVICE_UAS: Lazy> = Lazy::new(|| { Arc::new(UsbDescDevice { device_desc: UsbDeviceDescriptor { bLength: USB_DT_DEVICE_SIZE, @@ -285,17 +278,17 @@ static DESC_DEVICE_UAS_SUPER: Lazy> = Lazy::new(|| { wTotalLength: 0, bNumInterfaces: 1, bConfigurationValue: 1, - iConfiguration: UsbUasStringId::ConfigSuper as u8, + iConfiguration: UsbUasStringId::Configuration as u8, bmAttributes: USB_CONFIGURATION_ATTR_ONE | USB_CONFIGURATION_ATTR_SELF_POWER, bMaxPower: 50, }, iad_desc: vec![], - interfaces: vec![DESC_IFACE_EMPTY.clone(), DESC_IFACE_UAS_SUPER.clone()], + interfaces: vec![DESC_IFACE_BOT.clone(), DESC_IFACE_UAS.clone()], })], }) }); -static DESC_IFACE_UAS_SUPER: Lazy> = Lazy::new(|| { +static DESC_IFACE_UAS: Lazy> = Lazy::new(|| { Arc::new(UsbDescIface { interface_desc: UsbInterfaceDescriptor { bLength: USB_DT_INTERFACE_SIZE, @@ -430,136 +423,10 @@ static DESC_IFACE_UAS_SUPER: Lazy> = Lazy::new(|| { }) }); -static DESC_DEVICE_UAS_HIGH: Lazy> = Lazy::new(|| { - Arc::new(UsbDescDevice { - device_desc: UsbDeviceDescriptor { - bLength: USB_DT_DEVICE_SIZE, - bDescriptorType: USB_DT_DEVICE, - bcdUSB: 0x0200, - bDeviceClass: 0, - bDeviceSubClass: 0, - bDeviceProtocol: 0, - bMaxPacketSize0: 64, - idVendor: USB_VENDOR_ID_STRATOVIRT, - idProduct: USB_PRODUCT_ID_UAS, - bcdDevice: 0, - iManufacturer: UsbUasStringId::Manufacturer as u8, - iProduct: UsbUasStringId::Product as u8, - iSerialNumber: UsbUasStringId::SerialNumber as u8, - bNumConfigurations: 1, - }, - configs: vec![Arc::new(UsbDescConfig { - config_desc: UsbConfigDescriptor { - bLength: USB_DT_CONFIG_SIZE, - bDescriptorType: USB_DT_CONFIGURATION, - wTotalLength: 0, - bNumInterfaces: 1, - bConfigurationValue: 1, - iConfiguration: UsbUasStringId::ConfigHigh as u8, - bmAttributes: USB_CONFIGURATION_ATTR_ONE | USB_CONFIGURATION_ATTR_SELF_POWER, - bMaxPower: 50, - }, - iad_desc: vec![], - interfaces: vec![DESC_IFACE_EMPTY.clone(), DESC_IFACE_UAS_HIGH.clone()], - })], - }) -}); - -static DESC_IFACE_UAS_HIGH: Lazy> = Lazy::new(|| { - Arc::new(UsbDescIface { - interface_desc: UsbInterfaceDescriptor { - bLength: USB_DT_INTERFACE_SIZE, - bDescriptorType: USB_DT_INTERFACE, - bInterfaceNumber: 0, - bAlternateSetting: 1, - bNumEndpoints: 4, - bInterfaceClass: USB_CLASS_MASS_STORAGE, - bInterfaceSubClass: USB_SUBCLASS_SCSI, - bInterfaceProtocol: USB_IFACE_PROTOCOL_UAS, - iInterface: 0, - }, - other_desc: vec![], - endpoints: vec![ - Arc::new(UsbDescEndpoint { - endpoint_desc: UsbEndpointDescriptor { - bLength: USB_DT_ENDPOINT_SIZE, - bDescriptorType: USB_DT_ENDPOINT, - bEndpointAddress: USB_DIRECTION_HOST_TO_DEVICE | UAS_PIPE_ID_COMMAND, - bmAttributes: USB_ENDPOINT_ATTR_BULK, - wMaxPacketSize: 512, - bInterval: 0, - }, - extra: UsbPipeUsageDescriptor { - bLength: USB_DT_PIPE_USAGE_SIZE, - bDescriptorType: USB_DT_PIPE_USAGE, - bPipeId: UAS_PIPE_ID_COMMAND, - bReserved: 0, - } - .as_bytes() - .to_vec(), - }), - Arc::new(UsbDescEndpoint { - endpoint_desc: UsbEndpointDescriptor { - bLength: USB_DT_ENDPOINT_SIZE, - bDescriptorType: USB_DT_ENDPOINT, - bEndpointAddress: USB_DIRECTION_DEVICE_TO_HOST | UAS_PIPE_ID_STATUS, - bmAttributes: USB_ENDPOINT_ATTR_BULK, - wMaxPacketSize: 512, - bInterval: 0, - }, - extra: UsbPipeUsageDescriptor { - bLength: USB_DT_PIPE_USAGE_SIZE, - bDescriptorType: USB_DT_PIPE_USAGE, - bPipeId: UAS_PIPE_ID_STATUS, - bReserved: 0, - } - .as_bytes() - .to_vec(), - }), - Arc::new(UsbDescEndpoint { - endpoint_desc: UsbEndpointDescriptor { - bLength: USB_DT_ENDPOINT_SIZE, - bDescriptorType: USB_DT_ENDPOINT, - bEndpointAddress: USB_DIRECTION_DEVICE_TO_HOST | UAS_PIPE_ID_DATA_IN, - bmAttributes: USB_ENDPOINT_ATTR_BULK, - wMaxPacketSize: 512, - bInterval: 0, - }, - extra: UsbPipeUsageDescriptor { - bLength: USB_DT_PIPE_USAGE_SIZE, - bDescriptorType: USB_DT_PIPE_USAGE, - bPipeId: UAS_PIPE_ID_DATA_IN, - bReserved: 0, - } - .as_bytes() - .to_vec(), - }), - Arc::new(UsbDescEndpoint { - endpoint_desc: UsbEndpointDescriptor { - bLength: USB_DT_ENDPOINT_SIZE, - bDescriptorType: USB_DT_ENDPOINT, - bEndpointAddress: USB_DIRECTION_HOST_TO_DEVICE | UAS_PIPE_ID_DATA_OUT, - bmAttributes: USB_ENDPOINT_ATTR_BULK, - wMaxPacketSize: 512, - bInterval: 0, - }, - extra: UsbPipeUsageDescriptor { - bLength: USB_DT_PIPE_USAGE_SIZE, - bDescriptorType: USB_DT_PIPE_USAGE, - bPipeId: UAS_PIPE_ID_DATA_OUT, - bReserved: 0, - } - .as_bytes() - .to_vec(), - }), - ], - }) -}); - // NOTE: Fake BOT interface descriptor is needed here since Windows UASP driver always expects two // interfaces: both BOT and UASP. It also anticipates the UASP descriptor to be the second one. // Therefore, the first one can be a BOT storage stub. -static DESC_IFACE_EMPTY: Lazy> = Lazy::new(|| { +static DESC_IFACE_BOT: Lazy> = Lazy::new(|| { Arc::new(UsbDescIface { interface_desc: UsbInterfaceDescriptor { bLength: USB_DT_INTERFACE_SIZE, @@ -604,18 +471,8 @@ impl UsbUas { ..Default::default() }; - let mut base = UsbDeviceBase::new( - uas_config.id.clone().unwrap(), - USB_DEVICE_BUFFER_DEFAULT_LEN, - ); - - base.speed = match uas_config.speed.as_deref() { - Some("super") => USB_SPEED_SUPER, - _ => USB_SPEED_HIGH, - }; - Self { - base, + base: UsbDeviceBase::new(uas_config.id.unwrap(), USB_DEVICE_BUFFER_DEFAULT_LEN), scsi_bus: Arc::new(Mutex::new(ScsiBus::new("".to_string()))), scsi_device: Arc::new(Mutex::new(ScsiDevice::new( scsi_dev_cfg, @@ -623,68 +480,16 @@ impl UsbUas { drive_files, None, ))), - commands_high: VecDeque::new(), - commands_super: array::from_fn(|_| None), - statuses_high: VecDeque::new(), - statuses_super: array::from_fn(|_| None), + commands: array::from_fn(|_| None), + statuses: array::from_fn(|_| None), data: array::from_fn(|_| None), - data_ready_sent: false, } } - fn streams_enabled(&self) -> bool { - self.base.speed == USB_SPEED_SUPER - } - fn cancel_io(&mut self) { - self.commands_high = VecDeque::new(); - self.commands_super = array::from_fn(|_| None); - self.statuses_high = VecDeque::new(); - self.statuses_super = array::from_fn(|_| None); + self.commands = array::from_fn(|_| None); + self.statuses = array::from_fn(|_| None); self.data = array::from_fn(|_| None); - self.data_ready_sent = false; - } - - fn peek_next_status(&self, stream: usize) -> Option<&Arc>> { - match self.streams_enabled() { - true => self.statuses_super[stream].as_ref(), - false => self.statuses_high.front(), - } - } - - fn take_next_status(&mut self, stream: usize) -> Arc> { - match self.streams_enabled() { - true => self.statuses_super[stream].take().unwrap(), - false => self.statuses_high.pop_front().unwrap(), - } - } - - fn queue_status(&mut self, status: &Arc>, stream: usize) { - match self.streams_enabled() { - true => self.statuses_super[stream] = Some(Arc::clone(status)), - false => self.statuses_high.push_back(Arc::clone(status)), - }; - } - - fn peek_next_command(&self, stream: usize) -> Option<&UasIU> { - match self.streams_enabled() { - true => self.commands_super[stream].as_ref(), - false => self.commands_high.front(), - } - } - - fn take_next_command(&mut self, stream: usize) -> UasIU { - match self.streams_enabled() { - true => self.commands_super[stream].take().unwrap(), - false => self.commands_high.pop_front().unwrap(), - } - } - - fn queue_command(&mut self, command: UasIU, stream: usize) { - match self.streams_enabled() { - true => self.commands_super[stream] = Some(command), - false => self.commands_high.push_back(command), - } } fn handle_iu_command( @@ -692,7 +497,7 @@ impl UsbUas { iu: &UasIU, mut uas_request: UasRequest, ) -> Result { - // SAFETY: iu is guaranteed to be of type command + // SAFETY: IU is guaranteed to be of type command. let add_cdb_len = unsafe { iu.body.command.add_cdb_len }; let tag = u16::from_be(iu.header.tag); @@ -700,33 +505,23 @@ impl UsbUas { Self::fill_fake_sense( &mut uas_request.status.lock().unwrap(), tag, - &SCSI_SENSE_INVALID_PARAM_VALUE, + SCSI_SENSE_INVALID_PARAM_VALUE, ); uas_request.complete(); bail!("additional cdb length is not supported"); } - if self.streams_enabled() && tag > UAS_MAX_STREAMS as u16 { + if tag > UAS_MAX_STREAMS as u16 { Self::fill_fake_sense( &mut uas_request.status.lock().unwrap(), tag, - &SCSI_SENSE_INVALID_TAG, + SCSI_SENSE_INVALID_TAG, ); uas_request.complete(); bail!("invalid tag {}", tag); } - if self.streams_enabled() && self.commands_super[tag as usize].is_some() { - Self::fill_fake_sense( - &mut uas_request.status.lock().unwrap(), - tag, - &SCSI_SENSE_OVERLAPPED_COMMANDS, - ); - uas_request.complete(); - bail!("overlapped tag {}", tag); - } - - let (scsi_iovec, scsi_iovec_size) = match uas_request.data.as_ref() { + let (scsi_iovec, scsi_iovec_size) = match &uas_request.data { Some(data) => { let mut locked_data = data.lock().unwrap(); let iov_size = locked_data.get_iovecs_size() as u32; @@ -736,9 +531,9 @@ impl UsbUas { None => (Vec::new(), 0), }; - // SAFETY: iu is guaranteed to of type command + // SAFETY: IU is guaranteed to of type command. let cdb = unsafe { iu.body.command.cdb }; - // SAFETY: iu is guaranteed to of type command + // SAFETY: IU is guaranteed to of type command. let lun = unsafe { iu.body.command.lun } as u16; trace::usb_uas_handle_iu_command(self.device_id(), cdb[0]); let uas_request = Box::new(uas_request); @@ -750,7 +545,7 @@ impl UsbUas { Arc::clone(&self.scsi_device), uas_request, ) - .with_context(|| "Failed to create SCSI request.")?; + .with_context(|| "failed to create SCSI request")?; if scsi_request.cmd.xfer > scsi_request.datalen && scsi_request.cmd.mode != ScsiXferMode::ScsiXferNone @@ -766,7 +561,7 @@ impl UsbUas { EMULATE_SCSI_OPS => scsi_request.emulate_execute(), _ => scsi_request.execute(), } - .with_context(|| "Failed to execute SCSI request.")?; + .with_context(|| "failed to execute SCSI request")?; let upper_request = &mut scsi_request.lock().unwrap().upper_req; let uas_request = upper_request @@ -785,31 +580,34 @@ impl UsbUas { ) -> Result { let tag = u16::from_be(iu.header.tag); - if self.streams_enabled() && tag > UAS_MAX_STREAMS as u16 { + if tag > UAS_MAX_STREAMS as u16 { Self::fill_fake_sense( &mut uas_request.status.lock().unwrap(), tag, - &SCSI_SENSE_INVALID_TAG, + SCSI_SENSE_INVALID_TAG, ); uas_request.complete(); bail!("invalid tag {}", tag); } - if self.streams_enabled() && self.commands_super[tag as usize].is_some() { - Self::fill_fake_sense( - &mut uas_request.status.lock().unwrap(), - tag, - &SCSI_SENSE_OVERLAPPED_COMMANDS, - ); - uas_request.complete(); - bail!("overlapped tag {}", tag); - } - - // SAFETY: iu is guaranteed to be of type task management + // SAFETY: IU is guaranteed to be of type task management. let tmf = unsafe { iu.body.task_management.function }; + trace::usb_uas_handle_iu_task_management(self.device_id(), tmf, tag); - #[allow(clippy::match_single_binding)] match tmf { + UAS_TMF_ABORT_TASK => { + // SAFETY: IU is guaranteed to be of type task management. + let task_tag = unsafe { iu.body.task_management.task_tag } as usize; + self.commands[task_tag] = None; + self.statuses[task_tag] = None; + self.data[task_tag] = None; + trace::usb_uas_tmf_abort_task(self.device_id(), task_tag); + Self::fill_response( + &mut uas_request.status.lock().unwrap(), + tag, + UAS_RC_TMF_COMPLETE, + ); + } _ => { warn!("UAS {} device unsupported TMF {}.", self.device_id(), tmf); Self::fill_response( @@ -831,34 +629,9 @@ impl UsbUas { Self::fill_packet(packet, &mut iu, iu_len); } - fn fill_sense(packet: &mut UsbPacket, tag: u16, status: u8, sense: &ScsiSense) { + fn fill_fake_sense(packet: &mut UsbPacket, tag: u16, sense: ScsiSense) { let mut iu = UasIU::new(UAS_IU_ID_SENSE, tag); - // SAFETY: iu is guaranteed to be of type status - let iu_sense = unsafe { &mut iu.body.sense }; - - iu_sense.status = status; - iu_sense.status_qualifier = 0_u16.to_be(); - iu_sense.sense_length = 0_u16.to_be(); - - if status != GOOD { - iu_sense.sense_length = 18_u16.to_be(); - iu_sense.sense_data[0] = 0x71; // Error code: deferred errors - iu_sense.sense_data[2] = sense.key; - iu_sense.sense_data[7] = 10; // Additional sense length: total length - 8 - iu_sense.sense_data[12] = sense.asc; - iu_sense.sense_data[13] = sense.ascq; - } - - let sense_len = iu_sense.sense_length as usize; - let real_sense_len = size_of::() - iu_sense.sense_data.len() + sense_len; - let iu_len = size_of::() + real_sense_len; - trace::usb_uas_fill_sense(status, iu_len, sense_len); - Self::fill_packet(packet, &mut iu, iu_len); - } - - fn fill_fake_sense(packet: &mut UsbPacket, tag: u16, sense: &ScsiSense) { - let mut iu = UasIU::new(UAS_IU_ID_SENSE, tag); - // SAFETY: iu is guaranteed to be of type status + // SAFETY: IU is guaranteed to be of type status. let iu_sense = unsafe { &mut iu.body.sense }; iu_sense.status = CHECK_CONDITION; @@ -871,19 +644,32 @@ impl UsbUas { iu_sense.sense_data[13] = sense.ascq; let iu_len = size_of::() + size_of::(); - trace::usb_uas_fill_fake_sense(CHECK_CONDITION, iu_len, 18); + trace::usb_uas_fill_fake_sense(CHECK_CONDITION, iu_len, iu_sense.sense_length as usize); Self::fill_packet(packet, &mut iu, iu_len); } - fn fill_read_ready(packet: &mut UsbPacket, tag: u16) { - let mut iu = UasIU::new(UAS_IU_ID_READ_READY, tag); - let iu_len = size_of::(); - Self::fill_packet(packet, &mut iu, iu_len); - } + fn fill_sense(packet: &mut UsbPacket, tag: u16, sense: ScsiSense, status: u8) { + let mut iu = UasIU::new(UAS_IU_ID_SENSE, tag); + // SAFETY: IU is guaranteed to be of type status. + let iu_sense = unsafe { &mut iu.body.sense }; - fn fill_write_ready(packet: &mut UsbPacket, tag: u16) { - let mut iu = UasIU::new(UAS_IU_ID_WRITE_READY, tag); - let iu_len = size_of::(); + iu_sense.status = status; + iu_sense.status_qualifier = 0_u16.to_be(); + iu_sense.sense_length = 0_u16.to_be(); + + if status != GOOD { + iu_sense.sense_length = 18_u16.to_be(); + iu_sense.sense_data[0] = 0x71; // Error code: deferred errors + iu_sense.sense_data[2] = sense.key; + iu_sense.sense_data[7] = 10; // Additional sense length: total length - 8 + iu_sense.sense_data[12] = sense.asc; + iu_sense.sense_data[13] = sense.ascq; + } + + let sense_len = + size_of::() - iu_sense.sense_data.len() + iu_sense.sense_length as usize; + let iu_len = size_of::() + sense_len; + trace::usb_uas_fill_sense(status, iu_len, iu_sense.sense_length as usize); Self::fill_packet(packet, &mut iu, iu_len); } @@ -895,115 +681,52 @@ impl UsbUas { } fn try_start_next_transfer(&mut self, stream: usize) -> UasPacketStatus { - let command = self.peek_next_command(stream); - - if let Some(command) = command { - // SAFETY: iu is guaranteed to be of type command - let cdb = unsafe { &command.body.command.cdb }; - let xfer_len = scsi_cdb_xfer(cdb, Arc::clone(&self.scsi_device)); - trace::usb_uas_try_start_next_transfer(self.device_id(), xfer_len); - - if xfer_len > 0 { - self.try_start_next_data(stream) - } else { - self.try_start_next_non_data(stream) - } - } else { + if self.commands[stream].is_none() { debug!( - "UAS {} device no inflight command when trying to start the next transfer.", - self.device_id() + "UAS {} device no inflight command on stream {}.", + self.device_id(), + stream ); - UasPacketStatus::Pending + return UasPacketStatus::Pending; } - } - fn try_start_next_data(&mut self, stream: usize) -> UasPacketStatus { - let status = self.peek_next_status(stream); - - if status.is_none() { + if self.statuses[stream].is_none() { debug!( - "UAS {} device no inflight status when trying to start the next data transfer.", - self.device_id() + "UAS {} device no inflight status on stream {}.", + self.device_id(), + stream ); return UasPacketStatus::Pending; } - if !self.data_ready_sent { - return self.fill_data_ready(stream); + // SAFETY: Command was checked to be Some. + let command = self.commands[stream].as_ref().unwrap(); + // SAFETY: IU is guaranteed to be of type command. + let cdb = unsafe { &command.body.command.cdb }; + let xfer_len = scsi_cdb_xfer(cdb, Arc::clone(&self.scsi_device)); + trace::usb_uas_try_start_next_transfer(self.device_id(), xfer_len); + + if xfer_len == 0 { + return self.start_next_transfer(stream); } if self.data[stream].is_some() { self.start_next_transfer(stream) } else { debug!( - "UAS {} device no inflight data when trying to start the next data transfer.", - self.device_id() + "UAS {} device no inflight data on stream {}.", + self.device_id(), + stream ); UasPacketStatus::Pending } } - fn fill_data_ready(&mut self, stream: usize) -> UasPacketStatus { - // SAFETY: status must have been checked in try_start_next_data - let status = self.take_next_status(stream); - let mut locked_status = status.lock().unwrap(); - - // SAFETY: command must have been checked in try_start_next_transfer - let iu = self.peek_next_command(stream).unwrap(); - let tag = u16::from_be(iu.header.tag); - - // SAFETY: iu is guaranteed to be of type command - let cdb = unsafe { &iu.body.command.cdb }; - let xfer_mode = scsi_cdb_xfer_mode(cdb); - - match xfer_mode { - ScsiXferMode::ScsiXferFromDev => Self::fill_read_ready(&mut locked_status, tag), - ScsiXferMode::ScsiXferToDev => Self::fill_write_ready(&mut locked_status, tag), - ScsiXferMode::ScsiXferNone => { - warn!( - "UAS {} device cannot fill data ready, operation {} is not a data transfer.", - self.device_id(), - cdb[0] - ); - Self::fill_fake_sense(&mut locked_status, tag, &SCSI_SENSE_INVALID_PARAM_VALUE); - } - } - - let status_async = locked_status.is_async; - drop(locked_status); - - if status_async { - complete_async_packet(&status); - } - - self.data_ready_sent = true; - trace::usb_uas_fill_data_ready(self.device_id(), self.data_ready_sent); - UasPacketStatus::Completed - } - - fn try_start_next_non_data(&mut self, stream: usize) -> UasPacketStatus { - let status = self.peek_next_status(stream); - - if status.is_none() { - debug!( - "UAS {} device no inflight status when trying to start the next non-data transfer.", - self.device_id() - ); - return UasPacketStatus::Pending; - } - - self.start_next_transfer(stream) - } - fn start_next_transfer(&mut self, stream: usize) -> UasPacketStatus { trace::usb_uas_start_next_transfer(self.device_id(), stream); - - // SAFETY: status must have been checked in try_start_next_data or try_start_next_non_data - let status = self.take_next_status(stream); - - // SAFETY: command must have been checked in try_start_next_transfer - let command = self.take_next_command(stream); - + // SAFETY: Status and command must have been checked in try_start_next_transfer. + let status = self.statuses[stream].take().unwrap(); + let command = self.commands[stream].take().unwrap(); let mut uas_request = UasRequest::new(&status, &command); uas_request.data = self.data[stream].take(); @@ -1013,9 +736,6 @@ impl UsbUas { _ => Err(anyhow!("impossible command IU {}", command.header.id)), }; - self.data_ready_sent = false; - self.try_start_next_transfer(stream); - match result { Ok(result) => result, Err(err) => { @@ -1032,21 +752,11 @@ impl UsbDevice for UsbUas { fn realize(mut self) -> Result>> { info!("UAS {} device realize.", self.device_id()); self.base.reset_usb_endpoint(); - let mut desc_strings: Vec = - UAS_DESC_STRINGS.iter().map(|str| str.to_string()).collect(); - let prefix = &desc_strings[UsbUasStringId::SerialNumber as usize]; - desc_strings[UsbUasStringId::SerialNumber as usize] = - self.base.generate_serial_number(prefix); - - match self.base.speed { - USB_SPEED_HIGH => self - .base - .init_descriptor(DESC_DEVICE_UAS_HIGH.clone(), desc_strings)?, - USB_SPEED_SUPER => self - .base - .init_descriptor(DESC_DEVICE_UAS_SUPER.clone(), desc_strings)?, - _ => bail!("USB UAS unsupported device speed {}.", self.base.speed), - } + self.base.speed = USB_SPEED_SUPER; + let mut s: Vec = UAS_DESC_STRINGS.iter().map(|&s| s.to_string()).collect(); + let prefix = &s[UsbUasStringId::SerialNumber as usize]; + s[UsbUasStringId::SerialNumber as usize] = self.base.generate_serial_number(prefix); + self.base.init_descriptor(DESC_DEVICE_UAS.clone(), s)?; // NOTE: "aio=off,direct=false" must be configured and other aio/direct values are not // supported. @@ -1122,7 +832,7 @@ impl UsbDevice for UsbUas { trace::usb_uas_handle_data(self.device_id(), ep_number, stream); drop(locked_packet); - if self.streams_enabled() && (stream > UAS_MAX_STREAMS || stream == 0) { + if stream > UAS_MAX_STREAMS || ep_number != UAS_PIPE_ID_COMMAND && stream == 0 { warn!("UAS {} device invalid stream {}.", self.device_id(), stream); packet.lock().unwrap().status = UsbPacketStatus::Stall; return; @@ -1130,7 +840,7 @@ impl UsbDevice for UsbUas { // NOTE: The architecture of this device is rather simple: it first waits for all of the // required USB packets to arrive, and only then creates and sends an actual UAS request. - // The number of USB packets differs from 2 to 4 and depends on whether the command involves + // The number of USB packets differs from 2 to 3 and depends on whether the command involves // data transfers or not. Since the packets arrive in arbitrary order, some of them may be // queued asynchronously. Note that the command packet is always completed right away. For // all the other types of packets, their asynchronous status is determined by the return @@ -1138,7 +848,14 @@ impl UsbDevice for UsbUas { // completed in scsi_request_complete_cb() callback. match ep_number { UAS_PIPE_ID_COMMAND => { - if self.streams_enabled() && self.commands_super[stream].is_some() { + let mut locked_packet = packet.lock().unwrap(); + let mut iu = UasIU::default(); + let iov_size = locked_packet.get_iovecs_size() as usize; + let iu_len = min(iov_size, size_of::()); + locked_packet.transfer_packet(iu.as_mut_bytes(), iu_len); + let stream = u16::from_be(iu.header.tag) as usize; + + if self.commands[stream].is_some() { warn!( "UAS {} device multiple command packets on stream {}.", self.device_id(), @@ -1148,19 +865,13 @@ impl UsbDevice for UsbUas { return; } - let mut locked_packet = packet.lock().unwrap(); - let mut iu = UasIU::default(); - let iov_size = locked_packet.get_iovecs_size() as usize; - let iu_len = min(iov_size, size_of::()); - locked_packet.transfer_packet(iu.as_mut_bytes(), iu_len); - trace::usb_uas_command_received(packet_id, self.device_id()); - self.queue_command(iu, stream); + self.commands[stream] = Some(iu); self.try_start_next_transfer(stream); trace::usb_uas_command_completed(packet_id, self.device_id()); } UAS_PIPE_ID_STATUS => { - if self.streams_enabled() && self.statuses_super[stream].is_some() { + if self.statuses[stream].is_some() { warn!( "UAS {} device multiple status packets on stream {}.", self.device_id(), @@ -1171,7 +882,7 @@ impl UsbDevice for UsbUas { } trace::usb_uas_status_received(packet_id, self.device_id()); - self.queue_status(packet, stream); + self.statuses[stream] = Some(Arc::clone(packet)); let result = self.try_start_next_transfer(stream); match result { @@ -1219,7 +930,7 @@ impl UsbDevice for UsbUas { } } - fn set_controller(&mut self, _controller: std::sync::Weak>) {} + fn set_controller(&mut self, _cntlr: std::sync::Weak>) {} fn get_controller(&self) -> Option>> { None @@ -1246,9 +957,9 @@ impl UasRequest { // NOTE: Due to the specifics of this device, it waits for all of the required USB packets // to arrive before starting an actual transfer. Therefore, some packets may arrive earlier - // than others, and they won't be completed right away (except for command packets) but + // than others, and they won't be completed right away (except for the command packets), but // rather queued asynchronously. A certain packet may also be async if it was the last to - // arrive and UasRequest didn't complete right away. + // arrive, but UasRequest didn't complete right away. if status_async { complete_async_packet(status); } diff --git a/trace/trace_info/usb.toml b/trace/trace_info/usb.toml index 82991ed6..cabcf6ca 100644 --- a/trace/trace_info/usb.toml +++ b/trace/trace_info/usb.toml @@ -532,12 +532,6 @@ args = "device_id: &str, xfer_len: i32" message = "UAS {} device is trying to start next transfer of length {}." enabled = true -[[events]] -name = "usb_uas_fill_data_ready" -args = "device_id: &str, data_ready_sent: bool" -message = "UAS {} device set data_ready_sent to {}." -enabled = true - [[events]] name = "usb_uas_start_next_transfer" args = "device_id: &str, stream: usize" @@ -597,3 +591,15 @@ name = "usb_uas_data_queued_async" args = "packet_id: u32, device_id: &str" message = "USB {} data packet queued async on UAS {} device." enabled = true + +[[events]] +name = "usb_uas_handle_iu_task_management" +args = "device_id: &str, tmf: u8, tag: u16" +message = "UAS {} device handling TMF {} with tag {}." +enabled = true + +[[events]] +name = "usb_uas_tmf_abort_task" +args = "device_id: &str, task_tag: usize" +message = "UAS {} device aborting task with tag {}." +enabled = true -- Gitee From 5b17ac99c3a57a9350212a83c45af7b15d5585b2 Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Thu, 4 Apr 2024 15:08:47 +0300 Subject: [PATCH 179/489] usb: Remove obsolete code responsible for qualifier descriptors Qualifier decriptor is constructed implicitly at the moment of get_device_qualifier_descriptor call. Therefore, there is no need to store it explicitly anymore. Signed-off-by: goriainovstanislav --- devices/src/usb/descriptor.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/devices/src/usb/descriptor.rs b/devices/src/usb/descriptor.rs index ca4c51e7..3864464d 100644 --- a/devices/src/usb/descriptor.rs +++ b/devices/src/usb/descriptor.rs @@ -165,11 +165,6 @@ pub struct UsbDescDevice { pub configs: Vec>, } -/// USB device qualifier descriptor. -pub struct UsbDescDeviceQualifier { - pub qualifier_desc: UsbDeviceQualifierDescriptor, -} - /// USB config descriptor. pub struct UsbDescConfig { pub config_desc: UsbConfigDescriptor, @@ -221,7 +216,6 @@ pub struct UsbDescEndpoint { /// USB Descriptor. pub struct UsbDescriptor { pub device_desc: Option>, - pub device_qualifier_desc: Option>, pub configuration_selected: Option>, pub interfaces: Vec>>, pub altsetting: Vec, @@ -233,7 +227,6 @@ impl UsbDescriptor { pub fn new() -> Self { Self { device_desc: None, - device_qualifier_desc: None, configuration_selected: None, interfaces: vec![None; USB_MAX_INTERFACES as usize], altsetting: vec![0; USB_MAX_INTERFACES as usize], -- Gitee From 12cb38568753a3bb2e1668acb3e3ec2d3a9c04ac Mon Sep 17 00:00:00 2001 From: Dmitry Skorodumov Date: Mon, 8 Jul 2024 21:27:01 +0300 Subject: [PATCH 180/489] This is a temporary fix for PL011 send workflow The commit 1bf12724299717962661f947656aa8b5865583f4 introduces mechanic that works fine with virtio-serial. Unfortunately, it doesn't work with pl011 and breaks windbg. To use this mechanic with pl011, much more actions are required: we need properly return Send-FIFO_FULL/FIFO_EMPTY. We need properly signal INT_TX interrupt etc. The work for proper fix is in progress. Implement simple workaround so far: just send all the data synchronously if listener_fd is None. This will allow work with non-corrected PL011, which always reports that send-FIFO is empty and alway can accept data from guest to send out. Signed-off-by: Dmitry Skorodumov --- chardev_backend/src/chardev.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/chardev_backend/src/chardev.rs b/chardev_backend/src/chardev.rs index bd2b37db..8b065f99 100644 --- a/chardev_backend/src/chardev.rs +++ b/chardev_backend/src/chardev.rs @@ -273,11 +273,14 @@ impl Chardev { } return write_buffer_sync(self.output.as_ref().unwrap().clone(), buf); } - ChardevType::Socket { .. } => (), - } - - if self.output.is_none() { - return Ok(()); + ChardevType::Socket { .. } => { + if self.output.is_none() { + return Ok(()); + } + if listener_fd.is_none() { + return write_buffer_sync(self.output.as_ref().unwrap().clone(), buf); + } + } } if self.outbuf_is_full() { -- Gitee From 956ecfca1a3fa1ee1054956d4466dc4674f23af4 Mon Sep 17 00:00:00 2001 From: Mingwang Li Date: Mon, 8 Jul 2024 19:50:19 +0800 Subject: [PATCH 181/489] Machine: the Mutex lock of vm is changed to RwLock When lifecycle operations are performed on a VM, a deadlock may occur on the VM. Therefore, the VM lock is changed to the read/write lock. Signed-off-by: Mingwang Li --- cpu/src/lib.rs | 16 +++++----- .../src/interrupt_controller/aarch64/gicv3.rs | 2 +- .../src/interrupt_controller/aarch64/mod.rs | 6 ++-- hypervisor/src/kvm/mod.rs | 14 ++++----- machine/src/aarch64/micro.rs | 6 ++-- machine/src/aarch64/standard.rs | 10 +++---- machine/src/lib.rs | 30 +++++++++---------- machine/src/micro_common/mod.rs | 2 +- machine/src/standard_common/mod.rs | 18 +++++------ machine/src/x86_64/micro.rs | 6 ++-- machine/src/x86_64/standard.rs | 22 +++++++------- machine_manager/src/event_loop.rs | 4 +-- machine_manager/src/machine.rs | 2 +- machine_manager/src/qmp/qmp_socket.rs | 21 ++++++------- machine_manager/src/test_server.rs | 18 +++++------ migration/src/general.rs | 2 +- migration/src/manager.rs | 4 +-- migration/src/migration.rs | 4 +-- src/main.rs | 12 ++++---- util/src/loop_context.rs | 12 ++++---- 20 files changed, 107 insertions(+), 104 deletions(-) diff --git a/cpu/src/lib.rs b/cpu/src/lib.rs index 7a116295..3c3f3f0d 100644 --- a/cpu/src/lib.rs +++ b/cpu/src/lib.rs @@ -63,7 +63,7 @@ pub use x86_64::X86RegsIndex as RegsIndex; use std::cell::RefCell; use std::sync::atomic::{fence, AtomicBool, Ordering}; -use std::sync::{Arc, Barrier, Condvar, Mutex, Weak}; +use std::sync::{Arc, Barrier, Condvar, Mutex, RwLock, Weak}; use std::thread; use anyhow::{anyhow, Context, Result}; @@ -216,7 +216,7 @@ pub struct CPU { /// The thread tid of this VCPU. tid: Arc>>, /// The VM combined by this VCPU. - vm: Weak>, + vm: Weak>, /// The state backup of architecture CPU right before boot. boot_state: Arc>, /// Sync the pause state of vCPU in hypervisor and userspace. @@ -238,7 +238,7 @@ impl CPU { hypervisor_cpu: Arc, id: u8, arch_cpu: Arc>, - vm: Arc>, + vm: Arc>, ) -> Self { CPU { id, @@ -294,7 +294,7 @@ impl CPU { &self.hypervisor_cpu } - pub fn vm(&self) -> Weak> { + pub fn vm(&self) -> Weak> { self.vm.clone() } @@ -404,15 +404,15 @@ impl CPUInterface for CPU { fn guest_shutdown(&self) -> Result<()> { if let Some(vm) = self.vm.upgrade() { - let shutdown_act = vm.lock().unwrap().get_shutdown_action(); + let shutdown_act = vm.read().unwrap().get_shutdown_action(); match shutdown_act { ShutdownActionPoweroff => { let (cpu_state, _) = &*self.state; *cpu_state.lock().unwrap() = CpuLifecycleState::Stopped; - vm.lock().unwrap().destroy(); + vm.read().unwrap().destroy(); } ShutdownActionPause => { - vm.lock().unwrap().pause(); + vm.read().unwrap().pause(); } } } else { @@ -434,7 +434,7 @@ impl CPUInterface for CPU { if let Some(vm) = self.vm.upgrade() { let (cpu_state, _) = &*self.state; *cpu_state.lock().unwrap() = CpuLifecycleState::Paused; - vm.lock().unwrap().reset(); + vm.read().unwrap().reset(); } else { return Err(anyhow!(CpuError::NoMachineInterface)); } diff --git a/devices/src/interrupt_controller/aarch64/gicv3.rs b/devices/src/interrupt_controller/aarch64/gicv3.rs index 60babf03..26f41e22 100644 --- a/devices/src/interrupt_controller/aarch64/gicv3.rs +++ b/devices/src/interrupt_controller/aarch64/gicv3.rs @@ -338,7 +338,7 @@ impl GICDevice for GICv3 { Ok(()) } - fn reset(&self) -> Result<()> { + fn reset_state(&self) -> Result<()> { info!("Reset gicv3its"); self.reset_its_state()?; info!("Reset gicv3"); diff --git a/devices/src/interrupt_controller/aarch64/mod.rs b/devices/src/interrupt_controller/aarch64/mod.rs index ab548604..27371aba 100644 --- a/devices/src/interrupt_controller/aarch64/mod.rs +++ b/devices/src/interrupt_controller/aarch64/mod.rs @@ -73,7 +73,7 @@ pub trait GICDevice: MachineLifecycle { fn realize(&self) -> Result<()>; /// Reset 'GIC' - fn reset(&self) -> Result<()> { + fn reset_state(&self) -> Result<()> { Ok(()) } @@ -117,7 +117,9 @@ impl InterruptController { /// Reset the InterruptController pub fn reset(&self) -> Result<()> { - self.gic.reset().with_context(|| "Failed to reset GIC") + self.gic + .reset_state() + .with_context(|| "Failed to reset GIC") } /// Change `InterruptController` lifecycle state to `Stopped`. diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs index 6689e516..98dcfca4 100644 --- a/hypervisor/src/kvm/mod.rs +++ b/hypervisor/src/kvm/mod.rs @@ -419,23 +419,23 @@ impl KvmCpu { match run { #[cfg(target_arch = "x86_64")] VcpuExit::IoIn(addr, data) => { - vm.lock().unwrap().pio_in(u64::from(addr), data); + vm.read().unwrap().pio_in(u64::from(addr), data); } #[cfg(target_arch = "x86_64")] VcpuExit::IoOut(addr, data) => { #[cfg(feature = "boot_time")] capture_boot_signal(addr as u64, data); - vm.lock().unwrap().pio_out(u64::from(addr), data); + vm.read().unwrap().pio_out(u64::from(addr), data); } VcpuExit::MmioRead(addr, data) => { - vm.lock().unwrap().mmio_read(addr, data); + vm.read().unwrap().mmio_read(addr, data); } VcpuExit::MmioWrite(addr, data) => { #[cfg(all(target_arch = "aarch64", feature = "boot_time"))] capture_boot_signal(addr, data); - vm.lock().unwrap().mmio_write(addr, data); + vm.read().unwrap().mmio_write(addr, data); } #[cfg(target_arch = "x86_64")] VcpuExit::Hlt => { @@ -919,7 +919,7 @@ impl MsiIrqManager for KVMInterruptManager { #[cfg(test)] mod test { - use std::sync::{Arc, Mutex}; + use std::sync::{Arc, Mutex, RwLock}; use std::time::Duration; #[cfg(target_arch = "x86_64")] @@ -1002,7 +1002,7 @@ mod test { return; } - let vm = Arc::new(Mutex::new(TestVm::new())); + let vm = Arc::new(RwLock::new(TestVm::new())); let code_seg = kvm_segment { base: 0, @@ -1118,7 +1118,7 @@ mod test { vcpu_fd, )); - let vm = Arc::new(Mutex::new(TestVm::new())); + let vm = Arc::new(RwLock::new(TestVm::new())); let cpu = CPU::new( hypervisor_cpu.clone(), 0, diff --git a/machine/src/aarch64/micro.rs b/machine/src/aarch64/micro.rs index 51cc2de4..a3b761bf 100644 --- a/machine/src/aarch64/micro.rs +++ b/machine/src/aarch64/micro.rs @@ -10,7 +10,7 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, RwLock}; use anyhow::{bail, Context, Result}; @@ -132,8 +132,8 @@ impl MachineOps for LightMachine { Ok(()) } - fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> { - let mut locked_vm = vm.lock().unwrap(); + fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> { + let mut locked_vm = vm.write().unwrap(); trace::sysbus(&locked_vm.base.sysbus.lock().unwrap()); trace::vm_state(&locked_vm.base.vm_state); diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index a5a99aef..5eefe28d 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -15,7 +15,7 @@ pub use crate::error::MachineError; use std::mem::size_of; #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] use std::sync::RwLock; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, RwLock}; use anyhow::{anyhow, bail, Context, Result}; #[cfg(feature = "ramfb")] @@ -178,8 +178,8 @@ impl StdMachine { }) } - pub fn handle_reset_request(vm: &Arc>) -> Result<()> { - let mut locked_vm = vm.lock().unwrap(); + pub fn handle_reset_request(vm: &Arc>) -> Result<()> { + let mut locked_vm = vm.write().unwrap(); let mut fdt_addr: u64 = 0; for (cpu_index, cpu) in locked_vm.base.cpus.iter().enumerate() { @@ -520,9 +520,9 @@ impl MachineOps for StdMachine { } } - fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> { + fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> { let nr_cpus = vm_config.machine_config.nr_cpus; - let mut locked_vm = vm.lock().unwrap(); + let mut locked_vm = vm.write().unwrap(); locked_vm.init_global_config(vm_config)?; register_shutdown_event(locked_vm.shutdown_req.clone(), vm.clone()) .with_context(|| "Failed to register shutdown event")?; diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 19d4ba6c..8e6c668e 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -449,7 +449,7 @@ pub trait MachineOps: MachineLifecycle { /// * `max_cpus` - max cpu number of virtual machine. fn create_vcpu( vcpu_id: u8, - vm: Arc>, + vm: Arc>, hypervisor: Arc>, #[cfg(target_arch = "x86_64")] max_cpus: u8, ) -> Result> @@ -483,7 +483,7 @@ pub trait MachineOps: MachineLifecycle { /// * `max_cpus` - The max number of vcpus. /// * `boot_cfg` - Boot message generated by reading boot source to guest memory. fn init_vcpu( - vm: Arc>, + vm: Arc>, hypervisor: Arc>, nr_cpus: u8, #[cfg(target_arch = "x86_64")] max_cpus: u8, @@ -2052,7 +2052,7 @@ pub trait MachineOps: MachineLifecycle { /// /// * `vm` - The machine structure. /// * `vm_config` - VM configuration. - fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> + fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> where Self: Sized; @@ -2239,7 +2239,7 @@ pub trait MachineOps: MachineLifecycle { fn register_shutdown_event( shutdown_req: Arc, - vm: Arc>, + vm: Arc>, ) -> Result<()> { let shutdown_req_fd = shutdown_req.as_raw_fd(); let shutdown_req_handler: Rc = Rc::new(move |_, _| { @@ -2261,8 +2261,8 @@ fn register_shutdown_event( .with_context(|| "Failed to register event notifier.") } -fn handle_destroy_request(vm: &Arc>) -> bool { - let locked_vm = vm.lock().unwrap(); +fn handle_destroy_request(vm: &Arc>) -> bool { + let locked_vm = vm.read().unwrap(); let vmstate: VmState = { let state = locked_vm.machine_base().vm_state.deref().0.lock().unwrap(); *state @@ -2285,12 +2285,12 @@ fn handle_destroy_request(vm: &Arc>) -> bool { /// * `vm` - virtual machine that implement `MachineOps`. /// * `cmd_args` - Command arguments from user. pub fn vm_run( - vm: &Arc>, + vm: &Arc>, cmd_args: &arg_parser::ArgMatches, ) -> Result<()> { - let migrate = vm.lock().unwrap().get_migrate_info(); + let migrate = vm.read().unwrap().get_migrate_info(); if migrate.0 == MigrateMode::Unknown { - vm.lock() + vm.read() .unwrap() .run(cmd_args.is_present("freeze_cpu")) .with_context(|| "Failed to start VM.")?; @@ -2302,13 +2302,13 @@ pub fn vm_run( } /// Start incoming migration from destination. -fn start_incoming_migration(vm: &Arc>) -> Result<()> { - let (mode, path) = vm.lock().unwrap().get_migrate_info(); +fn start_incoming_migration(vm: &Arc>) -> Result<()> { + let (mode, path) = vm.read().unwrap().get_migrate_info(); match mode { MigrateMode::File => { MigrationManager::restore_snapshot(&path) .with_context(|| "Failed to restore snapshot")?; - vm.lock() + vm.read() .unwrap() .run(false) .with_context(|| "Failed to start VM.")?; @@ -2321,7 +2321,7 @@ fn start_incoming_migration(vm: &Arc>) -> Re MigrationManager::recv_migration(&mut sock) .with_context(|| "Failed to receive migration with unix mode")?; - vm.lock() + vm.read() .unwrap() .run(false) .with_context(|| "Failed to start VM.")?; @@ -2334,7 +2334,7 @@ fn start_incoming_migration(vm: &Arc>) -> Re MigrationManager::recv_migration(&mut sock) .with_context(|| "Failed to receive migration with tcp mode")?; - vm.lock() + vm.read() .unwrap() .run(false) .with_context(|| "Failed to start VM.")?; @@ -2347,7 +2347,7 @@ fn start_incoming_migration(vm: &Arc>) -> Re } // End the migration and reset the mode. - let locked_vm = vm.lock().unwrap(); + let locked_vm = vm.read().unwrap(); let vm_config = locked_vm.get_vm_config(); if let Some((mode, _)) = vm_config.lock().unwrap().incoming.as_mut() { *mode = MigrateMode::Unknown; diff --git a/machine/src/micro_common/mod.rs b/machine/src/micro_common/mod.rs index 076af9c5..9e5551be 100644 --- a/machine/src/micro_common/mod.rs +++ b/machine/src/micro_common/mod.rs @@ -544,7 +544,7 @@ impl MachineLifecycle for LightMachine { true } - fn reset(&mut self) -> bool { + fn reset(&self) -> bool { // For micro vm, the reboot command is equivalent to the shutdown command. for cpu in self.base.cpus.iter() { let (cpu_state, _) = cpu.state(); diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index 60944fb9..5563b34e 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -20,7 +20,7 @@ use std::os::unix::io::RawFd; use std::os::unix::prelude::AsRawFd; use std::rc::Rc; use std::string::String; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, RwLock}; use std::u64; use anyhow::{bail, Context, Result}; @@ -240,7 +240,7 @@ pub(crate) trait StdMachineOps: AcpiBuilder + MachineOps { /// /// * `clone_vm` - Reference of the StdMachine. #[cfg(target_arch = "x86_64")] - fn add_vcpu_device(&mut self, clone_vm: Arc>) -> Result<()>; + fn add_vcpu_device(&mut self, clone_vm: Arc>) -> Result<()>; /// Register event notifier for hotplug vcpu event. /// @@ -252,7 +252,7 @@ pub(crate) trait StdMachineOps: AcpiBuilder + MachineOps { fn register_hotplug_vcpu_event( &self, hotplug_req: Arc, - clone_vm: Arc>, + clone_vm: Arc>, ) -> Result<()> { let hotplug_req_fd = hotplug_req.as_raw_fd(); let hotplug_req_handler: Rc = Rc::new(move |_, _| { @@ -298,7 +298,7 @@ pub(crate) trait StdMachineOps: AcpiBuilder + MachineOps { fn register_reset_event( &self, reset_req: Arc, - clone_vm: Arc>, + clone_vm: Arc>, ) -> Result<()> { let reset_req_fd = reset_req.as_raw_fd(); let reset_req_handler: Rc = Rc::new(move |_, _| { @@ -323,12 +323,12 @@ pub(crate) trait StdMachineOps: AcpiBuilder + MachineOps { fn register_pause_event( &self, pause_req: Arc, - clone_vm: Arc>, + clone_vm: Arc>, ) -> Result<()> { let pause_req_fd = pause_req.as_raw_fd(); let pause_req_handler: Rc = Rc::new(move |_, _| { let _ret = pause_req.read(); - if !clone_vm.lock().unwrap().pause() { + if !clone_vm.read().unwrap().pause() { error!("VM pause failed"); } None @@ -348,12 +348,12 @@ pub(crate) trait StdMachineOps: AcpiBuilder + MachineOps { fn register_resume_event( &self, resume_req: Arc, - clone_vm: Arc>, + clone_vm: Arc>, ) -> Result<()> { let resume_req_fd = resume_req.as_raw_fd(); let resume_req_handler: Rc = Rc::new(move |_, _| { let _ret = resume_req.read(); - if !clone_vm.lock().unwrap().resume() { + if !clone_vm.read().unwrap().resume() { error!("VM resume failed!"); } None @@ -986,7 +986,7 @@ impl MachineLifecycle for StdMachine { .shutdown_action } - fn reset(&mut self) -> bool { + fn reset(&self) -> bool { if self.reset_req.write(1).is_err() { error!("Standard vm write reset request failed"); return false; diff --git a/machine/src/x86_64/micro.rs b/machine/src/x86_64/micro.rs index dad7e7b7..0c0afc76 100644 --- a/machine/src/x86_64/micro.rs +++ b/machine/src/x86_64/micro.rs @@ -10,7 +10,7 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, RwLock}; use anyhow::{bail, Context, Result}; @@ -138,8 +138,8 @@ impl MachineOps for LightMachine { .with_context(|| "Failed to realize serial device.") } - fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> { - let mut locked_vm = vm.lock().unwrap(); + fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> { + let mut locked_vm = vm.write().unwrap(); trace::sysbus(&locked_vm.base.sysbus); trace::vm_state(&locked_vm.base.vm_state); diff --git a/machine/src/x86_64/standard.rs b/machine/src/x86_64/standard.rs index 3a116911..c9c80f79 100644 --- a/machine/src/x86_64/standard.rs +++ b/machine/src/x86_64/standard.rs @@ -12,7 +12,7 @@ use std::io::{Seek, SeekFrom}; use std::mem::size_of; -use std::sync::{Arc, Barrier, Mutex}; +use std::sync::{Arc, Barrier, Mutex, RwLock}; use anyhow::{bail, Context, Result}; @@ -148,8 +148,8 @@ impl StdMachine { }) } - pub fn handle_reset_request(vm: &Arc>) -> Result<()> { - let mut locked_vm = vm.lock().unwrap(); + pub fn handle_reset_request(vm: &Arc>) -> Result<()> { + let mut locked_vm = vm.write().unwrap(); for (cpu_index, cpu) in locked_vm.base.cpus.iter().enumerate() { cpu.pause() @@ -178,7 +178,7 @@ impl StdMachine { Ok(()) } - fn init_ich9_lpc(&self, vm: Arc>) -> Result<()> { + fn init_ich9_lpc(&self, vm: Arc>) -> Result<()> { let root_bus = Arc::downgrade(&self.pci_host.lock().unwrap().root_bus); let ich = ich9_lpc::LPCBridge::new( root_bus, @@ -197,8 +197,8 @@ impl StdMachine { None } - pub fn handle_hotplug_vcpu_request(vm: &Arc>) -> Result<()> { - let mut locked_vm = vm.lock().unwrap(); + pub fn handle_hotplug_vcpu_request(vm: &Arc>) -> Result<()> { + let mut locked_vm = vm.write().unwrap(); locked_vm.add_vcpu_device(vm.clone()) } @@ -206,7 +206,7 @@ impl StdMachine { &mut self, boot_config: CPUBootConfig, cpu_topology: CPUTopology, - vm: Arc>, + vm: Arc>, ) -> Result<()> { let region_base: u64 = MEM_LAYOUT[LayoutEntryType::CpuController as usize].0; let region_size: u64 = MEM_LAYOUT[LayoutEntryType::CpuController as usize].1; @@ -296,7 +296,7 @@ impl StdMachineOps for StdMachine { self.cpu_controller.as_ref().unwrap() } - fn add_vcpu_device(&mut self, clone_vm: Arc>) -> Result<()> { + fn add_vcpu_device(&mut self, clone_vm: Arc>) -> Result<()> { let mut locked_controller = self.cpu_controller.as_ref().unwrap().lock().unwrap(); let device_id; let vcpu_id; @@ -310,7 +310,7 @@ impl StdMachineOps for StdMachine { let boot_cfg = locked_controller.get_boot_config(); let topology = locked_controller.get_topology_config(); - let hypervisor = clone_vm.lock().unwrap().base.hypervisor.clone(); + let hypervisor = clone_vm.read().unwrap().base.hypervisor.clone(); let vcpu = ::create_vcpu( vcpu_id, clone_vm, @@ -474,10 +474,10 @@ impl MachineOps for StdMachine { syscall_whitelist() } - fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> { + fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> { let nr_cpus = vm_config.machine_config.nr_cpus; let max_cpus = vm_config.machine_config.max_cpus; - let mut locked_vm = vm.lock().unwrap(); + let mut locked_vm = vm.write().unwrap(); locked_vm.init_global_config(vm_config)?; locked_vm.base.numa_nodes = locked_vm.add_numa_nodes(vm_config)?; locked_vm.init_interrupt_controller(u64::from(nr_cpus))?; diff --git a/machine_manager/src/event_loop.rs b/machine_manager/src/event_loop.rs index 79d7cf6f..e197a39e 100644 --- a/machine_manager/src/event_loop.rs +++ b/machine_manager/src/event_loop.rs @@ -12,7 +12,7 @@ use std::collections::HashMap; use std::os::unix::prelude::RawFd; -use std::sync::{Arc, Barrier, Mutex}; +use std::sync::{Arc, Barrier, RwLock}; use std::{process, thread}; use anyhow::{bail, Result}; @@ -126,7 +126,7 @@ impl EventLoop { /// # Arguments /// /// * `manager` - The main part to manager the event loop. - pub fn set_manager(manager: Arc>) { + pub fn set_manager(manager: Arc>) { // SAFETY: All concurrently accessed data of EventLoopContext is protected. unsafe { if let Some(event_loop) = GLOBAL_EVENT_LOOP.as_mut() { diff --git a/machine_manager/src/machine.rs b/machine_manager/src/machine.rs index a040d6ef..e3663844 100644 --- a/machine_manager/src/machine.rs +++ b/machine_manager/src/machine.rs @@ -116,7 +116,7 @@ pub trait MachineLifecycle { } /// Reset VM, stop running and restart a new VM. - fn reset(&mut self) -> bool { + fn reset(&self) -> bool { self.notify_lifecycle(VmState::Running, VmState::Shutdown) } diff --git a/machine_manager/src/qmp/qmp_socket.rs b/machine_manager/src/qmp/qmp_socket.rs index 35ad238f..62a9d62e 100644 --- a/machine_manager/src/qmp/qmp_socket.rs +++ b/machine_manager/src/qmp/qmp_socket.rs @@ -100,7 +100,7 @@ pub struct Socket { /// Socket stream with RwLock stream: RwLock>, /// Perform socket command - performer: Option>>, + performer: Option>>, } impl Socket { @@ -112,7 +112,7 @@ impl Socket { /// * `performer` - The `VM` to perform socket command. pub fn from_listener( listener: SocketListener, - performer: Option>>, + performer: Option>>, ) -> Self { Socket { listener, @@ -275,12 +275,13 @@ impl EventNotifierHelper for Socket { } /// Macro: to execute handle func with every arguments. +/// Attentions: Lifecycle commands cannot hold a write lock on the executor to avoid deadlock. macro_rules! qmp_command_match { ( $func:tt, $executor:expr, $ret:expr ) => { - $ret = $executor.$func().into(); + $ret = $executor.read().unwrap().$func().into(); }; ( $func:tt, $executor:expr, $cmd:expr, $ret:expr, $($arg:tt),* ) => { - $ret = $executor.$func( + $ret = $executor.write().unwrap().$func( $($cmd.$arg),* ).into(); }; @@ -289,7 +290,7 @@ macro_rules! qmp_command_match { /// Macro: to execute handle func with all arguments. macro_rules! qmp_command_match_with_argument { ( $func:tt, $executor:expr, $cmd:expr, $ret:expr ) => { - $ret = $executor.$func($cmd).into(); + $ret = $executor.write().unwrap().$func($cmd).into(); }; } @@ -365,7 +366,7 @@ fn parse_tcp_uri(uri: &str) -> Result<(String, u16)> { /// This function will fail when json parser failed or socket file description broke. fn handle_qmp( stream_fd: RawFd, - controller: &Arc>, + controller: &Arc>, leak_bucket: &mut LeakBucket, ) -> Result<()> { let mut qmp_service = crate::socket::SocketHandler::new(stream_fd); @@ -422,7 +423,7 @@ fn handle_qmp( /// function, and exec this qmp command. fn qmp_command_exec( qmp_command: QmpCommand, - controller: &Arc>, + controller: &Arc>, if_fd: Option, ) -> (String, bool) { let mut qmp_response = Response::create_empty_response(); @@ -430,7 +431,7 @@ fn qmp_command_exec( // Use macro create match to cover most Qmp command let mut id = create_command_matches!( - qmp_command.clone(); controller.lock().unwrap(); qmp_response; + qmp_command.clone(); controller; qmp_response; (stop, pause), (cont, resume), (system_powerdown, powerdown), @@ -493,12 +494,12 @@ fn qmp_command_exec( if id.is_none() { id = match qmp_command { QmpCommand::quit { id, .. } => { - controller.lock().unwrap().destroy(); + controller.read().unwrap().destroy(); shutdown_flag = true; id } QmpCommand::getfd { arguments, id } => { - qmp_response = controller.lock().unwrap().getfd(arguments.fd_name, if_fd); + qmp_response = controller.read().unwrap().getfd(arguments.fd_name, if_fd); id } QmpCommand::trace_get_state { arguments, id } => { diff --git a/machine_manager/src/test_server.rs b/machine_manager/src/test_server.rs index f126ede0..f8e2078c 100644 --- a/machine_manager/src/test_server.rs +++ b/machine_manager/src/test_server.rs @@ -14,7 +14,7 @@ use std::os::unix::io::RawFd; use std::os::unix::net::UnixStream; use std::os::unix::prelude::AsRawFd; use std::rc::Rc; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, RwLock}; use hex::FromHexError; use vmm_sys_util::epoll::EventSet; @@ -27,11 +27,11 @@ use util::test_helper::{eoi_intx, get_test_clock, has_msix_msg, query_intx, set_ pub struct TestSock { stream: UnixStream, - controller: Arc>, + controller: Arc>, } impl TestSock { - pub fn new(path: &str, controller: Arc>) -> Self { + pub fn new(path: &str, controller: Arc>) -> Self { let stream = match UnixStream::connect(path) { Ok(s) => s, Err(e) => { @@ -115,7 +115,7 @@ fn update_clock(target: u64) { } } -fn handle_test_cmd(stream_fd: RawFd, controller: &Arc>) { +fn handle_test_cmd(stream_fd: RawFd, controller: &Arc>) { let mut handler = SocketHandler::new(stream_fd); let msg = handler.get_line().unwrap().unwrap(); @@ -129,7 +129,7 @@ fn handle_test_cmd(stream_fd: RawFd, controller: &Arc { @@ -193,7 +193,7 @@ fn handle_test_cmd(stream_fd: RawFd, controller: &Arc { @@ -207,7 +207,7 @@ fn handle_test_cmd(stream_fd: RawFd, controller: &Arc { diff --git a/migration/src/general.rs b/migration/src/general.rs index 0777e0de..0f9f56dc 100644 --- a/migration/src/general.rs +++ b/migration/src/general.rs @@ -260,7 +260,7 @@ pub trait Lifecycle { /// Pause VM during migration. fn pause() -> Result<()> { if let Some(locked_vm) = &MIGRATION_MANAGER.vmm.read().unwrap().vm { - locked_vm.lock().unwrap().pause(); + locked_vm.read().unwrap().pause(); } Ok(()) diff --git a/migration/src/manager.rs b/migration/src/manager.rs index d381ae31..302350ff 100644 --- a/migration/src/manager.rs +++ b/migration/src/manager.rs @@ -163,7 +163,7 @@ pub struct Vmm { /// Vm config pub config: Arc>, /// Trait to represent a Vm. - pub vm: Option>>, + pub vm: Option>>, /// Trait to represent CPU devices. pub cpus: HashMap>, /// Trait to represent memory devices. @@ -245,7 +245,7 @@ impl MigrationManager { /// # Arguments /// /// * `vm` - vm instance with MachineLifecycle trait. - pub fn register_vm_instance(vm: Arc>) + pub fn register_vm_instance(vm: Arc>) where T: MachineLifecycle + Sync + Send + 'static, { diff --git a/migration/src/migration.rs b/migration/src/migration.rs index 2782d9cd..2edfa356 100644 --- a/migration/src/migration.rs +++ b/migration/src/migration.rs @@ -578,7 +578,7 @@ impl MigrationManager { /// Clear live migration environment and shut down VM. fn clear_migration() -> Result<()> { if let Some(locked_vm) = &MIGRATION_MANAGER.vmm.read().unwrap().vm { - locked_vm.lock().unwrap().destroy(); + locked_vm.read().unwrap().destroy(); } Ok(()) @@ -587,7 +587,7 @@ impl MigrationManager { /// Recover the virtual machine if migration is failed. pub fn recover_from_migration() -> Result<()> { if let Some(locked_vm) = &MIGRATION_MANAGER.vmm.read().unwrap().vm { - locked_vm.lock().unwrap().resume(); + locked_vm.read().unwrap().resume(); } Ok(()) diff --git a/src/main.rs b/src/main.rs index cff73cbe..2d85d8f1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,7 @@ use std::io::Write; use std::process::{ExitCode, Termination}; -use std::sync::{Arc, Mutex}; +use std::sync::{Arc, Mutex, RwLock}; use anyhow::{bail, Context, Result}; use log::{error, info}; @@ -154,12 +154,12 @@ fn real_main(cmd_args: &arg_parser::ArgMatches, vm_config: &mut VmConfig) -> Res let listeners = check_api_channel(cmd_args, vm_config)?; let mut sockets = Vec::new(); - let vm: Arc> = match vm_config.machine_config.mach_type { + let vm: Arc> = match vm_config.machine_config.mach_type { MachineType::MicroVm => { if is_test_enabled() { panic!("module test framework does not support microvm.") } - let vm = Arc::new(Mutex::new( + let vm = Arc::new(RwLock::new( LightMachine::new(vm_config).with_context(|| "Failed to init MicroVM")?, )); MachineOps::realize(&vm, vm_config).with_context(|| "Failed to realize micro VM.")?; @@ -171,7 +171,7 @@ fn real_main(cmd_args: &arg_parser::ArgMatches, vm_config: &mut VmConfig) -> Res vm } MachineType::StandardVm => { - let vm = Arc::new(Mutex::new( + let vm = Arc::new(RwLock::new( StdMachine::new(vm_config).with_context(|| "Failed to init StandardVM")?, )); MachineOps::realize(&vm, vm_config) @@ -199,7 +199,7 @@ fn real_main(cmd_args: &arg_parser::ArgMatches, vm_config: &mut VmConfig) -> Res if is_test_enabled() { panic!("please specify machine type.") } - let vm = Arc::new(Mutex::new( + let vm = Arc::new(RwLock::new( StdMachine::new(vm_config).with_context(|| "Failed to init NoneVM")?, )); EventLoop::set_manager(vm.clone()); @@ -213,7 +213,7 @@ fn real_main(cmd_args: &arg_parser::ArgMatches, vm_config: &mut VmConfig) -> Res let balloon_switch_on = vm_config.dev_name.get("balloon").is_some(); if !cmd_args.is_present("disable-seccomp") { - vm.lock() + vm.read() .unwrap() .register_seccomp(balloon_switch_on) .with_context(|| "Failed to register seccomp rules.")?; diff --git a/util/src/loop_context.rs b/util/src/loop_context.rs index 957fdb4c..a511b1fc 100644 --- a/util/src/loop_context.rs +++ b/util/src/loop_context.rs @@ -202,7 +202,7 @@ pub struct EventLoopContext { /// Epoll file descriptor. epoll: Epoll, /// Control epoll loop running. - manager: Option>>, + manager: Option>>, /// Used to wakeup epoll to re-evaluate events or timers. kick_event: EventFd, /// Used to avoid unnecessary kick operation when the @@ -290,7 +290,7 @@ impl EventLoopContext { } } - pub fn set_manager(&mut self, manager: Arc>) { + pub fn set_manager(&mut self, manager: Arc>) { self.manager = Some(manager); } @@ -547,8 +547,8 @@ impl EventLoopContext { /// Executes `epoll.wait()` to wait for events, and call the responding callbacks. pub fn run(&mut self) -> Result { if let Some(manager) = &self.manager { - if manager.lock().unwrap().loop_should_exit() { - manager.lock().unwrap().loop_cleanup()?; + if manager.read().unwrap().loop_should_exit() { + manager.read().unwrap().loop_cleanup()?; return Ok(false); } } @@ -558,8 +558,8 @@ impl EventLoopContext { pub fn iothread_run(&mut self) -> Result { if let Some(manager) = &self.manager { - if manager.lock().unwrap().loop_should_exit() { - manager.lock().unwrap().loop_cleanup()?; + if manager.read().unwrap().loop_should_exit() { + manager.read().unwrap().loop_cleanup()?; return Ok(false); } } -- Gitee From a3d968176fca28c4618ce2fb6fdc1b86520102cf Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 11 Jul 2024 11:13:15 +0800 Subject: [PATCH 182/489] machine: add missing `OhUiServer` use Add missing `OhUiServer` use. Fix: f30677c8bf6174(machine: unified `StdMachine`) Signed-off-by: liuxiangdong --- machine/src/standard_common/mod.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index 5563b34e..6818dce3 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -77,6 +77,8 @@ use machine_manager::qmp::{qmp_channel::QmpChannel, qmp_response::Response, qmp_ #[cfg(feature = "gtk")] use ui::gtk::qmp_query_display_image; use ui::input::{input_button, input_move_abs, input_point_sync, key_event, Axis}; +#[cfg(all(target_env = "ohos", feature = "ohui_srv"))] +use ui::ohui_srv::OhUiServer; #[cfg(feature = "vnc")] use ui::vnc::qmp_query_vnc; use util::aio::{AioEngine, WriteZeroesState}; -- Gitee From 90cda9001a9adc67aa9e234e2893c01f9cb74055 Mon Sep 17 00:00:00 2001 From: yexiao Date: Tue, 18 Jun 2024 00:33:47 +0800 Subject: [PATCH 183/489] xhci: fix some error with xhci controller Replace the function of report_transfer_error with submit_transfer, as the latter will send transfer event without length. Signed-off-by: Xiao Ye --- devices/src/usb/xhci/xhci_controller.rs | 34 ++++++++++++++++++++----- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index b515130d..02ec9b17 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -212,6 +212,7 @@ impl XhciTransfer { pub fn submit_transfer(&mut self) -> Result<()> { // Event Data Transfer Length Accumulator. let mut edtla: u32 = 0; + let mut shortpkt = false; let mut left = self.packet.lock().unwrap().actual_length; for i in 0..self.td.len() { let trb = &self.td[i]; @@ -222,7 +223,9 @@ impl XhciTransfer { TRBType::TrData | TRBType::TrNormal | TRBType::TrIsoch => { if chunk > left { chunk = left; - self.status = TRBCCode::ShortPacket; + if self.status == TRBCCode::Success { + shortpkt = true; + } } left -= chunk; edtla = edtla.checked_add(chunk).with_context(|| @@ -238,16 +241,25 @@ impl XhciTransfer { } } if (trb.control & TRB_TR_IOC == TRB_TR_IOC) - || (self.status == TRBCCode::ShortPacket - && (trb.control & TRB_TR_ISP == TRB_TR_ISP)) + || (shortpkt && (trb.control & TRB_TR_ISP == TRB_TR_ISP)) + || (self.status != TRBCCode::Success && left == 0) { - self.send_transfer_event(trb, chunk, &mut edtla)?; + self.send_transfer_event(trb, chunk, &mut edtla, shortpkt)?; + if self.status != TRBCCode::Success { + return Ok(()); + } } } Ok(()) } - fn send_transfer_event(&self, trb: &XhciTRB, transferred: u32, edtla: &mut u32) -> Result<()> { + fn send_transfer_event( + &self, + trb: &XhciTRB, + transferred: u32, + edtla: &mut u32, + shortpkt: bool, + ) -> Result<()> { let trb_type = trb.get_type(); let mut evt = XhciEvent::new(TRBType::ErTransfer, TRBCCode::Success); evt.slot_id = self.slotid as u8; @@ -255,7 +267,15 @@ impl XhciTransfer { evt.length = (trb.status & TRB_TR_LEN_MASK) - transferred; evt.flags = 0; evt.ptr = trb.addr; - evt.ccode = self.status; + evt.ccode = if self.status == TRBCCode::Success { + if shortpkt { + TRBCCode::ShortPacket + } else { + TRBCCode::Success + } + } else { + self.status + }; if trb_type == TRBType::TrEvdata { evt.ptr = trb.parameter; evt.flags |= TRB_EV_ED; @@ -2312,7 +2332,7 @@ impl XhciDevice { if xfer.running_retry { if report != TRBCCode::Invalid { xfer.status = report; - xfer.report_transfer_error()?; + xfer.submit_transfer()?; } let epctx = &mut self.slots[(slotid - 1) as usize].endpoints[(ep_id - 1) as usize]; epctx.retry = None; -- Gitee From 81c36659e043b3075c64c3d74525a29d5d85d05f Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Fri, 12 Jul 2024 07:40:41 +0800 Subject: [PATCH 184/489] pci: use unified "TestPciDevice" Use unified "TestPciDevice" for UT. Signed-off-by: liuxiangdong --- devices/src/pci/bus.rs | 87 +++------------------------------- devices/src/pci/host.rs | 73 ++--------------------------- devices/src/pci/mod.rs | 101 +++++++++++++++++++++++++++++----------- 3 files changed, 84 insertions(+), 177 deletions(-) diff --git a/devices/src/pci/bus.rs b/devices/src/pci/bus.rs index 1141afe9..0524caa0 100644 --- a/devices/src/pci/bus.rs +++ b/devices/src/pci/bus.rs @@ -269,64 +269,11 @@ impl PciBus { #[cfg(test)] mod tests { - use anyhow::Result; - use super::*; use crate::pci::bus::PciBus; - use crate::pci::config::{PciConfig, PCI_CONFIG_SPACE_SIZE}; use crate::pci::host::tests::create_pci_host; - use crate::pci::root_port::RootPort; - use crate::pci::{PciDevBase, RootPortConfig}; - use crate::{Device, DeviceBase}; - use util::gen_base_func; - - #[derive(Clone)] - struct PciDevice { - base: PciDevBase, - } - - impl Device for PciDevice { - gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); - } - - impl PciDevOps for PciDevice { - gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); - - fn write_config(&mut self, offset: usize, data: &[u8]) { - #[allow(unused_variables)] - self.base.config.write( - offset, - data, - 0, - #[cfg(target_arch = "x86_64")] - None, - None, - ); - } - - fn realize(mut self) -> Result<()> { - let devfn = self.base.devfn; - self.init_write_mask(false)?; - self.init_write_clear_mask(false)?; - - let dev = Arc::new(Mutex::new(self)); - dev.lock() - .unwrap() - .base - .parent_bus - .upgrade() - .unwrap() - .lock() - .unwrap() - .devices - .insert(devfn, dev.clone()); - Ok(()) - } - - fn unrealize(&mut self) -> Result<()> { - Ok(()) - } - } + use crate::pci::root_port::{RootPort, RootPortConfig}; + use crate::pci::tests::TestPciDevice; #[test] fn test_find_attached_bus() { @@ -342,26 +289,12 @@ mod tests { root_port.realize().unwrap(); // Test device is attached to the root bus. - let pci_dev = PciDevice { - base: PciDevBase { - base: DeviceBase::new("test1".to_string(), false), - config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 0), - devfn: 10, - parent_bus: root_bus.clone(), - }, - }; + let pci_dev = TestPciDevice::new("test1", 10, root_bus); pci_dev.realize().unwrap(); // Test device is attached to the root port. let bus = PciBus::find_bus_by_name(&locked_pci_host.root_bus, "pcie.1").unwrap(); - let pci_dev = PciDevice { - base: PciDevBase { - base: DeviceBase::new("test2".to_string(), false), - config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 0), - devfn: 12, - parent_bus: Arc::downgrade(&bus), - }, - }; + let pci_dev = TestPciDevice::new("test2", 12, Arc::downgrade(&bus)); pci_dev.realize().unwrap(); let info = PciBus::find_attached_bus(&locked_pci_host.root_bus, "test0"); @@ -395,16 +328,8 @@ mod tests { root_port.realize().unwrap(); let bus = PciBus::find_bus_by_name(&locked_pci_host.root_bus, "pcie.1").unwrap(); - let pci_dev = PciDevice { - base: PciDevBase { - base: DeviceBase::new("test1".to_string(), false), - config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 0), - devfn: 0, - parent_bus: Arc::downgrade(&bus), - }, - }; - let dev = Arc::new(Mutex::new(pci_dev.clone())); - let dev_ops: Arc> = dev; + let pci_dev = TestPciDevice::new("test1", 0, Arc::downgrade(&bus)); + let dev_ops: Arc> = Arc::new(Mutex::new(pci_dev.clone())); pci_dev.realize().unwrap(); let info = PciBus::find_attached_bus(&locked_pci_host.root_bus, "test1"); diff --git a/devices/src/pci/host.rs b/devices/src/pci/host.rs index 8bcaee72..1af69682 100644 --- a/devices/src/pci/host.rs +++ b/devices/src/pci/host.rs @@ -535,71 +535,11 @@ pub mod tests { use super::*; use crate::pci::bus::PciBus; - use crate::pci::config::{PciConfig, PCI_CONFIG_SPACE_SIZE, SECONDARY_BUS_NUM}; + use crate::pci::config::SECONDARY_BUS_NUM; use crate::pci::root_port::{RootPort, RootPortConfig}; - use crate::pci::{PciDevBase, Result}; - use crate::{Device, DeviceBase}; + use crate::pci::tests::TestPciDevice; use address_space::Region; - struct PciDevice { - base: PciDevBase, - } - - impl Device for PciDevice { - gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); - } - - impl PciDevOps for PciDevice { - gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); - - fn init_write_mask(&mut self, _is_bridge: bool) -> Result<()> { - let mut offset = 0_usize; - while offset < self.base.config.config.len() { - LittleEndian::write_u32( - &mut self.base.config.write_mask[offset..offset + 4], - 0xffff_ffff, - ); - offset += 4; - } - Ok(()) - } - - fn init_write_clear_mask(&mut self, _is_bridge: bool) -> Result<()> { - Ok(()) - } - - fn write_config(&mut self, offset: usize, data: &[u8]) { - #[allow(unused_variables)] - self.base.config.write( - offset, - data, - 0, - #[cfg(target_arch = "x86_64")] - None, - None, - ); - } - - fn realize(mut self) -> Result<()> { - let devfn = self.base.devfn; - self.init_write_mask(false)?; - self.init_write_clear_mask(false)?; - - let dev = Arc::new(Mutex::new(self)); - dev.lock() - .unwrap() - .base - .parent_bus - .upgrade() - .unwrap() - .lock() - .unwrap() - .devices - .insert(devfn, dev.clone()); - Ok(()) - } - } - pub fn create_pci_host() -> Arc> { #[cfg(target_arch = "x86_64")] let sys_io = AddressSpace::new( @@ -735,14 +675,7 @@ pub mod tests { root_port.realize().unwrap(); let bus = PciBus::find_bus_by_name(&pci_host.lock().unwrap().root_bus, "pcie.2").unwrap(); - let pci_dev = PciDevice { - base: PciDevBase { - base: DeviceBase::new("PCI device".to_string(), false), - config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 0), - devfn: 8, - parent_bus: Arc::downgrade(&bus), - }, - }; + let pci_dev = TestPciDevice::new("PCI device", 8, Arc::downgrade(&bus)); pci_dev.realize().unwrap(); let addr: u64 = 8_u64 << ECAM_DEVFN_SHIFT | SECONDARY_BUS_NUM as u64; diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs index 13da0346..9142c9fd 100644 --- a/devices/src/pci/mod.rs +++ b/devices/src/pci/mod.rs @@ -404,10 +404,84 @@ pub fn swizzle_map_irq(devfn: u8, pin: u8) -> u32 { #[cfg(test)] mod tests { use super::*; + use crate::pci::config::{PciConfig, PCI_CONFIG_SPACE_SIZE}; use crate::DeviceBase; use address_space::{AddressSpace, Region}; use util::gen_base_func; + #[derive(Clone)] + pub struct TestPciDevice { + base: PciDevBase, + } + + impl TestPciDevice { + pub fn new(name: &str, devfn: u8, parent_bus: Weak>) -> Self { + Self { + base: PciDevBase { + base: DeviceBase::new(name.to_string(), false), + config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 0), + devfn, + parent_bus, + }, + } + } + } + + impl Device for TestPciDevice { + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); + } + + impl PciDevOps for TestPciDevice { + gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); + + fn write_config(&mut self, offset: usize, data: &[u8]) { + self.base.config.write( + offset, + data, + 0, + #[cfg(target_arch = "x86_64")] + None, + None, + ); + } + + fn realize(mut self) -> Result<()> { + let devfn = self.base.devfn; + self.init_write_mask(false)?; + self.init_write_clear_mask(false)?; + + let dev = Arc::new(Mutex::new(self)); + let parent_bus = dev.lock().unwrap().base.parent_bus.upgrade().unwrap(); + parent_bus + .lock() + .unwrap() + .devices + .insert(devfn, dev.clone()); + + Ok(()) + } + + fn unrealize(&mut self) -> Result<()> { + Ok(()) + } + + fn init_write_mask(&mut self, _is_bridge: bool) -> Result<()> { + let mut offset = 0_usize; + while offset < self.base.config.config.len() { + LittleEndian::write_u32( + &mut self.base.config.write_mask[offset..offset + 4], + 0xffff_ffff, + ); + offset += 4; + } + Ok(()) + } + + fn init_write_clear_mask(&mut self, _is_bridge: bool) -> Result<()> { + Ok(()) + } + } + #[test] fn test_le_write_u16_01() { let mut buf: [u8; 2] = [0; 2]; @@ -449,24 +523,6 @@ mod tests { #[test] fn set_dev_id() { - struct PciDev { - base: PciDevBase, - } - - impl Device for PciDev { - gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); - } - - impl PciDevOps for PciDev { - gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); - - fn write_config(&mut self, _offset: usize, _data: &[u8]) {} - - fn realize(self) -> Result<()> { - Ok(()) - } - } - let sys_mem = AddressSpace::new( Region::init_container_region(u64::max_value(), "sysmem"), "sysmem", @@ -480,14 +536,7 @@ mod tests { sys_mem.root().clone(), ))); - let dev = PciDev { - base: PciDevBase { - base: DeviceBase::new("PCI device".to_string(), false), - config: PciConfig::new(1, 1), - devfn: 0, - parent_bus: Arc::downgrade(&parent_bus), - }, - }; + let dev = TestPciDevice::new("PCI device", 0, Arc::downgrade(&parent_bus)); assert_eq!(dev.set_dev_id(1, 2), 258); } } -- Gitee From c03408dc6685f4c653959ae8005ccb50b3303238 Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Fri, 17 May 2024 10:40:34 +0300 Subject: [PATCH 185/489] usb: Remove get_wakeup_endpoint from UsbDevice trait Wakeup endpoint is only required for USB keyboard and tablet devices and can be passed to notify_controller directly, so no get_wakeup_endpoint is needed. Signed-off-by: goriainovstanislav --- devices/src/usb/camera.rs | 8 +------- devices/src/usb/keyboard.rs | 13 +++++-------- devices/src/usb/mod.rs | 10 +++------- devices/src/usb/storage.rs | 6 +----- devices/src/usb/tablet.rs | 14 ++++++-------- devices/src/usb/uas.rs | 6 +----- devices/src/usb/usbhost/mod.rs | 4 ---- devices/src/usb/xhci/xhci_controller.rs | 16 +++++----------- 8 files changed, 22 insertions(+), 55 deletions(-) diff --git a/devices/src/usb/camera.rs b/devices/src/usb/camera.rs index a8807318..b4ef0861 100644 --- a/devices/src/usb/camera.rs +++ b/devices/src/usb/camera.rs @@ -32,9 +32,7 @@ use crate::camera_backend::{ }; use crate::usb::config::*; use crate::usb::descriptor::*; -use crate::usb::{ - UsbDevice, UsbDeviceBase, UsbDeviceRequest, UsbEndpoint, UsbPacket, UsbPacketStatus, -}; +use crate::usb::{UsbDevice, UsbDeviceBase, UsbDeviceRequest, UsbPacket, UsbPacketStatus}; use machine_manager::config::camera::CameraDevConfig; use machine_manager::config::valid_id; use machine_manager::event_loop::{register_event_helper, unregister_event_helper}; @@ -859,10 +857,6 @@ impl UsbDevice for UsbCamera { fn get_controller(&self) -> Option>> { None } - - fn get_wakeup_endpoint(&self) -> &UsbEndpoint { - self.base.get_endpoint(true, 1) - } } /// UVC payload diff --git a/devices/src/usb/keyboard.rs b/devices/src/usb/keyboard.rs index 214ade86..4c6847a3 100644 --- a/devices/src/usb/keyboard.rs +++ b/devices/src/usb/keyboard.rs @@ -22,11 +22,10 @@ use super::descriptor::{ UsbDescriptorOps, UsbDeviceDescriptor, UsbEndpointDescriptor, UsbInterfaceDescriptor, }; use super::hid::{Hid, HidType, QUEUE_LENGTH, QUEUE_MASK}; -use super::xhci::xhci_controller::XhciDevice; +use super::xhci::xhci_controller::{endpoint_number_to_id, XhciDevice}; use super::{config::*, USB_DEVICE_BUFFER_DEFAULT_LEN}; use super::{ - notify_controller, UsbDevice, UsbDeviceBase, UsbDeviceRequest, UsbEndpoint, UsbPacket, - UsbPacketStatus, + notify_controller, UsbDevice, UsbDeviceBase, UsbDeviceRequest, UsbPacket, UsbPacketStatus, }; use machine_manager::config::valid_id; use ui::input::{register_keyboard, unregister_keyboard, KeyboardOpts}; @@ -175,7 +174,9 @@ impl KeyboardOpts for UsbKeyboardAdapter { } drop(locked_kbd); let clone_kbd = self.usb_kbd.clone(); - notify_controller(&(clone_kbd as Arc>)) + // Wakeup endpoint. + let ep_id = endpoint_number_to_id(true, 1); + notify_controller(&(clone_kbd as Arc>), ep_id) } } @@ -260,8 +261,4 @@ impl UsbDevice for UsbKeyboard { fn get_controller(&self) -> Option>> { self.cntlr.clone() } - - fn get_wakeup_endpoint(&self) -> &UsbEndpoint { - self.base.get_endpoint(true, 1) - } } diff --git a/devices/src/usb/mod.rs b/devices/src/usb/mod.rs index ac2e3add..5fc8c517 100644 --- a/devices/src/usb/mod.rs +++ b/devices/src/usb/mod.rs @@ -76,7 +76,7 @@ pub struct UsbDeviceRequest { impl ByteCode for UsbDeviceRequest {} /// The data transmission channel. -#[derive(Default, Clone)] +#[derive(Default, Clone, Copy)] pub struct UsbEndpoint { pub ep_number: u8, pub in_direction: bool, @@ -366,9 +366,6 @@ pub trait UsbDevice: Send + Sync { /// Get the controller which the USB device attached. fn get_controller(&self) -> Option>>; - /// Get the endpoint to wakeup. - fn get_wakeup_endpoint(&self) -> &UsbEndpoint; - /// Set the attached USB port. fn set_usb_port(&mut self, port: Option>>) { let usb_dev = self.usb_device_base_mut(); @@ -445,7 +442,7 @@ pub trait UsbDevice: Send + Sync { } /// Notify controller to process data request. -pub fn notify_controller(dev: &Arc>) -> Result<()> { +pub fn notify_controller(dev: &Arc>, ep_id: u8) -> Result<()> { let locked_dev = dev.lock().unwrap(); let xhci = if let Some(cntlr) = &locked_dev.get_controller() { cntlr.upgrade().unwrap() @@ -460,7 +457,6 @@ pub fn notify_controller(dev: &Arc>) -> Result<()> { }; let slot_id = usb_dev.addr; let wakeup = usb_dev.remote_wakeup & USB_DEVICE_REMOTE_WAKEUP == USB_DEVICE_REMOTE_WAKEUP; - let ep = locked_dev.get_wakeup_endpoint().clone(); // Drop the small lock. drop(locked_dev); let mut locked_xhci = xhci.lock().unwrap(); @@ -477,7 +473,7 @@ pub fn notify_controller(dev: &Arc>) -> Result<()> { locked_xhci.port_notify(&usb_port, PORTSC_PLC)?; } } - if let Err(e) = locked_xhci.wakeup_endpoint(slot_id as u32, &ep, 0) { + if let Err(e) = locked_xhci.wakeup_endpoint(slot_id as u32, ep_id as u32, 0) { error!("Failed to wakeup endpoint {:?}", e); } Ok(()) diff --git a/devices/src/usb/storage.rs b/devices/src/usb/storage.rs index 429c7b9b..282169e4 100644 --- a/devices/src/usb/storage.rs +++ b/devices/src/usb/storage.rs @@ -27,7 +27,7 @@ use super::descriptor::{ }; use super::xhci::xhci_controller::XhciDevice; use super::{config::*, USB_DEVICE_BUFFER_DEFAULT_LEN}; -use super::{UsbDevice, UsbDeviceBase, UsbDeviceRequest, UsbEndpoint, UsbPacket, UsbPacketStatus}; +use super::{UsbDevice, UsbDeviceBase, UsbDeviceRequest, UsbPacket, UsbPacketStatus}; use crate::{ ScsiBus::{ ScsiBus, ScsiRequest, ScsiRequestOps, ScsiSense, ScsiXferMode, EMULATE_SCSI_OPS, GOOD, @@ -628,8 +628,4 @@ impl UsbDevice for UsbStorage { fn get_controller(&self) -> Option>> { self.cntlr.clone() } - - fn get_wakeup_endpoint(&self) -> &UsbEndpoint { - self.base.get_endpoint(true, 1) - } } diff --git a/devices/src/usb/tablet.rs b/devices/src/usb/tablet.rs index 78551cb8..b9c54fc9 100644 --- a/devices/src/usb/tablet.rs +++ b/devices/src/usb/tablet.rs @@ -23,10 +23,10 @@ use super::descriptor::{ UsbDescriptorOps, UsbDeviceDescriptor, UsbEndpointDescriptor, UsbInterfaceDescriptor, }; use super::hid::{Hid, HidType, QUEUE_LENGTH, QUEUE_MASK}; -use super::xhci::xhci_controller::XhciDevice; +use super::xhci::xhci_controller::{endpoint_number_to_id, XhciDevice}; use super::{ - config::*, notify_controller, UsbDevice, UsbDeviceBase, UsbDeviceRequest, UsbEndpoint, - UsbPacket, UsbPacketStatus, USB_DEVICE_BUFFER_DEFAULT_LEN, + config::*, notify_controller, UsbDevice, UsbDeviceBase, UsbDeviceRequest, UsbPacket, + UsbPacketStatus, USB_DEVICE_BUFFER_DEFAULT_LEN, }; use machine_manager::config::valid_id; use ui::input::{ @@ -229,7 +229,9 @@ impl PointerOpts for UsbTabletAdapter { locked_tablet.hid.num += 1; drop(locked_tablet); let clone_tablet = self.tablet.clone(); - notify_controller(&(clone_tablet as Arc>)) + // Wakeup endpoint. + let ep_id = endpoint_number_to_id(true, 1); + notify_controller(&(clone_tablet as Arc>), ep_id) } } @@ -300,8 +302,4 @@ impl UsbDevice for UsbTablet { fn get_controller(&self) -> Option>> { self.cntlr.clone() } - - fn get_wakeup_endpoint(&self) -> &UsbEndpoint { - self.base.get_endpoint(true, 1) - } } diff --git a/devices/src/usb/uas.rs b/devices/src/usb/uas.rs index 3baca6a4..688c1cca 100644 --- a/devices/src/usb/uas.rs +++ b/devices/src/usb/uas.rs @@ -31,7 +31,7 @@ use super::descriptor::{ }; use super::xhci::xhci_controller::XhciDevice; use super::{ - UsbDevice, UsbDeviceBase, UsbDeviceRequest, UsbEndpoint, UsbPacket, UsbPacketStatus, + UsbDevice, UsbDeviceBase, UsbDeviceRequest, UsbPacket, UsbPacketStatus, USB_DEVICE_BUFFER_DEFAULT_LEN, }; use crate::{ @@ -935,10 +935,6 @@ impl UsbDevice for UsbUas { fn get_controller(&self) -> Option>> { None } - - fn get_wakeup_endpoint(&self) -> &UsbEndpoint { - self.base.get_endpoint(true, 1) - } } impl UasRequest { diff --git a/devices/src/usb/usbhost/mod.rs b/devices/src/usb/usbhost/mod.rs index 65e05112..5859e19f 100644 --- a/devices/src/usb/usbhost/mod.rs +++ b/devices/src/usb/usbhost/mod.rs @@ -1097,10 +1097,6 @@ impl UsbDevice for UsbHost { None } - fn get_wakeup_endpoint(&self) -> &UsbEndpoint { - self.base.get_endpoint(true, 1) - } - fn handle_control(&mut self, packet: &Arc>, device_req: &UsbDeviceRequest) { trace::usb_host_req_control(self.config.hostbus, self.config.hostaddr, device_req); let mut locked_packet = packet.lock().unwrap(); diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index 02ec9b17..3fe6631e 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -30,7 +30,7 @@ use super::xhci_trb::{ TRB_TYPE_SHIFT, }; use crate::usb::{config::*, TransferOps}; -use crate::usb::{UsbDevice, UsbDeviceRequest, UsbEndpoint, UsbError, UsbPacket, UsbPacketStatus}; +use crate::usb::{UsbDevice, UsbDeviceRequest, UsbError, UsbPacket, UsbPacketStatus}; use address_space::{AddressSpace, GuestAddress}; use machine_manager::event_loop::EventLoop; @@ -2344,21 +2344,15 @@ impl XhciDevice { } /// Used for device to wakeup endpoint - pub fn wakeup_endpoint( - &mut self, - slot_id: u32, - ep: &UsbEndpoint, - stream_id: u32, - ) -> Result<()> { - let ep_id = endpoint_number_to_id(ep.in_direction, ep.ep_number); - if let Err(e) = self.get_endpoint_ctx(slot_id, ep_id as u32) { + pub fn wakeup_endpoint(&mut self, slot_id: u32, ep_id: u32, stream_id: u32) -> Result<()> { + if let Err(e) = self.get_endpoint_ctx(slot_id, ep_id) { trace::usb_xhci_unimplemented(&format!( "Invalid slot id or ep id, maybe device not activated, {:?}", e )); return Ok(()); } - self.kick_endpoint(slot_id, ep_id as u32, stream_id)?; + self.kick_endpoint(slot_id, ep_id, stream_id)?; Ok(()) } @@ -2516,7 +2510,7 @@ fn endpoint_id_to_number(ep_id: u8) -> (bool, u8) { (ep_id & 1 == 1, ep_id >> 1) } -fn endpoint_number_to_id(in_direction: bool, ep_number: u8) -> u8 { +pub fn endpoint_number_to_id(in_direction: bool, ep_number: u8) -> u8 { if ep_number == 0 { // Control endpoint. 1 -- Gitee From d92d33a9da66c23541dfbb6cf30d77e46433b699 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Tue, 16 Jul 2024 09:59:32 +0800 Subject: [PATCH 186/489] chardev: check output validation When the socket is closed, output would be set to None. So we should check output validation otherwise it would panic low potentially. Signed-off-by: Zhao Yi Min --- chardev_backend/src/chardev.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/chardev_backend/src/chardev.rs b/chardev_backend/src/chardev.rs index 8b065f99..d13d306e 100644 --- a/chardev_backend/src/chardev.rs +++ b/chardev_backend/src/chardev.rs @@ -301,6 +301,9 @@ impl Chardev { } fn consume_outbuf(&mut self) -> Result<()> { + if self.output.is_none() { + bail!("no output interface"); + } let output = self.output.as_ref().unwrap(); while !self.outbuf.is_empty() { if write_buffer_async(output.clone(), self.outbuf.front_mut().unwrap())? { -- Gitee From ededff2274d8de2da6ef411031521b783230b03c Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Tue, 28 Nov 2023 02:28:08 +0800 Subject: [PATCH 187/489] devices: Implement devicebase/busbase struct and Device/Bus trait We will implement a topology structure of ` Bus 1- Device 1- Bus 2` just like hardware. Implement devicebase/busbase struct and Device/Bus trait as the first step. The new topology follows the following rules: 1. Devices should implement Device trait. 2. Buses should implement Bus trait. 3. Every device must attached to its parent bus and may have extended child bus. 4. Every bus must attached to its parent device and may have devices which attached to it. Signed-off-by: liuxiangdong --- devices/src/lib.rs | 105 ++++++++++++++++++++++++++- devices/src/misc/ivshmem.rs | 2 +- devices/src/misc/pvpanic.rs | 5 +- devices/src/pci/bus.rs | 18 +++-- devices/src/pci/demo_device/mod.rs | 2 +- devices/src/pci/hotplug.rs | 5 +- devices/src/pci/mod.rs | 8 +- devices/src/pci/msix.rs | 4 +- devices/src/pci/root_port.rs | 2 +- devices/src/scsi/bus.rs | 12 ++- devices/src/scsi/disk.rs | 2 +- devices/src/sysbus/mod.rs | 9 ++- devices/src/usb/mod.rs | 2 +- devices/src/usb/xhci/xhci_pci.rs | 2 +- machine/src/aarch64/pci_host_root.rs | 2 +- machine/src/lib.rs | 3 +- machine/src/x86_64/ich9_lpc.rs | 6 +- machine/src/x86_64/mch.rs | 6 +- vfio/src/vfio_pci.rs | 2 +- virtio/src/transport/virtio_mmio.rs | 2 +- virtio/src/transport/virtio_pci.rs | 2 +- 21 files changed, 163 insertions(+), 38 deletions(-) diff --git a/devices/src/lib.rs b/devices/src/lib.rs index 491ca1d5..404a8c20 100644 --- a/devices/src/lib.rs +++ b/devices/src/lib.rs @@ -40,7 +40,10 @@ pub use scsi::bus as ScsiBus; pub use scsi::disk as ScsiDisk; use std::any::Any; +use std::collections::BTreeMap; +use std::sync::{Arc, Mutex, Weak}; +use anyhow::{bail, Context, Result}; use util::AsAny; #[derive(Clone, Default)] @@ -49,15 +52,24 @@ pub struct DeviceBase { pub id: String, /// Whether it supports hot-plug/hot-unplug. pub hotpluggable: bool, + /// parent bus. + pub parent: Option>>, + /// Child bus. + pub child: Option>>, } impl DeviceBase { - pub fn new(id: String, hotpluggable: bool) -> Self { - DeviceBase { id, hotpluggable } + pub fn new(id: String, hotpluggable: bool, parent: Option>>) -> Self { + DeviceBase { + id, + hotpluggable, + parent, + child: None, + } } } -pub trait Device: Any + AsAny { +pub trait Device: Any + AsAny + Send + Sync { fn device_base(&self) -> &DeviceBase; fn device_base_mut(&mut self) -> &mut DeviceBase; @@ -71,6 +83,93 @@ pub trait Device: Any + AsAny { fn hotpluggable(&self) -> bool { self.device_base().hotpluggable } + + /// Get the bus which this device is mounted on. + fn parent_bus(&self) -> Option>> { + self.device_base().parent.clone() + } + + /// Get the bus which this device has. + fn child_bus(&self) -> Option>> { + self.device_base().child.clone() + } +} + +#[derive(Default)] +pub struct BusBase { + /// Name of this bus. + pub name: String, + /// Parent device. + pub parent: Option>>, + /// Children devices. + /// + /// Note: + /// 1. The construction of FDT table needs to strictly follow the order of sysbus, + /// so `BTreemap` needs to be used. + /// 2. every device has a unique address on the bus. Using `u64` is sufficient for we can + /// convert it to u8(devfn) for PCI bus and convert it to (u8, u16)(target, lun) for SCSI bus. + /// SysBus doesn't need this unique `u64` address, so we will incrementally fill in a useless number. + pub children: BTreeMap>>, +} + +impl BusBase { + fn new(name: String) -> BusBase { + Self { + name, + ..Default::default() + } + } +} + +pub trait Bus: Send + Sync { + fn bus_base(&self) -> &BusBase; + + fn bus_base_mut(&mut self) -> &mut BusBase; + + /// Get the name of this bus. + fn name(&self) -> String { + self.bus_base().name.clone() + } + + /// Get the device that owns this bus. + fn parent_device(&self) -> Option>> { + self.bus_base().parent.clone() + } + + /// Get the devices mounted on this bus. + fn child_devices(&self) -> BTreeMap>> { + self.bus_base().children.clone() + } + + /// Get the specific device mounted on this bus. + fn child_dev(&self, key: u64) -> Option<&Arc>> { + self.bus_base().children.get(&key) + } + + /// Attach device to this bus. + fn attach_child(&mut self, key: u64, dev: Arc>) -> Result<()> { + let children = &mut self.bus_base_mut().children; + if children.get(&key).is_some() { + bail!( + "Location of the device {} is same as one of the bus {}", + dev.lock().unwrap().name(), + self.name() + ); + } + children.insert(key, dev); + + Ok(()) + } + + /// Detach device from this bus. + fn detach_child(&mut self, key: u64) -> Result<()> { + self.bus_base_mut() + .children + .remove(&key) + .with_context(|| format!("No such device using key {} in bus {}.", key, self.name()))?; + + Ok(()) + } } #[cfg(test)] diff --git a/devices/src/misc/ivshmem.rs b/devices/src/misc/ivshmem.rs index cc9e383f..acb9cc1a 100644 --- a/devices/src/misc/ivshmem.rs +++ b/devices/src/misc/ivshmem.rs @@ -52,7 +52,7 @@ impl Ivshmem { ) -> Self { Self { base: PciDevBase { - base: DeviceBase::new(name, false), + base: DeviceBase::new(name, false, Some(parent_bus.clone())), config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, PCI_BAR_MAX_IVSHMEM), devfn, parent_bus, diff --git a/devices/src/misc/pvpanic.rs b/devices/src/misc/pvpanic.rs index cdebea6c..2e2444ea 100644 --- a/devices/src/misc/pvpanic.rs +++ b/devices/src/misc/pvpanic.rs @@ -112,7 +112,7 @@ impl PvPanicPci { pub fn new(config: &PvpanicDevConfig, devfn: u8, parent_bus: Weak>) -> Self { Self { base: PciDevBase { - base: DeviceBase::new(config.id.clone(), false), + base: DeviceBase::new(config.id.clone(), false, Some(parent_bus.clone())), config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 1), devfn, parent_bus, @@ -262,6 +262,7 @@ impl PciDevOps for PvPanicPci { mod tests { use super::*; use crate::pci::{host::tests::create_pci_host, le_read_u16, PciHost}; + use crate::Bus; use machine_manager::config::str_slip_to_clap; fn init_pvpanic_dev(devfn: u8, supported_features: u32, dev_id: &str) -> Arc> { @@ -320,7 +321,7 @@ mod tests { let info = PciBus::find_attached_bus(&locked_pci_host.root_bus, "pvpanic_test"); assert!(info.is_some()); let (bus, dev) = info.unwrap(); - assert_eq!(bus.lock().unwrap().name, "pcie.0"); + assert_eq!(bus.lock().unwrap().name(), "pcie.0"); assert_eq!(dev.lock().unwrap().name(), "pvpanic_test"); } diff --git a/devices/src/pci/bus.rs b/devices/src/pci/bus.rs index 0524caa0..d87d5d85 100644 --- a/devices/src/pci/bus.rs +++ b/devices/src/pci/bus.rs @@ -22,15 +22,15 @@ use super::{ hotplug::HotplugOps, PciDevOps, PciIntxState, }; -use crate::MsiIrqManager; +use crate::{Bus, BusBase, MsiIrqManager}; use address_space::Region; +use util::gen_base_func; type DeviceBusInfo = (Arc>, Arc>); /// PCI bus structure. pub struct PciBus { - /// Bus name - pub name: String, + pub base: BusBase, /// Devices attached to the bus. pub devices: HashMap>>, /// Child buses of the bus. @@ -49,6 +49,10 @@ pub struct PciBus { pub msi_irq_manager: Option>, } +impl Bus for PciBus { + gen_base_func!(bus_base, bus_base_mut, BusBase, base); +} + impl PciBus { /// Create new bus entity. /// @@ -63,7 +67,7 @@ impl PciBus { mem_region: Region, ) -> Self { Self { - name, + base: BusBase::new(name), devices: HashMap::new(), child_buses: Vec::new(), parent_bridge: None, @@ -145,7 +149,7 @@ impl PciBus { /// * `name` - Bus name. pub fn find_bus_by_name(bus: &Arc>, bus_name: &str) -> Option>> { let locked_bus = bus.lock().unwrap(); - if locked_bus.name.as_str() == bus_name { + if locked_bus.name().as_str() == bus_name { return Some((*bus).clone()); } for sub_bus in &locked_bus.child_buses { @@ -303,13 +307,13 @@ mod tests { let info = PciBus::find_attached_bus(&locked_pci_host.root_bus, "test1"); assert!(info.is_some()); let (bus, dev) = info.unwrap(); - assert_eq!(bus.lock().unwrap().name, "pcie.0"); + assert_eq!(bus.lock().unwrap().name(), "pcie.0"); assert_eq!(dev.lock().unwrap().name(), "test1"); let info = PciBus::find_attached_bus(&locked_pci_host.root_bus, "test2"); assert!(info.is_some()); let (bus, dev) = info.unwrap(); - assert_eq!(bus.lock().unwrap().name, "pcie.1"); + assert_eq!(bus.lock().unwrap().name(), "pcie.1"); assert_eq!(dev.lock().unwrap().name(), "test2"); } diff --git a/devices/src/pci/demo_device/mod.rs b/devices/src/pci/demo_device/mod.rs index 987120c3..52e1381d 100644 --- a/devices/src/pci/demo_device/mod.rs +++ b/devices/src/pci/demo_device/mod.rs @@ -109,7 +109,7 @@ impl DemoDev { }; DemoDev { base: PciDevBase { - base: DeviceBase::new(cfg.id.clone(), false), + base: DeviceBase::new(cfg.id.clone(), false, Some(parent_bus.clone())), config: PciConfig::new(PCIE_CONFIG_SPACE_SIZE, cfg.bar_num), devfn, parent_bus, diff --git a/devices/src/pci/hotplug.rs b/devices/src/pci/hotplug.rs index df5bfca3..24533a24 100644 --- a/devices/src/pci/hotplug.rs +++ b/devices/src/pci/hotplug.rs @@ -15,6 +15,7 @@ use std::sync::{Arc, Mutex}; use anyhow::{bail, Context, Result}; use crate::pci::{PciBus, PciDevOps}; +use crate::Bus; pub trait HotplugOps: Send { /// Plug device, usually called when hot plug device in device_add. @@ -47,7 +48,7 @@ pub fn handle_plug(bus: &Arc>, dev: &Arc>) -> } else { bail!( "No hot plug controller found for bus {} when plug", - locked_bus.name + locked_bus.name() ); } } @@ -76,7 +77,7 @@ pub fn handle_unplug_pci_request( .with_context(|| { format!( "No hot plug controller found for bus {} when unplug request", - locked_bus.name + locked_bus.name() ) })?; // No need to hold the lock. diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs index 9142c9fd..b3168e7a 100644 --- a/devices/src/pci/mod.rs +++ b/devices/src/pci/mod.rs @@ -44,7 +44,7 @@ use crate::misc::ivshmem::Ivshmem; use crate::misc::pvpanic::PvPanicPci; use crate::pci::config::{HEADER_TYPE, HEADER_TYPE_MULTIFUNC, MAX_FUNC}; use crate::usb::xhci::xhci_pci::XhciPciDevice; -use crate::{Device, DeviceBase, MsiIrqManager}; +use crate::{Bus, Device, DeviceBase, MsiIrqManager}; #[cfg(feature = "demo_device")] use demo_device::DemoDev; @@ -221,7 +221,7 @@ pub trait PciDevOps: Device + Send { /// Get the path of the PCI bus where the device resides. fn get_parent_dev_path(&self, parent_bus: Arc>) -> String { let locked_parent_bus = parent_bus.lock().unwrap(); - let parent_dev_path = if locked_parent_bus.name.eq("pcie.0") { + let parent_dev_path = if locked_parent_bus.name().eq("pcie.0") { String::from("/pci@ffffffffffffffff") } else { // This else branch will not be executed currently, @@ -368,7 +368,7 @@ pub fn init_multifunction( // Function 0 should set multifunction bit. bail!( "PCI: single function device can't be populated in bus {} function {}.{}", - &locked_bus.name, + &locked_bus.name(), slot, devfn & 0x07 ); @@ -418,7 +418,7 @@ mod tests { pub fn new(name: &str, devfn: u8, parent_bus: Weak>) -> Self { Self { base: PciDevBase { - base: DeviceBase::new(name.to_string(), false), + base: DeviceBase::new(name.to_string(), false, Some(parent_bus.clone())), config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 0), devfn, parent_bus, diff --git a/devices/src/pci/msix.rs b/devices/src/pci/msix.rs index 451a6638..3d403402 100644 --- a/devices/src/pci/msix.rs +++ b/devices/src/pci/msix.rs @@ -644,7 +644,7 @@ mod tests { #[test] fn test_init_msix() { let mut base = PciDevBase { - base: DeviceBase::new("msix".to_string(), false), + base: DeviceBase::new("msix".to_string(), false, None), config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 2), devfn: 1, parent_bus: Weak::new(), @@ -747,7 +747,7 @@ mod tests { #[test] fn test_write_config() { let mut base = PciDevBase { - base: DeviceBase::new("msix".to_string(), false), + base: DeviceBase::new("msix".to_string(), false, None), config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 2), devfn: 1, parent_bus: Weak::new(), diff --git a/devices/src/pci/root_port.rs b/devices/src/pci/root_port.rs index 9d3bcf25..b6349058 100644 --- a/devices/src/pci/root_port.rs +++ b/devices/src/pci/root_port.rs @@ -121,7 +121,7 @@ impl RootPort { Self { base: PciDevBase { - base: DeviceBase::new(cfg.id, true), + base: DeviceBase::new(cfg.id, true, Some(parent_bus.clone())), config: PciConfig::new(PCIE_CONFIG_SPACE_SIZE, 2), devfn, parent_bus, diff --git a/devices/src/scsi/bus.rs b/devices/src/scsi/bus.rs index 8a222653..b816bdd7 100644 --- a/devices/src/scsi/bus.rs +++ b/devices/src/scsi/bus.rs @@ -24,8 +24,9 @@ use crate::ScsiDisk::{ SCSI_DISK_DEFAULT_BLOCK_SIZE_SHIFT, SCSI_DISK_F_DPOFUA, SCSI_DISK_F_REMOVABLE, SCSI_TYPE_DISK, SCSI_TYPE_ROM, SECTOR_SHIFT, }; +use crate::{Bus, BusBase}; use util::aio::{AioCb, AioReqResult, Iovec}; -use util::AsAny; +use util::{gen_base_func, AsAny}; /// Scsi Operation code. pub const TEST_UNIT_READY: u8 = 0x00; @@ -367,16 +368,19 @@ pub enum ScsiXferMode { } pub struct ScsiBus { - /// Bus name. - pub name: String, + pub base: BusBase, /// Scsi Devices attached to the bus. pub devices: HashMap<(u8, u16), Arc>>, } +impl Bus for ScsiBus { + gen_base_func!(bus_base, bus_base_mut, BusBase, base); +} + impl ScsiBus { pub fn new(bus_name: String) -> ScsiBus { ScsiBus { - name: bus_name, + base: BusBase::new(bus_name), devices: HashMap::new(), } } diff --git a/devices/src/scsi/disk.rs b/devices/src/scsi/disk.rs index 1f88cf0a..8aab9a22 100644 --- a/devices/src/scsi/disk.rs +++ b/devices/src/scsi/disk.rs @@ -182,7 +182,7 @@ impl ScsiDevice { }; ScsiDevice { - base: DeviceBase::new(dev_cfg.id.clone(), false), + base: DeviceBase::new(dev_cfg.id.clone(), false, None), dev_cfg, drive_cfg, state: ScsiDevState::new(), diff --git a/devices/src/sysbus/mod.rs b/devices/src/sysbus/mod.rs index 1e56f363..05479a3c 100644 --- a/devices/src/sysbus/mod.rs +++ b/devices/src/sysbus/mod.rs @@ -35,9 +35,10 @@ use crate::legacy::{FwCfgIO, RTC}; use crate::legacy::{FwCfgMem, PL011, PL031}; use crate::legacy::{PFlash, Serial}; use crate::pci::PciHost; -use crate::{Device, DeviceBase, IrqState, LineIrqManager, TriggerMode}; +use crate::{Bus, BusBase, Device, DeviceBase, IrqState, LineIrqManager, TriggerMode}; use acpi::{AmlBuilder, AmlScope}; use address_space::{AddressSpace, GuestAddress, Region, RegionIoEventFd, RegionOps}; +use util::gen_base_func; // Now that the serial device use a hardcoded IRQ number (4), and the starting // free IRQ number can be 5. @@ -53,6 +54,7 @@ pub const IRQ_BASE: i32 = 32; pub const IRQ_MAX: i32 = 191; pub struct SysBus { + pub base: BusBase, #[cfg(target_arch = "x86_64")] pub sys_io: Arc, pub sys_mem: Arc, @@ -89,6 +91,7 @@ impl SysBus { mmio_region: (u64, u64), ) -> Self { Self { + base: BusBase::new("sysbus".to_string()), #[cfg(target_arch = "x86_64")] sys_io: sys_io.clone(), sys_mem: sys_mem.clone(), @@ -157,6 +160,10 @@ impl SysBus { } } +impl Bus for SysBus { + gen_base_func!(bus_base, bus_base_mut, BusBase, base); +} + #[derive(Clone)] pub struct SysRes { // Note: region_base/region_size are both 0 means that this device doesn't have its own memory layout. diff --git a/devices/src/usb/mod.rs b/devices/src/usb/mod.rs index 5fc8c517..f8dc2f90 100644 --- a/devices/src/usb/mod.rs +++ b/devices/src/usb/mod.rs @@ -130,7 +130,7 @@ pub struct UsbDeviceBase { impl UsbDeviceBase { pub fn new(id: String, data_buf_len: usize) -> Self { let mut dev = UsbDeviceBase { - base: DeviceBase::new(id, false), + base: DeviceBase::new(id, false, None), port: None, speed: 0, addr: 0, diff --git a/devices/src/usb/xhci/xhci_pci.rs b/devices/src/usb/xhci/xhci_pci.rs index 8a7208e6..cdcd50cb 100644 --- a/devices/src/usb/xhci/xhci_pci.rs +++ b/devices/src/usb/xhci/xhci_pci.rs @@ -113,7 +113,7 @@ impl XhciPciDevice { ) -> Self { Self { base: PciDevBase { - base: DeviceBase::new(config.id.clone().unwrap(), true), + base: DeviceBase::new(config.id.clone().unwrap(), true, Some(parent_bus.clone())), config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 1), devfn, parent_bus, diff --git a/machine/src/aarch64/pci_host_root.rs b/machine/src/aarch64/pci_host_root.rs index 512cf8f3..7192fbbe 100644 --- a/machine/src/aarch64/pci_host_root.rs +++ b/machine/src/aarch64/pci_host_root.rs @@ -35,7 +35,7 @@ impl PciHostRoot { pub fn new(parent_bus: Weak>) -> Self { Self { base: PciDevBase { - base: DeviceBase::new("PCI Host Root".to_string(), false), + base: DeviceBase::new("PCI Host Root".to_string(), false, Some(parent_bus.clone())), config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 0), parent_bus, devfn: 0, diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 8e6c668e..1b71e85b 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -71,6 +71,7 @@ use devices::usb::uas::{UsbUas, UsbUasConfig}; use devices::usb::usbhost::{UsbHost, UsbHostConfig}; use devices::usb::xhci::xhci_pci::{XhciConfig, XhciPciDevice}; use devices::usb::UsbDevice; +use devices::Bus; #[cfg(target_arch = "aarch64")] use devices::InterruptController; use devices::ScsiDisk::{ScsiDevConfig, ScsiDevice}; @@ -1511,7 +1512,7 @@ pub trait MachineOps: MachineLifecycle { .with_context(|| format!("Bus not found, dev id {}", dev_id))? .0; let locked_bus = bus.lock().unwrap(); - if locked_bus.name == "pcie.0" { + if locked_bus.name() == "pcie.0" { // No need to reset root bus return Ok(()); } diff --git a/machine/src/x86_64/ich9_lpc.rs b/machine/src/x86_64/ich9_lpc.rs index 4038e503..83e1e4a5 100644 --- a/machine/src/x86_64/ich9_lpc.rs +++ b/machine/src/x86_64/ich9_lpc.rs @@ -64,7 +64,11 @@ impl LPCBridge { ) -> Result { Ok(Self { base: PciDevBase { - base: DeviceBase::new("ICH9 LPC bridge".to_string(), false), + base: DeviceBase::new( + "ICH9 LPC bridge".to_string(), + false, + Some(parent_bus.clone()), + ), config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 0), devfn: 0x1F << 3, parent_bus, diff --git a/machine/src/x86_64/mch.rs b/machine/src/x86_64/mch.rs index ddf7bd67..a025281e 100644 --- a/machine/src/x86_64/mch.rs +++ b/machine/src/x86_64/mch.rs @@ -57,7 +57,11 @@ impl Mch { ) -> Self { Self { base: PciDevBase { - base: DeviceBase::new("Memory Controller Hub".to_string(), false), + base: DeviceBase::new( + "Memory Controller Hub".to_string(), + false, + Some(parent_bus.clone()), + ), config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 0), devfn: 0, parent_bus, diff --git a/vfio/src/vfio_pci.rs b/vfio/src/vfio_pci.rs index 7a74badc..391fba16 100644 --- a/vfio/src/vfio_pci.rs +++ b/vfio/src/vfio_pci.rs @@ -132,7 +132,7 @@ impl VfioPciDevice { Self { // Unknown PCI or PCIe type here, allocate enough space to match the two types. base: PciDevBase { - base: DeviceBase::new(name, true), + base: DeviceBase::new(name, true, Some(parent_bus.clone())), config: PciConfig::new(PCIE_CONFIG_SPACE_SIZE, PCI_NUM_BARS), devfn, parent_bus, diff --git a/virtio/src/transport/virtio_mmio.rs b/virtio/src/transport/virtio_mmio.rs index 5d07ce77..8e872a38 100644 --- a/virtio/src/transport/virtio_mmio.rs +++ b/virtio/src/transport/virtio_mmio.rs @@ -148,7 +148,7 @@ impl VirtioMmioDevice { let queue_num = device.lock().unwrap().queue_num(); let mut mmio_device = VirtioMmioDevice { base: SysBusDevBase { - base: DeviceBase::new(name, false), + base: DeviceBase::new(name, false, None), dev_type: SysBusDevType::VirtioMmio, interrupt_evt: Some(Arc::new(create_new_eventfd()?)), ..Default::default() diff --git a/virtio/src/transport/virtio_pci.rs b/virtio/src/transport/virtio_pci.rs index d80ded3c..a4eabe2b 100644 --- a/virtio/src/transport/virtio_pci.rs +++ b/virtio/src/transport/virtio_pci.rs @@ -332,7 +332,7 @@ impl VirtioPciDevice { let queue_num = device.lock().unwrap().queue_num(); VirtioPciDevice { base: PciDevBase { - base: DeviceBase::new(name, true), + base: DeviceBase::new(name, true, Some(parent_bus.clone())), config: PciConfig::new(PCIE_CONFIG_SPACE_SIZE, VIRTIO_PCI_BAR_MAX), devfn, parent_bus, -- Gitee From 330a8eeccdfa112e1cd4968ce07ff0c7cdc27174 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 20 Jun 2024 19:38:45 +0800 Subject: [PATCH 188/489] devices: add method for converting from trait object to struct object Step 1. Add function device_as_any and bus_as_any: Currently, AsAny trait uses Any trait as a generic parameter. Any trait requires a `'static` lifecycle. This framework involves a large number of local variable transformations which don't have `'static` lifecycle. If AsAny is used directly on these local variables, an error "borrowed value does not live long enough"/ "argument requires that `XXXXX` is borrowed for `'static`" will be reported. So, add device/bus_as_any functions to make preparation for the runtime conversion. Step 2. Add convert_device/bus_ref/mut macro: We can use `downcast_mut/ref` after step 1, and then we can complete the runtime conversion from trait object to struct object by using device_as_any/device_as_any. Signed-off-by: liuxiangdong --- devices/src/lib.rs | 86 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 85 insertions(+), 1 deletion(-) diff --git a/devices/src/lib.rs b/devices/src/lib.rs index 404a8c20..33f9af56 100644 --- a/devices/src/lib.rs +++ b/devices/src/lib.rs @@ -74,6 +74,13 @@ pub trait Device: Any + AsAny + Send + Sync { fn device_base_mut(&mut self) -> &mut DeviceBase; + /// `Any` trait requires a `'static` lifecycle. Error "argument requires that `device` is borrowed for `'static`" + /// will be reported when using `as_any` directly for local variables which don't have `'static` lifecycle. + /// Encapsulation of `as_any` can solve this problem. + fn device_as_any(&mut self) -> &mut dyn Any { + self.as_any_mut() + } + /// Get device name. fn name(&self) -> String { self.device_base().id.clone() @@ -95,6 +102,44 @@ pub trait Device: Any + AsAny + Send + Sync { } } +/// Macro `convert_device_ref!`: Convert from Arc> to &$device_type. +/// +/// # Arguments +/// +/// * `$trait_device` - Variable defined as Arc>. +/// * `$lock_device` - Variable used to get MutexGuard<'_, dyn Device>. +/// * `$struct_device` - Variable used to get &$device_type. +/// * `$device_type` - Struct corresponding to device type. +#[macro_export] +macro_rules! convert_device_ref { + ($trait_device:expr, $lock_device: ident, $struct_device: ident, $device_type: ident) => { + let mut $lock_device = $trait_device.lock().unwrap(); + let $struct_device = $lock_device + .device_as_any() + .downcast_ref::<$device_type>() + .unwrap(); + }; +} + +/// Macro `convert_device_mut!`: Convert from Arc> to &mut $device_type. +/// +/// # Arguments +/// +/// * `$trait_device` - Variable defined as Arc>. +/// * `$lock_device` - Variable used to get MutexGuard<'_, dyn Device>. +/// * `$struct_device` - Variable used to get &mut $device_type. +/// * `$device_type` - Struct corresponding to device type. +#[macro_export] +macro_rules! convert_device_mut { + ($trait_device:expr, $lock_device: ident, $struct_device: ident, $device_type: ident) => { + let mut $lock_device = $trait_device.lock().unwrap(); + let $struct_device = $lock_device + .device_as_any() + .downcast_mut::<$device_type>() + .unwrap(); + }; +} + #[derive(Default)] pub struct BusBase { /// Name of this bus. @@ -121,11 +166,18 @@ impl BusBase { } } -pub trait Bus: Send + Sync { +pub trait Bus: Any + AsAny + Send + Sync { fn bus_base(&self) -> &BusBase; fn bus_base_mut(&mut self) -> &mut BusBase; + /// `Any` trait requires a `'static` lifecycle. Error "argument requires that `bus` is borrowed for `'static`" + /// will be reported when using `as_any` directly for local variables which don't have `'static` lifecycle. + /// Encapsulation of `as_any` can solve this problem. + fn bus_as_any(&mut self) -> &mut dyn Any { + self.as_any_mut() + } + /// Get the name of this bus. fn name(&self) -> String { self.bus_base().name.clone() @@ -172,6 +224,38 @@ pub trait Bus: Send + Sync { } } +/// Macro `convert_bus_ref!`: Convert from Arc> to &$bus_type. +/// +/// # Arguments +/// +/// * `$trait_bus` - Variable defined as Arc>. +/// * `$lock_bus` - Variable used to get MutexGuard<'_, dyn Bus>. +/// * `$struct_bus` - Variable used to get &$bus_type. +/// * `$bus_type` - Struct corresponding to bus type. +#[macro_export] +macro_rules! convert_bus_ref { + ($trait_bus:expr, $lock_bus: ident, $struct_bus: ident, $bus_type: ident) => { + let mut $lock_bus = $trait_bus.lock().unwrap(); + let $struct_bus = $lock_bus.bus_as_any().downcast_ref::<$bus_type>().unwrap(); + }; +} + +/// Macro `convert_bus_mut!`: Convert from Arc> to &mut $bus_type. +/// +/// # Arguments +/// +/// * `$trait_bus` - Variable defined as Arc>. +/// * `$lock_bus` - Variable used to get MutexGuard<'_, dyn Bus>. +/// * `$struct_bus` - Variable used to get &mut $bus_type. +/// * `$bus_type` - Struct corresponding to bus type. +#[macro_export] +macro_rules! convert_bus_mut { + ($trait_bus:expr, $lock_bus: ident, $struct_bus: ident, $bus_type: ident) => { + let mut $lock_bus = $trait_bus.lock().unwrap(); + let $struct_bus = $lock_bus.bus_as_any().downcast_mut::<$bus_type>().unwrap(); + }; +} + #[cfg(test)] pub mod test { use std::sync::Arc; -- Gitee From 1d820c8e03df07657841db6f49a8cbcb8f7b9583 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Tue, 28 Nov 2023 14:11:49 +0800 Subject: [PATCH 189/489] devices/scsi: adjust the scsi bus/disk module to the new framework Adjust the scsi bus/disk module to the new framework: 1.Scsi Bus have scsi disks as its child devices. 2.Scsi Disk have an scsi bus as its parent bus. Signed-off-by: liuxiangdong --- devices/src/scsi/bus.rs | 214 +++++++++++++++++--------------- devices/src/scsi/disk.rs | 15 ++- devices/src/usb/storage.rs | 8 +- devices/src/usb/uas.rs | 14 +-- machine/src/lib.rs | 18 +-- virtio/src/device/scsi_cntlr.rs | 14 ++- 6 files changed, 151 insertions(+), 132 deletions(-) diff --git a/devices/src/scsi/bus.rs b/devices/src/scsi/bus.rs index b816bdd7..cc7c7269 100644 --- a/devices/src/scsi/bus.rs +++ b/devices/src/scsi/bus.rs @@ -11,7 +11,6 @@ // See the Mulan PSL v2 for more details. use std::cmp; -use std::collections::HashMap; use std::io::Write; use std::sync::{Arc, Mutex}; @@ -24,7 +23,7 @@ use crate::ScsiDisk::{ SCSI_DISK_DEFAULT_BLOCK_SIZE_SHIFT, SCSI_DISK_F_DPOFUA, SCSI_DISK_F_REMOVABLE, SCSI_TYPE_DISK, SCSI_TYPE_ROM, SECTOR_SHIFT, }; -use crate::{Bus, BusBase}; +use crate::{convert_bus_ref, convert_device_ref, Bus, BusBase, Device, SCSI_DEVICE}; use util::aio::{AioCb, AioReqResult, Iovec}; use util::{gen_base_func, AsAny}; @@ -357,6 +356,11 @@ const GC_FC_CORE: u16 = 0x0001; /// The medium may be removed from the device. const GC_FC_REMOVABLE_MEDIUM: u16 = 0x0003; +// BusBase.Children uses `u64` for device's unique address. We use bits [32-39] in `u64` +// to represent the target number and bits[0-15] in `u64` to the lun number. +const TARGET_ID_SHIFT: u64 = 32; +const LUN_ID_MASK: u64 = 0xFFFF; + #[derive(Clone, PartialEq, Eq)] pub enum ScsiXferMode { /// TEST_UNIT_READY, ... @@ -367,21 +371,36 @@ pub enum ScsiXferMode { ScsiXferToDev, } +// Convert from (target, lun) to unique address in BusBase. +pub fn get_scsi_key(target: u8, lun: u16) -> u64 { + (target as u64) << TARGET_ID_SHIFT | lun as u64 +} + +// Convert from unique address in BusBase to (target, lun). +fn parse_scsi_key(key: u64) -> (u8, u16) { + ((key >> TARGET_ID_SHIFT) as u8, (key & LUN_ID_MASK) as u16) +} + pub struct ScsiBus { pub base: BusBase, - /// Scsi Devices attached to the bus. - pub devices: HashMap<(u8, u16), Arc>>, } impl Bus for ScsiBus { gen_base_func!(bus_base, bus_base_mut, BusBase, base); } +/// Convert from Arc> to &ScsiBus. +#[macro_export] +macro_rules! SCSI_BUS { + ($trait_bus:expr, $lock_bus: ident, $struct_bus: ident) => { + convert_bus_ref!($trait_bus, $lock_bus, $struct_bus, ScsiBus); + }; +} + impl ScsiBus { pub fn new(bus_name: String) -> ScsiBus { ScsiBus { base: BusBase::new(bus_name), - devices: HashMap::new(), } } @@ -389,9 +408,9 @@ impl ScsiBus { /// If the device requested by the target number and the lun number is non-existen, /// return the first device in ScsiBus's devices list. It's OK because we will not /// use this "random" device, we will just use it to prove that the target is existen. - pub fn get_device(&self, target: u8, lun: u16) -> Option>> { - if let Some(dev) = self.devices.get(&(target, lun)) { - return Some((*dev).clone()); + pub fn get_device(&self, target: u8, lun: u16) -> Option>> { + if let Some(device) = self.child_dev(get_scsi_key(target, lun)) { + return Some(device.clone()); } // If lun device requested in CDB's LUNS bytes is not found, it may be a target request. @@ -400,11 +419,11 @@ impl ScsiBus { // is non-existent. So, we should find if there exists a lun which has the same id with // target id in CBD's LUNS bytes. And, if there exist two or more luns which have the same // target id, just return the first one is OK enough. - for (id, device) in self.devices.iter() { - let (target_id, lun_id) = id; - if *target_id == target { - trace::scsi_bus_get_device(*target_id, lun, *lun_id); - return Some((*device).clone()); + for (key, device) in self.child_devices() { + let (target_id, lun_id) = parse_scsi_key(key); + if target_id == target { + trace::scsi_bus_get_device(target_id, lun, lun_id); + return Some(device.clone()); } } @@ -417,7 +436,7 @@ impl ScsiBus { fn scsi_bus_parse_req_cdb( cdb: [u8; SCSI_CMD_BUF_SIZE], - dev: Arc>, + dev: Arc>, ) -> Option { let op = cdb[0]; let len = scsi_cdb_length(&cdb); @@ -496,7 +515,7 @@ pub struct ScsiRequest { pub iovec: Vec, // Provided buffer's length. pub datalen: u32, - pub dev: Arc>, + pub dev: Arc>, // Upper level request which contains this ScsiRequest. pub upper_req: Box, } @@ -507,18 +526,17 @@ impl ScsiRequest { req_lun: u16, iovec: Vec, datalen: u32, - scsidevice: Arc>, + device: Arc>, upper_req: Box, ) -> Result { - let cmd = scsi_bus_parse_req_cdb(cdb, scsidevice.clone()).with_context(|| "Error cdb!")?; + let cmd = scsi_bus_parse_req_cdb(cdb, device.clone()).with_context(|| "Error cdb!")?; let op = cmd.op; let opstype = scsi_operation_type(op); if op == WRITE_10 || op == READ_10 { - let dev_lock = scsidevice.lock().unwrap(); - let disk_size = dev_lock.disk_sectors << SECTOR_SHIFT; - let disk_type = dev_lock.scsi_type; - drop(dev_lock); + SCSI_DEVICE!(device, locked_dev, scsi_dev); + let disk_size = scsi_dev.disk_sectors << SECTOR_SHIFT; + let disk_type = scsi_dev.scsi_type; let offset_shift = match disk_type { SCSI_TYPE_DISK => SCSI_DISK_DEFAULT_BLOCK_SIZE_SHIFT, _ => SCSI_CDROM_DEFAULT_BLOCK_SIZE_SHIFT, @@ -545,7 +563,7 @@ impl ScsiRequest { opstype, iovec, datalen, - dev: scsidevice, + dev: device, upper_req, }) } @@ -554,14 +572,14 @@ impl ScsiRequest { let mode = self.cmd.mode.clone(); let op = self.cmd.op; let dev = self.dev.clone(); - let locked_dev = dev.lock().unwrap(); + SCSI_DEVICE!(dev, locked_dev, scsi_dev); // SAFETY: the block_backend is assigned after device realized. - let block_backend = locked_dev.block_backend.as_ref().unwrap(); + let block_backend = scsi_dev.block_backend.as_ref().unwrap(); let mut locked_backend = block_backend.lock().unwrap(); let s_req = Arc::new(Mutex::new(self)); let scsicompletecb = ScsiCompleteCb { req: s_req.clone() }; - let offset_bits = match locked_dev.scsi_type { + let offset_bits = match scsi_dev.scsi_type { SCSI_TYPE_DISK => SCSI_DISK_DEFAULT_BLOCK_SIZE_SHIFT, _ => SCSI_CDROM_DEFAULT_BLOCK_SIZE_SHIFT, }; @@ -634,8 +652,8 @@ impl ScsiRequest { Ok(Vec::new()) } TEST_UNIT_READY => { - let dev_lock = self.dev.lock().unwrap(); - if dev_lock.block_backend.is_none() { + SCSI_DEVICE!(self.dev, locked_dev, scsi_dev); + if scsi_dev.block_backend.is_none() { Err(anyhow!("No scsi backend!")) } else { Ok(Vec::new()) @@ -670,7 +688,9 @@ impl ScsiRequest { let mut not_supported_flag = false; let mut sense = None; let mut status = GOOD; - let found_lun = self.dev.lock().unwrap().dev_cfg.lun; + SCSI_DEVICE!(self.dev, locked_dev, scsi_dev); + let found_lun = scsi_dev.dev_cfg.lun; + drop(locked_dev); // Requested lun id is not equal to found device id means it may be a target request. // REPORT LUNS is also a target request command. @@ -770,10 +790,10 @@ fn scsi_cdb_length(cdb: &[u8; SCSI_CMD_BUF_SIZE]) -> i32 { } } -pub fn scsi_cdb_xfer(cdb: &[u8; SCSI_CMD_BUF_SIZE], dev: Arc>) -> i32 { - let dev_lock = dev.lock().unwrap(); - let block_size = dev_lock.block_size as i32; - drop(dev_lock); +pub fn scsi_cdb_xfer(cdb: &[u8; SCSI_CMD_BUF_SIZE], dev: Arc>) -> i32 { + SCSI_DEVICE!(dev, locked_dev, scsi_dev); + let block_size = scsi_dev.block_size as i32; + drop(locked_dev); let mut xfer = match cdb[0] >> 5 { // Group Code | Transfer length. | @@ -883,28 +903,27 @@ fn scsi_cdb_xfer_mode(cdb: &[u8; SCSI_CMD_BUF_SIZE]) -> ScsiXferMode { /// VPD: Vital Product Data. fn scsi_command_emulate_vpd_page( cmd: &ScsiCommand, - dev: &Arc>, + dev: &Arc>, ) -> Result> { let buflen: usize; let mut outbuf: Vec = vec![0; 4]; - - let dev_lock = dev.lock().unwrap(); + SCSI_DEVICE!(dev, locked_dev, scsi_dev); let page_code = cmd.buf[2]; - outbuf[0] = dev_lock.scsi_type as u8 & 0x1f; + outbuf[0] = scsi_dev.scsi_type as u8 & 0x1f; outbuf[1] = page_code; match page_code { 0x00 => { // Supported VPD Pages. outbuf.push(0_u8); - if !dev_lock.state.serial.is_empty() { + if !scsi_dev.state.serial.is_empty() { // 0x80: Unit Serial Number. outbuf.push(0x80); } // 0x83: Device Identification. outbuf.push(0x83); - if dev_lock.scsi_type == SCSI_TYPE_DISK { + if scsi_dev.scsi_type == SCSI_TYPE_DISK { // 0xb0: Block Limits. outbuf.push(0xb0); // 0xb1: Block Device Characteristics. @@ -916,20 +935,20 @@ fn scsi_command_emulate_vpd_page( } 0x80 => { // Unit Serial Number. - let len = dev_lock.state.serial.len(); + let len = scsi_dev.state.serial.len(); if len == 0 { bail!("Missed serial number!"); } let l = cmp::min(SCSI_INQUIRY_VPD_SERIAL_NUMBER_MAX_LEN, len); - let mut serial_vec = dev_lock.state.serial.as_bytes().to_vec(); + let mut serial_vec = scsi_dev.state.serial.as_bytes().to_vec(); serial_vec.truncate(l); outbuf.append(&mut serial_vec); buflen = outbuf.len(); } 0x83 => { // Device Identification. - let mut len: u8 = dev_lock.state.device_id.len() as u8; + let mut len: u8 = scsi_dev.state.device_id.len() as u8; if len > (255 - 8) { len = 255 - 8; } @@ -941,7 +960,7 @@ fn scsi_command_emulate_vpd_page( // len: identifier length. outbuf.append(&mut [0x2_u8, 0_u8, 0_u8, len].to_vec()); - let mut device_id_vec = dev_lock.state.device_id.as_bytes().to_vec(); + let mut device_id_vec = scsi_dev.state.device_id.as_bytes().to_vec(); device_id_vec.truncate(len as usize); outbuf.append(&mut device_id_vec); } @@ -949,7 +968,7 @@ fn scsi_command_emulate_vpd_page( } 0xb0 => { // Block Limits. - if dev_lock.scsi_type == SCSI_TYPE_ROM { + if scsi_dev.scsi_type == SCSI_TYPE_ROM { bail!("Invalid scsi type: SCSI_TYPE_ROM !"); } outbuf.resize(64, 0); @@ -1069,7 +1088,7 @@ fn scsi_command_emulate_target_inquiry(lun: u16, cmd: &ScsiCommand) -> Result>, + dev: &Arc>, ) -> Result> { // Byte1 bit0: EVPD(enable vital product data). if cmd.buf[1] == 0x1 { @@ -1083,26 +1102,26 @@ fn scsi_command_emulate_inquiry( let buflen = cmp::min(cmd.xfer, SCSI_MAX_INQUIRY_LEN); let mut outbuf: Vec = vec![0; SCSI_MAX_INQUIRY_LEN as usize]; - let dev_lock = dev.lock().unwrap(); + SCSI_DEVICE!(dev, locked_dev, scsi_dev); - outbuf[0] = (dev_lock.scsi_type & 0x1f) as u8; - outbuf[1] = match dev_lock.state.features & SCSI_DISK_F_REMOVABLE { + outbuf[0] = (scsi_dev.scsi_type & 0x1f) as u8; + outbuf[1] = match scsi_dev.state.features & SCSI_DISK_F_REMOVABLE { 1 => 0x80, _ => 0, }; - let product_bytes = dev_lock.state.product.as_bytes(); + let product_bytes = scsi_dev.state.product.as_bytes(); let product_len = cmp::min(product_bytes.len(), SCSI_INQUIRY_PRODUCT_MAX_LEN); - let vendor_bytes = dev_lock.state.vendor.as_bytes(); + let vendor_bytes = scsi_dev.state.vendor.as_bytes(); let vendor_len = cmp::min(vendor_bytes.len(), SCSI_INQUIRY_VENDOR_MAX_LEN); - let version_bytes = dev_lock.state.version.as_bytes(); + let version_bytes = scsi_dev.state.version.as_bytes(); let vension_len = cmp::min(version_bytes.len(), SCSI_INQUIRY_VERSION_MAX_LEN); outbuf[16..16 + product_len].copy_from_slice(product_bytes); outbuf[8..8 + vendor_len].copy_from_slice(vendor_bytes); outbuf[32..32 + vension_len].copy_from_slice(version_bytes); - drop(dev_lock); + drop(locked_dev); // outbuf: // Byte2: Version. @@ -1125,17 +1144,17 @@ fn scsi_command_emulate_inquiry( fn scsi_command_emulate_read_capacity_10( cmd: &ScsiCommand, - dev: &Arc>, + dev: &Arc>, ) -> Result> { if cmd.buf[8] & 1 == 0 && cmd.lba != 0 { // PMI(Partial Medium Indicator) bail!("Invalid scsi cmd READ_CAPACITY_10!"); } - let dev_lock = dev.lock().unwrap(); - let block_size = dev_lock.block_size; + SCSI_DEVICE!(dev, locked_dev, scsi_dev); + let block_size = scsi_dev.block_size; let mut outbuf: Vec = vec![0; 8]; - let mut nb_sectors = cmp::min(dev_lock.disk_sectors as u32, u32::MAX); + let mut nb_sectors = cmp::min(scsi_dev.disk_sectors as u32, u32::MAX); nb_sectors /= block_size / DEFAULT_SECTOR_SIZE; nb_sectors -= 1; @@ -1150,18 +1169,18 @@ fn scsi_command_emulate_read_capacity_10( fn scsi_command_emulate_mode_sense( cmd: &ScsiCommand, - dev: &Arc>, + dev: &Arc>, ) -> Result> { // disable block descriptors(DBD) bit. let mut dbd: bool = cmd.buf[1] & 0x8 != 0; let page_code = cmd.buf[2] & 0x3f; let page_control = (cmd.buf[2] & 0xc0) >> 6; let mut outbuf: Vec = vec![0]; - let dev_lock = dev.lock().unwrap(); + SCSI_DEVICE!(dev, locked_dev, scsi_dev); let mut dev_specific_parameter: u8 = 0; - let mut nb_sectors = dev_lock.disk_sectors as u32; - let scsi_type = dev_lock.scsi_type; - let block_size = dev_lock.block_size; + let mut nb_sectors = scsi_dev.disk_sectors as u32; + let scsi_type = scsi_dev.scsi_type; + let block_size = scsi_dev.block_size; nb_sectors /= block_size / DEFAULT_SECTOR_SIZE; trace::scsi_emulate_mode_sense( @@ -1175,17 +1194,17 @@ fn scsi_command_emulate_mode_sense( // Device specific paramteter field for direct access block devices: // Bit 7: WP(Write Protect); bit 4: DPOFUA; if scsi_type == SCSI_TYPE_DISK { - if dev_lock.state.features & (1 << SCSI_DISK_F_DPOFUA) != 0 { + if scsi_dev.state.features & (1 << SCSI_DISK_F_DPOFUA) != 0 { dev_specific_parameter = 0x10; } - if dev_lock.drive_cfg.readonly { + if scsi_dev.drive_cfg.readonly { // Readonly. dev_specific_parameter |= 0x80; } } else { dbd = true; } - drop(dev_lock); + drop(locked_dev); if cmd.op == MODE_SENSE { outbuf.resize(4, 0); @@ -1361,12 +1380,12 @@ fn scsi_command_emulate_mode_sense_page( fn scsi_command_emulate_report_luns( cmd: &ScsiCommand, - dev: &Arc>, + dev: &Arc>, ) -> Result> { - let dev_lock = dev.lock().unwrap(); + SCSI_DEVICE!(dev, locked_dev, scsi_dev); // Byte 0-3: Lun List Length. Byte 4-7: Reserved. let mut outbuf: Vec = vec![0; 8]; - let target = dev_lock.dev_cfg.target; + let target = scsi_dev.dev_cfg.target; if cmd.xfer < 16 { bail!("scsi REPORT LUNS xfer {} too short!", cmd.xfer); @@ -1380,27 +1399,24 @@ fn scsi_command_emulate_report_luns( ); } - let scsi_bus = dev_lock.parent_bus.upgrade().unwrap(); - let scsi_bus_clone = scsi_bus.lock().unwrap(); + let bus = scsi_dev.parent_bus().unwrap().upgrade().unwrap(); + SCSI_BUS!(bus, locked_bus, scsi_bus); + drop(locked_dev); - drop(dev_lock); - - for (_pos, device) in scsi_bus_clone.devices.iter() { - let device_lock = device.lock().unwrap(); - if device_lock.dev_cfg.target != target { - drop(device_lock); + for device in scsi_bus.child_devices().values() { + SCSI_DEVICE!(device, locked_dev, scsi_dev); + if scsi_dev.dev_cfg.target != target { continue; } let len = outbuf.len(); - if device_lock.dev_cfg.lun < 256 { + if scsi_dev.dev_cfg.lun < 256 { outbuf.push(0); - outbuf.push(device_lock.dev_cfg.lun as u8); + outbuf.push(scsi_dev.dev_cfg.lun as u8); } else { - outbuf.push(0x40 | ((device_lock.dev_cfg.lun >> 8) & 0xff) as u8); - outbuf.push((device_lock.dev_cfg.lun & 0xff) as u8); + outbuf.push(0x40 | ((scsi_dev.dev_cfg.lun >> 8) & 0xff) as u8); + outbuf.push((scsi_dev.dev_cfg.lun & 0xff) as u8); } outbuf.resize(len + 8, 0); - drop(device_lock); } let len: u32 = outbuf.len() as u32 - 8; @@ -1410,20 +1426,19 @@ fn scsi_command_emulate_report_luns( fn scsi_command_emulate_service_action_in_16( cmd: &ScsiCommand, - dev: &Arc>, + dev: &Arc>, ) -> Result> { // Read Capacity(16) Command. // Byte 0: Operation Code(0x9e) // Byte 1: bit0 - bit4: Service Action(0x10), bit 5 - bit 7: Reserved. if cmd.buf[1] & 0x1f == SUBCODE_READ_CAPACITY_16 { - let dev_lock = dev.lock().unwrap(); - let block_size = dev_lock.block_size; + SCSI_DEVICE!(dev, locked_dev, scsi_dev); + let block_size = scsi_dev.block_size; let mut outbuf: Vec = vec![0; 32]; - let mut nb_sectors = dev_lock.disk_sectors; + let mut nb_sectors = scsi_dev.disk_sectors; nb_sectors /= (block_size / DEFAULT_SECTOR_SIZE) as u64; nb_sectors -= 1; - - drop(dev_lock); + drop(locked_dev); // Byte[0-7]: Returned Logical BLock Address(the logical block address of the last logical // block). @@ -1443,7 +1458,7 @@ fn scsi_command_emulate_service_action_in_16( fn scsi_command_emulate_read_disc_information( cmd: &ScsiCommand, - dev: &Arc>, + dev: &Arc>, ) -> Result> { // Byte1: Bits[0-2]: Data type. // Data Type | Returned Data. | @@ -1457,9 +1472,11 @@ fn scsi_command_emulate_read_disc_information( if data_type != 0 { bail!("Unsupported read disc information data type {}!", data_type); } - if dev.lock().unwrap().scsi_type != SCSI_TYPE_ROM { + SCSI_DEVICE!(dev, locked_dev, scsi_dev); + if scsi_dev.scsi_type != SCSI_TYPE_ROM { bail!("Read disc information command is only for scsi multi-media device!"); } + drop(locked_dev); // Outbuf: // Bytes[0-1]: Disc Information Length(32). @@ -1507,7 +1524,7 @@ const RT_RAW_TOC: u8 = 0x0010; fn scsi_command_emulate_read_toc( cmd: &ScsiCommand, - dev: &Arc>, + dev: &Arc>, ) -> Result> { // Byte1: Bit1: MSF.(MSF: Minute, Second, Frame) // MSF = 1: the address fields in some returned data formats shall be in MSF form. @@ -1521,7 +1538,8 @@ fn scsi_command_emulate_read_toc( match format { RT_FORMATTED_TOC => { - let nb_sectors = dev.lock().unwrap().disk_sectors as u32; + SCSI_DEVICE!(dev, locked_dev, scsi_dev); + let nb_sectors = scsi_dev.disk_sectors as u32; let mut buf = cdrom_read_formatted_toc(nb_sectors, msf, track_number)?; outbuf.append(&mut buf); } @@ -1542,11 +1560,11 @@ fn scsi_command_emulate_read_toc( fn scsi_command_emulate_get_configuration( _cmd: &ScsiCommand, - dev: &Arc>, + dev: &Arc>, ) -> Result> { - let dev_lock = dev.lock().unwrap(); - if dev_lock.scsi_type != SCSI_TYPE_ROM { - bail!("Invalid scsi type {}", dev_lock.scsi_type); + SCSI_DEVICE!(dev, locked_dev, scsi_dev); + if scsi_dev.scsi_type != SCSI_TYPE_ROM { + bail!("Invalid scsi type {}", scsi_dev.scsi_type); } // 8 bytes(Feature Header) + 12 bytes(Profile List Feature) + @@ -1559,7 +1577,7 @@ fn scsi_command_emulate_get_configuration( // Bytes[4-5]: Reserved. // Bytes[6-7]: Current Profile. BigEndian::write_u32(&mut outbuf[0..4], 36); - let current = if dev_lock.disk_sectors > CD_MAX_SECTORS as u64 { + let current = if scsi_dev.disk_sectors > CD_MAX_SECTORS as u64 { GC_PROFILE_DVD_ROM } else { GC_PROFILE_CD_ROM @@ -1620,14 +1638,14 @@ fn scsi_command_emulate_get_configuration( fn scsi_command_emulate_get_event_status_notification( cmd: &ScsiCommand, - dev: &Arc>, + dev: &Arc>, ) -> Result> { // Byte4: Notification Class Request. let notification_class_request = cmd.buf[4]; - let dev_lock = dev.lock().unwrap(); + SCSI_DEVICE!(dev, locked_dev, scsi_dev); - if dev_lock.scsi_type != SCSI_TYPE_ROM { - bail!("Invalid scsi type {}", dev_lock.scsi_type); + if scsi_dev.scsi_type != SCSI_TYPE_ROM { + bail!("Invalid scsi type {}", scsi_dev.scsi_type); } // Byte1: Bit0: Polled. diff --git a/devices/src/scsi/disk.rs b/devices/src/scsi/disk.rs index 8aab9a22..3b9e6a6c 100644 --- a/devices/src/scsi/disk.rs +++ b/devices/src/scsi/disk.rs @@ -11,12 +11,12 @@ // See the Mulan PSL v2 for more details. use std::collections::HashMap; -use std::sync::{Arc, Mutex, Weak}; +use std::sync::{Arc, Mutex}; use anyhow::{bail, Result}; use clap::Parser; -use crate::ScsiBus::{aio_complete_cb, ScsiBus, ScsiCompleteCb}; +use crate::ScsiBus::{aio_complete_cb, ScsiCompleteCb}; use crate::{Device, DeviceBase}; use block_backend::{create_block_backend, BlockDriverOps, BlockProperty}; use machine_manager::config::{valid_id, DriveConfig, DriveFile, VmConfig}; @@ -135,6 +135,14 @@ impl Device for ScsiDevice { gen_base_func!(device_base, device_base_mut, DeviceBase, base); } +/// Convert from Arc> to &ScsiDevice. +#[macro_export] +macro_rules! SCSI_DEVICE { + ($trait_device:expr, $lock_device: ident, $struct_device: ident) => { + convert_device_ref!($trait_device, $lock_device, $struct_device, ScsiDevice); + }; +} + pub struct ScsiDevice { pub base: DeviceBase, /// Configuration of the scsi device. @@ -155,8 +163,6 @@ pub struct ScsiDevice { pub block_size: u32, /// Scsi device type. pub scsi_type: u32, - /// Scsi Bus attached to. - pub parent_bus: Weak>, /// Drive backend files. drive_files: Arc>>, /// Aio context. @@ -192,7 +198,6 @@ impl ScsiDevice { disk_sectors: 0, block_size: 0, scsi_type, - parent_bus: Weak::new(), drive_files, aio: None, iothread, diff --git a/devices/src/usb/storage.rs b/devices/src/usb/storage.rs index 282169e4..74bb82ab 100644 --- a/devices/src/usb/storage.rs +++ b/devices/src/usb/storage.rs @@ -29,9 +29,10 @@ use super::xhci::xhci_controller::XhciDevice; use super::{config::*, USB_DEVICE_BUFFER_DEFAULT_LEN}; use super::{UsbDevice, UsbDeviceBase, UsbDeviceRequest, UsbPacket, UsbPacketStatus}; use crate::{ + Bus, ScsiBus::{ - ScsiBus, ScsiRequest, ScsiRequestOps, ScsiSense, ScsiXferMode, EMULATE_SCSI_OPS, GOOD, - SCSI_CMD_BUF_SIZE, + get_scsi_key, ScsiBus, ScsiRequest, ScsiRequestOps, ScsiSense, ScsiXferMode, + EMULATE_SCSI_OPS, GOOD, SCSI_CMD_BUF_SIZE, }, ScsiDisk::{ScsiDevConfig, ScsiDevice}, }; @@ -561,8 +562,7 @@ impl UsbDevice for UsbStorage { self.scsi_bus .lock() .unwrap() - .devices - .insert((0, 0), self.scsi_dev.clone()); + .attach_child(get_scsi_key(0, 0), self.scsi_dev.clone())?; let storage: Arc> = Arc::new(Mutex::new(self)); Ok(storage) diff --git a/devices/src/usb/uas.rs b/devices/src/usb/uas.rs index 688c1cca..c58f7ecf 100644 --- a/devices/src/usb/uas.rs +++ b/devices/src/usb/uas.rs @@ -34,9 +34,10 @@ use super::{ UsbDevice, UsbDeviceBase, UsbDeviceRequest, UsbPacket, UsbPacketStatus, USB_DEVICE_BUFFER_DEFAULT_LEN, }; +use crate::Bus; use crate::{ ScsiBus::{ - scsi_cdb_xfer, ScsiBus, ScsiRequest, ScsiRequestOps, ScsiSense, ScsiXferMode, + get_scsi_key, scsi_cdb_xfer, ScsiBus, ScsiRequest, ScsiRequestOps, ScsiSense, ScsiXferMode, CHECK_CONDITION, EMULATE_SCSI_OPS, GOOD, SCSI_SENSE_INVALID_PARAM_VALUE, SCSI_SENSE_INVALID_TAG, SCSI_SENSE_NO_SENSE, }, @@ -542,7 +543,7 @@ impl UsbUas { lun, scsi_iovec, scsi_iovec_size, - Arc::clone(&self.scsi_device), + self.scsi_device.clone(), uas_request, ) .with_context(|| "failed to create SCSI request")?; @@ -703,7 +704,7 @@ impl UsbUas { let command = self.commands[stream].as_ref().unwrap(); // SAFETY: IU is guaranteed to be of type command. let cdb = unsafe { &command.body.command.cdb }; - let xfer_len = scsi_cdb_xfer(cdb, Arc::clone(&self.scsi_device)); + let xfer_len = scsi_cdb_xfer(cdb, self.scsi_device.clone()); trace::usb_uas_try_start_next_transfer(self.device_id(), xfer_len); if xfer_len == 0 { @@ -762,14 +763,13 @@ impl UsbDevice for UsbUas { // supported. let mut locked_scsi_device = self.scsi_device.lock().unwrap(); locked_scsi_device.realize()?; - locked_scsi_device.parent_bus = Arc::downgrade(&self.scsi_bus); + locked_scsi_device.base.parent = + Some(Arc::downgrade(&self.scsi_bus) as Weak>); drop(locked_scsi_device); self.scsi_bus .lock() .unwrap() - .devices - .insert((0, 0), Arc::clone(&self.scsi_device)); - + .attach_child(get_scsi_key(0, 0), self.scsi_device.clone())?; let uas = Arc::new(Mutex::new(self)); Ok(uas) } diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 1b71e85b..c5ea3648 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -74,6 +74,7 @@ use devices::usb::UsbDevice; use devices::Bus; #[cfg(target_arch = "aarch64")] use devices::InterruptController; +use devices::ScsiBus::get_scsi_key; use devices::ScsiDisk::{ScsiDevConfig, ScsiDevice}; use hypervisor::{kvm::KvmHypervisor, test::TestHypervisor, HypervisorOps}; #[cfg(feature = "usb_camera")] @@ -1214,13 +1215,9 @@ pub trait MachineOps: MachineLifecycle { let virtio_device = virtio_pcidev.get_virtio_device().lock().unwrap(); let cntlr = virtio_device.as_any().downcast_ref::().unwrap(); let bus = cntlr.bus.as_ref().unwrap(); - if bus - .lock() - .unwrap() - .devices - .contains_key(&(device_cfg.target, device_cfg.lun)) - { - bail!("Wrong! Two scsi devices have the same scsi-id and lun"); + let key = get_scsi_key(device_cfg.target, device_cfg.lun); + if bus.lock().unwrap().child_dev(key).is_some() { + bail!("Wrong! Two scsi devices have the same scsi-id and lun!"); } let iothread = cntlr.config.iothread.clone(); @@ -1231,11 +1228,8 @@ pub trait MachineOps: MachineLifecycle { iothread, ))); device.lock().unwrap().realize()?; - bus.lock() - .unwrap() - .devices - .insert((device_cfg.target, device_cfg.lun), device.clone()); - device.lock().unwrap().parent_bus = Arc::downgrade(bus); + bus.lock().unwrap().attach_child(key, device.clone())?; + device.lock().unwrap().base.parent = Some(Arc::downgrade(bus) as Weak>); if let Some(bootindex) = device_cfg.bootindex { // Eg: OpenFirmware device path(virtio-scsi disk): diff --git a/virtio/src/device/scsi_cntlr.rs b/virtio/src/device/scsi_cntlr.rs index fa31c9b9..3970bf64 100644 --- a/virtio/src/device/scsi_cntlr.rs +++ b/virtio/src/device/scsi_cntlr.rs @@ -33,6 +33,8 @@ use devices::ScsiBus::{ ScsiBus, ScsiRequest, ScsiRequestOps, ScsiSense, ScsiXferMode, CHECK_CONDITION, EMULATE_SCSI_OPS, SCSI_CMD_BUF_SIZE, SCSI_SENSE_INVALID_OPCODE, }; +use devices::ScsiDisk::ScsiDevice; +use devices::{convert_device_ref, Bus, SCSI_DEVICE}; use machine_manager::config::{ get_pci_df, parse_bool, valid_block_device_virtqueue_size, valid_id, MAX_VIRTIO_QUEUE, }; @@ -296,11 +298,11 @@ impl VirtioDevice for ScsiCntlr { // Register event notifier for device aio. let bus = self.bus.as_ref().unwrap(); let locked_bus = bus.lock().unwrap(); - for device in locked_bus.devices.values() { - let locked_device = device.lock().unwrap(); + for device in locked_bus.child_devices().values() { + SCSI_DEVICE!(device, locked_dev, scsi_dev); let err_cb = self.gen_error_cb(interrupt_cb.clone()); // SAFETY: the disk_image is assigned after device realized. - let disk_image = locked_device.block_backend.as_ref().unwrap(); + let disk_image = scsi_dev.block_backend.as_ref().unwrap(); let mut locked_backend = disk_image.lock().unwrap(); locked_backend.register_io_event(self.base.broken.clone(), err_cb)?; } @@ -314,10 +316,10 @@ impl VirtioDevice for ScsiCntlr { )?; let bus = self.bus.as_ref().unwrap(); let locked_bus = bus.lock().unwrap(); - for device in locked_bus.devices.values() { - let locked_dev = device.lock().unwrap(); + for device in locked_bus.child_devices().values() { + SCSI_DEVICE!(device, locked_dev, scsi_dev); // SAFETY: the disk_image is assigned after device realized. - let disk_image = locked_dev.block_backend.as_ref().unwrap(); + let disk_image = scsi_dev.block_backend.as_ref().unwrap(); let mut locked_backend = disk_image.lock().unwrap(); locked_backend.unregister_io_event()?; } -- Gitee From 7974012a32b9d7e2260e8a8c7a2e38a282b43c73 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Fri, 21 Jun 2024 08:38:02 +0800 Subject: [PATCH 190/489] devices/sysbus: sysbus delete devices field `devices` field of struct `SysBus` has the same effect as the `children` field of struct `BusBase`. Since the devices mounted on sysbus do not need to describe their addresses, we will incrementally fill in a useless number in the hashmap. Delete useless `devices` field. Signed-off-by: liuxiangdong --- devices/src/legacy/pflash.rs | 2 +- devices/src/lib.rs | 5 ++++ devices/src/sysbus/mod.rs | 49 +++++++++++++++++++++++---------- machine/src/aarch64/fdt.rs | 21 +++++++------- machine/src/aarch64/standard.rs | 14 +++++----- machine/src/lib.rs | 22 ++++++++------- 6 files changed, 71 insertions(+), 42 deletions(-) diff --git a/devices/src/legacy/pflash.rs b/devices/src/legacy/pflash.rs index db9929a3..c12fb251 100644 --- a/devices/src/legacy/pflash.rs +++ b/devices/src/legacy/pflash.rs @@ -244,7 +244,7 @@ impl PFlash { .root() .add_subregion(rom_region, region_base) .with_context(|| "Failed to attach PFlash to system bus")?; - sysbus.lock().unwrap().devices.push(dev.clone()); + sysbus.lock().unwrap().sysbus_attach_child(dev.clone())?; Ok(dev) } diff --git a/devices/src/lib.rs b/devices/src/lib.rs index 33f9af56..1cb361b8 100644 --- a/devices/src/lib.rs +++ b/devices/src/lib.rs @@ -40,6 +40,7 @@ pub use scsi::bus as ScsiBus; pub use scsi::disk as ScsiDisk; use std::any::Any; +use std::any::TypeId; use std::collections::BTreeMap; use std::sync::{Arc, Mutex, Weak}; @@ -81,6 +82,10 @@ pub trait Device: Any + AsAny + Send + Sync { self.as_any_mut() } + fn device_type_id(&self) -> TypeId { + self.type_id() + } + /// Get device name. fn name(&self) -> String { self.device_base().id.clone() diff --git a/devices/src/sysbus/mod.rs b/devices/src/sysbus/mod.rs index 05479a3c..76a190e0 100644 --- a/devices/src/sysbus/mod.rs +++ b/devices/src/sysbus/mod.rs @@ -55,10 +55,11 @@ pub const IRQ_MAX: i32 = 191; pub struct SysBus { pub base: BusBase, + // Record the largest key used in the BTreemap of the busbase(children field). + max_key: u64, #[cfg(target_arch = "x86_64")] pub sys_io: Arc, pub sys_mem: Arc, - pub devices: Vec>>, pub free_irqs: (i32, i32), pub min_free_irq: i32, pub mmio_region: (u64, u64), @@ -92,10 +93,10 @@ impl SysBus { ) -> Self { Self { base: BusBase::new("sysbus".to_string()), + max_key: 0, #[cfg(target_arch = "x86_64")] sys_io: sys_io.clone(), sys_mem: sys_mem.clone(), - devices: Vec::new(), free_irqs, min_free_irq: free_irqs.0, mmio_region, @@ -155,7 +156,17 @@ impl SysBus { } } - self.devices.push(dev.clone()); + self.sysbus_attach_child(dev.clone())?; + Ok(()) + } + + pub fn sysbus_attach_child(&mut self, dev: Arc>) -> Result<()> { + self.attach_child(self.max_key, dev.clone())?; + // Note: Incrementally generate a number that has no substantive effect, and is only used for the + // key of Btreemap in the busbase(children field). + // The number of system-bus devices is limited, and it is also difficult to reach the `u64` range for + // hot-plug times. So, `u64` is currently sufficient for using and don't consider overflow issues for now. + self.max_key += 1; Ok(()) } } @@ -326,26 +337,37 @@ pub trait SysBusDevOps: Device + Send + AmlBuilder { } } +/// Convert from Arc> to &mut dyn SysBusDevOps. +#[macro_export] +macro_rules! SYS_BUS_DEVICE { + ($trait_device:expr, $lock_device: ident, $trait_sysbusdevops: ident) => { + let mut $lock_device = $trait_device.lock().unwrap(); + let $trait_sysbusdevops = to_sysbusdevops(&mut *$lock_device).unwrap(); + }; +} + impl AmlBuilder for SysBus { fn aml_bytes(&self) -> Vec { let mut scope = AmlScope::new("_SB"); - self.devices.iter().for_each(|dev| { - scope.append(&dev.lock().unwrap().aml_bytes()); - }); + let child_devices = self.base.children.clone(); + for dev in child_devices.values() { + SYS_BUS_DEVICE!(dev, locked_dev, sysbusdev); + scope.append(&sysbusdev.aml_bytes()); + } scope.aml_bytes() } } -pub type ToSysBusDevOpsFunc = fn(&dyn Any) -> &dyn SysBusDevOps; +pub type ToSysBusDevOpsFunc = fn(&mut dyn Any) -> &mut dyn SysBusDevOps; static mut SYSBUSDEVTYPE_HASHMAP: Option> = None; -pub fn convert_to_sysbusdevops(item: &dyn Any) -> &dyn SysBusDevOps { +pub fn convert_to_sysbusdevops(item: &mut dyn Any) -> &mut dyn SysBusDevOps { // SAFETY: The typeid of `T` is the typeid recorded in the hashmap. The target structure type of // the conversion is its own structure type, so the conversion result will definitely not be `None`. - let t = item.downcast_ref::().unwrap(); - t as &dyn SysBusDevOps + let t = item.downcast_mut::().unwrap(); + t as &mut dyn SysBusDevOps } pub fn register_sysbusdevops_type() -> Result<()> { @@ -388,13 +410,12 @@ pub fn devices_register_sysbusdevops_type() -> Result<()> { register_sysbusdevops_type::() } -pub fn to_sysbusdevops(dev: &dyn Device) -> Option<&dyn SysBusDevOps> { - let type_id = dev.type_id(); +pub fn to_sysbusdevops(dev: &mut dyn Device) -> Option<&mut dyn SysBusDevOps> { // SAFETY: SYSBUSDEVTYPE_HASHMAP has been built. And this function is called without changing hashmap. unsafe { let types = SYSBUSDEVTYPE_HASHMAP.as_mut().unwrap(); - let func = types.get(&type_id)?; - let sysbusdev = func(dev.as_any()); + let func = types.get(&dev.device_type_id())?; + let sysbusdev = func(dev.as_any_mut()); Some(sysbusdev) } } diff --git a/machine/src/aarch64/fdt.rs b/machine/src/aarch64/fdt.rs index c08822c3..7bf0c2c9 100644 --- a/machine/src/aarch64/fdt.rs +++ b/machine/src/aarch64/fdt.rs @@ -14,7 +14,8 @@ use anyhow::Result; use crate::MachineBase; use cpu::PMU_INTR; -use devices::sysbus::{SysBusDevType, SysRes}; +use devices::sysbus::{to_sysbusdevops, SysBusDevType, SysRes}; +use devices::{Bus, SYS_BUS_DEVICE}; use util::device_tree::{self, FdtBuilder}; /// Function that helps to generate arm pmu in device-tree. @@ -265,24 +266,24 @@ impl CompileFDTHelper for MachineBase { fdt.set_property_string("method", "hvc")?; fdt.end_node(psci_node_dep)?; - let devices = self.sysbus.lock().unwrap().devices.clone(); - for dev in devices.iter() { - let locked_dev = dev.lock().unwrap(); - match locked_dev.sysbusdev_base().dev_type { + let devices = self.sysbus.lock().unwrap().child_devices(); + for dev in devices.values() { + SYS_BUS_DEVICE!(dev, locked_dev, sysbusdev); + match sysbusdev.sysbusdev_base().dev_type { SysBusDevType::PL011 => { - generate_serial_device_node(fdt, &locked_dev.sysbusdev_base().res)? + generate_serial_device_node(fdt, &sysbusdev.sysbusdev_base().res)? } SysBusDevType::Rtc => { - generate_rtc_device_node(fdt, &locked_dev.sysbusdev_base().res)? + generate_rtc_device_node(fdt, &sysbusdev.sysbusdev_base().res)? } SysBusDevType::VirtioMmio => { - generate_virtio_devices_node(fdt, &locked_dev.sysbusdev_base().res)? + generate_virtio_devices_node(fdt, &sysbusdev.sysbusdev_base().res)? } SysBusDevType::FwCfg => { - generate_fwcfg_device_node(fdt, &locked_dev.sysbusdev_base().res)?; + generate_fwcfg_device_node(fdt, &sysbusdev.sysbusdev_base().res)?; } SysBusDevType::Flash => { - generate_flash_device_node(fdt, &locked_dev.sysbusdev_base().res)?; + generate_flash_device_node(fdt, &sysbusdev.sysbusdev_base().res)?; } _ => (), } diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index 5eefe28d..76b3b140 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -49,8 +49,8 @@ use devices::legacy::{ #[cfg(feature = "ramfb")] use devices::legacy::{Ramfb, RamfbConfig}; use devices::pci::{PciDevOps, PciHost, PciIntxState}; -use devices::sysbus::SysBusDevType; -use devices::{ICGICConfig, ICGICv3Config, GIC_IRQ_MAX}; +use devices::sysbus::{to_sysbusdevops, SysBusDevType}; +use devices::{ICGICConfig, ICGICv3Config, GIC_IRQ_MAX, SYS_BUS_DEVICE}; use hypervisor::kvm::aarch64::*; use hypervisor::kvm::*; #[cfg(feature = "ramfb")] @@ -953,11 +953,11 @@ impl AcpiBuilder for StdMachine { spcr.set_field(52, 1_u8 << 3); // Irq number used by the UART let mut uart_irq: u32 = 0; - let devices = self.base.sysbus.lock().unwrap().devices.clone(); - for dev in devices.iter() { - let locked_dev = dev.lock().unwrap(); - if locked_dev.sysbusdev_base().dev_type == SysBusDevType::PL011 { - uart_irq = locked_dev.sysbusdev_base().irq_state.irq as _; + let devices = self.get_sysbus_devices(); + for dev in devices.values() { + SYS_BUS_DEVICE!(dev, locked_dev, sysbusdev); + if sysbusdev.sysbusdev_base().dev_type == SysBusDevType::PL011 { + uart_irq = sysbusdev.sysbusdev_base().irq_state.irq as _; break; } } diff --git a/machine/src/lib.rs b/machine/src/lib.rs index c5ea3648..8ab05262 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -60,7 +60,9 @@ use devices::pci::{ }; use devices::smbios::smbios_table::{build_smbios_ep30, SmbiosTable}; use devices::smbios::{SMBIOS_ANCHOR_FILE, SMBIOS_TABLE_FILE}; -use devices::sysbus::{devices_register_sysbusdevops_type, SysBus, SysBusDevOps, SysBusDevType}; +use devices::sysbus::{ + devices_register_sysbusdevops_type, to_sysbusdevops, SysBus, SysBusDevOps, SysBusDevType, +}; #[cfg(feature = "usb_camera")] use devices::usb::camera::{UsbCamera, UsbCameraConfig}; use devices::usb::keyboard::{UsbKeyboard, UsbKeyboardConfig}; @@ -71,11 +73,11 @@ use devices::usb::uas::{UsbUas, UsbUasConfig}; use devices::usb::usbhost::{UsbHost, UsbHostConfig}; use devices::usb::xhci::xhci_pci::{XhciConfig, XhciPciDevice}; use devices::usb::UsbDevice; -use devices::Bus; #[cfg(target_arch = "aarch64")] use devices::InterruptController; use devices::ScsiBus::get_scsi_key; use devices::ScsiDisk::{ScsiDevConfig, ScsiDevice}; +use devices::{Bus, Device, SYS_BUS_DEVICE}; use hypervisor::{kvm::KvmHypervisor, test::TestHypervisor, HypervisorOps}; #[cfg(feature = "usb_camera")] use machine_manager::config::get_cameradev_by_id; @@ -778,9 +780,9 @@ pub trait MachineOps: MachineLifecycle { let mut virtio_device = None; if serial_cfg.bus.is_none() { // Micro_vm. - for dev in self.get_sysbus_devices().iter() { - let locked_busdev = dev.lock().unwrap(); - if locked_busdev.sysbusdev_base().dev_type == SysBusDevType::VirtioMmio { + for dev in self.get_sysbus_devices().values() { + SYS_BUS_DEVICE!(dev, locked_busdev, sysbusdev); + if sysbusdev.sysbusdev_base().dev_type == SysBusDevType::VirtioMmio { let virtio_mmio_dev = locked_busdev .as_any() .downcast_ref::() @@ -940,8 +942,8 @@ pub trait MachineOps: MachineLifecycle { Ok(()) } - fn get_sysbus_devices(&mut self) -> Vec>> { - self.machine_base().sysbus.lock().unwrap().devices.clone() + fn get_sysbus_devices(&self) -> BTreeMap>> { + self.machine_base().sysbus.lock().unwrap().child_devices() } fn get_fwcfg_dev(&mut self) -> Option>> { @@ -953,9 +955,9 @@ pub trait MachineOps: MachineLifecycle { } fn reset_all_devices(&mut self) -> Result<()> { - for dev in self.get_sysbus_devices().iter() { - dev.lock() - .unwrap() + for dev in self.get_sysbus_devices().values() { + SYS_BUS_DEVICE!(dev, locked_dev, sysbusdev); + sysbusdev .reset() .with_context(|| "Fail to reset sysbus device")?; } -- Gitee From b95fab8e9c931067d3a9e559ec232e0e035bbafe Mon Sep 17 00:00:00 2001 From: Mingwang Li Date: Wed, 17 Jul 2024 14:27:26 +0800 Subject: [PATCH 191/489] bugfix: resume VM before let vm exit After the VM is paused, if the management process exits, the VM can be shutdown only after it is resumed. Signed-off-by: Mingwang Li --- machine/src/aarch64/standard.rs | 3 ++- machine/src/lib.rs | 42 +++++++++++++++++++++++++++++- machine/src/standard_common/mod.rs | 22 ---------------- machine/src/x86_64/standard.rs | 3 ++- 4 files changed, 45 insertions(+), 25 deletions(-) diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index 76b3b140..c525e385 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -615,10 +615,11 @@ impl MachineOps for StdMachine { .with_context(|| "Fail to init display")?; #[cfg(feature = "windows_emu_pid")] - locked_vm.watch_windows_emu_pid( + crate::watch_windows_emu_pid( vm_config, locked_vm.power_button.clone(), locked_vm.shutdown_req.clone(), + vm.clone(), ); MigrationManager::register_vm_config(locked_vm.get_vm_config()); diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 8ab05262..067a4e1f 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -2365,10 +2365,21 @@ fn check_windows_emu_pid( pid_path: String, powerdown_req: Arc, shutdown_req: Arc, + vm: Arc>, ) { let mut check_delay = Duration::from_millis(WINDOWS_EMU_PID_DEFAULT_INTERVAL); if !Path::new(&pid_path).exists() { - log::info!("Detect emulator exited, let VM exits now"); + info!("Detect emulator exited, let VM exits now"); + let locked_vm = vm.read().unwrap(); + let mut vm_state = locked_vm.get_vm_state().deref().0.lock().unwrap(); + if *vm_state == VmState::Paused { + info!("VM state is paused, resume VM before exit"); + if let Err(e) = locked_vm.vm_resume(&locked_vm.machine_base().cpus, &mut vm_state) { + log::error!("Failed to resume VM when check windows emu pid: {:?}", e); + } + } + drop(vm_state); + drop(locked_vm); if get_run_stage() == VmRunningStage::Os { // Wait 30s for windows normal exit. check_delay = Duration::from_millis(WINDOWS_EMU_PID_POWERDOWN_INTERVAL); @@ -2389,6 +2400,35 @@ fn check_windows_emu_pid( pid_path.clone(), powerdown_req.clone(), shutdown_req.clone(), + vm.clone(), + ); + }); + EventLoop::get_ctx(None) + .unwrap() + .timer_add(check_emu_alive, check_delay); +} + +/// When windows emu exits, stratovirt should exits too. +#[cfg(feature = "windows_emu_pid")] +pub(crate) fn watch_windows_emu_pid( + vm_config: &VmConfig, + power_button: Arc, + shutdown_req: Arc, + vm: Arc>, +) { + let emu_pid = vm_config.emulator_pid.as_ref(); + if emu_pid.is_none() { + return; + } + info!("Watching on emulator lifetime"); + let pid_path = "/proc/".to_owned() + emu_pid.unwrap(); + let check_delay = Duration::from_millis(WINDOWS_EMU_PID_DEFAULT_INTERVAL); + let check_emu_alive = Box::new(move || { + check_windows_emu_pid( + pid_path.clone(), + power_button.clone(), + shutdown_req.clone(), + vm.clone(), ); }); EventLoop::get_ctx(None) diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index 6818dce3..0a116b3b 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -59,8 +59,6 @@ use devices::pci::{PciBus, PciHost}; use machine_manager::config::get_cameradev_config; #[cfg(target_arch = "aarch64")] use machine_manager::config::ShutdownAction; -#[cfg(feature = "windows_emu_pid")] -use machine_manager::config::VmConfig; use machine_manager::config::{ get_chardev_config, get_netdev_config, memory_unit_conversion, parse_incoming_uri, BootIndexInfo, ConfigCheck, DiskFormat, DriveConfig, ExBool, MigrateMode, NumaNode, NumaNodes, @@ -888,26 +886,6 @@ impl StdMachine { self.detach_usb_from_xhci_controller(&mut locked_vmconfig, id) } - /// When windows emu exits, stratovirt should exits too. - #[cfg(feature = "windows_emu_pid")] - pub(crate) fn watch_windows_emu_pid( - &self, - vm_config: &VmConfig, - power_button: Arc, - shutdown_req: Arc, - ) { - let emu_pid = vm_config.emulator_pid.as_ref(); - if emu_pid.is_none() { - return; - } - log::info!("Watching on emulator lifetime"); - crate::check_windows_emu_pid( - "/proc/".to_owned() + emu_pid.unwrap(), - power_button, - shutdown_req, - ); - } - #[cfg(target_arch = "x86_64")] fn plug_cpu_device(&mut self, args: &qmp_schema::DeviceAddArgument) -> Result<()> { if self.get_numa_nodes().is_some() { diff --git a/machine/src/x86_64/standard.rs b/machine/src/x86_64/standard.rs index c9c80f79..68cbf8a5 100644 --- a/machine/src/x86_64/standard.rs +++ b/machine/src/x86_64/standard.rs @@ -550,10 +550,11 @@ impl MachineOps for StdMachine { .with_context(|| "Fail to init display")?; #[cfg(feature = "windows_emu_pid")] - locked_vm.watch_windows_emu_pid( + crate::watch_windows_emu_pid( vm_config, locked_vm.shutdown_req.clone(), locked_vm.shutdown_req.clone(), + vm.clone(), ); MigrationManager::register_vm_config(locked_vm.get_vm_config()); -- Gitee From a0599c2253d8a2deddc3d5dc0fbc510260329d95 Mon Sep 17 00:00:00 2001 From: yexiao Date: Tue, 18 Jun 2024 09:12:39 +0800 Subject: [PATCH 192/489] virtio-net: remove the out event of tap fd. Remove the OUT event of tap fd to prevent triggering a large number of OUT events after initialization. Signed-off-by: Xiao Ye --- virtio/src/device/net.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index ef952304..78537269 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -1224,7 +1224,7 @@ impl NetIoHandler { tap_fd, Some(handler), NotifierOperation::AddShared, - EventSet::OUT | EventSet::IN | EventSet::EDGE_TRIGGERED, + EventSet::IN | EventSet::EDGE_TRIGGERED, )]; notifiers -- Gitee From 5a896e3154f03180d3b198286e1ae253d83c01a2 Mon Sep 17 00:00:00 2001 From: yexiao Date: Tue, 18 Jun 2024 09:27:16 +0800 Subject: [PATCH 193/489] virtio-net: move the event of handle_tx from rx thread to tx thread. Set all handle_tx on the same thread to prevent lock contention between tx_iothread and rx_iothread threads Signed-off-by: Xiao Ye --- virtio/src/device/net.rs | 31 +++++-------------------------- 1 file changed, 5 insertions(+), 26 deletions(-) diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index 78537269..05ac2857 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -1167,32 +1167,11 @@ impl NetIoHandler { if events.contains(EventSet::OUT) { net_queue.listen_state.lock().unwrap().set_tap_full(false); - let mut locked_queue = net_queue.tx.queue.lock().unwrap(); - - if let Err(ref err) = locked_queue.vring.suppress_queue_notify( - &net_queue.mem_space, - net_queue.driver_features, - false, - ) { - error!("Failed to enable tx queue notify: {:?}", err); - report_virtio_error( - net_queue.interrupt_cb.clone(), - net_queue.driver_features, - &device_broken, - ); - return None; - }; - - drop(locked_queue); - - if let Err(ref e) = net_queue.handle_tx(&tap) { - error!("Failed to handle tx(tx event) for net, {:?}", e); - report_virtio_error( - net_queue.interrupt_cb.clone(), - net_queue.driver_features, - &device_broken, - ); - } + net_queue + .tx + .queue_evt + .write(1) + .unwrap_or_else(|e| error!("Failed to notify tx thread: {:?}", e)); } if events.contains(EventSet::IN) { -- Gitee From 7032181b6094505f999ac3d087736e1f41c41117 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sat, 9 Dec 2023 16:19:46 +0800 Subject: [PATCH 194/489] devices/pci: pcibus delete parent_bridge field `parent_bridge` field of struct `PciBus` is only used for `RootPort` class, and `RootPort` is parent device of PciBus. We can get parent device from new BUS-DEVICE framework. Delete this field and use new framework to implement these functions. Signed-off-by: liuxiangdong --- devices/src/pci/bus.rs | 31 ++++++++++++------------------- devices/src/pci/intx.rs | 10 ++++++---- devices/src/pci/mod.rs | 15 ++++++--------- devices/src/pci/root_port.rs | 20 ++++++++++++++++++-- machine/src/lib.rs | 3 +-- 5 files changed, 43 insertions(+), 36 deletions(-) diff --git a/devices/src/pci/bus.rs b/devices/src/pci/bus.rs index d87d5d85..3490fe6d 100644 --- a/devices/src/pci/bus.rs +++ b/devices/src/pci/bus.rs @@ -22,7 +22,10 @@ use super::{ hotplug::HotplugOps, PciDevOps, PciIntxState, }; -use crate::{Bus, BusBase, MsiIrqManager}; +use crate::pci::RootPort; +use crate::{ + convert_device_mut, convert_device_ref, Bus, BusBase, MsiIrqManager, MUT_ROOT_PORT, ROOT_PORT, +}; use address_space::Region; use util::gen_base_func; @@ -35,8 +38,6 @@ pub struct PciBus { pub devices: HashMap>>, /// Child buses of the bus. pub child_buses: Vec>>, - /// Pci bridge which the bus originates from. - pub parent_bridge: Option>>, /// IO region which the parent bridge manages. #[cfg(target_arch = "x86_64")] pub io_region: Region, @@ -70,7 +71,6 @@ impl PciBus { base: BusBase::new(name), devices: HashMap::new(), child_buses: Vec::new(), - parent_bridge: None, #[cfg(target_arch = "x86_64")] io_region, mem_region, @@ -236,18 +236,11 @@ impl PciBus { } fn get_bridge_control_reg(&self, offset: usize, data: &mut [u8]) { - if self.parent_bridge.is_none() { - return; + if let Some(parent_bridge) = self.parent_device() { + let bridge = parent_bridge.upgrade().unwrap(); + MUT_ROOT_PORT!(bridge, locked_bridge, rootport); + rootport.read_config(offset, data); } - - self.parent_bridge - .as_ref() - .unwrap() - .upgrade() - .unwrap() - .lock() - .unwrap() - .read_config(offset, data); } pub fn generate_dev_id(&self, devfn: u8) -> u16 { @@ -260,11 +253,11 @@ impl PciBus { } pub fn get_msi_irq_manager(&self) -> Option> { - match &self.parent_bridge { + match self.parent_device().as_ref() { Some(parent_bridge) => { - let parent_bridge = parent_bridge.upgrade().unwrap(); - let locked_parent_bridge = parent_bridge.lock().unwrap(); - locked_parent_bridge.get_msi_irq_manager() + let bridge = parent_bridge.upgrade().unwrap(); + ROOT_PORT!(bridge, locked_bridge, rootport); + rootport.get_msi_irq_manager() } None => self.msi_irq_manager.clone(), } diff --git a/devices/src/pci/intx.rs b/devices/src/pci/intx.rs index b0624fe0..ca141850 100644 --- a/devices/src/pci/intx.rs +++ b/devices/src/pci/intx.rs @@ -15,8 +15,10 @@ use std::sync::{Arc, Mutex, Weak}; use anyhow::Result; use log::error; +use super::{PciDevOps, RootPort}; use crate::interrupt_controller::LineIrqManager; use crate::pci::{swizzle_map_irq, PciBus, PciConfig, INTERRUPT_PIN, PCI_PIN_NUM}; +use crate::{convert_device_ref, Bus, ROOT_PORT}; pub type InterruptHandler = Box Result<()> + Send + Sync>; @@ -133,13 +135,13 @@ pub fn init_intx( let locked_pci_bus = pci_bus.lock().unwrap(); let pin = config.config[INTERRUPT_PIN as usize] - 1; - let (irq, intx_state) = match &locked_pci_bus.parent_bridge { + let (irq, intx_state) = match &locked_pci_bus.parent_device() { Some(parent_bridge) => { let parent_bridge = parent_bridge.upgrade().unwrap(); - let locked_parent_bridge = parent_bridge.lock().unwrap(); + ROOT_PORT!(parent_bridge, locked_bridge, bridge); ( - swizzle_map_irq(locked_parent_bridge.pci_base().devfn, pin), - locked_parent_bridge.get_intx_state(), + swizzle_map_irq(bridge.pci_base().devfn, pin), + bridge.get_intx_state(), ) } None => { diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs index b3168e7a..97b9126c 100644 --- a/devices/src/pci/mod.rs +++ b/devices/src/pci/mod.rs @@ -44,7 +44,7 @@ use crate::misc::ivshmem::Ivshmem; use crate::misc::pvpanic::PvPanicPci; use crate::pci::config::{HEADER_TYPE, HEADER_TYPE_MULTIFUNC, MAX_FUNC}; use crate::usb::xhci::xhci_pci::XhciPciDevice; -use crate::{Bus, Device, DeviceBase, MsiIrqManager}; +use crate::{convert_device_ref, Bus, Device, DeviceBase, MsiIrqManager, ROOT_PORT}; #[cfg(feature = "demo_device")] use demo_device::DemoDev; @@ -227,16 +227,13 @@ pub trait PciDevOps: Device + Send { // This else branch will not be executed currently, // which is mainly to be compatible with new PCI bridge devices. // unwrap is safe because pci bus under root port will not return null. - locked_parent_bus - .parent_bridge - .as_ref() + let parent_bridge = locked_parent_bus + .parent_device() .unwrap() .upgrade() - .unwrap() - .lock() - .unwrap() - .get_dev_path() - .unwrap() + .unwrap(); + ROOT_PORT!(parent_bridge, locked_bridge, rootport); + rootport.get_dev_path().unwrap() }; parent_dev_path } diff --git a/devices/src/pci/root_port.rs b/devices/src/pci/root_port.rs index b6349058..21f252ef 100644 --- a/devices/src/pci/root_port.rs +++ b/devices/src/pci/root_port.rs @@ -347,6 +347,22 @@ impl Device for RootPort { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } +/// Convert from Arc> to &mut RootPort. +#[macro_export] +macro_rules! MUT_ROOT_PORT { + ($trait_device:expr, $lock_device: ident, $struct_device: ident) => { + convert_device_mut!($trait_device, $lock_device, $struct_device, RootPort); + }; +} + +/// Convert from Arc> to &RootPort. +#[macro_export] +macro_rules! ROOT_PORT { + ($trait_device:expr, $lock_device: ident, $struct_device: ident) => { + convert_device_ref!($trait_device, $lock_device, $struct_device, RootPort); + }; +} + impl PciDevOps for RootPort { gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); @@ -404,8 +420,8 @@ impl PciDevOps for RootPort { let root_port = Arc::new(Mutex::new(self)); #[allow(unused_mut)] let mut locked_root_port = root_port.lock().unwrap(); - locked_root_port.sec_bus.lock().unwrap().parent_bridge = - Some(Arc::downgrade(&root_port) as Weak>); + locked_root_port.sec_bus.lock().unwrap().base.parent = + Some(Arc::downgrade(&root_port) as Weak>); locked_root_port.sec_bus.lock().unwrap().hotplug_controller = Some(Arc::downgrade(&root_port) as Weak>); let pci_device = locked_parent_bus.devices.get(&locked_root_port.base.devfn); diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 067a4e1f..2f301863 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -1513,8 +1513,7 @@ pub trait MachineOps: MachineLifecycle { return Ok(()); } let parent_bridge = locked_bus - .parent_bridge - .as_ref() + .parent_device() .with_context(|| format!("Parent bridge does not exist, dev id {}", dev_id))?; let dev = parent_bridge.upgrade().unwrap(); let locked_dev = dev.lock().unwrap(); -- Gitee From eb7d27e32212df4d60c51f18465f5101f5c63422 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sat, 9 Dec 2023 18:32:24 +0800 Subject: [PATCH 195/489] devices/pci: pcidevbase deletes parent_bus field `parent_bus` field of struct `PciDevBase` has the same effect as the `parent_bus` field of struct `DeviceBase`. Delete it. Signed-off-by: liuxiangdong --- devices/src/misc/ivshmem.rs | 31 ++++++++-------- devices/src/misc/pvpanic.rs | 37 +++++++++---------- devices/src/pci/bus.rs | 16 +++++++++ devices/src/pci/config.rs | 11 +++--- devices/src/pci/demo_device/mod.rs | 19 +++++----- devices/src/pci/intx.rs | 14 ++++---- devices/src/pci/mod.rs | 40 +++++++++------------ devices/src/pci/msix.rs | 34 +++++++++--------- devices/src/pci/root_port.rs | 49 +++++++++++-------------- devices/src/usb/xhci/xhci_pci.rs | 26 +++++++------- machine/src/aarch64/pci_host_root.rs | 25 ++++++------- machine/src/x86_64/ich9_lpc.rs | 18 +++------- machine/src/x86_64/mch.rs | 42 ++++++---------------- vfio/src/vfio_pci.rs | 53 ++++++++++++++-------------- virtio/src/transport/virtio_pci.rs | 52 +++++++++++++-------------- 15 files changed, 214 insertions(+), 253 deletions(-) diff --git a/devices/src/misc/ivshmem.rs b/devices/src/misc/ivshmem.rs index acb9cc1a..08212c44 100644 --- a/devices/src/misc/ivshmem.rs +++ b/devices/src/misc/ivshmem.rs @@ -17,14 +17,12 @@ use std::sync::{ use anyhow::{bail, Result}; -use crate::pci::{ - config::{ - PciConfig, RegionType, DEVICE_ID, PCI_CLASS_MEMORY_RAM, PCI_CONFIG_SPACE_SIZE, - PCI_VENDOR_ID_REDHAT_QUMRANET, REVISION_ID, SUB_CLASS_CODE, VENDOR_ID, - }, - le_write_u16, PciBus, PciDevBase, PciDevOps, +use crate::pci::config::{ + PciConfig, RegionType, DEVICE_ID, PCI_CLASS_MEMORY_RAM, PCI_CONFIG_SPACE_SIZE, + PCI_VENDOR_ID_REDHAT_QUMRANET, REVISION_ID, SUB_CLASS_CODE, VENDOR_ID, }; -use crate::{Device, DeviceBase}; +use crate::pci::{le_write_u16, PciBus, PciDevBase, PciDevOps}; +use crate::{convert_bus_mut, convert_bus_ref, Device, DeviceBase, MUT_PCI_BUS, PCI_BUS}; use address_space::{GuestAddress, Region, RegionOps}; use util::gen_base_func; @@ -52,10 +50,9 @@ impl Ivshmem { ) -> Self { Self { base: PciDevBase { - base: DeviceBase::new(name, false, Some(parent_bus.clone())), + base: DeviceBase::new(name, false, Some(parent_bus)), config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, PCI_BAR_MAX_IVSHMEM), devfn, - parent_bus, }, dev_id: Arc::new(AtomicU16::new(0)), ram_mem_region, @@ -123,16 +120,16 @@ impl PciDevOps for Ivshmem { self.register_bars()?; // Attach to the PCI bus. - let pci_bus = self.base.parent_bus.upgrade().unwrap(); - let mut locked_pci_bus = pci_bus.lock().unwrap(); - let pci_device = locked_pci_bus.devices.get(&self.base.devfn); + let bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_PCI_BUS!(bus, locked_bus, pci_bus); + let pci_device = pci_bus.devices.get(&self.base.devfn); match pci_device { Some(device) => bail!( "Devfn {:?} has been used by {:?}", &self.base.devfn, device.lock().unwrap().name() ), - None => locked_pci_bus + None => pci_bus .devices .insert(self.base.devfn, Arc::new(Mutex::new(self))), }; @@ -140,16 +137,16 @@ impl PciDevOps for Ivshmem { } fn write_config(&mut self, offset: usize, data: &[u8]) { - let parent_bus = self.base.parent_bus.upgrade().unwrap(); - let locked_parent_bus = parent_bus.lock().unwrap(); + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + PCI_BUS!(parent_bus, locked_bus, pci_bus); self.base.config.write( offset, data, self.dev_id.load(Ordering::Acquire), #[cfg(target_arch = "x86_64")] - Some(&locked_parent_bus.io_region), - Some(&locked_parent_bus.mem_region), + Some(&pci_bus.io_region), + Some(&pci_bus.mem_region), ); } } diff --git a/devices/src/misc/pvpanic.rs b/devices/src/misc/pvpanic.rs index 2e2444ea..b1d483b3 100644 --- a/devices/src/misc/pvpanic.rs +++ b/devices/src/misc/pvpanic.rs @@ -20,16 +20,14 @@ use clap::Parser; use log::{debug, error, info}; use serde::{Deserialize, Serialize}; -use crate::pci::{ - config::{ - PciConfig, RegionType, CLASS_PI, DEVICE_ID, HEADER_TYPE, PCI_CLASS_SYSTEM_OTHER, - PCI_CONFIG_SPACE_SIZE, PCI_DEVICE_ID_REDHAT_PVPANIC, PCI_SUBDEVICE_ID_QEMU, - PCI_VENDOR_ID_REDHAT, PCI_VENDOR_ID_REDHAT_QUMRANET, REVISION_ID, SUBSYSTEM_ID, - SUBSYSTEM_VENDOR_ID, SUB_CLASS_CODE, VENDOR_ID, - }, - le_write_u16, PciBus, PciDevBase, PciDevOps, +use crate::pci::config::{ + PciConfig, RegionType, CLASS_PI, DEVICE_ID, HEADER_TYPE, PCI_CLASS_SYSTEM_OTHER, + PCI_CONFIG_SPACE_SIZE, PCI_DEVICE_ID_REDHAT_PVPANIC, PCI_SUBDEVICE_ID_QEMU, + PCI_VENDOR_ID_REDHAT, PCI_VENDOR_ID_REDHAT_QUMRANET, REVISION_ID, SUBSYSTEM_ID, + SUBSYSTEM_VENDOR_ID, SUB_CLASS_CODE, VENDOR_ID, }; -use crate::{Device, DeviceBase}; +use crate::pci::{le_write_u16, PciBus, PciDevBase, PciDevOps}; +use crate::{convert_bus_mut, convert_bus_ref, Device, DeviceBase, MUT_PCI_BUS, PCI_BUS}; use address_space::{GuestAddress, Region, RegionOps}; use machine_manager::config::{get_pci_df, valid_id}; use util::gen_base_func; @@ -112,10 +110,9 @@ impl PvPanicPci { pub fn new(config: &PvpanicDevConfig, devfn: u8, parent_bus: Weak>) -> Self { Self { base: PciDevBase { - base: DeviceBase::new(config.id.clone(), false, Some(parent_bus.clone())), + base: DeviceBase::new(config.id.clone(), false, Some(parent_bus)), config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 1), devfn, - parent_bus, }, dev_id: AtomicU16::new(0), pvpanic: Arc::new(PvPanicState::new(config.supported_features)), @@ -218,16 +215,16 @@ impl PciDevOps for PvPanicPci { // Attach to the PCI bus. let devfn = self.base.devfn; let dev = Arc::new(Mutex::new(self)); - let pci_bus = dev.lock().unwrap().base.parent_bus.upgrade().unwrap(); - let mut locked_pci_bus = pci_bus.lock().unwrap(); - let device_id = locked_pci_bus.generate_dev_id(devfn); + let bus = dev.lock().unwrap().parent_bus().unwrap().upgrade().unwrap(); + MUT_PCI_BUS!(bus, locked_bus, pci_bus); + let device_id = pci_bus.generate_dev_id(devfn); dev.lock() .unwrap() .dev_id .store(device_id, Ordering::Release); - let pci_device = locked_pci_bus.devices.get(&devfn); + let pci_device = pci_bus.devices.get(&devfn); if pci_device.is_none() { - locked_pci_bus.devices.insert(devfn, dev); + pci_bus.devices.insert(devfn, dev); } else { bail!( "pvpanic: Devfn {:?} has been used by {:?}", @@ -244,16 +241,16 @@ impl PciDevOps for PvPanicPci { } fn write_config(&mut self, offset: usize, data: &[u8]) { - let parent_bus = self.base.parent_bus.upgrade().unwrap(); - let locked_parent_bus = parent_bus.lock().unwrap(); + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + PCI_BUS!(parent_bus, locked_bus, pci_bus); self.base.config.write( offset, data, self.dev_id.load(Ordering::Acquire), #[cfg(target_arch = "x86_64")] - Some(&locked_parent_bus.io_region), - Some(&locked_parent_bus.mem_region), + Some(&pci_bus.io_region), + Some(&pci_bus.mem_region), ); } } diff --git a/devices/src/pci/bus.rs b/devices/src/pci/bus.rs index 3490fe6d..631f1be5 100644 --- a/devices/src/pci/bus.rs +++ b/devices/src/pci/bus.rs @@ -54,6 +54,22 @@ impl Bus for PciBus { gen_base_func!(bus_base, bus_base_mut, BusBase, base); } +/// Convert from Arc> to &mut PciBus. +#[macro_export] +macro_rules! MUT_PCI_BUS { + ($trait_bus:expr, $lock_bus: ident, $struct_bus: ident) => { + convert_bus_mut!($trait_bus, $lock_bus, $struct_bus, PciBus); + }; +} + +/// Convert from Arc> to &PciBus. +#[macro_export] +macro_rules! PCI_BUS { + ($trait_bus:expr, $lock_bus: ident, $struct_bus: ident) => { + convert_bus_ref!($trait_bus, $lock_bus, $struct_bus, PciBus); + }; +} + impl PciBus { /// Create new bus entity. /// diff --git a/devices/src/pci/config.rs b/devices/src/pci/config.rs index 16c9b6a5..69976cac 100644 --- a/devices/src/pci/config.rs +++ b/devices/src/pci/config.rs @@ -22,6 +22,7 @@ use crate::pci::{ le_read_u16, le_read_u32, le_read_u64, le_write_u16, le_write_u32, le_write_u64, pci_ext_cap_next, PciBus, PciError, BDF_FUNC_SHIFT, }; +use crate::{convert_bus_ref, Bus, PCI_BUS}; use address_space::Region; use util::num_ops::ranges_overlap; @@ -804,8 +805,8 @@ impl PciConfig { /// # Arguments /// /// * `bus` - The bus which region registered. - pub fn unregister_bars(&mut self, bus: &Arc>) -> Result<()> { - let locked_bus = bus.lock().unwrap(); + pub fn unregister_bars(&mut self, bus: &Arc>) -> Result<()> { + PCI_BUS!(bus, locked_bus, pci_bus); for bar in self.bars.iter_mut() { if bar.address == BAR_SPACE_UNMAPPED || bar.size == 0 { continue; @@ -815,7 +816,7 @@ impl PciConfig { { #[cfg(target_arch = "x86_64")] if let Some(region) = bar.region.as_ref() { - locked_bus + pci_bus .io_region .delete_subregion(region) .with_context(|| "Failed to unregister io bar")?; @@ -823,7 +824,7 @@ impl PciConfig { } _ => { if let Some(region) = bar.region.as_ref() { - locked_bus + pci_bus .mem_region .delete_subregion(region) .with_context(|| "Failed to unregister mem bar")?; @@ -1510,7 +1511,7 @@ mod tests { #[cfg(target_arch = "x86_64")] io_region.clone(), mem_region.clone(), - ))); + ))) as Arc>; assert!(pci_config.unregister_bars(&bus).is_ok()); diff --git a/devices/src/pci/demo_device/mod.rs b/devices/src/pci/demo_device/mod.rs index 52e1381d..37dc6b73 100644 --- a/devices/src/pci/demo_device/mod.rs +++ b/devices/src/pci/demo_device/mod.rs @@ -56,7 +56,7 @@ use crate::pci::{ init_msix, le_write_u16, PciBus, PciDevOps, }; use crate::pci::{demo_device::base_device::BaseDevice, PciDevBase}; -use crate::{Device, DeviceBase}; +use crate::{convert_bus_mut, convert_bus_ref, Device, DeviceBase, MUT_PCI_BUS, PCI_BUS}; use address_space::{AddressSpace, GuestAddress, Region, RegionOps}; use machine_manager::config::{get_pci_df, valid_id}; use util::gen_base_func; @@ -109,10 +109,9 @@ impl DemoDev { }; DemoDev { base: PciDevBase { - base: DeviceBase::new(cfg.id.clone(), false, Some(parent_bus.clone())), + base: DeviceBase::new(cfg.id.clone(), false, Some(parent_bus)), config: PciConfig::new(PCIE_CONFIG_SPACE_SIZE, cfg.bar_num), devfn, - parent_bus, }, cmd_cfg: cfg, mem_region: Region::init_container_region(u32::MAX as u64, "DemoDev"), @@ -135,14 +134,14 @@ impl DemoDev { } fn attach_to_parent_bus(self) -> Result<()> { - let parent_bus = self.base.parent_bus.upgrade().unwrap(); - let mut locked_parent_bus = parent_bus.lock().unwrap(); - if locked_parent_bus.devices.get(&self.base.devfn).is_some() { + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_PCI_BUS!(parent_bus, locked_bus, pci_bus); + if pci_bus.devices.get(&self.base.devfn).is_some() { bail!("device already existed"); } let devfn = self.base.devfn; let demo_pci_dev = Arc::new(Mutex::new(self)); - locked_parent_bus.devices.insert(devfn, demo_pci_dev); + pci_bus.devices.insert(devfn, demo_pci_dev); Ok(()) } @@ -223,8 +222,8 @@ impl PciDevOps for DemoDev { /// write the pci configuration space fn write_config(&mut self, offset: usize, data: &[u8]) { - let parent_bus = self.base.parent_bus.upgrade().unwrap(); - let parent_bus_locked = parent_bus.lock().unwrap(); + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + PCI_BUS!(parent_bus, locked_bus, pci_bus); self.base.config.write( offset, @@ -232,7 +231,7 @@ impl PciDevOps for DemoDev { self.dev_id.load(Ordering::Acquire), #[cfg(target_arch = "x86_64")] None, - Some(&parent_bus_locked.mem_region), + Some(&pci_bus.mem_region), ); } diff --git a/devices/src/pci/intx.rs b/devices/src/pci/intx.rs index ca141850..9b62e0bd 100644 --- a/devices/src/pci/intx.rs +++ b/devices/src/pci/intx.rs @@ -18,7 +18,7 @@ use log::error; use super::{PciDevOps, RootPort}; use crate::interrupt_controller::LineIrqManager; use crate::pci::{swizzle_map_irq, PciBus, PciConfig, INTERRUPT_PIN, PCI_PIN_NUM}; -use crate::{convert_device_ref, Bus, ROOT_PORT}; +use crate::{convert_bus_ref, convert_device_ref, Bus, PCI_BUS, ROOT_PORT}; pub type InterruptHandler = Box Result<()> + Send + Sync>; @@ -121,7 +121,7 @@ impl Intx { pub fn init_intx( name: String, config: &mut PciConfig, - parent_bus: Weak>, + parent_bus: Weak>, devfn: u8, ) -> Result<()> { if config.config[INTERRUPT_PIN as usize] == 0 { @@ -131,11 +131,11 @@ pub fn init_intx( return Ok(()); } - let (irq, intx_state) = if let Some(pci_bus) = parent_bus.upgrade() { - let locked_pci_bus = pci_bus.lock().unwrap(); + let (irq, intx_state) = if let Some(bus) = parent_bus.upgrade() { + PCI_BUS!(bus, locked_bus, pci_bus); let pin = config.config[INTERRUPT_PIN as usize] - 1; - let (irq, intx_state) = match &locked_pci_bus.parent_device() { + let (irq, intx_state) = match &pci_bus.parent_device() { Some(parent_bridge) => { let parent_bridge = parent_bridge.upgrade().unwrap(); ROOT_PORT!(parent_bridge, locked_bridge, bridge); @@ -145,10 +145,10 @@ pub fn init_intx( ) } None => { - if locked_pci_bus.intx_state.is_some() { + if pci_bus.intx_state.is_some() { ( swizzle_map_irq(devfn, pin), - Some(locked_pci_bus.intx_state.as_ref().unwrap().clone()), + Some(pci_bus.intx_state.as_ref().unwrap().clone()), ) } else { (std::u32::MAX, None) diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs index 97b9126c..e3da00e3 100644 --- a/devices/src/pci/mod.rs +++ b/devices/src/pci/mod.rs @@ -44,7 +44,9 @@ use crate::misc::ivshmem::Ivshmem; use crate::misc::pvpanic::PvPanicPci; use crate::pci::config::{HEADER_TYPE, HEADER_TYPE_MULTIFUNC, MAX_FUNC}; use crate::usb::xhci::xhci_pci::XhciPciDevice; -use crate::{convert_device_ref, Bus, Device, DeviceBase, MsiIrqManager, ROOT_PORT}; +use crate::{ + convert_bus_ref, convert_device_ref, Bus, Device, DeviceBase, MsiIrqManager, PCI_BUS, ROOT_PORT, +}; #[cfg(feature = "demo_device")] use demo_device::DemoDev; @@ -141,8 +143,6 @@ pub struct PciDevBase { pub config: PciConfig, /// Devfn. pub devfn: u8, - /// Primary Bus. - pub parent_bus: Weak>, } pub trait PciDevOps: Device + Send { @@ -219,19 +219,15 @@ pub trait PciDevOps: Device + Send { } /// Get the path of the PCI bus where the device resides. - fn get_parent_dev_path(&self, parent_bus: Arc>) -> String { - let locked_parent_bus = parent_bus.lock().unwrap(); - let parent_dev_path = if locked_parent_bus.name().eq("pcie.0") { + fn get_parent_dev_path(&self, parent_bus: Arc>) -> String { + PCI_BUS!(parent_bus, locked_bus, pci_bus); + let parent_dev_path = if pci_bus.name().eq("pcie.0") { String::from("/pci@ffffffffffffffff") } else { // This else branch will not be executed currently, // which is mainly to be compatible with new PCI bridge devices. // unwrap is safe because pci bus under root port will not return null. - let parent_bridge = locked_parent_bus - .parent_device() - .unwrap() - .upgrade() - .unwrap(); + let parent_bridge = pci_bus.parent_device().unwrap().upgrade().unwrap(); ROOT_PORT!(parent_bridge, locked_bridge, rootport); rootport.get_dev_path().unwrap() }; @@ -333,7 +329,7 @@ pub fn init_multifunction( multifunction: bool, config: &mut [u8], devfn: u8, - parent_bus: Weak>, + parent_bus: Weak>, ) -> Result<()> { let mut header_type = le_read_u16(config, HEADER_TYPE as usize)? & (!HEADER_TYPE_MULTIFUNC as u16); @@ -348,9 +344,9 @@ pub fn init_multifunction( // leave the bit to 0. let slot = pci_slot(devfn); let bus = parent_bus.upgrade().unwrap(); - let locked_bus = bus.lock().unwrap(); + PCI_BUS!(bus, locked_bus, pci_bus); if pci_func(devfn) != 0 { - let pci_dev = locked_bus.devices.get(&pci_devfn(slot, 0)); + let pci_dev = pci_bus.devices.get(&pci_devfn(slot, 0)); if pci_dev.is_none() { return Ok(()); } @@ -379,7 +375,7 @@ pub fn init_multifunction( // If function 0 is set to single function, the rest function should be None. for func in 1..MAX_FUNC { - if locked_bus.devices.get(&pci_devfn(slot, func)).is_some() { + if pci_bus.devices.get(&pci_devfn(slot, func)).is_some() { bail!( "PCI: {}.0 indicates single function, but {}.{} is already populated", slot, @@ -402,7 +398,7 @@ pub fn swizzle_map_irq(devfn: u8, pin: u8) -> u32 { mod tests { use super::*; use crate::pci::config::{PciConfig, PCI_CONFIG_SPACE_SIZE}; - use crate::DeviceBase; + use crate::{convert_bus_mut, DeviceBase, MUT_PCI_BUS}; use address_space::{AddressSpace, Region}; use util::gen_base_func; @@ -415,10 +411,9 @@ mod tests { pub fn new(name: &str, devfn: u8, parent_bus: Weak>) -> Self { Self { base: PciDevBase { - base: DeviceBase::new(name.to_string(), false, Some(parent_bus.clone())), + base: DeviceBase::new(name.to_string(), false, Some(parent_bus)), config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 0), devfn, - parent_bus, }, } } @@ -448,12 +443,9 @@ mod tests { self.init_write_clear_mask(false)?; let dev = Arc::new(Mutex::new(self)); - let parent_bus = dev.lock().unwrap().base.parent_bus.upgrade().unwrap(); - parent_bus - .lock() - .unwrap() - .devices - .insert(devfn, dev.clone()); + let parent_bus = dev.lock().unwrap().parent_bus().unwrap().upgrade().unwrap(); + MUT_PCI_BUS!(parent_bus, locked_bus, pci_bus); + pci_bus.devices.insert(devfn, dev.clone()); Ok(()) } diff --git a/devices/src/pci/msix.rs b/devices/src/pci/msix.rs index 3d403402..e82b7c17 100644 --- a/devices/src/pci/msix.rs +++ b/devices/src/pci/msix.rs @@ -21,9 +21,10 @@ use vmm_sys_util::eventfd::EventFd; use crate::pci::config::{CapId, RegionType, MINIMUM_BAR_SIZE_FOR_MMIO}; use crate::pci::{ - le_read_u16, le_read_u32, le_read_u64, le_write_u16, le_write_u32, le_write_u64, PciDevBase, + le_read_u16, le_read_u32, le_read_u64, le_write_u16, le_write_u32, le_write_u64, PciBus, + PciDevBase, }; -use crate::MsiIrqManager; +use crate::{convert_bus_ref, MsiIrqManager, PCI_BUS}; use address_space::{GuestAddress, Region, RegionOps}; use migration::{ DeviceStateDesc, FieldDesc, MigrationError, MigrationHook, MigrationManager, StateTransfer, @@ -552,7 +553,7 @@ pub fn init_msix( offset_opt: Option<(u32, u32)>, ) -> Result<()> { let config = &mut pcidev_base.config; - let parent_bus = &pcidev_base.parent_bus; + let parent_bus = pcidev_base.base.parent.as_ref().unwrap(); if vector_nr == 0 || vector_nr > MSIX_TABLE_SIZE_MAX as u32 + 1 { bail!( "invalid msix vectors, which should be in [1, {}]", @@ -586,9 +587,9 @@ pub fn init_msix( offset = msix_cap_offset + MSIX_CAP_PBA as usize; le_write_u32(&mut config.config, offset, pba_offset | bar_id as u32)?; - let msi_irq_manager = if let Some(pci_bus) = parent_bus.upgrade() { - let locked_pci_bus = pci_bus.lock().unwrap(); - locked_pci_bus.get_msi_irq_manager() + let msi_irq_manager = if let Some(bus) = parent_bus.upgrade() { + PCI_BUS!(bus, locked_bus, pci_bus); + pci_bus.get_msi_irq_manager() } else { error!("Msi irq controller is none"); None @@ -633,21 +634,20 @@ pub fn init_msix( #[cfg(test)] mod tests { - use std::sync::Weak; - use super::*; - use crate::{ - pci::config::{PciConfig, PCI_CONFIG_SPACE_SIZE}, - DeviceBase, - }; + use crate::pci::config::{PciConfig, PCI_CONFIG_SPACE_SIZE}; + use crate::pci::host::tests::create_pci_host; + use crate::DeviceBase; #[test] fn test_init_msix() { + let pci_host = create_pci_host(); + let locked_pci_host = pci_host.lock().unwrap(); + let root_bus = Arc::downgrade(&locked_pci_host.root_bus); let mut base = PciDevBase { - base: DeviceBase::new("msix".to_string(), false, None), + base: DeviceBase::new("msix".to_string(), false, Some(root_bus)), config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 2), devfn: 1, - parent_bus: Weak::new(), }; // Too many vectors. assert!(init_msix( @@ -746,11 +746,13 @@ mod tests { #[test] fn test_write_config() { + let pci_host = create_pci_host(); + let locked_pci_host = pci_host.lock().unwrap(); + let root_bus = Arc::downgrade(&locked_pci_host.root_bus); let mut base = PciDevBase { - base: DeviceBase::new("msix".to_string(), false, None), + base: DeviceBase::new("msix".to_string(), false, Some(root_bus)), config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 2), devfn: 1, - parent_bus: Weak::new(), }; init_msix(&mut base, 0, 2, Arc::new(AtomicU16::new(0)), None, None).unwrap(); let msix = base.config.msix.as_ref().unwrap(); diff --git a/devices/src/pci/root_port.rs b/devices/src/pci/root_port.rs index 21f252ef..cf05c4b6 100644 --- a/devices/src/pci/root_port.rs +++ b/devices/src/pci/root_port.rs @@ -38,7 +38,9 @@ use crate::pci::{init_multifunction, PciDevBase, PciError, PciIntxState, INTERRU use crate::pci::{ le_read_u16, le_write_clear_value_u16, le_write_set_value_u16, le_write_u16, PciDevOps, }; -use crate::{Device, DeviceBase, MsiIrqManager}; +use crate::{ + convert_bus_mut, convert_bus_ref, Device, DeviceBase, MsiIrqManager, MUT_PCI_BUS, PCI_BUS, +}; use address_space::Region; use machine_manager::config::{get_pci_df, parse_bool, valid_id}; use machine_manager::qmp::qmp_channel::send_device_deleted_msg; @@ -121,10 +123,9 @@ impl RootPort { Self { base: PciDevBase { - base: DeviceBase::new(cfg.id, true, Some(parent_bus.clone())), + base: DeviceBase::new(cfg.id, true, Some(parent_bus)), config: PciConfig::new(PCIE_CONFIG_SPACE_SIZE, 2), devfn, - parent_bus, }, port_num: cfg.port, sec_bus, @@ -236,16 +237,13 @@ impl RootPort { } fn register_region(&mut self) { + let bus = self.parent_bus().unwrap().upgrade().unwrap(); + PCI_BUS!(bus, locked_bus, pci_bus); + let command: u16 = le_read_u16(&self.base.config.config, COMMAND as usize).unwrap(); if command & COMMAND_IO_SPACE != 0 { #[cfg(target_arch = "x86_64")] - if let Err(e) = self - .base - .parent_bus - .upgrade() - .unwrap() - .lock() - .unwrap() + if let Err(e) = pci_bus .io_region .add_subregion(self.io_region.clone(), 0) .with_context(|| "Failed to add IO container region.") @@ -254,13 +252,7 @@ impl RootPort { } } if command & COMMAND_MEMORY_SPACE != 0 { - if let Err(e) = self - .base - .parent_bus - .upgrade() - .unwrap() - .lock() - .unwrap() + if let Err(e) = pci_bus .mem_region .add_subregion(self.mem_region.clone(), 0) .with_context(|| "Failed to add memory container region.") @@ -367,6 +359,7 @@ impl PciDevOps for RootPort { gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); fn realize(mut self) -> Result<()> { + let parent_bus = self.parent_bus().unwrap(); self.init_write_mask(true)?; self.init_write_clear_mask(true)?; @@ -382,7 +375,7 @@ impl PciDevOps for RootPort { self.multifunction, config_space, self.base.devfn, - self.base.parent_bus.clone(), + parent_bus.clone(), )?; #[cfg(target_arch = "aarch64")] @@ -400,18 +393,18 @@ impl PciDevOps for RootPort { init_intx( self.name(), &mut self.base.config, - self.base.parent_bus.clone(), + parent_bus.clone(), self.base.devfn, )?; - let parent_bus = self.base.parent_bus.upgrade().unwrap(); - let mut locked_parent_bus = parent_bus.lock().unwrap(); + let bus = parent_bus.upgrade().unwrap(); + MUT_PCI_BUS!(bus, locked_bus, pci_bus); #[cfg(target_arch = "x86_64")] - locked_parent_bus + pci_bus .io_region .add_subregion(self.sec_bus.lock().unwrap().io_region.clone(), 0) .with_context(|| "Failed to register subregion in I/O space.")?; - locked_parent_bus + pci_bus .mem_region .add_subregion(self.sec_bus.lock().unwrap().mem_region.clone(), 0) .with_context(|| "Failed to register subregion in memory space.")?; @@ -424,12 +417,10 @@ impl PciDevOps for RootPort { Some(Arc::downgrade(&root_port) as Weak>); locked_root_port.sec_bus.lock().unwrap().hotplug_controller = Some(Arc::downgrade(&root_port) as Weak>); - let pci_device = locked_parent_bus.devices.get(&locked_root_port.base.devfn); + let pci_device = pci_bus.devices.get(&locked_root_port.base.devfn); if pci_device.is_none() { - locked_parent_bus - .child_buses - .push(locked_root_port.sec_bus.clone()); - locked_parent_bus + pci_bus.child_buses.push(locked_root_port.sec_bus.clone()); + pci_bus .devices .insert(locked_root_port.base.devfn, root_port.clone()); } else { @@ -554,7 +545,7 @@ impl PciDevOps for RootPort { } fn get_dev_path(&self) -> Option { - let parent_bus = self.base.parent_bus.upgrade().unwrap(); + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); let parent_dev_path = self.get_parent_dev_path(parent_bus); let dev_path = self.populate_dev_path(parent_dev_path, self.base.devfn, "/pci-bridge@"); Some(dev_path) diff --git a/devices/src/usb/xhci/xhci_pci.rs b/devices/src/usb/xhci/xhci_pci.rs index cdcd50cb..7b966bd7 100644 --- a/devices/src/usb/xhci/xhci_pci.rs +++ b/devices/src/usb/xhci/xhci_pci.rs @@ -34,7 +34,7 @@ use crate::pci::config::{ }; use crate::pci::{init_intx, init_msix, le_write_u16, PciBus, PciDevBase, PciDevOps}; use crate::usb::UsbDevice; -use crate::{Device, DeviceBase}; +use crate::{convert_bus_mut, convert_bus_ref, Device, DeviceBase, MUT_PCI_BUS, PCI_BUS}; use address_space::{AddressRange, AddressSpace, Region, RegionIoEventFd}; use machine_manager::config::{get_pci_df, valid_id}; use machine_manager::event_loop::register_event_helper; @@ -113,10 +113,9 @@ impl XhciPciDevice { ) -> Self { Self { base: PciDevBase { - base: DeviceBase::new(config.id.clone().unwrap(), true, Some(parent_bus.clone())), + base: DeviceBase::new(config.id.clone().unwrap(), true, Some(parent_bus)), config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 1), devfn, - parent_bus, }, xhci: XhciDevice::new(mem_space, config), dev_id: Arc::new(AtomicU16::new(0)), @@ -297,10 +296,11 @@ impl PciDevOps for XhciPciDevice { Some((XHCI_MSIX_TABLE_OFFSET, XHCI_MSIX_PBA_OFFSET)), )?; + let parent_bus = self.parent_bus().unwrap(); init_intx( self.name(), &mut self.base.config, - self.base.parent_bus.clone(), + parent_bus, self.base.devfn, )?; @@ -337,11 +337,11 @@ impl PciDevOps for XhciPciDevice { })); let dev = Arc::new(Mutex::new(self)); // Attach to the PCI bus. - let pci_bus = dev.lock().unwrap().base.parent_bus.upgrade().unwrap(); - let mut locked_pci_bus = pci_bus.lock().unwrap(); - let pci_device = locked_pci_bus.devices.get(&devfn); + let bus = dev.lock().unwrap().parent_bus().unwrap().upgrade().unwrap(); + MUT_PCI_BUS!(bus, locked_bus, pci_bus); + let pci_device = pci_bus.devices.get(&devfn); if pci_device.is_none() { - locked_pci_bus.devices.insert(devfn, dev); + pci_bus.devices.insert(devfn, dev); } else { bail!( "Devfn {:?} has been used by {:?}", @@ -358,17 +358,17 @@ impl PciDevOps for XhciPciDevice { } fn write_config(&mut self, offset: usize, data: &[u8]) { - let parent_bus = self.base.parent_bus.upgrade().unwrap(); - let locked_parent_bus = parent_bus.lock().unwrap(); - locked_parent_bus.update_dev_id(self.base.devfn, &self.dev_id); + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + PCI_BUS!(parent_bus, locked_bus, pci_bus); + pci_bus.update_dev_id(self.base.devfn, &self.dev_id); self.base.config.write( offset, data, self.dev_id.clone().load(Ordering::Acquire), #[cfg(target_arch = "x86_64")] - Some(&locked_parent_bus.io_region), - Some(&locked_parent_bus.mem_region), + Some(&pci_bus.io_region), + Some(&pci_bus.mem_region), ); } diff --git a/machine/src/aarch64/pci_host_root.rs b/machine/src/aarch64/pci_host_root.rs index 7192fbbe..a984ec70 100644 --- a/machine/src/aarch64/pci_host_root.rs +++ b/machine/src/aarch64/pci_host_root.rs @@ -14,14 +14,12 @@ use std::sync::{Arc, Mutex, Weak}; use anyhow::Result; -use devices::pci::{ - config::{ - PciConfig, CLASS_CODE_HOST_BRIDGE, DEVICE_ID, PCI_CONFIG_SPACE_SIZE, PCI_VENDOR_ID_REDHAT, - REVISION_ID, SUB_CLASS_CODE, VENDOR_ID, - }, - le_write_u16, PciBus, PciDevBase, PciDevOps, +use devices::pci::config::{ + PciConfig, CLASS_CODE_HOST_BRIDGE, DEVICE_ID, PCI_CONFIG_SPACE_SIZE, PCI_VENDOR_ID_REDHAT, + REVISION_ID, SUB_CLASS_CODE, VENDOR_ID, }; -use devices::{Device, DeviceBase}; +use devices::pci::{le_write_u16, PciBus, PciDevBase, PciDevOps}; +use devices::{convert_bus_mut, Device, DeviceBase, MUT_PCI_BUS}; use util::gen_base_func; const DEVICE_ID_PCIE_HOST: u16 = 0x0008; @@ -35,9 +33,8 @@ impl PciHostRoot { pub fn new(parent_bus: Weak>) -> Self { Self { base: PciDevBase { - base: DeviceBase::new("PCI Host Root".to_string(), false, Some(parent_bus.clone())), + base: DeviceBase::new("PCI Host Root".to_string(), false, Some(parent_bus)), config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 0), - parent_bus, devfn: 0, }, } @@ -72,12 +69,10 @@ impl PciDevOps for PciHostRoot { )?; le_write_u16(&mut self.base.config.config, REVISION_ID, 0)?; - let parent_bus = self.base.parent_bus.upgrade().unwrap(); - parent_bus - .lock() - .unwrap() - .devices - .insert(0, Arc::new(Mutex::new(self))); + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_PCI_BUS!(parent_bus, locked_bus, pci_bus); + pci_bus.devices.insert(0, Arc::new(Mutex::new(self))); + Ok(()) } diff --git a/machine/src/x86_64/ich9_lpc.rs b/machine/src/x86_64/ich9_lpc.rs index 83e1e4a5..461f97b9 100644 --- a/machine/src/x86_64/ich9_lpc.rs +++ b/machine/src/x86_64/ich9_lpc.rs @@ -27,7 +27,7 @@ use devices::pci::config::{ HEADER_TYPE_MULTIFUNC, PCI_CONFIG_SPACE_SIZE, SUB_CLASS_CODE, VENDOR_ID, }; use devices::pci::{le_write_u16, le_write_u32, PciBus, PciDevBase, PciDevOps}; -use devices::{Device, DeviceBase}; +use devices::{convert_bus_mut, Device, DeviceBase, MUT_PCI_BUS}; use util::byte_code::ByteCode; use util::gen_base_func; use util::num_ops::ranges_overlap; @@ -64,14 +64,9 @@ impl LPCBridge { ) -> Result { Ok(Self { base: PciDevBase { - base: DeviceBase::new( - "ICH9 LPC bridge".to_string(), - false, - Some(parent_bus.clone()), - ), + base: DeviceBase::new("ICH9 LPC bridge".to_string(), false, Some(parent_bus)), config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 0), devfn: 0x1F << 3, - parent_bus, }, sys_io, pm_timer: Arc::new(Mutex::new(AcpiPMTimer::new())), @@ -281,12 +276,9 @@ impl PciDevOps for LPCBridge { self.init_pm_ctrl_reg() .with_context(|| "Fail to init IO region for PM control register")?; - let parent_bus = self.base.parent_bus.clone(); - parent_bus - .upgrade() - .unwrap() - .lock() - .unwrap() + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_PCI_BUS!(parent_bus, locked_bus, pci_bus); + pci_bus .devices .insert(0x1F << 3, Arc::new(Mutex::new(self))); Ok(()) diff --git a/machine/src/x86_64/mch.rs b/machine/src/x86_64/mch.rs index a025281e..f9d418c1 100644 --- a/machine/src/x86_64/mch.rs +++ b/machine/src/x86_64/mch.rs @@ -24,7 +24,7 @@ use devices::pci::{ }, le_read_u64, le_write_u16, PciBus, PciDevBase, PciDevOps, }; -use devices::{Device, DeviceBase}; +use devices::{convert_bus_mut, convert_bus_ref, Device, DeviceBase, MUT_PCI_BUS, PCI_BUS}; use util::gen_base_func; use util::num_ops::ranges_overlap; @@ -57,14 +57,9 @@ impl Mch { ) -> Self { Self { base: PciDevBase { - base: DeviceBase::new( - "Memory Controller Hub".to_string(), - false, - Some(parent_bus.clone()), - ), + base: DeviceBase::new("Memory Controller Hub".to_string(), false, Some(parent_bus)), config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 0), devfn: 0, - parent_bus, }, mmconfig_region: Some(mmconfig_region), mmconfig_ops, @@ -90,27 +85,17 @@ impl Mch { } if let Some(region) = self.mmconfig_region.as_ref() { - self.base - .parent_bus - .upgrade() - .unwrap() - .lock() - .unwrap() - .mem_region - .delete_subregion(region)?; + let bus = self.parent_bus().unwrap().upgrade().unwrap(); + PCI_BUS!(bus, locked_bus, pci_bus); + pci_bus.mem_region.delete_subregion(region)?; self.mmconfig_region = None; } if enable == 0x1 { let region = Region::init_io_region(length, self.mmconfig_ops.clone(), "PcieXBar"); let base_addr: u64 = pciexbar & addr_mask; - self.base - .parent_bus - .upgrade() - .unwrap() - .lock() - .unwrap() - .mem_region - .add_subregion(region, base_addr)?; + let bus = self.parent_bus().unwrap().upgrade().unwrap(); + PCI_BUS!(bus, locked_bus, pci_bus); + pci_bus.mem_region.add_subregion(region, base_addr)?; } Ok(()) } @@ -152,14 +137,9 @@ impl PciDevOps for Mch { CLASS_CODE_HOST_BRIDGE, )?; - let parent_bus = self.base.parent_bus.clone(); - parent_bus - .upgrade() - .unwrap() - .lock() - .unwrap() - .devices - .insert(0, Arc::new(Mutex::new(self))); + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_PCI_BUS!(parent_bus, locked_bus, pci_bus); + pci_bus.devices.insert(0, Arc::new(Mutex::new(self))); Ok(()) } diff --git a/vfio/src/vfio_pci.rs b/vfio/src/vfio_pci.rs index 391fba16..b4c1f273 100644 --- a/vfio/src/vfio_pci.rs +++ b/vfio/src/vfio_pci.rs @@ -43,7 +43,9 @@ use devices::pci::{ init_multifunction, le_read_u16, le_read_u32, le_write_u16, le_write_u32, pci_ext_cap_id, pci_ext_cap_next, pci_ext_cap_ver, PciBus, PciDevBase, PciDevOps, }; -use devices::{pci::MsiVector, Device, DeviceBase}; +use devices::{ + convert_bus_mut, convert_bus_ref, pci::MsiVector, Device, DeviceBase, MUT_PCI_BUS, PCI_BUS, +}; use machine_manager::config::{get_pci_df, parse_bool, valid_id}; use util::gen_base_func; use util::loop_context::create_new_eventfd; @@ -132,10 +134,9 @@ impl VfioPciDevice { Self { // Unknown PCI or PCIe type here, allocate enough space to match the two types. base: PciDevBase { - base: DeviceBase::new(name, true, Some(parent_bus.clone())), + base: DeviceBase::new(name, true, Some(parent_bus)), config: PciConfig::new(PCIE_CONFIG_SPACE_SIZE, PCI_NUM_BARS), devfn, - parent_bus, }, config_size: 0, config_offset: 0, @@ -453,7 +454,7 @@ impl VfioPciDevice { } fn unregister_bars(&mut self) -> Result<()> { - let bus = self.base.parent_bus.upgrade().unwrap(); + let bus = self.parent_bus().unwrap().upgrade().unwrap(); self.base.config.unregister_bars(&bus)?; Ok(()) } @@ -474,9 +475,9 @@ impl VfioPciDevice { MSIX_CAP_FUNC_MASK | MSIX_CAP_ENABLE, )?; - let msi_irq_manager = if let Some(pci_bus) = self.base.parent_bus.upgrade() { - let locked_pci_bus = pci_bus.lock().unwrap(); - locked_pci_bus.get_msi_irq_manager() + let msi_irq_manager = if let Some(bus) = self.parent_bus().unwrap().upgrade() { + PCI_BUS!(bus, locked_bus, pci_bus); + pci_bus.get_msi_irq_manager() } else { None }; @@ -508,7 +509,7 @@ impl VfioPciDevice { let cloned_dev = self.vfio_device.clone(); let cloned_gsi_routes = self.gsi_msi_routes.clone(); - let parent_bus = self.base.parent_bus.clone(); + let parent_bus = self.parent_bus().unwrap().clone(); let dev_id = self.dev_id.clone(); let devfn = self.base.devfn; let cloned_msix = msix.clone(); @@ -522,8 +523,9 @@ impl VfioPciDevice { } let entry = locked_msix.get_message(vector as u16); - let parent_bus = parent_bus.upgrade().unwrap(); - parent_bus.lock().unwrap().update_dev_id(devfn, &dev_id); + let bus = parent_bus.upgrade().unwrap(); + PCI_BUS!(bus, locked_bus, pci_bus); + pci_bus.update_dev_id(devfn, &dev_id); let msix_vector = MsiVector { msg_addr_lo: entry.address_lo, msg_addr_hi: entry.address_hi, @@ -821,6 +823,7 @@ impl PciDevOps for VfioPciDevice { gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); fn realize(mut self) -> Result<()> { + let parent_bus = self.parent_bus().unwrap(); self.init_write_mask(false)?; self.init_write_clear_mask(false)?; Result::with_context(self.vfio_device.lock().unwrap().reset(), || { @@ -838,21 +841,17 @@ impl PciDevOps for VfioPciDevice { self.multi_func, &mut self.base.config.config, self.base.devfn, - self.base.parent_bus.clone(), + parent_bus.clone(), ), || "Failed to init vfio device multifunction.", )?; #[cfg(target_arch = "aarch64")] { - let bus_num = self - .base - .parent_bus - .upgrade() - .unwrap() - .lock() - .unwrap() - .number(SECONDARY_BUS_NUM as usize); + let bus = parent_bus.upgrade().unwrap(); + PCI_BUS!(bus, locked_bus, pci_bus); + let bus_num = pci_bus.number(SECONDARY_BUS_NUM as usize); + drop(locked_bus); self.dev_id = Arc::new(AtomicU16::new(self.set_dev_id(bus_num, self.base.devfn))); } @@ -867,11 +866,11 @@ impl PciDevOps for VfioPciDevice { let devfn = self.base.devfn; let dev = Arc::new(Mutex::new(self)); - let pci_bus = dev.lock().unwrap().base.parent_bus.upgrade().unwrap(); - let mut locked_pci_bus = pci_bus.lock().unwrap(); - let pci_device = locked_pci_bus.devices.get(&devfn); + let parent_bus = dev.lock().unwrap().parent_bus().unwrap().upgrade().unwrap(); + MUT_PCI_BUS!(parent_bus, locked_bus, pci_bus); + let pci_device = pci_bus.devices.get(&devfn); if pci_device.is_none() { - locked_pci_bus.devices.insert(devfn, dev); + pci_bus.devices.insert(devfn, dev); } else { bail!( "Devfn {:?} has been used by {:?}", @@ -965,15 +964,15 @@ impl PciDevOps for VfioPciDevice { let was_enable = self.base.config.msix.as_ref().map_or(false, |m| { m.lock().unwrap().is_enabled(&self.base.config.config) }); - let parent_bus = self.base.parent_bus.upgrade().unwrap(); - let locked_parent_bus = parent_bus.lock().unwrap(); + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + PCI_BUS!(parent_bus, locked_bus, pci_bus); self.base.config.write( offset, data, self.dev_id.load(Ordering::Acquire), #[cfg(target_arch = "x86_64")] - Some(&locked_parent_bus.io_region), - Some(&locked_parent_bus.mem_region), + Some(&pci_bus.io_region), + Some(&pci_bus.mem_region), ); if ranges_overlap(offset, size, COMMAND as usize, REG_SIZE).unwrap() { diff --git a/virtio/src/transport/virtio_pci.rs b/virtio/src/transport/virtio_pci.rs index a4eabe2b..19bd0212 100644 --- a/virtio/src/transport/virtio_pci.rs +++ b/virtio/src/transport/virtio_pci.rs @@ -46,7 +46,7 @@ use devices::pci::{ config::PciConfig, init_intx, init_msix, init_multifunction, le_write_u16, le_write_u32, PciBus, PciDevBase, PciDevOps, PciError, }; -use devices::{Device, DeviceBase}; +use devices::{convert_bus_mut, convert_bus_ref, Device, DeviceBase, MUT_PCI_BUS, PCI_BUS}; #[cfg(feature = "virtio_gpu")] use machine_manager::config::VIRTIO_GPU_ENABLE_BAR0_SIZE; use migration::{DeviceStateDesc, FieldDesc, MigrationHook, MigrationManager, StateTransfer}; @@ -332,10 +332,9 @@ impl VirtioPciDevice { let queue_num = device.lock().unwrap().queue_num(); VirtioPciDevice { base: PciDevBase { - base: DeviceBase::new(name, true, Some(parent_bus.clone())), + base: DeviceBase::new(name, true, Some(parent_bus)), config: PciConfig::new(PCIE_CONFIG_SPACE_SIZE, VIRTIO_PCI_BAR_MAX), devfn, - parent_bus, }, device, dev_id: Arc::new(AtomicU16::new(0)), @@ -469,11 +468,9 @@ impl VirtioPciDevice { } locked_dev.virtio_base_mut().queues = queues; - let parent = self.base.parent_bus.upgrade().unwrap(); - parent - .lock() - .unwrap() - .update_dev_id(self.base.devfn, &self.dev_id); + let bus = self.parent_bus().unwrap().upgrade().unwrap(); + PCI_BUS!(bus, locked_bus, pci_bus); + pci_bus.update_dev_id(self.base.devfn, &self.dev_id); if self.need_irqfd { let mut queue_num = locked_dev.queue_num(); // No need to create call event for control queue. @@ -1012,6 +1009,7 @@ impl PciDevOps for VirtioPciDevice { fn realize(mut self) -> Result<()> { info!("func: realize, id: {:?}", &self.base.base.id); + let parent_bus = self.parent_bus().unwrap(); self.init_write_mask(false)?; self.init_write_clear_mask(false)?; @@ -1051,7 +1049,7 @@ impl PciDevOps for VirtioPciDevice { self.multi_func, &mut self.base.config.config, self.base.devfn, - self.base.parent_bus.clone(), + parent_bus.clone(), )?; #[cfg(target_arch = "aarch64")] self.base.config.set_interrupt_pin(); @@ -1123,7 +1121,7 @@ impl PciDevOps for VirtioPciDevice { init_intx( self.name(), &mut self.base.config, - self.base.parent_bus.clone(), + parent_bus.clone(), self.base.devfn, )?; @@ -1160,11 +1158,11 @@ impl PciDevOps for VirtioPciDevice { )?; // Register device to pci bus. - let pci_bus = dev.lock().unwrap().base.parent_bus.upgrade().unwrap(); - let mut locked_pci_bus = pci_bus.lock().unwrap(); - let pci_device = locked_pci_bus.devices.get(&devfn); + let bus = parent_bus.upgrade().unwrap(); + MUT_PCI_BUS!(bus, locked_bus, pci_bus); + let pci_device = pci_bus.devices.get(&devfn); if pci_device.is_none() { - locked_pci_bus.devices.insert(devfn, dev.clone()); + pci_bus.devices.insert(devfn, dev.clone()); } else { bail!( "Devfn {:?} has been used by {:?}", @@ -1186,7 +1184,7 @@ impl PciDevOps for VirtioPciDevice { .unrealize() .with_context(|| "Failed to unrealize the virtio device")?; - let bus = self.base.parent_bus.upgrade().unwrap(); + let bus = self.parent_bus().unwrap().upgrade().unwrap(); self.base.config.unregister_bars(&bus)?; MigrationManager::unregister_device_instance(MsixState::descriptor(), &self.name()); @@ -1213,15 +1211,15 @@ impl PciDevOps for VirtioPciDevice { } trace::virtio_tpt_write_config(&self.base.base.id, offset as u64, data); - let parent_bus = self.base.parent_bus.upgrade().unwrap(); - let locked_parent_bus = parent_bus.lock().unwrap(); + let bus = self.parent_bus().unwrap().upgrade().unwrap(); + PCI_BUS!(bus, locked_bus, pci_bus); self.base.config.write( offset, data, self.dev_id.clone().load(Ordering::Acquire), #[cfg(target_arch = "x86_64")] - Some(&locked_parent_bus.io_region), - Some(&locked_parent_bus.mem_region), + Some(&pci_bus.io_region), + Some(&pci_bus.mem_region), ); self.do_cfg_access(offset, end, true); } @@ -1240,7 +1238,7 @@ impl PciDevOps for VirtioPciDevice { } fn get_dev_path(&self) -> Option { - let parent_bus = self.base.parent_bus.upgrade().unwrap(); + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); match self.device.lock().unwrap().device_type() { VIRTIO_TYPE_BLOCK => { // The virtio blk device is identified as a single-channel SCSI device, @@ -1330,12 +1328,12 @@ impl MigrationHook for VirtioPciDevice { } // Reregister ioevents for notifies. - let parent_bus = self.base.parent_bus.upgrade().unwrap(); - let locked_parent_bus = parent_bus.lock().unwrap(); + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + PCI_BUS!(parent_bus, locked_bus, pci_bus); if let Err(e) = self.base.config.update_bar_mapping( #[cfg(target_arch = "x86_64")] - Some(&locked_parent_bus.io_region), - Some(&locked_parent_bus.mem_region), + Some(&pci_bus.io_region), + Some(&pci_bus.mem_region), ) { bail!("Failed to update bar, error is {:?}", e); } @@ -1643,10 +1641,11 @@ mod tests { ) .unwrap(); + let parent_bus = virtio_pci.parent_bus().unwrap(); init_intx( virtio_pci.name(), &mut virtio_pci.base.config, - virtio_pci.base.parent_bus.clone(), + parent_bus.clone(), virtio_pci.base.devfn, ) .unwrap(); @@ -1701,11 +1700,12 @@ mod tests { fn test_multifunction() { let (_, _parent_bus, mut virtio_pci) = virtio_pci_test_init(true); + let parent_bus = virtio_pci.parent_bus().unwrap(); assert!(init_multifunction( virtio_pci.multi_func, &mut virtio_pci.base.config.config, virtio_pci.base.devfn, - virtio_pci.base.parent_bus.clone() + parent_bus, ) .is_ok()); let header_type = -- Gitee From e61ae8f0b83696171d4584f9acea5fc2c56029c2 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Mon, 11 Dec 2023 20:48:39 +0800 Subject: [PATCH 196/489] devices/pcibus: pcibus deletes devices field `devices` field of struct `PciBus` has the same effect as the `children` field of struct `BusBase`. Delete it. Signed-off-by: liuxiangdong --- devices/src/misc/ivshmem.rs | 18 ++------ devices/src/misc/pvpanic.rs | 67 ++++++++++++---------------- devices/src/pci/bus.rs | 53 +++++++++++----------- devices/src/pci/demo_device/mod.rs | 29 +++++------- devices/src/pci/host.rs | 47 ++++++++++++------- devices/src/pci/hotplug.rs | 14 +++--- devices/src/pci/mod.rs | 53 +++++++++++++--------- devices/src/pci/root_port.rs | 66 +++++++++++++-------------- devices/src/usb/xhci/xhci_pci.rs | 16 ++----- machine/src/aarch64/pci_host_root.rs | 6 +-- machine/src/lib.rs | 23 +++++----- machine/src/x86_64/ich9_lpc.rs | 8 ++-- machine/src/x86_64/mch.rs | 6 +-- vfio/src/vfio_pci.rs | 21 +++------ virtio/src/transport/virtio_pci.rs | 16 ++----- 15 files changed, 202 insertions(+), 241 deletions(-) diff --git a/devices/src/misc/ivshmem.rs b/devices/src/misc/ivshmem.rs index 08212c44..ae91fcbb 100644 --- a/devices/src/misc/ivshmem.rs +++ b/devices/src/misc/ivshmem.rs @@ -15,14 +15,14 @@ use std::sync::{ Arc, Mutex, Weak, }; -use anyhow::{bail, Result}; +use anyhow::Result; use crate::pci::config::{ PciConfig, RegionType, DEVICE_ID, PCI_CLASS_MEMORY_RAM, PCI_CONFIG_SPACE_SIZE, PCI_VENDOR_ID_REDHAT_QUMRANET, REVISION_ID, SUB_CLASS_CODE, VENDOR_ID, }; use crate::pci::{le_write_u16, PciBus, PciDevBase, PciDevOps}; -use crate::{convert_bus_mut, convert_bus_ref, Device, DeviceBase, MUT_PCI_BUS, PCI_BUS}; +use crate::{convert_bus_ref, Device, DeviceBase, PCI_BUS}; use address_space::{GuestAddress, Region, RegionOps}; use util::gen_base_func; @@ -121,18 +121,8 @@ impl PciDevOps for Ivshmem { // Attach to the PCI bus. let bus = self.parent_bus().unwrap().upgrade().unwrap(); - MUT_PCI_BUS!(bus, locked_bus, pci_bus); - let pci_device = pci_bus.devices.get(&self.base.devfn); - match pci_device { - Some(device) => bail!( - "Devfn {:?} has been used by {:?}", - &self.base.devfn, - device.lock().unwrap().name() - ), - None => pci_bus - .devices - .insert(self.base.devfn, Arc::new(Mutex::new(self))), - }; + let mut locked_bus = bus.lock().unwrap(); + locked_bus.attach_child(self.base.devfn as u64, Arc::new(Mutex::new(self)))?; Ok(()) } diff --git a/devices/src/misc/pvpanic.rs b/devices/src/misc/pvpanic.rs index b1d483b3..eae09f88 100644 --- a/devices/src/misc/pvpanic.rs +++ b/devices/src/misc/pvpanic.rs @@ -222,16 +222,7 @@ impl PciDevOps for PvPanicPci { .unwrap() .dev_id .store(device_id, Ordering::Release); - let pci_device = pci_bus.devices.get(&devfn); - if pci_device.is_none() { - pci_bus.devices.insert(devfn, dev); - } else { - bail!( - "pvpanic: Devfn {:?} has been used by {:?}", - &devfn, - pci_device.unwrap().lock().unwrap().name() - ); - } + locked_bus.attach_child(devfn as u64, dev)?; Ok(()) } @@ -259,9 +250,17 @@ impl PciDevOps for PvPanicPci { mod tests { use super::*; use crate::pci::{host::tests::create_pci_host, le_read_u16, PciHost}; - use crate::Bus; + use crate::{convert_device_mut, Bus}; use machine_manager::config::str_slip_to_clap; + /// Convert from Arc> to &mut PvPanicPci. + #[macro_export] + macro_rules! MUT_PVPANIC_PCI { + ($trait_device:expr, $lock_device: ident, $struct_device: ident) => { + convert_device_mut!($trait_device, $lock_device, $struct_device, PvPanicPci); + }; + } + fn init_pvpanic_dev(devfn: u8, supported_features: u32, dev_id: &str) -> Arc> { let pci_host = create_pci_host(); let locked_pci_host = pci_host.lock().unwrap(); @@ -311,7 +310,7 @@ mod tests { let pvpanic_dev = root_bus.upgrade().unwrap().lock().unwrap().get_device(0, 7); assert!(pvpanic_dev.is_some()); assert_eq!( - pvpanic_dev.unwrap().lock().unwrap().pci_base().base.id, + pvpanic_dev.unwrap().lock().unwrap().name(), "pvpanic_test".to_string() ); @@ -335,40 +334,28 @@ mod tests { .unwrap() .get_device(0, 7) .unwrap(); - - let info = le_read_u16( - &pvpanic_dev.lock().unwrap().pci_base_mut().config.config, - VENDOR_ID as usize, - ) - .unwrap_or_else(|_| 0); + MUT_PVPANIC_PCI!(pvpanic_dev, locked_dev, pvpanic); + let info = le_read_u16(&pvpanic.pci_base_mut().config.config, VENDOR_ID as usize) + .unwrap_or_else(|_| 0); assert_eq!(info, PCI_VENDOR_ID_REDHAT); - let info = le_read_u16( - &pvpanic_dev.lock().unwrap().pci_base_mut().config.config, - DEVICE_ID as usize, - ) - .unwrap_or_else(|_| 0); + let info = le_read_u16(&pvpanic.pci_base_mut().config.config, DEVICE_ID as usize) + .unwrap_or_else(|_| 0); assert_eq!(info, PCI_DEVICE_ID_REDHAT_PVPANIC); let info = le_read_u16( - &pvpanic_dev.lock().unwrap().pci_base_mut().config.config, + &pvpanic.pci_base_mut().config.config, SUB_CLASS_CODE as usize, ) .unwrap_or_else(|_| 0); assert_eq!(info, PCI_CLASS_SYSTEM_OTHER); - let info = le_read_u16( - &pvpanic_dev.lock().unwrap().pci_base_mut().config.config, - SUBSYSTEM_VENDOR_ID, - ) - .unwrap_or_else(|_| 0); + let info = le_read_u16(&pvpanic.pci_base_mut().config.config, SUBSYSTEM_VENDOR_ID) + .unwrap_or_else(|_| 0); assert_eq!(info, PVPANIC_PCI_VENDOR_ID); - let info = le_read_u16( - &pvpanic_dev.lock().unwrap().pci_base_mut().config.config, - SUBSYSTEM_ID, - ) - .unwrap_or_else(|_| 0); + let info = + le_read_u16(&pvpanic.pci_base_mut().config.config, SUBSYSTEM_ID).unwrap_or_else(|_| 0); assert_eq!(info, PCI_SUBDEVICE_ID_QEMU); } @@ -385,10 +372,11 @@ mod tests { .unwrap() .get_device(0, 7) .unwrap(); + MUT_PVPANIC_PCI!(pvpanic_dev, locked_dev, pvpanic); // test read supported_features let mut data_read = [0xffu8; 1]; - let result = &pvpanic_dev.lock().unwrap().pci_base_mut().config.bars[0] + let result = &pvpanic.pci_base_mut().config.bars[0] .region .as_ref() .unwrap() @@ -413,11 +401,12 @@ mod tests { .unwrap() .get_device(0, 7) .unwrap(); + MUT_PVPANIC_PCI!(pvpanic_dev, locked_dev, pvpanic); // test write panicked event let data_write = [PVPANIC_PANICKED as u8; 1]; let count = data_write.len() as u64; - let result = &pvpanic_dev.lock().unwrap().pci_base_mut().config.bars[0] + let result = &pvpanic.pci_base_mut().config.bars[0] .region .as_ref() .unwrap() @@ -438,11 +427,12 @@ mod tests { .unwrap() .get_device(0, 7) .unwrap(); + MUT_PVPANIC_PCI!(pvpanic_dev, locked_dev, pvpanic); // test write crashload event let data_write = [PVPANIC_CRASHLOADED as u8; 1]; let count = data_write.len() as u64; - let result = &pvpanic_dev.lock().unwrap().pci_base_mut().config.bars[0] + let result = &pvpanic.pci_base_mut().config.bars[0] .region .as_ref() .unwrap() @@ -463,11 +453,12 @@ mod tests { .unwrap() .get_device(0, 7) .unwrap(); + MUT_PVPANIC_PCI!(pvpanic_dev, locked_dev, pvpanic); // test write unknown event let data_write = [100u8; 1]; let count = data_write.len() as u64; - let result = &pvpanic_dev.lock().unwrap().pci_base_mut().config.bars[0] + let result = &pvpanic.pci_base_mut().config.bars[0] .region .as_ref() .unwrap() diff --git a/devices/src/pci/bus.rs b/devices/src/pci/bus.rs index 631f1be5..6e03f1a1 100644 --- a/devices/src/pci/bus.rs +++ b/devices/src/pci/bus.rs @@ -10,11 +10,10 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use std::collections::HashMap; use std::sync::atomic::{AtomicU16, Ordering}; use std::sync::{Arc, Mutex, Weak}; -use anyhow::{bail, Context, Result}; +use anyhow::{Context, Result}; use log::debug; use super::{ @@ -22,20 +21,19 @@ use super::{ hotplug::HotplugOps, PciDevOps, PciIntxState, }; -use crate::pci::RootPort; +use crate::pci::{to_pcidevops, RootPort}; use crate::{ - convert_device_mut, convert_device_ref, Bus, BusBase, MsiIrqManager, MUT_ROOT_PORT, ROOT_PORT, + convert_device_mut, convert_device_ref, Bus, BusBase, Device, MsiIrqManager, MUT_ROOT_PORT, + PCI_BUS_DEVICE, ROOT_PORT, }; use address_space::Region; use util::gen_base_func; -type DeviceBusInfo = (Arc>, Arc>); +type DeviceBusInfo = (Arc>, Arc>); /// PCI bus structure. pub struct PciBus { pub base: BusBase, - /// Devices attached to the bus. - pub devices: HashMap>>, /// Child buses of the bus. pub child_buses: Vec>>, /// IO region which the parent bridge manages. @@ -85,7 +83,6 @@ impl PciBus { ) -> Self { Self { base: BusBase::new(name), - devices: HashMap::new(), child_buses: Vec::new(), #[cfg(target_arch = "x86_64")] io_region, @@ -115,9 +112,9 @@ impl PciBus { /// /// * `bus_num` - The bus number. /// * `devfn` - Slot number << 3 | Function number. - pub fn get_device(&self, bus_num: u8, devfn: u8) -> Option>> { - if let Some(dev) = self.devices.get(&devfn) { - return Some((*dev).clone()); + pub fn get_device(&self, bus_num: u8, devfn: u8) -> Option>> { + if let Some(dev) = self.child_dev(devfn as u64) { + return Some(dev.clone()); } debug!("Can't find device {}:{}", bus_num, devfn); None @@ -185,7 +182,7 @@ impl PciBus { pub fn find_attached_bus(pci_bus: &Arc>, name: &str) -> Option { // Device is attached in pci_bus. let locked_bus = pci_bus.lock().unwrap(); - for dev in locked_bus.devices.values() { + for dev in locked_bus.child_devices().values() { if dev.lock().unwrap().name() == name { return Some((pci_bus.clone(), dev.clone())); } @@ -205,30 +202,27 @@ impl PciBus { /// /// * `bus` - Bus to detach from. /// * `dev` - Device attached to the bus. - pub fn detach_device(bus: &Arc>, dev: &Arc>) -> Result<()> { - let mut dev_locked = dev.lock().unwrap(); - dev_locked + pub fn detach_device(bus: &Arc>, dev: &Arc>) -> Result<()> { + PCI_BUS_DEVICE!(dev, locked_dev, pci_dev); + pci_dev .unrealize() - .with_context(|| format!("Failed to unrealize device {}", dev_locked.name()))?; + .with_context(|| format!("Failed to unrealize device {}", pci_dev.name()))?; - let devfn = dev_locked.pci_base().devfn; + let devfn = pci_dev.pci_base().devfn as u64; let mut locked_bus = bus.lock().unwrap(); - if locked_bus.devices.get(&devfn).is_some() { - locked_bus.devices.remove(&devfn); - } else { - bail!("Device {} not found in the bus", dev_locked.name()); - } + locked_bus + .detach_child(devfn) + .with_context(|| format!("Device {} not found in the bus", pci_dev.name()))?; Ok(()) } pub fn reset(&mut self) -> Result<()> { - for (_id, pci_dev) in self.devices.iter() { + for dev in self.child_devices().values() { + PCI_BUS_DEVICE!(dev, locked_dev, pci_dev); pci_dev - .lock() - .unwrap() .reset(false) - .with_context(|| "Fail to reset pci dev")?; + .with_context(|| format!("Fail to reset pci dev {}", pci_dev.name()))?; } for child_bus in self.child_buses.iter_mut() { @@ -287,6 +281,7 @@ mod tests { use crate::pci::host::tests::create_pci_host; use crate::pci::root_port::{RootPort, RootPortConfig}; use crate::pci::tests::TestPciDevice; + use crate::pci::{clean_pcidevops_type, register_pcidevops_type}; #[test] fn test_find_attached_bus() { @@ -328,6 +323,8 @@ mod tests { #[test] fn test_detach_device() { + register_pcidevops_type::().unwrap(); + let pci_host = create_pci_host(); let locked_pci_host = pci_host.lock().unwrap(); let root_bus = Arc::downgrade(&locked_pci_host.root_bus); @@ -342,7 +339,7 @@ mod tests { let bus = PciBus::find_bus_by_name(&locked_pci_host.root_bus, "pcie.1").unwrap(); let pci_dev = TestPciDevice::new("test1", 0, Arc::downgrade(&bus)); - let dev_ops: Arc> = Arc::new(Mutex::new(pci_dev.clone())); + let dev_ops: Arc> = Arc::new(Mutex::new(pci_dev.clone())); pci_dev.realize().unwrap(); let info = PciBus::find_attached_bus(&locked_pci_host.root_bus, "test1"); @@ -353,5 +350,7 @@ mod tests { let info = PciBus::find_attached_bus(&locked_pci_host.root_bus, "test1"); assert!(info.is_none()); + + clean_pcidevops_type(); } } diff --git a/devices/src/pci/demo_device/mod.rs b/devices/src/pci/demo_device/mod.rs index 37dc6b73..483bfbab 100644 --- a/devices/src/pci/demo_device/mod.rs +++ b/devices/src/pci/demo_device/mod.rs @@ -41,22 +41,20 @@ use std::{ }, }; -use anyhow::{bail, Result}; +use anyhow::Result; use clap::Parser; use log::error; -use crate::pci::demo_device::{ - dpy_device::DemoDisplay, gpu_device::DemoGpu, kbd_pointer_device::DemoKbdMouse, +use crate::pci::config::{ + PciConfig, RegionType, DEVICE_ID, HEADER_TYPE, HEADER_TYPE_ENDPOINT, PCIE_CONFIG_SPACE_SIZE, + SUB_CLASS_CODE, VENDOR_ID, }; -use crate::pci::{ - config::{ - PciConfig, RegionType, DEVICE_ID, HEADER_TYPE, HEADER_TYPE_ENDPOINT, - PCIE_CONFIG_SPACE_SIZE, SUB_CLASS_CODE, VENDOR_ID, - }, - init_msix, le_write_u16, PciBus, PciDevOps, +use crate::pci::demo_device::{ + base_device::BaseDevice, dpy_device::DemoDisplay, gpu_device::DemoGpu, + kbd_pointer_device::DemoKbdMouse, }; -use crate::pci::{demo_device::base_device::BaseDevice, PciDevBase}; -use crate::{convert_bus_mut, convert_bus_ref, Device, DeviceBase, MUT_PCI_BUS, PCI_BUS}; +use crate::pci::{init_msix, le_write_u16, PciBus, PciDevBase, PciDevOps}; +use crate::{convert_bus_ref, Device, DeviceBase, PCI_BUS}; use address_space::{AddressSpace, GuestAddress, Region, RegionOps}; use machine_manager::config::{get_pci_df, valid_id}; use util::gen_base_func; @@ -134,14 +132,11 @@ impl DemoDev { } fn attach_to_parent_bus(self) -> Result<()> { + let devfn = self.base.devfn as u64; let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); - MUT_PCI_BUS!(parent_bus, locked_bus, pci_bus); - if pci_bus.devices.get(&self.base.devfn).is_some() { - bail!("device already existed"); - } - let devfn = self.base.devfn; + let mut locked_bus = parent_bus.lock().unwrap(); let demo_pci_dev = Arc::new(Mutex::new(self)); - pci_bus.devices.insert(devfn, demo_pci_dev); + locked_bus.attach_child(devfn, demo_pci_dev)?; Ok(()) } diff --git a/devices/src/pci/host.rs b/devices/src/pci/host.rs index 1af69682..4d45a4f4 100644 --- a/devices/src/pci/host.rs +++ b/devices/src/pci/host.rs @@ -16,11 +16,11 @@ use anyhow::{Context, Result}; #[cfg(target_arch = "aarch64")] use crate::pci::PCI_INTR_BASE; -use crate::pci::{bus::PciBus, PciDevOps, PCI_PIN_NUM, PCI_SLOT_MAX}; +use crate::pci::{bus::PciBus, to_pcidevops, PCI_PIN_NUM, PCI_SLOT_MAX}; #[cfg(target_arch = "x86_64")] use crate::pci::{le_read_u32, le_write_u32}; use crate::sysbus::{SysBusDevBase, SysBusDevOps}; -use crate::{Device, DeviceBase}; +use crate::{Bus, Device, DeviceBase, PCI_BUS_DEVICE}; use acpi::{ AmlActiveLevel, AmlAddressSpaceDecode, AmlAnd, AmlArg, AmlBuilder, AmlCacheable, AmlCreateDWordField, AmlDWord, AmlDWordDesc, AmlDevice, AmlEdgeLevel, AmlEisaId, AmlElse, @@ -111,14 +111,16 @@ impl PciHost { } } - pub fn find_device(&self, bus_num: u8, devfn: u8) -> Option>> { + pub fn find_device(&self, bus_num: u8, devfn: u8) -> Option>> { let locked_root_bus = self.root_bus.lock().unwrap(); if bus_num == 0 { - return locked_root_bus.get_device(0, devfn); + let dev = locked_root_bus.child_dev(devfn as u64)?; + return Some(dev.clone()); } for bus in &locked_root_bus.child_buses { if let Some(b) = PciBus::find_bus_by_num(bus, bus_num) { - return b.lock().unwrap().get_device(bus_num, devfn); + let dev = b.lock().unwrap().child_dev(devfn as u64)?.clone(); + return Some(dev); } } None @@ -197,7 +199,8 @@ impl PciHost { match locked_hb.find_device(bus_num, devfn) { Some(dev) => { offset &= PIO_OFFSET_MASK; - dev.lock().unwrap().read_config(offset as usize, data); + PCI_BUS_DEVICE!(dev, locked_dev, pci_dev); + pci_dev.read_config(offset as usize, data); } None => { for d in data.iter_mut() { @@ -219,7 +222,8 @@ impl PciHost { let devfn = ((offset >> PIO_DEVFN_SHIFT) & CONFIG_DEVFN_MASK) as u8; if let Some(dev) = locked_hb.find_device(bus_num, devfn) { offset &= PIO_OFFSET_MASK; - dev.lock().unwrap().write_config(offset as usize, data); + PCI_BUS_DEVICE!(dev, locked_dev, pci_dev); + pci_dev.write_config(offset as usize, data); } true }; @@ -244,9 +248,9 @@ impl SysBusDevOps for PciHost { match self.find_device(bus_num, devfn) { Some(dev) => { let addr: usize = (offset & ECAM_OFFSET_MASK) as usize; - let dev_name = &dev.lock().unwrap().pci_base().base.id.clone(); - trace::pci_read_config(dev_name, addr, data); - dev.lock().unwrap().read_config(addr, data); + PCI_BUS_DEVICE!(dev, locked_dev, pci_dev); + trace::pci_read_config(&pci_dev.name(), addr, data); + pci_dev.read_config(addr, data); } None => { for d in data.iter_mut() { @@ -263,9 +267,9 @@ impl SysBusDevOps for PciHost { match self.find_device(bus_num, devfn) { Some(dev) => { let addr: usize = (offset & ECAM_OFFSET_MASK) as usize; - let dev_name = &dev.lock().unwrap().pci_base().base.id.clone(); - trace::pci_write_config(dev_name, addr, data); - dev.lock().unwrap().write_config(addr, data); + PCI_BUS_DEVICE!(dev, locked_dev, pci_dev); + trace::pci_write_config(&pci_dev.name(), addr, data); + pci_dev.write_config(addr, data); true } None => true, @@ -273,10 +277,9 @@ impl SysBusDevOps for PciHost { } fn reset(&mut self) -> Result<()> { - for (_id, pci_dev) in self.root_bus.lock().unwrap().devices.iter_mut() { + for dev in self.root_bus.lock().unwrap().child_devices().values() { + PCI_BUS_DEVICE!(dev, locked_dev, pci_dev); pci_dev - .lock() - .unwrap() .reset(true) .with_context(|| "Fail to reset pci device under pci host")?; } @@ -531,6 +534,7 @@ impl AmlBuilder for PciHost { #[cfg(test)] pub mod tests { + #[cfg(target_arch = "x86_64")] use byteorder::{ByteOrder, LittleEndian}; use super::*; @@ -538,6 +542,7 @@ pub mod tests { use crate::pci::config::SECONDARY_BUS_NUM; use crate::pci::root_port::{RootPort, RootPortConfig}; use crate::pci::tests::TestPciDevice; + use crate::pci::{clean_pcidevops_type, register_pcidevops_type, PciDevOps}; use address_space::Region; pub fn create_pci_host() -> Arc> { @@ -571,6 +576,8 @@ pub mod tests { #[test] #[cfg(target_arch = "x86_64")] fn test_pio_ops() { + register_pcidevops_type::().unwrap(); + let pci_host = create_pci_host(); let root_bus = Arc::downgrade(&pci_host.lock().unwrap().root_bus); let pio_addr_ops = PciHost::build_pio_addr_ops(pci_host.clone()); @@ -597,7 +604,6 @@ pub mod tests { assert_eq!(buf, data); // Non-DWORD access on CONFIG_ADDR - let mut config = [0_u8; 4]; (pio_addr_ops.read)(&mut config, GuestAddress(0), 0); let data = [0x12, 0x34]; @@ -649,10 +655,15 @@ pub mod tests { let mut buf = [0_u8; 4]; (pio_data_ops.read)(&mut buf, GuestAddress(0), 0); assert_eq!(buf, [0xff_u8; 4]); + + clean_pcidevops_type(); } #[test] fn test_mmio_ops() { + register_pcidevops_type::().unwrap(); + register_pcidevops_type::().unwrap(); + let pci_host = create_pci_host(); let root_bus = Arc::downgrade(&pci_host.lock().unwrap().root_bus); let mmconfig_region_ops = PciHost::build_mmconfig_ops(pci_host.clone()); @@ -703,5 +714,7 @@ pub mod tests { let mut buf = [0_u8; 2]; (mmconfig_region_ops.read)(&mut buf, GuestAddress(0), addr); assert_eq!(buf, data); + + clean_pcidevops_type(); } } diff --git a/devices/src/pci/hotplug.rs b/devices/src/pci/hotplug.rs index 24533a24..862956be 100644 --- a/devices/src/pci/hotplug.rs +++ b/devices/src/pci/hotplug.rs @@ -14,19 +14,19 @@ use std::sync::{Arc, Mutex}; use anyhow::{bail, Context, Result}; -use crate::pci::{PciBus, PciDevOps}; -use crate::Bus; +use crate::pci::PciBus; +use crate::{Bus, Device}; pub trait HotplugOps: Send { /// Plug device, usually called when hot plug device in device_add. - fn plug(&mut self, dev: &Arc>) -> Result<()>; + fn plug(&mut self, dev: &Arc>) -> Result<()>; /// Unplug device request, usually called when hot unplug device in device_del. /// Only send unplug request to the guest OS, without actually removing the device. - fn unplug_request(&mut self, dev: &Arc>) -> Result<()>; + fn unplug_request(&mut self, dev: &Arc>) -> Result<()>; /// Remove the device. - fn unplug(&mut self, dev: &Arc>) -> Result<()>; + fn unplug(&mut self, dev: &Arc>) -> Result<()>; } /// Plug the device into the bus. @@ -41,7 +41,7 @@ pub trait HotplugOps: Send { /// Return Error if /// * No hot plug controller found. /// * Device plug failed. -pub fn handle_plug(bus: &Arc>, dev: &Arc>) -> Result<()> { +pub fn handle_plug(bus: &Arc>, dev: &Arc>) -> Result<()> { let locked_bus = bus.lock().unwrap(); if let Some(hpc) = locked_bus.hotplug_controller.as_ref() { hpc.upgrade().unwrap().lock().unwrap().plug(dev) @@ -67,7 +67,7 @@ pub fn handle_plug(bus: &Arc>, dev: &Arc>) -> /// * Device unplug request failed. pub fn handle_unplug_pci_request( bus: &Arc>, - dev: &Arc>, + dev: &Arc>, ) -> Result<()> { let locked_bus = bus.lock().unwrap(); let hpc = locked_bus diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs index e3da00e3..b7faa792 100644 --- a/devices/src/pci/mod.rs +++ b/devices/src/pci/mod.rs @@ -266,15 +266,15 @@ pub trait PciDevOps: Device + Send { } } -pub type ToPciDevOpsFunc = fn(&dyn Any) -> &dyn PciDevOps; +pub type ToPciDevOpsFunc = fn(&mut dyn Any) -> &mut dyn PciDevOps; static mut PCIDEVOPS_HASHMAP: Option> = None; -pub fn convert_to_pcidevops(item: &dyn Any) -> &dyn PciDevOps { +pub fn convert_to_pcidevops(item: &mut dyn Any) -> &mut dyn PciDevOps { // SAFETY: The typeid of `T` is the typeid recorded in the hashmap. The target structure type of // the conversion is its own structure type, so the conversion result will definitely not be `None`. - let t = item.downcast_ref::().unwrap(); - t as &dyn PciDevOps + let t = item.downcast_mut::().unwrap(); + t as &mut dyn PciDevOps } pub fn register_pcidevops_type() -> Result<()> { @@ -306,17 +306,32 @@ pub fn devices_register_pcidevops_type() -> Result<()> { register_pcidevops_type::() } -pub fn to_pcidevops(dev: &dyn Device) -> Option<&dyn PciDevOps> { - let type_id = dev.type_id(); +#[cfg(test)] +pub fn clean_pcidevops_type() { + unsafe { + PCIDEVOPS_HASHMAP = None; + } +} + +pub fn to_pcidevops(dev: &mut dyn Device) -> Option<&mut dyn PciDevOps> { // SAFETY: PCIDEVOPS_HASHMAP has been built. And this function is called without changing hashmap. unsafe { let types = PCIDEVOPS_HASHMAP.as_mut().unwrap(); - let func = types.get(&type_id)?; - let pcidev = func(dev.as_any()); + let func = types.get(&dev.device_type_id())?; + let pcidev = func(dev.as_any_mut()); Some(pcidev) } } +/// Convert from Arc> to &mut dyn PciDevOps. +#[macro_export] +macro_rules! PCI_BUS_DEVICE { + ($trait_device:expr, $lock_device: ident, $trait_pcidevops: ident) => { + let mut $lock_device = $trait_device.lock().unwrap(); + let $trait_pcidevops = to_pcidevops(&mut *$lock_device).unwrap(); + }; +} + /// Init multifunction for pci devices. /// /// # Arguments @@ -346,22 +361,19 @@ pub fn init_multifunction( let bus = parent_bus.upgrade().unwrap(); PCI_BUS!(bus, locked_bus, pci_bus); if pci_func(devfn) != 0 { - let pci_dev = pci_bus.devices.get(&pci_devfn(slot, 0)); - if pci_dev.is_none() { + let dev = pci_bus.child_dev(pci_devfn(slot, 0) as u64); + if dev.is_none() { return Ok(()); } let mut data = vec![0_u8; 2]; - pci_dev - .unwrap() - .lock() - .unwrap() - .read_config(HEADER_TYPE as usize, data.as_mut_slice()); + PCI_BUS_DEVICE!(dev.unwrap(), locked_dev, pci_dev); + pci_dev.read_config(HEADER_TYPE as usize, data.as_mut_slice()); if LittleEndian::read_u16(&data) & HEADER_TYPE_MULTIFUNC as u16 == 0 { // Function 0 should set multifunction bit. bail!( "PCI: single function device can't be populated in bus {} function {}.{}", - &locked_bus.name(), + &pci_bus.name(), slot, devfn & 0x07 ); @@ -375,7 +387,7 @@ pub fn init_multifunction( // If function 0 is set to single function, the rest function should be None. for func in 1..MAX_FUNC { - if pci_bus.devices.get(&pci_devfn(slot, func)).is_some() { + if pci_bus.child_dev(pci_devfn(slot, func) as u64).is_some() { bail!( "PCI: {}.0 indicates single function, but {}.{} is already populated", slot, @@ -398,7 +410,7 @@ pub fn swizzle_map_irq(devfn: u8, pin: u8) -> u32 { mod tests { use super::*; use crate::pci::config::{PciConfig, PCI_CONFIG_SPACE_SIZE}; - use crate::{convert_bus_mut, DeviceBase, MUT_PCI_BUS}; + use crate::DeviceBase; use address_space::{AddressSpace, Region}; use util::gen_base_func; @@ -438,14 +450,13 @@ mod tests { } fn realize(mut self) -> Result<()> { - let devfn = self.base.devfn; + let devfn = self.base.devfn as u64; self.init_write_mask(false)?; self.init_write_clear_mask(false)?; let dev = Arc::new(Mutex::new(self)); let parent_bus = dev.lock().unwrap().parent_bus().unwrap().upgrade().unwrap(); - MUT_PCI_BUS!(parent_bus, locked_bus, pci_bus); - pci_bus.devices.insert(devfn, dev.clone()); + parent_bus.lock().unwrap().attach_child(devfn, dev)?; Ok(()) } diff --git a/devices/src/pci/root_port.rs b/devices/src/pci/root_port.rs index cf05c4b6..ea6b43b1 100644 --- a/devices/src/pci/root_port.rs +++ b/devices/src/pci/root_port.rs @@ -34,12 +34,13 @@ use crate::pci::config::{BRIDGE_CONTROL, BRIDGE_CTL_SEC_BUS_RESET}; use crate::pci::hotplug::HotplugOps; use crate::pci::intx::init_intx; use crate::pci::msix::init_msix; -use crate::pci::{init_multifunction, PciDevBase, PciError, PciIntxState, INTERRUPT_PIN}; use crate::pci::{ - le_read_u16, le_write_clear_value_u16, le_write_set_value_u16, le_write_u16, PciDevOps, + init_multifunction, le_read_u16, le_write_clear_value_u16, le_write_set_value_u16, + le_write_u16, to_pcidevops, PciDevBase, PciDevOps, PciError, PciIntxState, INTERRUPT_PIN, }; use crate::{ - convert_bus_mut, convert_bus_ref, Device, DeviceBase, MsiIrqManager, MUT_PCI_BUS, PCI_BUS, + convert_bus_mut, convert_bus_ref, Bus, Device, DeviceBase, MsiIrqManager, MUT_PCI_BUS, PCI_BUS, + PCI_BUS_DEVICE, }; use address_space::Region; use machine_manager::config::{get_pci_df, parse_bool, valid_id}; @@ -221,10 +222,10 @@ impl RootPort { // Store device in a temp vector and unlock the bus. // If the device unrealize called when the bus is locked, a deadlock occurs. // This is because the device unrealize also requires the bus lock. - let devices = self.sec_bus.lock().unwrap().devices.clone(); + let devices = self.sec_bus.lock().unwrap().child_devices().clone(); for dev in devices.values() { - let mut locked_dev = dev.lock().unwrap(); - if let Err(e) = locked_dev.unrealize() { + PCI_BUS_DEVICE!(dev, locked_dev, pci_dev); + if let Err(e) = pci_dev.unrealize() { error!("{}", format!("{:?}", e)); error!("Failed to unrealize device {}.", locked_dev.name()); } @@ -233,7 +234,7 @@ impl RootPort { // Send QMP event for successful hot unplugging. send_device_deleted_msg(&locked_dev.name()); } - self.sec_bus.lock().unwrap().devices.clear(); + self.sec_bus.lock().unwrap().bus_base_mut().children.clear(); } fn register_region(&mut self) { @@ -417,12 +418,10 @@ impl PciDevOps for RootPort { Some(Arc::downgrade(&root_port) as Weak>); locked_root_port.sec_bus.lock().unwrap().hotplug_controller = Some(Arc::downgrade(&root_port) as Weak>); - let pci_device = pci_bus.devices.get(&locked_root_port.base.devfn); + let pci_device = pci_bus.child_dev(locked_root_port.base.devfn as u64); if pci_device.is_none() { pci_bus.child_buses.push(locked_root_port.sec_bus.clone()); - pci_bus - .devices - .insert(locked_root_port.base.devfn, root_port.clone()); + pci_bus.attach_child(locked_root_port.base.devfn as u64, root_port.clone())?; } else { bail!( "Devfn {:?} has been used by {:?}", @@ -568,11 +567,13 @@ impl PciDevOps for RootPort { } impl HotplugOps for RootPort { - fn plug(&mut self, dev: &Arc>) -> Result<()> { + fn plug(&mut self, dev: &Arc>) -> Result<()> { if !dev.lock().unwrap().hotpluggable() { bail!("Don't support hot-plug!"); } - let devfn = dev.lock().unwrap().pci_base().devfn; + PCI_BUS_DEVICE!(dev, locked_dev, pci_dev); + let devfn = pci_dev.pci_base().devfn; + drop(locked_dev); // Only if devfn is equal to 0, hot plugging is supported. if devfn != 0 { return Err(anyhow!(PciError::HotplugUnsupported(devfn))); @@ -594,7 +595,7 @@ impl HotplugOps for RootPort { Ok(()) } - fn unplug_request(&mut self, dev: &Arc>) -> Result<()> { + fn unplug_request(&mut self, dev: &Arc>) -> Result<()> { let pcie_cap_offset = self.base.config.pci_express_cap_offset; let sltctl = le_read_u16( &self.base.config.config, @@ -609,7 +610,9 @@ impl HotplugOps for RootPort { if !dev.lock().unwrap().hotpluggable() { bail!("Don't support hot-unplug request!"); } - let devfn = dev.lock().unwrap().pci_base().devfn; + PCI_BUS_DEVICE!(dev, locked_dev, pci_dev); + let devfn = pci_dev.pci_base().devfn; + drop(locked_dev); if devfn != 0 { return self.unplug(dev); } @@ -647,14 +650,14 @@ impl HotplugOps for RootPort { Ok(()) } - fn unplug(&mut self, dev: &Arc>) -> Result<()> { + fn unplug(&mut self, dev: &Arc>) -> Result<()> { if !dev.lock().unwrap().hotpluggable() { bail!("Don't support hot-unplug!"); } - let devfn = dev.lock().unwrap().pci_base().devfn; - let mut locked_dev = dev.lock().unwrap(); - locked_dev.unrealize()?; - self.sec_bus.lock().unwrap().devices.remove(&devfn); + PCI_BUS_DEVICE!(dev, locked_dev, pci_dev); + let devfn = pci_dev.pci_base().devfn as u64; + pci_dev.unrealize()?; + self.sec_bus.lock().unwrap().detach_child(devfn)?; Ok(()) } } @@ -700,7 +703,7 @@ impl MigrationHook for RootPort {} #[cfg(test)] mod tests { use super::*; - use crate::pci::host::tests::create_pci_host; + use crate::{convert_device_mut, pci::host::tests::create_pci_host, MUT_ROOT_PORT}; #[test] fn test_read_config() { @@ -714,12 +717,10 @@ mod tests { let root_port = RootPort::new(root_port_config, root_bus.clone()); root_port.realize().unwrap(); - let root_port = pci_host.lock().unwrap().find_device(0, 8).unwrap(); + let dev = pci_host.lock().unwrap().find_device(0, 8).unwrap(); let mut buf = [1_u8; 4]; - root_port - .lock() - .unwrap() - .read_config(PCIE_CONFIG_SPACE_SIZE - 1, &mut buf); + MUT_ROOT_PORT!(dev, locked_dev, root_port); + root_port.read_config(PCIE_CONFIG_SPACE_SIZE - 1, &mut buf); assert_eq!(buf, [1_u8; 4]); } @@ -734,19 +735,14 @@ mod tests { }; let root_port = RootPort::new(root_port_config, root_bus.clone()); root_port.realize().unwrap(); - let root_port = pci_host.lock().unwrap().find_device(0, 8).unwrap(); + let dev = pci_host.lock().unwrap().find_device(0, 8).unwrap(); + MUT_ROOT_PORT!(dev, locked_dev, root_port); // Invalid write. let data = [1_u8; 4]; - root_port - .lock() - .unwrap() - .write_config(PCIE_CONFIG_SPACE_SIZE - 1, &data); + root_port.write_config(PCIE_CONFIG_SPACE_SIZE - 1, &data); let mut buf = [0_u8]; - root_port - .lock() - .unwrap() - .read_config(PCIE_CONFIG_SPACE_SIZE - 1, &mut buf); + root_port.read_config(PCIE_CONFIG_SPACE_SIZE - 1, &mut buf); assert_eq!(buf, [0_u8]); } } diff --git a/devices/src/usb/xhci/xhci_pci.rs b/devices/src/usb/xhci/xhci_pci.rs index 7b966bd7..e8b2e646 100644 --- a/devices/src/usb/xhci/xhci_pci.rs +++ b/devices/src/usb/xhci/xhci_pci.rs @@ -34,7 +34,7 @@ use crate::pci::config::{ }; use crate::pci::{init_intx, init_msix, le_write_u16, PciBus, PciDevBase, PciDevOps}; use crate::usb::UsbDevice; -use crate::{convert_bus_mut, convert_bus_ref, Device, DeviceBase, MUT_PCI_BUS, PCI_BUS}; +use crate::{convert_bus_ref, Device, DeviceBase, PCI_BUS}; use address_space::{AddressRange, AddressSpace, Region, RegionIoEventFd}; use machine_manager::config::{get_pci_df, valid_id}; use machine_manager::event_loop::register_event_helper; @@ -314,7 +314,7 @@ impl PciDevOps for XhciPciDevice { mem_region_size, )?; - let devfn = self.base.devfn; + let devfn = self.base.devfn as u64; // It is safe to unwrap, because it is initialized in init_msix. let cloned_msix = self.base.config.msix.as_ref().unwrap().clone(); let cloned_intx = self.base.config.intx.as_ref().unwrap().clone(); @@ -338,17 +338,7 @@ impl PciDevOps for XhciPciDevice { let dev = Arc::new(Mutex::new(self)); // Attach to the PCI bus. let bus = dev.lock().unwrap().parent_bus().unwrap().upgrade().unwrap(); - MUT_PCI_BUS!(bus, locked_bus, pci_bus); - let pci_device = pci_bus.devices.get(&devfn); - if pci_device.is_none() { - pci_bus.devices.insert(devfn, dev); - } else { - bail!( - "Devfn {:?} has been used by {:?}", - &devfn, - pci_device.unwrap().lock().unwrap().name() - ); - } + bus.lock().unwrap().attach_child(devfn, dev)?; Ok(()) } diff --git a/machine/src/aarch64/pci_host_root.rs b/machine/src/aarch64/pci_host_root.rs index a984ec70..ec50c954 100644 --- a/machine/src/aarch64/pci_host_root.rs +++ b/machine/src/aarch64/pci_host_root.rs @@ -19,7 +19,7 @@ use devices::pci::config::{ REVISION_ID, SUB_CLASS_CODE, VENDOR_ID, }; use devices::pci::{le_write_u16, PciBus, PciDevBase, PciDevOps}; -use devices::{convert_bus_mut, Device, DeviceBase, MUT_PCI_BUS}; +use devices::{Device, DeviceBase}; use util::gen_base_func; const DEVICE_ID_PCIE_HOST: u16 = 0x0008; @@ -70,8 +70,8 @@ impl PciDevOps for PciHostRoot { le_write_u16(&mut self.base.config.config, REVISION_ID, 0)?; let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); - MUT_PCI_BUS!(parent_bus, locked_bus, pci_bus); - pci_bus.devices.insert(0, Arc::new(Mutex::new(self))); + let mut locked_bus = parent_bus.lock().unwrap(); + locked_bus.attach_child(0, Arc::new(Mutex::new(self)))?; Ok(()) } diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 2f301863..fcc9f8c6 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -55,8 +55,8 @@ use devices::misc::scream::{Scream, ScreamConfig}; #[cfg(feature = "demo_device")] use devices::pci::demo_device::{DemoDev, DemoDevConfig}; use devices::pci::{ - devices_register_pcidevops_type, register_pcidevops_type, PciBus, PciDevOps, PciHost, RootPort, - RootPortConfig, + devices_register_pcidevops_type, register_pcidevops_type, to_pcidevops, PciBus, PciDevOps, + PciHost, RootPort, RootPortConfig, }; use devices::smbios::smbios_table::{build_smbios_ep30, SmbiosTable}; use devices::smbios::{SMBIOS_ANCHOR_FILE, SMBIOS_TABLE_FILE}; @@ -77,7 +77,7 @@ use devices::usb::UsbDevice; use devices::InterruptController; use devices::ScsiBus::get_scsi_key; use devices::ScsiDisk::{ScsiDevConfig, ScsiDevice}; -use devices::{Bus, Device, SYS_BUS_DEVICE}; +use devices::{Bus, Device, PCI_BUS_DEVICE, SYS_BUS_DEVICE}; use hypervisor::{kvm::KvmHypervisor, test::TestHypervisor, HypervisorOps}; #[cfg(feature = "usb_camera")] use machine_manager::config::get_cameradev_by_id; @@ -1209,11 +1209,11 @@ pub trait MachineOps: MachineLifecycle { .get_pci_dev_by_id_and_type(vm_config, Some(&cntlr), "virtio-scsi-pci") .with_context(|| format!("Can not find scsi controller from pci bus {}", cntlr))?; let locked_pcidev = pci_dev.lock().unwrap(); - let prefix = locked_pcidev.get_dev_path().unwrap(); let virtio_pcidev = locked_pcidev .as_any() .downcast_ref::() .unwrap(); + let prefix = virtio_pcidev.get_dev_path().unwrap(); let virtio_device = virtio_pcidev.get_virtio_device().lock().unwrap(); let cntlr = virtio_device.as_any().downcast_ref::().unwrap(); let bus = cntlr.bus.as_ref().unwrap(); @@ -1521,7 +1521,7 @@ pub trait MachineOps: MachineLifecycle { drop(locked_dev); let mut devfn = None; let locked_bus = locked_pci_host.root_bus.lock().unwrap(); - for (id, dev) in &locked_bus.devices { + for (id, dev) in &locked_bus.child_devices() { if dev.lock().unwrap().name() == name { devfn = Some(*id); break; @@ -1529,12 +1529,11 @@ pub trait MachineOps: MachineLifecycle { } drop(locked_bus); // It's safe to call devfn.unwrap(), because the bus exists. - match locked_pci_host.find_device(0, devfn.unwrap()) { - Some(dev) => dev - .lock() - .unwrap() - .reset(false) - .with_context(|| "Failed to reset bus"), + match locked_pci_host.find_device(0, devfn.unwrap() as u8) { + Some(dev) => { + PCI_BUS_DEVICE!(dev, locked_dev, pci_dev); + pci_dev.reset(false).with_context(|| "Failed to reset bus") + } None => bail!("Failed to found device"), } } @@ -1695,7 +1694,7 @@ pub trait MachineOps: MachineLifecycle { vm_config: &VmConfig, id: Option<&str>, dev_type: &str, - ) -> Option>> { + ) -> Option>> { let (id_check, id_str) = if id.is_some() { (true, format! {"id={}", id.unwrap()}) } else { diff --git a/machine/src/x86_64/ich9_lpc.rs b/machine/src/x86_64/ich9_lpc.rs index 461f97b9..1507fe8b 100644 --- a/machine/src/x86_64/ich9_lpc.rs +++ b/machine/src/x86_64/ich9_lpc.rs @@ -27,7 +27,7 @@ use devices::pci::config::{ HEADER_TYPE_MULTIFUNC, PCI_CONFIG_SPACE_SIZE, SUB_CLASS_CODE, VENDOR_ID, }; use devices::pci::{le_write_u16, le_write_u32, PciBus, PciDevBase, PciDevOps}; -use devices::{convert_bus_mut, Device, DeviceBase, MUT_PCI_BUS}; +use devices::{Device, DeviceBase}; use util::byte_code::ByteCode; use util::gen_base_func; use util::num_ops::ranges_overlap; @@ -277,10 +277,8 @@ impl PciDevOps for LPCBridge { .with_context(|| "Fail to init IO region for PM control register")?; let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); - MUT_PCI_BUS!(parent_bus, locked_bus, pci_bus); - pci_bus - .devices - .insert(0x1F << 3, Arc::new(Mutex::new(self))); + let mut locked_bus = parent_bus.lock().unwrap(); + locked_bus.attach_child(0x1F << 3, Arc::new(Mutex::new(self)))?; Ok(()) } diff --git a/machine/src/x86_64/mch.rs b/machine/src/x86_64/mch.rs index f9d418c1..b8a1679c 100644 --- a/machine/src/x86_64/mch.rs +++ b/machine/src/x86_64/mch.rs @@ -24,7 +24,7 @@ use devices::pci::{ }, le_read_u64, le_write_u16, PciBus, PciDevBase, PciDevOps, }; -use devices::{convert_bus_mut, convert_bus_ref, Device, DeviceBase, MUT_PCI_BUS, PCI_BUS}; +use devices::{convert_bus_ref, Device, DeviceBase, PCI_BUS}; use util::gen_base_func; use util::num_ops::ranges_overlap; @@ -138,8 +138,8 @@ impl PciDevOps for Mch { )?; let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); - MUT_PCI_BUS!(parent_bus, locked_bus, pci_bus); - pci_bus.devices.insert(0, Arc::new(Mutex::new(self))); + let mut locked_bus = parent_bus.lock().unwrap(); + locked_bus.attach_child(0, Arc::new(Mutex::new(self)))?; Ok(()) } diff --git a/vfio/src/vfio_pci.rs b/vfio/src/vfio_pci.rs index b4c1f273..dbe0d2a4 100644 --- a/vfio/src/vfio_pci.rs +++ b/vfio/src/vfio_pci.rs @@ -41,11 +41,9 @@ use devices::pci::msix::{ }; use devices::pci::{ init_multifunction, le_read_u16, le_read_u32, le_write_u16, le_write_u32, pci_ext_cap_id, - pci_ext_cap_next, pci_ext_cap_ver, PciBus, PciDevBase, PciDevOps, -}; -use devices::{ - convert_bus_mut, convert_bus_ref, pci::MsiVector, Device, DeviceBase, MUT_PCI_BUS, PCI_BUS, + pci_ext_cap_next, pci_ext_cap_ver, MsiVector, PciBus, PciDevBase, PciDevOps, }; +use devices::{convert_bus_ref, Device, DeviceBase, PCI_BUS}; use machine_manager::config::{get_pci_df, parse_bool, valid_id}; use util::gen_base_func; use util::loop_context::create_new_eventfd; @@ -864,20 +862,11 @@ impl PciDevOps for VfioPciDevice { )?)); Result::with_context(self.register_bars(), || "Failed to register bars")?; - let devfn = self.base.devfn; + let devfn = self.base.devfn as u64; let dev = Arc::new(Mutex::new(self)); let parent_bus = dev.lock().unwrap().parent_bus().unwrap().upgrade().unwrap(); - MUT_PCI_BUS!(parent_bus, locked_bus, pci_bus); - let pci_device = pci_bus.devices.get(&devfn); - if pci_device.is_none() { - pci_bus.devices.insert(devfn, dev); - } else { - bail!( - "Devfn {:?} has been used by {:?}", - &devfn, - pci_device.unwrap().lock().unwrap().name() - ); - } + let mut locked_bus = parent_bus.lock().unwrap(); + locked_bus.attach_child(devfn, dev)?; Ok(()) } diff --git a/virtio/src/transport/virtio_pci.rs b/virtio/src/transport/virtio_pci.rs index 19bd0212..5e8114ec 100644 --- a/virtio/src/transport/virtio_pci.rs +++ b/virtio/src/transport/virtio_pci.rs @@ -46,7 +46,7 @@ use devices::pci::{ config::PciConfig, init_intx, init_msix, init_multifunction, le_write_u16, le_write_u32, PciBus, PciDevBase, PciDevOps, PciError, }; -use devices::{convert_bus_mut, convert_bus_ref, Device, DeviceBase, MUT_PCI_BUS, PCI_BUS}; +use devices::{convert_bus_ref, Device, DeviceBase, PCI_BUS}; #[cfg(feature = "virtio_gpu")] use machine_manager::config::VIRTIO_GPU_ENABLE_BAR0_SIZE; use migration::{DeviceStateDesc, FieldDesc, MigrationHook, MigrationManager, StateTransfer}; @@ -1139,7 +1139,7 @@ impl PciDevOps for VirtioPciDevice { .with_context(|| "Failed to realize virtio device")?; let name = self.name(); - let devfn = self.base.devfn; + let devfn = self.base.devfn as u64; let dev = Arc::new(Mutex::new(self)); let mut mem_region_size = ((VIRTIO_PCI_CAP_NOTIFY_OFFSET + VIRTIO_PCI_CAP_NOTIFY_LENGTH) as u64) @@ -1159,17 +1159,7 @@ impl PciDevOps for VirtioPciDevice { // Register device to pci bus. let bus = parent_bus.upgrade().unwrap(); - MUT_PCI_BUS!(bus, locked_bus, pci_bus); - let pci_device = pci_bus.devices.get(&devfn); - if pci_device.is_none() { - pci_bus.devices.insert(devfn, dev.clone()); - } else { - bail!( - "Devfn {:?} has been used by {:?}", - &devfn, - pci_device.unwrap().lock().unwrap().name() - ); - } + bus.lock().unwrap().attach_child(devfn, dev.clone())?; MigrationManager::register_transport_instance(VirtioPciState::descriptor(), dev, &name); -- Gitee From 2088ccc5dcf7f77ee0dc731bcb8362dff0539df2 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 1 Feb 2024 23:09:14 +0800 Subject: [PATCH 197/489] devices/pci: remove child_buses/sec_bus/root_bus in pci architecture 1. `child_buses` field of struct `PciBus` refers to the secondary PCI bus extended from bridge devices mounted on the `PciBus`. We can get it from PciBus.child_dev().child_bus(). 2. `sec_bus` field of struct `RootPort` refers to the secondary PCI bus extended from `RootPort`. And it has the same effect as the `child_bus` field of struct `DeviceBase`. 3. `root_bus` field of struct `PciHost` refers to the PCI bus extended from `PciHost`. And it has the same effect as the `child_bus` field of struct `DeviceBase`. Delete them. Signed-off-by: liuxiangdong --- devices/src/misc/ivshmem.rs | 4 +- devices/src/misc/pvpanic.rs | 85 +++++++----------------- devices/src/misc/scream/mod.rs | 4 +- devices/src/pci/bus.rs | 99 +++++++++++++++------------- devices/src/pci/demo_device/mod.rs | 13 ++-- devices/src/pci/host.rs | 37 ++++++----- devices/src/pci/hotplug.rs | 18 ++--- devices/src/pci/mod.rs | 6 +- devices/src/pci/msix.rs | 6 +- devices/src/pci/root_port.rs | 67 +++++++++---------- devices/src/usb/xhci/xhci_pci.rs | 4 +- machine/src/aarch64/pci_host_root.rs | 6 +- machine/src/aarch64/standard.rs | 15 +++-- machine/src/lib.rs | 30 +++++---- machine/src/standard_common/mod.rs | 9 ++- machine/src/x86_64/ich9_lpc.rs | 6 +- machine/src/x86_64/mch.rs | 4 +- machine/src/x86_64/standard.rs | 12 ++-- vfio/src/vfio_pci.rs | 4 +- virtio/src/transport/virtio_pci.rs | 6 +- 20 files changed, 210 insertions(+), 225 deletions(-) diff --git a/devices/src/misc/ivshmem.rs b/devices/src/misc/ivshmem.rs index ae91fcbb..685fbb9e 100644 --- a/devices/src/misc/ivshmem.rs +++ b/devices/src/misc/ivshmem.rs @@ -22,7 +22,7 @@ use crate::pci::config::{ PCI_VENDOR_ID_REDHAT_QUMRANET, REVISION_ID, SUB_CLASS_CODE, VENDOR_ID, }; use crate::pci::{le_write_u16, PciBus, PciDevBase, PciDevOps}; -use crate::{convert_bus_ref, Device, DeviceBase, PCI_BUS}; +use crate::{convert_bus_ref, Bus, Device, DeviceBase, PCI_BUS}; use address_space::{GuestAddress, Region, RegionOps}; use util::gen_base_func; @@ -45,7 +45,7 @@ impl Ivshmem { pub fn new( name: String, devfn: u8, - parent_bus: Weak>, + parent_bus: Weak>, ram_mem_region: Region, ) -> Self { Self { diff --git a/devices/src/misc/pvpanic.rs b/devices/src/misc/pvpanic.rs index eae09f88..76d23219 100644 --- a/devices/src/misc/pvpanic.rs +++ b/devices/src/misc/pvpanic.rs @@ -27,7 +27,7 @@ use crate::pci::config::{ SUBSYSTEM_VENDOR_ID, SUB_CLASS_CODE, VENDOR_ID, }; use crate::pci::{le_write_u16, PciBus, PciDevBase, PciDevOps}; -use crate::{convert_bus_mut, convert_bus_ref, Device, DeviceBase, MUT_PCI_BUS, PCI_BUS}; +use crate::{convert_bus_mut, convert_bus_ref, Bus, Device, DeviceBase, MUT_PCI_BUS, PCI_BUS}; use address_space::{GuestAddress, Region, RegionOps}; use machine_manager::config::{get_pci_df, valid_id}; use util::gen_base_func; @@ -107,7 +107,7 @@ pub struct PvPanicPci { } impl PvPanicPci { - pub fn new(config: &PvpanicDevConfig, devfn: u8, parent_bus: Weak>) -> Self { + pub fn new(config: &PvpanicDevConfig, devfn: u8, parent_bus: Weak>) -> Self { Self { base: PciDevBase { base: DeviceBase::new(config.id.clone(), false, Some(parent_bus)), @@ -250,7 +250,7 @@ impl PciDevOps for PvPanicPci { mod tests { use super::*; use crate::pci::{host::tests::create_pci_host, le_read_u16, PciHost}; - use crate::{convert_device_mut, Bus}; + use crate::{convert_bus_ref, convert_device_mut, PCI_BUS}; use machine_manager::config::str_slip_to_clap; /// Convert from Arc> to &mut PvPanicPci. @@ -264,7 +264,7 @@ mod tests { fn init_pvpanic_dev(devfn: u8, supported_features: u32, dev_id: &str) -> Arc> { let pci_host = create_pci_host(); let locked_pci_host = pci_host.lock().unwrap(); - let root_bus = Arc::downgrade(&locked_pci_host.root_bus); + let root_bus = Arc::downgrade(&locked_pci_host.child_bus().unwrap()); let config = PvpanicDevConfig { id: dev_id.to_string(), @@ -273,11 +273,10 @@ mod tests { bus: "pcie.0".to_string(), addr: (3, 0), }; - let pvpanic_dev = PvPanicPci::new(&config, devfn, root_bus.clone()); + let pvpanic_dev = PvPanicPci::new(&config, devfn, root_bus); assert_eq!(pvpanic_dev.base.base.id, "pvpanic_test".to_string()); pvpanic_dev.realize().unwrap(); - drop(root_bus); drop(locked_pci_host); pci_host @@ -304,17 +303,17 @@ mod tests { #[test] fn test_pvpanic_attached() { let pci_host = init_pvpanic_dev(7, PVPANIC_PANICKED | PVPANIC_CRASHLOADED, "pvpanic_test"); - let locked_pci_host = pci_host.lock().unwrap(); - let root_bus = Arc::downgrade(&locked_pci_host.root_bus); - - let pvpanic_dev = root_bus.upgrade().unwrap().lock().unwrap().get_device(0, 7); + let root_bus = pci_host.lock().unwrap().child_bus().unwrap(); + PCI_BUS!(root_bus, locked_bus, pci_bus); + let pvpanic_dev = pci_bus.get_device(0, 7); + drop(locked_bus); assert!(pvpanic_dev.is_some()); assert_eq!( pvpanic_dev.unwrap().lock().unwrap().name(), "pvpanic_test".to_string() ); - let info = PciBus::find_attached_bus(&locked_pci_host.root_bus, "pvpanic_test"); + let info = PciBus::find_attached_bus(&root_bus, "pvpanic_test"); assert!(info.is_some()); let (bus, dev) = info.unwrap(); assert_eq!(bus.lock().unwrap().name(), "pcie.0"); @@ -324,16 +323,9 @@ mod tests { #[test] fn test_pvpanic_config() { let pci_host = init_pvpanic_dev(7, PVPANIC_PANICKED | PVPANIC_CRASHLOADED, "pvpanic_test"); - let locked_pci_host = pci_host.lock().unwrap(); - let root_bus = Arc::downgrade(&locked_pci_host.root_bus); - - let pvpanic_dev = root_bus - .upgrade() - .unwrap() - .lock() - .unwrap() - .get_device(0, 7) - .unwrap(); + let root_bus = pci_host.lock().unwrap().child_bus().unwrap(); + PCI_BUS!(root_bus, locked_bus, pci_bus); + let pvpanic_dev = pci_bus.get_device(0, 7).unwrap(); MUT_PVPANIC_PCI!(pvpanic_dev, locked_dev, pvpanic); let info = le_read_u16(&pvpanic.pci_base_mut().config.config, VENDOR_ID as usize) .unwrap_or_else(|_| 0); @@ -362,16 +354,9 @@ mod tests { #[test] fn test_pvpanic_read_features() { let pci_host = init_pvpanic_dev(7, PVPANIC_PANICKED | PVPANIC_CRASHLOADED, "pvpanic_test"); - let locked_pci_host = pci_host.lock().unwrap(); - let root_bus = Arc::downgrade(&locked_pci_host.root_bus); - - let pvpanic_dev = root_bus - .upgrade() - .unwrap() - .lock() - .unwrap() - .get_device(0, 7) - .unwrap(); + let root_bus = pci_host.lock().unwrap().child_bus().unwrap(); + PCI_BUS!(root_bus, locked_bus, pci_bus); + let pvpanic_dev = pci_bus.get_device(0, 7).unwrap(); MUT_PVPANIC_PCI!(pvpanic_dev, locked_dev, pvpanic); // test read supported_features @@ -391,16 +376,9 @@ mod tests { #[test] fn test_pvpanic_write_panicked() { let pci_host = init_pvpanic_dev(7, PVPANIC_PANICKED | PVPANIC_CRASHLOADED, "pvpanic_test"); - let locked_pci_host = pci_host.lock().unwrap(); - let root_bus = Arc::downgrade(&locked_pci_host.root_bus); - - let pvpanic_dev = root_bus - .upgrade() - .unwrap() - .lock() - .unwrap() - .get_device(0, 7) - .unwrap(); + let root_bus = pci_host.lock().unwrap().child_bus().unwrap(); + PCI_BUS!(root_bus, locked_bus, pci_bus); + let pvpanic_dev = pci_bus.get_device(0, 7).unwrap(); MUT_PVPANIC_PCI!(pvpanic_dev, locked_dev, pvpanic); // test write panicked event @@ -417,16 +395,9 @@ mod tests { #[test] fn test_pvpanic_write_crashload() { let pci_host = init_pvpanic_dev(7, PVPANIC_PANICKED | PVPANIC_CRASHLOADED, "pvpanic_test"); - let locked_pci_host = pci_host.lock().unwrap(); - let root_bus = Arc::downgrade(&locked_pci_host.root_bus); - - let pvpanic_dev = root_bus - .upgrade() - .unwrap() - .lock() - .unwrap() - .get_device(0, 7) - .unwrap(); + let root_bus = pci_host.lock().unwrap().child_bus().unwrap(); + PCI_BUS!(root_bus, locked_bus, pci_bus); + let pvpanic_dev = pci_bus.get_device(0, 7).unwrap(); MUT_PVPANIC_PCI!(pvpanic_dev, locked_dev, pvpanic); // test write crashload event @@ -444,15 +415,9 @@ mod tests { fn test_pvpanic_write_unknown() { let pci_host = init_pvpanic_dev(7, PVPANIC_PANICKED | PVPANIC_CRASHLOADED, "pvpanic_test"); let locked_pci_host = pci_host.lock().unwrap(); - let root_bus = Arc::downgrade(&locked_pci_host.root_bus); - - let pvpanic_dev = root_bus - .upgrade() - .unwrap() - .lock() - .unwrap() - .get_device(0, 7) - .unwrap(); + let root_bus = locked_pci_host.child_bus().unwrap(); + PCI_BUS!(root_bus, locked_bus, pci_bus); + let pvpanic_dev = pci_bus.get_device(0, 7).unwrap(); MUT_PVPANIC_PCI!(pvpanic_dev, locked_dev, pvpanic); // test write unknown event diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index 0c5be725..254671df 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -37,7 +37,7 @@ use log::{error, warn}; use self::alsa::AlsaStreamData; use self::audio_demo::AudioDemo; use super::ivshmem::Ivshmem; -use crate::pci::{PciBus, PciDevOps}; +use crate::{pci::PciDevOps, Bus}; use address_space::{GuestAddress, HostMemMapping, Region}; use machine_manager::config::{get_pci_df, parse_bool, valid_id}; #[cfg(all(target_env = "ohos", feature = "scream_ohaudio"))] @@ -534,7 +534,7 @@ impl Scream { Ok(()) } - pub fn realize(&mut self, parent_bus: Weak>) -> Result<()> { + pub fn realize(&mut self, parent_bus: Weak>) -> Result<()> { let host_mmap = Arc::new(HostMemMapping::new( GuestAddress(0), None, diff --git a/devices/src/pci/bus.rs b/devices/src/pci/bus.rs index 6e03f1a1..7bf02021 100644 --- a/devices/src/pci/bus.rs +++ b/devices/src/pci/bus.rs @@ -23,19 +23,17 @@ use super::{ }; use crate::pci::{to_pcidevops, RootPort}; use crate::{ - convert_device_mut, convert_device_ref, Bus, BusBase, Device, MsiIrqManager, MUT_ROOT_PORT, - PCI_BUS_DEVICE, ROOT_PORT, + convert_bus_mut, convert_bus_ref, convert_device_mut, convert_device_ref, Bus, BusBase, Device, + MsiIrqManager, MUT_ROOT_PORT, PCI_BUS_DEVICE, ROOT_PORT, }; use address_space::Region; use util::gen_base_func; -type DeviceBusInfo = (Arc>, Arc>); +type DeviceBusInfo = (Arc>, Arc>); /// PCI bus structure. pub struct PciBus { pub base: BusBase, - /// Child buses of the bus. - pub child_buses: Vec>>, /// IO region which the parent bridge manages. #[cfg(target_arch = "x86_64")] pub io_region: Region, @@ -83,7 +81,6 @@ impl PciBus { ) -> Self { Self { base: BusBase::new(name), - child_buses: Vec::new(), #[cfg(target_arch = "x86_64")] io_region, mem_region, @@ -139,15 +136,18 @@ impl PciBus { /// /// * `bus` - Bus to find from. /// * `bus_number` - The bus number. - pub fn find_bus_by_num(bus: &Arc>, bus_num: u8) -> Option>> { - let locked_bus = bus.lock().unwrap(); - if locked_bus.number(SECONDARY_BUS_NUM as usize) == bus_num { - return Some((*bus).clone()); + pub fn find_bus_by_num(bus: &Arc>, bus_num: u8) -> Option>> { + PCI_BUS!(bus, locked_bus, pci_bus); + if pci_bus.number(SECONDARY_BUS_NUM as usize) == bus_num { + return Some(bus.clone()); } - if locked_bus.in_range(bus_num) { - for sub_bus in &locked_bus.child_buses { - if let Some(b) = PciBus::find_bus_by_num(sub_bus, bus_num) { - return Some(b); + if pci_bus.in_range(bus_num) { + for dev in pci_bus.child_devices().values() { + let child_bus = dev.lock().unwrap().child_bus(); + if let Some(sub_bus) = child_bus { + if let Some(b) = PciBus::find_bus_by_num(&sub_bus, bus_num) { + return Some(b); + } } } } @@ -160,14 +160,20 @@ impl PciBus { /// /// * `bus` - Bus to find from. /// * `name` - Bus name. - pub fn find_bus_by_name(bus: &Arc>, bus_name: &str) -> Option>> { + pub fn find_bus_by_name( + bus: &Arc>, + bus_name: &str, + ) -> Option>> { let locked_bus = bus.lock().unwrap(); if locked_bus.name().as_str() == bus_name { - return Some((*bus).clone()); + return Some(bus.clone()); } - for sub_bus in &locked_bus.child_buses { - if let Some(b) = PciBus::find_bus_by_name(sub_bus, bus_name) { - return Some(b); + for dev in locked_bus.child_devices().values() { + let child_bus = dev.lock().unwrap().child_bus(); + if let Some(sub_bus) = child_bus { + if let Some(b) = PciBus::find_bus_by_name(&sub_bus, bus_name) { + return Some(b); + } } } None @@ -177,20 +183,22 @@ impl PciBus { /// /// # Arguments /// - /// * `pci_bus` - On which bus to find. + /// * `bus` - On which bus to find. /// * `name` - Device name. - pub fn find_attached_bus(pci_bus: &Arc>, name: &str) -> Option { - // Device is attached in pci_bus. - let locked_bus = pci_bus.lock().unwrap(); + pub fn find_attached_bus(bus: &Arc>, name: &str) -> Option { + // Device is attached in bus. + let locked_bus = bus.lock().unwrap(); for dev in locked_bus.child_devices().values() { if dev.lock().unwrap().name() == name { - return Some((pci_bus.clone(), dev.clone())); + return Some((bus.clone(), dev.clone())); } - } - // Find in child bus. - for bus in &locked_bus.child_buses { - if let Some(found) = PciBus::find_attached_bus(bus, name) { - return Some(found); + + // Find in child bus. + let child_bus = dev.lock().unwrap().child_bus(); + if let Some(sub_bus) = child_bus { + if let Some(found) = PciBus::find_attached_bus(&sub_bus, name) { + return Some(found); + } } } None @@ -202,7 +210,7 @@ impl PciBus { /// /// * `bus` - Bus to detach from. /// * `dev` - Device attached to the bus. - pub fn detach_device(bus: &Arc>, dev: &Arc>) -> Result<()> { + pub fn detach_device(bus: &Arc>, dev: &Arc>) -> Result<()> { PCI_BUS_DEVICE!(dev, locked_dev, pci_dev); pci_dev .unrealize() @@ -223,14 +231,11 @@ impl PciBus { pci_dev .reset(false) .with_context(|| format!("Fail to reset pci dev {}", pci_dev.name()))?; - } - for child_bus in self.child_buses.iter_mut() { - child_bus - .lock() - .unwrap() - .reset() - .with_context(|| "Fail to reset child bus")?; + if let Some(bus) = pci_dev.child_bus() { + MUT_PCI_BUS!(bus, locked_bus, pci_bus); + pci_bus.reset().with_context(|| "Fail to reset child bus")?; + } } Ok(()) @@ -287,7 +292,7 @@ mod tests { fn test_find_attached_bus() { let pci_host = create_pci_host(); let locked_pci_host = pci_host.lock().unwrap(); - let root_bus = Arc::downgrade(&locked_pci_host.root_bus); + let root_bus = Arc::downgrade(&locked_pci_host.child_bus().unwrap()); let root_port_config = RootPortConfig { addr: (1, 0), id: "pcie.1".to_string(), @@ -301,20 +306,21 @@ mod tests { pci_dev.realize().unwrap(); // Test device is attached to the root port. - let bus = PciBus::find_bus_by_name(&locked_pci_host.root_bus, "pcie.1").unwrap(); + let bus = + PciBus::find_bus_by_name(&locked_pci_host.child_bus().unwrap(), "pcie.1").unwrap(); let pci_dev = TestPciDevice::new("test2", 12, Arc::downgrade(&bus)); pci_dev.realize().unwrap(); - let info = PciBus::find_attached_bus(&locked_pci_host.root_bus, "test0"); + let info = PciBus::find_attached_bus(&locked_pci_host.child_bus().unwrap(), "test0"); assert!(info.is_none()); - let info = PciBus::find_attached_bus(&locked_pci_host.root_bus, "test1"); + let info = PciBus::find_attached_bus(&locked_pci_host.child_bus().unwrap(), "test1"); assert!(info.is_some()); let (bus, dev) = info.unwrap(); assert_eq!(bus.lock().unwrap().name(), "pcie.0"); assert_eq!(dev.lock().unwrap().name(), "test1"); - let info = PciBus::find_attached_bus(&locked_pci_host.root_bus, "test2"); + let info = PciBus::find_attached_bus(&locked_pci_host.child_bus().unwrap(), "test2"); assert!(info.is_some()); let (bus, dev) = info.unwrap(); assert_eq!(bus.lock().unwrap().name(), "pcie.1"); @@ -327,7 +333,7 @@ mod tests { let pci_host = create_pci_host(); let locked_pci_host = pci_host.lock().unwrap(); - let root_bus = Arc::downgrade(&locked_pci_host.root_bus); + let root_bus = Arc::downgrade(&locked_pci_host.child_bus().unwrap()); let root_port_config = RootPortConfig { id: "pcie.1".to_string(), @@ -337,18 +343,19 @@ mod tests { let root_port = RootPort::new(root_port_config, root_bus.clone()); root_port.realize().unwrap(); - let bus = PciBus::find_bus_by_name(&locked_pci_host.root_bus, "pcie.1").unwrap(); + let bus = + PciBus::find_bus_by_name(&locked_pci_host.child_bus().unwrap(), "pcie.1").unwrap(); let pci_dev = TestPciDevice::new("test1", 0, Arc::downgrade(&bus)); let dev_ops: Arc> = Arc::new(Mutex::new(pci_dev.clone())); pci_dev.realize().unwrap(); - let info = PciBus::find_attached_bus(&locked_pci_host.root_bus, "test1"); + let info = PciBus::find_attached_bus(&locked_pci_host.child_bus().unwrap(), "test1"); assert!(info.is_some()); let res = PciBus::detach_device(&bus, &dev_ops); assert!(res.is_ok()); - let info = PciBus::find_attached_bus(&locked_pci_host.root_bus, "test1"); + let info = PciBus::find_attached_bus(&locked_pci_host.child_bus().unwrap(), "test1"); assert!(info.is_none()); clean_pcidevops_type(); diff --git a/devices/src/pci/demo_device/mod.rs b/devices/src/pci/demo_device/mod.rs index 483bfbab..77fcfd30 100644 --- a/devices/src/pci/demo_device/mod.rs +++ b/devices/src/pci/demo_device/mod.rs @@ -33,13 +33,8 @@ pub mod dpy_device; pub mod gpu_device; pub mod kbd_pointer_device; -use std::{ - sync::Mutex, - sync::{ - atomic::{AtomicU16, Ordering}, - Arc, Weak, - }, -}; +use std::sync::atomic::{AtomicU16, Ordering}; +use std::sync::{Arc, Mutex, Weak}; use anyhow::Result; use clap::Parser; @@ -54,7 +49,7 @@ use crate::pci::demo_device::{ kbd_pointer_device::DemoKbdMouse, }; use crate::pci::{init_msix, le_write_u16, PciBus, PciDevBase, PciDevOps}; -use crate::{convert_bus_ref, Device, DeviceBase, PCI_BUS}; +use crate::{convert_bus_ref, Bus, Device, DeviceBase, PCI_BUS}; use address_space::{AddressSpace, GuestAddress, Region, RegionOps}; use machine_manager::config::{get_pci_df, valid_id}; use util::gen_base_func; @@ -95,7 +90,7 @@ impl DemoDev { cfg: DemoDevConfig, devfn: u8, sys_mem: Arc, - parent_bus: Weak>, + parent_bus: Weak>, ) -> Self { // You can choose different device function based on the parameter of device_type. let device_type = cfg.device_type.clone().unwrap_or_default(); diff --git a/devices/src/pci/host.rs b/devices/src/pci/host.rs index 4d45a4f4..6f1a2559 100644 --- a/devices/src/pci/host.rs +++ b/devices/src/pci/host.rs @@ -20,7 +20,7 @@ use crate::pci::{bus::PciBus, to_pcidevops, PCI_PIN_NUM, PCI_SLOT_MAX}; #[cfg(target_arch = "x86_64")] use crate::pci::{le_read_u32, le_write_u32}; use crate::sysbus::{SysBusDevBase, SysBusDevOps}; -use crate::{Bus, Device, DeviceBase, PCI_BUS_DEVICE}; +use crate::{Device, DeviceBase, PCI_BUS_DEVICE}; use acpi::{ AmlActiveLevel, AmlAddressSpaceDecode, AmlAnd, AmlArg, AmlBuilder, AmlCacheable, AmlCreateDWordField, AmlDWord, AmlDWordDesc, AmlDevice, AmlEdgeLevel, AmlEisaId, AmlElse, @@ -54,7 +54,6 @@ const ECAM_OFFSET_MASK: u64 = 0xfff; #[derive(Clone)] pub struct PciHost { base: SysBusDevBase, - pub root_bus: Arc>, #[cfg(target_arch = "x86_64")] config_addr: u32, pcie_ecam_range: (u64, u64), @@ -96,9 +95,10 @@ impl PciHost { io_region, mem_region, ); + let mut base = SysBusDevBase::default(); + base.base.child = Some(Arc::new(Mutex::new(root_bus))); PciHost { - base: SysBusDevBase::default(), - root_bus: Arc::new(Mutex::new(root_bus)), + base, #[cfg(target_arch = "x86_64")] config_addr: 0, pcie_ecam_range, @@ -112,15 +112,20 @@ impl PciHost { } pub fn find_device(&self, bus_num: u8, devfn: u8) -> Option>> { - let locked_root_bus = self.root_bus.lock().unwrap(); + let root_bus = self.child_bus().unwrap(); + let locked_root_bus = root_bus.lock().unwrap(); if bus_num == 0 { let dev = locked_root_bus.child_dev(devfn as u64)?; return Some(dev.clone()); } - for bus in &locked_root_bus.child_buses { - if let Some(b) = PciBus::find_bus_by_num(bus, bus_num) { - let dev = b.lock().unwrap().child_dev(devfn as u64)?.clone(); - return Some(dev); + + for dev in locked_root_bus.child_devices().values() { + let child_bus = dev.lock().unwrap().child_bus(); + if let Some(bus) = child_bus { + if let Some(b) = PciBus::find_bus_by_num(&bus, bus_num) { + let dev = b.lock().unwrap().child_dev(devfn as u64)?.clone(); + return Some(dev); + } } } None @@ -277,7 +282,8 @@ impl SysBusDevOps for PciHost { } fn reset(&mut self) -> Result<()> { - for dev in self.root_bus.lock().unwrap().child_devices().values() { + let root_bus = self.child_bus().unwrap(); + for dev in root_bus.lock().unwrap().child_devices().values() { PCI_BUS_DEVICE!(dev, locked_dev, pci_dev); pci_dev .reset(true) @@ -579,7 +585,7 @@ pub mod tests { register_pcidevops_type::().unwrap(); let pci_host = create_pci_host(); - let root_bus = Arc::downgrade(&pci_host.lock().unwrap().root_bus); + let root_bus = Arc::downgrade(&pci_host.lock().unwrap().child_bus().unwrap()); let pio_addr_ops = PciHost::build_pio_addr_ops(pci_host.clone()); let pio_data_ops = PciHost::build_pio_data_ops(pci_host.clone()); let root_port_config = RootPortConfig { @@ -665,7 +671,8 @@ pub mod tests { register_pcidevops_type::().unwrap(); let pci_host = create_pci_host(); - let root_bus = Arc::downgrade(&pci_host.lock().unwrap().root_bus); + let root_bus = pci_host.lock().unwrap().child_bus().unwrap(); + let weak_root_bus = Arc::downgrade(&root_bus); let mmconfig_region_ops = PciHost::build_mmconfig_ops(pci_host.clone()); let root_port_config = RootPortConfig { @@ -673,7 +680,7 @@ pub mod tests { id: "pcie.1".to_string(), ..Default::default() }; - let mut root_port = RootPort::new(root_port_config, root_bus.clone()); + let mut root_port = RootPort::new(root_port_config, weak_root_bus.clone()); root_port.write_config(SECONDARY_BUS_NUM as usize, &[1]); root_port.realize().unwrap(); let root_port_config = RootPortConfig { @@ -681,11 +688,11 @@ pub mod tests { id: "pcie.2".to_string(), ..Default::default() }; - let mut root_port = RootPort::new(root_port_config, root_bus.clone()); + let mut root_port = RootPort::new(root_port_config, weak_root_bus); root_port.write_config(SECONDARY_BUS_NUM as usize, &[2]); root_port.realize().unwrap(); - let bus = PciBus::find_bus_by_name(&pci_host.lock().unwrap().root_bus, "pcie.2").unwrap(); + let bus = PciBus::find_bus_by_name(&root_bus, "pcie.2").unwrap(); let pci_dev = TestPciDevice::new("PCI device", 8, Arc::downgrade(&bus)); pci_dev.realize().unwrap(); diff --git a/devices/src/pci/hotplug.rs b/devices/src/pci/hotplug.rs index 862956be..7f13de93 100644 --- a/devices/src/pci/hotplug.rs +++ b/devices/src/pci/hotplug.rs @@ -15,7 +15,7 @@ use std::sync::{Arc, Mutex}; use anyhow::{bail, Context, Result}; use crate::pci::PciBus; -use crate::{Bus, Device}; +use crate::{convert_bus_ref, Bus, Device, PCI_BUS}; pub trait HotplugOps: Send { /// Plug device, usually called when hot plug device in device_add. @@ -41,14 +41,14 @@ pub trait HotplugOps: Send { /// Return Error if /// * No hot plug controller found. /// * Device plug failed. -pub fn handle_plug(bus: &Arc>, dev: &Arc>) -> Result<()> { - let locked_bus = bus.lock().unwrap(); - if let Some(hpc) = locked_bus.hotplug_controller.as_ref() { +pub fn handle_plug(bus: &Arc>, dev: &Arc>) -> Result<()> { + PCI_BUS!(bus, locked_bus, pci_bus); + if let Some(hpc) = pci_bus.hotplug_controller.as_ref() { hpc.upgrade().unwrap().lock().unwrap().plug(dev) } else { bail!( "No hot plug controller found for bus {} when plug", - locked_bus.name() + pci_bus.name() ); } } @@ -66,18 +66,18 @@ pub fn handle_plug(bus: &Arc>, dev: &Arc>) -> Re /// * No hot plug controller found. /// * Device unplug request failed. pub fn handle_unplug_pci_request( - bus: &Arc>, + bus: &Arc>, dev: &Arc>, ) -> Result<()> { - let locked_bus = bus.lock().unwrap(); - let hpc = locked_bus + PCI_BUS!(bus, locked_bus, pci_bus); + let hpc = pci_bus .hotplug_controller .as_ref() .cloned() .with_context(|| { format!( "No hot plug controller found for bus {} when unplug request", - locked_bus.name() + pci_bus.name() ) })?; // No need to hold the lock. diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs index b7faa792..cbb95263 100644 --- a/devices/src/pci/mod.rs +++ b/devices/src/pci/mod.rs @@ -420,7 +420,7 @@ mod tests { } impl TestPciDevice { - pub fn new(name: &str, devfn: u8, parent_bus: Weak>) -> Self { + pub fn new(name: &str, devfn: u8, parent_bus: Weak>) -> Self { Self { base: PciDevBase { base: DeviceBase::new(name.to_string(), false, Some(parent_bus)), @@ -529,12 +529,12 @@ mod tests { None, ) .unwrap(); - let parent_bus: Arc> = Arc::new(Mutex::new(PciBus::new( + let parent_bus = Arc::new(Mutex::new(PciBus::new( String::from("test bus"), #[cfg(target_arch = "x86_64")] Region::init_container_region(1 << 16, "parent_bus"), sys_mem.root().clone(), - ))); + ))) as Arc>; let dev = TestPciDevice::new("PCI device", 0, Arc::downgrade(&parent_bus)); assert_eq!(dev.set_dev_id(1, 2), 258); diff --git a/devices/src/pci/msix.rs b/devices/src/pci/msix.rs index e82b7c17..70eb603d 100644 --- a/devices/src/pci/msix.rs +++ b/devices/src/pci/msix.rs @@ -637,13 +637,13 @@ mod tests { use super::*; use crate::pci::config::{PciConfig, PCI_CONFIG_SPACE_SIZE}; use crate::pci::host::tests::create_pci_host; - use crate::DeviceBase; + use crate::{Device, DeviceBase}; #[test] fn test_init_msix() { let pci_host = create_pci_host(); let locked_pci_host = pci_host.lock().unwrap(); - let root_bus = Arc::downgrade(&locked_pci_host.root_bus); + let root_bus = Arc::downgrade(&locked_pci_host.child_bus().unwrap()); let mut base = PciDevBase { base: DeviceBase::new("msix".to_string(), false, Some(root_bus)), config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 2), @@ -748,7 +748,7 @@ mod tests { fn test_write_config() { let pci_host = create_pci_host(); let locked_pci_host = pci_host.lock().unwrap(); - let root_bus = Arc::downgrade(&locked_pci_host.root_bus); + let root_bus = Arc::downgrade(&locked_pci_host.child_bus().unwrap()); let mut base = PciDevBase { base: DeviceBase::new("msix".to_string(), false, Some(root_bus)), config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 2), diff --git a/devices/src/pci/root_port.rs b/devices/src/pci/root_port.rs index ea6b43b1..aceea6fa 100644 --- a/devices/src/pci/root_port.rs +++ b/devices/src/pci/root_port.rs @@ -94,7 +94,6 @@ struct RootPortState { pub struct RootPort { base: PciDevBase, port_num: u8, - sec_bus: Arc>, #[cfg(target_arch = "x86_64")] io_region: Region, mem_region: Region, @@ -110,26 +109,27 @@ impl RootPort { /// /// * `cfg` - Root port config. /// * `parent_bus` - Weak reference to the parent bus. - pub fn new(cfg: RootPortConfig, parent_bus: Weak>) -> Self { + pub fn new(cfg: RootPortConfig, parent_bus: Weak>) -> Self { let devfn = cfg.addr.0 << 3 | cfg.addr.1; #[cfg(target_arch = "x86_64")] let io_region = Region::init_container_region(1 << 16, "RootPortIo"); let mem_region = Region::init_container_region(u64::max_value(), "RootPortMem"); - let sec_bus = Arc::new(Mutex::new(PciBus::new( + let child_bus = Arc::new(Mutex::new(PciBus::new( cfg.id.clone(), #[cfg(target_arch = "x86_64")] io_region.clone(), mem_region.clone(), ))); + let mut dev_base = DeviceBase::new(cfg.id, true, Some(parent_bus)); + dev_base.child = Some(child_bus); Self { base: PciDevBase { - base: DeviceBase::new(cfg.id, true, Some(parent_bus)), + base: dev_base, config: PciConfig::new(PCIE_CONFIG_SPACE_SIZE, 2), devfn, }, port_num: cfg.port, - sec_bus, #[cfg(target_arch = "x86_64")] io_region, mem_region, @@ -222,7 +222,8 @@ impl RootPort { // Store device in a temp vector and unlock the bus. // If the device unrealize called when the bus is locked, a deadlock occurs. // This is because the device unrealize also requires the bus lock. - let devices = self.sec_bus.lock().unwrap().child_devices().clone(); + let bus = self.child_bus().unwrap(); + let devices = bus.lock().unwrap().child_devices(); for dev in devices.values() { PCI_BUS_DEVICE!(dev, locked_dev, pci_dev); if let Err(e) = pci_dev.unrealize() { @@ -234,7 +235,7 @@ impl RootPort { // Send QMP event for successful hot unplugging. send_device_deleted_msg(&locked_dev.name()); } - self.sec_bus.lock().unwrap().bus_base_mut().children.clear(); + bus.lock().unwrap().bus_base_mut().children.clear(); } fn register_region(&mut self) { @@ -398,37 +399,30 @@ impl PciDevOps for RootPort { self.base.devfn, )?; - let bus = parent_bus.upgrade().unwrap(); - MUT_PCI_BUS!(bus, locked_bus, pci_bus); + let arc_parent_bus = parent_bus.upgrade().unwrap(); + MUT_PCI_BUS!(arc_parent_bus, locked_parent_bus, parent_pci_bus); + let child_bus = self.child_bus().unwrap(); + MUT_PCI_BUS!(child_bus, locked_child_bus, child_pci_bus); #[cfg(target_arch = "x86_64")] - pci_bus + parent_pci_bus .io_region - .add_subregion(self.sec_bus.lock().unwrap().io_region.clone(), 0) + .add_subregion(child_pci_bus.io_region.clone(), 0) .with_context(|| "Failed to register subregion in I/O space.")?; - pci_bus + parent_pci_bus .mem_region - .add_subregion(self.sec_bus.lock().unwrap().mem_region.clone(), 0) + .add_subregion(child_pci_bus.mem_region.clone(), 0) .with_context(|| "Failed to register subregion in memory space.")?; + drop(locked_child_bus); let name = self.name(); let root_port = Arc::new(Mutex::new(self)); - #[allow(unused_mut)] - let mut locked_root_port = root_port.lock().unwrap(); - locked_root_port.sec_bus.lock().unwrap().base.parent = - Some(Arc::downgrade(&root_port) as Weak>); - locked_root_port.sec_bus.lock().unwrap().hotplug_controller = + let locked_root_port = root_port.lock().unwrap(); + let child_bus = locked_root_port.child_bus().unwrap(); + MUT_PCI_BUS!(child_bus, locked_child_bus, child_pci_bus); + child_pci_bus.base.parent = Some(Arc::downgrade(&root_port) as Weak>); + child_pci_bus.hotplug_controller = Some(Arc::downgrade(&root_port) as Weak>); - let pci_device = pci_bus.child_dev(locked_root_port.base.devfn as u64); - if pci_device.is_none() { - pci_bus.child_buses.push(locked_root_port.sec_bus.clone()); - pci_bus.attach_child(locked_root_port.base.devfn as u64, root_port.clone())?; - } else { - bail!( - "Devfn {:?} has been used by {:?}", - locked_root_port.base.devfn, - pci_device.unwrap().lock().unwrap().name() - ); - } + parent_pci_bus.attach_child(locked_root_port.base.devfn as u64, root_port.clone())?; // Need to drop locked_root_port in order to register root_port instance. drop(locked_root_port); MigrationManager::register_device_instance(RootPortState::descriptor(), root_port, &name); @@ -515,11 +509,11 @@ impl PciDevOps for RootPort { /// Only set slot status to on, and no other device reset actions are implemented. fn reset(&mut self, reset_child_device: bool) -> Result<()> { if reset_child_device { - self.sec_bus - .lock() - .unwrap() + let child_bus = self.child_bus().unwrap(); + MUT_PCI_BUS!(child_bus, locked_child_bus, child_pci_bus); + child_pci_bus .reset() - .with_context(|| "Fail to reset sec_bus in root port")?; + .with_context(|| "Fail to reset child_bus in root port")?; } else { let cap_offset = self.base.config.pci_express_cap_offset; le_write_u16( @@ -657,7 +651,8 @@ impl HotplugOps for RootPort { PCI_BUS_DEVICE!(dev, locked_dev, pci_dev); let devfn = pci_dev.pci_base().devfn as u64; pci_dev.unrealize()?; - self.sec_bus.lock().unwrap().detach_child(devfn)?; + let child_bus = self.child_bus().unwrap(); + child_bus.lock().unwrap().detach_child(devfn)?; Ok(()) } } @@ -708,7 +703,7 @@ mod tests { #[test] fn test_read_config() { let pci_host = create_pci_host(); - let root_bus = Arc::downgrade(&pci_host.lock().unwrap().root_bus); + let root_bus = Arc::downgrade(&pci_host.lock().unwrap().child_bus().unwrap()); let root_port_config = RootPortConfig { addr: (1, 0), id: "pcie.1".to_string(), @@ -727,7 +722,7 @@ mod tests { #[test] fn test_write_config() { let pci_host = create_pci_host(); - let root_bus = Arc::downgrade(&pci_host.lock().unwrap().root_bus); + let root_bus = Arc::downgrade(&pci_host.lock().unwrap().child_bus().unwrap()); let root_port_config = RootPortConfig { addr: (1, 0), id: "pcie.1".to_string(), diff --git a/devices/src/usb/xhci/xhci_pci.rs b/devices/src/usb/xhci/xhci_pci.rs index e8b2e646..82d990ea 100644 --- a/devices/src/usb/xhci/xhci_pci.rs +++ b/devices/src/usb/xhci/xhci_pci.rs @@ -34,7 +34,7 @@ use crate::pci::config::{ }; use crate::pci::{init_intx, init_msix, le_write_u16, PciBus, PciDevBase, PciDevOps}; use crate::usb::UsbDevice; -use crate::{convert_bus_ref, Device, DeviceBase, PCI_BUS}; +use crate::{convert_bus_ref, Bus, Device, DeviceBase, PCI_BUS}; use address_space::{AddressRange, AddressSpace, Region, RegionIoEventFd}; use machine_manager::config::{get_pci_df, valid_id}; use machine_manager::event_loop::register_event_helper; @@ -108,7 +108,7 @@ impl XhciPciDevice { pub fn new( config: &XhciConfig, devfn: u8, - parent_bus: Weak>, + parent_bus: Weak>, mem_space: &Arc, ) -> Self { Self { diff --git a/machine/src/aarch64/pci_host_root.rs b/machine/src/aarch64/pci_host_root.rs index ec50c954..d3566f3c 100644 --- a/machine/src/aarch64/pci_host_root.rs +++ b/machine/src/aarch64/pci_host_root.rs @@ -18,8 +18,8 @@ use devices::pci::config::{ PciConfig, CLASS_CODE_HOST_BRIDGE, DEVICE_ID, PCI_CONFIG_SPACE_SIZE, PCI_VENDOR_ID_REDHAT, REVISION_ID, SUB_CLASS_CODE, VENDOR_ID, }; -use devices::pci::{le_write_u16, PciBus, PciDevBase, PciDevOps}; -use devices::{Device, DeviceBase}; +use devices::pci::{le_write_u16, PciDevBase, PciDevOps}; +use devices::{Bus, Device, DeviceBase}; use util::gen_base_func; const DEVICE_ID_PCIE_HOST: u16 = 0x0008; @@ -30,7 +30,7 @@ pub struct PciHostRoot { } impl PciHostRoot { - pub fn new(parent_bus: Weak>) -> Self { + pub fn new(parent_bus: Weak>) -> Self { Self { base: PciDevBase { base: DeviceBase::new("PCI Host Root".to_string(), false, Some(parent_bus)), diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index c525e385..f2fe637e 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -48,9 +48,11 @@ use devices::legacy::{ }; #[cfg(feature = "ramfb")] use devices::legacy::{Ramfb, RamfbConfig}; -use devices::pci::{PciDevOps, PciHost, PciIntxState}; +use devices::pci::{PciBus, PciDevOps, PciHost, PciIntxState}; use devices::sysbus::{to_sysbusdevops, SysBusDevType}; -use devices::{ICGICConfig, ICGICv3Config, GIC_IRQ_MAX, SYS_BUS_DEVICE}; +use devices::{ + convert_bus_mut, Device, ICGICConfig, ICGICv3Config, GIC_IRQ_MAX, MUT_PCI_BUS, SYS_BUS_DEVICE, +}; use hypervisor::kvm::aarch64::*; use hypervisor::kvm::*; #[cfg(feature = "ramfb")] @@ -318,7 +320,7 @@ impl StdMachine { impl StdMachineOps for StdMachine { fn init_pci_host(&self) -> Result<()> { - let root_bus = Arc::downgrade(&self.pci_host.lock().unwrap().root_bus); + let root_bus = Arc::downgrade(&self.pci_host.lock().unwrap().child_bus().unwrap()); let mmconfig_region_ops = PciHost::build_mmconfig_ops(self.pci_host.clone()); let mmconfig_region = Region::init_io_region( MEM_LAYOUT[LayoutEntryType::HighPcieEcam as usize].1, @@ -432,16 +434,17 @@ impl MachineOps for StdMachine { self.base.irq_chip = Some(locked_hypervisor.create_interrupt_controller(&intc_conf)?); self.base.irq_chip.as_ref().unwrap().realize()?; - let root_bus = &self.pci_host.lock().unwrap().root_bus; + let root_bus = &self.pci_host.lock().unwrap().child_bus().unwrap(); + MUT_PCI_BUS!(root_bus, locked_bus, root_pci_bus); let irq_manager = locked_hypervisor.create_irq_manager()?; - root_bus.lock().unwrap().msi_irq_manager = irq_manager.msi_irq_manager; + root_pci_bus.msi_irq_manager = irq_manager.msi_irq_manager; let line_irq_manager = irq_manager.line_irq_manager; if let Some(line_irq_manager) = line_irq_manager.clone() { let irq_state = Some(Arc::new(Mutex::new(PciIntxState::new( IRQ_MAP[IrqEntryType::Pcie as usize].0 as u32, line_irq_manager.clone(), )))); - root_bus.lock().unwrap().intx_state = irq_state; + root_pci_bus.intx_state = irq_state; } else { return Err(anyhow!( "Failed to create intx state: legacy irq manager is none." diff --git a/machine/src/lib.rs b/machine/src/lib.rs index fcc9f8c6..39e82b6f 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -77,7 +77,7 @@ use devices::usb::UsbDevice; use devices::InterruptController; use devices::ScsiBus::get_scsi_key; use devices::ScsiDisk::{ScsiDevConfig, ScsiDevice}; -use devices::{Bus, Device, PCI_BUS_DEVICE, SYS_BUS_DEVICE}; +use devices::{convert_bus_ref, Bus, Device, PCI_BUS, PCI_BUS_DEVICE, SYS_BUS_DEVICE}; use hypervisor::{kvm::KvmHypervisor, test::TestHypervisor, HypervisorOps}; #[cfg(feature = "usb_camera")] use machine_manager::config::get_cameradev_by_id; @@ -931,8 +931,10 @@ pub trait MachineOps: MachineLifecycle { check_arg_exist!(("bus", dev_cfg.bus), ("addr", dev_cfg.addr)); let bdf = PciBdf::new(dev_cfg.bus.clone().unwrap(), dev_cfg.addr.unwrap()); let multi_func = dev_cfg.multifunction.unwrap_or_default(); - let root_bus = self.get_pci_host()?.lock().unwrap().root_bus.clone(); - let msi_irq_manager = root_bus.lock().unwrap().msi_irq_manager.clone(); + let root_bus = self.get_pci_host()?.lock().unwrap().child_bus().unwrap(); + PCI_BUS!(root_bus, locked_bus, root_pci_bus); + let msi_irq_manager = root_pci_bus.msi_irq_manager.clone(); + drop(locked_bus); let need_irqfd = msi_irq_manager.as_ref().unwrap().irqfd_enable(); self.add_virtio_pci_device(&dev_cfg.id, &bdf, device, multi_func, need_irqfd) .with_context(|| "Failed to add pci fs device")?; @@ -997,7 +999,9 @@ pub trait MachineOps: MachineLifecycle { if name.is_empty() { bail!("Device id is empty"); } - if PciBus::find_attached_bus(&pci_host.lock().unwrap().root_bus, name).is_some() { + if PciBus::find_attached_bus(&pci_host.lock().unwrap().child_bus().unwrap(), name) + .is_some() + { bail!("Device id {} existed", name); } if self.check_id_existed_in_xhci(name).unwrap_or_default() { @@ -1446,9 +1450,9 @@ pub trait MachineOps: MachineLifecycle { Ok(()) } - fn get_devfn_and_parent_bus(&mut self, bdf: &PciBdf) -> Result<(u8, Weak>)> { + fn get_devfn_and_parent_bus(&mut self, bdf: &PciBdf) -> Result<(u8, Weak>)> { let pci_host = self.get_pci_host()?; - let bus = pci_host.lock().unwrap().root_bus.clone(); + let bus = pci_host.lock().unwrap().child_bus().unwrap().clone(); let pci_bus = PciBus::find_bus_by_name(&bus, &bdf.bus); if pci_bus.is_none() { bail!("Parent bus :{} not found", &bdf.bus); @@ -1463,7 +1467,7 @@ pub trait MachineOps: MachineLifecycle { let bdf = PciBdf::new(dev_cfg.bus.clone(), dev_cfg.addr); let (_, parent_bus) = self.get_devfn_and_parent_bus(&bdf)?; let pci_host = self.get_pci_host()?; - let bus = pci_host.lock().unwrap().root_bus.clone(); + let bus = pci_host.lock().unwrap().child_bus().unwrap().clone(); if PciBus::find_bus_by_name(&bus, &dev_cfg.id).is_some() { bail!("ID {} already exists.", &dev_cfg.id); } @@ -1504,7 +1508,7 @@ pub trait MachineOps: MachineLifecycle { fn reset_bus(&mut self, dev_id: &str) -> Result<()> { let pci_host = self.get_pci_host()?; let locked_pci_host = pci_host.lock().unwrap(); - let bus = PciBus::find_attached_bus(&locked_pci_host.root_bus, dev_id) + let bus = PciBus::find_attached_bus(&locked_pci_host.child_bus().unwrap(), dev_id) .with_context(|| format!("Bus not found, dev id {}", dev_id))? .0; let locked_bus = bus.lock().unwrap(); @@ -1520,7 +1524,8 @@ pub trait MachineOps: MachineLifecycle { let name = locked_dev.name(); drop(locked_dev); let mut devfn = None; - let locked_bus = locked_pci_host.root_bus.lock().unwrap(); + let bus = locked_pci_host.child_bus().unwrap(); + let locked_bus = bus.lock().unwrap(); for (id, dev) in &locked_bus.child_devices() { if dev.lock().unwrap().name() == name { devfn = Some(*id); @@ -1710,9 +1715,10 @@ pub trait MachineOps: MachineLifecycle { let bdf = get_pci_bdf(cfg_args).ok()?; let devfn = (bdf.addr.0 << 3) + bdf.addr.1; let pci_host = self.get_pci_host().ok()?; - let root_bus = pci_host.lock().unwrap().root_bus.clone(); - if let Some(pci_bus) = PciBus::find_bus_by_name(&root_bus, &bdf.bus) { - return pci_bus.lock().unwrap().get_device(0, devfn); + let root_bus = pci_host.lock().unwrap().child_bus().unwrap().clone(); + if let Some(bus) = PciBus::find_bus_by_name(&root_bus, &bdf.bus) { + PCI_BUS!(bus, locked_bus, pci_bus); + return pci_bus.get_device(0, devfn); } else { return None; } diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index 0a116b3b..ee6d2cd1 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -55,6 +55,7 @@ use devices::legacy::FwCfgOps; use devices::misc::scream::set_record_authority; use devices::pci::hotplug::{handle_plug, handle_unplug_pci_request}; use devices::pci::{PciBus, PciHost}; +use devices::Device; #[cfg(feature = "usb_camera")] use machine_manager::config::get_cameradev_config; #[cfg(target_arch = "aarch64")] @@ -1276,7 +1277,9 @@ impl DeviceInterface for StdMachine { // It's safe to call get_pci_host().unwrap() because it has been checked before. let locked_pci_host = self.get_pci_host().unwrap().lock().unwrap(); - if let Some((bus, dev)) = PciBus::find_attached_bus(&locked_pci_host.root_bus, &args.id) { + if let Some((bus, dev)) = + PciBus::find_attached_bus(&locked_pci_host.child_bus().unwrap(), &args.id) + { match handle_plug(&bus, &dev) { Ok(()) => Response::create_empty_response(), Err(e) => { @@ -1313,7 +1316,9 @@ impl DeviceInterface for StdMachine { }; let locked_pci_host = pci_host.lock().unwrap(); - if let Some((bus, dev)) = PciBus::find_attached_bus(&locked_pci_host.root_bus, &device_id) { + if let Some((bus, dev)) = + PciBus::find_attached_bus(&locked_pci_host.child_bus().unwrap(), &device_id) + { return match handle_unplug_pci_request(&bus, &dev) { Ok(()) => { let locked_dev = dev.lock().unwrap(); diff --git a/machine/src/x86_64/ich9_lpc.rs b/machine/src/x86_64/ich9_lpc.rs index 1507fe8b..e93f85e4 100644 --- a/machine/src/x86_64/ich9_lpc.rs +++ b/machine/src/x86_64/ich9_lpc.rs @@ -26,8 +26,8 @@ use devices::pci::config::{ PciConfig, CLASS_CODE_ISA_BRIDGE, DEVICE_ID, HEADER_TYPE, HEADER_TYPE_BRIDGE, HEADER_TYPE_MULTIFUNC, PCI_CONFIG_SPACE_SIZE, SUB_CLASS_CODE, VENDOR_ID, }; -use devices::pci::{le_write_u16, le_write_u32, PciBus, PciDevBase, PciDevOps}; -use devices::{Device, DeviceBase}; +use devices::pci::{le_write_u16, le_write_u32, PciDevBase, PciDevOps}; +use devices::{Bus, Device, DeviceBase}; use util::byte_code::ByteCode; use util::gen_base_func; use util::num_ops::ranges_overlap; @@ -57,7 +57,7 @@ pub struct LPCBridge { impl LPCBridge { pub fn new( - parent_bus: Weak>, + parent_bus: Weak>, sys_io: Arc, reset_req: Arc, shutdown_req: Arc, diff --git a/machine/src/x86_64/mch.rs b/machine/src/x86_64/mch.rs index b8a1679c..9ec0d110 100644 --- a/machine/src/x86_64/mch.rs +++ b/machine/src/x86_64/mch.rs @@ -24,7 +24,7 @@ use devices::pci::{ }, le_read_u64, le_write_u16, PciBus, PciDevBase, PciDevOps, }; -use devices::{convert_bus_ref, Device, DeviceBase, PCI_BUS}; +use devices::{convert_bus_ref, Bus, Device, DeviceBase, PCI_BUS}; use util::gen_base_func; use util::num_ops::ranges_overlap; @@ -51,7 +51,7 @@ pub struct Mch { impl Mch { pub fn new( - parent_bus: Weak>, + parent_bus: Weak>, mmconfig_region: Region, mmconfig_ops: RegionOps, ) -> Self { diff --git a/machine/src/x86_64/standard.rs b/machine/src/x86_64/standard.rs index 68cbf8a5..be3067c6 100644 --- a/machine/src/x86_64/standard.rs +++ b/machine/src/x86_64/standard.rs @@ -36,7 +36,8 @@ use devices::legacy::{ error::LegacyError as DevErrorKind, FwCfgEntryType, FwCfgIO, FwCfgOps, PFlash, Serial, RTC, SERIAL_ADDR, }; -use devices::pci::{PciDevOps, PciHost}; +use devices::pci::{PciBus, PciDevOps, PciHost}; +use devices::{convert_bus_mut, Device, MUT_PCI_BUS}; use hypervisor::kvm::x86_64::*; use hypervisor::kvm::*; #[cfg(feature = "gtk")] @@ -179,7 +180,7 @@ impl StdMachine { } fn init_ich9_lpc(&self, vm: Arc>) -> Result<()> { - let root_bus = Arc::downgrade(&self.pci_host.lock().unwrap().root_bus); + let root_bus = Arc::downgrade(&self.pci_host.lock().unwrap().child_bus().unwrap()); let ich = ich9_lpc::LPCBridge::new( root_bus, self.base.sys_io.clone(), @@ -235,7 +236,7 @@ impl StdMachine { impl StdMachineOps for StdMachine { fn init_pci_host(&self) -> Result<()> { - let root_bus = Arc::downgrade(&self.pci_host.lock().unwrap().root_bus); + let root_bus = Arc::downgrade(&self.pci_host.lock().unwrap().child_bus().unwrap()); let mmconfig_region_ops = PciHost::build_mmconfig_ops(self.pci_host.clone()); let mmconfig_region = Region::init_io_region( MEM_LAYOUT[LayoutEntryType::PcieEcam as usize].1, @@ -394,9 +395,10 @@ impl MachineOps for StdMachine { let mut locked_hypervisor = hypervisor.lock().unwrap(); locked_hypervisor.create_interrupt_controller()?; - let root_bus = &self.pci_host.lock().unwrap().root_bus; + let child_bus = self.pci_host.lock().unwrap().child_bus().unwrap(); + MUT_PCI_BUS!(child_bus, locked_bus, pci_bus); let irq_manager = locked_hypervisor.create_irq_manager()?; - root_bus.lock().unwrap().msi_irq_manager = irq_manager.msi_irq_manager; + pci_bus.msi_irq_manager = irq_manager.msi_irq_manager; self.base.sysbus.lock().unwrap().irq_manager = irq_manager.line_irq_manager; Ok(()) diff --git a/vfio/src/vfio_pci.rs b/vfio/src/vfio_pci.rs index dbe0d2a4..3ae3cae8 100644 --- a/vfio/src/vfio_pci.rs +++ b/vfio/src/vfio_pci.rs @@ -43,7 +43,7 @@ use devices::pci::{ init_multifunction, le_read_u16, le_read_u32, le_write_u16, le_write_u32, pci_ext_cap_id, pci_ext_cap_next, pci_ext_cap_ver, MsiVector, PciBus, PciDevBase, PciDevOps, }; -use devices::{convert_bus_ref, Device, DeviceBase, PCI_BUS}; +use devices::{convert_bus_ref, Bus, Device, DeviceBase, PCI_BUS}; use machine_manager::config::{get_pci_df, parse_bool, valid_id}; use util::gen_base_func; use util::loop_context::create_new_eventfd; @@ -125,7 +125,7 @@ impl VfioPciDevice { vfio_device: Arc>, devfn: u8, name: String, - parent_bus: Weak>, + parent_bus: Weak>, multi_func: bool, mem_as: Arc, ) -> Self { diff --git a/virtio/src/transport/virtio_pci.rs b/virtio/src/transport/virtio_pci.rs index 5e8114ec..ec320904 100644 --- a/virtio/src/transport/virtio_pci.rs +++ b/virtio/src/transport/virtio_pci.rs @@ -46,7 +46,7 @@ use devices::pci::{ config::PciConfig, init_intx, init_msix, init_multifunction, le_write_u16, le_write_u32, PciBus, PciDevBase, PciDevOps, PciError, }; -use devices::{convert_bus_ref, Device, DeviceBase, PCI_BUS}; +use devices::{convert_bus_ref, Bus, Device, DeviceBase, PCI_BUS}; #[cfg(feature = "virtio_gpu")] use machine_manager::config::VIRTIO_GPU_ENABLE_BAR0_SIZE; use migration::{DeviceStateDesc, FieldDesc, MigrationHook, MigrationManager, StateTransfer}; @@ -325,7 +325,7 @@ impl VirtioPciDevice { devfn: u8, sys_mem: Arc, device: Arc>, - parent_bus: Weak>, + parent_bus: Weak>, multi_func: bool, need_irqfd: bool, ) -> Self { @@ -1458,7 +1458,7 @@ mod tests { 0, sys_mem, virtio_dev.clone(), - Arc::downgrade(&parent_bus), + Arc::downgrade(&(parent_bus.clone() as Arc>)), multi_func, false, ); -- Gitee From bba70a2ec476f15f0eea732266d1b3bf72c0cdbf Mon Sep 17 00:00:00 2001 From: Li Huachao Date: Thu, 18 Jul 2024 18:54:57 +0800 Subject: [PATCH 198/489] Memory: change memory read/write scopes trace to events --- address_space/src/address_space.rs | 14 ++++---------- trace/trace_info/memory.toml | 8 ++++---- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/address_space/src/address_space.rs b/address_space/src/address_space.rs index d34dd59e..d19e6c3d 100644 --- a/address_space/src/address_space.rs +++ b/address_space/src/address_space.rs @@ -611,7 +611,7 @@ impl AddressSpace { /// /// Return Error if the `addr` is not mapped. pub fn read(&self, dst: &mut dyn std::io::Write, addr: GuestAddress, count: u64) -> Result<()> { - trace::trace_scope_start!(address_space_read, args = (&addr, count)); + trace::address_space_read(&addr, count); let view = self.flat_view.load(); view.read(dst, addr, count)?; @@ -630,7 +630,7 @@ impl AddressSpace { /// /// Return Error if the `addr` is not mapped. pub fn write(&self, src: &mut dyn std::io::Read, addr: GuestAddress, count: u64) -> Result<()> { - trace::trace_scope_start!(address_space_write, args = (&addr, count)); + trace::address_space_write(&addr, count); let view = self.flat_view.load(); let mut buf = Vec::new(); @@ -698,10 +698,7 @@ impl AddressSpace { /// # Note /// To use this method, it is necessary to implement `ByteCode` trait for your object. pub fn write_object_direct(&self, data: &T, host_addr: u64) -> Result<()> { - trace::trace_scope_start!( - address_space_write_direct, - args = (host_addr, std::mem::size_of::()) - ); + trace::address_space_write_direct(host_addr, std::mem::size_of::()); // Mark vmm dirty page manually if live migration is active. MigrationManager::mark_dirty_log(host_addr, data.as_bytes().len() as u64); @@ -741,10 +738,7 @@ impl AddressSpace { /// # Note /// To use this method, it is necessary to implement `ByteCode` trait for your object. pub fn read_object_direct(&self, host_addr: u64) -> Result { - trace::trace_scope_start!( - address_space_read_direct, - args = (host_addr, std::mem::size_of::()) - ); + trace::address_space_read_direct(host_addr, std::mem::size_of::()); let mut obj = T::default(); let mut dst = obj.as_mut_bytes(); // SAFETY: host_addr is managed by address_space, it has been verified for legality. diff --git a/trace/trace_info/memory.toml b/trace/trace_info/memory.toml index 4ff485a5..1a832e58 100644 --- a/trace/trace_info/memory.toml +++ b/trace/trace_info/memory.toml @@ -1,22 +1,22 @@ -[[scopes]] +[[events]] name = "address_space_read" args = "addr: &dyn fmt::Debug, count: u64" message = "Memory: flatview_read addr {:?}, count {}" enabled = true -[[scopes]] +[[events]] name = "address_space_write" args = "addr: &dyn fmt::Debug, count: u64" message = "Memory: flatview_write addr {:?}, count {}" enabled = true -[[scopes]] +[[events]] name = "address_space_read_direct" args = "host_addr: u64, count: usize" message = "Memory: address_space_read_direct host_addr {}, count {}" enabled = true -[[scopes]] +[[events]] name = "address_space_write_direct" args = "host_addr: u64, count: usize" message = "Memory: address_space_write_direct host_addr {}, count {}" -- Gitee From bb46a93410f1b1679bfbe2ae095dde8fbb4ff4f2 Mon Sep 17 00:00:00 2001 From: Li Huachao Date: Thu, 18 Jul 2024 19:00:39 +0800 Subject: [PATCH 199/489] Balloon: change balloon scopes trace to events --- trace/trace_info/virtio.toml | 10 ++-------- virtio/src/device/balloon.rs | 5 ++--- 2 files changed, 4 insertions(+), 11 deletions(-) diff --git a/trace/trace_info/virtio.toml b/trace/trace_info/virtio.toml index 1f8ea241..d30ba1f7 100644 --- a/trace/trace_info/virtio.toml +++ b/trace/trace_info/virtio.toml @@ -298,20 +298,14 @@ args = "" message = "Vhost: deleting mem region failed: not matched." enabled = true -[[scopes]] +[[events]] name = "auto_msg_evt_handler" args = "" message = "Balloon: handle auto balloon message" enabled = true -[[scopes]] +[[events]] name = "reporting_evt_handler" args = "" message = "Balloon: handle fpr message" enabled = true - -[[scopes]] -name = "process_balloon_queue" -args = "" -message = "Balloon: handle normal balloon message" -enabled = true diff --git a/virtio/src/device/balloon.rs b/virtio/src/device/balloon.rs index 97724ece..7240a331 100644 --- a/virtio/src/device/balloon.rs +++ b/virtio/src/device/balloon.rs @@ -610,7 +610,6 @@ impl BalloonIoHandler { /// if `req_type` is `BALLOON_INFLATE_EVENT`, then inflate the balloon, otherwise, deflate the /// balloon. fn process_balloon_queue(&mut self, req_type: bool) -> Result<()> { - trace::trace_scope_start!(process_balloon_queue); let queue = if req_type { trace::virtio_receive_request("Balloon".to_string(), "to inflate".to_string()); &self.inf_queue @@ -647,7 +646,7 @@ impl BalloonIoHandler { } fn reporting_evt_handler(&mut self) -> Result<()> { - trace::trace_scope_start!(reporting_evt_handler); + trace::reporting_evt_handler(); let queue = self .report_queue .as_ref() @@ -682,7 +681,7 @@ impl BalloonIoHandler { } fn auto_msg_evt_handler(&mut self) -> Result<()> { - trace::trace_scope_start!(auto_msg_evt_handler); + trace::auto_msg_evt_handler(); let queue = self .msg_queue .as_ref() -- Gitee From e85cb4513b7f24b9e2f8a53756efa44031ba11d9 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sun, 14 Jul 2024 12:21:58 +0800 Subject: [PATCH 200/489] clippy: fix clippy warnings. Fix clippy warning: error: casting to the same type is unnecessary (usize -> usize) --> image/src/cmdline.rs:73:28 | 73 | let str = args[idx as usize].clone(); | ^^^^^^^^^^^^ help: try: idx | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast = note: -D clippy::unnecessary-cast implied by -D warnings Signed-off-by: liuxiangdong --- image/src/cmdline.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/image/src/cmdline.rs b/image/src/cmdline.rs index 8cf7c392..8235ff5d 100644 --- a/image/src/cmdline.rs +++ b/image/src/cmdline.rs @@ -70,7 +70,7 @@ impl ArgsParse { let mut pre_opt = (0, "".to_string()); for idx in 0..len { - let str = args[idx as usize].clone(); + let str = args[idx].clone(); if str.starts_with('-') && str.len() > 1 { if !pre_opt.1.is_empty() { bail!("missing argument for option '{}'", pre_opt.1); -- Gitee From e6092199602a14363a0f869523575df3b4eb7448 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Fri, 12 Jul 2024 22:49:32 +0800 Subject: [PATCH 201/489] devices: unified bus/device reset function Move reset function to Bus/Device trait to unify reset function: 1. Bus reset means all devices attached to this bus should reset. 2. Device reset is the device's own logic. Signed-off-by: liuxiangdong --- devices/src/legacy/fwcfg.rs | 20 +++++----- devices/src/legacy/pflash.rs | 24 ++++++------ devices/src/legacy/ramfb.rs | 10 ++--- devices/src/legacy/rtc.rs | 14 +++---- devices/src/lib.rs | 16 ++++++++ devices/src/pci/bus.rs | 40 +++++++++---------- devices/src/pci/demo_device/mod.rs | 9 ++--- devices/src/pci/host.rs | 24 ++++++------ devices/src/pci/mod.rs | 5 --- devices/src/pci/root_port.rs | 62 +++++++++++++++--------------- devices/src/sysbus/mod.rs | 4 -- devices/src/usb/xhci/xhci_pci.rs | 16 ++++---- machine/src/lib.rs | 30 +++++++-------- vfio/src/vfio_pci.rs | 12 +++--- virtio/src/transport/virtio_pci.rs | 26 ++++++------- 15 files changed, 157 insertions(+), 155 deletions(-) diff --git a/devices/src/legacy/fwcfg.rs b/devices/src/legacy/fwcfg.rs index dfd20dfb..c6016497 100644 --- a/devices/src/legacy/fwcfg.rs +++ b/devices/src/legacy/fwcfg.rs @@ -936,6 +936,11 @@ impl FwCfgOps for FwCfgMem { #[cfg(target_arch = "aarch64")] impl Device for FwCfgMem { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); + + fn reset(&mut self, _reset_child_device: bool) -> Result<()> { + self.fwcfg.select_entry(FwCfgEntryType::Signature as u16); + Ok(()) + } } #[cfg(target_arch = "aarch64")] @@ -992,11 +997,6 @@ impl SysBusDevOps for FwCfgMem { .set_sys(-1, region_base, region_size, region_name); Ok(()) } - - fn reset(&mut self) -> Result<()> { - self.fwcfg.select_entry(FwCfgEntryType::Signature as u16); - Ok(()) - } } #[allow(clippy::upper_case_acronyms)] @@ -1095,6 +1095,11 @@ impl FwCfgOps for FwCfgIO { #[cfg(target_arch = "x86_64")] impl Device for FwCfgIO { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); + + fn reset(&mut self, _reset_child_device: bool) -> Result<()> { + self.fwcfg.select_entry(FwCfgEntryType::Signature as u16); + Ok(()) + } } #[cfg(target_arch = "x86_64")] @@ -1154,11 +1159,6 @@ impl SysBusDevOps for FwCfgIO { .set_sys(-1, region_base, region_size, region_name); Ok(()) } - - fn reset(&mut self) -> Result<()> { - self.fwcfg.select_entry(FwCfgEntryType::Signature as u16); - Ok(()) - } } pub trait FwCfgOps: Send + Sync { diff --git a/devices/src/legacy/pflash.rs b/devices/src/legacy/pflash.rs index c12fb251..c4b1b1de 100644 --- a/devices/src/legacy/pflash.rs +++ b/devices/src/legacy/pflash.rs @@ -699,6 +699,18 @@ impl PFlash { impl Device for PFlash { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); + + fn reset(&mut self, _reset_child_device: bool) -> Result<()> { + self.rom + .as_ref() + .unwrap() + .set_rom_device_romd(true) + .with_context(|| "Fail to set PFlash rom region read only")?; + self.cmd = 0x00; + self.write_cycle = 0; + self.status = 0x80; + Ok(()) + } } impl SysBusDevOps for PFlash { @@ -899,18 +911,6 @@ impl SysBusDevOps for PFlash { .set_sys(0, region_base, region_size, region_name); Ok(()) } - - fn reset(&mut self) -> Result<()> { - self.rom - .as_ref() - .unwrap() - .set_rom_device_romd(true) - .with_context(|| "Fail to set PFlash rom region read only")?; - self.cmd = 0x00; - self.write_cycle = 0; - self.status = 0x80; - Ok(()) - } } impl AmlBuilder for PFlash { diff --git a/devices/src/legacy/ramfb.rs b/devices/src/legacy/ramfb.rs index 0394c7b2..7bb501b5 100644 --- a/devices/src/legacy/ramfb.rs +++ b/devices/src/legacy/ramfb.rs @@ -260,6 +260,11 @@ impl Ramfb { impl Device for Ramfb { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); + + fn reset(&mut self, _reset_child_device: bool) -> Result<()> { + self.ramfb_state.reset_ramfb_state(); + Ok(()) + } } impl SysBusDevOps for Ramfb { @@ -274,11 +279,6 @@ impl SysBusDevOps for Ramfb { error!("Ramfb can not be written!"); false } - - fn reset(&mut self) -> Result<()> { - self.ramfb_state.reset_ramfb_state(); - Ok(()) - } } impl AmlBuilder for Ramfb { diff --git a/devices/src/legacy/rtc.rs b/devices/src/legacy/rtc.rs index c24e2752..6860a1e2 100644 --- a/devices/src/legacy/rtc.rs +++ b/devices/src/legacy/rtc.rs @@ -346,6 +346,13 @@ impl RTC { impl Device for RTC { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); + + fn reset(&mut self, _reset_child_device: bool) -> Result<()> { + self.cmos_data.fill(0); + self.init_rtc_reg(); + self.set_memory(self.mem_size, self.gap_start); + Ok(()) + } } impl SysBusDevOps for RTC { @@ -372,13 +379,6 @@ impl SysBusDevOps for RTC { self.write_data(data) } } - - fn reset(&mut self) -> Result<()> { - self.cmos_data.fill(0); - self.init_rtc_reg(); - self.set_memory(self.mem_size, self.gap_start); - Ok(()) - } } impl AmlBuilder for RTC { diff --git a/devices/src/lib.rs b/devices/src/lib.rs index 1cb361b8..98aea03f 100644 --- a/devices/src/lib.rs +++ b/devices/src/lib.rs @@ -105,6 +105,10 @@ pub trait Device: Any + AsAny + Send + Sync { fn child_bus(&self) -> Option>> { self.device_base().child.clone() } + + fn reset(&mut self, _reset_child_device: bool) -> Result<()> { + Ok(()) + } } /// Macro `convert_device_ref!`: Convert from Arc> to &$device_type. @@ -227,6 +231,18 @@ pub trait Bus: Any + AsAny + Send + Sync { Ok(()) } + + /// Bus reset means that all devices attached to this bus should reset. + fn reset(&self) -> Result<()> { + for dev in self.child_devices().values() { + let mut locked_dev = dev.lock().unwrap(); + locked_dev + .reset(true) + .with_context(|| format!("Failed to reset device {}", locked_dev.name()))?; + } + + Ok(()) + } } /// Macro `convert_bus_ref!`: Convert from Arc> to &$bus_type. diff --git a/devices/src/pci/bus.rs b/devices/src/pci/bus.rs index 7bf02021..0ee81116 100644 --- a/devices/src/pci/bus.rs +++ b/devices/src/pci/bus.rs @@ -46,10 +46,6 @@ pub struct PciBus { pub msi_irq_manager: Option>, } -impl Bus for PciBus { - gen_base_func!(bus_base, bus_base_mut, BusBase, base); -} - /// Convert from Arc> to &mut PciBus. #[macro_export] macro_rules! MUT_PCI_BUS { @@ -66,6 +62,26 @@ macro_rules! PCI_BUS { }; } +impl Bus for PciBus { + gen_base_func!(bus_base, bus_base_mut, BusBase, base); + + fn reset(&self) -> Result<()> { + for dev in self.child_devices().values() { + PCI_BUS_DEVICE!(dev, locked_dev, pci_dev); + pci_dev + .reset(false) + .with_context(|| format!("Fail to reset pci dev {}", pci_dev.name()))?; + + if let Some(bus) = pci_dev.child_bus() { + MUT_PCI_BUS!(bus, locked_bus, pci_bus); + pci_bus.reset().with_context(|| "Fail to reset child bus")?; + } + } + + Ok(()) + } +} + impl PciBus { /// Create new bus entity. /// @@ -225,22 +241,6 @@ impl PciBus { Ok(()) } - pub fn reset(&mut self) -> Result<()> { - for dev in self.child_devices().values() { - PCI_BUS_DEVICE!(dev, locked_dev, pci_dev); - pci_dev - .reset(false) - .with_context(|| format!("Fail to reset pci dev {}", pci_dev.name()))?; - - if let Some(bus) = pci_dev.child_bus() { - MUT_PCI_BUS!(bus, locked_bus, pci_bus); - pci_bus.reset().with_context(|| "Fail to reset child bus")?; - } - } - - Ok(()) - } - fn is_during_reset(&self) -> bool { let mut data = vec![0_u8; 2]; self.get_bridge_control_reg(BRIDGE_CONTROL as usize + 1, &mut data); diff --git a/devices/src/pci/demo_device/mod.rs b/devices/src/pci/demo_device/mod.rs index 77fcfd30..b78ff617 100644 --- a/devices/src/pci/demo_device/mod.rs +++ b/devices/src/pci/demo_device/mod.rs @@ -186,6 +186,10 @@ const CLASS_CODE_DEMO: u16 = 0xEE; impl Device for DemoDev { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); + + fn reset(&mut self, _reset_child_device: bool) -> Result<()> { + self.base.config.reset_common_regs() + } } impl PciDevOps for DemoDev { @@ -224,11 +228,6 @@ impl PciDevOps for DemoDev { Some(&pci_bus.mem_region), ); } - - /// Reset device - fn reset(&mut self, _reset_child_device: bool) -> Result<()> { - self.base.config.reset_common_regs() - } } pub trait DeviceTypeOperation: Send { diff --git a/devices/src/pci/host.rs b/devices/src/pci/host.rs index 6f1a2559..28481157 100644 --- a/devices/src/pci/host.rs +++ b/devices/src/pci/host.rs @@ -242,6 +242,18 @@ impl PciHost { impl Device for PciHost { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); + + fn reset(&mut self, _reset_child_device: bool) -> Result<()> { + let root_bus = self.child_bus().unwrap(); + for dev in root_bus.lock().unwrap().child_devices().values() { + PCI_BUS_DEVICE!(dev, locked_dev, pci_dev); + pci_dev + .reset(true) + .with_context(|| "Fail to reset pci device under pci host")?; + } + + Ok(()) + } } impl SysBusDevOps for PciHost { @@ -280,18 +292,6 @@ impl SysBusDevOps for PciHost { None => true, } } - - fn reset(&mut self) -> Result<()> { - let root_bus = self.child_bus().unwrap(); - for dev in root_bus.lock().unwrap().child_devices().values() { - PCI_BUS_DEVICE!(dev, locked_dev, pci_dev); - pci_dev - .reset(true) - .with_context(|| "Fail to reset pci device under pci host")?; - } - - Ok(()) - } } #[cfg(target_arch = "x86_64")] diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs index cbb95263..59f295f5 100644 --- a/devices/src/pci/mod.rs +++ b/devices/src/pci/mod.rs @@ -213,11 +213,6 @@ pub trait PciDevOps: Device + Send { ((bus_num as u16) << bus_shift) | (devfn as u16) } - /// Reset device - fn reset(&mut self, _reset_child_device: bool) -> Result<()> { - Ok(()) - } - /// Get the path of the PCI bus where the device resides. fn get_parent_dev_path(&self, parent_bus: Arc>) -> String { PCI_BUS!(parent_bus, locked_bus, pci_bus); diff --git a/devices/src/pci/root_port.rs b/devices/src/pci/root_port.rs index aceea6fa..5c978646 100644 --- a/devices/src/pci/root_port.rs +++ b/devices/src/pci/root_port.rs @@ -339,6 +339,37 @@ impl RootPort { impl Device for RootPort { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); + + /// Only set slot status to on, and no other device reset actions are implemented. + fn reset(&mut self, reset_child_device: bool) -> Result<()> { + if reset_child_device { + let child_bus = self.child_bus().unwrap(); + MUT_PCI_BUS!(child_bus, locked_child_bus, child_pci_bus); + child_pci_bus + .reset() + .with_context(|| "Fail to reset child_bus in root port")?; + } else { + let cap_offset = self.base.config.pci_express_cap_offset; + le_write_u16( + &mut self.base.config.config, + (cap_offset + PCI_EXP_SLTSTA) as usize, + PCI_EXP_SLTSTA_PDS, + )?; + le_write_u16( + &mut self.base.config.config, + (cap_offset + PCI_EXP_SLTCTL) as usize, + !PCI_EXP_SLTCTL_PCC | PCI_EXP_SLTCTL_PWR_IND_ON, + )?; + le_write_u16( + &mut self.base.config.config, + (cap_offset + PCI_EXP_LNKSTA) as usize, + PCI_EXP_LNKSTA_DLLLA, + )?; + } + + self.base.config.reset_bridge_regs()?; + self.base.config.reset() + } } /// Convert from Arc> to &mut RootPort. @@ -506,37 +537,6 @@ impl PciDevOps for RootPort { self.do_unplug(offset, data, old_ctl, old_status); } - /// Only set slot status to on, and no other device reset actions are implemented. - fn reset(&mut self, reset_child_device: bool) -> Result<()> { - if reset_child_device { - let child_bus = self.child_bus().unwrap(); - MUT_PCI_BUS!(child_bus, locked_child_bus, child_pci_bus); - child_pci_bus - .reset() - .with_context(|| "Fail to reset child_bus in root port")?; - } else { - let cap_offset = self.base.config.pci_express_cap_offset; - le_write_u16( - &mut self.base.config.config, - (cap_offset + PCI_EXP_SLTSTA) as usize, - PCI_EXP_SLTSTA_PDS, - )?; - le_write_u16( - &mut self.base.config.config, - (cap_offset + PCI_EXP_SLTCTL) as usize, - !PCI_EXP_SLTCTL_PCC | PCI_EXP_SLTCTL_PWR_IND_ON, - )?; - le_write_u16( - &mut self.base.config.config, - (cap_offset + PCI_EXP_LNKSTA) as usize, - PCI_EXP_LNKSTA_DLLLA, - )?; - } - - self.base.config.reset_bridge_regs()?; - self.base.config.reset() - } - fn get_dev_path(&self) -> Option { let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); let parent_dev_path = self.get_parent_dev_path(parent_bus); diff --git a/devices/src/sysbus/mod.rs b/devices/src/sysbus/mod.rs index 76a190e0..a436f779 100644 --- a/devices/src/sysbus/mod.rs +++ b/devices/src/sysbus/mod.rs @@ -331,10 +331,6 @@ pub trait SysBusDevOps: Device + Send + AmlBuilder { ) }); } - - fn reset(&mut self) -> Result<()> { - Ok(()) - } } /// Convert from Arc> to &mut dyn SysBusDevOps. diff --git a/devices/src/usb/xhci/xhci_pci.rs b/devices/src/usb/xhci/xhci_pci.rs index 82d990ea..e0ccbf6d 100644 --- a/devices/src/usb/xhci/xhci_pci.rs +++ b/devices/src/usb/xhci/xhci_pci.rs @@ -238,6 +238,14 @@ impl XhciPciDevice { impl Device for XhciPciDevice { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); + + fn reset(&mut self, _reset_child_device: bool) -> Result<()> { + self.xhci.lock().unwrap().reset(); + + self.base.config.reset()?; + + Ok(()) + } } impl PciDevOps for XhciPciDevice { @@ -361,14 +369,6 @@ impl PciDevOps for XhciPciDevice { Some(&pci_bus.mem_region), ); } - - fn reset(&mut self, _reset_child_device: bool) -> Result<()> { - self.xhci.lock().unwrap().reset(); - - self.base.config.reset()?; - - Ok(()) - } } struct DoorbellHandler { diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 39e82b6f..62f01f69 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -55,14 +55,12 @@ use devices::misc::scream::{Scream, ScreamConfig}; #[cfg(feature = "demo_device")] use devices::pci::demo_device::{DemoDev, DemoDevConfig}; use devices::pci::{ - devices_register_pcidevops_type, register_pcidevops_type, to_pcidevops, PciBus, PciDevOps, - PciHost, RootPort, RootPortConfig, + devices_register_pcidevops_type, register_pcidevops_type, PciBus, PciDevOps, PciHost, RootPort, + RootPortConfig, }; use devices::smbios::smbios_table::{build_smbios_ep30, SmbiosTable}; use devices::smbios::{SMBIOS_ANCHOR_FILE, SMBIOS_TABLE_FILE}; -use devices::sysbus::{ - devices_register_sysbusdevops_type, to_sysbusdevops, SysBus, SysBusDevOps, SysBusDevType, -}; +use devices::sysbus::{devices_register_sysbusdevops_type, to_sysbusdevops, SysBus, SysBusDevType}; #[cfg(feature = "usb_camera")] use devices::usb::camera::{UsbCamera, UsbCameraConfig}; use devices::usb::keyboard::{UsbKeyboard, UsbKeyboardConfig}; @@ -77,7 +75,7 @@ use devices::usb::UsbDevice; use devices::InterruptController; use devices::ScsiBus::get_scsi_key; use devices::ScsiDisk::{ScsiDevConfig, ScsiDevice}; -use devices::{convert_bus_ref, Bus, Device, PCI_BUS, PCI_BUS_DEVICE, SYS_BUS_DEVICE}; +use devices::{convert_bus_ref, Bus, Device, PCI_BUS, SYS_BUS_DEVICE}; use hypervisor::{kvm::KvmHypervisor, test::TestHypervisor, HypervisorOps}; #[cfg(feature = "usb_camera")] use machine_manager::config::get_cameradev_by_id; @@ -957,18 +955,15 @@ pub trait MachineOps: MachineLifecycle { } fn reset_all_devices(&mut self) -> Result<()> { - for dev in self.get_sysbus_devices().values() { - SYS_BUS_DEVICE!(dev, locked_dev, sysbusdev); - sysbusdev - .reset() - .with_context(|| "Fail to reset sysbus device")?; - } + let sysbus = self.machine_base().sysbus.clone(); + sysbus.lock().unwrap().reset()?; + // Todo: this logic will be deleted after deleting pci_host in machine struct. if let Ok(pci_host) = self.get_pci_host() { pci_host .lock() .unwrap() - .reset() + .reset(true) .with_context(|| "Fail to reset pci host")?; } @@ -1535,10 +1530,11 @@ pub trait MachineOps: MachineLifecycle { drop(locked_bus); // It's safe to call devfn.unwrap(), because the bus exists. match locked_pci_host.find_device(0, devfn.unwrap() as u8) { - Some(dev) => { - PCI_BUS_DEVICE!(dev, locked_dev, pci_dev); - pci_dev.reset(false).with_context(|| "Failed to reset bus") - } + Some(dev) => dev + .lock() + .unwrap() + .reset(false) + .with_context(|| "Failed to reset bus"), None => bail!("Failed to found device"), } } diff --git a/vfio/src/vfio_pci.rs b/vfio/src/vfio_pci.rs index 3ae3cae8..3e28c2e3 100644 --- a/vfio/src/vfio_pci.rs +++ b/vfio/src/vfio_pci.rs @@ -815,6 +815,12 @@ impl VfioPciDevice { impl Device for VfioPciDevice { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); + + fn reset(&mut self, _reset_child_device: bool) -> Result<()> { + Result::with_context(self.vfio_device.lock().unwrap().reset(), || { + "Fail to reset vfio dev" + }) + } } impl PciDevOps for VfioPciDevice { @@ -988,12 +994,6 @@ impl PciDevOps for VfioPciDevice { } } } - - fn reset(&mut self, _reset_child_device: bool) -> Result<()> { - Result::with_context(self.vfio_device.lock().unwrap().reset(), || { - "Fail to reset vfio dev" - }) - } } fn get_irq_rawfds(gsi_msi_routes: &[GsiMsiRoute], start: u32, count: u32) -> Vec { diff --git a/virtio/src/transport/virtio_pci.rs b/virtio/src/transport/virtio_pci.rs index ec320904..b812decd 100644 --- a/virtio/src/transport/virtio_pci.rs +++ b/virtio/src/transport/virtio_pci.rs @@ -1002,6 +1002,19 @@ impl VirtioPciDevice { impl Device for VirtioPciDevice { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); + + fn reset(&mut self, _reset_child_device: bool) -> Result<()> { + info!("func: reset, id: {:?}", &self.base.base.id); + self.deactivate_device(); + self.device + .lock() + .unwrap() + .reset() + .with_context(|| "Failed to reset virtio device")?; + self.base.config.reset()?; + + Ok(()) + } } impl PciDevOps for VirtioPciDevice { @@ -1214,19 +1227,6 @@ impl PciDevOps for VirtioPciDevice { self.do_cfg_access(offset, end, true); } - fn reset(&mut self, _reset_child_device: bool) -> Result<()> { - info!("func: reset, id: {:?}", &self.base.base.id); - self.deactivate_device(); - self.device - .lock() - .unwrap() - .reset() - .with_context(|| "Failed to reset virtio device")?; - self.base.config.reset()?; - - Ok(()) - } - fn get_dev_path(&self) -> Option { let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); match self.device.lock().unwrap().device_type() { -- Gitee From c93410ae9b653d4aa5b6a1c867bab69bdc7a6437 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sat, 13 Jul 2024 18:49:50 +0800 Subject: [PATCH 202/489] devices: unified device unrealize function Move unrealize function to Device trait to unify unrealize function: 1. Default unrealize is not supported. 2. Device unrealize is the device's own logic. Signed-off-by: liuxiangdong --- devices/src/lib.rs | 5 +++++ devices/src/misc/pvpanic.rs | 8 +++---- devices/src/pci/demo_device/mod.rs | 9 ++++---- devices/src/pci/mod.rs | 13 ++++-------- devices/src/usb/xhci/xhci_pci.rs | 10 ++++----- vfio/src/vfio_pci.rs | 16 +++++++------- virtio/src/transport/virtio_pci.rs | 34 +++++++++++++++--------------- 7 files changed, 47 insertions(+), 48 deletions(-) diff --git a/devices/src/lib.rs b/devices/src/lib.rs index 98aea03f..b75fc0e4 100644 --- a/devices/src/lib.rs +++ b/devices/src/lib.rs @@ -109,6 +109,11 @@ pub trait Device: Any + AsAny + Send + Sync { fn reset(&mut self, _reset_child_device: bool) -> Result<()> { Ok(()) } + + /// Unrealize device. + fn unrealize(&mut self) -> Result<()> { + bail!("Unrealize of the device {} is not implemented", self.name()); + } } /// Macro `convert_device_ref!`: Convert from Arc> to &$device_type. diff --git a/devices/src/misc/pvpanic.rs b/devices/src/misc/pvpanic.rs index 76d23219..f3bc7409 100644 --- a/devices/src/misc/pvpanic.rs +++ b/devices/src/misc/pvpanic.rs @@ -165,6 +165,10 @@ impl PvPanicPci { impl Device for PvPanicPci { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); + + fn unrealize(&mut self) -> Result<()> { + Ok(()) + } } impl PciDevOps for PvPanicPci { @@ -227,10 +231,6 @@ impl PciDevOps for PvPanicPci { Ok(()) } - fn unrealize(&mut self) -> Result<()> { - Ok(()) - } - fn write_config(&mut self, offset: usize, data: &[u8]) { let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); PCI_BUS!(parent_bus, locked_bus, pci_bus); diff --git a/devices/src/pci/demo_device/mod.rs b/devices/src/pci/demo_device/mod.rs index b78ff617..9e5c20a8 100644 --- a/devices/src/pci/demo_device/mod.rs +++ b/devices/src/pci/demo_device/mod.rs @@ -190,6 +190,10 @@ impl Device for DemoDev { fn reset(&mut self, _reset_child_device: bool) -> Result<()> { self.base.config.reset_common_regs() } + + fn unrealize(&mut self) -> Result<()> { + self.device.lock().unwrap().unrealize() + } } impl PciDevOps for DemoDev { @@ -209,11 +213,6 @@ impl PciDevOps for DemoDev { Ok(()) } - /// Unrealize PCI/PCIe device. - fn unrealize(&mut self) -> Result<()> { - self.device.lock().unwrap().unrealize() - } - /// write the pci configuration space fn write_config(&mut self, offset: usize, data: &[u8]) { let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs index 59f295f5..8d2ce847 100644 --- a/devices/src/pci/mod.rs +++ b/devices/src/pci/mod.rs @@ -175,11 +175,6 @@ pub trait PciDevOps: Device + Send { /// Realize PCI/PCIe device. fn realize(self) -> Result<()>; - /// Unrealize PCI/PCIe device. - fn unrealize(&mut self) -> Result<()> { - bail!("Unrealize of the pci device is not implemented"); - } - /// Configuration space read. /// /// # Arguments @@ -428,6 +423,10 @@ mod tests { impl Device for TestPciDevice { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); + + fn unrealize(&mut self) -> Result<()> { + Ok(()) + } } impl PciDevOps for TestPciDevice { @@ -456,10 +455,6 @@ mod tests { Ok(()) } - fn unrealize(&mut self) -> Result<()> { - Ok(()) - } - fn init_write_mask(&mut self, _is_bridge: bool) -> Result<()> { let mut offset = 0_usize; while offset < self.base.config.config.len() { diff --git a/devices/src/usb/xhci/xhci_pci.rs b/devices/src/usb/xhci/xhci_pci.rs index e0ccbf6d..67afc3ca 100644 --- a/devices/src/usb/xhci/xhci_pci.rs +++ b/devices/src/usb/xhci/xhci_pci.rs @@ -246,6 +246,11 @@ impl Device for XhciPciDevice { Ok(()) } + + fn unrealize(&mut self) -> Result<()> { + trace::usb_xhci_exit(); + Ok(()) + } } impl PciDevOps for XhciPciDevice { @@ -350,11 +355,6 @@ impl PciDevOps for XhciPciDevice { Ok(()) } - fn unrealize(&mut self) -> Result<()> { - trace::usb_xhci_exit(); - Ok(()) - } - fn write_config(&mut self, offset: usize, data: &[u8]) { let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); PCI_BUS!(parent_bus, locked_bus, pci_bus); diff --git a/vfio/src/vfio_pci.rs b/vfio/src/vfio_pci.rs index 3e28c2e3..22ae5945 100644 --- a/vfio/src/vfio_pci.rs +++ b/vfio/src/vfio_pci.rs @@ -821,6 +821,14 @@ impl Device for VfioPciDevice { "Fail to reset vfio dev" }) } + + fn unrealize(&mut self) -> Result<()> { + if let Err(e) = VfioPciDevice::unrealize(self) { + error!("{:?}", e); + bail!("Failed to unrealize vfio-pci."); + } + Ok(()) + } } impl PciDevOps for VfioPciDevice { @@ -877,14 +885,6 @@ impl PciDevOps for VfioPciDevice { Ok(()) } - fn unrealize(&mut self) -> Result<()> { - if let Err(e) = VfioPciDevice::unrealize(self) { - error!("{:?}", e); - bail!("Failed to unrealize vfio-pci."); - } - Ok(()) - } - /// Read pci data from pci config if it emulate, otherwise read from vfio device. fn read_config(&mut self, offset: usize, data: &mut [u8]) { let size = data.len(); diff --git a/virtio/src/transport/virtio_pci.rs b/virtio/src/transport/virtio_pci.rs index b812decd..d33c4713 100644 --- a/virtio/src/transport/virtio_pci.rs +++ b/virtio/src/transport/virtio_pci.rs @@ -1015,6 +1015,23 @@ impl Device for VirtioPciDevice { Ok(()) } + + fn unrealize(&mut self) -> Result<()> { + info!("func: unrealize, id: {:?}", &self.base.base.id); + self.device + .lock() + .unwrap() + .unrealize() + .with_context(|| "Failed to unrealize the virtio device")?; + + let bus = self.parent_bus().unwrap().upgrade().unwrap(); + self.base.config.unregister_bars(&bus)?; + + MigrationManager::unregister_device_instance(MsixState::descriptor(), &self.name()); + MigrationManager::unregister_transport_instance(VirtioPciState::descriptor(), &self.name()); + + Ok(()) + } } impl PciDevOps for VirtioPciDevice { @@ -1179,23 +1196,6 @@ impl PciDevOps for VirtioPciDevice { Ok(()) } - fn unrealize(&mut self) -> Result<()> { - info!("func: unrealize, id: {:?}", &self.base.base.id); - self.device - .lock() - .unwrap() - .unrealize() - .with_context(|| "Failed to unrealize the virtio device")?; - - let bus = self.parent_bus().unwrap().upgrade().unwrap(); - self.base.config.unregister_bars(&bus)?; - - MigrationManager::unregister_device_instance(MsixState::descriptor(), &self.name()); - MigrationManager::unregister_transport_instance(VirtioPciState::descriptor(), &self.name()); - - Ok(()) - } - fn read_config(&mut self, offset: usize, data: &mut [u8]) { trace::virtio_tpt_read_config(&self.base.base.id, offset as u64, data.len()); self.do_cfg_access(offset, offset + data.len(), false); -- Gitee From 5b0fa2511e33118dcc6c2cd06901034ed1516826 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sat, 13 Jul 2024 21:56:13 +0800 Subject: [PATCH 203/489] devices: delete the parameters of `realize` function Unify the parameter of `realize` function to `mut self` or `self`. Make preparation for unifing `realize` function in next commit. Signed-off-by: liuxiangdong --- devices/src/acpi/cpu_controller.rs | 12 +++-- devices/src/acpi/ged.rs | 9 ++-- devices/src/acpi/power.rs | 9 ++-- devices/src/legacy/fwcfg.rs | 20 ++++---- devices/src/legacy/pflash.rs | 15 +++--- devices/src/legacy/pl011.rs | 10 ++-- devices/src/legacy/pl031.rs | 9 ++-- devices/src/legacy/ramfb.rs | 16 ++++--- devices/src/legacy/rtc.rs | 9 ++-- devices/src/legacy/serial.rs | 9 ++-- devices/src/lib.rs | 4 ++ devices/src/scsi/disk.rs | 21 +++++---- devices/src/sysbus/mod.rs | 8 ++++ devices/src/usb/storage.rs | 62 +++++++++++++------------ devices/src/usb/uas.rs | 71 +++++++++++++++-------------- machine/src/aarch64/micro.rs | 8 +--- machine/src/aarch64/standard.rs | 22 ++++----- machine/src/lib.rs | 11 ++--- machine/src/micro_common/mod.rs | 2 +- machine/src/x86_64/micro.rs | 2 +- machine/src/x86_64/standard.rs | 14 +++--- virtio/src/transport/virtio_mmio.rs | 9 ++-- 22 files changed, 198 insertions(+), 154 deletions(-) diff --git a/devices/src/acpi/cpu_controller.rs b/devices/src/acpi/cpu_controller.rs index 70d0866a..a15fdc39 100644 --- a/devices/src/acpi/cpu_controller.rs +++ b/devices/src/acpi/cpu_controller.rs @@ -20,7 +20,7 @@ use log::{error, info}; use vmm_sys_util::eventfd::EventFd; use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps}; -use crate::{Device, DeviceBase}; +use crate::{convert_bus_mut, Device, DeviceBase, MUT_SYS_BUS}; use acpi::{ AcpiError, AcpiLocalApic, AmlAcquire, AmlAddressSpaceType, AmlArg, AmlBuffer, AmlBuilder, AmlCallWithArgs1, AmlCallWithArgs2, AmlCallWithArgs4, AmlDevice, AmlEisaId, AmlEqual, AmlField, @@ -107,15 +107,17 @@ impl CpuController { .set_sys_resource(sysbus, region_base, region_size, "CPUController") .with_context(|| AcpiError::Alignment(region_size.try_into().unwrap()))?; cpu_controller.set_boot_vcpu(boot_vcpus)?; + cpu_controller.set_parent_bus(sysbus.clone()); Ok(cpu_controller) } - pub fn realize(self, sysbus: &Arc>) -> Result>> { + pub fn realize(self) -> Result>> { + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); let dev = Arc::new(Mutex::new(self)); - let ret_dev = dev.clone(); - sysbus.lock().unwrap().attach_device(&dev)?; - Ok(ret_dev) + sysbus.attach_device(&dev)?; + Ok(dev) } fn eject_cpu(&mut self, vcpu_id: u8) -> Result<()> { diff --git a/devices/src/acpi/ged.rs b/devices/src/acpi/ged.rs index cfe072e2..915b2bce 100644 --- a/devices/src/acpi/ged.rs +++ b/devices/src/acpi/ged.rs @@ -20,7 +20,7 @@ use vmm_sys_util::epoll::EventSet; use vmm_sys_util::eventfd::EventFd; use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps}; -use crate::{Device, DeviceBase}; +use crate::{convert_bus_mut, Device, DeviceBase, MUT_SYS_BUS}; use acpi::{ AcpiError, AmlActiveLevel, AmlAddressSpaceType, AmlAnd, AmlBuilder, AmlDevice, AmlEdgeLevel, AmlEqual, AmlExtendedInterrupt, AmlField, AmlFieldAccessType, AmlFieldLockRule, AmlFieldUnit, @@ -99,14 +99,17 @@ impl Ged { ged.base.interrupt_evt = Some(Arc::new(create_new_eventfd()?)); ged.set_sys_resource(sysbus, region_base, region_size, "Ged") .with_context(|| AcpiError::Alignment(region_size as u32))?; + ged.set_parent_bus(sysbus.clone()); Ok(ged) } - pub fn realize(self, sysbus: &Arc>) -> Result>> { + pub fn realize(self) -> Result>> { + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); let ged_event = self.ged_event.clone(); let dev = Arc::new(Mutex::new(self)); - sysbus.lock().unwrap().attach_device(&dev)?; + sysbus.attach_device(&dev)?; let ged = dev.lock().unwrap(); ged.register_acpi_powerdown_event(ged_event.power_button) diff --git a/devices/src/acpi/power.rs b/devices/src/acpi/power.rs index ca401127..faea9c85 100644 --- a/devices/src/acpi/power.rs +++ b/devices/src/acpi/power.rs @@ -19,7 +19,7 @@ use log::info; use crate::acpi::ged::{AcpiEvent, Ged}; use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps}; -use crate::{Device, DeviceBase}; +use crate::{convert_bus_mut, Device, DeviceBase, MUT_SYS_BUS}; use acpi::{ AcpiError, AmlAddressSpaceType, AmlBuilder, AmlDevice, AmlField, AmlFieldAccessType, AmlFieldLockRule, AmlFieldUnit, AmlFieldUpdateRule, AmlIndex, AmlInteger, AmlMethod, AmlName, @@ -99,6 +99,7 @@ impl PowerDev { }; pdev.set_sys_resource(sysbus, region_base, region_size, "PowerDev") .with_context(|| AcpiError::Alignment(region_size as u32))?; + pdev.set_parent_bus(sysbus.clone()); Ok(pdev) } @@ -184,9 +185,11 @@ impl PowerDev { self.ged.lock().unwrap().inject_acpi_event(evt); } - pub fn realize(self, sysbus: &Arc>) -> Result<()> { + pub fn realize(self) -> Result<()> { + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); let dev = Arc::new(Mutex::new(self)); - sysbus.lock().unwrap().attach_device(&dev)?; + sysbus.attach_device(&dev)?; let pdev_available: bool; { diff --git a/devices/src/legacy/fwcfg.rs b/devices/src/legacy/fwcfg.rs index c6016497..25635fc8 100644 --- a/devices/src/legacy/fwcfg.rs +++ b/devices/src/legacy/fwcfg.rs @@ -20,7 +20,7 @@ use log::{error, warn}; use crate::legacy::error::LegacyError; use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; -use crate::{Device, DeviceBase}; +use crate::{convert_bus_mut, Device, DeviceBase, MUT_SYS_BUS}; use acpi::{ AmlBuilder, AmlDevice, AmlInteger, AmlNameDecl, AmlResTemplate, AmlScopeBuilder, AmlString, }; @@ -855,16 +855,17 @@ impl FwCfgMem { fwcfgmem .set_sys_resource(sysbus, region_base, region_size, "FwCfgMem") .with_context(|| "Failed to allocate system resource for FwCfg.")?; + fwcfgmem.set_parent_bus(sysbus.clone()); Ok(fwcfgmem) } - pub fn realize(mut self, sysbus: &Arc>) -> Result>> { + pub fn realize(mut self) -> Result>> { + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); self.fwcfg.common_realize()?; let dev = Arc::new(Mutex::new(self)); sysbus - .lock() - .unwrap() .attach_device(&dev) .with_context(|| "Failed to attach FwCfg device to system bus.")?; Ok(dev) @@ -1016,16 +1017,17 @@ impl FwCfgIO { fwcfg .set_sys_resource(sysbus, FW_CFG_IO_BASE, FW_CFG_IO_SIZE, "FwCfgIO") .with_context(|| "Failed to allocate system resource for FwCfg.")?; + fwcfg.set_parent_bus(sysbus.clone()); Ok(fwcfg) } - pub fn realize(mut self, sysbus: &Arc>) -> Result>> { + pub fn realize(mut self) -> Result>> { + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); self.fwcfg.common_realize()?; let dev = Arc::new(Mutex::new(self)); sysbus - .lock() - .unwrap() .attach_device(&dev) .with_context(|| "Failed to attach FwCfg device to system bus.")?; Ok(dev) @@ -1488,7 +1490,7 @@ mod test { let sys_mem = address_space_init(); let fwcfg = FwCfgMem::new(sys_mem, &mut sys_bus, 0x0902_0000, 0x0000_0018).unwrap(); - let fwcfg_dev = fwcfg.realize(&mut sys_bus).unwrap(); + let fwcfg_dev = fwcfg.realize().unwrap(); // Read FW_CFG_DMA_SIGNATURE entry. let base = GuestAddress(0x0000); let mut read_data = vec![0xff_u8, 0xff, 0xff, 0xff]; @@ -1528,7 +1530,7 @@ mod test { let sys_mem = address_space_init(); let fwcfg = FwCfgIO::new(sys_mem, &mut sys_bus).unwrap(); - let fwcfg_dev = FwCfgIO::realize(fwcfg, &mut sys_bus).unwrap(); + let fwcfg_dev = fwcfg.realize().unwrap(); // Read FW_CFG_DMA_SIGNATURE entry. let base = GuestAddress(0x0000); let mut read_data = vec![0xff_u8, 0xff, 0xff, 0xff]; diff --git a/devices/src/legacy/pflash.rs b/devices/src/legacy/pflash.rs index c4b1b1de..e0a1b3af 100644 --- a/devices/src/legacy/pflash.rs +++ b/devices/src/legacy/pflash.rs @@ -19,7 +19,7 @@ use log::{error, warn}; use super::error::LegacyError; use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; -use crate::{Device, DeviceBase}; +use crate::{convert_bus_mut, Device, DeviceBase, MUT_SYS_BUS}; use acpi::AmlBuilder; use address_space::{FileBackend, GuestAddress, HostMemMapping, Region}; use util::gen_base_func; @@ -227,24 +227,25 @@ impl PFlash { pflash .set_sys_resource(sysbus, region_base, region_size, "PflashRom") .with_context(|| "Failed to allocate system resource for PFlash.")?; + pflash.set_parent_bus(sysbus.clone()); Ok(pflash) } - pub fn realize(self, sysbus: &Arc>) -> Result>> { + pub fn realize(self) -> Result>> { + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); let region_base = self.base.res.region_base; let host_mmap = self.host_mmap.clone(); let dev = Arc::new(Mutex::new(self)); - let region_ops = sysbus.lock().unwrap().build_region_ops(&dev); + let region_ops = sysbus.build_region_ops(&dev); let rom_region = Region::init_rom_device_region(host_mmap, region_ops, "PflashRom"); dev.lock().unwrap().rom = Some(rom_region.clone()); sysbus - .lock() - .unwrap() .sys_mem .root() .add_subregion(rom_region, region_base) .with_context(|| "Failed to attach PFlash to system bus")?; - sysbus.lock().unwrap().sysbus_attach_child(dev.clone())?; + sysbus.sysbus_attach_child(dev.clone())?; Ok(dev) } @@ -949,7 +950,7 @@ mod test { flash_size, fd, sector_len, 4, 2, read_only, &sysbus, flash_base, ) .unwrap(); - let dev = pflash.realize(&sysbus).unwrap(); + let dev = pflash.realize().unwrap(); dev } diff --git a/devices/src/legacy/pl011.rs b/devices/src/legacy/pl011.rs index 164f4b43..35c04fe7 100644 --- a/devices/src/legacy/pl011.rs +++ b/devices/src/legacy/pl011.rs @@ -17,7 +17,7 @@ use log::error; use super::error::LegacyError; use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; -use crate::{Device, DeviceBase}; +use crate::{convert_bus_mut, Device, DeviceBase, MUT_SYS_BUS}; use acpi::{ AmlActiveLevel, AmlBuilder, AmlDevice, AmlEdgeLevel, AmlExtendedInterrupt, AmlIntShare, AmlInteger, AmlMemory32Fixed, AmlNameDecl, AmlReadAndWrite, AmlResTemplate, AmlResourceUsage, @@ -148,6 +148,7 @@ impl PL011 { pl011 .set_sys_resource(sysbus, region_base, region_size, "PL011") .with_context(|| "Failed to set system resource for PL011.")?; + pl011.set_parent_bus(sysbus.clone()); Ok(pl011) } @@ -162,18 +163,19 @@ impl PL011 { } } - pub fn realize(self, sysbus: &Arc>) -> Result<()> { + pub fn realize(self) -> Result<()> { self.chardev .lock() .unwrap() .realize() .with_context(|| "Failed to realize chardev")?; + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); let dev = Arc::new(Mutex::new(self)); sysbus - .lock() - .unwrap() .attach_device(&dev) .with_context(|| "Failed to attach PL011 to system bus.")?; + drop(locked_bus); MigrationManager::register_device_instance( PL011State::descriptor(), dev.clone(), diff --git a/devices/src/legacy/pl031.rs b/devices/src/legacy/pl031.rs index ab41fb2a..b88454c4 100644 --- a/devices/src/legacy/pl031.rs +++ b/devices/src/legacy/pl031.rs @@ -18,7 +18,7 @@ use byteorder::{ByteOrder, LittleEndian}; use super::error::LegacyError; use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; -use crate::{Device, DeviceBase}; +use crate::{convert_bus_mut, Device, DeviceBase, MUT_SYS_BUS}; use acpi::AmlBuilder; use address_space::GuestAddress; use migration::{ @@ -95,13 +95,16 @@ impl PL031 { pl031 .set_sys_resource(sysbus, region_base, region_size, "PL031") .with_context(|| LegacyError::SetSysResErr)?; + pl031.set_parent_bus(sysbus.clone()); Ok(pl031) } - pub fn realize(self, sysbus: &Arc>) -> Result<()> { + pub fn realize(self) -> Result<()> { + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); let dev = Arc::new(Mutex::new(self)); - sysbus.lock().unwrap().attach_device(&dev)?; + sysbus.attach_device(&dev)?; MigrationManager::register_device_instance( PL031State::descriptor(), diff --git a/devices/src/legacy/ramfb.rs b/devices/src/legacy/ramfb.rs index 7bb501b5..b87a62a2 100644 --- a/devices/src/legacy/ramfb.rs +++ b/devices/src/legacy/ramfb.rs @@ -22,7 +22,7 @@ use log::error; use super::fwcfg::{FwCfgOps, FwCfgWriteCallback}; use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; -use crate::{Device, DeviceBase}; +use crate::{convert_bus_mut, Device, DeviceBase, MUT_SYS_BUS}; use acpi::AmlBuilder; use address_space::{AddressSpace, GuestAddress}; use machine_manager::config::valid_id; @@ -244,16 +244,20 @@ pub struct Ramfb { } impl Ramfb { - pub fn new(sys_mem: Arc, install: bool) -> Self { - Ramfb { + pub fn new(sys_mem: Arc, sysbus: &Arc>, install: bool) -> Self { + let mut ramfb = Ramfb { base: SysBusDevBase::new(SysBusDevType::Ramfb), ramfb_state: RamfbState::new(sys_mem, install), - } + }; + ramfb.set_parent_bus(sysbus.clone()); + ramfb } - pub fn realize(self, sysbus: &Arc>) -> Result<()> { + pub fn realize(self) -> Result<()> { + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); let dev = Arc::new(Mutex::new(self)); - sysbus.lock().unwrap().attach_device(&dev)?; + sysbus.attach_device(&dev)?; Ok(()) } } diff --git a/devices/src/legacy/rtc.rs b/devices/src/legacy/rtc.rs index 6860a1e2..add41a88 100644 --- a/devices/src/legacy/rtc.rs +++ b/devices/src/legacy/rtc.rs @@ -17,7 +17,7 @@ use anyhow::Result; use log::{debug, error, warn}; use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; -use crate::{Device, DeviceBase}; +use crate::{convert_bus_mut, Device, DeviceBase, MUT_SYS_BUS}; use acpi::{ AmlBuilder, AmlDevice, AmlEisaId, AmlIoDecode, AmlIoResource, AmlIrqNoFlags, AmlNameDecl, AmlResTemplate, AmlScopeBuilder, @@ -143,6 +143,7 @@ impl RTC { rtc.init_rtc_reg(); rtc.set_sys_resource(sysbus, RTC_PORT_INDEX, 8, "RTC")?; + rtc.set_parent_bus(sysbus.clone()); Ok(rtc) } @@ -264,9 +265,11 @@ impl RTC { true } - pub fn realize(self, sysbus: &Arc>) -> Result<()> { + pub fn realize(self) -> Result<()> { + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); let dev = Arc::new(Mutex::new(self)); - sysbus.lock().unwrap().attach_device(&dev)?; + sysbus.attach_device(&dev)?; Ok(()) } diff --git a/devices/src/legacy/serial.rs b/devices/src/legacy/serial.rs index dc7e25fb..898a933b 100644 --- a/devices/src/legacy/serial.rs +++ b/devices/src/legacy/serial.rs @@ -18,7 +18,7 @@ use log::{debug, error}; use super::error::LegacyError; use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; -use crate::{Device, DeviceBase}; +use crate::{convert_bus_mut, Device, DeviceBase, MUT_SYS_BUS}; use acpi::{ AmlActiveLevel, AmlBuilder, AmlDevice, AmlEdgeLevel, AmlEisaId, AmlExtendedInterrupt, AmlIntShare, AmlInteger, AmlIoDecode, AmlIoResource, AmlNameDecl, AmlResTemplate, @@ -141,17 +141,20 @@ impl Serial { serial .set_sys_resource(sysbus, region_base, region_size, "Serial") .with_context(|| LegacyError::SetSysResErr)?; + serial.set_parent_bus(sysbus.clone()); Ok(serial) } - pub fn realize(self, sysbus: &Arc>) -> Result<()> { + pub fn realize(self) -> Result<()> { self.chardev .lock() .unwrap() .realize() .with_context(|| "Failed to realize chardev")?; + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); let dev = Arc::new(Mutex::new(self)); - sysbus.lock().unwrap().attach_device(&dev)?; + sysbus.attach_device(&dev)?; MigrationManager::register_device_instance( SerialState::descriptor(), diff --git a/devices/src/lib.rs b/devices/src/lib.rs index b75fc0e4..ecc9c140 100644 --- a/devices/src/lib.rs +++ b/devices/src/lib.rs @@ -101,6 +101,10 @@ pub trait Device: Any + AsAny + Send + Sync { self.device_base().parent.clone() } + fn set_parent_bus(&mut self, bus: Arc>) { + self.device_base_mut().parent = Some(Arc::downgrade(&bus)); + } + /// Get the bus which this device has. fn child_bus(&self) -> Option>> { self.device_base().child.clone() diff --git a/devices/src/scsi/disk.rs b/devices/src/scsi/disk.rs index 3b9e6a6c..9e1c9895 100644 --- a/devices/src/scsi/disk.rs +++ b/devices/src/scsi/disk.rs @@ -24,6 +24,8 @@ use machine_manager::event_loop::EventLoop; use util::aio::{Aio, AioEngine, WriteZeroesState}; use util::gen_base_func; +use super::bus::ScsiBus; + /// SCSI DEVICE TYPES. pub const SCSI_TYPE_DISK: u32 = 0x00; pub const SCSI_TYPE_TAPE: u32 = 0x01; @@ -143,6 +145,7 @@ macro_rules! SCSI_DEVICE { }; } +#[derive(Default)] pub struct ScsiDevice { pub base: DeviceBase, /// Configuration of the scsi device. @@ -181,30 +184,30 @@ impl ScsiDevice { drive_cfg: DriveConfig, drive_files: Arc>>, iothread: Option, + scsi_bus: Arc>, ) -> ScsiDevice { let scsi_type = match dev_cfg.classtype.as_str() { "scsi-hd" => SCSI_TYPE_DISK, _ => SCSI_TYPE_ROM, }; - ScsiDevice { + let mut scsi_dev = ScsiDevice { base: DeviceBase::new(dev_cfg.id.clone(), false, None), dev_cfg, drive_cfg, state: ScsiDevState::new(), - block_backend: None, req_align: 1, buf_align: 1, - disk_sectors: 0, - block_size: 0, scsi_type, drive_files, - aio: None, iothread, - } + ..Default::default() + }; + scsi_dev.set_parent_bus(scsi_bus); + scsi_dev } - pub fn realize(&mut self) -> Result<()> { + pub fn realize(mut self) -> Result>> { match self.scsi_type { SCSI_TYPE_DISK => { self.block_size = SCSI_DISK_DEFAULT_BLOCK_SIZE; @@ -231,6 +234,7 @@ impl ScsiDevice { self.req_align = alignments.0; self.buf_align = alignments.1; let drive_id = VmConfig::get_drive_id(&drive_files, &self.drive_cfg.path_on_host)?; + drop(drive_files); let mut thread_pool = None; if self.drive_cfg.aio != AioEngine::Off { @@ -254,7 +258,8 @@ impl ScsiDevice { self.block_backend = Some(backend); self.disk_sectors = disk_size >> SECTOR_SHIFT; - Ok(()) + let dev = Arc::new(Mutex::new(self)); + Ok(dev) } } diff --git a/devices/src/sysbus/mod.rs b/devices/src/sysbus/mod.rs index a436f779..01de827d 100644 --- a/devices/src/sysbus/mod.rs +++ b/devices/src/sysbus/mod.rs @@ -175,6 +175,14 @@ impl Bus for SysBus { gen_base_func!(bus_base, bus_base_mut, BusBase, base); } +/// Convert from Arc> to &mut SysBus. +#[macro_export] +macro_rules! MUT_SYS_BUS { + ($trait_bus:expr, $lock_bus: ident, $struct_bus: ident) => { + convert_bus_mut!($trait_bus, $lock_bus, $struct_bus, SysBus); + }; +} + #[derive(Clone)] pub struct SysRes { // Note: region_base/region_size are both 0 means that this device doesn't have its own memory layout. diff --git a/devices/src/usb/storage.rs b/devices/src/usb/storage.rs index 74bb82ab..2c03f09a 100644 --- a/devices/src/usb/storage.rs +++ b/devices/src/usb/storage.rs @@ -28,14 +28,12 @@ use super::descriptor::{ use super::xhci::xhci_controller::XhciDevice; use super::{config::*, USB_DEVICE_BUFFER_DEFAULT_LEN}; use super::{UsbDevice, UsbDeviceBase, UsbDeviceRequest, UsbPacket, UsbPacketStatus}; -use crate::{ - Bus, - ScsiBus::{ - get_scsi_key, ScsiBus, ScsiRequest, ScsiRequestOps, ScsiSense, ScsiXferMode, - EMULATE_SCSI_OPS, GOOD, SCSI_CMD_BUF_SIZE, - }, - ScsiDisk::{ScsiDevConfig, ScsiDevice}, +use crate::Bus; +use crate::ScsiBus::{ + get_scsi_key, ScsiBus, ScsiRequest, ScsiRequestOps, ScsiSense, ScsiXferMode, EMULATE_SCSI_OPS, + GOOD, SCSI_CMD_BUF_SIZE, }; +use crate::ScsiDisk::{ScsiDevConfig, ScsiDevice}; use machine_manager::config::{DriveConfig, DriveFile}; use util::aio::AioEngine; use util::gen_base_func; @@ -258,7 +256,9 @@ pub struct UsbStorage { // (usb-storage/scsi bus/scsi device) correspond one-to-one, add scsi device member here // for the execution efficiency (No need to find a unique device from the hash table of the // unique bus). - scsi_dev: Arc>, + scsi_dev: Option>>, + /// Drive backend files. + drive_files: Arc>>, } #[derive(Debug)] @@ -334,29 +334,15 @@ impl UsbStorage { bail!("USB-storage: \"aio=off,direct=false\" must be configured."); } - let scsidev_classtype = match &drive_cfg.media as &str { - "disk" => "scsi-hd".to_string(), - _ => "scsi-cd".to_string(), - }; - let scsi_dev_cfg = ScsiDevConfig { - classtype: scsidev_classtype, - drive: dev_cfg.drive.clone(), - ..Default::default() - }; - Ok(Self { base: UsbDeviceBase::new(dev_cfg.id.clone(), USB_DEVICE_BUFFER_DEFAULT_LEN), state: UsbStorageState::new(), cntlr: None, dev_cfg, - drive_cfg: drive_cfg.clone(), + drive_cfg, scsi_bus: Arc::new(Mutex::new(ScsiBus::new("".to_string()))), - scsi_dev: Arc::new(Mutex::new(ScsiDevice::new( - scsi_dev_cfg, - drive_cfg, - drive_files, - None, - ))), + scsi_dev: None, + drive_files, }) } @@ -513,7 +499,7 @@ impl UsbStorage { 0, packet.iovecs.clone(), self.state.iovec_len, - self.scsi_dev.clone(), + self.scsi_dev.as_ref().unwrap().clone(), csw, ) .with_context(|| "Error in creating scsirequest.")?; @@ -556,13 +542,29 @@ impl UsbDevice for UsbStorage { // NOTE: "aio=off,direct=false" must be configured and other aio/direct values are not // supported. - let mut locked_scsi_dev = self.scsi_dev.lock().unwrap(); - locked_scsi_dev.realize()?; - drop(locked_scsi_dev); + let scsidev_classtype = match self.drive_cfg.media.as_str() { + "disk" => "scsi-hd".to_string(), + _ => "scsi-cd".to_string(), + }; + let scsi_dev_cfg = ScsiDevConfig { + classtype: scsidev_classtype, + drive: self.dev_cfg.drive.clone(), + ..Default::default() + }; + let scsi_device = ScsiDevice::new( + scsi_dev_cfg, + self.drive_cfg.clone(), + self.drive_files.clone(), + None, + self.scsi_bus.clone(), + ); + let realized_scsi = scsi_device.realize()?; + self.scsi_dev = Some(realized_scsi.clone()); + self.scsi_bus .lock() .unwrap() - .attach_child(get_scsi_key(0, 0), self.scsi_dev.clone())?; + .attach_child(get_scsi_key(0, 0), realized_scsi)?; let storage: Arc> = Arc::new(Mutex::new(self)); Ok(storage) diff --git a/devices/src/usb/uas.rs b/devices/src/usb/uas.rs index c58f7ecf..d4c9dfbc 100644 --- a/devices/src/usb/uas.rs +++ b/devices/src/usb/uas.rs @@ -35,14 +35,12 @@ use super::{ USB_DEVICE_BUFFER_DEFAULT_LEN, }; use crate::Bus; -use crate::{ - ScsiBus::{ - get_scsi_key, scsi_cdb_xfer, ScsiBus, ScsiRequest, ScsiRequestOps, ScsiSense, ScsiXferMode, - CHECK_CONDITION, EMULATE_SCSI_OPS, GOOD, SCSI_SENSE_INVALID_PARAM_VALUE, - SCSI_SENSE_INVALID_TAG, SCSI_SENSE_NO_SENSE, - }, - ScsiDisk::{ScsiDevConfig, ScsiDevice}, +use crate::ScsiBus::{ + get_scsi_key, scsi_cdb_xfer, ScsiBus, ScsiRequest, ScsiRequestOps, ScsiSense, ScsiXferMode, + CHECK_CONDITION, EMULATE_SCSI_OPS, GOOD, SCSI_SENSE_INVALID_PARAM_VALUE, + SCSI_SENSE_INVALID_TAG, SCSI_SENSE_NO_SENSE, }; +use crate::ScsiDisk::{ScsiDevConfig, ScsiDevice}; use machine_manager::config::{DriveConfig, DriveFile}; use util::byte_code::ByteCode; use util::gen_base_func; @@ -108,8 +106,11 @@ pub struct UsbUasConfig { pub struct UsbUas { base: UsbDeviceBase, + uas_config: UsbUasConfig, scsi_bus: Arc>, - scsi_device: Arc>, + scsi_device: Option>>, + drive_cfg: DriveConfig, + drive_files: Arc>>, commands: [Option; UAS_MAX_STREAMS + 1], statuses: [Option>>; UAS_MAX_STREAMS + 1], data: [Option>>; UAS_MAX_STREAMS + 1], @@ -462,25 +463,16 @@ impl UsbUas { drive_cfg: DriveConfig, drive_files: Arc>>, ) -> Self { - let scsidev_classtype = match &drive_cfg.media as &str { - "disk" => "scsi-hd".to_string(), - _ => "scsi-cd".to_string(), - }; - let scsi_dev_cfg = ScsiDevConfig { - classtype: scsidev_classtype, - drive: uas_config.drive.clone(), - ..Default::default() - }; - Self { - base: UsbDeviceBase::new(uas_config.id.unwrap(), USB_DEVICE_BUFFER_DEFAULT_LEN), + base: UsbDeviceBase::new( + uas_config.id.as_ref().unwrap().clone(), + USB_DEVICE_BUFFER_DEFAULT_LEN, + ), + uas_config, scsi_bus: Arc::new(Mutex::new(ScsiBus::new("".to_string()))), - scsi_device: Arc::new(Mutex::new(ScsiDevice::new( - scsi_dev_cfg, - drive_cfg, - drive_files, - None, - ))), + scsi_device: None, + drive_cfg, + drive_files, commands: array::from_fn(|_| None), statuses: array::from_fn(|_| None), data: array::from_fn(|_| None), @@ -543,7 +535,7 @@ impl UsbUas { lun, scsi_iovec, scsi_iovec_size, - self.scsi_device.clone(), + self.scsi_device.as_ref().unwrap().clone(), uas_request, ) .with_context(|| "failed to create SCSI request")?; @@ -704,7 +696,7 @@ impl UsbUas { let command = self.commands[stream].as_ref().unwrap(); // SAFETY: IU is guaranteed to be of type command. let cdb = unsafe { &command.body.command.cdb }; - let xfer_len = scsi_cdb_xfer(cdb, self.scsi_device.clone()); + let xfer_len = scsi_cdb_xfer(cdb, self.scsi_device.as_ref().unwrap().clone()); trace::usb_uas_try_start_next_transfer(self.device_id(), xfer_len); if xfer_len == 0 { @@ -761,15 +753,28 @@ impl UsbDevice for UsbUas { // NOTE: "aio=off,direct=false" must be configured and other aio/direct values are not // supported. - let mut locked_scsi_device = self.scsi_device.lock().unwrap(); - locked_scsi_device.realize()?; - locked_scsi_device.base.parent = - Some(Arc::downgrade(&self.scsi_bus) as Weak>); - drop(locked_scsi_device); + let scsidev_classtype = match self.drive_cfg.media.as_str() { + "disk" => "scsi-hd".to_string(), + _ => "scsi-cd".to_string(), + }; + let scsi_dev_cfg = ScsiDevConfig { + classtype: scsidev_classtype, + drive: self.uas_config.drive.clone(), + ..Default::default() + }; + let scsi_device = ScsiDevice::new( + scsi_dev_cfg, + self.drive_cfg.clone(), + self.drive_files.clone(), + None, + self.scsi_bus.clone(), + ); + let realized_scsi = scsi_device.realize()?; + self.scsi_device = Some(realized_scsi.clone()); self.scsi_bus .lock() .unwrap() - .attach_child(get_scsi_key(0, 0), self.scsi_device.clone())?; + .attach_child(get_scsi_key(0, 0), realized_scsi)?; let uas = Arc::new(Mutex::new(self)); Ok(uas) } diff --git a/machine/src/aarch64/micro.rs b/machine/src/aarch64/micro.rs index a3b761bf..9c04f55f 100644 --- a/machine/src/aarch64/micro.rs +++ b/machine/src/aarch64/micro.rs @@ -111,9 +111,7 @@ impl MachineOps for LightMachine { MEM_LAYOUT[LayoutEntryType::Rtc as usize].0, MEM_LAYOUT[LayoutEntryType::Rtc as usize].1, )?; - pl031 - .realize(&self.base.sysbus) - .with_context(|| "Failed to realize pl031.") + pl031.realize().with_context(|| "Failed to realize pl031.") } fn add_serial_device(&mut self, config: &SerialConfig) -> Result<()> { @@ -121,9 +119,7 @@ impl MachineOps for LightMachine { let region_size: u64 = MEM_LAYOUT[LayoutEntryType::Uart as usize].1; let pl011 = PL011::new(config.clone(), &self.base.sysbus, region_base, region_size) .with_context(|| "Failed to create PL011")?; - pl011 - .realize(&self.base.sysbus) - .with_context(|| "Failed to realize PL011")?; + pl011.realize().with_context(|| "Failed to realize PL011")?; let mut bs = self.base.boot_source.lock().unwrap(); bs.kernel_cmdline.push(Param { param_type: "earlycon".to_string(), diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index f2fe637e..a848e120 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -385,7 +385,7 @@ impl StdMachineOps for StdMachine { .with_context(|| DevErrorKind::AddEntryErr("bios-geometry".to_string()))?; let fwcfg_dev = fwcfg - .realize(&self.base.sysbus) + .realize() .with_context(|| "Failed to realize fwcfg device")?; self.base.fwcfg_dev = Some(fwcfg_dev.clone()); @@ -461,8 +461,7 @@ impl MachineOps for StdMachine { MEM_LAYOUT[LayoutEntryType::Rtc as usize].0, MEM_LAYOUT[LayoutEntryType::Rtc as usize].1, )?; - rtc.realize(&self.base.sysbus) - .with_context(|| "Failed to realize PL031") + rtc.realize().with_context(|| "Failed to realize PL031") } fn add_ged_device(&mut self) -> Result<()> { @@ -474,9 +473,7 @@ impl MachineOps for StdMachine { MEM_LAYOUT[LayoutEntryType::Ged as usize].1, GedEvent::new(self.power_button.clone()), )?; - let ged_dev = ged - .realize(&self.base.sysbus) - .with_context(|| "Failed to realize Ged")?; + let ged_dev = ged.realize().with_context(|| "Failed to realize Ged")?; if battery_present { let pdev = PowerDev::new( ged_dev, @@ -484,7 +481,7 @@ impl MachineOps for StdMachine { MEM_LAYOUT[LayoutEntryType::PowerDev as usize].0, MEM_LAYOUT[LayoutEntryType::PowerDev as usize].1, )?; - pdev.realize(&self.base.sysbus) + pdev.realize() .with_context(|| "Failed to realize PowerDev")?; } Ok(()) @@ -495,9 +492,7 @@ impl MachineOps for StdMachine { let region_size: u64 = MEM_LAYOUT[LayoutEntryType::Uart as usize].1; let pl011 = PL011::new(config.clone(), &self.base.sysbus, region_base, region_size) .with_context(|| "Failed to create PL011")?; - pl011 - .realize(&self.base.sysbus) - .with_context(|| "Failed to realize PL011")?; + pl011.realize().with_context(|| "Failed to realize PL011")?; let mut bs = self.base.boot_source.lock().unwrap(); bs.kernel_cmdline.push(Param { param_type: "earlycon".to_string(), @@ -661,7 +656,8 @@ impl MachineOps for StdMachine { flash_base, ) .with_context(|| MachineError::InitPflashErr)?; - PFlash::realize(pflash, &self.base.sysbus) + pflash + .realize() .with_context(|| MachineError::RlzPflashErr)?; flash_base += flash_size; } @@ -710,10 +706,10 @@ impl MachineOps for StdMachine { .get_fwcfg_dev() .with_context(|| "Ramfb device must be used UEFI to boot, please add pflash devices")?; let sys_mem = self.get_sys_mem(); - let mut ramfb = Ramfb::new(sys_mem.clone(), config.install); + let mut ramfb = Ramfb::new(sys_mem.clone(), &self.base.sysbus, config.install); ramfb.ramfb_state.setup(&fwcfg_dev)?; - ramfb.realize(&self.base.sysbus) + ramfb.realize() } fn get_pci_host(&mut self) -> Result<&Arc>> { diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 62f01f69..d6e7813d 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -1221,16 +1221,15 @@ pub trait MachineOps: MachineLifecycle { bail!("Wrong! Two scsi devices have the same scsi-id and lun!"); } let iothread = cntlr.config.iothread.clone(); - - let device = Arc::new(Mutex::new(ScsiDevice::new( + let scsi_device = ScsiDevice::new( device_cfg.clone(), drive_arg, self.get_drive_files(), iothread, - ))); - device.lock().unwrap().realize()?; - bus.lock().unwrap().attach_child(key, device.clone())?; - device.lock().unwrap().base.parent = Some(Arc::downgrade(bus) as Weak>); + bus.clone(), + ); + let device = scsi_device.realize()?; + bus.lock().unwrap().attach_child(key, device)?; if let Some(bootindex) = device_cfg.bootindex { // Eg: OpenFirmware device path(virtio-scsi disk): diff --git a/machine/src/micro_common/mod.rs b/machine/src/micro_common/mod.rs index 9e5551be..55fb2037 100644 --- a/machine/src/micro_common/mod.rs +++ b/machine/src/micro_common/mod.rs @@ -500,7 +500,7 @@ impl LightMachine { region_size, )?; let mmio_device = dev - .realize(&self.base.sysbus) + .realize() .with_context(|| MachineError::RlzVirtioMmioErr)?; #[cfg(target_arch = "x86_64")] { diff --git a/machine/src/x86_64/micro.rs b/machine/src/x86_64/micro.rs index 0c0afc76..f33189bc 100644 --- a/machine/src/x86_64/micro.rs +++ b/machine/src/x86_64/micro.rs @@ -134,7 +134,7 @@ impl MachineOps for LightMachine { let region_size: u64 = 8; let serial = Serial::new(config.clone(), &self.base.sysbus, region_base, region_size)?; serial - .realize(&self.base.sysbus) + .realize() .with_context(|| "Failed to realize serial device.") } diff --git a/machine/src/x86_64/standard.rs b/machine/src/x86_64/standard.rs index be3067c6..b1cfe285 100644 --- a/machine/src/x86_64/standard.rs +++ b/machine/src/x86_64/standard.rs @@ -226,7 +226,7 @@ impl StdMachine { self.base.cpus.clone(), )?; let realize_controller = cpu_controller - .realize(&self.base.sysbus) + .realize() .with_context(|| "Failed to realize Cpu Controller")?; self.register_hotplug_vcpu_event(hotplug_cpu_req, vm)?; self.cpu_controller = Some(realize_controller); @@ -286,7 +286,8 @@ impl StdMachineOps for StdMachine { .add_file_entry("bootorder", boot_order) .with_context(|| DevErrorKind::AddEntryErr("bootorder".to_string()))?; - let fwcfg_dev = FwCfgIO::realize(fwcfg, &self.base.sysbus) + let fwcfg_dev = fwcfg + .realize() .with_context(|| "Failed to realize fwcfg device")?; self.base.fwcfg_dev = Some(fwcfg_dev.clone()); @@ -441,7 +442,7 @@ impl MachineOps for StdMachine { MEM_LAYOUT[LayoutEntryType::MemBelow4g as usize].0 + MEM_LAYOUT[LayoutEntryType::MemBelow4g as usize].1, ); - rtc.realize(&self.base.sysbus) + rtc.realize() .with_context(|| "Failed to realize RTC device") } @@ -457,8 +458,7 @@ impl MachineOps for StdMachine { ged_event, )?; - ged.realize(&self.base.sysbus) - .with_context(|| "Failed to realize Ged")?; + ged.realize().with_context(|| "Failed to realize Ged")?; Ok(()) } @@ -467,7 +467,7 @@ impl MachineOps for StdMachine { let region_size: u64 = 8; let serial = Serial::new(config.clone(), &self.base.sysbus, region_base, region_size)?; serial - .realize(&self.base.sysbus) + .realize() .with_context(|| "Failed to realize serial device.")?; Ok(()) } @@ -623,7 +623,7 @@ impl MachineOps for StdMachine { ) .with_context(|| MachineError::InitPflashErr)?; pflash - .realize(&self.base.sysbus) + .realize() .with_context(|| MachineError::RlzPflashErr)?; flash_end -= pfl_size; } diff --git a/virtio/src/transport/virtio_mmio.rs b/virtio/src/transport/virtio_mmio.rs index 8e872a38..cab3973d 100644 --- a/virtio/src/transport/virtio_mmio.rs +++ b/virtio/src/transport/virtio_mmio.rs @@ -27,7 +27,7 @@ use crate::{ }; use address_space::{AddressRange, AddressSpace, GuestAddress, RegionIoEventFd}; use devices::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; -use devices::{Device, DeviceBase}; +use devices::{convert_bus_mut, Device, DeviceBase, MUT_SYS_BUS}; use migration::{DeviceStateDesc, FieldDesc, MigrationHook, MigrationManager, StateTransfer}; use migration_derive::{ByteCode, Desc}; use util::byte_code::ByteCode; @@ -159,11 +159,12 @@ impl VirtioMmioDevice { interrupt_cb: None, }; mmio_device.set_sys_resource(sysbus, region_base, region_size, "VirtioMmio")?; + mmio_device.set_parent_bus(sysbus.clone()); Ok(mmio_device) } - pub fn realize(mut self, sysbus: &Arc>) -> Result>> { + pub fn realize(mut self) -> Result>> { self.assign_interrupt_cb(); self.device .lock() @@ -171,8 +172,10 @@ impl VirtioMmioDevice { .realize() .with_context(|| "Failed to realize virtio.")?; + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); let dev = Arc::new(Mutex::new(self)); - sysbus.lock().unwrap().attach_device(&dev)?; + sysbus.attach_device(&dev)?; Ok(dev) } -- Gitee From 9ac5ada1e236765de3b32de8d0a61ff7dd3fa9fe Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sun, 14 Jul 2024 10:13:46 +0800 Subject: [PATCH 204/489] devices: unified device `realize` function Move `realize` function to `Device` trait to unify `realize` function: 1. Each device has its own `realize` logic. Signed-off-by: liuxiangdong --- devices/src/acpi/cpu_controller.rs | 16 ++-- devices/src/acpi/ged.rs | 32 ++++---- devices/src/acpi/power.rs | 47 ++++++------ devices/src/legacy/fwcfg.rs | 44 +++++------ devices/src/legacy/pflash.rs | 38 ++++----- devices/src/legacy/pl011.rs | 57 +++++++------- devices/src/legacy/pl031.rs | 24 +++--- devices/src/legacy/ramfb.rs | 16 ++-- devices/src/legacy/rtc.rs | 16 ++-- devices/src/legacy/serial.rs | 53 ++++++------- devices/src/lib.rs | 10 +++ devices/src/misc/ivshmem.rs | 15 ++-- devices/src/misc/pvpanic.rs | 20 ++--- devices/src/misc/scream/mod.rs | 15 ++-- devices/src/pci/demo_device/mod.rs | 38 ++++----- devices/src/pci/mod.rs | 30 ++++---- devices/src/pci/root_port.rs | 50 ++++++------ devices/src/scsi/disk.rs | 110 +++++++++++++-------------- devices/src/usb/storage.rs | 2 +- devices/src/usb/uas.rs | 2 +- devices/src/usb/xhci/xhci_pci.rs | 22 +++--- machine/src/aarch64/micro.rs | 7 +- machine/src/aarch64/pci_host_root.rs | 15 ++-- machine/src/aarch64/standard.rs | 11 ++- machine/src/lib.rs | 3 +- machine/src/micro_common/mod.rs | 1 + machine/src/x86_64/ich9_lpc.rs | 15 ++-- machine/src/x86_64/mch.rs | 15 ++-- machine/src/x86_64/micro.rs | 8 +- machine/src/x86_64/standard.rs | 11 ++- vfio/src/vfio_pci.rs | 28 +++---- virtio/src/transport/virtio_mmio.rs | 32 ++++---- virtio/src/transport/virtio_pci.rs | 50 ++++++------ 33 files changed, 439 insertions(+), 414 deletions(-) diff --git a/devices/src/acpi/cpu_controller.rs b/devices/src/acpi/cpu_controller.rs index a15fdc39..797f44d4 100644 --- a/devices/src/acpi/cpu_controller.rs +++ b/devices/src/acpi/cpu_controller.rs @@ -112,14 +112,6 @@ impl CpuController { Ok(cpu_controller) } - pub fn realize(self) -> Result>> { - let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); - MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); - let dev = Arc::new(Mutex::new(self)); - sysbus.attach_device(&dev)?; - Ok(dev) - } - fn eject_cpu(&mut self, vcpu_id: u8) -> Result<()> { let vcpu = self.vcpu_map.get(&vcpu_id).unwrap(); vcpu.destroy()?; @@ -256,6 +248,14 @@ impl CpuController { impl Device for CpuController { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); + + fn realize(self) -> Result>> { + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); + let dev = Arc::new(Mutex::new(self)); + sysbus.attach_device(&dev)?; + Ok(dev) + } } impl SysBusDevOps for CpuController { diff --git a/devices/src/acpi/ged.rs b/devices/src/acpi/ged.rs index 915b2bce..76a15032 100644 --- a/devices/src/acpi/ged.rs +++ b/devices/src/acpi/ged.rs @@ -104,22 +104,6 @@ impl Ged { Ok(ged) } - pub fn realize(self) -> Result>> { - let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); - MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); - let ged_event = self.ged_event.clone(); - let dev = Arc::new(Mutex::new(self)); - sysbus.attach_device(&dev)?; - - let ged = dev.lock().unwrap(); - ged.register_acpi_powerdown_event(ged_event.power_button) - .with_context(|| "Failed to register ACPI powerdown event.")?; - #[cfg(target_arch = "x86_64")] - ged.register_acpi_cpu_resize_event(ged_event.cpu_resize) - .with_context(|| "Failed to register ACPI cpu resize event.")?; - Ok(dev.clone()) - } - fn register_acpi_powerdown_event(&self, power_button: Arc) -> Result<()> { let power_down_fd = power_button.as_raw_fd(); let ged_clone = self.clone(); @@ -189,6 +173,22 @@ impl Ged { impl Device for Ged { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); + + fn realize(self) -> Result>> { + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); + let ged_event = self.ged_event.clone(); + let dev = Arc::new(Mutex::new(self)); + sysbus.attach_device(&dev)?; + + let ged = dev.lock().unwrap(); + ged.register_acpi_powerdown_event(ged_event.power_button) + .with_context(|| "Failed to register ACPI powerdown event.")?; + #[cfg(target_arch = "x86_64")] + ged.register_acpi_cpu_resize_event(ged_event.cpu_resize) + .with_context(|| "Failed to register ACPI cpu resize event.")?; + Ok(dev.clone()) + } } impl SysBusDevOps for Ged { diff --git a/devices/src/acpi/power.rs b/devices/src/acpi/power.rs index faea9c85..3a2a614c 100644 --- a/devices/src/acpi/power.rs +++ b/devices/src/acpi/power.rs @@ -184,29 +184,6 @@ impl PowerDev { fn send_power_event(&self, evt: AcpiEvent) { self.ged.lock().unwrap().inject_acpi_event(evt); } - - pub fn realize(self) -> Result<()> { - let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); - MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); - let dev = Arc::new(Mutex::new(self)); - sysbus.attach_device(&dev)?; - - let pdev_available: bool; - { - let mut pdev = dev.lock().unwrap(); - pdev_available = pdev.power_battery_init_info().is_ok(); - if pdev_available { - pdev.send_power_event(AcpiEvent::BatteryInf); - } - } - if pdev_available { - power_status_update(&dev); - } else { - let mut pdev = dev.lock().unwrap(); - pdev.power_load_static_status(); - } - Ok(()) - } } impl StateTransfer for PowerDev { @@ -234,6 +211,30 @@ impl MigrationHook for PowerDev { impl Device for PowerDev { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); + + fn realize(self) -> Result>> { + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); + let dev = Arc::new(Mutex::new(self)); + sysbus.attach_device(&dev)?; + + let pdev_available: bool; + { + let mut pdev = dev.lock().unwrap(); + pdev_available = pdev.power_battery_init_info().is_ok(); + if pdev_available { + pdev.send_power_event(AcpiEvent::BatteryInf); + } + } + if pdev_available { + power_status_update(&dev); + } else { + let mut pdev = dev.lock().unwrap(); + pdev.power_load_static_status(); + } + + Ok(dev) + } } impl SysBusDevOps for PowerDev { diff --git a/devices/src/legacy/fwcfg.rs b/devices/src/legacy/fwcfg.rs index 25635fc8..71258d93 100644 --- a/devices/src/legacy/fwcfg.rs +++ b/devices/src/legacy/fwcfg.rs @@ -859,17 +859,6 @@ impl FwCfgMem { Ok(fwcfgmem) } - - pub fn realize(mut self) -> Result>> { - let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); - MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); - self.fwcfg.common_realize()?; - let dev = Arc::new(Mutex::new(self)); - sysbus - .attach_device(&dev) - .with_context(|| "Failed to attach FwCfg device to system bus.")?; - Ok(dev) - } } #[cfg(target_arch = "aarch64")] @@ -942,6 +931,17 @@ impl Device for FwCfgMem { self.fwcfg.select_entry(FwCfgEntryType::Signature as u16); Ok(()) } + + fn realize(mut self) -> Result>> { + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); + self.fwcfg.common_realize()?; + let dev = Arc::new(Mutex::new(self)); + sysbus + .attach_device(&dev) + .with_context(|| "Failed to attach FwCfg device to system bus.")?; + Ok(dev) + } } #[cfg(target_arch = "aarch64")] @@ -1021,17 +1021,6 @@ impl FwCfgIO { Ok(fwcfg) } - - pub fn realize(mut self) -> Result>> { - let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); - MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); - self.fwcfg.common_realize()?; - let dev = Arc::new(Mutex::new(self)); - sysbus - .attach_device(&dev) - .with_context(|| "Failed to attach FwCfg device to system bus.")?; - Ok(dev) - } } #[cfg(target_arch = "x86_64")] @@ -1102,6 +1091,17 @@ impl Device for FwCfgIO { self.fwcfg.select_entry(FwCfgEntryType::Signature as u16); Ok(()) } + + fn realize(mut self) -> Result>> { + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); + self.fwcfg.common_realize()?; + let dev = Arc::new(Mutex::new(self)); + sysbus + .attach_device(&dev) + .with_context(|| "Failed to attach FwCfg device to system bus.")?; + Ok(dev) + } } #[cfg(target_arch = "x86_64")] diff --git a/devices/src/legacy/pflash.rs b/devices/src/legacy/pflash.rs index e0a1b3af..d3a6c0a4 100644 --- a/devices/src/legacy/pflash.rs +++ b/devices/src/legacy/pflash.rs @@ -231,25 +231,6 @@ impl PFlash { Ok(pflash) } - pub fn realize(self) -> Result>> { - let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); - MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); - let region_base = self.base.res.region_base; - let host_mmap = self.host_mmap.clone(); - let dev = Arc::new(Mutex::new(self)); - let region_ops = sysbus.build_region_ops(&dev); - let rom_region = Region::init_rom_device_region(host_mmap, region_ops, "PflashRom"); - dev.lock().unwrap().rom = Some(rom_region.clone()); - sysbus - .sys_mem - .root() - .add_subregion(rom_region, region_base) - .with_context(|| "Failed to attach PFlash to system bus")?; - sysbus.sysbus_attach_child(dev.clone())?; - - Ok(dev) - } - fn set_read_array_mode(&mut self, is_illegal_cmd: bool) -> Result<()> { if is_illegal_cmd { warn!( @@ -712,6 +693,25 @@ impl Device for PFlash { self.status = 0x80; Ok(()) } + + fn realize(self) -> Result>> { + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); + let region_base = self.base.res.region_base; + let host_mmap = self.host_mmap.clone(); + let dev = Arc::new(Mutex::new(self)); + let region_ops = sysbus.build_region_ops(&dev); + let rom_region = Region::init_rom_device_region(host_mmap, region_ops, "PflashRom"); + dev.lock().unwrap().rom = Some(rom_region.clone()); + sysbus + .sys_mem + .root() + .add_subregion(rom_region, region_base) + .with_context(|| "Failed to attach PFlash to system bus")?; + sysbus.sysbus_attach_child(dev.clone())?; + + Ok(dev) + } } impl SysBusDevOps for PFlash { diff --git a/devices/src/legacy/pl011.rs b/devices/src/legacy/pl011.rs index 35c04fe7..b656b875 100644 --- a/devices/src/legacy/pl011.rs +++ b/devices/src/legacy/pl011.rs @@ -163,34 +163,6 @@ impl PL011 { } } - pub fn realize(self) -> Result<()> { - self.chardev - .lock() - .unwrap() - .realize() - .with_context(|| "Failed to realize chardev")?; - let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); - MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); - let dev = Arc::new(Mutex::new(self)); - sysbus - .attach_device(&dev) - .with_context(|| "Failed to attach PL011 to system bus.")?; - drop(locked_bus); - MigrationManager::register_device_instance( - PL011State::descriptor(), - dev.clone(), - PL011_SNAPSHOT_ID, - ); - let locked_dev = dev.lock().unwrap(); - locked_dev.chardev.lock().unwrap().set_receiver(&dev); - EventLoop::update_event( - EventNotifierHelper::internal_notifiers(locked_dev.chardev.clone()), - None, - ) - .with_context(|| LegacyError::RegNotifierErr)?; - Ok(()) - } - fn unpause_rx(&mut self) { if self.paused { trace::pl011_unpause_rx(); @@ -236,6 +208,35 @@ impl InputReceiver for PL011 { impl Device for PL011 { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); + + fn realize(self) -> Result>> { + self.chardev + .lock() + .unwrap() + .realize() + .with_context(|| "Failed to realize chardev")?; + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); + let dev = Arc::new(Mutex::new(self)); + sysbus + .attach_device(&dev) + .with_context(|| "Failed to attach PL011 to system bus.")?; + drop(locked_bus); + MigrationManager::register_device_instance( + PL011State::descriptor(), + dev.clone(), + PL011_SNAPSHOT_ID, + ); + let locked_dev = dev.lock().unwrap(); + locked_dev.chardev.lock().unwrap().set_receiver(&dev); + EventLoop::update_event( + EventNotifierHelper::internal_notifiers(locked_dev.chardev.clone()), + None, + ) + .with_context(|| LegacyError::RegNotifierErr)?; + drop(locked_dev); + Ok(dev) + } } impl SysBusDevOps for PL011 { diff --git a/devices/src/legacy/pl031.rs b/devices/src/legacy/pl031.rs index b88454c4..a206a6fe 100644 --- a/devices/src/legacy/pl031.rs +++ b/devices/src/legacy/pl031.rs @@ -100,7 +100,16 @@ impl PL031 { Ok(pl031) } - pub fn realize(self) -> Result<()> { + /// Get current clock value. + fn get_current_value(&self) -> u32 { + (self.base_time.elapsed().as_secs() as u128 + self.tick_offset as u128) as u32 + } +} + +impl Device for PL031 { + gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); + + fn realize(self) -> Result>> { let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); let dev = Arc::new(Mutex::new(self)); @@ -108,21 +117,12 @@ impl PL031 { MigrationManager::register_device_instance( PL031State::descriptor(), - dev, + dev.clone(), PL031_SNAPSHOT_ID, ); - Ok(()) + Ok(dev) } - - /// Get current clock value. - fn get_current_value(&self) -> u32 { - (self.base_time.elapsed().as_secs() as u128 + self.tick_offset as u128) as u32 - } -} - -impl Device for PL031 { - gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); } impl SysBusDevOps for PL031 { diff --git a/devices/src/legacy/ramfb.rs b/devices/src/legacy/ramfb.rs index b87a62a2..40eda77e 100644 --- a/devices/src/legacy/ramfb.rs +++ b/devices/src/legacy/ramfb.rs @@ -252,14 +252,6 @@ impl Ramfb { ramfb.set_parent_bus(sysbus.clone()); ramfb } - - pub fn realize(self) -> Result<()> { - let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); - MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); - let dev = Arc::new(Mutex::new(self)); - sysbus.attach_device(&dev)?; - Ok(()) - } } impl Device for Ramfb { @@ -269,6 +261,14 @@ impl Device for Ramfb { self.ramfb_state.reset_ramfb_state(); Ok(()) } + + fn realize(self) -> Result>> { + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); + let dev = Arc::new(Mutex::new(self)); + sysbus.attach_device(&dev)?; + Ok(dev) + } } impl SysBusDevOps for Ramfb { diff --git a/devices/src/legacy/rtc.rs b/devices/src/legacy/rtc.rs index add41a88..36934418 100644 --- a/devices/src/legacy/rtc.rs +++ b/devices/src/legacy/rtc.rs @@ -265,14 +265,6 @@ impl RTC { true } - pub fn realize(self) -> Result<()> { - let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); - MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); - let dev = Arc::new(Mutex::new(self)); - sysbus.attach_device(&dev)?; - Ok(()) - } - /// Get current clock value. fn get_current_value(&self) -> i64 { (self.base_time.elapsed().as_secs() as i128 + self.tick_offset as i128) as i64 @@ -356,6 +348,14 @@ impl Device for RTC { self.set_memory(self.mem_size, self.gap_start); Ok(()) } + + fn realize(self) -> Result>> { + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); + let dev = Arc::new(Mutex::new(self)); + sysbus.attach_device(&dev)?; + Ok(dev) + } } impl SysBusDevOps for RTC { diff --git a/devices/src/legacy/serial.rs b/devices/src/legacy/serial.rs index 898a933b..e21112b3 100644 --- a/devices/src/legacy/serial.rs +++ b/devices/src/legacy/serial.rs @@ -145,32 +145,6 @@ impl Serial { Ok(serial) } - pub fn realize(self) -> Result<()> { - self.chardev - .lock() - .unwrap() - .realize() - .with_context(|| "Failed to realize chardev")?; - let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); - MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); - let dev = Arc::new(Mutex::new(self)); - sysbus.attach_device(&dev)?; - - MigrationManager::register_device_instance( - SerialState::descriptor(), - dev.clone(), - SERIAL_SNAPSHOT_ID, - ); - let locked_dev = dev.lock().unwrap(); - locked_dev.chardev.lock().unwrap().set_receiver(&dev); - EventLoop::update_event( - EventNotifierHelper::internal_notifiers(locked_dev.chardev.clone()), - None, - ) - .with_context(|| LegacyError::RegNotifierErr)?; - Ok(()) - } - fn unpause_rx(&mut self) { if self.paused { trace::serial_unpause_rx(); @@ -378,6 +352,33 @@ impl InputReceiver for Serial { impl Device for Serial { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); + + fn realize(self) -> Result>> { + self.chardev + .lock() + .unwrap() + .realize() + .with_context(|| "Failed to realize chardev")?; + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); + let dev = Arc::new(Mutex::new(self)); + sysbus.attach_device(&dev)?; + + MigrationManager::register_device_instance( + SerialState::descriptor(), + dev.clone(), + SERIAL_SNAPSHOT_ID, + ); + let locked_dev = dev.lock().unwrap(); + locked_dev.chardev.lock().unwrap().set_receiver(&dev); + EventLoop::update_event( + EventNotifierHelper::internal_notifiers(locked_dev.chardev.clone()), + None, + ) + .with_context(|| LegacyError::RegNotifierErr)?; + drop(locked_dev); + Ok(dev) + } } impl SysBusDevOps for Serial { diff --git a/devices/src/lib.rs b/devices/src/lib.rs index ecc9c140..d335d1a7 100644 --- a/devices/src/lib.rs +++ b/devices/src/lib.rs @@ -114,6 +114,16 @@ pub trait Device: Any + AsAny + Send + Sync { Ok(()) } + /// Realize device. + fn realize(self) -> Result>> + where + Self: Sized, + { + // Note: Only PciHost does not have its own realization logic, + // but it will not be called. + bail!("Realize of the device {} is not implemented", self.name()); + } + /// Unrealize device. fn unrealize(&mut self) -> Result<()> { bail!("Unrealize of the device {} is not implemented", self.name()); diff --git a/devices/src/misc/ivshmem.rs b/devices/src/misc/ivshmem.rs index 685fbb9e..6145bb86 100644 --- a/devices/src/misc/ivshmem.rs +++ b/devices/src/misc/ivshmem.rs @@ -91,12 +91,8 @@ impl Ivshmem { impl Device for Ivshmem { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); -} - -impl PciDevOps for Ivshmem { - gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); - fn realize(mut self) -> Result<()> { + fn realize(mut self) -> Result>> { self.init_write_mask(false)?; self.init_write_clear_mask(false)?; le_write_u16( @@ -122,9 +118,14 @@ impl PciDevOps for Ivshmem { // Attach to the PCI bus. let bus = self.parent_bus().unwrap().upgrade().unwrap(); let mut locked_bus = bus.lock().unwrap(); - locked_bus.attach_child(self.base.devfn as u64, Arc::new(Mutex::new(self)))?; - Ok(()) + let dev = Arc::new(Mutex::new(self)); + locked_bus.attach_child(dev.lock().unwrap().base.devfn as u64, dev.clone())?; + Ok(dev) } +} + +impl PciDevOps for Ivshmem { + gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); fn write_config(&mut self, offset: usize, data: &[u8]) { let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); diff --git a/devices/src/misc/pvpanic.rs b/devices/src/misc/pvpanic.rs index f3bc7409..8c8dcd06 100644 --- a/devices/src/misc/pvpanic.rs +++ b/devices/src/misc/pvpanic.rs @@ -166,15 +166,7 @@ impl PvPanicPci { impl Device for PvPanicPci { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); - fn unrealize(&mut self) -> Result<()> { - Ok(()) - } -} - -impl PciDevOps for PvPanicPci { - gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); - - fn realize(mut self) -> Result<()> { + fn realize(mut self) -> Result>> { self.init_write_mask(false)?; self.init_write_clear_mask(false)?; le_write_u16( @@ -226,10 +218,18 @@ impl PciDevOps for PvPanicPci { .unwrap() .dev_id .store(device_id, Ordering::Release); - locked_bus.attach_child(devfn as u64, dev)?; + locked_bus.attach_child(devfn as u64, dev.clone())?; + Ok(dev) + } + + fn unrealize(&mut self) -> Result<()> { Ok(()) } +} + +impl PciDevOps for PvPanicPci { + gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); fn write_config(&mut self, offset: usize, data: &[u8]) { let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index 254671df..7d4a50a1 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -18,15 +18,10 @@ mod ohaudio; #[cfg(feature = "scream_pulseaudio")] mod pulseaudio; -use std::{ - mem, - str::FromStr, - sync::{ - atomic::{fence, Ordering}, - Arc, Mutex, RwLock, Weak, - }, - thread, -}; +use std::str::FromStr; +use std::sync::atomic::{fence, Ordering}; +use std::sync::{Arc, Mutex, RwLock, Weak}; +use std::{mem, thread}; use anyhow::{anyhow, bail, Context, Result}; use clap::{ArgAction, Parser}; @@ -37,7 +32,7 @@ use log::{error, warn}; use self::alsa::AlsaStreamData; use self::audio_demo::AudioDemo; use super::ivshmem::Ivshmem; -use crate::{pci::PciDevOps, Bus}; +use crate::{Bus, Device}; use address_space::{GuestAddress, HostMemMapping, Region}; use machine_manager::config::{get_pci_df, parse_bool, valid_id}; #[cfg(all(target_env = "ohos", feature = "scream_ohaudio"))] diff --git a/devices/src/pci/demo_device/mod.rs b/devices/src/pci/demo_device/mod.rs index 9e5c20a8..58a88c7d 100644 --- a/devices/src/pci/demo_device/mod.rs +++ b/devices/src/pci/demo_device/mod.rs @@ -126,16 +126,6 @@ impl DemoDev { Ok(()) } - fn attach_to_parent_bus(self) -> Result<()> { - let devfn = self.base.devfn as u64; - let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); - let mut locked_bus = parent_bus.lock().unwrap(); - let demo_pci_dev = Arc::new(Mutex::new(self)); - locked_bus.attach_child(devfn, demo_pci_dev)?; - - Ok(()) - } - fn register_data_handling_bar(&mut self) -> Result<()> { let device = self.device.clone(); let write_ops = move |data: &[u8], addr: GuestAddress, offset: u64| -> bool { @@ -191,16 +181,7 @@ impl Device for DemoDev { self.base.config.reset_common_regs() } - fn unrealize(&mut self) -> Result<()> { - self.device.lock().unwrap().unrealize() - } -} - -impl PciDevOps for DemoDev { - gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); - - /// Realize PCI/PCIe device. - fn realize(mut self) -> Result<()> { + fn realize(mut self) -> Result>> { self.init_pci_config()?; if self.cmd_cfg.bar_num > 0 { init_msix(&mut self.base, 0, 1, self.dev_id.clone(), None, None)?; @@ -209,10 +190,23 @@ impl PciDevOps for DemoDev { self.register_data_handling_bar()?; self.device.lock().unwrap().realize()?; - self.attach_to_parent_bus()?; - Ok(()) + let devfn = self.base.devfn as u64; + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + let mut locked_bus = parent_bus.lock().unwrap(); + let demo_pci_dev = Arc::new(Mutex::new(self)); + locked_bus.attach_child(devfn, demo_pci_dev.clone())?; + + Ok(demo_pci_dev) } + fn unrealize(&mut self) -> Result<()> { + self.device.lock().unwrap().unrealize() + } +} + +impl PciDevOps for DemoDev { + gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); + /// write the pci configuration space fn write_config(&mut self, offset: usize, data: &[u8]) { let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs index 8d2ce847..ccac50e5 100644 --- a/devices/src/pci/mod.rs +++ b/devices/src/pci/mod.rs @@ -172,9 +172,6 @@ pub trait PciDevOps: Device + Send { Ok(()) } - /// Realize PCI/PCIe device. - fn realize(self) -> Result<()>; - /// Configuration space read. /// /// # Arguments @@ -424,6 +421,21 @@ mod tests { impl Device for TestPciDevice { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); + fn realize(mut self) -> Result>> { + let devfn = self.base.devfn as u64; + self.init_write_mask(false)?; + self.init_write_clear_mask(false)?; + + let dev = Arc::new(Mutex::new(self)); + let parent_bus = dev.lock().unwrap().parent_bus().unwrap().upgrade().unwrap(); + parent_bus + .lock() + .unwrap() + .attach_child(devfn, dev.clone())?; + + Ok(dev) + } + fn unrealize(&mut self) -> Result<()> { Ok(()) } @@ -443,18 +455,6 @@ mod tests { ); } - fn realize(mut self) -> Result<()> { - let devfn = self.base.devfn as u64; - self.init_write_mask(false)?; - self.init_write_clear_mask(false)?; - - let dev = Arc::new(Mutex::new(self)); - let parent_bus = dev.lock().unwrap().parent_bus().unwrap().upgrade().unwrap(); - parent_bus.lock().unwrap().attach_child(devfn, dev)?; - - Ok(()) - } - fn init_write_mask(&mut self, _is_bridge: bool) -> Result<()> { let mut offset = 0_usize; while offset < self.base.config.config.len() { diff --git a/devices/src/pci/root_port.rs b/devices/src/pci/root_port.rs index 5c978646..0d854c08 100644 --- a/devices/src/pci/root_port.rs +++ b/devices/src/pci/root_port.rs @@ -370,28 +370,8 @@ impl Device for RootPort { self.base.config.reset_bridge_regs()?; self.base.config.reset() } -} -/// Convert from Arc> to &mut RootPort. -#[macro_export] -macro_rules! MUT_ROOT_PORT { - ($trait_device:expr, $lock_device: ident, $struct_device: ident) => { - convert_device_mut!($trait_device, $lock_device, $struct_device, RootPort); - }; -} - -/// Convert from Arc> to &RootPort. -#[macro_export] -macro_rules! ROOT_PORT { - ($trait_device:expr, $lock_device: ident, $struct_device: ident) => { - convert_device_ref!($trait_device, $lock_device, $struct_device, RootPort); - }; -} - -impl PciDevOps for RootPort { - gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); - - fn realize(mut self) -> Result<()> { + fn realize(mut self) -> Result>> { let parent_bus = self.parent_bus().unwrap(); self.init_write_mask(true)?; self.init_write_clear_mask(true)?; @@ -456,10 +436,34 @@ impl PciDevOps for RootPort { parent_pci_bus.attach_child(locked_root_port.base.devfn as u64, root_port.clone())?; // Need to drop locked_root_port in order to register root_port instance. drop(locked_root_port); - MigrationManager::register_device_instance(RootPortState::descriptor(), root_port, &name); + MigrationManager::register_device_instance( + RootPortState::descriptor(), + root_port.clone(), + &name, + ); - Ok(()) + Ok(root_port) } +} + +/// Convert from Arc> to &mut RootPort. +#[macro_export] +macro_rules! MUT_ROOT_PORT { + ($trait_device:expr, $lock_device: ident, $struct_device: ident) => { + convert_device_mut!($trait_device, $lock_device, $struct_device, RootPort); + }; +} + +/// Convert from Arc> to &RootPort. +#[macro_export] +macro_rules! ROOT_PORT { + ($trait_device:expr, $lock_device: ident, $struct_device: ident) => { + convert_device_ref!($trait_device, $lock_device, $struct_device, RootPort); + }; +} + +impl PciDevOps for RootPort { + gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); fn write_config(&mut self, offset: usize, data: &[u8]) { let size = data.len(); diff --git a/devices/src/scsi/disk.rs b/devices/src/scsi/disk.rs index 9e1c9895..a3106890 100644 --- a/devices/src/scsi/disk.rs +++ b/devices/src/scsi/disk.rs @@ -135,6 +135,61 @@ impl ScsiDevState { impl Device for ScsiDevice { gen_base_func!(device_base, device_base_mut, DeviceBase, base); + + fn realize(mut self) -> Result>> { + match self.scsi_type { + SCSI_TYPE_DISK => { + self.block_size = SCSI_DISK_DEFAULT_BLOCK_SIZE; + self.state.product = "STRA HARDDISK".to_string(); + } + SCSI_TYPE_ROM => { + self.block_size = SCSI_CDROM_DEFAULT_BLOCK_SIZE; + self.state.product = "STRA CDROM".to_string(); + } + _ => { + bail!("Scsi type {} does not support now", self.scsi_type); + } + } + + if let Some(serial) = &self.dev_cfg.serial { + self.state.serial = serial.clone(); + } + + let drive_files = self.drive_files.lock().unwrap(); + // File path can not be empty string. And it has also been checked in command parsing by using `Clap`. + let file = VmConfig::fetch_drive_file(&drive_files, &self.drive_cfg.path_on_host)?; + + let alignments = VmConfig::fetch_drive_align(&drive_files, &self.drive_cfg.path_on_host)?; + self.req_align = alignments.0; + self.buf_align = alignments.1; + let drive_id = VmConfig::get_drive_id(&drive_files, &self.drive_cfg.path_on_host)?; + drop(drive_files); + + let mut thread_pool = None; + if self.drive_cfg.aio != AioEngine::Off { + thread_pool = Some(EventLoop::get_ctx(None).unwrap().thread_pool.clone()); + } + let aio = Aio::new(Arc::new(aio_complete_cb), self.drive_cfg.aio, thread_pool)?; + let conf = BlockProperty { + id: drive_id, + format: self.drive_cfg.format, + iothread: self.iothread.clone(), + direct: self.drive_cfg.direct, + req_align: self.req_align, + buf_align: self.buf_align, + discard: false, + write_zeroes: WriteZeroesState::Off, + l2_cache_size: self.drive_cfg.l2_cache_size, + refcount_cache_size: self.drive_cfg.refcount_cache_size, + }; + let backend = create_block_backend(file, aio, conf)?; + let disk_size = backend.lock().unwrap().disk_size()?; + self.block_backend = Some(backend); + self.disk_sectors = disk_size >> SECTOR_SHIFT; + + let dev = Arc::new(Mutex::new(self)); + Ok(dev) + } } /// Convert from Arc> to &ScsiDevice. @@ -206,61 +261,6 @@ impl ScsiDevice { scsi_dev.set_parent_bus(scsi_bus); scsi_dev } - - pub fn realize(mut self) -> Result>> { - match self.scsi_type { - SCSI_TYPE_DISK => { - self.block_size = SCSI_DISK_DEFAULT_BLOCK_SIZE; - self.state.product = "STRA HARDDISK".to_string(); - } - SCSI_TYPE_ROM => { - self.block_size = SCSI_CDROM_DEFAULT_BLOCK_SIZE; - self.state.product = "STRA CDROM".to_string(); - } - _ => { - bail!("Scsi type {} does not support now", self.scsi_type); - } - } - - if let Some(serial) = &self.dev_cfg.serial { - self.state.serial = serial.clone(); - } - - let drive_files = self.drive_files.lock().unwrap(); - // File path can not be empty string. And it has also been checked in command parsing by using `Clap`. - let file = VmConfig::fetch_drive_file(&drive_files, &self.drive_cfg.path_on_host)?; - - let alignments = VmConfig::fetch_drive_align(&drive_files, &self.drive_cfg.path_on_host)?; - self.req_align = alignments.0; - self.buf_align = alignments.1; - let drive_id = VmConfig::get_drive_id(&drive_files, &self.drive_cfg.path_on_host)?; - drop(drive_files); - - let mut thread_pool = None; - if self.drive_cfg.aio != AioEngine::Off { - thread_pool = Some(EventLoop::get_ctx(None).unwrap().thread_pool.clone()); - } - let aio = Aio::new(Arc::new(aio_complete_cb), self.drive_cfg.aio, thread_pool)?; - let conf = BlockProperty { - id: drive_id, - format: self.drive_cfg.format, - iothread: self.iothread.clone(), - direct: self.drive_cfg.direct, - req_align: self.req_align, - buf_align: self.buf_align, - discard: false, - write_zeroes: WriteZeroesState::Off, - l2_cache_size: self.drive_cfg.l2_cache_size, - refcount_cache_size: self.drive_cfg.refcount_cache_size, - }; - let backend = create_block_backend(file, aio, conf)?; - let disk_size = backend.lock().unwrap().disk_size()?; - self.block_backend = Some(backend); - self.disk_sectors = disk_size >> SECTOR_SHIFT; - - let dev = Arc::new(Mutex::new(self)); - Ok(dev) - } } #[cfg(test)] diff --git a/devices/src/usb/storage.rs b/devices/src/usb/storage.rs index 2c03f09a..e8765ea9 100644 --- a/devices/src/usb/storage.rs +++ b/devices/src/usb/storage.rs @@ -28,12 +28,12 @@ use super::descriptor::{ use super::xhci::xhci_controller::XhciDevice; use super::{config::*, USB_DEVICE_BUFFER_DEFAULT_LEN}; use super::{UsbDevice, UsbDeviceBase, UsbDeviceRequest, UsbPacket, UsbPacketStatus}; -use crate::Bus; use crate::ScsiBus::{ get_scsi_key, ScsiBus, ScsiRequest, ScsiRequestOps, ScsiSense, ScsiXferMode, EMULATE_SCSI_OPS, GOOD, SCSI_CMD_BUF_SIZE, }; use crate::ScsiDisk::{ScsiDevConfig, ScsiDevice}; +use crate::{Bus, Device}; use machine_manager::config::{DriveConfig, DriveFile}; use util::aio::AioEngine; use util::gen_base_func; diff --git a/devices/src/usb/uas.rs b/devices/src/usb/uas.rs index d4c9dfbc..79780033 100644 --- a/devices/src/usb/uas.rs +++ b/devices/src/usb/uas.rs @@ -34,13 +34,13 @@ use super::{ UsbDevice, UsbDeviceBase, UsbDeviceRequest, UsbPacket, UsbPacketStatus, USB_DEVICE_BUFFER_DEFAULT_LEN, }; -use crate::Bus; use crate::ScsiBus::{ get_scsi_key, scsi_cdb_xfer, ScsiBus, ScsiRequest, ScsiRequestOps, ScsiSense, ScsiXferMode, CHECK_CONDITION, EMULATE_SCSI_OPS, GOOD, SCSI_SENSE_INVALID_PARAM_VALUE, SCSI_SENSE_INVALID_TAG, SCSI_SENSE_NO_SENSE, }; use crate::ScsiDisk::{ScsiDevConfig, ScsiDevice}; +use crate::{Bus, Device}; use machine_manager::config::{DriveConfig, DriveFile}; use util::byte_code::ByteCode; use util::gen_base_func; diff --git a/devices/src/usb/xhci/xhci_pci.rs b/devices/src/usb/xhci/xhci_pci.rs index 67afc3ca..07b2bb2b 100644 --- a/devices/src/usb/xhci/xhci_pci.rs +++ b/devices/src/usb/xhci/xhci_pci.rs @@ -247,16 +247,7 @@ impl Device for XhciPciDevice { Ok(()) } - fn unrealize(&mut self) -> Result<()> { - trace::usb_xhci_exit(); - Ok(()) - } -} - -impl PciDevOps for XhciPciDevice { - gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); - - fn realize(mut self) -> Result<()> { + fn realize(mut self) -> Result>> { self.init_write_mask(false)?; self.init_write_clear_mask(false)?; le_write_u16( @@ -351,9 +342,18 @@ impl PciDevOps for XhciPciDevice { let dev = Arc::new(Mutex::new(self)); // Attach to the PCI bus. let bus = dev.lock().unwrap().parent_bus().unwrap().upgrade().unwrap(); - bus.lock().unwrap().attach_child(devfn, dev)?; + bus.lock().unwrap().attach_child(devfn, dev.clone())?; + Ok(dev) + } + + fn unrealize(&mut self) -> Result<()> { + trace::usb_xhci_exit(); Ok(()) } +} + +impl PciDevOps for XhciPciDevice { + gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); fn write_config(&mut self, offset: usize, data: &[u8]) { let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); diff --git a/machine/src/aarch64/micro.rs b/machine/src/aarch64/micro.rs index 9c04f55f..57802912 100644 --- a/machine/src/aarch64/micro.rs +++ b/machine/src/aarch64/micro.rs @@ -19,7 +19,7 @@ use crate::{register_shutdown_event, LightMachine, MachineOps}; use address_space::{AddressSpace, GuestAddress, Region}; use cpu::CPUTopology; use devices::legacy::{PL011, PL031}; -use devices::{ICGICConfig, ICGICv2Config, ICGICv3Config, GIC_IRQ_MAX}; +use devices::{Device, ICGICConfig, ICGICv2Config, ICGICv3Config, GIC_IRQ_MAX}; use hypervisor::kvm::aarch64::*; use machine_manager::config::{Param, SerialConfig, VmConfig}; use migration::{MigrationManager, MigrationStatus}; @@ -111,7 +111,10 @@ impl MachineOps for LightMachine { MEM_LAYOUT[LayoutEntryType::Rtc as usize].0, MEM_LAYOUT[LayoutEntryType::Rtc as usize].1, )?; - pl031.realize().with_context(|| "Failed to realize pl031.") + pl031 + .realize() + .with_context(|| "Failed to realize pl031.")?; + Ok(()) } fn add_serial_device(&mut self, config: &SerialConfig) -> Result<()> { diff --git a/machine/src/aarch64/pci_host_root.rs b/machine/src/aarch64/pci_host_root.rs index d3566f3c..b3950f24 100644 --- a/machine/src/aarch64/pci_host_root.rs +++ b/machine/src/aarch64/pci_host_root.rs @@ -43,12 +43,8 @@ impl PciHostRoot { impl Device for PciHostRoot { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); -} - -impl PciDevOps for PciHostRoot { - gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); - fn realize(mut self) -> Result<()> { + fn realize(mut self) -> Result>> { self.init_write_mask(false)?; self.init_write_clear_mask(false)?; @@ -71,10 +67,15 @@ impl PciDevOps for PciHostRoot { let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); let mut locked_bus = parent_bus.lock().unwrap(); - locked_bus.attach_child(0, Arc::new(Mutex::new(self)))?; + let dev = Arc::new(Mutex::new(self)); + locked_bus.attach_child(0, dev.clone())?; - Ok(()) + Ok(dev) } +} + +impl PciDevOps for PciHostRoot { + gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); fn write_config(&mut self, offset: usize, data: &[u8]) { self.base.config.write(offset, data, 0, None); diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index a848e120..9be74e0c 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -48,7 +48,7 @@ use devices::legacy::{ }; #[cfg(feature = "ramfb")] use devices::legacy::{Ramfb, RamfbConfig}; -use devices::pci::{PciBus, PciDevOps, PciHost, PciIntxState}; +use devices::pci::{PciBus, PciHost, PciIntxState}; use devices::sysbus::{to_sysbusdevops, SysBusDevType}; use devices::{ convert_bus_mut, Device, ICGICConfig, ICGICv3Config, GIC_IRQ_MAX, MUT_PCI_BUS, SYS_BUS_DEVICE, @@ -339,7 +339,8 @@ impl StdMachineOps for StdMachine { let pcihost_root = PciHostRoot::new(root_bus); pcihost_root .realize() - .with_context(|| "Failed to realize pcihost root device.") + .with_context(|| "Failed to realize pcihost root device.")?; + Ok(()) } fn add_fwcfg_device(&mut self, nr_cpus: u8) -> Result>>> { @@ -461,7 +462,8 @@ impl MachineOps for StdMachine { MEM_LAYOUT[LayoutEntryType::Rtc as usize].0, MEM_LAYOUT[LayoutEntryType::Rtc as usize].1, )?; - rtc.realize().with_context(|| "Failed to realize PL031") + rtc.realize().with_context(|| "Failed to realize PL031")?; + Ok(()) } fn add_ged_device(&mut self) -> Result<()> { @@ -709,7 +711,8 @@ impl MachineOps for StdMachine { let mut ramfb = Ramfb::new(sys_mem.clone(), &self.base.sysbus, config.install); ramfb.ramfb_state.setup(&fwcfg_dev)?; - ramfb.realize() + ramfb.realize()?; + Ok(()) } fn get_pci_host(&mut self) -> Result<&Arc>> { diff --git a/machine/src/lib.rs b/machine/src/lib.rs index d6e7813d..8a47faac 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -1945,7 +1945,8 @@ pub trait MachineOps: MachineLifecycle { let sys_mem = self.get_sys_mem().clone(); let demo_dev = DemoDev::new(config, devfn, sys_mem, parent_bus); - demo_dev.realize() + demo_dev.realize()?; + Ok(()) } /// Return the syscall whitelist for seccomp. diff --git a/machine/src/micro_common/mod.rs b/machine/src/micro_common/mod.rs index 55fb2037..53f12626 100644 --- a/machine/src/micro_common/mod.rs +++ b/machine/src/micro_common/mod.rs @@ -51,6 +51,7 @@ use cpu::CpuLifecycleState; #[cfg(target_arch = "x86_64")] use devices::sysbus::SysBusDevOps; use devices::sysbus::{IRQ_BASE, IRQ_MAX}; +use devices::Device; #[cfg(target_arch = "x86_64")] use machine_manager::config::Param; use machine_manager::config::{ diff --git a/machine/src/x86_64/ich9_lpc.rs b/machine/src/x86_64/ich9_lpc.rs index e93f85e4..bb9f0e8f 100644 --- a/machine/src/x86_64/ich9_lpc.rs +++ b/machine/src/x86_64/ich9_lpc.rs @@ -230,12 +230,8 @@ impl LPCBridge { impl Device for LPCBridge { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); -} -impl PciDevOps for LPCBridge { - gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); - - fn realize(mut self) -> Result<()> { + fn realize(mut self) -> Result>> { self.init_write_mask(false)?; self.init_write_clear_mask(false)?; @@ -278,9 +274,14 @@ impl PciDevOps for LPCBridge { let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); let mut locked_bus = parent_bus.lock().unwrap(); - locked_bus.attach_child(0x1F << 3, Arc::new(Mutex::new(self)))?; - Ok(()) + let dev = Arc::new(Mutex::new(self)); + locked_bus.attach_child(0x1F << 3, dev.clone())?; + Ok(dev) } +} + +impl PciDevOps for LPCBridge { + gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); fn write_config(&mut self, offset: usize, data: &[u8]) { self.base.config.write(offset, data, 0, None, None); diff --git a/machine/src/x86_64/mch.rs b/machine/src/x86_64/mch.rs index 9ec0d110..0aec6ec8 100644 --- a/machine/src/x86_64/mch.rs +++ b/machine/src/x86_64/mch.rs @@ -112,12 +112,8 @@ impl Mch { impl Device for Mch { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); -} -impl PciDevOps for Mch { - gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); - - fn realize(mut self) -> Result<()> { + fn realize(mut self) -> Result>> { self.init_write_mask(false)?; self.init_write_clear_mask(false)?; @@ -139,9 +135,14 @@ impl PciDevOps for Mch { let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); let mut locked_bus = parent_bus.lock().unwrap(); - locked_bus.attach_child(0, Arc::new(Mutex::new(self)))?; - Ok(()) + let dev = Arc::new(Mutex::new(self)); + locked_bus.attach_child(0, dev.clone())?; + Ok(dev) } +} + +impl PciDevOps for Mch { + gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); fn write_config(&mut self, offset: usize, data: &[u8]) { let old_pciexbar: u64 = le_read_u64(&self.base.config.config, PCIEXBAR as usize).unwrap(); diff --git a/machine/src/x86_64/micro.rs b/machine/src/x86_64/micro.rs index f33189bc..8f0494b5 100644 --- a/machine/src/x86_64/micro.rs +++ b/machine/src/x86_64/micro.rs @@ -18,7 +18,8 @@ use crate::micro_common::syscall::syscall_whitelist; use crate::{register_shutdown_event, LightMachine, MachineBase, MachineError, MachineOps}; use address_space::{AddressSpace, Region}; use cpu::{CPUBootConfig, CPUTopology}; -use devices::legacy::FwCfgOps; +use devices::legacy::{FwCfgOps, Serial, SERIAL_ADDR}; +use devices::Device; use hypervisor::kvm::x86_64::*; use hypervisor::kvm::*; use machine_manager::config::{SerialConfig, VmConfig}; @@ -128,14 +129,13 @@ impl MachineOps for LightMachine { } fn add_serial_device(&mut self, config: &SerialConfig) -> Result<()> { - use devices::legacy::{Serial, SERIAL_ADDR}; - let region_base: u64 = SERIAL_ADDR; let region_size: u64 = 8; let serial = Serial::new(config.clone(), &self.base.sysbus, region_base, region_size)?; serial .realize() - .with_context(|| "Failed to realize serial device.") + .with_context(|| "Failed to realize serial device.")?; + Ok(()) } fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> { diff --git a/machine/src/x86_64/standard.rs b/machine/src/x86_64/standard.rs index b1cfe285..901f054c 100644 --- a/machine/src/x86_64/standard.rs +++ b/machine/src/x86_64/standard.rs @@ -36,7 +36,7 @@ use devices::legacy::{ error::LegacyError as DevErrorKind, FwCfgEntryType, FwCfgIO, FwCfgOps, PFlash, Serial, RTC, SERIAL_ADDR, }; -use devices::pci::{PciBus, PciDevOps, PciHost}; +use devices::pci::{PciBus, PciHost}; use devices::{convert_bus_mut, Device, MUT_PCI_BUS}; use hypervisor::kvm::x86_64::*; use hypervisor::kvm::*; @@ -191,7 +191,8 @@ impl StdMachine { .with_context(|| "Fail to register reset event in LPC")?; register_shutdown_event(ich.shutdown_req.clone(), vm) .with_context(|| "Fail to register shutdown event in LPC")?; - ich.realize() + ich.realize()?; + Ok(()) } pub fn get_vcpu_reg_val(&self, _addr: u64, _vcpu: usize) -> Option { @@ -268,7 +269,8 @@ impl StdMachineOps for StdMachine { .with_context(|| "Failed to register CONFIG_DATA port in I/O space.")?; let mch = Mch::new(root_bus, mmconfig_region, mmconfig_region_ops); - mch.realize() + mch.realize()?; + Ok(()) } fn add_fwcfg_device( @@ -443,7 +445,8 @@ impl MachineOps for StdMachine { + MEM_LAYOUT[LayoutEntryType::MemBelow4g as usize].1, ); rtc.realize() - .with_context(|| "Failed to realize RTC device") + .with_context(|| "Failed to realize RTC device")?; + Ok(()) } fn add_ged_device(&mut self) -> Result<()> { diff --git a/vfio/src/vfio_pci.rs b/vfio/src/vfio_pci.rs index 22ae5945..d52ea581 100644 --- a/vfio/src/vfio_pci.rs +++ b/vfio/src/vfio_pci.rs @@ -822,19 +822,7 @@ impl Device for VfioPciDevice { }) } - fn unrealize(&mut self) -> Result<()> { - if let Err(e) = VfioPciDevice::unrealize(self) { - error!("{:?}", e); - bail!("Failed to unrealize vfio-pci."); - } - Ok(()) - } -} - -impl PciDevOps for VfioPciDevice { - gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); - - fn realize(mut self) -> Result<()> { + fn realize(mut self) -> Result>> { let parent_bus = self.parent_bus().unwrap(); self.init_write_mask(false)?; self.init_write_clear_mask(false)?; @@ -880,10 +868,22 @@ impl PciDevOps for VfioPciDevice { let dev = Arc::new(Mutex::new(self)); let parent_bus = dev.lock().unwrap().parent_bus().unwrap().upgrade().unwrap(); let mut locked_bus = parent_bus.lock().unwrap(); - locked_bus.attach_child(devfn, dev)?; + locked_bus.attach_child(devfn, dev.clone())?; + Ok(dev) + } + + fn unrealize(&mut self) -> Result<()> { + if let Err(e) = VfioPciDevice::unrealize(self) { + error!("{:?}", e); + bail!("Failed to unrealize vfio-pci."); + } Ok(()) } +} + +impl PciDevOps for VfioPciDevice { + gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); /// Read pci data from pci config if it emulate, otherwise read from vfio device. fn read_config(&mut self, offset: usize, data: &mut [u8]) { diff --git a/virtio/src/transport/virtio_mmio.rs b/virtio/src/transport/virtio_mmio.rs index cab3973d..f01f87c0 100644 --- a/virtio/src/transport/virtio_mmio.rs +++ b/virtio/src/transport/virtio_mmio.rs @@ -164,22 +164,6 @@ impl VirtioMmioDevice { Ok(mmio_device) } - pub fn realize(mut self) -> Result>> { - self.assign_interrupt_cb(); - self.device - .lock() - .unwrap() - .realize() - .with_context(|| "Failed to realize virtio.")?; - - let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); - MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); - let dev = Arc::new(Mutex::new(self)); - sysbus.attach_device(&dev)?; - - Ok(dev) - } - /// Activate the virtio device, this function is called by vcpu thread when frontend /// virtio driver is ready and write `DRIVER_OK` to backend. fn activate(&mut self) -> Result<()> { @@ -378,6 +362,22 @@ impl VirtioMmioDevice { impl Device for VirtioMmioDevice { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); + + fn realize(mut self) -> Result>> { + self.assign_interrupt_cb(); + self.device + .lock() + .unwrap() + .realize() + .with_context(|| "Failed to realize virtio.")?; + + let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); + MUT_SYS_BUS!(parent_bus, locked_bus, sysbus); + let dev = Arc::new(Mutex::new(self)); + sysbus.attach_device(&dev)?; + + Ok(dev) + } } impl SysBusDevOps for VirtioMmioDevice { diff --git a/virtio/src/transport/virtio_pci.rs b/virtio/src/transport/virtio_pci.rs index d33c4713..8a058d8e 100644 --- a/virtio/src/transport/virtio_pci.rs +++ b/virtio/src/transport/virtio_pci.rs @@ -1016,28 +1016,7 @@ impl Device for VirtioPciDevice { Ok(()) } - fn unrealize(&mut self) -> Result<()> { - info!("func: unrealize, id: {:?}", &self.base.base.id); - self.device - .lock() - .unwrap() - .unrealize() - .with_context(|| "Failed to unrealize the virtio device")?; - - let bus = self.parent_bus().unwrap().upgrade().unwrap(); - self.base.config.unregister_bars(&bus)?; - - MigrationManager::unregister_device_instance(MsixState::descriptor(), &self.name()); - MigrationManager::unregister_transport_instance(VirtioPciState::descriptor(), &self.name()); - - Ok(()) - } -} - -impl PciDevOps for VirtioPciDevice { - gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); - - fn realize(mut self) -> Result<()> { + fn realize(mut self) -> Result>> { info!("func: realize, id: {:?}", &self.base.base.id); let parent_bus = self.parent_bus().unwrap(); self.init_write_mask(false)?; @@ -1191,10 +1170,35 @@ impl PciDevOps for VirtioPciDevice { let bus = parent_bus.upgrade().unwrap(); bus.lock().unwrap().attach_child(devfn, dev.clone())?; - MigrationManager::register_transport_instance(VirtioPciState::descriptor(), dev, &name); + MigrationManager::register_transport_instance( + VirtioPciState::descriptor(), + dev.clone(), + &name, + ); + + Ok(dev) + } + + fn unrealize(&mut self) -> Result<()> { + info!("func: unrealize, id: {:?}", &self.base.base.id); + self.device + .lock() + .unwrap() + .unrealize() + .with_context(|| "Failed to unrealize the virtio device")?; + + let bus = self.parent_bus().unwrap().upgrade().unwrap(); + self.base.config.unregister_bars(&bus)?; + + MigrationManager::unregister_device_instance(MsixState::descriptor(), &self.name()); + MigrationManager::unregister_transport_instance(VirtioPciState::descriptor(), &self.name()); Ok(()) } +} + +impl PciDevOps for VirtioPciDevice { + gen_base_func!(pci_base, pci_base_mut, PciDevBase, base); fn read_config(&mut self, offset: usize, data: &mut [u8]) { trace::virtio_tpt_read_config(&self.base.base.id, offset as u64, data.len()); -- Gitee From c45f567b922cc4877930f4fc7a20c62dc9fd1022 Mon Sep 17 00:00:00 2001 From: zhanghan Date: Thu, 18 Jul 2024 21:08:30 +0800 Subject: [PATCH 205/489] OHAudio:fix audio task's detroy logic we need to change status of audio tasks before we drop audio tasks. So audio callback function will get right task status. Signed-off-by: zhanghan --- devices/src/misc/scream/ohaudio.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index 6fcee525..1f585305 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -297,8 +297,8 @@ impl OhAudioProcess for OhAudioRender { match status { OhAudioStatus::Paused => return, OhAudioStatus::Error => { - self.ctx = None; self.set_status(OhAudioStatus::Ready); + self.ctx = None; return; } OhAudioStatus::Started => self.flush(), @@ -431,8 +431,8 @@ impl OhAudioProcess for OhAudioCapture { match status { OhAudioStatus::Paused => return, _ => { - self.ctx = None; self.set_status(OhAudioStatus::Ready); + self.ctx = None; } } trace::oh_scream_capture_destroy(); -- Gitee From 709f6ae00a951b82d68396049bf255087a6526da Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Fri, 12 Jul 2024 11:49:04 +0800 Subject: [PATCH 206/489] acpi: Add configuration interface for Hardware Signature ... which is used for VM S4 state. Signed-off-by: Keqian Zhu --- docs/config_guidebook.md | 8 ++++++++ machine/src/aarch64/standard.rs | 5 +++++ machine/src/standard_common/mod.rs | 17 +++++++++++++++-- machine/src/x86_64/standard.rs | 5 +++++ machine_manager/src/cmdline.rs | 14 ++++++++++++++ machine_manager/src/config/machine_config.rs | 5 +++++ machine_manager/src/config/mod.rs | 1 + 7 files changed, 53 insertions(+), 2 deletions(-) diff --git a/docs/config_guidebook.md b/docs/config_guidebook.md index a836f704..c37d0437 100644 --- a/docs/config_guidebook.md +++ b/docs/config_guidebook.md @@ -285,6 +285,14 @@ The SMBIOS specification defines the data structures and information that will e ``` +### 1.12 Hardware Signature +This option is used for configuring ACPI Hardware Signature, which is used for VM S4 state. It's an 32 bit integer. For more information, please refer to https://uefi.org/htmlspecs/ACPI_Spec_6_4_html/05_ACPI_Software_Programming_Model/ACPI_Software_Programming_Model.html#firmware-acpi-control-structure-facs-table. + +```shell +# cmdline +-hardware-signature 1 +``` + ## 2. Device Configuration For machine type "microvm", only virtio-mmio and legacy devices are supported. diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index 9be74e0c..c82efefc 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -1149,6 +1149,11 @@ impl AcpiBuilder for StdMachine { .with_context(|| "Fail to add PPTT table to loader")?; Ok(pptt_begin) } + + fn get_hardware_signature(&self) -> Option { + let vm_config = self.machine_base().vm_config.lock().unwrap(); + vm_config.hardware_signature + } } /// Function that helps to generate flash node in device-tree. diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index ee6d2cd1..86ee0e26 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -142,7 +142,8 @@ pub(crate) trait StdMachineOps: AcpiBuilder + MachineOps { let mut xsdt_entries = Vec::new(); - let facs_addr = Self::build_facs_table(&acpi_tables) + let facs_addr = self + .build_facs_table(&acpi_tables) .with_context(|| "Failed to build ACPI FACS table")?; let dsdt_addr = self @@ -697,12 +698,15 @@ pub(crate) trait AcpiBuilder { Ok(fadt_begin as u64) } + /// Get the Hardware Signature used to build FACS table. + fn get_hardware_signature(&self) -> Option; + /// Build ACPI FACS table, returns the offset of ACPI FACS table in `acpi_data`. /// /// # Arguments /// /// `acpi_data` - Bytes streams that ACPI tables converts to. - fn build_facs_table(acpi_data: &Arc>>) -> Result + fn build_facs_table(&self, acpi_data: &Arc>>) -> Result where Self: Sized, { @@ -715,6 +719,15 @@ pub(crate) trait AcpiBuilder { // FACS table length. facs_data[4] = 0x40; + // FACS table Hardware Signature. + if let Some(signature) = self.get_hardware_signature() { + let signature = signature.as_bytes(); + facs_data[8] = signature[0]; + facs_data[9] = signature[1]; + facs_data[10] = signature[2]; + facs_data[11] = signature[3]; + } + let mut locked_acpi_data = acpi_data.lock().unwrap(); let facs_begin = locked_acpi_data.len() as u32; locked_acpi_data.extend(facs_data); diff --git a/machine/src/x86_64/standard.rs b/machine/src/x86_64/standard.rs index 901f054c..865eb456 100644 --- a/machine/src/x86_64/standard.rs +++ b/machine/src/x86_64/standard.rs @@ -914,4 +914,9 @@ impl AcpiBuilder for StdMachine { .with_context(|| "Fail to add SRAT table to loader")?; Ok(srat_begin) } + + fn get_hardware_signature(&self) -> Option { + let vm_config = self.machine_base().vm_config.lock().unwrap(); + vm_config.hardware_signature + } } diff --git a/machine_manager/src/cmdline.rs b/machine_manager/src/cmdline.rs index fc7304b9..f29804e6 100644 --- a/machine_manager/src/cmdline.rs +++ b/machine_manager/src/cmdline.rs @@ -460,6 +460,15 @@ pub fn create_args_parser<'a>() -> ArgParser<'a> { .takes_values(true) .required(false), ) + .arg( + Arg::with_name("hardware-signature") + .multiple(false) + .long("hardware-signature") + .value_name("<32bit integer>") + .help("set ACPI Hardware Signature") + .takes_value(true) + .required(false), + ) .arg( Arg::with_name("smbios") .multiple(true) @@ -577,6 +586,11 @@ pub fn create_vmconfig(args: &ArgMatches) -> Result { add_kernel_cmdline, vec ); + add_args_to_config!( + (args.value_of("hardware-signature")), + vm_cfg, + add_hw_signature + ); add_args_to_config_multi!((args.values_of("drive")), vm_cfg, add_drive); add_args_to_config_multi!((args.values_of("object")), vm_cfg, add_object); add_args_to_config_multi!((args.values_of("netdev")), vm_cfg, add_netdev); diff --git a/machine_manager/src/config/machine_config.rs b/machine_manager/src/config/machine_config.rs index 2f9cf70e..25d3b7c1 100644 --- a/machine_manager/src/config/machine_config.rs +++ b/machine_manager/src/config/machine_config.rs @@ -459,6 +459,11 @@ impl VmConfig { self.machine_config.battery = true; true } + + pub fn add_hw_signature(&mut self, config: &str) -> Result<()> { + self.hardware_signature = Some(u32::from_str(config)?); + Ok(()) + } } impl VmConfig { diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index e172f7d5..2aff9801 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -135,6 +135,7 @@ pub struct VmConfig { pub global_config: HashMap, pub numa_nodes: Vec<(String, String)>, pub incoming: Option, + pub hardware_signature: Option, #[cfg(feature = "vnc")] pub vnc: Option, #[cfg(any(feature = "gtk", all(target_env = "ohos", feature = "ohui_srv")))] -- Gitee From dc37a7d81462f05e1568027136fcc940f0c2082d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=A5=9A=E5=BD=B1?= Date: Mon, 15 Jul 2024 17:20:05 +0800 Subject: [PATCH 207/489] ohui: adapt to the new update ledstate interface When typing keyboards keys, obatin and refresh the state of ledstate, ensure that the keyboard status in the vm is synchronized with the pc. Signed-off-by: Jiahong Li --- ui/src/input.rs | 28 ---------------------------- ui/src/ohui_srv/mod.rs | 7 ++----- ui/src/ohui_srv/msg.rs | 8 ++------ ui/src/ohui_srv/msg_handle.rs | 34 ++++++++++------------------------ 4 files changed, 14 insertions(+), 63 deletions(-) diff --git a/ui/src/input.rs b/ui/src/input.rs index d540c998..59f2b931 100644 --- a/ui/src/input.rs +++ b/ui/src/input.rs @@ -252,23 +252,6 @@ impl KeyBoardState { #[derive(Default)] struct LedState { kbd_led: u8, - sync: Option>, -} - -pub trait SyncLedstate: Send + Sync { - fn sync_to_host(&self, state: u8) { - debug!("ledstate in guest is {}", state); - } -} - -impl LedState { - fn register_led_sync(&mut self, sync: Arc) { - self.sync = Some(sync); - } - - fn unregister_led_sync(&mut self) { - self.sync = None; - } } #[derive(Default)] @@ -345,14 +328,6 @@ impl Inputs { } } -pub fn register_led_sync(sync: Arc) { - LED_STATE.lock().unwrap().register_led_sync(sync); -} - -pub fn unregister_led_sync() { - LED_STATE.lock().unwrap().unregister_led_sync(); -} - pub fn register_keyboard(device: &str, kbd: Arc>) { INPUTS.lock().unwrap().register_kbd(device, kbd); } @@ -490,9 +465,6 @@ pub fn get_kbd_led_state() -> u8 { pub fn set_kbd_led_state(state: u8) { LED_STATE.lock().unwrap().kbd_led = state; - if let Some(sync_cb) = LED_STATE.lock().unwrap().sync.as_ref() { - sync_cb.sync_to_host(state); - } } pub fn keyboard_modifier_get(key_mod: KeyboardModifier) -> bool { diff --git a/ui/src/ohui_srv/mod.rs b/ui/src/ohui_srv/mod.rs index 899d2634..b650946d 100755 --- a/ui/src/ohui_srv/mod.rs +++ b/ui/src/ohui_srv/mod.rs @@ -35,7 +35,6 @@ use crate::{ DisplayChangeListenerOperations, DisplayMouse, DisplaySurface, DISPLAY_UPDATE_INTERVAL_DEFAULT, }, - input::{register_led_sync, unregister_led_sync}, pixman::{bytes_per_pixel, get_image_data, ref_pixman_image, unref_pixman_image}, }; use address_space::FileBackend; @@ -95,7 +94,7 @@ pub struct OhUiServer { // transfer channel via unix sock channel: Arc>, // message handler - msg_handler: Arc, + msg_handler: OhUiMsgHandler, // connected or not connected: AtomicBool, // iothread processing unix socket @@ -181,7 +180,7 @@ impl OhUiServer { passthru: OnceCell::new(), surface: RwLock::new(GuestSurface::new()), channel, - msg_handler: Arc::new(OhUiMsgHandler::new()), + msg_handler: OhUiMsgHandler::new(), connected: AtomicBool::new(false), iothread: OnceCell::new(), cursorbuffer, @@ -267,9 +266,7 @@ impl OhUiServer { self.connected.store(conn, Ordering::Relaxed); if conn { self.msg_handler.update_sock(self.channel.clone()); - register_led_sync(self.msg_handler.clone()); } else { - unregister_led_sync(); self.channel.lock().unwrap().disconnect(); self.msg_handler.reset(); } diff --git a/ui/src/ohui_srv/msg.rs b/ui/src/ohui_srv/msg.rs index c359d71f..1ce2d446 100755 --- a/ui/src/ohui_srv/msg.rs +++ b/ui/src/ohui_srv/msg.rs @@ -110,6 +110,8 @@ impl ByteCode for MouseMotionEvent {} pub struct KeyboardEvent { pub key_action: u16, pub keycode: u16, + pub led_state: u8, + pad: [u8; 3], } impl ByteCode for KeyboardEvent {} @@ -132,12 +134,6 @@ pub struct LedstateEvent { impl ByteCode for LedstateEvent {} -impl LedstateEvent { - pub fn new(state: u32) -> Self { - LedstateEvent { state } - } -} - #[repr(C, packed)] #[derive(Debug, Default, Copy, Clone)] pub struct GreetEvent { diff --git a/ui/src/ohui_srv/msg_handle.rs b/ui/src/ohui_srv/msg_handle.rs index 1e085e52..2ce24ca6 100755 --- a/ui/src/ohui_srv/msg_handle.rs +++ b/ui/src/ohui_srv/msg_handle.rs @@ -27,11 +27,10 @@ use crate::{ console::{get_active_console, graphic_hardware_ui_info}, input::{ self, get_kbd_led_state, input_button, input_move_abs, input_point_sync, keyboard_update, - release_all_key, trigger_key, Axis, SyncLedstate, ABS_MAX, CAPS_LOCK_LED, - INPUT_BUTTON_WHEEL_DOWN, INPUT_BUTTON_WHEEL_LEFT, INPUT_BUTTON_WHEEL_RIGHT, - INPUT_BUTTON_WHEEL_UP, INPUT_POINT_BACK, INPUT_POINT_FORWARD, INPUT_POINT_LEFT, - INPUT_POINT_MIDDLE, INPUT_POINT_RIGHT, KEYCODE_CAPS_LOCK, KEYCODE_NUM_LOCK, - KEYCODE_SCR_LOCK, NUM_LOCK_LED, SCROLL_LOCK_LED, + release_all_key, trigger_key, Axis, ABS_MAX, CAPS_LOCK_LED, INPUT_BUTTON_WHEEL_DOWN, + INPUT_BUTTON_WHEEL_LEFT, INPUT_BUTTON_WHEEL_RIGHT, INPUT_BUTTON_WHEEL_UP, INPUT_POINT_BACK, + INPUT_POINT_FORWARD, INPUT_POINT_LEFT, INPUT_POINT_MIDDLE, INPUT_POINT_RIGHT, + KEYCODE_CAPS_LOCK, KEYCODE_NUM_LOCK, KEYCODE_SCR_LOCK, NUM_LOCK_LED, SCROLL_LOCK_LED, }, keycode::{DpyMod, KeyCode}, }; @@ -133,17 +132,6 @@ pub struct OhUiMsgHandler { writer: Mutex>, } -impl SyncLedstate for OhUiMsgHandler { - fn sync_to_host(&self, state: u8) { - if let Some(writer) = self.writer.lock().unwrap().as_mut() { - let body = LedstateEvent::new(state as u32); - if let Err(e) = writer.send_message(EventType::Ledstate, &body) { - error!("sync_to_host: failed to send message with error {e}"); - } - } - } -} - impl OhUiMsgHandler { pub fn new() -> Self { OhUiMsgHandler { @@ -206,11 +194,7 @@ impl OhUiMsgHandler { } Ok(()) } - EventType::Ledstate => { - let body = LedstateEvent::from_bytes(&body_bytes[..]).unwrap(); - self.handle_ledstate(body); - Ok(()) - } + EventType::Ledstate => Ok(()), EventType::Greet => { let body = GreetEvent::from_bytes(&body_bytes[..]).unwrap(); trace::oh_event_greet(body.token_id); @@ -273,9 +257,11 @@ impl OhUiMsgHandler { } fn handle_keyboard(&self, ke: &KeyboardEvent) -> Result<()> { - if self.state.lock().unwrap().led_state.is_some() { - self.state.lock().unwrap().sync_kbd_led_state()?; - } + self.state + .lock() + .unwrap() + .update_host_ledstate(ke.led_state); + self.state.lock().unwrap().sync_kbd_led_state()?; let hmkey = ke.keycode; let keycode = match self.hmcode2svcode.get(&hmkey) { Some(k) => *k, -- Gitee From 47a4afa88194ad2441e734f11d80708d27b8f8c3 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Mon, 22 Jul 2024 09:33:03 +0800 Subject: [PATCH 208/489] ohui: remove unused code Remove unused code. Signed-off-by: Zhao Yi Min --- ui/src/ohui_srv/msg_handle.rs | 28 ++++------------------------ 1 file changed, 4 insertions(+), 24 deletions(-) diff --git a/ui/src/ohui_srv/msg_handle.rs b/ui/src/ohui_srv/msg_handle.rs index 2ce24ca6..84b78857 100755 --- a/ui/src/ohui_srv/msg_handle.rs +++ b/ui/src/ohui_srv/msg_handle.rs @@ -57,7 +57,6 @@ fn trans_mouse_pos(x: f64, y: f64, w: f64, h: f64) -> (u32, u32) { struct WindowState { width: u32, height: u32, - led_state: Option, } impl WindowState { @@ -96,19 +95,10 @@ impl WindowState { input_point_sync() } - fn update_host_ledstate(&mut self, led: u8) { - self.led_state = Some(led); - } - - fn sync_kbd_led_state(&mut self) -> Result<()> { - if self.led_state.is_none() { - return Ok(()); - } - - let host_stat = self.led_state.unwrap(); + fn sync_kbd_led_state(&mut self, led: u8) -> Result<()> { let guest_stat = get_kbd_led_state(); - if host_stat != guest_stat { - let sync_bits = host_stat ^ guest_stat; + if led != guest_stat { + let sync_bits = led ^ guest_stat; if (sync_bits & CAPS_LOCK_LED) != 0 { trigger_key(KEYCODE_CAPS_LOCK)?; } @@ -119,7 +109,6 @@ impl WindowState { trigger_key(KEYCODE_SCR_LOCK)?; } } - self.led_state = None; Ok(()) } } @@ -260,8 +249,7 @@ impl OhUiMsgHandler { self.state .lock() .unwrap() - .update_host_ledstate(ke.led_state); - self.state.lock().unwrap().sync_kbd_led_state()?; + .sync_kbd_led_state(ke.led_state)?; let hmkey = ke.keycode; let keycode = match self.hmcode2svcode.get(&hmkey) { Some(k) => *k, @@ -306,14 +294,6 @@ impl OhUiMsgHandler { trace::oh_event_windowinfo(wi.width, wi.height); } - fn handle_ledstate(&self, led: &LedstateEvent) { - self.state - .lock() - .unwrap() - .update_host_ledstate(led.state as u8); - trace::oh_event_ledstate(led.state); - } - pub fn send_windowinfo(&self, w: u32, h: u32) { self.state.lock().unwrap().update_window_info(w, h); if let Some(writer) = self.writer.lock().unwrap().as_mut() { -- Gitee From fc64fd07457af67fa5566be985da118cccb0b499 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sun, 14 Jul 2024 15:22:06 +0800 Subject: [PATCH 209/489] vhost-vsock: vsock should not support write_config MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit According to Virtio Spec: Socket device configuration uses the following layout structure: struct virtio_vsock_config { le64 guest_cid; }; The guest_cid field contains the guest’s context ID, which uniquely identifies the device for its lifetime. The upper 32 bits of the CID are reserved and zeroed. So, config space of vsock should not be changed in the lifetime, which means `write_config` should not be supported. Signed-off-by: liuxiangdong --- virtio/src/vhost/kernel/vsock.rs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/virtio/src/vhost/kernel/vsock.rs b/virtio/src/vhost/kernel/vsock.rs index 4f2d1a44..e6580ffa 100644 --- a/virtio/src/vhost/kernel/vsock.rs +++ b/virtio/src/vhost/kernel/vsock.rs @@ -23,8 +23,8 @@ use vmm_sys_util::ioctl::ioctl_with_ref; use super::super::{VhostIoHandler, VhostNotify, VhostOps}; use super::{VhostBackend, VHOST_VSOCK_SET_GUEST_CID, VHOST_VSOCK_SET_RUNNING}; use crate::{ - check_config_space_rw, Queue, VirtioBase, VirtioDevice, VirtioError, VirtioInterrupt, - VirtioInterruptType, VIRTIO_F_ACCESS_PLATFORM, VIRTIO_TYPE_VSOCK, + Queue, VirtioBase, VirtioDevice, VirtioError, VirtioInterrupt, VirtioInterruptType, + VIRTIO_F_ACCESS_PLATFORM, VIRTIO_TYPE_VSOCK, }; use address_space::AddressSpace; use machine_manager::config::{get_pci_df, parse_bool, valid_id, DEFAULT_VIRTQUEUE_SIZE}; @@ -234,10 +234,7 @@ impl VirtioDevice for Vsock { Ok(()) } - fn write_config(&mut self, offset: u64, data: &[u8]) -> Result<()> { - check_config_space_rw(&self.config_space, offset, data)?; - let data_len = data.len(); - self.config_space[(offset as usize)..(offset as usize + data_len)].copy_from_slice(data); + fn write_config(&mut self, _offset: u64, _data: &[u8]) -> Result<()> { Ok(()) } -- Gitee From b747690eb725ba515226f10ce673fde80d64a702 Mon Sep 17 00:00:00 2001 From: Jinhao Gao Date: Thu, 18 Jul 2024 15:59:16 +0800 Subject: [PATCH 210/489] hisysevent: Add hisysevent module Add hisysevent module to to interconnect with the hisysevent Service of openHarmonyOS. Signed-off-by: Jinhao Gao Please enter the commit message for your changes. Lines starting --- Cargo.lock | 11 +++ Cargo.toml | 2 + hisysevent/Cargo.toml | 16 +++ hisysevent/build.rs | 18 ++++ hisysevent/src/interface.rs | 189 ++++++++++++++++++++++++++++++++++++ hisysevent/src/lib.rs | 27 ++++++ 6 files changed, 263 insertions(+) create mode 100644 hisysevent/Cargo.toml create mode 100644 hisysevent/build.rs create mode 100644 hisysevent/src/interface.rs create mode 100644 hisysevent/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 90552e41..dd39a60c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -757,6 +757,16 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "hisysevent" +version = "2.4.0" +dependencies = [ + "anyhow", + "lazy_static", + "libloading", + "log", +] + [[package]] name = "hypervisor" version = "2.4.0" @@ -1584,6 +1594,7 @@ name = "stratovirt" version = "2.4.0" dependencies = [ "anyhow", + "hisysevent", "log", "machine", "machine_manager", diff --git a/Cargo.toml b/Cargo.toml index b00a2da0..3277768c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ machine = { path = "machine" } machine_manager = { path = "machine_manager" } util = { path = "util" } trace = { path = "trace" } +hisysevent = { path = "hisysevent" } [workspace] members = [ @@ -42,6 +43,7 @@ virtio_gpu = ["machine/virtio_gpu"] trace_to_logger = ["trace/trace_to_logger"] trace_to_ftrace = ["trace/trace_to_ftrace"] trace_to_hitrace = ["trace/trace_to_hitrace"] +hisysevent = ["hisysevent/hisysevent"] [package.metadata.rpm.cargo] buildflags = ["--release"] diff --git a/hisysevent/Cargo.toml b/hisysevent/Cargo.toml new file mode 100644 index 00000000..b7febaa7 --- /dev/null +++ b/hisysevent/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "hisysevent" +version = "2.4.0" +authors = ["Huawei StratoVirt Team"] +edition = "2021" +license = "Mulan PSL v2" +description = "Provide hisysevent infrastructure of hmos for StratoVirt" + +[dependencies] +log = "0.4" +lazy_static = "1.4.0" +anyhow = "1.0" +libloading = "0.7.4" + +[features] +hisysevent = [] diff --git a/hisysevent/build.rs b/hisysevent/build.rs new file mode 100644 index 00000000..89563d85 --- /dev/null +++ b/hisysevent/build.rs @@ -0,0 +1,18 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +fn main() { + println!( + "cargo:rerun-if-changed={}/hisysevent", + std::env::var("CARGO_MANIFEST_DIR").unwrap() + ); +} diff --git a/hisysevent/src/interface.rs b/hisysevent/src/interface.rs new file mode 100644 index 00000000..5f6ecf64 --- /dev/null +++ b/hisysevent/src/interface.rs @@ -0,0 +1,189 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::ffi::{c_char, c_int, c_uint, c_ulonglong, CString, OsStr}; + +use anyhow::{Context, Result}; +use lazy_static::lazy_static; +use libloading::os::unix::Symbol; +use libloading::Library; +use log::error; + +const MAX_PARAM_NAME_LENGTH: usize = 49; + +#[derive(Copy, Clone, Debug)] +pub enum HiSysEventType { + _Fault = 1, + _Statistic, + _Security, + _Behavior, +} + +#[derive(Copy, Clone, Debug)] +pub enum EventParamType { + // Invalid type. + _Invalid = 0, + _TypeBool, + _TypeI8, + _TypeU8, + _TypeI16, + _TypeU16, + _TypeI32, + _TypeU32, + _TypeI64, + _TypeU64, + _TypeF32, + _TypeF64, + _TypeString, + _ArrayBool, + _ArrayI8, + _ArrayU8, + _ArrayI16, + _ArrayU16, + _ArrayI32, + _ArrayU32, + _ArrayI64, + _ArrayU64, + _ArrayF32, + _ArrayF64, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub union EventParamValue { + pub bool_value: bool, + pub i8_value: i8, + pub u8_value: u8, + pub i16_value: i16, + pub u16_value: u16, + pub i32_value: i32, + pub u32_value: u32, + pub i64_value: i64, + pub u64_value: u64, + pub f32_value: f32, + pub f64_value: f64, + // String. + pub char_ptr_value: *const c_char, + // Array. + pub void_ptr_value: *const (), +} + +pub struct EventParam<'a> { + pub param_name: &'a str, + pub param_type: EventParamType, + pub param_value: EventParamValue, + pub array_size: usize, +} + +#[repr(C)] +#[derive(Copy, Clone)] +struct EventParamWrapper { + pub param_name: [u8; MAX_PARAM_NAME_LENGTH], + pub param_type: c_int, + pub param_value: EventParamValue, + pub array_size: c_uint, +} + +lazy_static! { + static ref HISYSEVENT_FUNC_TABLE: HiSysEventFuncTable = + // SAFETY: The dynamic library should be always existing. + unsafe { + HiSysEventFuncTable::new(OsStr::new("libhisysevent.z.so")) + .map_err(|e| { + error!("failed to init HiSysEventFuncTable with error: {:?}", e); + e + }) + .unwrap() + }; +} + +macro_rules! get_libfn { + ( $lib: ident, $tname: ident, $fname: ident ) => { + $lib.get::<$tname>(stringify!($fname).as_bytes()) + .with_context(|| format!("failed to get function {}", stringify!($fname)))? + .into_raw() + }; +} + +type HiSysEventWriteWrapperFn = unsafe extern "C" fn( + func: *const c_char, + line: c_ulonglong, + domain: *const c_char, + name: *const c_char, + event_type: c_int, + params: *const EventParamWrapper, + size: c_uint, +) -> c_int; + +struct HiSysEventFuncTable { + pub hisysevent_write: Symbol, +} + +impl HiSysEventFuncTable { + unsafe fn new(library_name: &OsStr) -> Result { + let library = + Library::new(library_name).with_context(|| "failed to load hisysevent library")?; + + Ok(Self { + hisysevent_write: get_libfn!(library, HiSysEventWriteWrapperFn, HiSysEvent_Write), + }) + } +} + +fn format_param_array(event_params: &[EventParam]) -> Vec { + let mut params_wrapper: Vec = vec![]; + + for param in event_params { + let mut param_name = [0_u8; MAX_PARAM_NAME_LENGTH]; + let name = param.param_name.as_bytes(); + let end = std::cmp::min(name.len(), param_name.len()); + param_name[..end].copy_from_slice(&name[..end]); + params_wrapper.push(EventParamWrapper { + param_name, + param_type: param.param_type as i32, + param_value: param.param_value, + array_size: param.array_size as u32, + }); + } + + params_wrapper +} + +// Write system event. +pub(crate) fn write_to_hisysevent( + func_name: &str, + event_name: &str, + event_type: c_int, + event_params: &[EventParam], +) { + let func = CString::new(func_name).unwrap(); + let domain = CString::new("VM_ENGINE").unwrap(); + let event = CString::new(event_name).unwrap(); + + let params_wrapper = format_param_array(event_params); + + // SAFETY: Call hisysevent function, all parameters are just read. + let ret = unsafe { + (HISYSEVENT_FUNC_TABLE.hisysevent_write)( + func.as_ptr() as *const c_char, + line!() as c_ulonglong, + domain.as_ptr() as *const c_char, + event.as_ptr() as *const c_char, + event_type, + params_wrapper.as_ptr() as *const EventParamWrapper, + params_wrapper.len() as u32, + ) + }; + if ret != 0 { + error!("Failed to write event {} to hisysevent.", event_name); + } +} diff --git a/hisysevent/src/lib.rs b/hisysevent/src/lib.rs new file mode 100644 index 00000000..3166fcaf --- /dev/null +++ b/hisysevent/src/lib.rs @@ -0,0 +1,27 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +#[cfg(all(target_env = "ohos", feature = "hisysevent"))] +mod interface; + +#[macro_export] +macro_rules! function { + () => {{ + fn hook() {} + fn type_name_of(_: T) -> &'static str { + std::any::type_name::() + } + let name = type_name_of(hook); + let off_set: usize = 6; // ::hook + &name[..name.len() - off_set] + }}; +} -- Gitee From d236b6557a733cb8198399c250d9fe1e4b78da5d Mon Sep 17 00:00:00 2001 From: Jinhao Gao Date: Thu, 18 Jul 2024 16:35:09 +0800 Subject: [PATCH 211/489] hisysevent: Add event code generator macro Add code generator macro to parse event configuration file for generator hisysevent writing function. Signed-off-by: Jinhao Gao --- Cargo.lock | 13 ++ hisysevent/Cargo.toml | 1 + hisysevent/code_generator/Cargo.toml | 18 +++ hisysevent/code_generator/src/lib.rs | 202 +++++++++++++++++++++++++++ hisysevent/event_info/example.toml | 5 + hisysevent/src/lib.rs | 7 + 6 files changed, 246 insertions(+) create mode 100644 hisysevent/code_generator/Cargo.toml create mode 100644 hisysevent/code_generator/src/lib.rs create mode 100644 hisysevent/event_info/example.toml diff --git a/Cargo.lock b/Cargo.lock index dd39a60c..20ed7089 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -314,6 +314,18 @@ dependencies = [ "os_str_bytes", ] +[[package]] +name = "code_generator" +version = "2.4.0" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "serde", + "syn 2.0.18", + "toml", +] + [[package]] name = "const_format" version = "0.2.31" @@ -762,6 +774,7 @@ name = "hisysevent" version = "2.4.0" dependencies = [ "anyhow", + "code_generator", "lazy_static", "libloading", "log", diff --git a/hisysevent/Cargo.toml b/hisysevent/Cargo.toml index b7febaa7..11b3b69a 100644 --- a/hisysevent/Cargo.toml +++ b/hisysevent/Cargo.toml @@ -11,6 +11,7 @@ log = "0.4" lazy_static = "1.4.0" anyhow = "1.0" libloading = "0.7.4" +code_generator = { path = "code_generator" } [features] hisysevent = [] diff --git a/hisysevent/code_generator/Cargo.toml b/hisysevent/code_generator/Cargo.toml new file mode 100644 index 00000000..9c1fc3c1 --- /dev/null +++ b/hisysevent/code_generator/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "code_generator" +version = "2.4.0" +authors = ["Huawei StratoVirt Team"] +edition = "2021" +license = "Mulan PSL v2" + +[lib] +name = "code_generator" +proc-macro = true + +[dependencies] +proc-macro2 = "1.0" +quote = "1.0" +regex = "1" +serde = { version = "1.0", features = ["derive"] } +syn = "2.0.18" +toml = "0.7" diff --git a/hisysevent/code_generator/src/lib.rs b/hisysevent/code_generator/src/lib.rs new file mode 100644 index 00000000..8d7c8d06 --- /dev/null +++ b/hisysevent/code_generator/src/lib.rs @@ -0,0 +1,202 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::{fs, io::Read}; + +use proc_macro::TokenStream; +use quote::quote; +use regex::Regex; +use serde::Deserialize; +use syn::{parse_str, Expr, Ident, Type}; + +const EVENT_DIR_NAME: &str = "event_info"; + +#[derive(Debug, Deserialize)] +struct EventDesc { + name: String, + event_type: String, + args: String, + enabled: bool, +} + +#[derive(Debug, Deserialize)] +struct HiSysEventConf { + events: Option>, +} + +fn get_event_desc() -> HiSysEventConf { + let event_dir_path = format!( + "{}/{}", + std::env::var("CARGO_MANIFEST_DIR").unwrap(), + EVENT_DIR_NAME + ); + let paths = fs::read_dir(event_dir_path).unwrap(); + let mut desc = String::new(); + + for path in paths { + let file_path = path.unwrap().path(); + let file_name = file_path.to_str().unwrap(); + if file_name.ends_with(".toml") { + let mut file = fs::File::open(file_path).unwrap(); + file.read_to_string(&mut desc).unwrap(); + } + } + match toml::from_str::(&desc) { + Ok(ret) => ret, + Err(e) => panic!("Failed to parse event info : {}", e), + } +} + +fn is_slice(arg_type: &str) -> bool { + let regex = Regex::new(r"\[([^\[\]]*)\]").unwrap(); + let match_texts = regex + .captures_iter(arg_type) + .map(|mat| mat.get(1).map_or("", |m| m.as_str())); + match match_texts.count() { + 0 => false, + 1 => true, + _ => panic!("The format of parameter type: {} is wrong!", arg_type), + } +} + +fn capitalize(s: &str) -> String { + if s.is_empty() { + return String::new(); + } + + let mut chars = s.chars().collect::>(); + if chars[0].is_alphabetic() { + chars[0] = chars[0] + .to_uppercase() + .collect::() + .chars() + .next() + .unwrap(); + } + chars.iter().collect() +} + +fn parse_param_type(arg_type: &str) -> String { + if is_slice(arg_type) { + let regex = Regex::new(r"\[([^\[\]]*)\]").unwrap(); + let match_texts: Vec<&str> = regex + .captures_iter(arg_type) + .map(|mat| mat.get(1).map_or("", |m| m.as_str())) + .collect(); + format!("Array{}", capitalize(match_texts[0])) + } else { + format!("Type{}", capitalize(arg_type)) + } +} + +fn generate_param_value(arg_type: &str, arg_value: &str) -> (Ident, Expr) { + let param_type: Ident; + let param_value: Expr; + if is_slice(arg_type) { + let trans_token = ".as_ptr() as *const std::ffi::c_int as *const ()"; + param_type = parse_str::("void_ptr_value").unwrap(); + param_value = parse_str::(format!("{}{}", arg_value, trans_token).as_str()).unwrap(); + } else if arg_type.contains("String") { + let cstr_arg = format!("std::ffi::CString::new({}).unwrap()", arg_value); + let trans_token = ".into_raw() as *const std::ffi::c_char"; + param_type = parse_str::("char_ptr_value").unwrap(); + param_value = parse_str::(format!("{}{}", cstr_arg, trans_token).as_str()).unwrap(); + } else { + param_type = parse_str::(format!("{}_value", arg_type).as_str()).unwrap(); + param_value = parse_str::(format!("{} as {}", arg_value, arg_type).as_str()).unwrap(); + } + (param_type, param_value) +} + +#[proc_macro] +pub fn gen_hisysevent_func(_input: TokenStream) -> TokenStream { + let events = match get_event_desc().events { + Some(events) => events, + None => return TokenStream::from(quote!()), + }; + let hisysevent_func = events.iter().map(|desc| { + if desc.name.trim().is_empty() { + panic!("Empty event name is unsupported!"); + } + let desc_name = desc.name.trim(); + let func_name = parse_str::(desc_name).unwrap(); + let event_name = desc_name; + let event_type = + parse_str::(format!("HiSysEventType::_{}", desc.event_type.trim()).as_str()) + .unwrap(); + + let func_args = match desc.args.is_empty() { + true => quote!(), + false => { + let split_args: Vec<&str> = desc.args.split(',').collect(); + let _args = split_args.iter().map(|arg| { + let (v, t) = arg.split_once(':').unwrap(); + let arg_name = parse_str::(v.trim()).unwrap(); + let arg_type = parse_str::(t.trim()).unwrap(); + quote!( + #arg_name: #arg_type, + ) + }); + quote! { #( #_args )* } + } + }; + + let param_body = { + let split_args: Vec<&str> = desc.args.split(',').collect(); + let _args = split_args.iter().map(|arg| { + let (v, t) = arg.split_once(':').unwrap(); + let param_name = v.trim(); + let param_type_str: String = parse_param_type(t.trim()); + let param_type_token = format!("EventParamType::_{}", param_type_str); + let param_type = parse_str::(param_type_token.as_str()).unwrap(); + let (elem_type, elem_value) = generate_param_value(t.trim(), v.trim()); + let param_size = if param_type_str.contains("Array") { + parse_str::(format!("{}.len()", v.trim()).as_str()).unwrap() + } else { + parse_str::("0").unwrap() + }; + + quote!( + EventParam { + param_name: #param_name, + param_type: #param_type, + param_value: EventParamValue{#elem_type: #elem_value}, + array_size: #param_size}, + ) + }); + quote! { #( #_args )* } + }; + + let func_body = match desc.enabled { + true => { + quote!( + #[cfg(all(target_env = "ohos", feature = "hisysevent"))] + { + let func = function!(); + let params: &[EventParam] = &[#param_body]; + write_to_hisysevent(func, #event_name, #event_type as std::ffi::c_int, params); + } + ) + } + false => quote!(), + }; + + quote!( + #[inline(always)] + pub fn #func_name(#func_args) { + #func_body + } + ) + }); + + TokenStream::from(quote! { #( #hisysevent_func )* }) +} diff --git a/hisysevent/event_info/example.toml b/hisysevent/event_info/example.toml new file mode 100644 index 00000000..6a5e97ad --- /dev/null +++ b/hisysevent/event_info/example.toml @@ -0,0 +1,5 @@ +[[events]] +name = "example" +event_type = "Behavior" +args = "example_bool: bool, example_str: String, example_integer: u32, example_array: &[u8]" +enabled = true diff --git a/hisysevent/src/lib.rs b/hisysevent/src/lib.rs index 3166fcaf..6ab5515a 100644 --- a/hisysevent/src/lib.rs +++ b/hisysevent/src/lib.rs @@ -13,6 +13,11 @@ #[cfg(all(target_env = "ohos", feature = "hisysevent"))] mod interface; +use code_generator::gen_hisysevent_func; + +#[cfg(all(target_env = "ohos", feature = "hisysevent"))] +use crate::interface::*; + #[macro_export] macro_rules! function { () => {{ @@ -25,3 +30,5 @@ macro_rules! function { &name[..name.len() - off_set] }}; } + +gen_hisysevent_func! {} -- Gitee From 6b6e6d09eb2e16877fc05175dfd67b7e8b95cdf6 Mon Sep 17 00:00:00 2001 From: Jinhao Gao Date: Fri, 19 Jul 2024 09:48:50 +0800 Subject: [PATCH 212/489] Docs: Add hisysevent markdown file Add hisysevent markdown file to introduce the way to use hisysevent. Signed-off-by: Jinhao Gao --- docs/hisysevent.md | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 docs/hisysevent.md diff --git a/docs/hisysevent.md b/docs/hisysevent.md new file mode 100644 index 00000000..b92ce4fe --- /dev/null +++ b/docs/hisysevent.md @@ -0,0 +1,40 @@ +# HiSysEvent + +HiSysEvent(https://gitee.com/openharmony/hiviewdfx_hisysevent) is a tool in open- +harmonyOS to recode important information of key processes during system running, +helping locate faults and do some data analytics. + +This document describes the way to how to use hisysevent in StratoVirt. + +## Add Event + +### Modify configuration file + +First, you need to modify or creat toml file in the event/event_info directory +to add a new event in order to generate the event function. For example: + +```toml +[[events]] +name = "example" +event_type = "Behavior" +args = "example_bool: bool, example_str: String, example_integer: u64, example_array: &[u8]" +enable = true +``` + +In the above configuration, "name" is used to represent the only event, and +duplication is not allowed; "event_type" is one of four event type defined +by openharmonyOS: Fault, Statistic, Security and Behavior; "args" will be +formatted as arguments passed to hisysevent service in open-harmonyOS; +"enabled" indicates whether it is enabled during compilation. + +### Call event function + +Just call the event function where needed. +```rust +fn init_machine_ram(&self, sys_mem: &Arc, mem_size: u64) -> Result<()> { + hisysevent::example("true", "init_ram".to_string(), mem_size, &[0,1]); + let vm_ram = self.get_vm_ram(); + let layout_size = MEM_LAYOUT[LayoutEntryType::Mem as usize].1; + ...... +} +``` -- Gitee From 52839e47daaf16777c2f2ef6c9ba1dc015af8f97 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Mon, 29 Jul 2024 15:46:25 +0800 Subject: [PATCH 213/489] ohui: add parameter 'ui-path' for cmdline This patch introduces a new parameter 'ui-path' for cmdline to define the directory path of OHUI framebuffer and cursor files. Signed-off-by: Zhao Yi Min --- machine/src/aarch64/standard.rs | 5 ++++- machine_manager/src/config/display.rs | 18 +++++++++++++----- ui/src/ohui_srv/mod.rs | 8 ++++---- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index c82efefc..c117223b 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -312,7 +312,10 @@ impl StdMachine { if dpy.display_type != "ohui" { return Ok(()); } - self.ohui_server = Some(Arc::new(OhUiServer::new(dpy.get_ui_path())?)); + self.ohui_server = Some(Arc::new(OhUiServer::new( + dpy.get_ui_path(), + dpy.get_sock_path(), + )?)); } Ok(()) } diff --git a/machine_manager/src/config/display.rs b/machine_manager/src/config/display.rs index d0782858..74154f9d 100644 --- a/machine_manager/src/config/display.rs +++ b/machine_manager/src/config/display.rs @@ -39,7 +39,7 @@ pub struct UiContext { } #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] -fn get_sock_path(p: &str) -> Result { +fn get_dir_path(p: &str) -> Result { let path = std::fs::canonicalize(p) .with_context(|| format!("Failed to get real directory path: {:?}", p))?; if !path.exists() { @@ -75,16 +75,24 @@ pub struct DisplayConfig { #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] #[arg(long)] pub iothread: Option, - /// Confirm related files' path. Default ui path is "/tmp". + /// Confirm socket path. Default socket path is "/tmp". #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] - #[arg(long, alias = "socks-path", default_value = "/tmp/", value_parser = get_sock_path)] - pub path: String, + #[arg(long, alias = "socks-path", default_value = "/tmp/", value_parser = get_dir_path)] + pub sock_path: String, + /// Define the directory path for OHUI framebuffer and cursor. + #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] + #[arg(long, alias = "ui-path", default_value = "/dev/shm/hwf/", value_parser = get_dir_path)] + pub ui_path: String, } #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] impl DisplayConfig { + pub fn get_sock_path(&self) -> String { + self.sock_path.clone() + } + pub fn get_ui_path(&self) -> String { - self.path.clone() + self.ui_path.clone() } } diff --git a/ui/src/ohui_srv/mod.rs b/ui/src/ohui_srv/mod.rs index b650946d..384bf02f 100755 --- a/ui/src/ohui_srv/mod.rs +++ b/ui/src/ohui_srv/mod.rs @@ -171,10 +171,10 @@ impl OhUiServer { Ok(cursorbuffer) } - pub fn new(path: String) -> Result { - let channel = Self::init_channel(&path)?; - let (fb_file, framebuffer) = Self::init_fb_file(&path)?; - let cursorbuffer = Self::init_cursor_file(&path)?; + pub fn new(ui_path: String, sock_path: String) -> Result { + let channel = Self::init_channel(&sock_path)?; + let (fb_file, framebuffer) = Self::init_fb_file(&ui_path)?; + let cursorbuffer = Self::init_cursor_file(&ui_path)?; Ok(OhUiServer { passthru: OnceCell::new(), -- Gitee From dcec9710f25ccd580e2319c8cae5b7f20cd7b459 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Mon, 29 Jul 2024 17:15:09 +0800 Subject: [PATCH 214/489] pflash: Allow less than 64M size writable pflash There is no 64M size requirement for writable pflash. Signed-off-by: Keqian Zhu --- devices/src/legacy/pflash.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/devices/src/legacy/pflash.rs b/devices/src/legacy/pflash.rs index d3a6c0a4..5db5b9bc 100644 --- a/devices/src/legacy/pflash.rs +++ b/devices/src/legacy/pflash.rs @@ -69,11 +69,10 @@ impl PFlash { read_only: bool, ) -> Result { // We don't have to occupy the whole memory region. - // If flash is read-only, expose just real data size, - // rounded up to page_size + // Expose just real data size, rounded up to page_size. if let Some(fd) = backend.as_ref() { let len = fd.as_ref().metadata().unwrap().len(); - if len > region_max_size || len == 0 || (!read_only && len != region_max_size) { + if len > region_max_size || len == 0 || (!read_only && len % host_page_size() != 0) { bail!( "Invalid flash file: Region size 0x{region_max_size:X}, file size 0x{len:X}; read_only {read_only}" ); -- Gitee From 86438d6aab978519eedb47a00611f63d72da2f52 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Mon, 29 Jul 2024 19:28:12 +0800 Subject: [PATCH 215/489] ohui/ui-path: set different default value for different display The original default value made gtk unit test fail. So let's use a available directory for gtk type although it is not required. Signed-off-by: Zhao Yi Min --- machine_manager/src/config/display.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/machine_manager/src/config/display.rs b/machine_manager/src/config/display.rs index 74154f9d..743a476c 100644 --- a/machine_manager/src/config/display.rs +++ b/machine_manager/src/config/display.rs @@ -40,6 +40,10 @@ pub struct UiContext { #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] fn get_dir_path(p: &str) -> Result { + if cfg!(debug_assertions) { + return Ok(p.to_string()); + } + let path = std::fs::canonicalize(p) .with_context(|| format!("Failed to get real directory path: {:?}", p))?; if !path.exists() { @@ -81,7 +85,7 @@ pub struct DisplayConfig { pub sock_path: String, /// Define the directory path for OHUI framebuffer and cursor. #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] - #[arg(long, alias = "ui-path", default_value = "/dev/shm/hwf/", value_parser = get_dir_path)] + #[arg(long, alias = "ui-path", default_value_if("display_type", "ohui", "/dev/shm/hwf/"), default_value = "/tmp/", value_parser = get_dir_path)] pub ui_path: String, } -- Gitee From ea6e8e676e9bc5ef7d885b29af0d5bbe74cf356c Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 18 Jul 2024 04:52:50 +0800 Subject: [PATCH 216/489] virtio: virtio ut should init Eventloop if test `activate` The virtio `activate` function involves the `Eventloop`. If do `activate` in UT tests, `Eventloop` needs to be initialized first. Otherwise executing a single UT will result in an error. Signed-off-by: liuxiangdong --- virtio/src/device/balloon.rs | 31 +++++++++++++++++++------------ virtio/src/device/block.rs | 1 + virtio/src/device/net.rs | 4 ++++ 3 files changed, 24 insertions(+), 12 deletions(-) diff --git a/virtio/src/device/balloon.rs b/virtio/src/device/balloon.rs index 7240a331..4c981c18 100644 --- a/virtio/src/device/balloon.rs +++ b/virtio/src/device/balloon.rs @@ -1240,6 +1240,7 @@ mod tests { use crate::tests::{address_space_init, MEMORY_SIZE}; use crate::*; use address_space::{AddressRange, HostMemMapping, Region}; + use machine_manager::event_loop::EventLoop; const QUEUE_SIZE: u16 = 256; @@ -1532,6 +1533,8 @@ mod tests { #[test] fn test_balloon_activate() { + EventLoop::object_init(&None).unwrap(); + let mem_space = address_space_init(); let interrupt_evt = EventFd::new(libc::EFD_NONBLOCK).unwrap(); let interrupt_status = Arc::new(AtomicU32::new(0)); @@ -1548,18 +1551,20 @@ mod tests { }, ) as VirtioInterrupt); - let mut queue_config_inf = QueueConfig::new(QUEUE_SIZE); - queue_config_inf.desc_table = GuestAddress(0); - queue_config_inf.avail_ring = GuestAddress(4096); - queue_config_inf.used_ring = GuestAddress(8192); - queue_config_inf.ready = true; - queue_config_inf.size = QUEUE_SIZE; - let mut queues: Vec>> = Vec::new(); - let queue1 = Arc::new(Mutex::new(Queue::new(queue_config_inf, 1).unwrap())); - queues.push(queue1); - let event_inf = Arc::new(EventFd::new(libc::EFD_NONBLOCK).unwrap()); - let queue_evts: Vec> = vec![event_inf.clone()]; + let mut queue_evts: Vec> = Vec::new(); + for i in 0..QUEUE_NUM_BALLOON as u64 { + let mut queue_config_inf = QueueConfig::new(QUEUE_SIZE); + queue_config_inf.desc_table = GuestAddress(12288 * i + 0); + queue_config_inf.avail_ring = GuestAddress(12288 * i + 4096); + queue_config_inf.used_ring = GuestAddress(12288 * i + 8192); + queue_config_inf.ready = true; + queue_config_inf.size = QUEUE_SIZE; + let queue = Arc::new(Mutex::new(Queue::new(queue_config_inf, 1).unwrap())); + queues.push(queue); + let event_inf = Arc::new(EventFd::new(libc::EFD_NONBLOCK).unwrap()); + queue_evts.push(event_inf); + } let bln_cfg = BalloonConfig { id: "bln".to_string(), @@ -1568,7 +1573,9 @@ mod tests { }; let mut bln = Balloon::new(bln_cfg, mem_space.clone()); bln.base.queues = queues; - assert!(bln.activate(mem_space, interrupt_cb, queue_evts).is_err()); + assert!(bln.activate(mem_space, interrupt_cb, queue_evts).is_ok()); + + EventLoop::loop_clean(); } #[test] diff --git a/virtio/src/device/block.rs b/virtio/src/device/block.rs index 601b41d7..cb0a51c0 100644 --- a/virtio/src/device/block.rs +++ b/virtio/src/device/block.rs @@ -1746,5 +1746,6 @@ mod tests { break; } } + EventLoop::loop_clean(); } } diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index 05ac2857..407bf67f 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -1941,6 +1941,8 @@ mod tests { #[test] fn test_iothread() { + EventLoop::object_init(&None).unwrap(); + let mut net = Net::new(NetworkInterfaceConfig::default(), NetDevcfg::default()); net.net_cfg.iothread = Some("iothread".to_string()); if let Err(err) = net.realize() { @@ -1952,5 +1954,7 @@ mod tests { } else { assert!(false); } + + EventLoop::loop_clean(); } } -- Gitee From c5f25c730a90a0cf2602f1c6447088deef955cc8 Mon Sep 17 00:00:00 2001 From: zhanghan Date: Thu, 1 Aug 2024 14:27:11 +0800 Subject: [PATCH 217/489] OHUI:force to update ohui-fb When dpy_switch, new surface is created but not copy to ohui-fb, because viogpu bar0 passthru to ohui-fb. Force to copy data from surface to ohui-fb when dpy_switch. Signed-off-by: zhanghan --- ui/src/ohui_srv/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ui/src/ohui_srv/mod.rs b/ui/src/ohui_srv/mod.rs index 384bf02f..6f13d6b0 100755 --- a/ui/src/ohui_srv/mod.rs +++ b/ui/src/ohui_srv/mod.rs @@ -219,11 +219,12 @@ impl OhUiServer { stride: i32, pos: (i32, i32), size: (i32, i32), + force_copy: bool, ) { let (x, y) = pos; let (w, h) = size; - if self.framebuffer == 0 || *self.passthru.get_or_init(|| false) { + if self.framebuffer == 0 || (!force_copy && *self.passthru.get_or_init(|| false)) { return; } @@ -297,6 +298,7 @@ impl DisplayChangeListenerOperations for OhUiServer { locked_surface.stride, (0, 0), (locked_surface.width, locked_surface.height), + true, ); if !self.connected() { @@ -328,6 +330,7 @@ impl DisplayChangeListenerOperations for OhUiServer { locked_surface.stride, (x, y), (w, h), + false, ); self.msg_handler -- Gitee From 98e2af542d5686c61e9c9342652409949029bbae Mon Sep 17 00:00:00 2001 From: yexiao Date: Thu, 25 Jul 2024 18:27:32 +0800 Subject: [PATCH 218/489] mod_test: modify module test Clear the buffer of the stream before sending qmp command. Signed-off-by: Xiao Ye --- tests/mod_test/src/libtest.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tests/mod_test/src/libtest.rs b/tests/mod_test/src/libtest.rs index ada68e0a..aa19403b 100644 --- a/tests/mod_test/src/libtest.rs +++ b/tests/mod_test/src/libtest.rs @@ -54,6 +54,12 @@ impl StreamHandler { .unwrap(); } + fn clear_stream(&self) { + let mut stream = self.stream.try_clone().unwrap(); + stream.set_nonblocking(true).unwrap(); + stream.read(&mut [0_u8; 1024]); + } + fn read_line(&self, timeout: Duration) -> String { let start = Instant::now(); let mut resp = self.read_buffer.borrow_mut(); @@ -137,6 +143,7 @@ impl TestState { pub fn qmp(&self, cmd: &str) -> Value { let timeout = Duration::from_secs(10); + self.qmp_sock.clear_stream(); self.qmp_sock.write_line(cmd); serde_json::from_slice(self.qmp_sock.read_line(timeout).as_bytes()).unwrap() } -- Gitee From 1a796e5dbf99e3ef7bb1fb74ab62b82c7507c88a Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Wed, 17 Jul 2024 09:20:17 +0800 Subject: [PATCH 219/489] virtio-mmio: fix error Configuration space register address range According to Virtio Spec: 0x100+ is Configuration space register. Device-specific configuration space starts at the offset 0x100 and is accessed with byte alignment. Its meaning and size depend on the device and the driver. And each virtio-mmio device has a mmio range sized 0x200, (`MEM_LAYOUT[LayoutEntryType::Mmio as usize].1). Thus, the right `Configuration space register` range is `[0x100, 0x1ff]`. Fix it. Signed-off-by: liuxiangdong --- virtio/src/transport/virtio_mmio.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/virtio/src/transport/virtio_mmio.rs b/virtio/src/transport/virtio_mmio.rs index f01f87c0..42892b0d 100644 --- a/virtio/src/transport/virtio_mmio.rs +++ b/virtio/src/transport/virtio_mmio.rs @@ -400,7 +400,7 @@ impl SysBusDevOps for VirtioMmioDevice { }; LittleEndian::write_u32(data, value); } - 0x100..=0xfff => { + 0x100..=0x1ff => { if let Err(ref e) = self .device .lock() @@ -460,7 +460,7 @@ impl SysBusDevOps for VirtioMmioDevice { self.device.lock().unwrap().set_device_activated(true); } } - 0x100..=0xfff => { + 0x100..=0x1ff => { let mut locked_device = self.device.lock().unwrap(); if locked_device.check_device_status(CONFIG_STATUS_DRIVER, CONFIG_STATUS_FAILED) { if let Err(ref e) = locked_device.write_config(offset - 0x100, data) { @@ -845,7 +845,7 @@ mod tests { // read the unknown register let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; assert_eq!(virtio_mmio_device.read(&mut buf[..], addr, 0xf1), false); - assert_eq!(virtio_mmio_device.read(&mut buf[..], addr, 0xfff + 1), true); + assert_eq!(virtio_mmio_device.read(&mut buf[..], addr, 0x1ff + 1), true); assert_eq!(buf, [0xff, 0xff, 0xff, 0xff]); // read the configuration space of virtio device -- Gitee From d8bfdfec9fd835b7fa0ca28de62def1a9dfd4138 Mon Sep 17 00:00:00 2001 From: zhanghan Date: Fri, 2 Aug 2024 11:46:08 +0800 Subject: [PATCH 220/489] MST:fix usb camera mst case adjust different log for ohcamera Signed-off-by: zhanghan --- tests/mod_test/tests/usb_camera_test.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/mod_test/tests/usb_camera_test.rs b/tests/mod_test/tests/usb_camera_test.rs index b519e1ca..72539614 100644 --- a/tests/mod_test/tests/usb_camera_test.rs +++ b/tests/mod_test/tests/usb_camera_test.rs @@ -553,11 +553,17 @@ fn test_xhci_camera_hotplug_invalid() { .with_config("auto_run", true) .build(); + #[cfg(not(target_env = "ohos"))] qmp_cameradev_add(&test_state, "camdev0", "v4l2", "/tmp/not-existed"); + #[cfg(target_env = "ohos")] + qmp_cameradev_add(&test_state, "camdev0", "ohcamera", "InvalidNum"); // Invalid cameradev. let value = qmp_plug_camera(&test_state, "usbcam0", "camdev0"); let desc = value["error"]["desc"].as_str().unwrap().to_string(); + #[cfg(not(target_env = "ohos"))] assert_eq!(desc, "Failed to open v4l2 backend /tmp/not-existed."); + #[cfg(target_env = "ohos")] + assert_eq!(desc, "Invalid PATH format"); // Invalid device id. let value = qmp_unplug_camera(&test_state.clone(), "usbcam0"); let desc = value["error"]["desc"].as_str().unwrap().to_string(); -- Gitee From 944c279503f0d9de6331dfd8cb1da6ceaa42b263 Mon Sep 17 00:00:00 2001 From: jinhaogao Date: Sat, 3 Aug 2024 15:40:28 +0800 Subject: [PATCH 221/489] Test: Modify the parameter of hotplugging block in pci test. Change the parameter of hotplugging block from asynchronous to synchronous in case that the asynchronous backend is not supported. Signed-off-by: jinhaogao --- tests/mod_test/tests/pci_test.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/mod_test/tests/pci_test.rs b/tests/mod_test/tests/pci_test.rs index e23d67b1..bdd4da48 100644 --- a/tests/mod_test/tests/pci_test.rs +++ b/tests/mod_test/tests/pci_test.rs @@ -250,8 +250,8 @@ fn build_hotplug_blk_cmd( let add_blk_command = format!( "{{\"execute\": \"blockdev-add\", \ \"arguments\": {{\"node-name\": \"drive-{}\", \"file\": {{\"driver\": \ - \"file\", \"filename\": \"{}\", \"aio\": \"native\"}}, \ - \"cache\": {{\"direct\": true}}, \"read-only\": false}}}}", + \"file\", \"filename\": \"{}\", \"aio\": \"off\"}}, \ + \"cache\": {{\"direct\": false}}, \"read-only\": false}}}}", hotplug_blk_id, hotplug_image_path ); -- Gitee From 7494af6d37736616930de679de7618bb3bdf1f51 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Fri, 19 Jul 2024 15:13:30 +0800 Subject: [PATCH 222/489] vhost-vsock: add class-id for vhost-vsock Add class-id for virtio socket type. Signed-off-by: liuxiangdong --- virtio/src/transport/virtio_pci.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/virtio/src/transport/virtio_pci.rs b/virtio/src/transport/virtio_pci.rs index 8a058d8e..ca392dde 100644 --- a/virtio/src/transport/virtio_pci.rs +++ b/virtio/src/transport/virtio_pci.rs @@ -31,7 +31,7 @@ use crate::{ CONFIG_STATUS_FEATURES_OK, CONFIG_STATUS_NEEDS_RESET, INVALID_VECTOR_NUM, QUEUE_TYPE_PACKED_VRING, QUEUE_TYPE_SPLIT_VRING, VIRTIO_F_RING_PACKED, VIRTIO_F_VERSION_1, VIRTIO_MMIO_INT_CONFIG, VIRTIO_MMIO_INT_VRING, VIRTIO_TYPE_BLOCK, VIRTIO_TYPE_CONSOLE, - VIRTIO_TYPE_FS, VIRTIO_TYPE_GPU, VIRTIO_TYPE_NET, VIRTIO_TYPE_SCSI, + VIRTIO_TYPE_FS, VIRTIO_TYPE_GPU, VIRTIO_TYPE_NET, VIRTIO_TYPE_SCSI, VIRTIO_TYPE_VSOCK, }; #[cfg(feature = "virtio_gpu")] use address_space::HostMemMapping; @@ -170,7 +170,7 @@ fn get_virtio_class_id(device_type: u32, _device_quirk: Option VIRTIO_PCI_CLASS_ID_BLOCK, VIRTIO_TYPE_FS => VIRTIO_PCI_CLASS_ID_STORAGE_OTHER, VIRTIO_TYPE_NET => VIRTIO_PCI_CLASS_ID_NET, - VIRTIO_TYPE_CONSOLE => VIRTIO_PCI_CLASS_ID_COMMUNICATION_OTHER, + VIRTIO_TYPE_CONSOLE | VIRTIO_TYPE_VSOCK => VIRTIO_PCI_CLASS_ID_COMMUNICATION_OTHER, #[cfg(target_arch = "x86_64")] VIRTIO_TYPE_GPU => VIRTIO_PCI_CLASS_ID_DISPLAY_VGA, #[cfg(target_arch = "aarch64")] -- Gitee From c1d08973ba85914e6ea21964020f68edeacf2618 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Tue, 30 Jul 2024 11:30:00 +0800 Subject: [PATCH 223/489] Revert "Machine: the Mutex lock of vm is changed to RwLock" This reverts commit bd9ede4c0b27435c232c70f7a6da9b36bff230b6. Signed-off-by: Keqian Zhu --- cpu/src/lib.rs | 16 ++++----- .../src/interrupt_controller/aarch64/gicv3.rs | 2 +- .../src/interrupt_controller/aarch64/mod.rs | 6 ++-- hypervisor/src/kvm/mod.rs | 14 ++++---- machine/src/aarch64/micro.rs | 6 ++-- machine/src/aarch64/standard.rs | 10 +++--- machine/src/lib.rs | 36 +++++++++---------- machine/src/micro_common/mod.rs | 2 +- machine/src/standard_common/mod.rs | 18 +++++----- machine/src/x86_64/micro.rs | 6 ++-- machine/src/x86_64/standard.rs | 22 ++++++------ machine_manager/src/event_loop.rs | 4 +-- machine_manager/src/machine.rs | 2 +- machine_manager/src/qmp/qmp_socket.rs | 21 ++++++----- machine_manager/src/test_server.rs | 18 +++++----- migration/src/general.rs | 2 +- migration/src/manager.rs | 4 +-- migration/src/migration.rs | 4 +-- src/main.rs | 12 +++---- util/src/loop_context.rs | 12 +++---- 20 files changed, 107 insertions(+), 110 deletions(-) diff --git a/cpu/src/lib.rs b/cpu/src/lib.rs index 3c3f3f0d..7a116295 100644 --- a/cpu/src/lib.rs +++ b/cpu/src/lib.rs @@ -63,7 +63,7 @@ pub use x86_64::X86RegsIndex as RegsIndex; use std::cell::RefCell; use std::sync::atomic::{fence, AtomicBool, Ordering}; -use std::sync::{Arc, Barrier, Condvar, Mutex, RwLock, Weak}; +use std::sync::{Arc, Barrier, Condvar, Mutex, Weak}; use std::thread; use anyhow::{anyhow, Context, Result}; @@ -216,7 +216,7 @@ pub struct CPU { /// The thread tid of this VCPU. tid: Arc>>, /// The VM combined by this VCPU. - vm: Weak>, + vm: Weak>, /// The state backup of architecture CPU right before boot. boot_state: Arc>, /// Sync the pause state of vCPU in hypervisor and userspace. @@ -238,7 +238,7 @@ impl CPU { hypervisor_cpu: Arc, id: u8, arch_cpu: Arc>, - vm: Arc>, + vm: Arc>, ) -> Self { CPU { id, @@ -294,7 +294,7 @@ impl CPU { &self.hypervisor_cpu } - pub fn vm(&self) -> Weak> { + pub fn vm(&self) -> Weak> { self.vm.clone() } @@ -404,15 +404,15 @@ impl CPUInterface for CPU { fn guest_shutdown(&self) -> Result<()> { if let Some(vm) = self.vm.upgrade() { - let shutdown_act = vm.read().unwrap().get_shutdown_action(); + let shutdown_act = vm.lock().unwrap().get_shutdown_action(); match shutdown_act { ShutdownActionPoweroff => { let (cpu_state, _) = &*self.state; *cpu_state.lock().unwrap() = CpuLifecycleState::Stopped; - vm.read().unwrap().destroy(); + vm.lock().unwrap().destroy(); } ShutdownActionPause => { - vm.read().unwrap().pause(); + vm.lock().unwrap().pause(); } } } else { @@ -434,7 +434,7 @@ impl CPUInterface for CPU { if let Some(vm) = self.vm.upgrade() { let (cpu_state, _) = &*self.state; *cpu_state.lock().unwrap() = CpuLifecycleState::Paused; - vm.read().unwrap().reset(); + vm.lock().unwrap().reset(); } else { return Err(anyhow!(CpuError::NoMachineInterface)); } diff --git a/devices/src/interrupt_controller/aarch64/gicv3.rs b/devices/src/interrupt_controller/aarch64/gicv3.rs index 26f41e22..60babf03 100644 --- a/devices/src/interrupt_controller/aarch64/gicv3.rs +++ b/devices/src/interrupt_controller/aarch64/gicv3.rs @@ -338,7 +338,7 @@ impl GICDevice for GICv3 { Ok(()) } - fn reset_state(&self) -> Result<()> { + fn reset(&self) -> Result<()> { info!("Reset gicv3its"); self.reset_its_state()?; info!("Reset gicv3"); diff --git a/devices/src/interrupt_controller/aarch64/mod.rs b/devices/src/interrupt_controller/aarch64/mod.rs index 27371aba..ab548604 100644 --- a/devices/src/interrupt_controller/aarch64/mod.rs +++ b/devices/src/interrupt_controller/aarch64/mod.rs @@ -73,7 +73,7 @@ pub trait GICDevice: MachineLifecycle { fn realize(&self) -> Result<()>; /// Reset 'GIC' - fn reset_state(&self) -> Result<()> { + fn reset(&self) -> Result<()> { Ok(()) } @@ -117,9 +117,7 @@ impl InterruptController { /// Reset the InterruptController pub fn reset(&self) -> Result<()> { - self.gic - .reset_state() - .with_context(|| "Failed to reset GIC") + self.gic.reset().with_context(|| "Failed to reset GIC") } /// Change `InterruptController` lifecycle state to `Stopped`. diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs index 98dcfca4..6689e516 100644 --- a/hypervisor/src/kvm/mod.rs +++ b/hypervisor/src/kvm/mod.rs @@ -419,23 +419,23 @@ impl KvmCpu { match run { #[cfg(target_arch = "x86_64")] VcpuExit::IoIn(addr, data) => { - vm.read().unwrap().pio_in(u64::from(addr), data); + vm.lock().unwrap().pio_in(u64::from(addr), data); } #[cfg(target_arch = "x86_64")] VcpuExit::IoOut(addr, data) => { #[cfg(feature = "boot_time")] capture_boot_signal(addr as u64, data); - vm.read().unwrap().pio_out(u64::from(addr), data); + vm.lock().unwrap().pio_out(u64::from(addr), data); } VcpuExit::MmioRead(addr, data) => { - vm.read().unwrap().mmio_read(addr, data); + vm.lock().unwrap().mmio_read(addr, data); } VcpuExit::MmioWrite(addr, data) => { #[cfg(all(target_arch = "aarch64", feature = "boot_time"))] capture_boot_signal(addr, data); - vm.read().unwrap().mmio_write(addr, data); + vm.lock().unwrap().mmio_write(addr, data); } #[cfg(target_arch = "x86_64")] VcpuExit::Hlt => { @@ -919,7 +919,7 @@ impl MsiIrqManager for KVMInterruptManager { #[cfg(test)] mod test { - use std::sync::{Arc, Mutex, RwLock}; + use std::sync::{Arc, Mutex}; use std::time::Duration; #[cfg(target_arch = "x86_64")] @@ -1002,7 +1002,7 @@ mod test { return; } - let vm = Arc::new(RwLock::new(TestVm::new())); + let vm = Arc::new(Mutex::new(TestVm::new())); let code_seg = kvm_segment { base: 0, @@ -1118,7 +1118,7 @@ mod test { vcpu_fd, )); - let vm = Arc::new(RwLock::new(TestVm::new())); + let vm = Arc::new(Mutex::new(TestVm::new())); let cpu = CPU::new( hypervisor_cpu.clone(), 0, diff --git a/machine/src/aarch64/micro.rs b/machine/src/aarch64/micro.rs index 57802912..e528da66 100644 --- a/machine/src/aarch64/micro.rs +++ b/machine/src/aarch64/micro.rs @@ -10,7 +10,7 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use std::sync::{Arc, Mutex, RwLock}; +use std::sync::{Arc, Mutex}; use anyhow::{bail, Context, Result}; @@ -131,8 +131,8 @@ impl MachineOps for LightMachine { Ok(()) } - fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> { - let mut locked_vm = vm.write().unwrap(); + fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> { + let mut locked_vm = vm.lock().unwrap(); trace::sysbus(&locked_vm.base.sysbus.lock().unwrap()); trace::vm_state(&locked_vm.base.vm_state); diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index c117223b..4da86b19 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -15,7 +15,7 @@ pub use crate::error::MachineError; use std::mem::size_of; #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] use std::sync::RwLock; -use std::sync::{Arc, Mutex, RwLock}; +use std::sync::{Arc, Mutex}; use anyhow::{anyhow, bail, Context, Result}; #[cfg(feature = "ramfb")] @@ -180,8 +180,8 @@ impl StdMachine { }) } - pub fn handle_reset_request(vm: &Arc>) -> Result<()> { - let mut locked_vm = vm.write().unwrap(); + pub fn handle_reset_request(vm: &Arc>) -> Result<()> { + let mut locked_vm = vm.lock().unwrap(); let mut fdt_addr: u64 = 0; for (cpu_index, cpu) in locked_vm.base.cpus.iter().enumerate() { @@ -523,9 +523,9 @@ impl MachineOps for StdMachine { } } - fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> { + fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> { let nr_cpus = vm_config.machine_config.nr_cpus; - let mut locked_vm = vm.write().unwrap(); + let mut locked_vm = vm.lock().unwrap(); locked_vm.init_global_config(vm_config)?; register_shutdown_event(locked_vm.shutdown_req.clone(), vm.clone()) .with_context(|| "Failed to register shutdown event")?; diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 8a47faac..8a79e42b 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -451,7 +451,7 @@ pub trait MachineOps: MachineLifecycle { /// * `max_cpus` - max cpu number of virtual machine. fn create_vcpu( vcpu_id: u8, - vm: Arc>, + vm: Arc>, hypervisor: Arc>, #[cfg(target_arch = "x86_64")] max_cpus: u8, ) -> Result> @@ -485,7 +485,7 @@ pub trait MachineOps: MachineLifecycle { /// * `max_cpus` - The max number of vcpus. /// * `boot_cfg` - Boot message generated by reading boot source to guest memory. fn init_vcpu( - vm: Arc>, + vm: Arc>, hypervisor: Arc>, nr_cpus: u8, #[cfg(target_arch = "x86_64")] max_cpus: u8, @@ -2049,7 +2049,7 @@ pub trait MachineOps: MachineLifecycle { /// /// * `vm` - The machine structure. /// * `vm_config` - VM configuration. - fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> + fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> where Self: Sized; @@ -2236,7 +2236,7 @@ pub trait MachineOps: MachineLifecycle { fn register_shutdown_event( shutdown_req: Arc, - vm: Arc>, + vm: Arc>, ) -> Result<()> { let shutdown_req_fd = shutdown_req.as_raw_fd(); let shutdown_req_handler: Rc = Rc::new(move |_, _| { @@ -2258,8 +2258,8 @@ fn register_shutdown_event( .with_context(|| "Failed to register event notifier.") } -fn handle_destroy_request(vm: &Arc>) -> bool { - let locked_vm = vm.read().unwrap(); +fn handle_destroy_request(vm: &Arc>) -> bool { + let locked_vm = vm.lock().unwrap(); let vmstate: VmState = { let state = locked_vm.machine_base().vm_state.deref().0.lock().unwrap(); *state @@ -2282,12 +2282,12 @@ fn handle_destroy_request(vm: &Arc>) -> bool { /// * `vm` - virtual machine that implement `MachineOps`. /// * `cmd_args` - Command arguments from user. pub fn vm_run( - vm: &Arc>, + vm: &Arc>, cmd_args: &arg_parser::ArgMatches, ) -> Result<()> { - let migrate = vm.read().unwrap().get_migrate_info(); + let migrate = vm.lock().unwrap().get_migrate_info(); if migrate.0 == MigrateMode::Unknown { - vm.read() + vm.lock() .unwrap() .run(cmd_args.is_present("freeze_cpu")) .with_context(|| "Failed to start VM.")?; @@ -2299,13 +2299,13 @@ pub fn vm_run( } /// Start incoming migration from destination. -fn start_incoming_migration(vm: &Arc>) -> Result<()> { - let (mode, path) = vm.read().unwrap().get_migrate_info(); +fn start_incoming_migration(vm: &Arc>) -> Result<()> { + let (mode, path) = vm.lock().unwrap().get_migrate_info(); match mode { MigrateMode::File => { MigrationManager::restore_snapshot(&path) .with_context(|| "Failed to restore snapshot")?; - vm.read() + vm.lock() .unwrap() .run(false) .with_context(|| "Failed to start VM.")?; @@ -2318,7 +2318,7 @@ fn start_incoming_migration(vm: &Arc>) -> R MigrationManager::recv_migration(&mut sock) .with_context(|| "Failed to receive migration with unix mode")?; - vm.read() + vm.lock() .unwrap() .run(false) .with_context(|| "Failed to start VM.")?; @@ -2331,7 +2331,7 @@ fn start_incoming_migration(vm: &Arc>) -> R MigrationManager::recv_migration(&mut sock) .with_context(|| "Failed to receive migration with tcp mode")?; - vm.read() + vm.lock() .unwrap() .run(false) .with_context(|| "Failed to start VM.")?; @@ -2344,7 +2344,7 @@ fn start_incoming_migration(vm: &Arc>) -> R } // End the migration and reset the mode. - let locked_vm = vm.read().unwrap(); + let locked_vm = vm.lock().unwrap(); let vm_config = locked_vm.get_vm_config(); if let Some((mode, _)) = vm_config.lock().unwrap().incoming.as_mut() { *mode = MigrateMode::Unknown; @@ -2365,12 +2365,12 @@ fn check_windows_emu_pid( pid_path: String, powerdown_req: Arc, shutdown_req: Arc, - vm: Arc>, + vm: Arc>, ) { let mut check_delay = Duration::from_millis(WINDOWS_EMU_PID_DEFAULT_INTERVAL); if !Path::new(&pid_path).exists() { info!("Detect emulator exited, let VM exits now"); - let locked_vm = vm.read().unwrap(); + let locked_vm = vm.lock().unwrap(); let mut vm_state = locked_vm.get_vm_state().deref().0.lock().unwrap(); if *vm_state == VmState::Paused { info!("VM state is paused, resume VM before exit"); @@ -2414,7 +2414,7 @@ pub(crate) fn watch_windows_emu_pid( vm_config: &VmConfig, power_button: Arc, shutdown_req: Arc, - vm: Arc>, + vm: Arc>, ) { let emu_pid = vm_config.emulator_pid.as_ref(); if emu_pid.is_none() { diff --git a/machine/src/micro_common/mod.rs b/machine/src/micro_common/mod.rs index 53f12626..8410e96b 100644 --- a/machine/src/micro_common/mod.rs +++ b/machine/src/micro_common/mod.rs @@ -545,7 +545,7 @@ impl MachineLifecycle for LightMachine { true } - fn reset(&self) -> bool { + fn reset(&mut self) -> bool { // For micro vm, the reboot command is equivalent to the shutdown command. for cpu in self.base.cpus.iter() { let (cpu_state, _) = cpu.state(); diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index 86ee0e26..a7fb49ce 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -20,7 +20,7 @@ use std::os::unix::io::RawFd; use std::os::unix::prelude::AsRawFd; use std::rc::Rc; use std::string::String; -use std::sync::{Arc, Mutex, RwLock}; +use std::sync::{Arc, Mutex}; use std::u64; use anyhow::{bail, Context, Result}; @@ -242,7 +242,7 @@ pub(crate) trait StdMachineOps: AcpiBuilder + MachineOps { /// /// * `clone_vm` - Reference of the StdMachine. #[cfg(target_arch = "x86_64")] - fn add_vcpu_device(&mut self, clone_vm: Arc>) -> Result<()>; + fn add_vcpu_device(&mut self, clone_vm: Arc>) -> Result<()>; /// Register event notifier for hotplug vcpu event. /// @@ -254,7 +254,7 @@ pub(crate) trait StdMachineOps: AcpiBuilder + MachineOps { fn register_hotplug_vcpu_event( &self, hotplug_req: Arc, - clone_vm: Arc>, + clone_vm: Arc>, ) -> Result<()> { let hotplug_req_fd = hotplug_req.as_raw_fd(); let hotplug_req_handler: Rc = Rc::new(move |_, _| { @@ -300,7 +300,7 @@ pub(crate) trait StdMachineOps: AcpiBuilder + MachineOps { fn register_reset_event( &self, reset_req: Arc, - clone_vm: Arc>, + clone_vm: Arc>, ) -> Result<()> { let reset_req_fd = reset_req.as_raw_fd(); let reset_req_handler: Rc = Rc::new(move |_, _| { @@ -325,12 +325,12 @@ pub(crate) trait StdMachineOps: AcpiBuilder + MachineOps { fn register_pause_event( &self, pause_req: Arc, - clone_vm: Arc>, + clone_vm: Arc>, ) -> Result<()> { let pause_req_fd = pause_req.as_raw_fd(); let pause_req_handler: Rc = Rc::new(move |_, _| { let _ret = pause_req.read(); - if !clone_vm.read().unwrap().pause() { + if !clone_vm.lock().unwrap().pause() { error!("VM pause failed"); } None @@ -350,12 +350,12 @@ pub(crate) trait StdMachineOps: AcpiBuilder + MachineOps { fn register_resume_event( &self, resume_req: Arc, - clone_vm: Arc>, + clone_vm: Arc>, ) -> Result<()> { let resume_req_fd = resume_req.as_raw_fd(); let resume_req_handler: Rc = Rc::new(move |_, _| { let _ret = resume_req.read(); - if !clone_vm.read().unwrap().resume() { + if !clone_vm.lock().unwrap().resume() { error!("VM resume failed!"); } None @@ -980,7 +980,7 @@ impl MachineLifecycle for StdMachine { .shutdown_action } - fn reset(&self) -> bool { + fn reset(&mut self) -> bool { if self.reset_req.write(1).is_err() { error!("Standard vm write reset request failed"); return false; diff --git a/machine/src/x86_64/micro.rs b/machine/src/x86_64/micro.rs index 8f0494b5..c530633f 100644 --- a/machine/src/x86_64/micro.rs +++ b/machine/src/x86_64/micro.rs @@ -10,7 +10,7 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use std::sync::{Arc, Mutex, RwLock}; +use std::sync::{Arc, Mutex}; use anyhow::{bail, Context, Result}; @@ -138,8 +138,8 @@ impl MachineOps for LightMachine { Ok(()) } - fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> { - let mut locked_vm = vm.write().unwrap(); + fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> { + let mut locked_vm = vm.lock().unwrap(); trace::sysbus(&locked_vm.base.sysbus); trace::vm_state(&locked_vm.base.vm_state); diff --git a/machine/src/x86_64/standard.rs b/machine/src/x86_64/standard.rs index 865eb456..da509da7 100644 --- a/machine/src/x86_64/standard.rs +++ b/machine/src/x86_64/standard.rs @@ -12,7 +12,7 @@ use std::io::{Seek, SeekFrom}; use std::mem::size_of; -use std::sync::{Arc, Barrier, Mutex, RwLock}; +use std::sync::{Arc, Barrier, Mutex}; use anyhow::{bail, Context, Result}; @@ -149,8 +149,8 @@ impl StdMachine { }) } - pub fn handle_reset_request(vm: &Arc>) -> Result<()> { - let mut locked_vm = vm.write().unwrap(); + pub fn handle_reset_request(vm: &Arc>) -> Result<()> { + let mut locked_vm = vm.lock().unwrap(); for (cpu_index, cpu) in locked_vm.base.cpus.iter().enumerate() { cpu.pause() @@ -179,7 +179,7 @@ impl StdMachine { Ok(()) } - fn init_ich9_lpc(&self, vm: Arc>) -> Result<()> { + fn init_ich9_lpc(&self, vm: Arc>) -> Result<()> { let root_bus = Arc::downgrade(&self.pci_host.lock().unwrap().child_bus().unwrap()); let ich = ich9_lpc::LPCBridge::new( root_bus, @@ -199,8 +199,8 @@ impl StdMachine { None } - pub fn handle_hotplug_vcpu_request(vm: &Arc>) -> Result<()> { - let mut locked_vm = vm.write().unwrap(); + pub fn handle_hotplug_vcpu_request(vm: &Arc>) -> Result<()> { + let mut locked_vm = vm.lock().unwrap(); locked_vm.add_vcpu_device(vm.clone()) } @@ -208,7 +208,7 @@ impl StdMachine { &mut self, boot_config: CPUBootConfig, cpu_topology: CPUTopology, - vm: Arc>, + vm: Arc>, ) -> Result<()> { let region_base: u64 = MEM_LAYOUT[LayoutEntryType::CpuController as usize].0; let region_size: u64 = MEM_LAYOUT[LayoutEntryType::CpuController as usize].1; @@ -300,7 +300,7 @@ impl StdMachineOps for StdMachine { self.cpu_controller.as_ref().unwrap() } - fn add_vcpu_device(&mut self, clone_vm: Arc>) -> Result<()> { + fn add_vcpu_device(&mut self, clone_vm: Arc>) -> Result<()> { let mut locked_controller = self.cpu_controller.as_ref().unwrap().lock().unwrap(); let device_id; let vcpu_id; @@ -314,7 +314,7 @@ impl StdMachineOps for StdMachine { let boot_cfg = locked_controller.get_boot_config(); let topology = locked_controller.get_topology_config(); - let hypervisor = clone_vm.read().unwrap().base.hypervisor.clone(); + let hypervisor = clone_vm.lock().unwrap().base.hypervisor.clone(); let vcpu = ::create_vcpu( vcpu_id, clone_vm, @@ -479,10 +479,10 @@ impl MachineOps for StdMachine { syscall_whitelist() } - fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> { + fn realize(vm: &Arc>, vm_config: &mut VmConfig) -> Result<()> { let nr_cpus = vm_config.machine_config.nr_cpus; let max_cpus = vm_config.machine_config.max_cpus; - let mut locked_vm = vm.write().unwrap(); + let mut locked_vm = vm.lock().unwrap(); locked_vm.init_global_config(vm_config)?; locked_vm.base.numa_nodes = locked_vm.add_numa_nodes(vm_config)?; locked_vm.init_interrupt_controller(u64::from(nr_cpus))?; diff --git a/machine_manager/src/event_loop.rs b/machine_manager/src/event_loop.rs index e197a39e..79d7cf6f 100644 --- a/machine_manager/src/event_loop.rs +++ b/machine_manager/src/event_loop.rs @@ -12,7 +12,7 @@ use std::collections::HashMap; use std::os::unix::prelude::RawFd; -use std::sync::{Arc, Barrier, RwLock}; +use std::sync::{Arc, Barrier, Mutex}; use std::{process, thread}; use anyhow::{bail, Result}; @@ -126,7 +126,7 @@ impl EventLoop { /// # Arguments /// /// * `manager` - The main part to manager the event loop. - pub fn set_manager(manager: Arc>) { + pub fn set_manager(manager: Arc>) { // SAFETY: All concurrently accessed data of EventLoopContext is protected. unsafe { if let Some(event_loop) = GLOBAL_EVENT_LOOP.as_mut() { diff --git a/machine_manager/src/machine.rs b/machine_manager/src/machine.rs index e3663844..a040d6ef 100644 --- a/machine_manager/src/machine.rs +++ b/machine_manager/src/machine.rs @@ -116,7 +116,7 @@ pub trait MachineLifecycle { } /// Reset VM, stop running and restart a new VM. - fn reset(&self) -> bool { + fn reset(&mut self) -> bool { self.notify_lifecycle(VmState::Running, VmState::Shutdown) } diff --git a/machine_manager/src/qmp/qmp_socket.rs b/machine_manager/src/qmp/qmp_socket.rs index 62a9d62e..35ad238f 100644 --- a/machine_manager/src/qmp/qmp_socket.rs +++ b/machine_manager/src/qmp/qmp_socket.rs @@ -100,7 +100,7 @@ pub struct Socket { /// Socket stream with RwLock stream: RwLock>, /// Perform socket command - performer: Option>>, + performer: Option>>, } impl Socket { @@ -112,7 +112,7 @@ impl Socket { /// * `performer` - The `VM` to perform socket command. pub fn from_listener( listener: SocketListener, - performer: Option>>, + performer: Option>>, ) -> Self { Socket { listener, @@ -275,13 +275,12 @@ impl EventNotifierHelper for Socket { } /// Macro: to execute handle func with every arguments. -/// Attentions: Lifecycle commands cannot hold a write lock on the executor to avoid deadlock. macro_rules! qmp_command_match { ( $func:tt, $executor:expr, $ret:expr ) => { - $ret = $executor.read().unwrap().$func().into(); + $ret = $executor.$func().into(); }; ( $func:tt, $executor:expr, $cmd:expr, $ret:expr, $($arg:tt),* ) => { - $ret = $executor.write().unwrap().$func( + $ret = $executor.$func( $($cmd.$arg),* ).into(); }; @@ -290,7 +289,7 @@ macro_rules! qmp_command_match { /// Macro: to execute handle func with all arguments. macro_rules! qmp_command_match_with_argument { ( $func:tt, $executor:expr, $cmd:expr, $ret:expr ) => { - $ret = $executor.write().unwrap().$func($cmd).into(); + $ret = $executor.$func($cmd).into(); }; } @@ -366,7 +365,7 @@ fn parse_tcp_uri(uri: &str) -> Result<(String, u16)> { /// This function will fail when json parser failed or socket file description broke. fn handle_qmp( stream_fd: RawFd, - controller: &Arc>, + controller: &Arc>, leak_bucket: &mut LeakBucket, ) -> Result<()> { let mut qmp_service = crate::socket::SocketHandler::new(stream_fd); @@ -423,7 +422,7 @@ fn handle_qmp( /// function, and exec this qmp command. fn qmp_command_exec( qmp_command: QmpCommand, - controller: &Arc>, + controller: &Arc>, if_fd: Option, ) -> (String, bool) { let mut qmp_response = Response::create_empty_response(); @@ -431,7 +430,7 @@ fn qmp_command_exec( // Use macro create match to cover most Qmp command let mut id = create_command_matches!( - qmp_command.clone(); controller; qmp_response; + qmp_command.clone(); controller.lock().unwrap(); qmp_response; (stop, pause), (cont, resume), (system_powerdown, powerdown), @@ -494,12 +493,12 @@ fn qmp_command_exec( if id.is_none() { id = match qmp_command { QmpCommand::quit { id, .. } => { - controller.read().unwrap().destroy(); + controller.lock().unwrap().destroy(); shutdown_flag = true; id } QmpCommand::getfd { arguments, id } => { - qmp_response = controller.read().unwrap().getfd(arguments.fd_name, if_fd); + qmp_response = controller.lock().unwrap().getfd(arguments.fd_name, if_fd); id } QmpCommand::trace_get_state { arguments, id } => { diff --git a/machine_manager/src/test_server.rs b/machine_manager/src/test_server.rs index f8e2078c..f126ede0 100644 --- a/machine_manager/src/test_server.rs +++ b/machine_manager/src/test_server.rs @@ -14,7 +14,7 @@ use std::os::unix::io::RawFd; use std::os::unix::net::UnixStream; use std::os::unix::prelude::AsRawFd; use std::rc::Rc; -use std::sync::{Arc, Mutex, RwLock}; +use std::sync::{Arc, Mutex}; use hex::FromHexError; use vmm_sys_util::epoll::EventSet; @@ -27,11 +27,11 @@ use util::test_helper::{eoi_intx, get_test_clock, has_msix_msg, query_intx, set_ pub struct TestSock { stream: UnixStream, - controller: Arc>, + controller: Arc>, } impl TestSock { - pub fn new(path: &str, controller: Arc>) -> Self { + pub fn new(path: &str, controller: Arc>) -> Self { let stream = match UnixStream::connect(path) { Ok(s) => s, Err(e) => { @@ -115,7 +115,7 @@ fn update_clock(target: u64) { } } -fn handle_test_cmd(stream_fd: RawFd, controller: &Arc>) { +fn handle_test_cmd(stream_fd: RawFd, controller: &Arc>) { let mut handler = SocketHandler::new(stream_fd); let msg = handler.get_line().unwrap().unwrap(); @@ -129,7 +129,7 @@ fn handle_test_cmd(stream_fd: RawFd, controller: &Arc { @@ -193,7 +193,7 @@ fn handle_test_cmd(stream_fd: RawFd, controller: &Arc { @@ -207,7 +207,7 @@ fn handle_test_cmd(stream_fd: RawFd, controller: &Arc { diff --git a/migration/src/general.rs b/migration/src/general.rs index 0f9f56dc..0777e0de 100644 --- a/migration/src/general.rs +++ b/migration/src/general.rs @@ -260,7 +260,7 @@ pub trait Lifecycle { /// Pause VM during migration. fn pause() -> Result<()> { if let Some(locked_vm) = &MIGRATION_MANAGER.vmm.read().unwrap().vm { - locked_vm.read().unwrap().pause(); + locked_vm.lock().unwrap().pause(); } Ok(()) diff --git a/migration/src/manager.rs b/migration/src/manager.rs index 302350ff..d381ae31 100644 --- a/migration/src/manager.rs +++ b/migration/src/manager.rs @@ -163,7 +163,7 @@ pub struct Vmm { /// Vm config pub config: Arc>, /// Trait to represent a Vm. - pub vm: Option>>, + pub vm: Option>>, /// Trait to represent CPU devices. pub cpus: HashMap>, /// Trait to represent memory devices. @@ -245,7 +245,7 @@ impl MigrationManager { /// # Arguments /// /// * `vm` - vm instance with MachineLifecycle trait. - pub fn register_vm_instance(vm: Arc>) + pub fn register_vm_instance(vm: Arc>) where T: MachineLifecycle + Sync + Send + 'static, { diff --git a/migration/src/migration.rs b/migration/src/migration.rs index 2edfa356..2782d9cd 100644 --- a/migration/src/migration.rs +++ b/migration/src/migration.rs @@ -578,7 +578,7 @@ impl MigrationManager { /// Clear live migration environment and shut down VM. fn clear_migration() -> Result<()> { if let Some(locked_vm) = &MIGRATION_MANAGER.vmm.read().unwrap().vm { - locked_vm.read().unwrap().destroy(); + locked_vm.lock().unwrap().destroy(); } Ok(()) @@ -587,7 +587,7 @@ impl MigrationManager { /// Recover the virtual machine if migration is failed. pub fn recover_from_migration() -> Result<()> { if let Some(locked_vm) = &MIGRATION_MANAGER.vmm.read().unwrap().vm { - locked_vm.read().unwrap().resume(); + locked_vm.lock().unwrap().resume(); } Ok(()) diff --git a/src/main.rs b/src/main.rs index 2d85d8f1..cff73cbe 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,7 +12,7 @@ use std::io::Write; use std::process::{ExitCode, Termination}; -use std::sync::{Arc, Mutex, RwLock}; +use std::sync::{Arc, Mutex}; use anyhow::{bail, Context, Result}; use log::{error, info}; @@ -154,12 +154,12 @@ fn real_main(cmd_args: &arg_parser::ArgMatches, vm_config: &mut VmConfig) -> Res let listeners = check_api_channel(cmd_args, vm_config)?; let mut sockets = Vec::new(); - let vm: Arc> = match vm_config.machine_config.mach_type { + let vm: Arc> = match vm_config.machine_config.mach_type { MachineType::MicroVm => { if is_test_enabled() { panic!("module test framework does not support microvm.") } - let vm = Arc::new(RwLock::new( + let vm = Arc::new(Mutex::new( LightMachine::new(vm_config).with_context(|| "Failed to init MicroVM")?, )); MachineOps::realize(&vm, vm_config).with_context(|| "Failed to realize micro VM.")?; @@ -171,7 +171,7 @@ fn real_main(cmd_args: &arg_parser::ArgMatches, vm_config: &mut VmConfig) -> Res vm } MachineType::StandardVm => { - let vm = Arc::new(RwLock::new( + let vm = Arc::new(Mutex::new( StdMachine::new(vm_config).with_context(|| "Failed to init StandardVM")?, )); MachineOps::realize(&vm, vm_config) @@ -199,7 +199,7 @@ fn real_main(cmd_args: &arg_parser::ArgMatches, vm_config: &mut VmConfig) -> Res if is_test_enabled() { panic!("please specify machine type.") } - let vm = Arc::new(RwLock::new( + let vm = Arc::new(Mutex::new( StdMachine::new(vm_config).with_context(|| "Failed to init NoneVM")?, )); EventLoop::set_manager(vm.clone()); @@ -213,7 +213,7 @@ fn real_main(cmd_args: &arg_parser::ArgMatches, vm_config: &mut VmConfig) -> Res let balloon_switch_on = vm_config.dev_name.get("balloon").is_some(); if !cmd_args.is_present("disable-seccomp") { - vm.read() + vm.lock() .unwrap() .register_seccomp(balloon_switch_on) .with_context(|| "Failed to register seccomp rules.")?; diff --git a/util/src/loop_context.rs b/util/src/loop_context.rs index a511b1fc..957fdb4c 100644 --- a/util/src/loop_context.rs +++ b/util/src/loop_context.rs @@ -202,7 +202,7 @@ pub struct EventLoopContext { /// Epoll file descriptor. epoll: Epoll, /// Control epoll loop running. - manager: Option>>, + manager: Option>>, /// Used to wakeup epoll to re-evaluate events or timers. kick_event: EventFd, /// Used to avoid unnecessary kick operation when the @@ -290,7 +290,7 @@ impl EventLoopContext { } } - pub fn set_manager(&mut self, manager: Arc>) { + pub fn set_manager(&mut self, manager: Arc>) { self.manager = Some(manager); } @@ -547,8 +547,8 @@ impl EventLoopContext { /// Executes `epoll.wait()` to wait for events, and call the responding callbacks. pub fn run(&mut self) -> Result { if let Some(manager) = &self.manager { - if manager.read().unwrap().loop_should_exit() { - manager.read().unwrap().loop_cleanup()?; + if manager.lock().unwrap().loop_should_exit() { + manager.lock().unwrap().loop_cleanup()?; return Ok(false); } } @@ -558,8 +558,8 @@ impl EventLoopContext { pub fn iothread_run(&mut self) -> Result { if let Some(manager) = &self.manager { - if manager.read().unwrap().loop_should_exit() { - manager.read().unwrap().loop_cleanup()?; + if manager.lock().unwrap().loop_should_exit() { + manager.lock().unwrap().loop_cleanup()?; return Ok(false); } } -- Gitee From 839bc7cb2984794a74bc0a6c3c5700091e5cf33c Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Tue, 30 Jul 2024 14:55:12 +0800 Subject: [PATCH 224/489] machine: Avoid deadlock by retry when pause destroy or reset VM Enable timeout when waiting for vCPU exits. When the timeout occurs, which means the vCPU may also try to acquire VM lock which is already hold by us. So we should give up and try again. Signed-off-by: Keqian Zhu --- cpu/src/aarch64/mod.rs | 2 ++ cpu/src/lib.rs | 18 +++++++++++++++--- hypervisor/src/kvm/aarch64/mod.rs | 10 +++++++--- hypervisor/src/kvm/mod.rs | 13 +++++++++---- machine/src/aarch64/standard.rs | 7 ++++--- machine/src/lib.rs | 6 +++++- machine/src/standard_common/mod.rs | 12 +++++++++--- machine_manager/src/qmp/qmp_socket.rs | 26 ++++++++++++++++++++++++-- migration/src/general.rs | 16 +++++++++++++++- 9 files changed, 90 insertions(+), 20 deletions(-) diff --git a/cpu/src/aarch64/mod.rs b/cpu/src/aarch64/mod.rs index 3aebcbc0..9d89b489 100644 --- a/cpu/src/aarch64/mod.rs +++ b/cpu/src/aarch64/mod.rs @@ -108,6 +108,8 @@ pub struct ArmCPUState { pub features: ArmCPUFeatures, /// Virtual timer count. pub vtimer_cnt: u64, + /// Virtual timer count valid. + pub vtimer_cnt_valid: bool, } impl ArmCPUState { diff --git a/cpu/src/lib.rs b/cpu/src/lib.rs index 7a116295..2690c1c2 100644 --- a/cpu/src/lib.rs +++ b/cpu/src/lib.rs @@ -65,14 +65,16 @@ use std::cell::RefCell; use std::sync::atomic::{fence, AtomicBool, Ordering}; use std::sync::{Arc, Barrier, Condvar, Mutex, Weak}; use std::thread; +use std::time::Duration; +use std::time::Instant; -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, bail, Context, Result}; use log::{error, info, warn}; use nix::unistd::gettid; use machine_manager::config::ShutdownAction::{ShutdownActionPause, ShutdownActionPoweroff}; use machine_manager::event; -use machine_manager::machine::{HypervisorType, MachineInterface}; +use machine_manager::machine::{HypervisorType, MachineInterface, VmState}; use machine_manager::qmp::{qmp_channel::QmpChannel, qmp_schema}; // SIGRTMIN = 34 (GNU, in MUSL is 35) and SIGRTMAX = 64 in linux, VCPU signal @@ -412,7 +414,17 @@ impl CPUInterface for CPU { vm.lock().unwrap().destroy(); } ShutdownActionPause => { - vm.lock().unwrap().pause(); + let now = Instant::now(); + while !vm.lock().unwrap().pause() { + thread::sleep(Duration::from_millis(5)); + if now.elapsed() > Duration::from_secs(2) { + // Not use resume() to avoid unnecessary qmp event. + vm.lock() + .unwrap() + .notify_lifecycle(VmState::Paused, VmState::Running); + bail!("Failed to pause VM"); + } + } } } } else { diff --git a/hypervisor/src/kvm/aarch64/mod.rs b/hypervisor/src/kvm/aarch64/mod.rs index 07212360..3befdd7c 100644 --- a/hypervisor/src/kvm/aarch64/mod.rs +++ b/hypervisor/src/kvm/aarch64/mod.rs @@ -259,6 +259,7 @@ impl KvmCpu { .get_one_reg(KVM_REG_ARM_TIMER_CNT) .with_context(|| "Failed to get virtual timer count")? as u64; + locked_arch_cpu.vtimer_cnt_valid = true; } } @@ -270,7 +271,7 @@ impl KvmCpu { arch_cpu: Arc>, regs_index: RegsIndex, ) -> Result<()> { - let locked_arch_cpu = arch_cpu.lock().unwrap(); + let mut locked_arch_cpu = arch_cpu.lock().unwrap(); let apic_id = locked_arch_cpu.apic_id; match regs_index { RegsIndex::CoreRegs => { @@ -300,8 +301,11 @@ impl KvmCpu { } } RegsIndex::VtimerCount => { - self.set_one_reg(KVM_REG_ARM_TIMER_CNT, locked_arch_cpu.vtimer_cnt as u128) - .with_context(|| "Failed to set virtual timer count")?; + if locked_arch_cpu.vtimer_cnt_valid { + self.set_one_reg(KVM_REG_ARM_TIMER_CNT, locked_arch_cpu.vtimer_cnt as u128) + .with_context(|| "Failed to set virtual timer count")?; + locked_arch_cpu.vtimer_cnt_valid = false; + } } } diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs index 6689e516..d8a8da8f 100644 --- a/hypervisor/src/kvm/mod.rs +++ b/hypervisor/src/kvm/mod.rs @@ -645,7 +645,9 @@ impl CPUHypervisorOps for KvmCpu { if *cpu_state.lock().unwrap() == CpuLifecycleState::Running { *cpu_state.lock().unwrap() = CpuLifecycleState::Paused; cvar.notify_one() - } else if *cpu_state.lock().unwrap() == CpuLifecycleState::Paused { + } else if *cpu_state.lock().unwrap() == CpuLifecycleState::Paused + && pause_signal.load(Ordering::SeqCst) + { return Ok(()); } @@ -662,10 +664,13 @@ impl CPUHypervisorOps for KvmCpu { } // It shall wait for the vCPU pause state from hypervisor exits. - loop { - if pause_signal.load(Ordering::SeqCst) { - break; + let mut sleep_times = 0; + while !pause_signal.load(Ordering::SeqCst) { + if sleep_times >= 5 { + bail!(CpuError::StopVcpu("timeout".to_string())); } + thread::sleep(Duration::from_millis(5)); + sleep_times += 1; } Ok(()) diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index 4da86b19..74d24c52 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -63,7 +63,7 @@ use machine_manager::config::{ BootIndexInfo, DriveConfig, NumaNode, Param, SerialConfig, VmConfig, }; use machine_manager::event; -use machine_manager::machine::MachineLifecycle; +use machine_manager::machine::{MachineLifecycle, VmState}; use machine_manager::qmp::{qmp_channel::QmpChannel, qmp_schema}; use migration::{MigrationManager, MigrationStatus}; #[cfg(feature = "gtk")] @@ -289,8 +289,9 @@ impl StdMachine { if let Some(vcpu) = self.get_cpus().get(vcpu_index) { let (cpu_state, _) = vcpu.state(); let cpu_state = *cpu_state.lock().unwrap(); - if cpu_state != CpuLifecycleState::Paused { - self.pause(); + if cpu_state != CpuLifecycleState::Paused && !self.pause() { + self.notify_lifecycle(VmState::Paused, VmState::Running); + return None; } let value = match vcpu.hypervisor_cpu.get_one_reg(addr) { diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 8a79e42b..fbb6f14e 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -37,7 +37,7 @@ use std::time::Duration; use anyhow::{anyhow, bail, Context, Result}; use clap::Parser; -use log::{info, warn}; +use log::{error, info, warn}; use vmm_sys_util::epoll::EventSet; use vmm_sys_util::eventfd::EventFd; @@ -2244,6 +2244,10 @@ fn register_shutdown_event( if handle_destroy_request(&vm) { Some(gen_delete_notifiers(&[shutdown_req_fd])) } else { + warn!("Fail to shutdown VM, try again"); + if shutdown_req.write(1).is_err() { + error!("Failed to send shutdown request"); + } None } }); diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index a7fb49ce..ebf86b18 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -24,7 +24,7 @@ use std::sync::{Arc, Mutex}; use std::u64; use anyhow::{bail, Context, Result}; -use log::error; +use log::{error, warn}; use util::set_termi_canon_mode; use vmm_sys_util::epoll::EventSet; use vmm_sys_util::eventfd::EventFd; @@ -306,7 +306,10 @@ pub(crate) trait StdMachineOps: AcpiBuilder + MachineOps { let reset_req_handler: Rc = Rc::new(move |_, _| { read_fd(reset_req_fd); if let Err(e) = StdMachine::handle_reset_request(&clone_vm) { - error!("Fail to reboot standard VM, {:?}", e); + warn!("Fail to reboot standard VM, {:?}, try again", e); + if reset_req.write(1).is_err() { + error!("Failed to send VM reset request"); + } } None @@ -331,7 +334,10 @@ pub(crate) trait StdMachineOps: AcpiBuilder + MachineOps { let pause_req_handler: Rc = Rc::new(move |_, _| { let _ret = pause_req.read(); if !clone_vm.lock().unwrap().pause() { - error!("VM pause failed"); + warn!("VM pause failed, try again"); + if pause_req.write(1).is_err() { + error!("Failed to send VM pause request"); + } } None }); diff --git a/machine_manager/src/qmp/qmp_socket.rs b/machine_manager/src/qmp/qmp_socket.rs index 35ad238f..8326e7cd 100644 --- a/machine_manager/src/qmp/qmp_socket.rs +++ b/machine_manager/src/qmp/qmp_socket.rs @@ -15,6 +15,8 @@ use std::os::unix::io::{AsRawFd, RawFd}; use std::rc::Rc; use std::str::FromStr; use std::sync::{Arc, Mutex, RwLock}; +use std::thread; +use std::time::{Duration, Instant}; use anyhow::{bail, Context, Result}; use log::{error, info, warn}; @@ -25,7 +27,7 @@ use super::qmp_schema::QmpCommand; use super::{qmp_channel::QmpChannel, qmp_response::QmpGreeting, qmp_response::Response}; use crate::event; use crate::event_loop::EventLoop; -use crate::machine::MachineExternalInterface; +use crate::machine::{MachineExternalInterface, VmState}; use crate::socket::SocketHandler; use crate::socket::SocketRWHandler; use crate::temp_cleaner::TempCleaner; @@ -431,7 +433,6 @@ fn qmp_command_exec( // Use macro create match to cover most Qmp command let mut id = create_command_matches!( qmp_command.clone(); controller.lock().unwrap(); qmp_response; - (stop, pause), (cont, resume), (system_powerdown, powerdown), (system_reset, reset), @@ -492,6 +493,27 @@ fn qmp_command_exec( // Handle the Qmp command which macro can't cover if id.is_none() { id = match qmp_command { + QmpCommand::stop { arguments: _, id } => { + let now = Instant::now(); + while !controller.lock().unwrap().pause() { + thread::sleep(Duration::from_millis(5)); + if now.elapsed() > Duration::from_secs(2) { + // Not use resume() to avoid unnecessary qmp event. + controller + .lock() + .unwrap() + .notify_lifecycle(VmState::Paused, VmState::Running); + qmp_response = Response::create_error_response( + qmp_schema::QmpErrorClass::GenericError( + "Failed to pause VM".to_string(), + ), + None, + ); + break; + } + } + id + } QmpCommand::quit { id, .. } => { controller.lock().unwrap().destroy(); shutdown_flag = true; diff --git a/migration/src/general.rs b/migration/src/general.rs index 0777e0de..d0c7c65d 100644 --- a/migration/src/general.rs +++ b/migration/src/general.rs @@ -14,6 +14,8 @@ use std::collections::{hash_map::DefaultHasher, HashMap}; use std::hash::{Hash, Hasher}; use std::io::{Read, Write}; use std::mem::size_of; +use std::thread; +use std::time::{Duration, Instant}; use anyhow::{anyhow, bail, Context, Result}; @@ -22,6 +24,7 @@ use crate::protocol::{ DeviceStateDesc, FileFormat, MigrationHeader, MigrationStatus, VersionCheck, HEADER_LENGTH, }; use crate::{MigrationError, MigrationManager}; +use machine_manager::machine::VmState; use util::unix::host_page_size; impl MigrationManager { @@ -260,7 +263,18 @@ pub trait Lifecycle { /// Pause VM during migration. fn pause() -> Result<()> { if let Some(locked_vm) = &MIGRATION_MANAGER.vmm.read().unwrap().vm { - locked_vm.lock().unwrap().pause(); + let now = Instant::now(); + while !locked_vm.lock().unwrap().pause() { + thread::sleep(Duration::from_millis(5)); + if now.elapsed() > Duration::from_secs(2) { + // Not use resume() to avoid unnecessary qmp event. + locked_vm + .lock() + .unwrap() + .notify_lifecycle(VmState::Paused, VmState::Running); + bail!("Failed to pause VM"); + } + } } Ok(()) -- Gitee From 3cc9ee8443baad896117ba3dae1394180b197f09 Mon Sep 17 00:00:00 2001 From: Jinyu Tang Date: Mon, 5 Aug 2024 15:37:57 +0800 Subject: [PATCH 225/489] Micro: fix the ioctl allow for aarch64 In micro mode, KVM_SET_VCPU_EVENTS and KVM_SET_ONE_REG are not allowed by seccomp, but they are essential for vcpu init. The guest can not run when use micro mode in aarch64 for this reason. So fix it. --- machine/src/aarch64/micro.rs | 1 + machine/src/micro_common/syscall.rs | 1 + machine/src/x86_64/micro.rs | 1 - 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/machine/src/aarch64/micro.rs b/machine/src/aarch64/micro.rs index e528da66..6afc15e2 100644 --- a/machine/src/aarch64/micro.rs +++ b/machine/src/aarch64/micro.rs @@ -231,6 +231,7 @@ pub(crate) fn arch_ioctl_allow_list(bpf_rule: BpfRule) -> BpfRule { .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_ONE_REG() as u32) .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_DEVICE_ATTR() as u32) .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_REG_LIST() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_ONE_REG() as u32) } pub(crate) fn arch_syscall_whitelist() -> Vec { diff --git a/machine/src/micro_common/syscall.rs b/machine/src/micro_common/syscall.rs index f3acec19..6ae9a56a 100644 --- a/machine/src/micro_common/syscall.rs +++ b/machine/src/micro_common/syscall.rs @@ -159,6 +159,7 @@ fn ioctl_allow_list() -> BpfRule { .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_API_VERSION() as u32) .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_MP_STATE() as u32) .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_MP_STATE() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_VCPU_EVENTS() as u32) .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_VCPU_EVENTS() as u32); arch_ioctl_allow_list(bpf_rule) } diff --git a/machine/src/x86_64/micro.rs b/machine/src/x86_64/micro.rs index c530633f..5747076a 100644 --- a/machine/src/x86_64/micro.rs +++ b/machine/src/x86_64/micro.rs @@ -235,7 +235,6 @@ pub(crate) fn arch_ioctl_allow_list(bpf_rule: BpfRule) -> BpfRule { .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_LAPIC() as u32) .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_MSRS() as u32) .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_MSRS() as u32) - .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_VCPU_EVENTS() as u32) .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_CPUID2() as u32) } -- Gitee From cffe5f346b6d1977ddd9dfd871e9ebe64fc98d3e Mon Sep 17 00:00:00 2001 From: Li Huachao Date: Tue, 6 Aug 2024 09:35:48 +0800 Subject: [PATCH 226/489] Memory/Baloon: MST enhancements Skip NUMA related test cases if the system does not support NUMA. --- tests/mod_test/src/utils.rs | 28 ++++++++++++++++++++++++++++ tests/mod_test/tests/balloon_test.rs | 7 ++++++- tests/mod_test/tests/memory_test.rs | 11 ++++++++++- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/tests/mod_test/src/utils.rs b/tests/mod_test/src/utils.rs index b84205d4..228247e2 100644 --- a/tests/mod_test/src/utils.rs +++ b/tests/mod_test/src/utils.rs @@ -127,3 +127,31 @@ pub fn cleanup_img(image_path: String) { fs::remove_file(img_path).expect("lack permissions to remove the file"); } + +pub fn support_numa() -> bool { + let numa_nodes_path = "/sys/devices/system/node/"; + + if Path::new(numa_nodes_path).exists() { + match fs::read_dir(numa_nodes_path) { + Ok(entries) => { + let mut has_nodes = false; + for entry in entries { + if let Ok(entry) = entry { + if entry.file_name().to_str().unwrap_or("").starts_with("node") { + has_nodes = true; + break; + } + } + } + if has_nodes { + return true; + } else { + return false; + } + } + Err(_) => return false, + } + } else { + return false; + } +} diff --git a/tests/mod_test/tests/balloon_test.rs b/tests/mod_test/tests/balloon_test.rs index dbcd67fd..9fc23cc4 100644 --- a/tests/mod_test/tests/balloon_test.rs +++ b/tests/mod_test/tests/balloon_test.rs @@ -13,10 +13,11 @@ use std::cell::RefCell; use std::fs::{remove_file, File}; use std::io::{self, BufRead, BufReader}; -use std::process::Command; +use std::process::{exit, Command}; use std::rc::Rc; use std::{thread, time}; +use mod_test::utils::support_numa; use serde_json::json; use mod_test::libdriver::machine::TestStdMachine; @@ -1054,6 +1055,10 @@ fn auto_balloon_test_001() { /// Expect: /// 1/2.Success fn balloon_numa1() { + if !support_numa() { + return; + } + let page_num = 255_u32; let mut idx = 0_u32; let balloon = VirtioBalloonTest::numa_node_new(); diff --git a/tests/mod_test/tests/memory_test.rs b/tests/mod_test/tests/memory_test.rs index 155ce51a..aeeda0cf 100644 --- a/tests/mod_test/tests/memory_test.rs +++ b/tests/mod_test/tests/memory_test.rs @@ -12,10 +12,11 @@ use std::cell::RefCell; use std::fs::{remove_file, File}; -use std::process::Command; +use std::process::{exit, Command}; use std::rc::Rc; use std::string::String; +use mod_test::utils::support_numa; use serde_json::{json, Value::String as JsonString}; use mod_test::{ @@ -609,6 +610,10 @@ fn ram_readwrite_exception() { /// 1/2/3/4: success. #[test] fn ram_readwrite_numa() { + if !support_numa() { + return; + } + let mut args: Vec<&str> = Vec::new(); let mut extra_args: Vec<&str> = MACHINE_TYPE_ARG.split(' ').collect(); args.append(&mut extra_args); @@ -665,6 +670,10 @@ fn ram_readwrite_numa() { /// 1/2/3/4: success. #[test] fn ram_readwrite_numa1() { + if !support_numa() { + return; + } + let mut args: Vec<&str> = Vec::new(); let mut extra_args: Vec<&str> = MACHINE_TYPE_ARG.split(' ').collect(); args.append(&mut extra_args); -- Gitee From 623cfbe165601d968e16ef223a8ac904e9a1478d Mon Sep 17 00:00:00 2001 From: Li Huachao Date: Tue, 6 Aug 2024 10:08:30 +0800 Subject: [PATCH 227/489] Memory: do not test hugepage on ohos. On the OH system, the virtual machine does not have hugepage usage scenarios, maybe insufficient hugepages are reserved. So we ignore this test case. --- tests/mod_test/tests/memory_test.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/mod_test/tests/memory_test.rs b/tests/mod_test/tests/memory_test.rs index aeeda0cf..143dbc74 100644 --- a/tests/mod_test/tests/memory_test.rs +++ b/tests/mod_test/tests/memory_test.rs @@ -475,6 +475,7 @@ fn prealloc_ram_read_write() { /// 4. Destroy device. /// Expect: /// 1/2/3/4: success. +#[cfg(not(target_env = "ohos"))] #[test] fn hugepage_ram_read_write() { // crate hugetlbfs directory -- Gitee From 43c7f5220f231e0c8d1a47e30fa8e5b7d62860bf Mon Sep 17 00:00:00 2001 From: zhanghan Date: Mon, 5 Aug 2024 19:21:48 +0800 Subject: [PATCH 228/489] scream: support volume sync on OHOS This patch extends ivshmem bar0 and adds msix interrupt support to synchronize volume on OHOS. Scream registers bar0 extension operations to handle bar0 read/write. When the guest changes volume, scream driver writes the changed volume to the specific field of bar0 then scream handler sets the OHOS volume. When OHOS volume changes, OH audio framework calls scream callback and then scream notify the guest via msix vector 0. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: 楚影 --- devices/src/misc/ivshmem.rs | 94 +++++++++++++++++++-- devices/src/misc/scream/mod.rs | 17 +++- devices/src/misc/scream/ohaudio.rs | 75 +++++++++++++++- util/src/ohos_binding/audio/mod.rs | 73 ++++++++++++++++ util/src/ohos_binding/hwf_adapter/mod.rs | 25 ++++++ util/src/ohos_binding/hwf_adapter/volume.rs | 45 ++++++++++ 6 files changed, 318 insertions(+), 11 deletions(-) create mode 100644 util/src/ohos_binding/hwf_adapter/volume.rs diff --git a/devices/src/misc/ivshmem.rs b/devices/src/misc/ivshmem.rs index 6145bb86..090779fa 100644 --- a/devices/src/misc/ivshmem.rs +++ b/devices/src/misc/ivshmem.rs @@ -12,15 +12,17 @@ use std::sync::{ atomic::{AtomicU16, Ordering}, - Arc, Mutex, Weak, + Arc, Mutex, RwLock, Weak, }; use anyhow::Result; +use log::error; use crate::pci::config::{ PciConfig, RegionType, DEVICE_ID, PCI_CLASS_MEMORY_RAM, PCI_CONFIG_SPACE_SIZE, PCI_VENDOR_ID_REDHAT_QUMRANET, REVISION_ID, SUB_CLASS_CODE, VENDOR_ID, }; +use crate::pci::msix::init_msix; use crate::pci::{le_write_u16, PciBus, PciDevBase, PciDevOps}; use crate::{convert_bus_ref, Bus, Device, DeviceBase, PCI_BUS}; use address_space::{GuestAddress, Region, RegionOps}; @@ -34,11 +36,27 @@ const PCI_BAR_MAX_IVSHMEM: u8 = 3; const IVSHMEM_REG_BAR_SIZE: u64 = 0x100; +const IVSHMEM_BAR0_IRQ_MASK: u64 = 0; +const IVSHMEM_BAR0_IRQ_STATUS: u64 = 4; +const IVSHMEM_BAR0_IVPOSITION: u64 = 8; +const IVSHMEM_BAR0_DOORBELL: u64 = 12; + +type Bar0Write = dyn Fn(&[u8], u64) -> bool + Send + Sync; +type Bar0Read = dyn Fn(&mut [u8], u64) -> bool + Send + Sync; + +#[derive(Default)] +struct Bar0Ops { + write: Option>, + read: Option>, +} + /// Intel-VM shared memory device structure. pub struct Ivshmem { base: PciDevBase, dev_id: Arc, ram_mem_region: Region, + vector_nr: u32, + bar0_ops: Arc>, } impl Ivshmem { @@ -47,6 +65,7 @@ impl Ivshmem { devfn: u8, parent_bus: Weak>, ram_mem_region: Region, + vector_nr: u32, ) -> Self { Self { base: PciDevBase { @@ -56,14 +75,45 @@ impl Ivshmem { }, dev_id: Arc::new(AtomicU16::new(0)), ram_mem_region, + vector_nr, + bar0_ops: Arc::new(RwLock::new(Bar0Ops::default())), } } fn register_bars(&mut self) -> Result<()> { - // Currently, ivshmem uses only the shared memory and does not use interrupt. - // Therefore, bar0 read and write callback is not implemented. - let reg_read = move |_: &mut [u8], _: GuestAddress, _: u64| -> bool { true }; - let reg_write = move |_: &[u8], _: GuestAddress, _: u64| -> bool { true }; + // Currently, ivshmem does not support intx interrupt, ivposition and doorbell. + let bar0_ops = self.bar0_ops.clone(); + let reg_read = move |data: &mut [u8], _: GuestAddress, offset: u64| -> bool { + if offset >= IVSHMEM_REG_BAR_SIZE { + error!("ivshmem: read offset {} exceeds bar0 size", offset); + return true; + } + match offset { + IVSHMEM_BAR0_IRQ_MASK | IVSHMEM_BAR0_IRQ_STATUS | IVSHMEM_BAR0_IVPOSITION => {} + _ => { + if let Some(rcb) = bar0_ops.read().unwrap().read.as_ref() { + return rcb(data, offset); + } + } + } + true + }; + let bar0_ops = self.bar0_ops.clone(); + let reg_write = move |data: &[u8], _: GuestAddress, offset: u64| -> bool { + if offset >= IVSHMEM_REG_BAR_SIZE { + error!("ivshmem: write offset {} exceeds bar0 size", offset); + return true; + } + match offset { + IVSHMEM_BAR0_IRQ_MASK | IVSHMEM_BAR0_IRQ_STATUS | IVSHMEM_BAR0_DOORBELL => {} + _ => { + if let Some(wcb) = bar0_ops.read().unwrap().write.as_ref() { + return wcb(data, offset); + } + } + } + true + }; let reg_region_ops = RegionOps { read: Arc::new(reg_read), write: Arc::new(reg_write), @@ -73,11 +123,23 @@ impl Ivshmem { self.base.config.register_bar( 0, Region::init_io_region(IVSHMEM_REG_BAR_SIZE, reg_region_ops, "IvshmemIo"), - RegionType::Mem64Bit, + RegionType::Mem32Bit, false, IVSHMEM_REG_BAR_SIZE, )?; + // bar1: msix + if self.vector_nr > 0 { + init_msix( + &mut self.base, + 1, + self.vector_nr, + self.dev_id.clone(), + None, + None, + )?; + } + // bar2: ram self.base.config.register_bar( 2, @@ -87,6 +149,22 @@ impl Ivshmem { self.ram_mem_region.size(), ) } + + pub fn trigger_msix(&self, vector: u16) { + if self.vector_nr == 0 { + return; + } + if let Some(msix) = self.base.config.msix.as_ref() { + msix.lock() + .unwrap() + .notify(vector, self.dev_id.load(Ordering::Acquire)); + } + } + + pub fn set_bar0_ops(&mut self, bar0_ops: (Arc, Arc)) { + self.bar0_ops.write().unwrap().write = Some(bar0_ops.0); + self.bar0_ops.write().unwrap().read = Some(bar0_ops.1); + } } impl Device for Ivshmem { @@ -117,7 +195,9 @@ impl Device for Ivshmem { // Attach to the PCI bus. let bus = self.parent_bus().unwrap().upgrade().unwrap(); - let mut locked_bus = bus.lock().unwrap(); + PCI_BUS!(bus, locked_bus, pci_bus); + self.dev_id + .store(pci_bus.generate_dev_id(self.base.devfn), Ordering::Release); let dev = Arc::new(Mutex::new(self)); locked_bus.attach_child(dev.lock().unwrap().base.devfn as u64, dev.clone())?; Ok(dev) diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index 7d4a50a1..c5e11e56 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -36,7 +36,7 @@ use crate::{Bus, Device}; use address_space::{GuestAddress, HostMemMapping, Region}; use machine_manager::config::{get_pci_df, parse_bool, valid_id}; #[cfg(all(target_env = "ohos", feature = "scream_ohaudio"))] -use ohaudio::OhAudio; +use ohaudio::{OhAudio, OhAudioVolume}; #[cfg(feature = "scream_pulseaudio")] use pulseaudio::PulseStreamData; #[cfg(all(target_env = "ohos", feature = "scream_ohaudio"))] @@ -49,6 +49,8 @@ pub const WINDOWS_SAMPLE_BASE_RATE: u8 = 128; pub const TARGET_LATENCY_MS: u32 = 50; +const IVSHMEM_VECTORS_NR: u32 = 1; + // A frame of back-end audio data is 50ms, and the next frame of audio data needs // to be trained in polling within 50ms. Theoretically, the shorter the polling time, // the better. However, if the value is too small, the overhead is high. So take a @@ -543,8 +545,17 @@ impl Scream { let devfn = (self.config.addr.0 << 3) + self.config.addr.1; let mem_region = Region::init_ram_region(host_mmap, "ivshmem_ram"); - let ivshmem = Ivshmem::new("ivshmem".to_string(), devfn, parent_bus, mem_region); - ivshmem.realize()?; + let ivshmem = Ivshmem::new( + "ivshmem".to_string(), + devfn, + parent_bus, + mem_region, + IVSHMEM_VECTORS_NR, + ); + let _ivshmem = ivshmem.realize()?; + + #[cfg(target_env = "ohos")] + OhAudioVolume::init_volume_sync(_ivshmem); self.start_play_thread_fn()?; self.start_record_thread_fn() diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index 1f585305..c44d7067 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -23,15 +23,18 @@ use std::{ time::{Duration, Instant}, }; -use log::{error, warn}; +use log::{error, info, warn}; +use crate::misc::ivshmem::Ivshmem; use crate::misc::scream::{AudioInterface, ScreamDirection, ShmemStreamHeader, StreamData}; +use crate::pci::{le_read_u32, le_write_u32}; use machine_manager::notifier::register_vm_pause_notifier; use util::ohos_binding::audio::*; const STREAM_DATA_VEC_CAPACITY: usize = 15; const FLUSH_DELAY_MS: u64 = 5; const FLUSH_DELAY_CNT: u64 = 200; +const IVSHMEM_BAR0_VOLUME: u64 = 240; trait OhAudioProcess { fn init(&mut self, stream: &StreamData) -> bool; @@ -631,6 +634,76 @@ impl AudioInterface for OhAudio { } } +pub struct OhAudioVolume { + shm_dev: Arc>, + ohos_vol: RwLock, +} + +impl GuestVolumeNotifier for OhAudioVolume { + fn notify(&self, vol: u32) { + *self.ohos_vol.write().unwrap() = vol; + self.shm_dev.lock().unwrap().trigger_msix(0); + } +} + +impl OhAudioVolume { + pub fn new(shm_dev: Arc>) -> Arc { + let vol = Arc::new(Self { + shm_dev, + ohos_vol: RwLock::new(0), + }); + register_guest_volume_notifier(vol.clone()); + vol + } + + fn set_volume(&self, vol: u32) { + set_ohos_volume(vol); + } + + fn get_volume(&self) -> u32 { + *self.ohos_vol.read().unwrap() + } + + fn init_volume(&self) { + *self.ohos_vol.write().unwrap() = get_ohos_volume(); + } + + pub fn init_volume_sync(ivshmem: Arc>) { + let ohvol = OhAudioVolume::new(ivshmem.clone()); + let ohvol2 = ohvol.clone(); + ohvol.init_volume(); + let bar0_write = Arc::new(move |data: &[u8], offset: u64| { + match offset { + IVSHMEM_BAR0_VOLUME => match le_read_u32(data, 0) { + Ok(v) => ohvol.set_volume(v), + Err(e) => error!("ohaudio le_read_u32 failed: {e}"), + }, + _ => { + info!("ivshmem-scream on ohaudio: unsupported write:{offset}"); + } + } + true + }); + let bar0_read = Arc::new(move |data: &mut [u8], offset: u64| { + match offset { + IVSHMEM_BAR0_VOLUME => { + if let Err(e) = le_write_u32(data, 0, ohvol2.get_volume()) { + error!("ohaudio le_write_u32 failed: {e}"); + } + } + _ => { + info!("ivshmem-scream on ohaudio: unsupported read:{offset}"); + } + } + true + }); + ivshmem + .lock() + .unwrap() + .set_bar0_ops((bar0_write, bar0_read)); + } +} + #[cfg(test)] mod tests { use crate::misc::scream::ohaudio::{on_read_data_cb, on_write_data_cb, StreamUnit}; diff --git a/util/src/ohos_binding/audio/mod.rs b/util/src/ohos_binding/audio/mod.rs index 4dd7687f..e67bf4e4 100755 --- a/util/src/ohos_binding/audio/mod.rs +++ b/util/src/ohos_binding/audio/mod.rs @@ -14,9 +14,12 @@ mod sys; use std::os::raw::c_void; use std::ptr; +use std::sync::{Arc, RwLock}; use log::error; +use once_cell::sync::Lazy; +use super::hwf_adapter::{hwf_adapter_volume_api, volume::VolumeFuncTable}; use sys as capi; const AUDIO_SAMPLE_RATE_44KHZ: u32 = 44100; @@ -366,6 +369,76 @@ impl AudioContext { } } +// From here, the code is related to ohaudio volume. +static OH_VOLUME_ADAPTER: Lazy> = Lazy::new(|| RwLock::new(OhVolume::new())); + +pub trait GuestVolumeNotifier: Send + Sync { + fn notify(&self, vol: u32); +} + +struct OhVolume { + capi: Arc, + notifiers: Vec>, +} + +impl OhVolume { + fn new() -> Self { + let capi = hwf_adapter_volume_api(); + // SAFETY: We call related API sequentially for specified ctx. + unsafe { (*capi.register_volume_change)(on_ohos_volume_changed) }; + Self { + capi, + notifiers: Vec::new(), + } + } + + fn get_ohos_volume(&self) -> u32 { + // SAFETY: We call related API sequentially for specified ctx. + unsafe { (self.capi.get_volume)() as u32 } + } + + fn set_ohos_volume(&self, volume: i32) { + // SAFETY: We call related API sequentially for specified ctx. + unsafe { (self.capi.set_volume)(volume) }; + } + + fn notify_volume_change(&self, volume: i32) { + for notifier in self.notifiers.iter() { + notifier.notify(volume as u32); + } + } + + fn register_guest_notifier(&mut self, notifier: Arc) { + self.notifiers.push(notifier); + } +} + +// SAFETY: use RW lock to ensure the security of resources. +unsafe extern "C" fn on_ohos_volume_changed(volume: i32) { + OH_VOLUME_ADAPTER + .read() + .unwrap() + .notify_volume_change(volume); +} + +pub fn register_guest_volume_notifier(notifier: Arc) { + OH_VOLUME_ADAPTER + .write() + .unwrap() + .register_guest_notifier(notifier); +} + +pub fn get_ohos_volume() -> u32 { + OH_VOLUME_ADAPTER.read().unwrap().get_ohos_volume() +} + +pub fn set_ohos_volume(vol: u32) { + OH_VOLUME_ADAPTER + .read() + .unwrap() + .set_ohos_volume(vol as i32); +} + #[cfg(test)] mod tests { use crate::ohos_binding::audio::sys as capi; diff --git a/util/src/ohos_binding/hwf_adapter/mod.rs b/util/src/ohos_binding/hwf_adapter/mod.rs index 2709c81f..14e4e0c2 100644 --- a/util/src/ohos_binding/hwf_adapter/mod.rs +++ b/util/src/ohos_binding/hwf_adapter/mod.rs @@ -15,6 +15,9 @@ pub mod camera; #[cfg(feature = "usb_host")] pub mod usb; +#[cfg(feature = "scream_ohaudio")] +pub mod volume; + use std::ffi::OsStr; use std::sync::Arc; @@ -27,6 +30,8 @@ use once_cell::sync::Lazy; use camera::CamFuncTable; #[cfg(feature = "usb_host")] use usb::UsbFuncTable; +#[cfg(feature = "scream_ohaudio")] +use volume::VolumeFuncTable; static LIB_HWF_ADAPTER: Lazy = Lazy::new(|| // SAFETY: The dynamic library should be always existing. @@ -46,6 +51,8 @@ struct LibHwfAdapter { camera: Arc, #[cfg(feature = "usb_host")] usb: Arc, + #[cfg(feature = "scream_ohaudio")] + volume: Arc, } impl LibHwfAdapter { @@ -63,12 +70,20 @@ impl LibHwfAdapter { UsbFuncTable::new(&library).with_context(|| "failed to init usb function table")?, ); + #[cfg(feature = "scream_ohaudio")] + let volume = Arc::new( + VolumeFuncTable::new(&library) + .with_context(|| "failed to init volume function table")?, + ); + Ok(Self { library, #[cfg(feature = "usb_camera_oh")] camera, #[cfg(feature = "usb_host")] usb, + #[cfg(feature = "scream_ohaudio")] + volume, }) } @@ -81,6 +96,11 @@ impl LibHwfAdapter { fn get_usb_api(&self) -> Arc { self.usb.clone() } + + #[cfg(feature = "scream_ohaudio")] + fn get_volume_api(&self) -> Arc { + self.volume.clone() + } } #[cfg(feature = "usb_camera_oh")] @@ -92,3 +112,8 @@ pub fn hwf_adapter_camera_api() -> Arc { pub fn hwf_adapter_usb_api() -> Arc { LIB_HWF_ADAPTER.get_usb_api() } + +#[cfg(feature = "scream_ohaudio")] +pub fn hwf_adapter_volume_api() -> Arc { + LIB_HWF_ADAPTER.get_volume_api() +} diff --git a/util/src/ohos_binding/hwf_adapter/volume.rs b/util/src/ohos_binding/hwf_adapter/volume.rs new file mode 100644 index 00000000..3de5e34b --- /dev/null +++ b/util/src/ohos_binding/hwf_adapter/volume.rs @@ -0,0 +1,45 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::os::raw::c_int; + +use anyhow::{Context, Result}; +use libloading::os::unix::Symbol as RawSymbol; +use libloading::Library; + +use crate::get_libfn; + +pub type VolumeChangedCallBack = unsafe extern "C" fn(c_int); + +type OhSysAudioGetVolumeFn = unsafe extern "C" fn() -> c_int; +type OhSysAudioSetVolumeFn = unsafe extern "C" fn(c_int); +type OhSysAudioRegisterVolumeChangeFn = unsafe extern "C" fn(VolumeChangedCallBack) -> c_int; + +pub struct VolumeFuncTable { + pub get_volume: RawSymbol, + pub set_volume: RawSymbol, + pub register_volume_change: RawSymbol, +} + +impl VolumeFuncTable { + pub unsafe fn new(library: &Library) -> Result { + Ok(Self { + get_volume: get_libfn!(library, OhSysAudioGetVolumeFn, OhSysAudioGetVolume), + set_volume: get_libfn!(library, OhSysAudioSetVolumeFn, OhSysAudioSetVolume), + register_volume_change: get_libfn!( + library, + OhSysAudioRegisterVolumeChangeFn, + OhSysAudioRegisterVolumeChange + ), + }) + } +} -- Gitee From 9cc7b6ba0be27ea4aca9c804b0709abe972948d0 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Fri, 19 Jul 2024 16:31:11 +0800 Subject: [PATCH 229/489] mst: shield aio related tests on HarmonyOS HarmonyOS does not support libaio/io_uring now. Shield these tests. Signed-off-by: liuxiangdong --- tests/mod_test/tests/block_test.rs | 12 ++++++++++-- tests/mod_test/tests/scsi_test.rs | 4 ++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/tests/mod_test/tests/block_test.rs b/tests/mod_test/tests/block_test.rs index e7a633aa..dc2395be 100644 --- a/tests/mod_test/tests/block_test.rs +++ b/tests/mod_test/tests/block_test.rs @@ -708,6 +708,11 @@ fn blk_all_features() { let device_args = Rc::new(String::from( ",multifunction=on,serial=111111,num-queues=4,bootindex=1,iothread=iothread1", )); + #[cfg(target_env = "ohos")] + let drive_args = Rc::new(String::from( + ",direct=false,readonly=off,throttling.iops-total=1024", + )); + #[cfg(not(target_env = "ohos"))] let drive_args = if aio_probe(AioEngine::IoUring).is_ok() { Rc::new(String::from( ",direct=on,aio=io_uring,readonly=off,throttling.iops-total=1024", @@ -1038,16 +1043,18 @@ fn blk_iops() { /// 1/2/3: success. #[test] fn blk_with_different_aio() { - const BLOCK_DRIVER_CFG: [(ImageType, &str, AioEngine); 6] = [ + let block_driver_cfg: Vec<(ImageType, &str, AioEngine)> = vec![ (ImageType::Raw, "off", AioEngine::Off), (ImageType::Qcow2, "off", AioEngine::Off), (ImageType::Raw, "off", AioEngine::Threads), (ImageType::Qcow2, "off", AioEngine::Threads), + #[cfg(not(target_env = "ohos"))] (ImageType::Raw, "on", AioEngine::Native), + #[cfg(not(target_env = "ohos"))] (ImageType::Raw, "on", AioEngine::IoUring), ]; - for (image_type, direct, aio_engine) in BLOCK_DRIVER_CFG { + for (image_type, direct, aio_engine) in block_driver_cfg { println!("Image type: {:?}", image_type); let image_path = Rc::new(create_img(TEST_IMAGE_SIZE_1M, 1, &image_type)); let device_args = Rc::new(String::from("")); @@ -1106,6 +1113,7 @@ fn blk_with_different_aio() { /// 3. Destroy device. /// Expect: /// 1/2/3: success. +#[cfg(not(target_env = "ohos"))] #[test] fn blk_aio_io_uring() { for image_type in ImageType::IMAGE_TYPE { diff --git a/tests/mod_test/tests/scsi_test.rs b/tests/mod_test/tests/scsi_test.rs index aecb4b80..61fb6805 100644 --- a/tests/mod_test/tests/scsi_test.rs +++ b/tests/mod_test/tests/scsi_test.rs @@ -27,6 +27,7 @@ use mod_test::libdriver::virtio::{ use mod_test::libdriver::virtio_pci_modern::TestVirtioPciDev; use mod_test::libtest::{test_init, TestState, MACHINE_TYPE_ARG}; use mod_test::utils::{cleanup_img, create_img, ImageType, TEST_IMAGE_SIZE}; +#[cfg(not(target_env = "ohos"))] use util::aio::{aio_probe, AioEngine}; use util::byte_code::ByteCode; use util::offset_of; @@ -505,6 +506,7 @@ impl std::fmt::Display for ScsiDeviceType { } } +#[allow(dead_code)] #[derive(Clone, Debug, Copy)] enum TestAioType { AioOff = 0, @@ -1865,6 +1867,7 @@ fn aio_model_test() { let mut lun = 0x2; let mut device_vec: Vec = Vec::new(); + #[cfg(not(target_env = "ohos"))] if aio_probe(AioEngine::IoUring).is_ok() { // Scsi Disk 1. AIO io_uring. Direct false. let image_path = Rc::new(create_img(TEST_IMAGE_SIZE, 0, &ImageType::Raw)); @@ -1916,6 +1919,7 @@ fn aio_model_test() { // Scsi Disk 5. AIO native. Direct false. This is not allowed. // Stratovirt will report "native aio type should be used with direct on" + #[cfg(not(target_env = "ohos"))] if aio_probe(AioEngine::Native).is_ok() { // Scsi Disk 6. AIO native. Direct true. lun += 1; -- Gitee From 471378be185a35043fd1b6d58656b5b8aab23c20 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Fri, 19 Jul 2024 17:06:25 +0800 Subject: [PATCH 230/489] mst: fix some warnings Fix some warnings in mst. Signed-off-by: liuxiangdong --- tests/mod_test/src/libtest.rs | 2 +- tests/mod_test/tests/balloon_test.rs | 2 +- tests/mod_test/tests/memory_test.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/mod_test/src/libtest.rs b/tests/mod_test/src/libtest.rs index aa19403b..3aa95723 100644 --- a/tests/mod_test/src/libtest.rs +++ b/tests/mod_test/src/libtest.rs @@ -57,7 +57,7 @@ impl StreamHandler { fn clear_stream(&self) { let mut stream = self.stream.try_clone().unwrap(); stream.set_nonblocking(true).unwrap(); - stream.read(&mut [0_u8; 1024]); + let _ = stream.read(&mut [0_u8; 1024]); } fn read_line(&self, timeout: Duration) -> String { diff --git a/tests/mod_test/tests/balloon_test.rs b/tests/mod_test/tests/balloon_test.rs index 9fc23cc4..b67453e3 100644 --- a/tests/mod_test/tests/balloon_test.rs +++ b/tests/mod_test/tests/balloon_test.rs @@ -13,7 +13,7 @@ use std::cell::RefCell; use std::fs::{remove_file, File}; use std::io::{self, BufRead, BufReader}; -use std::process::{exit, Command}; +use std::process::Command; use std::rc::Rc; use std::{thread, time}; diff --git a/tests/mod_test/tests/memory_test.rs b/tests/mod_test/tests/memory_test.rs index 143dbc74..ed7dca58 100644 --- a/tests/mod_test/tests/memory_test.rs +++ b/tests/mod_test/tests/memory_test.rs @@ -12,7 +12,7 @@ use std::cell::RefCell; use std::fs::{remove_file, File}; -use std::process::{exit, Command}; +use std::process::Command; use std::rc::Rc; use std::string::String; -- Gitee From 0a93987056808d4121fc0f6d45f38e672c331169 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Fri, 19 Jul 2024 19:14:12 +0800 Subject: [PATCH 231/489] mst: delete redundant `add_msix_msg` function Delete redundant `add_msix_msg` function. Signed-off-by: liuxiangdong --- hypervisor/src/test/mod.rs | 17 ++--------------- 1 file changed, 2 insertions(+), 15 deletions(-) diff --git a/hypervisor/src/test/mod.rs b/hypervisor/src/test/mod.rs index 8e4697ae..7120bb9e 100644 --- a/hypervisor/src/test/mod.rs +++ b/hypervisor/src/test/mod.rs @@ -41,7 +41,7 @@ use devices::{pci::MsiVector, IrqManager, LineIrqManager, MsiIrqManager, Trigger use devices::{GICVersion, GICv3, ICGICConfig, InterruptController, GIC_IRQ_INTERNAL}; use machine_manager::machine::HypervisorType; use migration::{MigrateMemSlot, MigrateOps}; -use util::test_helper::{IntxInfo, MsixMsg, TEST_INTX_LIST, TEST_MSIX_LIST}; +use util::test_helper::{add_msix_msg, IntxInfo, TEST_INTX_LIST}; pub struct TestHypervisor {} @@ -301,19 +301,6 @@ impl TestInterruptManager { pub fn arch_map_irq(&self, gsi: u32) -> u32 { gsi + GIC_IRQ_INTERNAL } - - pub fn add_msix_msg(addr: u64, data: u32) { - let new_msg = MsixMsg::new(addr, data); - let mut msix_list_lock = TEST_MSIX_LIST.lock().unwrap(); - - for msg in msix_list_lock.iter() { - if new_msg.addr == msg.addr && new_msg.data == msg.data { - return; - } - } - - msix_list_lock.push(new_msg); - } } impl LineIrqManager for TestInterruptManager { @@ -405,7 +392,7 @@ impl MsiIrqManager for TestInterruptManager { let data = vector.msg_data; let mut addr: u64 = vector.msg_addr_hi as u64; addr = (addr << 32) + vector.msg_addr_lo as u64; - TestInterruptManager::add_msix_msg(addr, data); + add_msix_msg(addr, data); Ok(()) } -- Gitee From ded113e1084cded99170b79322b515c58b7a749d Mon Sep 17 00:00:00 2001 From: sujerry1991 Date: Wed, 7 Aug 2024 21:10:48 +0800 Subject: [PATCH 232/489] io_uring: delete ASYNC for performance Without ASYNC flag, the operation for io_uring is to try and issue an sqe as non-blocking first, and if that fails, execute it in an async manner. With ASYNC flag it ask for an sqe to be issued aysnc form the start. Note that this flag immediately causes the SQE to be offloaded to an async helper thread with no initial non-blocking attempt. This may be less efficient and should not be used liberally or without understanding the performance and efficiency tradeoffs. Signed-off-by: Yan Wang --- util/src/aio/uring.rs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/util/src/aio/uring.rs b/util/src/aio/uring.rs index 8f95832e..367a85eb 100644 --- a/util/src/aio/uring.rs +++ b/util/src/aio/uring.rs @@ -13,7 +13,7 @@ use std::os::unix::io::AsRawFd; use anyhow::{bail, Context}; -use io_uring::{opcode, squeue, types, IoUring}; +use io_uring::{opcode, types, IoUring}; use libc; use vmm_sys_util::eventfd::EventFd; @@ -70,17 +70,12 @@ impl AioContext for IoUringContext { OpCode::Preadv => opcode::Readv::new(fd, iovs as *const libc::iovec, len as u32) .offset(offset) .build() - .flags(squeue::Flags::ASYNC) .user_data(data), OpCode::Pwritev => opcode::Writev::new(fd, iovs as *const libc::iovec, len as u32) .offset(offset) .build() - .flags(squeue::Flags::ASYNC) - .user_data(data), - OpCode::Fdsync => opcode::Fsync::new(fd) - .build() - .flags(squeue::Flags::ASYNC) .user_data(data), + OpCode::Fdsync => opcode::Fsync::new(fd).build().user_data(data), _ => { bail!("Invalid entry code"); } -- Gitee From 6c0513e72f55482e35aae888c5cfa41a25bac746 Mon Sep 17 00:00:00 2001 From: lixiang_yewu Date: Wed, 7 Aug 2024 07:25:12 +0000 Subject: [PATCH 233/489] update docs/trace.md. Signed-off-by: lixiang_yewu --- docs/trace.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/trace.md b/docs/trace.md index bf1c24aa..d4623fa6 100644 --- a/docs/trace.md +++ b/docs/trace.md @@ -70,7 +70,7 @@ of settings. ### log StratoVirt supports outputting trace to the log file at trace level. Turn on -the **trace_to_logger** feature to use is. +the **trace_to_logger** feature to use it. ### Ftrace @@ -80,7 +80,7 @@ suited for performance issues. It can be enabled by turning on the **trace_to_ftrace** feature during compilation. StratoVirt use ftrace by writing trace data to ftrace marker, and developers can -read trace records from trace file under mounted ftrace director, +read trace records from trace file under mounted ftrace directory, e.g. /sys/kernel/debug/tracing/trace. ### HiTraceMeter -- Gitee From 3c17ee88c5ab9d74b85499ce863f8fd2fd71609c Mon Sep 17 00:00:00 2001 From: Jinhao Gao Date: Thu, 8 Aug 2024 14:53:58 +0800 Subject: [PATCH 234/489] PCI: Add devfn for pciconfig Log the information of pci bar mapping. Signed-off-by: Jinhao Gao --- devices/src/misc/ivshmem.rs | 2 +- devices/src/misc/pvpanic.rs | 2 +- devices/src/pci/config.rs | 31 +++++++++++++++++++--------- devices/src/pci/demo_device/mod.rs | 2 +- devices/src/pci/mod.rs | 2 +- devices/src/pci/msix.rs | 4 ++-- devices/src/pci/root_port.rs | 2 +- devices/src/usb/xhci/xhci_pci.rs | 2 +- machine/src/aarch64/pci_host_root.rs | 2 +- machine/src/x86_64/ich9_lpc.rs | 2 +- machine/src/x86_64/mch.rs | 2 +- vfio/src/vfio_pci.rs | 4 ++-- virtio/src/transport/virtio_pci.rs | 2 +- 13 files changed, 35 insertions(+), 24 deletions(-) diff --git a/devices/src/misc/ivshmem.rs b/devices/src/misc/ivshmem.rs index 090779fa..d4d50f36 100644 --- a/devices/src/misc/ivshmem.rs +++ b/devices/src/misc/ivshmem.rs @@ -70,7 +70,7 @@ impl Ivshmem { Self { base: PciDevBase { base: DeviceBase::new(name, false, Some(parent_bus)), - config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, PCI_BAR_MAX_IVSHMEM), + config: PciConfig::new(devfn, PCI_CONFIG_SPACE_SIZE, PCI_BAR_MAX_IVSHMEM), devfn, }, dev_id: Arc::new(AtomicU16::new(0)), diff --git a/devices/src/misc/pvpanic.rs b/devices/src/misc/pvpanic.rs index 8c8dcd06..1647a2d5 100644 --- a/devices/src/misc/pvpanic.rs +++ b/devices/src/misc/pvpanic.rs @@ -111,7 +111,7 @@ impl PvPanicPci { Self { base: PciDevBase { base: DeviceBase::new(config.id.clone(), false, Some(parent_bus)), - config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 1), + config: PciConfig::new(devfn, PCI_CONFIG_SPACE_SIZE, 1), devfn, }, dev_id: AtomicU16::new(0), diff --git a/devices/src/pci/config.rs b/devices/src/pci/config.rs index 69976cac..02858fe1 100644 --- a/devices/src/pci/config.rs +++ b/devices/src/pci/config.rs @@ -14,7 +14,7 @@ use std::collections::HashSet; use std::sync::{Arc, Mutex}; use anyhow::{anyhow, Context, Result}; -use log::{error, warn}; +use log::{error, info, warn}; use crate::pci::intx::Intx; use crate::pci::msix::{Msix, MSIX_TABLE_ENTRY_SIZE}; @@ -383,6 +383,8 @@ pub enum PcieDevType { /// Configuration space of PCI/PCIe device. #[derive(Clone)] pub struct PciConfig { + /// Device number and function number. + pub devfn: u8, /// Configuration space data. pub config: Vec, /// Mask of writable bits. @@ -412,7 +414,7 @@ impl PciConfig { /// /// * `config_size` - Configuration size in bytes. /// * `nr_bar` - Number of BARs. - pub fn new(config_size: usize, nr_bar: u8) -> Self { + pub fn new(devfn: u8, config_size: usize, nr_bar: u8) -> Self { let mut bars = Vec::new(); for _ in 0..nr_bar as usize { bars.push(Bar { @@ -426,6 +428,7 @@ impl PciConfig { } PciConfig { + devfn, config: vec![0; config_size], write_mask: vec![0; config_size], write_clear_mask: vec![0; config_size], @@ -905,6 +908,10 @@ impl PciConfig { } } + info!( + "pci dev {} delete bar {} mapping: addr 0x{:X} size {}", + self.devfn, id, self.bars[id].address, self.bars[id].size + ); trace::pci_update_mappings_del(id, self.bars[id].address, self.bars[id].size); self.bars[id].address = BAR_SPACE_UNMAPPED; } @@ -939,6 +946,10 @@ impl PciConfig { } } + info!( + "pci dev {} update bar {} mapping: addr 0x{:X} size {}", + self.devfn, id, new_addr, self.bars[id].size + ); trace::pci_update_mappings_add(id, self.bars[id].address, self.bars[id].size); self.bars[id].address = new_addr; } @@ -1209,7 +1220,7 @@ mod tests { #[test] fn test_find_pci_cap() { - let mut pci_config = PciConfig::new(PCI_CONFIG_SPACE_SIZE, 3); + let mut pci_config = PciConfig::new(0, PCI_CONFIG_SPACE_SIZE, 3); let offset = pci_config.find_pci_cap(MSIX_CAP_ID); assert_eq!(offset, 0xff); @@ -1239,7 +1250,7 @@ mod tests { write: Arc::new(write_ops), }; let region = Region::init_io_region(8192, region_ops.clone(), "io"); - let mut pci_config = PciConfig::new(PCI_CONFIG_SPACE_SIZE, 3); + let mut pci_config = PciConfig::new(0, PCI_CONFIG_SPACE_SIZE, 3); #[cfg(target_arch = "x86_64")] assert!(pci_config @@ -1316,7 +1327,7 @@ mod tests { write: Arc::new(write_ops), }; let region = Region::init_io_region(8192, region_ops, "io"); - let mut pci_config = PciConfig::new(PCI_CONFIG_SPACE_SIZE, 6); + let mut pci_config = PciConfig::new(0, PCI_CONFIG_SPACE_SIZE, 6); #[cfg(target_arch = "x86_64")] assert!(pci_config @@ -1413,7 +1424,7 @@ mod tests { #[test] fn test_add_pci_cap() { - let mut pci_config = PciConfig::new(PCI_CONFIG_SPACE_SIZE, 2); + let mut pci_config = PciConfig::new(0, PCI_CONFIG_SPACE_SIZE, 2); // Overflow. assert!(pci_config @@ -1430,7 +1441,7 @@ mod tests { #[test] fn test_add_pcie_ext_cap() { - let mut pci_config = PciConfig::new(PCIE_CONFIG_SPACE_SIZE, 2); + let mut pci_config = PciConfig::new(0, PCIE_CONFIG_SPACE_SIZE, 2); // Overflow. assert!(pci_config @@ -1451,7 +1462,7 @@ mod tests { #[test] fn test_get_ext_cap_size() { - let mut pcie_config = PciConfig::new(PCIE_CONFIG_SPACE_SIZE, 3); + let mut pcie_config = PciConfig::new(0, PCIE_CONFIG_SPACE_SIZE, 3); let offset1 = pcie_config.add_pcie_ext_cap(1, 0x10, 1).unwrap(); let offset2 = pcie_config.add_pcie_ext_cap(1, 0x40, 1).unwrap(); pcie_config.add_pcie_ext_cap(1, 0x20, 1).unwrap(); @@ -1464,7 +1475,7 @@ mod tests { #[test] fn test_reset_common_regs() { - let mut pcie_config = PciConfig::new(PCIE_CONFIG_SPACE_SIZE, 3); + let mut pcie_config = PciConfig::new(0, PCIE_CONFIG_SPACE_SIZE, 3); pcie_config.init_common_write_mask().unwrap(); pcie_config.init_common_write_clear_mask().unwrap(); @@ -1489,7 +1500,7 @@ mod tests { write: Arc::new(write_ops), }; let region = Region::init_io_region(4096, region_ops, "io"); - let mut pci_config = PciConfig::new(PCI_CONFIG_SPACE_SIZE, 3); + let mut pci_config = PciConfig::new(0, PCI_CONFIG_SPACE_SIZE, 3); // bar is unmapped #[cfg(target_arch = "x86_64")] diff --git a/devices/src/pci/demo_device/mod.rs b/devices/src/pci/demo_device/mod.rs index 58a88c7d..b4163f7a 100644 --- a/devices/src/pci/demo_device/mod.rs +++ b/devices/src/pci/demo_device/mod.rs @@ -103,7 +103,7 @@ impl DemoDev { DemoDev { base: PciDevBase { base: DeviceBase::new(cfg.id.clone(), false, Some(parent_bus)), - config: PciConfig::new(PCIE_CONFIG_SPACE_SIZE, cfg.bar_num), + config: PciConfig::new(devfn, PCIE_CONFIG_SPACE_SIZE, cfg.bar_num), devfn, }, cmd_cfg: cfg, diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs index ccac50e5..ccf1263a 100644 --- a/devices/src/pci/mod.rs +++ b/devices/src/pci/mod.rs @@ -411,7 +411,7 @@ mod tests { Self { base: PciDevBase { base: DeviceBase::new(name.to_string(), false, Some(parent_bus)), - config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 0), + config: PciConfig::new(devfn, PCI_CONFIG_SPACE_SIZE, 0), devfn, }, } diff --git a/devices/src/pci/msix.rs b/devices/src/pci/msix.rs index 70eb603d..7f960f44 100644 --- a/devices/src/pci/msix.rs +++ b/devices/src/pci/msix.rs @@ -646,7 +646,7 @@ mod tests { let root_bus = Arc::downgrade(&locked_pci_host.child_bus().unwrap()); let mut base = PciDevBase { base: DeviceBase::new("msix".to_string(), false, Some(root_bus)), - config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 2), + config: PciConfig::new(1, PCI_CONFIG_SPACE_SIZE, 2), devfn: 1, }; // Too many vectors. @@ -751,7 +751,7 @@ mod tests { let root_bus = Arc::downgrade(&locked_pci_host.child_bus().unwrap()); let mut base = PciDevBase { base: DeviceBase::new("msix".to_string(), false, Some(root_bus)), - config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 2), + config: PciConfig::new(1, PCI_CONFIG_SPACE_SIZE, 2), devfn: 1, }; init_msix(&mut base, 0, 2, Arc::new(AtomicU16::new(0)), None, None).unwrap(); diff --git a/devices/src/pci/root_port.rs b/devices/src/pci/root_port.rs index 0d854c08..00bffd49 100644 --- a/devices/src/pci/root_port.rs +++ b/devices/src/pci/root_port.rs @@ -126,7 +126,7 @@ impl RootPort { Self { base: PciDevBase { base: dev_base, - config: PciConfig::new(PCIE_CONFIG_SPACE_SIZE, 2), + config: PciConfig::new(devfn, PCIE_CONFIG_SPACE_SIZE, 2), devfn, }, port_num: cfg.port, diff --git a/devices/src/usb/xhci/xhci_pci.rs b/devices/src/usb/xhci/xhci_pci.rs index 07b2bb2b..602cf136 100644 --- a/devices/src/usb/xhci/xhci_pci.rs +++ b/devices/src/usb/xhci/xhci_pci.rs @@ -114,7 +114,7 @@ impl XhciPciDevice { Self { base: PciDevBase { base: DeviceBase::new(config.id.clone().unwrap(), true, Some(parent_bus)), - config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 1), + config: PciConfig::new(devfn, PCI_CONFIG_SPACE_SIZE, 1), devfn, }, xhci: XhciDevice::new(mem_space, config), diff --git a/machine/src/aarch64/pci_host_root.rs b/machine/src/aarch64/pci_host_root.rs index b3950f24..65ec778f 100644 --- a/machine/src/aarch64/pci_host_root.rs +++ b/machine/src/aarch64/pci_host_root.rs @@ -34,7 +34,7 @@ impl PciHostRoot { Self { base: PciDevBase { base: DeviceBase::new("PCI Host Root".to_string(), false, Some(parent_bus)), - config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 0), + config: PciConfig::new(0, PCI_CONFIG_SPACE_SIZE, 0), devfn: 0, }, } diff --git a/machine/src/x86_64/ich9_lpc.rs b/machine/src/x86_64/ich9_lpc.rs index bb9f0e8f..b27b8276 100644 --- a/machine/src/x86_64/ich9_lpc.rs +++ b/machine/src/x86_64/ich9_lpc.rs @@ -65,7 +65,7 @@ impl LPCBridge { Ok(Self { base: PciDevBase { base: DeviceBase::new("ICH9 LPC bridge".to_string(), false, Some(parent_bus)), - config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 0), + config: PciConfig::new(0x1F << 3, PCI_CONFIG_SPACE_SIZE, 0), devfn: 0x1F << 3, }, sys_io, diff --git a/machine/src/x86_64/mch.rs b/machine/src/x86_64/mch.rs index 0aec6ec8..13a47cdf 100644 --- a/machine/src/x86_64/mch.rs +++ b/machine/src/x86_64/mch.rs @@ -58,7 +58,7 @@ impl Mch { Self { base: PciDevBase { base: DeviceBase::new("Memory Controller Hub".to_string(), false, Some(parent_bus)), - config: PciConfig::new(PCI_CONFIG_SPACE_SIZE, 0), + config: PciConfig::new(0, PCI_CONFIG_SPACE_SIZE, 0), devfn: 0, }, mmconfig_region: Some(mmconfig_region), diff --git a/vfio/src/vfio_pci.rs b/vfio/src/vfio_pci.rs index d52ea581..5dad8163 100644 --- a/vfio/src/vfio_pci.rs +++ b/vfio/src/vfio_pci.rs @@ -133,7 +133,7 @@ impl VfioPciDevice { // Unknown PCI or PCIe type here, allocate enough space to match the two types. base: PciDevBase { base: DeviceBase::new(name, true, Some(parent_bus)), - config: PciConfig::new(PCIE_CONFIG_SPACE_SIZE, PCI_NUM_BARS), + config: PciConfig::new(devfn, PCIE_CONFIG_SPACE_SIZE, PCI_NUM_BARS), devfn, }, config_size: 0, @@ -185,7 +185,7 @@ impl VfioPciDevice { // Cache the pci config space to avoid overwriting the original config space. Because we // will parse the chain of extended caps in cache config and insert them into original // config space. - let mut config = PciConfig::new(PCIE_CONFIG_SPACE_SIZE, PCI_NUM_BARS); + let mut config = PciConfig::new(self.base.devfn, PCIE_CONFIG_SPACE_SIZE, PCI_NUM_BARS); config.config = config_data; let mut next = PCI_CONFIG_SPACE_SIZE; while (PCI_CONFIG_SPACE_SIZE..PCIE_CONFIG_SPACE_SIZE).contains(&next) { diff --git a/virtio/src/transport/virtio_pci.rs b/virtio/src/transport/virtio_pci.rs index ca392dde..149cb329 100644 --- a/virtio/src/transport/virtio_pci.rs +++ b/virtio/src/transport/virtio_pci.rs @@ -333,7 +333,7 @@ impl VirtioPciDevice { VirtioPciDevice { base: PciDevBase { base: DeviceBase::new(name, true, Some(parent_bus)), - config: PciConfig::new(PCIE_CONFIG_SPACE_SIZE, VIRTIO_PCI_BAR_MAX), + config: PciConfig::new(devfn, PCIE_CONFIG_SPACE_SIZE, VIRTIO_PCI_BAR_MAX), devfn, }, device, -- Gitee From 327cb7e790859b62a680bde5cb49aff090d8b1d7 Mon Sep 17 00:00:00 2001 From: Jinhao Gao Date: Thu, 8 Aug 2024 15:08:59 +0800 Subject: [PATCH 235/489] Trace: Delete the pci trace of updating bar mapping The information of updating bar mapping is logged. So don't need to trace. Signed-off-by: Jinhao Gao --- devices/src/pci/config.rs | 4 ++-- trace/trace_info/pci.toml | 12 ------------ 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/devices/src/pci/config.rs b/devices/src/pci/config.rs index 02858fe1..5228e337 100644 --- a/devices/src/pci/config.rs +++ b/devices/src/pci/config.rs @@ -912,7 +912,7 @@ impl PciConfig { "pci dev {} delete bar {} mapping: addr 0x{:X} size {}", self.devfn, id, self.bars[id].address, self.bars[id].size ); - trace::pci_update_mappings_del(id, self.bars[id].address, self.bars[id].size); + self.bars[id].address = BAR_SPACE_UNMAPPED; } @@ -950,7 +950,7 @@ impl PciConfig { "pci dev {} update bar {} mapping: addr 0x{:X} size {}", self.devfn, id, new_addr, self.bars[id].size ); - trace::pci_update_mappings_add(id, self.bars[id].address, self.bars[id].size); + self.bars[id].address = new_addr; } } diff --git a/trace/trace_info/pci.toml b/trace/trace_info/pci.toml index dfd7642f..be76599f 100644 --- a/trace/trace_info/pci.toml +++ b/trace/trace_info/pci.toml @@ -15,15 +15,3 @@ name = "msix_write_config" args = "dev_id: u16, masked: bool, enabled: bool" message = "dev id: {} masked: {} enabled: {}" enabled = true - -[[events]] -name = "pci_update_mappings_add" -args = "bar_id: usize, addr: u64, size: u64" -message = "bar id: {} addr: 0x{:#X} size: {}" -enabled = true - -[[events]] -name = "pci_update_mappings_del" -args = "bar_id: usize, addr: u64, size: u64" -message = "bar id: {} addr: 0x{:#X} size: {}" -enabled = true -- Gitee From 5343ce907eafc768f1b4a420c4551b09d201a04a Mon Sep 17 00:00:00 2001 From: zephyr Date: Thu, 8 Aug 2024 22:01:45 +0800 Subject: [PATCH 236/489] Ohaudio: pause play and record threads if vm paused Pause play and record threads if vm paused. --- devices/src/misc/scream/mod.rs | 46 ++++++++- devices/src/misc/scream/ohaudio.rs | 154 ++++++----------------------- 2 files changed, 76 insertions(+), 124 deletions(-) diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index c5e11e56..b0821164 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -20,7 +20,7 @@ mod pulseaudio; use std::str::FromStr; use std::sync::atomic::{fence, Ordering}; -use std::sync::{Arc, Mutex, RwLock, Weak}; +use std::sync::{Arc, Condvar, Mutex, RwLock, Weak}; use std::{mem, thread}; use anyhow::{anyhow, bail, Context, Result}; @@ -35,6 +35,7 @@ use super::ivshmem::Ivshmem; use crate::{Bus, Device}; use address_space::{GuestAddress, HostMemMapping, Region}; use machine_manager::config::{get_pci_df, parse_bool, valid_id}; +use machine_manager::notifier::register_vm_pause_notifier; #[cfg(all(target_env = "ohos", feature = "scream_ohaudio"))] use ohaudio::{OhAudio, OhAudioVolume}; #[cfg(feature = "scream_pulseaudio")] @@ -59,6 +60,17 @@ const POLL_DELAY_US: u64 = (TARGET_LATENCY_MS as u64) * 1000 / 8; pub const SCREAM_MAGIC: u64 = 0x02032023; +#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd)] +pub enum AudioStatus { + // Processor is ready and waiting for play/capture. + #[default] + Ready, + // Processor is started and doing job. + Started, + // OH audio framework error occurred. + Error, +} + /// The scream device defines the audio directions. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum ScreamDirection { @@ -191,6 +203,10 @@ pub struct StreamData { pub audio_size: u32, /// Location of the played or recorded audio data in the shared memory. pub audio_base: u64, + /// used for VM pause + cond: Arc, + paused: Arc>, + pause_notifier_id: u64, } impl StreamData { @@ -200,6 +216,27 @@ impl StreamData { self.chunk_idx = header.chunk_idx; } + #[inline(always)] + fn wait_if_paused(&mut self, interface: Arc>) { + let mut locked_pause = self.paused.lock().unwrap(); + while *locked_pause { + interface.lock().unwrap().destroy(); + locked_pause = self.cond.wait(locked_pause).unwrap(); + } + } + + fn register_pause_notifier(&mut self) { + let cond = self.cond.clone(); + let cond_pause = self.paused.clone(); + let pause_notify = Arc::new(move |paused: bool| { + *cond_pause.lock().unwrap() = paused; + if !paused { + cond.notify_all(); + } + }); + self.pause_notifier_id = register_vm_pause_notifier(pause_notify); + } + fn wait_for_ready( &mut self, interface: Arc>, @@ -221,6 +258,7 @@ impl StreamData { if header.magic != SCREAM_MAGIC || stream_header.is_started == 0 { interface.lock().unwrap().destroy(); while header.magic != SCREAM_MAGIC || stream_header.is_started == 0 { + self.wait_if_paused(interface.clone()); thread::sleep(time::Duration::from_millis(10)); header = // SAFETY: hva is allocated by libc:::mmap, it can be guaranteed to be legal. @@ -293,6 +331,8 @@ impl StreamData { let play = &header.play; loop { + self.wait_if_paused(interface.clone()); + if play.fmt.fmt_generation != self.fmt.fmt_generation { break; } @@ -337,6 +377,8 @@ impl StreamData { interface.lock().unwrap().pre_receive(addr, capt); while capt.is_started != 0 { + self.wait_if_paused(interface.clone()); + if !self.update_buffer_by_chunk_idx(hva, shmem_size, capt) { return; } @@ -483,6 +525,7 @@ impl Scream { .spawn(move || { let clone_interface = interface.clone(); let mut play_data = StreamData::default(); + play_data.register_pause_notifier(); loop { play_data.wait_for_ready( @@ -510,6 +553,7 @@ impl Scream { .spawn(move || { let clone_interface = interface.clone(); let mut capt_data = StreamData::default(); + capt_data.register_pause_notifier(); loop { capt_data.wait_for_ready( diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index c44d7067..cea3b21f 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -14,7 +14,7 @@ use std::collections::VecDeque; use std::os::raw::c_void; use std::sync::{ atomic::{fence, AtomicBool, AtomicI32, Ordering}, - Arc, Mutex, RwLock, + Arc, Mutex, }; use std::{ cmp, @@ -26,7 +26,9 @@ use std::{ use log::{error, info, warn}; use crate::misc::ivshmem::Ivshmem; -use crate::misc::scream::{AudioInterface, ScreamDirection, ShmemStreamHeader, StreamData}; +use crate::misc::scream::{ + AudioInterface, AudioStatus, ScreamDirection, ShmemStreamHeader, StreamData, +}; use crate::pci::{le_read_u32, le_write_u32}; use machine_manager::notifier::register_vm_pause_notifier; use util::ohos_binding::audio::*; @@ -162,26 +164,12 @@ impl StreamQueue { } } -#[derive(Copy, Clone, Default, PartialEq, PartialOrd)] -enum OhAudioStatus { - // Processor is ready and waiting for play/capture. - #[default] - Ready, - // Processor is started and doing job. - Started, - // Processor is paused. - Paused, - // OH audio framework error occurred. - Error, -} - struct OhAudioRender { ctx: Option, stream_data: Arc>, flushing: AtomicBool, - status: Arc>, + status: AudioStatus, last_called_time: Option, - pause_notifier_id: u64, } impl Default for OhAudioRender { @@ -190,9 +178,8 @@ impl Default for OhAudioRender { ctx: None, stream_data: Arc::new(Mutex::new(StreamQueue::new(STREAM_DATA_VEC_CAPACITY))), flushing: AtomicBool::new(false), - status: Arc::new(RwLock::new(OhAudioStatus::default())), + status: AudioStatus::default(), last_called_time: None, - pause_notifier_id: 0, } } } @@ -235,32 +222,6 @@ impl OhAudioRender { fn set_flushing(&mut self, flush: bool) { self.flushing.store(flush, Ordering::Release); } - - #[inline(always)] - fn get_status(&self) -> OhAudioStatus { - *self.status.read().unwrap() - } - - #[inline(always)] - fn set_status(&self, status: OhAudioStatus) { - *self.status.write().unwrap() = status; - } - - fn register_pause_notifier(&mut self) { - let status = self.status.clone(); - let pause_notify = Arc::new(move |paused: bool| { - let s = *status.read().unwrap(); - if paused { - if s == OhAudioStatus::Paused { - return; - } - *status.write().unwrap() = OhAudioStatus::Paused; - } else { - *status.write().unwrap() = OhAudioStatus::Error; - } - }); - self.pause_notifier_id = register_vm_pause_notifier(pause_notify); - } } impl OhAudioProcess for OhAudioRender { @@ -283,7 +244,7 @@ impl OhAudioProcess for OhAudioRender { } match self.ctx.as_ref().unwrap().start() { Ok(()) => { - self.set_status(OhAudioStatus::Started); + self.status = AudioStatus::Started; trace::oh_scream_render_init(&self.ctx); } Err(e) => { @@ -291,35 +252,27 @@ impl OhAudioProcess for OhAudioRender { } } self.last_called_time = None; - self.get_status() == OhAudioStatus::Started + self.status == AudioStatus::Started } fn destroy(&mut self) { - let status = self.get_status(); - - match status { - OhAudioStatus::Paused => return, - OhAudioStatus::Error => { - self.set_status(OhAudioStatus::Ready); + match self.status { + AudioStatus::Error => { self.ctx = None; + self.status = AudioStatus::Ready; return; } - OhAudioStatus::Started => self.flush(), + AudioStatus::Started => self.flush(), _ => {} } self.ctx = None; self.stream_data.lock().unwrap().clear(); self.set_flushing(false); - self.set_status(OhAudioStatus::Ready); + self.status = AudioStatus::Ready; trace::oh_scream_render_destroy(); } fn process(&mut self, recv_data: &StreamData) -> i32 { - let mut status = self.get_status(); - if status == OhAudioStatus::Paused { - return 0; - } - self.check_fmt_update(recv_data); fence(Ordering::Acquire); @@ -331,13 +284,12 @@ impl OhAudioProcess for OhAudioRender { recv_data.audio_size as usize, )); - if status == OhAudioStatus::Error { + if self.status == AudioStatus::Error { error!("Audio server error occurred. Destroy and reconnect it."); self.destroy(); - status = self.get_status(); } - if status == OhAudioStatus::Ready && !self.init(recv_data) { + if self.status == AudioStatus::Ready && !self.init(recv_data) { error!("failed to init oh audio"); self.destroy(); } @@ -353,9 +305,8 @@ struct OhAudioCapture { shm_addr: u64, shm_len: u64, cur_pos: u64, - status: Arc>, + status: AudioStatus, last_called_time: Option, - pause_notifier_id: u64, } impl OhAudioCapture { @@ -370,33 +321,6 @@ impl OhAudioCapture { self.destroy(); } } - - #[inline(always)] - fn get_status(&self) -> OhAudioStatus { - *self.status.write().unwrap() - } - - #[inline(always)] - fn set_status(&self, status: OhAudioStatus) { - *self.status.write().unwrap() = status; - } - - fn register_pause_notifier(&mut self) { - let status = self.status.clone(); - let pause_notify = Arc::new(move |paused: bool| { - let s = *status.read().unwrap(); - if paused { - if s == OhAudioStatus::Paused { - return; - } - *status.write().unwrap() = OhAudioStatus::Paused; - } else { - // Set error status to recreate capture context. - *status.write().unwrap() = OhAudioStatus::Error; - } - }); - self.pause_notifier_id = register_vm_pause_notifier(pause_notify); - } } impl OhAudioProcess for OhAudioCapture { @@ -418,7 +342,7 @@ impl OhAudioProcess for OhAudioCapture { match self.ctx.as_ref().unwrap().start() { Ok(()) => { self.last_called_time = None; - self.set_status(OhAudioStatus::Started); + self.status = AudioStatus::Started; trace::oh_scream_capture_init(&self.ctx); true } @@ -430,14 +354,8 @@ impl OhAudioProcess for OhAudioCapture { } fn destroy(&mut self) { - let status = self.get_status(); - match status { - OhAudioStatus::Paused => return, - _ => { - self.set_status(OhAudioStatus::Ready); - self.ctx = None; - } - } + self.status = AudioStatus::Ready; + self.ctx = None; trace::oh_scream_capture_destroy(); } @@ -450,27 +368,21 @@ impl OhAudioProcess for OhAudioCapture { } fn process(&mut self, recv_data: &StreamData) -> i32 { - let mut status = self.get_status(); - if status == OhAudioStatus::Paused { - return -1; - } self.check_fmt_update(recv_data); trace::trace_scope_start!(ohaudio_capturer_process, args = (recv_data)); - if status == OhAudioStatus::Error { + if self.status == AudioStatus::Error { self.destroy(); - status = self.get_status(); } - if status == OhAudioStatus::Ready && !self.init(recv_data) { + if self.status == AudioStatus::Ready && !self.init(recv_data) { self.destroy(); return -1; } self.new_chunks.store(0, Ordering::Release); while self.new_chunks.load(Ordering::Acquire) == 0 { - status = self.get_status(); - if status == OhAudioStatus::Paused || status == OhAudioStatus::Error { + if self.status == AudioStatus::Error { return -1; } thread::sleep(Duration::from_millis(10)); @@ -499,7 +411,7 @@ extern "C" fn on_write_data_cb( let elapsed = last.elapsed().as_millis(); if elapsed >= 1000 { warn!("{elapsed}ms elapsed after last on_write called. Will restart render."); - render.set_status(OhAudioStatus::Error); + render.status = AudioStatus::Error; return 0; } render.last_called_time = Some(Instant::now()); @@ -542,7 +454,7 @@ extern "C" fn on_read_data_cb( let elapsed = last.elapsed().as_millis(); if elapsed >= 1000 { warn!("{elapsed}ms elapsed after last on_read called. Will restart capture."); - capture.set_status(OhAudioStatus::Error); + capture.status = AudioStatus::Error; return 0; } capture.last_called_time = Some(Instant::now()); @@ -552,7 +464,7 @@ extern "C" fn on_read_data_cb( trace::trace_scope_start!(ohaudio_read_cb, args = (length)); loop { - if capture.get_status() != OhAudioStatus::Started { + if capture.status != AudioStatus::Started { return 0; } if capture.new_chunks.load(Ordering::Acquire) == 0 { @@ -602,16 +514,12 @@ unsafe impl Send for OhAudio {} impl OhAudio { pub fn init(dir: ScreamDirection) -> Self { match dir { - ScreamDirection::Playback => { - let mut processor = Box::::default(); - processor.register_pause_notifier(); - Self { processor } - } - ScreamDirection::Record => { - let mut processor = Box::::default(); - processor.register_pause_notifier(); - Self { processor } - } + ScreamDirection::Playback => Self { + processor: Box::::default(), + }, + ScreamDirection::Record => Self { + processor: Box::::default(), + }, } } } -- Gitee From 1b06e5f7e4c82da3e1a953b854d305af421f7cf6 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Fri, 9 Aug 2024 12:07:53 +0800 Subject: [PATCH 237/489] scream: introduce AudioExtension to support volume sync This patch introduces a new interface 'AudioExtension' to support volume sync. Scream only processes ivshmem bar0 read or write, and audio backend processes volume synchronization. Signed-off-by: Zhao Yi Min --- devices/src/misc/scream/mod.rs | 64 +++++++++++++++++++++++-- devices/src/misc/scream/ohaudio.rs | 77 ++++++++++-------------------- 2 files changed, 84 insertions(+), 57 deletions(-) diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index b0821164..88ce9e59 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -26,12 +26,13 @@ use std::{mem, thread}; use anyhow::{anyhow, bail, Context, Result}; use clap::{ArgAction, Parser}; use core::time; -use log::{error, warn}; +use log::{error, info, warn}; #[cfg(feature = "scream_alsa")] use self::alsa::AlsaStreamData; use self::audio_demo::AudioDemo; use super::ivshmem::Ivshmem; +use crate::pci::{le_read_u32, le_write_u32}; use crate::{Bus, Device}; use address_space::{GuestAddress, HostMemMapping, Region}; use machine_manager::config::{get_pci_df, parse_bool, valid_id}; @@ -50,7 +51,10 @@ pub const WINDOWS_SAMPLE_BASE_RATE: u8 = 128; pub const TARGET_LATENCY_MS: u32 = 50; +#[cfg(all(target_env = "ohos", feature = "scream_ohaudio"))] +const IVSHMEM_VOLUME_SYNC_VECTOR: u16 = 0; const IVSHMEM_VECTORS_NR: u32 = 1; +const IVSHMEM_BAR0_VOLUME: u64 = 240; // A frame of back-end audio data is 50ms, and the next frame of audio data needs // to be trained in polling within 50ms. Theoretically, the shorter the polling time, @@ -596,14 +600,52 @@ impl Scream { mem_region, IVSHMEM_VECTORS_NR, ); - let _ivshmem = ivshmem.realize()?; + let ivshmem = ivshmem.realize()?; - #[cfg(target_env = "ohos")] - OhAudioVolume::init_volume_sync(_ivshmem); + self.set_ivshmem_ops(ivshmem); self.start_play_thread_fn()?; self.start_record_thread_fn() } + + fn set_ivshmem_ops(&mut self, ivshmem: Arc>) { + let interface = self.create_audio_extension(ivshmem.clone()); + let interface2 = interface.clone(); + let bar0_write = Arc::new(move |data: &[u8], offset: u64| { + match offset { + IVSHMEM_BAR0_VOLUME => { + interface.set_host_volume(le_read_u32(data, 0).unwrap()); + } + _ => { + info!("ivshmem-scream: unsupported write: {offset}"); + } + } + true + }); + let bar0_read = Arc::new(move |data: &mut [u8], offset: u64| { + match offset { + IVSHMEM_BAR0_VOLUME => { + let _ = le_write_u32(data, 0, interface2.get_host_volume()); + } + _ => { + info!("ivshmem-scream: unsupported read: {offset}"); + } + } + true + }); + ivshmem + .lock() + .unwrap() + .set_bar0_ops((bar0_write, bar0_read)); + } + + fn create_audio_extension(&self, _ivshmem: Arc>) -> Arc { + match self.config.interface { + #[cfg(all(target_env = "ohos", feature = "scream_ohaudio"))] + ScreamInterface::OhAudio => OhAudioVolume::new(_ivshmem), + _ => Arc::new(AudioExtensionDummy {}), + } + } } pub trait AudioInterface: Send { @@ -614,3 +656,17 @@ pub trait AudioInterface: Send { fn receive(&mut self, recv_data: &StreamData) -> i32; fn destroy(&mut self); } + +pub trait AudioExtension: Send + Sync { + fn set_host_volume(&self, _vol: u32) {} + fn get_host_volume(&self) -> u32 { + 0 + } +} + +struct AudioExtensionDummy; +impl AudioExtension for AudioExtensionDummy {} +// SAFETY: it is a dummy +unsafe impl Send for AudioExtensionDummy {} +// SAFETY: it is a dummy +unsafe impl Sync for AudioExtensionDummy {} diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index cea3b21f..c275ea02 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -14,7 +14,7 @@ use std::collections::VecDeque; use std::os::raw::c_void; use std::sync::{ atomic::{fence, AtomicBool, AtomicI32, Ordering}, - Arc, Mutex, + Arc, Mutex, RwLock, }; use std::{ cmp, @@ -23,11 +23,12 @@ use std::{ time::{Duration, Instant}, }; -use log::{error, info, warn}; +use log::{error, warn}; use crate::misc::ivshmem::Ivshmem; use crate::misc::scream::{ - AudioInterface, AudioStatus, ScreamDirection, ShmemStreamHeader, StreamData, + AudioExtension, AudioInterface, AudioStatus, ScreamDirection, ShmemStreamHeader, StreamData, + IVSHMEM_VOLUME_SYNC_VECTOR, }; use crate::pci::{le_read_u32, le_write_u32}; use machine_manager::notifier::register_vm_pause_notifier; @@ -36,7 +37,6 @@ use util::ohos_binding::audio::*; const STREAM_DATA_VEC_CAPACITY: usize = 15; const FLUSH_DELAY_MS: u64 = 5; const FLUSH_DELAY_CNT: u64 = 200; -const IVSHMEM_BAR0_VOLUME: u64 = 240; trait OhAudioProcess { fn init(&mut self, stream: &StreamData) -> bool; @@ -547,10 +547,28 @@ pub struct OhAudioVolume { ohos_vol: RwLock, } +// SAFETY: all fields are protected by lock +unsafe impl Send for OhAudioVolume {} +// SAFETY: all fields are protected by lock +unsafe impl Sync for OhAudioVolume {} + impl GuestVolumeNotifier for OhAudioVolume { fn notify(&self, vol: u32) { *self.ohos_vol.write().unwrap() = vol; - self.shm_dev.lock().unwrap().trigger_msix(0); + self.shm_dev + .lock() + .unwrap() + .trigger_msix(IVSHMEM_VOLUME_SYNC_VECTOR); + } +} + +impl AudioExtension for OhAudioVolume { + fn get_host_volume(&self) -> u32 { + *self.ohos_vol.read().unwrap() + } + + fn set_host_volume(&self, vol: u32) { + set_ohos_volume(vol); } } @@ -558,58 +576,11 @@ impl OhAudioVolume { pub fn new(shm_dev: Arc>) -> Arc { let vol = Arc::new(Self { shm_dev, - ohos_vol: RwLock::new(0), + ohos_vol: RwLock::new(get_ohos_volume()), }); register_guest_volume_notifier(vol.clone()); vol } - - fn set_volume(&self, vol: u32) { - set_ohos_volume(vol); - } - - fn get_volume(&self) -> u32 { - *self.ohos_vol.read().unwrap() - } - - fn init_volume(&self) { - *self.ohos_vol.write().unwrap() = get_ohos_volume(); - } - - pub fn init_volume_sync(ivshmem: Arc>) { - let ohvol = OhAudioVolume::new(ivshmem.clone()); - let ohvol2 = ohvol.clone(); - ohvol.init_volume(); - let bar0_write = Arc::new(move |data: &[u8], offset: u64| { - match offset { - IVSHMEM_BAR0_VOLUME => match le_read_u32(data, 0) { - Ok(v) => ohvol.set_volume(v), - Err(e) => error!("ohaudio le_read_u32 failed: {e}"), - }, - _ => { - info!("ivshmem-scream on ohaudio: unsupported write:{offset}"); - } - } - true - }); - let bar0_read = Arc::new(move |data: &mut [u8], offset: u64| { - match offset { - IVSHMEM_BAR0_VOLUME => { - if let Err(e) = le_write_u32(data, 0, ohvol2.get_volume()) { - error!("ohaudio le_write_u32 failed: {e}"); - } - } - _ => { - info!("ivshmem-scream on ohaudio: unsupported read:{offset}"); - } - } - true - }); - ivshmem - .lock() - .unwrap() - .set_bar0_ops((bar0_write, bar0_read)); - } } #[cfg(test)] -- Gitee From f33aca3d7c1f412ba85c40dc10dccec9d4a6321c Mon Sep 17 00:00:00 2001 From: zephyr Date: Thu, 11 Jul 2024 14:09:57 +0800 Subject: [PATCH 238/489] Query_state: add state_query module to enable state query from a qmp command A new module state_query is introduced to allow other modules to register state query callback functions in this module, and then use the newly introduced qmp command to perform status queries of different modules. --- machine/src/standard_common/mod.rs | 17 +++++++ machine_manager/src/lib.rs | 1 + machine_manager/src/machine.rs | 8 ++++ machine_manager/src/qmp/qmp_schema.rs | 18 ++++++- machine_manager/src/qmp/qmp_socket.rs | 3 +- machine_manager/src/state_query.rs | 69 +++++++++++++++++++++++++++ 6 files changed, 114 insertions(+), 2 deletions(-) create mode 100644 machine_manager/src/state_query.rs diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index ebf86b18..4af265d9 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -25,6 +25,7 @@ use std::u64; use anyhow::{bail, Context, Result}; use log::{error, warn}; +use serde_json::json; use util::set_termi_canon_mode; use vmm_sys_util::epoll::EventSet; use vmm_sys_util::eventfd::EventFd; @@ -73,6 +74,7 @@ use machine_manager::machine::{ }; use machine_manager::qmp::qmp_schema::{BlockDevAddArgument, UpdateRegionArgument}; use machine_manager::qmp::{qmp_channel::QmpChannel, qmp_response::Response, qmp_schema}; +use machine_manager::state_query::query_workloads; #[cfg(feature = "gtk")] use ui::gtk::qmp_query_display_image; use ui::input::{input_button, input_move_abs, input_point_sync, key_event, Axis}; @@ -2029,6 +2031,21 @@ impl DeviceInterface for StdMachine { ), } } + + fn query_workloads(&self) -> Response { + let workloads = query_workloads(); + + if !workloads.is_empty() { + let status = workloads + .iter() + .map(|(module, state)| json!({ "module": module, "state": state })) + .collect(); + + Response::create_response(serde_json::Value::Array(status), None) + } else { + Response::create_empty_response() + } + } } fn parse_blockdev(args: &BlockDevAddArgument) -> Result { diff --git a/machine_manager/src/lib.rs b/machine_manager/src/lib.rs index b1475fce..cab6b880 100644 --- a/machine_manager/src/lib.rs +++ b/machine_manager/src/lib.rs @@ -30,6 +30,7 @@ pub mod notifier; pub mod qmp; pub mod signal_handler; pub mod socket; +pub mod state_query; pub mod temp_cleaner; pub mod test_server; diff --git a/machine_manager/src/machine.rs b/machine_manager/src/machine.rs index a040d6ef..bc4a38ec 100644 --- a/machine_manager/src/machine.rs +++ b/machine_manager/src/machine.rs @@ -237,6 +237,14 @@ pub trait DeviceInterface { /// Query display of stratovirt. fn query_display_image(&self) -> Response; + /// Query state. + fn query_workloads(&self) -> Response { + Response::create_error_response( + QmpErrorClass::GenericError("query_workloads not supported for VM".to_string()), + None, + ) + } + /// Set balloon's size. fn balloon(&self, size: u64) -> Response; diff --git a/machine_manager/src/qmp/qmp_schema.rs b/machine_manager/src/qmp/qmp_schema.rs index 4281624f..d520bd6a 100644 --- a/machine_manager/src/qmp/qmp_schema.rs +++ b/machine_manager/src/qmp/qmp_schema.rs @@ -137,7 +137,8 @@ define_qmp_command_enum!( blockdev_snapshot_delete_internal_sync("blockdev-snapshot-delete-internal-sync", blockdev_snapshot_internal, FALSE), query_vcpu_reg("query-vcpu-reg", query_vcpu_reg, FALSE), trace_get_state("trace-get-state", trace_get_state, FALSE), - trace_set_state("trace-set-state", trace_set_state, FALSE) + trace_set_state("trace-set-state", trace_set_state, FALSE), + query_workloads("query-workloads", query_workloads, FALSE) ); /// Command trait for Deserialize and find back Response. @@ -1986,6 +1987,21 @@ pub struct trace_set_state { } pub type TraceSetArgument = trace_set_state; +/// query_workloads +/// +/// Query the current workloads of the running VM. +/// +/// # Examples +/// +/// ```text +/// -> {"execute": "query-workloads", "arguments": {}} +/// <- {"return":[{"module":"scream-play","state":"Off"},{"module":"tap-0","state":"upload: 0 download: 0"}]} +/// ``` +#[derive(Default, Debug, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct query_workloads {} +generate_command_impl!(query_workloads, Empty); + #[cfg(test)] mod tests { use super::*; diff --git a/machine_manager/src/qmp/qmp_socket.rs b/machine_manager/src/qmp/qmp_socket.rs index 8326e7cd..24993aa2 100644 --- a/machine_manager/src/qmp/qmp_socket.rs +++ b/machine_manager/src/qmp/qmp_socket.rs @@ -466,7 +466,8 @@ fn qmp_command_exec( (query_vnc, query_vnc), (query_display_image, query_display_image), (list_type, list_type), - (query_hotpluggable_cpus, query_hotpluggable_cpus); + (query_hotpluggable_cpus, query_hotpluggable_cpus), + (query_workloads, query_workloads); (input_event, input_event, key, value), (device_list_properties, device_list_properties, typename), (device_del, device_del, id), diff --git a/machine_manager/src/state_query.rs b/machine_manager/src/state_query.rs new file mode 100644 index 00000000..e5c0dd9f --- /dev/null +++ b/machine_manager/src/state_query.rs @@ -0,0 +1,69 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::collections::HashMap; +use std::sync::{Arc, RwLock}; + +use log::error; +use once_cell::sync::Lazy; + +static STATE_QUERY_MANAGER: Lazy> = + Lazy::new(|| RwLock::new(StateQueryManager::new())); + +pub type StateQueryCallback = dyn Fn() -> String + Send + Sync; + +struct StateQueryManager { + query_callbacks: HashMap>, +} + +impl StateQueryManager { + fn new() -> Self { + Self { + query_callbacks: HashMap::new(), + } + } + + fn register_query_callback(&mut self, key: String, callback: Arc) { + self.query_callbacks.insert(key, callback); + } + + fn unregister_query_callback(&mut self, key: &str) { + if self.query_callbacks.remove(key).is_none() { + error!("There is no query callback with key {}", key); + } + } + + fn query_workloads(&self) -> Vec<(String, String)> { + self.query_callbacks + .iter() + .map(|(module, query)| (module.clone(), query())) + .collect() + } +} + +pub fn register_state_query_callback(key: String, callback: Arc) { + STATE_QUERY_MANAGER + .write() + .unwrap() + .register_query_callback(key, callback); +} + +pub fn unregister_state_query_callback(key: &str) { + STATE_QUERY_MANAGER + .write() + .unwrap() + .unregister_query_callback(key); +} + +pub fn query_workloads() -> Vec<(String, String)> { + STATE_QUERY_MANAGER.read().unwrap().query_workloads() +} -- Gitee From 4e26a97d7df8b45f2f6e466308c0bef6f732790e Mon Sep 17 00:00:00 2001 From: zephyr Date: Fri, 9 Aug 2024 09:38:41 +0800 Subject: [PATCH 239/489] Scream: add a get_status function for trait AudioInterface Add a get_status function for trait AudioInterface so as to facilitate queries in other modules. --- devices/src/misc/scream/alsa.rs | 12 ++++++++++-- devices/src/misc/scream/audio_demo.rs | 6 +++++- devices/src/misc/scream/mod.rs | 1 + devices/src/misc/scream/ohaudio.rs | 13 +++++++++++++ devices/src/misc/scream/pulseaudio.rs | 16 ++++++++++++---- 5 files changed, 41 insertions(+), 7 deletions(-) diff --git a/devices/src/misc/scream/alsa.rs b/devices/src/misc/scream/alsa.rs index e3ca324c..7daaee0f 100644 --- a/devices/src/misc/scream/alsa.rs +++ b/devices/src/misc/scream/alsa.rs @@ -24,8 +24,8 @@ use anyhow::Result; use log::{debug, error, warn}; use super::{ - AudioInterface, ScreamDirection, ShmemStreamFmt, StreamData, AUDIO_SAMPLE_RATE_44KHZ, - TARGET_LATENCY_MS, + AudioInterface, AudioStatus, ScreamDirection, ShmemStreamFmt, StreamData, + AUDIO_SAMPLE_RATE_44KHZ, TARGET_LATENCY_MS, }; const MAX_CHANNELS: u8 = 8; @@ -283,4 +283,12 @@ impl AudioInterface for AlsaStreamData { self.init = false; } + + fn get_status(&self) -> AudioStatus { + if self.init { + AudioStatus::Started + } else { + AudioStatus::Ready + } + } } diff --git a/devices/src/misc/scream/audio_demo.rs b/devices/src/misc/scream/audio_demo.rs index d22b7bc3..3576c43f 100644 --- a/devices/src/misc/scream/audio_demo.rs +++ b/devices/src/misc/scream/audio_demo.rs @@ -19,7 +19,7 @@ use std::{ use core::time; use log::error; -use super::{AudioInterface, ScreamDirection, StreamData}; +use super::{AudioInterface, AudioStatus, ScreamDirection, StreamData}; pub struct AudioDemo { file: File, @@ -86,4 +86,8 @@ impl AudioInterface for AudioDemo { } fn destroy(&mut self) {} + + fn get_status(&self) -> AudioStatus { + AudioStatus::Started + } } diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index 88ce9e59..468bf8fa 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -655,6 +655,7 @@ pub trait AudioInterface: Send { fn pre_receive(&mut self, start_addr: u64, sh_header: &ShmemStreamHeader) {} fn receive(&mut self, recv_data: &StreamData) -> i32; fn destroy(&mut self); + fn get_status(&self) -> AudioStatus; } pub trait AudioExtension: Send + Sync { diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index c275ea02..0dcfd271 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -43,6 +43,7 @@ trait OhAudioProcess { fn destroy(&mut self); fn preprocess(&mut self, _start_addr: u64, _sh_header: &ShmemStreamHeader) {} fn process(&mut self, recv_data: &StreamData) -> i32; + fn get_status(&self) -> AudioStatus; } #[derive(Debug, Clone, Copy)] @@ -295,6 +296,10 @@ impl OhAudioProcess for OhAudioRender { } 0 } + + fn get_status(&self) -> AudioStatus { + self.status + } } #[derive(Default)] @@ -390,6 +395,10 @@ impl OhAudioProcess for OhAudioCapture { self.new_chunks.load(Ordering::Acquire) } + + fn get_status(&self) -> AudioStatus { + self.status + } } extern "C" fn on_write_data_cb( @@ -540,6 +549,10 @@ impl AudioInterface for OhAudio { fn destroy(&mut self) { self.processor.destroy(); } + + fn get_status(&self) -> AudioStatus { + self.processor.get_status() + } } pub struct OhAudioVolume { diff --git a/devices/src/misc/scream/pulseaudio.rs b/devices/src/misc/scream/pulseaudio.rs index c42fabac..2e90bfbb 100644 --- a/devices/src/misc/scream/pulseaudio.rs +++ b/devices/src/misc/scream/pulseaudio.rs @@ -22,7 +22,7 @@ use pulse::{ time::MicroSeconds, }; -use super::{AudioInterface, AUDIO_SAMPLE_RATE_44KHZ}; +use super::{AudioInterface, AudioStatus, AUDIO_SAMPLE_RATE_44KHZ}; use crate::misc::scream::{ScreamDirection, ShmemStreamFmt, StreamData, TARGET_LATENCY_MS}; const MAX_LATENCY_MS: u32 = 100; @@ -215,9 +215,9 @@ impl PulseStreamData { .map_or_else( |_| { warn!( - "Unable to open PulseAudio with sample rate {}, sample size {} and channels {}", - self.ss.rate, recv_data.fmt.size, recv_data.fmt.channels - ); + "Unable to open PulseAudio with sample rate {}, sample size {} and channels {}", + self.ss.rate, recv_data.fmt.size, recv_data.fmt.channels + ); None }, Some, @@ -289,6 +289,14 @@ impl AudioInterface for PulseStreamData { } self.simple = None; } + + fn get_status(&self) -> AudioStatus { + if self.simple.is_some() { + AudioStatus::Started + } else { + AudioStatus::Ready + } + } } #[cfg(test)] -- Gitee From 2b0ad4eac24af30d1d8fab41a7ad008883123df3 Mon Sep 17 00:00:00 2001 From: zephyr Date: Thu, 8 Aug 2024 14:18:11 +0800 Subject: [PATCH 240/489] Scream: register a state query callback function A callback function for query scream status is registered in STATE_QUERY_MANAGER. --- devices/src/misc/scream/mod.rs | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index 468bf8fa..a273e6e7 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -37,6 +37,7 @@ use crate::{Bus, Device}; use address_space::{GuestAddress, HostMemMapping, Region}; use machine_manager::config::{get_pci_df, parse_bool, valid_id}; use machine_manager::notifier::register_vm_pause_notifier; +use machine_manager::state_query::register_state_query_callback; #[cfg(all(target_env = "ohos", feature = "scream_ohaudio"))] use ohaudio::{OhAudio, OhAudioVolume}; #[cfg(feature = "scream_pulseaudio")] @@ -524,6 +525,8 @@ impl Scream { let shmem_size = self.size; let interface = self.interface_init("ScreamPlay", ScreamDirection::Playback); self.interface_resource.push(interface.clone()); + let cloned_interface = interface.clone(); + self.register_state_query("scream-play".to_string(), cloned_interface); thread::Builder::new() .name("scream audio play worker".to_string()) .spawn(move || { @@ -552,6 +555,8 @@ impl Scream { let interface = self.interface_init("ScreamCapt", ScreamDirection::Record); let _ti = self.token_id.clone(); self.interface_resource.push(interface.clone()); + let cloned_interface = interface.clone(); + self.register_state_query("scream-record".to_string(), cloned_interface); thread::Builder::new() .name("scream audio capt worker".to_string()) .spawn(move || { @@ -579,6 +584,16 @@ impl Scream { Ok(()) } + fn register_state_query(&self, module: String, interface: Arc>) { + register_state_query_callback( + module, + Arc::new(move || match interface.lock().unwrap().get_status() { + AudioStatus::Started => "On".to_string(), + _ => "Off".to_string(), + }), + ); + } + pub fn realize(&mut self, parent_bus: Weak>) -> Result<()> { let host_mmap = Arc::new(HostMemMapping::new( GuestAddress(0), -- Gitee From a37d176084337c56f87c766c3938289c0e2d6400 Mon Sep 17 00:00:00 2001 From: zephyr Date: Tue, 30 Jul 2024 09:17:38 +0800 Subject: [PATCH 241/489] Net: add upload and download count, and register a state query callback function A upload count and a download count are added to Tap to record the net use status, and the callback function for query status is registered in virtio-net module through STATE_QUERY_MANAGER. --- docs/qmp.md | 11 +++++++++++ util/src/tap.rs | 14 +++++++++++++- virtio/src/device/net.rs | 33 +++++++++++++++++++++++++++++++++ 3 files changed, 57 insertions(+), 1 deletion(-) diff --git a/docs/qmp.md b/docs/qmp.md index e4837f58..5e5e25e9 100644 --- a/docs/qmp.md +++ b/docs/qmp.md @@ -534,6 +534,17 @@ Query the display image of virtiogpu. Currently only stdvm and gtk supports. <- { "return": { "fileDir": "/tmp/stratovirt-images", "isSuccess": true } } ``` +### query-workloads + +Query the workloads of the vm. + +#### Example + +```json +-> {"execute": "query-workloads", "arguments": {}} +<- {"return":[{"module":"scream-play","state":"Off"},{"module":"tap-0","state":"upload: 0 download: 0"}]} +``` + ### trace-get-state Query whether the trace state is enabled. diff --git a/util/src/tap.rs b/util/src/tap.rs index 1c8039cf..462de289 100644 --- a/util/src/tap.rs +++ b/util/src/tap.rs @@ -14,7 +14,10 @@ use std::fs::{File, OpenOptions}; use std::io::{ErrorKind, Read, Result as IoResult, Write}; use std::os::unix::fs::OpenOptionsExt; use std::os::unix::io::{AsRawFd, FromRawFd, RawFd}; -use std::sync::Arc; +use std::sync::{ + atomic::{AtomicU64, Ordering}, + Arc, +}; use anyhow::{anyhow, bail, Context, Result}; use log::error; @@ -57,6 +60,8 @@ pub struct IfReq { pub struct Tap { pub file: Arc, pub enabled: bool, + pub upload_stats: Arc, + pub download_stats: Arc, } impl Tap { @@ -127,6 +132,8 @@ impl Tap { Ok(Tap { file: Arc::new(file), enabled: true, + upload_stats: Arc::new(AtomicU64::new(0)), + download_stats: Arc::new(AtomicU64::new(0)), }) } @@ -214,6 +221,8 @@ impl Tap { } } error!("Failed to call readv for net handle_rx: {:?}", e); + } else { + self.download_stats.fetch_add(size as u64, Ordering::SeqCst); } size @@ -237,7 +246,10 @@ impl Tap { // Ignore other errors which can not be handled. _ => error!("Failed to call writev for net handle_tx: {:?}", e), } + } else { + self.upload_stats.fetch_add(size as u64, Ordering::SeqCst); } + break; } 0_i8 diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index 407bf67f..689e9c59 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -46,6 +46,9 @@ use crate::{ use address_space::AddressSpace; use machine_manager::config::{ConfigCheck, NetDevcfg, NetworkInterfaceConfig}; use machine_manager::event_loop::{register_event_helper, unregister_event_helper, EventLoop}; +use machine_manager::state_query::{ + register_state_query_callback, unregister_state_query_callback, +}; use migration::{ migration::Migratable, DeviceStateDesc, FieldDesc, MigrationHook, MigrationManager, StateTransfer, @@ -1462,6 +1465,21 @@ impl VirtioDevice for Net { self.taps = None; } + if let Some(ref taps) = self.taps { + for (idx, tap) in taps.iter().enumerate() { + let upload_stats = tap.upload_stats.clone(); + let download_stats = tap.download_stats.clone(); + register_state_query_callback( + format!("tap-{}", idx), + Arc::new(move || { + let upload = upload_stats.load(Ordering::SeqCst); + let download = download_stats.load(Ordering::SeqCst); + format!("upload: {} download: {}", upload, download) + }), + ) + } + } + self.init_config_features()?; Ok(()) @@ -1521,6 +1539,11 @@ impl VirtioDevice for Net { } fn unrealize(&mut self) -> Result<()> { + if let Some(ref taps) = self.taps { + for (idx, _) in taps.iter().enumerate() { + unregister_state_query_callback(&format!("tap-{}", idx)); + } + } mark_mac_table(&self.config_space.lock().unwrap().mac, false); MigrationManager::unregister_device_instance( VirtioNetState::descriptor(), @@ -1734,6 +1757,16 @@ impl VirtioDevice for Net { self.ctrl_info = None; Ok(()) } + + fn reset(&mut self) -> Result<()> { + if let Some(ref mut taps) = self.taps { + for tap in taps.iter_mut() { + tap.download_stats.store(0, Ordering::SeqCst); + tap.upload_stats.store(0, Ordering::SeqCst); + } + } + Ok(()) + } } // SAFETY: Send and Sync is not auto-implemented for `Sender` type. -- Gitee From 7fdb96286d74c180d0d84b8bb98b7e4eeb259cca Mon Sep 17 00:00:00 2001 From: zephyr Date: Fri, 9 Aug 2024 18:14:23 +0800 Subject: [PATCH 242/489] Ohaudio: remove unused imports Remove unused 'le_read_u32', 'le_write_u32' and 'register_vm_pause_notifier' imports. --- devices/src/misc/scream/ohaudio.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index 0dcfd271..a378d39e 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -30,8 +30,6 @@ use crate::misc::scream::{ AudioExtension, AudioInterface, AudioStatus, ScreamDirection, ShmemStreamHeader, StreamData, IVSHMEM_VOLUME_SYNC_VECTOR, }; -use crate::pci::{le_read_u32, le_write_u32}; -use machine_manager::notifier::register_vm_pause_notifier; use util::ohos_binding::audio::*; const STREAM_DATA_VEC_CAPACITY: usize = 15; -- Gitee From 76a1a07cce73a6ee4599fc3e10961960b0a0df36 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Sat, 10 Aug 2024 18:20:49 +0800 Subject: [PATCH 243/489] scream: enable low latency mode Let's enable low latency mode to decrease sound delay. Signed-off-by: Zhao Yi Min --- util/src/ohos_binding/audio/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/util/src/ohos_binding/audio/mod.rs b/util/src/ohos_binding/audio/mod.rs index e67bf4e4..1a1b600a 100755 --- a/util/src/ohos_binding/audio/mod.rs +++ b/util/src/ohos_binding/audio/mod.rs @@ -249,7 +249,6 @@ impl AudioContext { )) } - #[allow(unused)] fn set_latency_mode(&self) -> Result<(), OAErr> { call_capi!(OH_AudioStreamBuilder_SetLatencyMode( self.builder, @@ -332,6 +331,7 @@ impl AudioContext { self.set_fmt(size, rate, channels)?; self.set_sample_rate()?; self.set_sample_format()?; + self.set_latency_mode()?; self.create_processor(cb) } -- Gitee From 2e67f1f261432920b8b67ec0e221225eed355996 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Mon, 12 Aug 2024 14:50:26 +0800 Subject: [PATCH 244/489] ohaudio: remove unuseful code OH audio framework has fixed up the issue so we don't need to check last call time. Signed-off-by: Zhao Yi Min --- devices/src/misc/scream/ohaudio.rs | 40 ++---------------------------- 1 file changed, 2 insertions(+), 38 deletions(-) diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index a378d39e..5b03c188 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -16,14 +16,9 @@ use std::sync::{ atomic::{fence, AtomicBool, AtomicI32, Ordering}, Arc, Mutex, RwLock, }; -use std::{ - cmp, - io::Read, - ptr, thread, - time::{Duration, Instant}, -}; +use std::{cmp, io::Read, ptr, thread, time::Duration}; -use log::{error, warn}; +use log::error; use crate::misc::ivshmem::Ivshmem; use crate::misc::scream::{ @@ -168,7 +163,6 @@ struct OhAudioRender { stream_data: Arc>, flushing: AtomicBool, status: AudioStatus, - last_called_time: Option, } impl Default for OhAudioRender { @@ -178,7 +172,6 @@ impl Default for OhAudioRender { stream_data: Arc::new(Mutex::new(StreamQueue::new(STREAM_DATA_VEC_CAPACITY))), flushing: AtomicBool::new(false), status: AudioStatus::default(), - last_called_time: None, } } } @@ -250,7 +243,6 @@ impl OhAudioProcess for OhAudioRender { error!("failed to start oh audio renderer: {}", e); } } - self.last_called_time = None; self.status == AudioStatus::Started } @@ -309,7 +301,6 @@ struct OhAudioCapture { shm_len: u64, cur_pos: u64, status: AudioStatus, - last_called_time: Option, } impl OhAudioCapture { @@ -344,7 +335,6 @@ impl OhAudioProcess for OhAudioCapture { } match self.ctx.as_ref().unwrap().start() { Ok(()) => { - self.last_called_time = None; self.status = AudioStatus::Started; trace::oh_scream_capture_init(&self.ctx); true @@ -412,19 +402,6 @@ extern "C" fn on_write_data_cb( .unwrap_unchecked() }; - match &render.last_called_time { - None => render.last_called_time = Some(Instant::now()), - Some(last) => { - let elapsed = last.elapsed().as_millis(); - if elapsed >= 1000 { - warn!("{elapsed}ms elapsed after last on_write called. Will restart render."); - render.status = AudioStatus::Error; - return 0; - } - render.last_called_time = Some(Instant::now()); - } - } - let len = length as usize; // SAFETY: the buffer is guaranteed by OH audio framework. let wbuf = unsafe { std::slice::from_raw_parts_mut(buffer as *mut u8, len) }; @@ -455,19 +432,6 @@ extern "C" fn on_read_data_cb( .unwrap_unchecked() }; - match &capture.last_called_time { - None => capture.last_called_time = Some(Instant::now()), - Some(last) => { - let elapsed = last.elapsed().as_millis(); - if elapsed >= 1000 { - warn!("{elapsed}ms elapsed after last on_read called. Will restart capture."); - capture.status = AudioStatus::Error; - return 0; - } - capture.last_called_time = Some(Instant::now()); - } - } - trace::trace_scope_start!(ohaudio_read_cb, args = (length)); loop { -- Gitee From 01d49e801e8e525bfff24fcec79ba9c6dbadc0f5 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Mon, 12 Aug 2024 15:59:00 +0800 Subject: [PATCH 245/489] scream: notify starting work via mmio trap This patch introduces a new field in bar0 to let the guest notify the backend to start processing audio stream. The patch also adds a new struct to process conditional value with two bits, 0x1 indicating play or capture, 0x2 bit indicating start or stop. Signed-off-by: Zhao Yi Min --- devices/src/misc/scream/mod.rs | 153 ++++++++++++++++++++++----------- 1 file changed, 101 insertions(+), 52 deletions(-) diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index a273e6e7..fe55fda8 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -56,6 +56,10 @@ pub const TARGET_LATENCY_MS: u32 = 50; const IVSHMEM_VOLUME_SYNC_VECTOR: u16 = 0; const IVSHMEM_VECTORS_NR: u32 = 1; const IVSHMEM_BAR0_VOLUME: u64 = 240; +const IVSHMEM_BAR0_STATUS: u64 = 244; + +const STATUS_PLAY_BIT: u32 = 0x1; +const STATUS_START_BIT: u32 = 0x2; // A frame of back-end audio data is 50ms, and the next frame of audio data needs // to be trained in polling within 50ms. Theoretically, the shorter the polling time, @@ -199,6 +203,51 @@ impl ShmemStreamFmt { } } +struct ScreamCond { + cond: Condvar, + paused: Mutex, +} + +impl ScreamCond { + const STREAM_PAUSE_BIT: u8 = 0x1; + const VM_PAUSE_BIT: u8 = 0x2; + + fn new() -> Arc { + Arc::new(Self { + cond: Condvar::default(), + paused: Mutex::new(Self::STREAM_PAUSE_BIT), + }) + } + + fn wait_if_paused(&self, interface: Arc>) { + let mut locked_pause = self.paused.lock().unwrap(); + while *locked_pause != 0 { + interface.lock().unwrap().destroy(); + locked_pause = self.cond.wait(locked_pause).unwrap(); + } + } + + fn set_value(&self, bv: u8, set: bool) { + let mut locked_pause = self.paused.lock().unwrap(); + let old_val = *locked_pause; + match set { + true => *locked_pause = old_val | bv, + false => *locked_pause = old_val & !bv, + } + if *locked_pause == 0 { + self.cond.notify_all(); + } + } + + fn set_vm_pause(&self, paused: bool) { + self.set_value(Self::VM_PAUSE_BIT, paused); + } + + fn set_stream_pause(&self, paused: bool) { + self.set_value(Self::STREAM_PAUSE_BIT, paused); + } +} + /// Audio stream data structure. #[derive(Debug, Default)] pub struct StreamData { @@ -208,9 +257,7 @@ pub struct StreamData { pub audio_size: u32, /// Location of the played or recorded audio data in the shared memory. pub audio_base: u64, - /// used for VM pause - cond: Arc, - paused: Arc>, + /// VM pause notifier id. pause_notifier_id: u64, } @@ -221,23 +268,9 @@ impl StreamData { self.chunk_idx = header.chunk_idx; } - #[inline(always)] - fn wait_if_paused(&mut self, interface: Arc>) { - let mut locked_pause = self.paused.lock().unwrap(); - while *locked_pause { - interface.lock().unwrap().destroy(); - locked_pause = self.cond.wait(locked_pause).unwrap(); - } - } - - fn register_pause_notifier(&mut self) { - let cond = self.cond.clone(); - let cond_pause = self.paused.clone(); + fn register_pause_notifier(&mut self, cond: Arc) { let pause_notify = Arc::new(move |paused: bool| { - *cond_pause.lock().unwrap() = paused; - if !paused { - cond.notify_all(); - } + cond.set_vm_pause(paused); }); self.pause_notifier_id = register_vm_pause_notifier(pause_notify); } @@ -246,8 +279,8 @@ impl StreamData { &mut self, interface: Arc>, dir: ScreamDirection, - poll_delay_us: u64, hva: u64, + cond: Arc, ) { // SAFETY: hva is the shared memory base address. It already verifies the validity // of the address range during the scream realize. @@ -257,27 +290,24 @@ impl StreamData { ScreamDirection::Playback => &header.play, ScreamDirection::Record => &header.capt, }; - trace::scream_init(&dir, &stream_header); loop { - if header.magic != SCREAM_MAGIC || stream_header.is_started == 0 { + let mut locked_paused = cond.paused.lock().unwrap(); + while *locked_paused != 0 { interface.lock().unwrap().destroy(); - while header.magic != SCREAM_MAGIC || stream_header.is_started == 0 { - self.wait_if_paused(interface.clone()); - thread::sleep(time::Duration::from_millis(10)); - header = - // SAFETY: hva is allocated by libc:::mmap, it can be guaranteed to be legal. - &unsafe { std::slice::from_raw_parts(hva as *const ShmemHeader, 1) }[0]; - } - self.init(stream_header); + locked_paused = cond.cond.wait(locked_paused).unwrap(); } - // Audio playback requires waiting for the guest to play audio data. - if dir == ScreamDirection::Playback && self.chunk_idx == stream_header.chunk_idx { - thread::sleep(time::Duration::from_micros(poll_delay_us)); + if header.magic != SCREAM_MAGIC || stream_header.is_started == 0 { + *locked_paused |= ScreamCond::STREAM_PAUSE_BIT; continue; } + header = + // SAFETY: hva is allocated by libc:::mmap, it can be guaranteed to be legal. + &unsafe { std::slice::from_raw_parts(hva as *const ShmemHeader, 1) }[0]; + self.init(stream_header); + let mut last_end = 0; // The recording buffer is behind the playback buffer. Thereforce, the end position of // the playback buffer must be calculted to determine whether the two buffers overlap. @@ -287,14 +317,11 @@ impl StreamData { } if !stream_header.check(last_end) { + *locked_paused |= ScreamCond::STREAM_PAUSE_BIT; continue; } - // Guest reformats the audio, and the scream device also needs to be init. - if self.fmt != stream_header.fmt { - self.init(stream_header); - continue; - } + trace::scream_init(&dir, &stream_header); return; } @@ -329,6 +356,7 @@ impl StreamData { hva: u64, shmem_size: u64, interface: Arc>, + cond: Arc, ) { // SAFETY: hva is the shared memory base address. It already verifies the validity // of the address range during the header check. @@ -336,7 +364,7 @@ impl StreamData { let play = &header.play; loop { - self.wait_if_paused(interface.clone()); + cond.wait_if_paused(interface.clone()); if play.fmt.fmt_generation != self.fmt.fmt_generation { break; @@ -373,6 +401,7 @@ impl StreamData { hva: u64, shmem_size: u64, interface: Arc>, + cond: Arc, ) { // SAFETY: hva is the shared memory base address. It already verifies the validity // of the address range during the header check. @@ -382,7 +411,7 @@ impl StreamData { interface.lock().unwrap().pre_receive(addr, capt); while capt.is_started != 0 { - self.wait_if_paused(interface.clone()); + cond.wait_if_paused(interface.clone()); if !self.update_buffer_by_chunk_idx(hva, shmem_size, capt) { return; @@ -520,7 +549,7 @@ impl Scream { } } - fn start_play_thread_fn(&mut self) -> Result<()> { + fn start_play_thread_fn(&mut self, cond: Arc) -> Result<()> { let hva = self.hva; let shmem_size = self.size; let interface = self.interface_init("ScreamPlay", ScreamDirection::Playback); @@ -532,24 +561,29 @@ impl Scream { .spawn(move || { let clone_interface = interface.clone(); let mut play_data = StreamData::default(); - play_data.register_pause_notifier(); + play_data.register_pause_notifier(cond.clone()); loop { play_data.wait_for_ready( clone_interface.clone(), ScreamDirection::Playback, - POLL_DELAY_US, hva, + cond.clone(), ); - play_data.playback_trans(hva, shmem_size, clone_interface.clone()); + play_data.playback_trans( + hva, + shmem_size, + clone_interface.clone(), + cond.clone(), + ); } }) .with_context(|| "Failed to create thread scream")?; Ok(()) } - fn start_record_thread_fn(&mut self) -> Result<()> { + fn start_record_thread_fn(&mut self, cond: Arc) -> Result<()> { let hva = self.hva; let shmem_size = self.size; let interface = self.interface_init("ScreamCapt", ScreamDirection::Record); @@ -562,14 +596,14 @@ impl Scream { .spawn(move || { let clone_interface = interface.clone(); let mut capt_data = StreamData::default(); - capt_data.register_pause_notifier(); + capt_data.register_pause_notifier(cond.clone()); loop { capt_data.wait_for_ready( clone_interface.clone(), ScreamDirection::Record, - POLL_DELAY_US, hva, + cond.clone(), ); #[cfg(all(target_env = "ohos", feature = "scream_ohaudio"))] @@ -577,7 +611,7 @@ impl Scream { bound_tokenid(*token_id.read().unwrap()) .unwrap_or_else(|e| error!("bound token ID failed: {}", e)); } - capt_data.capture_trans(hva, shmem_size, clone_interface.clone()); + capt_data.capture_trans(hva, shmem_size, clone_interface.clone(), cond.clone()); } }) .with_context(|| "Failed to create thread scream")?; @@ -617,13 +651,20 @@ impl Scream { ); let ivshmem = ivshmem.realize()?; - self.set_ivshmem_ops(ivshmem); + let play_cond = ScreamCond::new(); + let capt_cond = ScreamCond::new(); + self.set_ivshmem_ops(ivshmem, play_cond.clone(), capt_cond.clone()); - self.start_play_thread_fn()?; - self.start_record_thread_fn() + self.start_play_thread_fn(play_cond)?; + self.start_record_thread_fn(capt_cond) } - fn set_ivshmem_ops(&mut self, ivshmem: Arc>) { + fn set_ivshmem_ops( + &mut self, + ivshmem: Arc>, + play_cond: Arc, + capt_cond: Arc, + ) { let interface = self.create_audio_extension(ivshmem.clone()); let interface2 = interface.clone(); let bar0_write = Arc::new(move |data: &[u8], offset: u64| { @@ -631,6 +672,14 @@ impl Scream { IVSHMEM_BAR0_VOLUME => { interface.set_host_volume(le_read_u32(data, 0).unwrap()); } + IVSHMEM_BAR0_STATUS => { + let val = le_read_u32(data, 0).unwrap(); + if val & STATUS_PLAY_BIT == STATUS_PLAY_BIT { + play_cond.set_stream_pause(val & STATUS_START_BIT != STATUS_START_BIT); + } else { + capt_cond.set_stream_pause(val & STATUS_START_BIT != STATUS_START_BIT); + } + } _ => { info!("ivshmem-scream: unsupported write: {offset}"); } -- Gitee From cf79238ae0e918b8aa08a5ef58cdb26ac6f52b88 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Tue, 13 Aug 2024 22:05:24 +0800 Subject: [PATCH 246/489] ivshmem: set max access size for bar0 region Set max access size to 4 bytes for bar0 region. Signed-off-by: Zhao Yi Min --- devices/src/misc/ivshmem.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/devices/src/misc/ivshmem.rs b/devices/src/misc/ivshmem.rs index d4d50f36..2d132582 100644 --- a/devices/src/misc/ivshmem.rs +++ b/devices/src/misc/ivshmem.rs @@ -120,9 +120,12 @@ impl Ivshmem { }; // bar0: mmio register + let mut bar0_region = + Region::init_io_region(IVSHMEM_REG_BAR_SIZE, reg_region_ops, "IvshmemIo"); + bar0_region.set_access_size(4); self.base.config.register_bar( 0, - Region::init_io_region(IVSHMEM_REG_BAR_SIZE, reg_region_ops, "IvshmemIo"), + bar0_region, RegionType::Mem32Bit, false, IVSHMEM_REG_BAR_SIZE, -- Gitee From 7bef8c288ba23159b3ca18b8c4b5333220023c18 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Wed, 14 Aug 2024 19:21:37 +0800 Subject: [PATCH 247/489] xhci: Check whether event ring address is valid The event ring must locate in guest ram. Signed-off-by: Keqian Zhu --- devices/src/usb/xhci/xhci_controller.rs | 15 +++++++-- devices/src/usb/xhci/xhci_regs.rs | 44 ++++++++++++++----------- 2 files changed, 36 insertions(+), 23 deletions(-) diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index 3fe6631e..2114f607 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -25,7 +25,7 @@ use super::xhci_pci::XhciConfig; use super::xhci_regs::{XhciInterrupter, XhciOperReg}; use super::xhci_ring::{XhciCommandRing, XhciEventRingSeg, XhciTRB, XhciTransferRing}; use super::xhci_trb::{ - TRBCCode, TRBType, SETUP_TRB_TR_LEN, TRB_EV_ED, TRB_TR_DIR, TRB_TR_FRAMEID_MASK, + TRBCCode, TRBType, SETUP_TRB_TR_LEN, TRB_EV_ED, TRB_SIZE, TRB_TR_DIR, TRB_TR_FRAMEID_MASK, TRB_TR_FRAMEID_SHIFT, TRB_TR_IDT, TRB_TR_IOC, TRB_TR_ISP, TRB_TR_LEN_MASK, TRB_TR_SIA, TRB_TYPE_SHIFT, }; @@ -2359,7 +2359,7 @@ impl XhciDevice { pub(crate) fn reset_event_ring(&mut self, idx: u32) -> Result<()> { let mut locked_intr = self.intrs[idx as usize].lock().unwrap(); if locked_intr.erstsz == 0 || locked_intr.erstba == 0 { - locked_intr.er_start = 0; + locked_intr.er_start = GuestAddress(0); locked_intr.er_size = 0; return Ok(()); } @@ -2368,7 +2368,16 @@ impl XhciDevice { if seg.size < 16 || seg.size > 4096 { bail!("Invalid segment size {}", seg.size); } - locked_intr.er_start = addr64_from_u32(seg.addr_lo, seg.addr_hi); + + // GPAChecked: the event ring must locate in guest ram. + let base_addr = GuestAddress(addr64_from_u32(seg.addr_lo, seg.addr_hi)); + // SAFETY: seg size is a 16 bit register, will not overflow. + let er_len = seg.size * TRB_SIZE; + if !self.mem_space.address_in_memory(base_addr, er_len as u64) { + bail!("The event ring does not locate in guest ram"); + } + + locked_intr.er_start = base_addr; locked_intr.er_size = seg.size; locked_intr.er_ep_idx = 0; locked_intr.er_pcs = true; diff --git a/devices/src/usb/xhci/xhci_regs.rs b/devices/src/usb/xhci/xhci_regs.rs index d817a631..28186170 100644 --- a/devices/src/usb/xhci/xhci_regs.rs +++ b/devices/src/usb/xhci/xhci_regs.rs @@ -188,7 +188,7 @@ pub struct XhciInterrupter { pub erdp: u64, /// Event Ring Producer Cycle State pub er_pcs: bool, - pub er_start: u64, + pub er_start: GuestAddress, pub er_size: u32, pub er_ep_idx: u32, } @@ -212,7 +212,7 @@ impl XhciInterrupter { erstba: 0, erdp: 0, er_pcs: true, - er_start: 0, + er_start: GuestAddress(0), er_size: 0, er_ep_idx: 0, } @@ -238,7 +238,7 @@ impl XhciInterrupter { self.erstba = 0; self.erdp = 0; self.er_pcs = true; - self.er_start = 0; + self.er_start = GuestAddress(0); self.er_size = 0; self.er_ep_idx = 0; } @@ -248,19 +248,21 @@ impl XhciInterrupter { let er_end = self .er_start .checked_add((TRB_SIZE * self.er_size) as u64) - .ok_or(UsbError::MemoryAccessOverflow( - self.er_start, - (TRB_SIZE * self.er_size) as u64, - ))?; - if self.erdp < self.er_start || self.erdp >= er_end { + .ok_or_else(|| { + UsbError::MemoryAccessOverflow( + self.er_start.raw_value(), + (TRB_SIZE * self.er_size) as u64, + ) + })?; + if self.erdp < self.er_start.raw_value() || self.erdp >= er_end.raw_value() { bail!( "DMA out of range, erdp {} er_start {:x} er_size {}", self.erdp, - self.er_start, + self.er_start.raw_value(), self.er_size ); } - let dp_idx = (self.erdp - self.er_start) / TRB_SIZE as u64; + let dp_idx = (self.erdp - self.er_start.raw_value()) / TRB_SIZE as u64; if ((self.er_ep_idx + 2) % self.er_size) as u64 == dp_idx { debug!("Event ring full error, idx {}", dp_idx); let event = XhciEvent::new(TRBType::ErHostController, TRBCCode::EventRingFullError); @@ -335,10 +337,12 @@ impl XhciInterrupter { let addr = self .er_start .checked_add((TRB_SIZE * self.er_ep_idx) as u64) - .ok_or(UsbError::MemoryAccessOverflow( - self.er_start, - (TRB_SIZE * self.er_ep_idx) as u64, - ))?; + .ok_or_else(|| { + UsbError::MemoryAccessOverflow( + self.er_start.raw_value(), + (TRB_SIZE * self.er_ep_idx) as u64, + ) + })?; let cycle = trb.control as u8; // Toggle the cycle bit to avoid driver read it. let control = if trb.control & TRB_C == TRB_C { @@ -350,10 +354,10 @@ impl XhciInterrupter { LittleEndian::write_u64(&mut buf, trb.parameter); LittleEndian::write_u32(&mut buf[8..], trb.status); LittleEndian::write_u32(&mut buf[12..], control); - dma_write_bytes(&self.mem, GuestAddress(addr), &buf)?; + dma_write_bytes(&self.mem, addr, &buf)?; // Write the cycle bit at last. fence(Ordering::SeqCst); - dma_write_bytes(&self.mem, GuestAddress(addr + 12), &[cycle])?; + dma_write_bytes(&self.mem, addr.unchecked_add(12), &[cycle])?; Ok(()) } } @@ -650,14 +654,14 @@ pub fn build_runtime_ops(xhci_dev: &Arc>) -> RegionOps { } else { error!( "Memory access overflow, addr {:x} offset {:x}", - locked_intr.er_start, + locked_intr.er_start.raw_value(), (TRB_SIZE * locked_intr.er_size) as u64 ); return false; }; - if erdp >= locked_intr.er_start - && erdp < er_end - && (erdp - locked_intr.er_start) / TRB_SIZE as u64 + if erdp >= locked_intr.er_start.raw_value() + && erdp < er_end.raw_value() + && (erdp - locked_intr.er_start.raw_value()) / TRB_SIZE as u64 != locked_intr.er_ep_idx as u64 { drop(locked_intr); -- Gitee From ccdd0b7c30c76b48575ce25028c39f145bfb9c05 Mon Sep 17 00:00:00 2001 From: Fan Xuan Zhe Date: Thu, 15 Aug 2024 18:42:27 +0800 Subject: [PATCH 248/489] PvPanic: add hisysevent trace when panic occurred Add hisysevent trace when panicked/crashloaded event happened. --- Cargo.lock | 1 + devices/Cargo.toml | 1 + devices/src/misc/pvpanic.rs | 2 ++ hisysevent/event_info/misc.toml | 5 +++++ 4 files changed, 9 insertions(+) create mode 100644 hisysevent/event_info/misc.toml diff --git a/Cargo.lock b/Cargo.lock index 20ed7089..9453a417 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -387,6 +387,7 @@ dependencies = [ "clap", "cpu", "drm-fourcc", + "hisysevent", "libc", "libpulse-binding", "libpulse-simple-binding", diff --git a/devices/Cargo.toml b/devices/Cargo.toml index fec9d5c1..69dc546d 100644 --- a/devices/Cargo.toml +++ b/devices/Cargo.toml @@ -38,6 +38,7 @@ rusb = { version = "0.9", optional = true } libusb1-sys = { version = "0.6.4", optional = true } trace = { path = "../trace" } clap = { version = "=4.1.4", default-features = false, features = ["std", "derive"] } +hisysevent = { path = "../hisysevent" } [features] default = [] diff --git a/devices/src/misc/pvpanic.rs b/devices/src/misc/pvpanic.rs index 1647a2d5..366d0f45 100644 --- a/devices/src/misc/pvpanic.rs +++ b/devices/src/misc/pvpanic.rs @@ -87,12 +87,14 @@ impl PvPanicState { if (event & PVPANIC_PANICKED) == PVPANIC_PANICKED && (self.supported_features & PVPANIC_PANICKED) == PVPANIC_PANICKED { + hisysevent::STRATOVIRT_PVPANIC("PANICKED".to_string()); info!("pvpanic: panicked event"); } if (event & PVPANIC_CRASHLOADED) == PVPANIC_CRASHLOADED && (self.supported_features & PVPANIC_CRASHLOADED) == PVPANIC_CRASHLOADED { + hisysevent::STRATOVIRT_PVPANIC("CRASHLOADED".to_string()); info!("pvpanic: crashloaded event"); } diff --git a/hisysevent/event_info/misc.toml b/hisysevent/event_info/misc.toml new file mode 100644 index 00000000..eeb4be8d --- /dev/null +++ b/hisysevent/event_info/misc.toml @@ -0,0 +1,5 @@ +[[events]] +name = "STRATOVIRT_PVPANIC" +event_type = "Fault" +args = "event: String" +enabled = true -- Gitee From 51bed2e7c9ff62fdc6551f9526b074165d155768 Mon Sep 17 00:00:00 2001 From: zhanghan64 Date: Tue, 13 Aug 2024 16:54:37 +0800 Subject: [PATCH 249/489] scream:support microphone authority sync This patch defines an status register on ivshmem BAR0, in which BIT2 is used for passing microphone's authority infomation to frontend. We use msix 1 to tell front end status-changed-event, and use BAR0 register to pass related info.` Signed-off-by: zhanghan64 --- devices/src/misc/scream/mod.rs | 60 ++++++++++++++++++++++++++++------ 1 file changed, 50 insertions(+), 10 deletions(-) diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index fe55fda8..237d271a 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -27,6 +27,7 @@ use anyhow::{anyhow, bail, Context, Result}; use clap::{ArgAction, Parser}; use core::time; use log::{error, info, warn}; +use once_cell::sync::Lazy; #[cfg(feature = "scream_alsa")] use self::alsa::AlsaStreamData; @@ -54,12 +55,14 @@ pub const TARGET_LATENCY_MS: u32 = 50; #[cfg(all(target_env = "ohos", feature = "scream_ohaudio"))] const IVSHMEM_VOLUME_SYNC_VECTOR: u16 = 0; -const IVSHMEM_VECTORS_NR: u32 = 1; +const IVSHMEM_STATUS_CHANGE_VECTOR: u16 = 1; +const IVSHMEM_VECTORS_NR: u32 = 2; const IVSHMEM_BAR0_VOLUME: u64 = 240; const IVSHMEM_BAR0_STATUS: u64 = 244; const STATUS_PLAY_BIT: u32 = 0x1; const STATUS_START_BIT: u32 = 0x2; +const STATUS_MIC_AVAIL_BIT: u32 = 0x4; // A frame of back-end audio data is 50ms, and the next frame of audio data needs // to be trained in polling within 50ms. Theoretically, the shorter the polling time, @@ -80,6 +83,26 @@ pub enum AudioStatus { Error, } +type AuthorityNotify = dyn Fn() + Send + Sync; + +#[derive(Clone)] +pub struct AuthorityInformation { + state: bool, + notify: Option>, +} + +impl AuthorityInformation { + const fn default() -> AuthorityInformation { + AuthorityInformation { + state: true, + notify: None, + } + } +} + +type AuthInfo = RwLock; +static AUTH_INFO: Lazy = Lazy::new(|| RwLock::new(AuthorityInformation::default())); + /// The scream device defines the audio directions. #[derive(Debug, Copy, Clone, PartialEq, Eq)] pub enum ScreamDirection { @@ -106,20 +129,19 @@ pub struct ShmemStreamHeader { pub fmt: ShmemStreamFmt, } -fn record_authority_rw(auth: bool, write: bool) -> bool { - static AUTH: RwLock = RwLock::new(true); - if write { - *AUTH.write().unwrap() = auth; +pub fn set_record_authority(auth: bool) { + AUTH_INFO.write().unwrap().state = auth; + if let Some(auth_notify) = &AUTH_INFO.read().unwrap().notify { + auth_notify(); } - *AUTH.read().unwrap() } -pub fn set_record_authority(auth: bool) { - record_authority_rw(auth, true); +pub fn set_authority_notify(notify: Option>) { + AUTH_INFO.write().unwrap().notify = notify; } -fn get_record_authority() -> bool { - record_authority_rw(false, false) +pub fn get_record_authority() -> bool { + AUTH_INFO.read().unwrap().state } impl ShmemStreamHeader { @@ -650,11 +672,20 @@ impl Scream { IVSHMEM_VECTORS_NR, ); let ivshmem = ivshmem.realize()?; + let ivshmem_cloned = ivshmem.clone(); let play_cond = ScreamCond::new(); let capt_cond = ScreamCond::new(); self.set_ivshmem_ops(ivshmem, play_cond.clone(), capt_cond.clone()); + let author_notify = Arc::new(move || { + ivshmem_cloned + .lock() + .unwrap() + .trigger_msix(IVSHMEM_STATUS_CHANGE_VECTOR); + }); + set_authority_notify(Some(author_notify)); + self.start_play_thread_fn(play_cond)?; self.start_record_thread_fn(capt_cond) } @@ -691,6 +722,9 @@ impl Scream { IVSHMEM_BAR0_VOLUME => { let _ = le_write_u32(data, 0, interface2.get_host_volume()); } + IVSHMEM_BAR0_STATUS => { + let _ = le_write_u32(data, 0, interface2.get_status_register()); + } _ => { info!("ivshmem-scream: unsupported read: {offset}"); } @@ -727,6 +761,12 @@ pub trait AudioExtension: Send + Sync { fn get_host_volume(&self) -> u32 { 0 } + fn get_status_register(&self) -> u32 { + match get_record_authority() { + true => STATUS_MIC_AVAIL_BIT, + false => 0, + } + } } struct AudioExtensionDummy; -- Gitee From 65e8a72ca696ab081b753a75fe0c4a02fd10c9b6 Mon Sep 17 00:00:00 2001 From: lixiang_yewu Date: Thu, 15 Aug 2024 11:17:03 +0000 Subject: [PATCH 250/489] update docs/snapshot.md. Signed-off-by: lixiang_yewu --- docs/snapshot.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/snapshot.md b/docs/snapshot.md index 6a9c97f7..5e9c118b 100644 --- a/docs/snapshot.md +++ b/docs/snapshot.md @@ -25,7 +25,7 @@ $ ncat -U path/to/socket {"return":{}} ``` -When VM is in paused state, is's safe to take a snapshot of the VM into the specified directory with QMP. +When VM is in paused state, it's safe to take a snapshot of the VM into the specified directory with QMP. ```shell $ ncat -U path/to/socket {"QMP":{"version":{"StratoVirt":{"micro":1,"minor":0,"major":0},"package":""},"capabilities":[]}} -- Gitee From db1465cf9ce68e8f32534c483a77ff6e2588ed41 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Fri, 16 Aug 2024 12:52:42 +0800 Subject: [PATCH 251/489] pci: Fix `unused_parens` clippy warnings warning: unnecessary parentheses around function argument --> devices/src/pci/config.rs:1316:23 | 1316 | u64::from((MEM_BASE_ADDR_MASK as u32)) | ^ ^ | = note: `#[warn(unused_parens)]` on by default help: remove these parentheses | 1316 - u64::from((MEM_BASE_ADDR_MASK as u32)) 1316 + u64::from(MEM_BASE_ADDR_MASK as u32) Signed-off-by: liuxiangdong --- devices/src/pci/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devices/src/pci/config.rs b/devices/src/pci/config.rs index 5228e337..2f041c4f 100644 --- a/devices/src/pci/config.rs +++ b/devices/src/pci/config.rs @@ -1313,7 +1313,7 @@ mod tests { assert_eq!(pci_config.get_bar_address(0), BAR_SPACE_UNMAPPED); assert_eq!( pci_config.get_bar_address(1), - (MEM_BASE_ADDR_MASK as u32) as u64 + u64::from(MEM_BASE_ADDR_MASK as u32) ); assert_eq!(pci_config.get_bar_address(2), MEM_BASE_ADDR_MASK); } -- Gitee From f766ddf64b88216ddcf9c88d7f3896d1e003bd5f Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Fri, 16 Aug 2024 12:55:00 +0800 Subject: [PATCH 252/489] clippy: fix all cast_lossless warnings Use command line: cargo clippy --fix --workspace -- -Aclippy::all -Wclippy::cast_lossless Signed-off-by: liuxiangdong --- acpi/src/acpi_device.rs | 2 +- acpi/src/aml_compiler.rs | 2 +- acpi/src/table_loader.rs | 2 +- address_space/src/address.rs | 10 +- address_space/src/host_mmap.rs | 4 +- block_backend/src/lib.rs | 4 +- block_backend/src/qcow2/cache.rs | 2 +- block_backend/src/qcow2/check.rs | 34 +-- block_backend/src/qcow2/header.rs | 12 +- block_backend/src/qcow2/mod.rs | 30 +-- block_backend/src/qcow2/refcount.rs | 16 +- block_backend/src/qcow2/snapshot.rs | 2 +- block_backend/src/qcow2/table.rs | 6 +- block_backend/src/raw.rs | 6 +- boot_loader/src/x86_64/direct_boot/gdt.rs | 4 +- boot_loader/src/x86_64/direct_boot/mod.rs | 8 +- boot_loader/src/x86_64/standard_boot/elf.rs | 12 +- boot_loader/src/x86_64/standard_boot/mod.rs | 2 +- cpu/src/x86_64/mod.rs | 18 +- devices/src/acpi/power.rs | 2 +- .../src/interrupt_controller/aarch64/state.rs | 18 +- devices/src/legacy/fwcfg.rs | 28 +-- devices/src/legacy/pflash.rs | 20 +- devices/src/legacy/pl011.rs | 16 +- devices/src/legacy/pl031.rs | 2 +- devices/src/legacy/rtc.rs | 4 +- devices/src/misc/ivshmem.rs | 2 +- devices/src/misc/pvpanic.rs | 4 +- devices/src/misc/scream/mod.rs | 16 +- devices/src/pci/bus.rs | 6 +- devices/src/pci/config.rs | 40 ++-- devices/src/pci/host.rs | 16 +- devices/src/pci/mod.rs | 19 +- devices/src/pci/msix.rs | 42 ++-- devices/src/pci/root_port.rs | 11 +- devices/src/scsi/bus.rs | 22 +- devices/src/smbios/smbios_table.rs | 10 +- devices/src/usb/descriptor.rs | 6 +- devices/src/usb/hid.rs | 2 +- devices/src/usb/keyboard.rs | 4 +- devices/src/usb/mod.rs | 26 +-- devices/src/usb/storage.rs | 4 +- devices/src/usb/xhci/xhci_controller.rs | 38 ++-- devices/src/usb/xhci/xhci_pci.rs | 29 +-- devices/src/usb/xhci/xhci_regs.rs | 38 ++-- devices/src/usb/xhci/xhci_ring.rs | 10 +- hypervisor/src/kvm/aarch64/gicv2.rs | 8 +- hypervisor/src/kvm/aarch64/gicv3.rs | 10 +- hypervisor/src/kvm/aarch64/mod.rs | 41 ++-- hypervisor/src/kvm/mod.rs | 2 +- hypervisor/src/test/mod.rs | 6 +- image/src/img.rs | 8 +- machine/src/aarch64/fdt.rs | 2 +- machine/src/aarch64/standard.rs | 10 +- machine/src/lib.rs | 4 +- machine/src/standard_common/mod.rs | 20 +- machine/src/x86_64/ich9_lpc.rs | 17 +- machine_manager/src/config/machine_config.rs | 2 +- machine_manager/src/config/network.rs | 2 +- machine_manager/src/qmp/qmp_channel.rs | 2 +- machine_manager/src/socket.rs | 6 +- migration/migration_derive/src/attr_parser.rs | 2 +- migration/src/manager.rs | 2 +- migration/src/protocol.rs | 10 +- tests/mod_test/src/libdriver/pci.rs | 14 +- tests/mod_test/src/libdriver/pci_bus.rs | 9 +- tests/mod_test/src/libdriver/qcow2.rs | 2 +- tests/mod_test/src/libdriver/usb.rs | 196 ++++++++++-------- tests/mod_test/src/libdriver/virtio.rs | 30 +-- tests/mod_test/src/libdriver/virtio_block.rs | 18 +- tests/mod_test/src/libdriver/virtio_gpu.rs | 4 +- .../src/libdriver/virtio_pci_modern.rs | 108 +++++----- tests/mod_test/src/utils.rs | 8 +- tests/mod_test/tests/aarch64/acpi_test.rs | 8 +- tests/mod_test/tests/balloon_test.rs | 28 +-- tests/mod_test/tests/block_test.rs | 63 +++--- tests/mod_test/tests/net_test.rs | 34 +-- tests/mod_test/tests/pci_test.rs | 18 +- tests/mod_test/tests/rng_test.rs | 4 +- tests/mod_test/tests/scream_test.rs | 16 +- tests/mod_test/tests/scsi_test.rs | 78 +++---- tests/mod_test/tests/serial_test.rs | 14 +- tests/mod_test/tests/usb_camera_test.rs | 4 +- tests/mod_test/tests/usb_storage_test.rs | 10 +- tests/mod_test/tests/usb_test.rs | 80 ++++--- tests/mod_test/tests/virtio_test.rs | 67 +++--- tests/mod_test/tests/virtiofs_test.rs | 4 +- tests/mod_test/tests/vnc_test.rs | 4 +- ui/src/console.rs | 4 +- ui/src/pixman.rs | 14 +- util/src/aio/mod.rs | 24 +-- util/src/aio/threads.rs | 2 +- util/src/aio/uring.rs | 2 +- util/src/edid.rs | 2 +- util/src/file.rs | 2 +- util/src/leak_bucket.rs | 2 +- util/src/logger.rs | 4 +- util/src/num_ops.rs | 8 +- util/src/tap.rs | 4 +- util/src/unix.rs | 6 +- vfio/src/vfio_pci.rs | 25 +-- virtio/src/device/balloon.rs | 20 +- virtio/src/device/block.rs | 18 +- virtio/src/device/gpu.rs | 20 +- virtio/src/device/net.rs | 8 +- virtio/src/device/rng.rs | 36 ++-- virtio/src/device/scsi_cntlr.rs | 4 +- virtio/src/device/serial.rs | 8 +- virtio/src/lib.rs | 18 +- virtio/src/queue/mod.rs | 2 +- virtio/src/queue/split.rs | 136 ++++++------ virtio/src/transport/virtio_mmio.rs | 16 +- virtio/src/transport/virtio_pci.rs | 44 ++-- virtio/src/vhost/kernel/net.rs | 4 +- virtio/src/vhost/kernel/vsock.rs | 6 +- virtio/src/vhost/user/block.rs | 4 +- virtio/src/vhost/user/client.rs | 8 +- 117 files changed, 1064 insertions(+), 973 deletions(-) diff --git a/acpi/src/acpi_device.rs b/acpi/src/acpi_device.rs index aff03b84..d315fc40 100644 --- a/acpi/src/acpi_device.rs +++ b/acpi/src/acpi_device.rs @@ -52,7 +52,7 @@ impl AcpiPMTimer { } let now = Instant::now(); let time_nanos = now.duration_since(self.start).as_nanos(); - let counter: u128 = (time_nanos * PM_TIMER_FREQUENCY) / (NANOSECONDS_PER_SECOND as u128); + let counter: u128 = (time_nanos * PM_TIMER_FREQUENCY) / u128::from(NANOSECONDS_PER_SECOND); data.copy_from_slice(&((counter & 0xFFFF_FFFF) as u32).to_le_bytes()); true diff --git a/acpi/src/aml_compiler.rs b/acpi/src/aml_compiler.rs index 2ad8d51a..b7aa0a9a 100644 --- a/acpi/src/aml_compiler.rs +++ b/acpi/src/aml_compiler.rs @@ -1616,7 +1616,7 @@ impl AmlIrqNoFlags { impl AmlBuilder for AmlIrqNoFlags { fn aml_bytes(&self) -> Vec { - let irq_mask = 1 << (self.irq as u16); + let irq_mask = 1 << u16::from(self.irq); vec![0x22, (irq_mask & 0xFF) as u8, (irq_mask >> 8) as u8] } } diff --git a/acpi/src/table_loader.rs b/acpi/src/table_loader.rs index 0a58c6de..74a9d173 100644 --- a/acpi/src/table_loader.rs +++ b/acpi/src/table_loader.rs @@ -356,7 +356,7 @@ impl TableLoader { dst_file_entry.file_blob.lock().unwrap() [offset as usize..(offset as usize + size as usize)] - .copy_from_slice(&(src_offset as u64).as_bytes()[0..size as usize]); + .copy_from_slice(&u64::from(src_offset).as_bytes()[0..size as usize]); self.cmds.push(TableLoaderEntry::new_add_pointer_entry( dst_file, src_file, offset, size, diff --git a/address_space/src/address.rs b/address_space/src/address.rs index a5ace6f0..6fd1a8dc 100644 --- a/address_space/src/address.rs +++ b/address_space/src/address.rs @@ -166,16 +166,16 @@ impl AddressRange { /// /// * `other` - Other AddressRange. pub fn find_intersection(&self, other: AddressRange) -> Option { - let begin = self.base.raw_value() as u128; - let end = self.size as u128 + begin; - let other_begin = other.base.raw_value() as u128; - let other_end = other.size as u128 + other_begin; + let begin = u128::from(self.base.raw_value()); + let end = u128::from(self.size) + begin; + let other_begin = u128::from(other.base.raw_value()); + let other_end = u128::from(other.size) + other_begin; if end <= other_begin || other_end <= begin { return None; } let start = std::cmp::max(self.base, other.base); - let size_inter = (std::cmp::min(end, other_end) - start.0 as u128) as u64; + let size_inter = (std::cmp::min(end, other_end) - u128::from(start.0)) as u64; Some(AddressRange { base: start, diff --git a/address_space/src/host_mmap.rs b/address_space/src/host_mmap.rs index d2012e6f..c4b8ce17 100644 --- a/address_space/src/host_mmap.rs +++ b/address_space/src/host_mmap.rs @@ -209,8 +209,8 @@ fn mem_prealloc(host_addr: u64, size: u64, nr_vcpus: u8) { let page_size = host_page_size(); let threads = max_nr_threads(nr_vcpus); let nr_pages = (size + page_size - 1) / page_size; - let pages_per_thread = nr_pages / (threads as u64); - let left = nr_pages % (threads as u64); + let pages_per_thread = nr_pages / u64::from(threads); + let left = nr_pages % u64::from(threads); let mut addr = host_addr; let mut threads_join = Vec::new(); for i in 0..threads { diff --git a/block_backend/src/lib.rs b/block_backend/src/lib.rs index b4de1fc9..c571f292 100644 --- a/block_backend/src/lib.rs +++ b/block_backend/src/lib.rs @@ -402,7 +402,7 @@ pub fn create_block_backend( DiskFormat::Raw => { let mut raw_file = RawDriver::new(file, aio, prop.clone()); let file_size = raw_file.disk_size()?; - if file_size & (prop.req_align as u64 - 1) != 0 { + if file_size & (u64::from(prop.req_align) - 1) != 0 { bail!("The size of raw file is not aligned to {}.", prop.req_align); } Ok(Arc::new(Mutex::new(raw_file))) @@ -415,7 +415,7 @@ pub fn create_block_backend( .with_context(|| "Failed to load metadata")?; let file_size = qcow2.disk_size()?; - if file_size & (prop.req_align as u64 - 1) != 0 { + if file_size & (u64::from(prop.req_align) - 1) != 0 { bail!( "The size of qcow2 file is not aligned to {}.", prop.req_align diff --git a/block_backend/src/qcow2/cache.rs b/block_backend/src/qcow2/cache.rs index 445ddc31..c46bc5d9 100644 --- a/block_backend/src/qcow2/cache.rs +++ b/block_backend/src/qcow2/cache.rs @@ -85,7 +85,7 @@ impl CacheTable { bail!("Invalid idx {}", idx); } let v = match self.entry_size { - ENTRY_SIZE_U16 => BigEndian::read_u16(&self.table_data[start..end]) as u64, + ENTRY_SIZE_U16 => u64::from(BigEndian::read_u16(&self.table_data[start..end])), ENTRY_SIZE_U64 => BigEndian::read_u64(&self.table_data[start..end]), _ => bail!("Unsupported entry size {}", self.entry_size), }; diff --git a/block_backend/src/qcow2/check.rs b/block_backend/src/qcow2/check.rs index 2f6bb9f7..c148178c 100644 --- a/block_backend/src/qcow2/check.rs +++ b/block_backend/src/qcow2/check.rs @@ -105,7 +105,7 @@ impl RefcountBlock { let start_bytes = idx * self.entry_bytes; let end_bytes = start_bytes + self.entry_bytes; let value = match self.entry_bytes { - ENTRY_SIZE_U16 => BigEndian::read_u16(&self.data[start_bytes..end_bytes]) as u64, + ENTRY_SIZE_U16 => u64::from(BigEndian::read_u16(&self.data[start_bytes..end_bytes])), ENTRY_SIZE_U64 => BigEndian::read_u64(&self.data[start_bytes..end_bytes]), _ => bail!("Entry size is unsupported"), }; @@ -221,7 +221,7 @@ impl Qcow2Driver { let snapshot_table_length = size_of::() as u64; let snapshot_table_offset = self.header.snapshots_offset; // Validate snapshot table. - if (u64::MAX - nb_snapshots as u64 * snapshot_table_length) < snapshot_table_offset + if (u64::MAX - u64::from(nb_snapshots) * snapshot_table_length) < snapshot_table_offset || !is_aligned(self.header.cluster_size(), snapshot_table_offset) { res.err_num += 1; @@ -300,7 +300,7 @@ impl Qcow2Driver { /// Rebuild a new refcount table according to metadata, including active l1 table, active l2 table, /// snapshot table, refcount table and refcount block. pub(crate) fn check_refcounts(&mut self, check: &mut Qcow2Check) -> Result<()> { - let cluster_bits = self.header.cluster_bits as u64; + let cluster_bits = u64::from(self.header.cluster_bits); let cluster_size = 1 << cluster_bits; let virtual_size = self.header.size; check.res.disk_frag.total_clusters = div_round_up(virtual_size, cluster_size).unwrap(); @@ -380,14 +380,14 @@ impl Qcow2Driver { 0, self.header.cluster_size(), file_len, - self.header.cluster_bits as u64, + u64::from(self.header.cluster_bits), check, )?; // Increase the refcount of active l1 table. let active_l1_offset = self.header.l1_table_offset; let active_l1_size = self.header.l1_size; - self.check_refcounts_l1(active_l1_offset, active_l1_size as u64, true, check)?; + self.check_refcounts_l1(active_l1_offset, u64::from(active_l1_size), true, check)?; // Increase the refcount of snapshot table. for idx in 0..self.header.nb_snapshots { @@ -404,7 +404,7 @@ impl Qcow2Driver { continue; } - if snap_l1_size as u64 > QCOW2_MAX_L1_SIZE / ENTRY_SIZE { + if u64::from(snap_l1_size) > QCOW2_MAX_L1_SIZE / ENTRY_SIZE { output_msg!( check.quite, "ERROR snapshot {:?}({:?}) l1_size={:?} l1 table is too large; snapshot table entry courropted", @@ -414,7 +414,7 @@ impl Qcow2Driver { continue; } - self.check_refcounts_l1(snap_l1_offset, snap_l1_size as u64, false, check)?; + self.check_refcounts_l1(snap_l1_offset, u64::from(snap_l1_size), false, check)?; } let snap_table_offset = self.header.snapshots_offset; @@ -424,19 +424,19 @@ impl Qcow2Driver { snap_table_offset, snap_table_size, file_len, - self.header.cluster_bits as u64, + u64::from(self.header.cluster_bits), check, )?; } let reftable_offset = self.header.refcount_table_offset; let reftable_bytes = - self.header.refcount_table_clusters as u64 * self.header.cluster_size(); + u64::from(self.header.refcount_table_clusters) * self.header.cluster_size(); self.increase_refcounts( reftable_offset, reftable_bytes, file_len, - self.header.cluster_bits as u64, + u64::from(self.header.cluster_bits), check, )?; @@ -463,7 +463,7 @@ impl Qcow2Driver { l1_offset, l1_size_bytes, file_len, - self.header.cluster_bits as u64, + u64::from(self.header.cluster_bits), check, )?; let l1_table = self @@ -497,7 +497,7 @@ impl Qcow2Driver { l2_offset, self.header.cluster_size(), file_len, - self.header.cluster_bits as u64, + u64::from(self.header.cluster_bits), check, )?; @@ -529,7 +529,7 @@ impl Qcow2Driver { file_len: u64, check: &mut Qcow2Check, ) -> Result<()> { - let cluster_bits = self.header.cluster_bits as u64; + let cluster_bits = u64::from(self.header.cluster_bits); let cluster_size = 1 << cluster_bits; let l2_size = cluster_size >> ENTRY_BITS; @@ -661,7 +661,7 @@ impl Qcow2Driver { } fn check_refcount_block(&mut self, check: &mut Qcow2Check) -> Result<()> { - let cluster_bits = self.header.cluster_bits as u64; + let cluster_bits = u64::from(self.header.cluster_bits); let cluster_size = 1 << cluster_bits; let file_len = self.driver.disk_size()?; let nb_clusters = bytes_to_clusters(file_len, cluster_size)?; @@ -794,7 +794,7 @@ impl Qcow2Driver { ); if need_fixed { - let added = rc_value_2 as i32 - rc_value_1 as i32; + let added = i32::from(rc_value_2) - i32::from(rc_value_1); let cluster_offset = cluster_idx << cluster_bits; self.refcount.update_refcount( cluster_offset, @@ -964,8 +964,8 @@ impl Qcow2Driver { let mut reftable_offset: u64 = 0; let mut new_reftable: Vec = Vec::new(); let mut reftable_clusters: u64 = 0; - let cluster_bits = self.header.cluster_bits as u64; - let refblock_bits: u64 = cluster_bits + 3 - self.header.refcount_order as u64; + let cluster_bits = u64::from(self.header.cluster_bits); + let refblock_bits: u64 = cluster_bits + 3 - u64::from(self.header.refcount_order); let refblock_size: u64 = 1 << refblock_bits; // self.refblock.nb_clusters means the maximum number of clusters that can be represented by diff --git a/block_backend/src/qcow2/header.rs b/block_backend/src/qcow2/header.rs index d2b9f8f7..99404b9f 100644 --- a/block_backend/src/qcow2/header.rs +++ b/block_backend/src/qcow2/header.rs @@ -138,7 +138,7 @@ impl QcowHeader { if !(MIN_CLUSTER_BIT..=MAX_CLUSTER_BIT).contains(&self.cluster_bits) { bail!("Invalid cluster bits {}", self.cluster_bits); } - if self.header_length as u64 > self.cluster_size() { + if u64::from(self.header_length) > self.cluster_size() { bail!( "Header length {} over cluster size {}", self.header_length, @@ -168,7 +168,7 @@ impl QcowHeader { if self.refcount_table_clusters == 0 { bail!("Refcount table clusters is zero"); } - if self.refcount_table_clusters as u64 > MAX_REFTABLE_SIZE / self.cluster_size() { + if u64::from(self.refcount_table_clusters) > MAX_REFTABLE_SIZE / self.cluster_size() { bail!( "Refcount table size over limit {}", self.refcount_table_clusters @@ -181,7 +181,7 @@ impl QcowHeader { ); } self.refcount_table_offset - .checked_add(self.refcount_table_clusters as u64 * self.cluster_size()) + .checked_add(u64::from(self.refcount_table_clusters) * self.cluster_size()) .with_context(|| { format!( "Invalid offset {} or refcount table clusters {}", @@ -192,7 +192,7 @@ impl QcowHeader { } fn check_l1_table(&self) -> Result<()> { - if self.l1_size as u64 > MAX_L1TABLE_SIZE / ENTRY_SIZE { + if u64::from(self.l1_size) > MAX_L1TABLE_SIZE / ENTRY_SIZE { bail!("L1 table size over limit {}", self.l1_size); } if !self.cluster_aligned(self.l1_table_offset) { @@ -201,7 +201,7 @@ impl QcowHeader { let size_per_l1_entry = self.cluster_size() * self.cluster_size() / ENTRY_SIZE; let l1_need_sz = div_round_up(self.size, size_per_l1_entry).with_context(|| "Failed to get l1 size")?; - if (self.l1_size as u64) < l1_need_sz { + if u64::from(self.l1_size) < l1_need_sz { bail!( "L1 table is too small, l1 size {} expect {}", self.l1_size, @@ -209,7 +209,7 @@ impl QcowHeader { ); } self.l1_table_offset - .checked_add(self.l1_size as u64 * ENTRY_SIZE) + .checked_add(u64::from(self.l1_size) * ENTRY_SIZE) .with_context(|| { format!( "Invalid offset {} or entry size {}", diff --git a/block_backend/src/qcow2/mod.rs b/block_backend/src/qcow2/mod.rs index c8296d21..3edc388e 100644 --- a/block_backend/src/qcow2/mod.rs +++ b/block_backend/src/qcow2/mod.rs @@ -335,8 +335,8 @@ impl Qcow2Driver { } pub fn load_refcount_table(&mut self) -> Result<()> { - let sz = - self.header.refcount_table_clusters as u64 * (self.header.cluster_size() / ENTRY_SIZE); + let sz = u64::from(self.header.refcount_table_clusters) + * (self.header.cluster_size() / ENTRY_SIZE); self.refcount.refcount_table = self .sync_aio .borrow_mut() @@ -479,7 +479,7 @@ impl Qcow2Driver { /// Extend the l1 table. pub fn grow_l1_table(&mut self, new_l1_size: u64) -> Result<()> { - let old_l1_size = self.header.l1_size as u64; + let old_l1_size = u64::from(self.header.l1_size); if new_l1_size <= old_l1_size { return Ok(()); } @@ -542,7 +542,7 @@ impl Qcow2Driver { /// Output: target entry. pub fn get_table_cluster(&mut self, guest_offset: u64) -> Result>> { let l1_index = self.table.get_l1_table_index(guest_offset); - if l1_index >= self.header.l1_size as u64 { + if l1_index >= u64::from(self.header.l1_size) { bail!("Need to grow l1 table size."); } @@ -828,11 +828,11 @@ impl Qcow2Driver { let snap = self.snapshot.snapshots[snap_id as usize].clone(); // Validate snapshot table - if snap.l1_size as u64 > MAX_L1_SIZE / ENTRY_SIZE { + if u64::from(snap.l1_size) > MAX_L1_SIZE / ENTRY_SIZE { bail!("Snapshot L1 table too large"); } - if i64::MAX as u64 - snap.l1_size as u64 * ENTRY_SIZE < snap.l1_table_offset + if i64::MAX as u64 - u64::from(snap.l1_size) * ENTRY_SIZE < snap.l1_table_offset || !is_aligned(self.header.cluster_size(), snap.l1_table_offset) { bail!("Snapshot L1 table offset invalid"); @@ -842,12 +842,12 @@ impl Qcow2Driver { let mut snap_l1_table = self .sync_aio .borrow_mut() - .read_ctrl_cluster(snap.l1_table_offset, snap.l1_size as u64)?; + .read_ctrl_cluster(snap.l1_table_offset, u64::from(snap.l1_size))?; // SAFETY: Upper limit of l1_size is decided by disk virtual size. snap_l1_table.resize(snap.l1_size as usize, 0); let cluster_size = self.header.cluster_size(); - let snap_l1_table_bytes = snap.l1_size as u64 * ENTRY_SIZE; + let snap_l1_table_bytes = u64::from(snap.l1_size) * ENTRY_SIZE; let snap_l1_table_clusters = bytes_to_clusters(snap_l1_table_bytes, cluster_size).unwrap(); let new_l1_table_offset = self.alloc_cluster(snap_l1_table_clusters, true)?; @@ -882,7 +882,7 @@ impl Qcow2Driver { // Free the snaphshot L1 table. let old_l1_table_clusters = - bytes_to_clusters(old_l1_size as u64 * ENTRY_SIZE, cluster_size).unwrap(); + bytes_to_clusters(u64::from(old_l1_size) * ENTRY_SIZE, cluster_size).unwrap(); self.refcount.update_refcount( old_l1_table_offset, old_l1_table_clusters, @@ -933,7 +933,7 @@ impl Qcow2Driver { // Free the snaphshot L1 table. let l1_table_clusters = - bytes_to_clusters(snap.l1_size as u64 * ENTRY_SIZE, cluster_size).unwrap(); + bytes_to_clusters(u64::from(snap.l1_size) * ENTRY_SIZE, cluster_size).unwrap(); self.refcount.update_refcount( snap.l1_table_offset, l1_table_clusters, @@ -972,7 +972,7 @@ impl Qcow2Driver { Ok(SnapshotInfo { id: snap.id.to_string(), name: snap.name.clone(), - vm_state_size: snap.vm_state_size as u64, + vm_state_size: u64::from(snap.vm_state_size), date_sec: snap.date_sec, date_nsec: snap.date_nsec, vm_clock_nsec: snap.vm_clock_nsec, @@ -993,7 +993,7 @@ impl Qcow2Driver { // Alloc cluster and copy L1 table for snapshot. let cluster_size = self.header.cluster_size(); - let l1_table_len = self.header.l1_size as u64 * ENTRY_SIZE; + let l1_table_len = u64::from(self.header.l1_size) * ENTRY_SIZE; let l1_table_clusters = bytes_to_clusters(l1_table_len, cluster_size).unwrap(); let new_l1_table_offset = self.alloc_cluster(l1_table_clusters, true)?; self.sync_aio @@ -1272,7 +1272,7 @@ impl Qcow2Driver { _ => snap.icount.to_string(), }; - let date = get_format_time(snap.date_sec as i64); + let date = get_format_time(i64::from(snap.date_sec)); let date_str = format!( "{:04}-{:02}-{:02} {:02}:{:02}:{:02}", date[0], date[1], date[2], date[3], date[4], date[5] @@ -1985,10 +1985,10 @@ mod test { .custom_flags(libc::O_CREAT | libc::O_TRUNC) .open(path) .unwrap(); - file.set_len(cluster_sz * 3 + header.l1_size as u64 * ENTRY_SIZE) + file.set_len(cluster_sz * 3 + u64::from(header.l1_size) * ENTRY_SIZE) .unwrap(); let zero_buf = - vec![0_u8; (cluster_sz * 3 + header.l1_size as u64 * ENTRY_SIZE) as usize]; + vec![0_u8; (cluster_sz * 3 + u64::from(header.l1_size) * ENTRY_SIZE) as usize]; file.write_all(&zero_buf).unwrap(); file.seek(SeekFrom::Start(0)).unwrap(); file.write_all(&header.to_vec()).unwrap(); diff --git a/block_backend/src/qcow2/refcount.rs b/block_backend/src/qcow2/refcount.rs index 0318d7e9..67c4c1e2 100644 --- a/block_backend/src/qcow2/refcount.rs +++ b/block_backend/src/qcow2/refcount.rs @@ -119,7 +119,7 @@ impl RefCount { self.refcount_table_offset = header.refcount_table_offset; self.refcount_table_clusters = header.refcount_table_clusters; self.refcount_table_size = - header.refcount_table_clusters as u64 * header.cluster_size() / ENTRY_SIZE; + u64::from(header.refcount_table_clusters) * header.cluster_size() / ENTRY_SIZE; self.refcount_blk_bits = header.cluster_bits + 3 - header.refcount_order; self.refcount_blk_size = 1 << self.refcount_blk_bits; self.cluster_bits = header.cluster_bits; @@ -141,7 +141,7 @@ impl RefCount { } fn cluster_in_rc_block(&self, cluster_index: u64) -> u64 { - cluster_index & (self.refcount_blk_size - 1) as u64 + cluster_index & u64::from(self.refcount_blk_size - 1) } /// Allocate a continuous space that is not referenced by existing refcount table @@ -182,7 +182,7 @@ impl RefCount { let (table, blocks) = refcount_metadata_size( clusters, self.cluster_size, - header.refcount_order as u64, + u64::from(header.refcount_order), true, )?; self.extend_refcount_table(header, start_idx, table, blocks)?; @@ -274,7 +274,7 @@ impl RefCount { // Free the old cluster of refcount table. self.update_refcount( old_table_offset, - old_table_clusters as u64, + u64::from(old_table_clusters), -1, true, &Qcow2DiscardType::Other, @@ -443,7 +443,7 @@ impl RefCount { ) })? }; - let cluster_idx = rt_idx * self.refcount_blk_size as u64 + rb_idx + i as u64; + let cluster_idx = rt_idx * u64::from(self.refcount_blk_size) + rb_idx + i as u64; if rc_value == 0 { if self.discard_passthrough.contains(discard_type) { // update refcount discard. @@ -460,7 +460,7 @@ impl RefCount { } for (idx, rc_value) in rb_vec.iter().enumerate() { - borrowed_entry.set_entry_map(rb_idx as usize + idx, *rc_value as u64)?; + borrowed_entry.set_entry_map(rb_idx as usize + idx, u64::from(*rc_value))?; } if !is_dirty { self.refcount_blk_cache.add_dirty_table(cache_entry.clone()); @@ -829,7 +829,7 @@ mod test { let free_cluster_index = 3 + ((header.l1_size * ENTRY_SIZE as u32 + cluster_sz as u32 - 1) >> cluster_bits); let addr = qcow2.alloc_cluster(1, true).unwrap(); - assert_eq!(addr, cluster_sz * free_cluster_index as u64); + assert_eq!(addr, cluster_sz * u64::from(free_cluster_index)); qcow2.flush().unwrap(); // Check if the refcount of the cluster is updated to the disk. let mut rc_value = [0_u8; 2]; @@ -837,7 +837,7 @@ mod test { .as_ref() .read_at( &mut rc_value, - cluster_sz * 2 + 2 * free_cluster_index as u64, + cluster_sz * 2 + 2 * u64::from(free_cluster_index), ) .unwrap(); assert_eq!(1, BigEndian::read_u16(&rc_value)); diff --git a/block_backend/src/qcow2/snapshot.rs b/block_backend/src/qcow2/snapshot.rs index b5ee4ba3..7a858e59 100644 --- a/block_backend/src/qcow2/snapshot.rs +++ b/block_backend/src/qcow2/snapshot.rs @@ -281,7 +281,7 @@ impl QcowSnapshot { // Snapshot Extra data. // vm_state_size_large is used for vm snapshot. // It's equal to vm_state_size which is also 0 in disk snapshot. - BigEndian::write_u64(&mut buf[40..48], self.vm_state_size as u64); + BigEndian::write_u64(&mut buf[40..48], u64::from(self.vm_state_size)); BigEndian::write_u64(&mut buf[48..56], self.disk_size); if self.extra_data_size == SNAPSHOT_EXTRA_DATA_LEN_24 as u32 { BigEndian::write_u64(&mut buf[56..64], self.icount); diff --git a/block_backend/src/qcow2/table.rs b/block_backend/src/qcow2/table.rs index 6554f3fb..c791cfa0 100644 --- a/block_backend/src/qcow2/table.rs +++ b/block_backend/src/qcow2/table.rs @@ -133,9 +133,9 @@ impl Qcow2Table { }; info!("Driver {} l2 cache size {}", conf.id, cache_size); let l2_table_cache: Qcow2Cache = Qcow2Cache::new(cache_size as usize); - self.cluster_bits = header.cluster_bits as u64; + self.cluster_bits = u64::from(header.cluster_bits); self.cluster_size = header.cluster_size(); - self.l2_bits = header.cluster_bits as u64 - ENTRY_BITS; + self.l2_bits = u64::from(header.cluster_bits) - ENTRY_BITS; self.l2_size = header.cluster_size() / ENTRY_SIZE; self.l2_table_cache = l2_table_cache; self.l1_table_offset = header.l1_table_offset; @@ -147,7 +147,7 @@ impl Qcow2Table { self.l1_table = self .sync_aio .borrow_mut() - .read_ctrl_cluster(self.l1_table_offset, self.l1_size as u64)?; + .read_ctrl_cluster(self.l1_table_offset, u64::from(self.l1_size))?; for l1_entry in &self.l1_table { let l1_entry_addr = l1_entry & L1_TABLE_OFFSET_MASK; self.l1_table_map.insert(l1_entry_addr, 1); diff --git a/block_backend/src/raw.rs b/block_backend/src/raw.rs index 056d0643..0edbc75d 100644 --- a/block_backend/src/raw.rs +++ b/block_backend/src/raw.rs @@ -56,12 +56,12 @@ impl RawDriver { // get_file_alignment() detects the alignment length by submitting IO to the first sector. // If this area is fallocated, misaligned IO will also return success, so we pre fill this area. pub fn alloc_first_block(&mut self, new_size: u64) -> Result<()> { - let write_size = if new_size < MAX_FILE_ALIGN as u64 { + let write_size = if new_size < u64::from(MAX_FILE_ALIGN) { SECTOR_SIZE } else { - MAX_FILE_ALIGN as u64 + u64::from(MAX_FILE_ALIGN) }; - let max_align = std::cmp::max(MAX_FILE_ALIGN as u64, host_page_size()) as usize; + let max_align = std::cmp::max(u64::from(MAX_FILE_ALIGN), host_page_size()) as usize; // SAFETY: allocate aligned memory and free it later. let align_buf = unsafe { libc::memalign(max_align, write_size as usize) }; if align_buf.is_null() { diff --git a/boot_loader/src/x86_64/direct_boot/gdt.rs b/boot_loader/src/x86_64/direct_boot/gdt.rs index 62c70be6..f5d95af3 100644 --- a/boot_loader/src/x86_64/direct_boot/gdt.rs +++ b/boot_loader/src/x86_64/direct_boot/gdt.rs @@ -119,9 +119,9 @@ pub fn setup_gdt(guest_mem: &Arc) -> Result { ]; let mut code_seg: kvm_segment = GdtEntry(gdt_table[GDT_ENTRY_BOOT_CS as usize]).into(); - code_seg.selector = GDT_ENTRY_BOOT_CS as u16 * 8; + code_seg.selector = u16::from(GDT_ENTRY_BOOT_CS) * 8; let mut data_seg: kvm_segment = GdtEntry(gdt_table[GDT_ENTRY_BOOT_DS as usize]).into(); - data_seg.selector = GDT_ENTRY_BOOT_DS as u16 * 8; + data_seg.selector = u16::from(GDT_ENTRY_BOOT_DS) * 8; write_gdt_table(&gdt_table[..], guest_mem)?; write_idt_value(0, guest_mem)?; diff --git a/boot_loader/src/x86_64/direct_boot/mod.rs b/boot_loader/src/x86_64/direct_boot/mod.rs index ddeede39..8aed3118 100644 --- a/boot_loader/src/x86_64/direct_boot/mod.rs +++ b/boot_loader/src/x86_64/direct_boot/mod.rs @@ -66,7 +66,7 @@ fn load_bzimage(kernel_image: &mut File) -> Result { return Err(e); } - let mut setup_size = boot_hdr.setup_sects as u64; + let mut setup_size = u64::from(boot_hdr.setup_sects); if setup_size == 0 { setup_size = 4; } @@ -107,8 +107,8 @@ fn load_kernel_image( let (boot_hdr, kernel_start, vmlinux_start) = if let Ok(hdr) = load_bzimage(&mut kernel_image) { ( hdr, - hdr.code32_start as u64 + BZIMAGE_BOOT_OFFSET, - hdr.code32_start as u64, + u64::from(hdr.code32_start) + BZIMAGE_BOOT_OFFSET, + u64::from(hdr.code32_start), ) } else { ( @@ -209,7 +209,7 @@ fn setup_kernel_cmdline( sys_mem.write( &mut config.kernel_cmdline.as_bytes(), GuestAddress(CMDLINE_START), - cmdline_len as u64, + u64::from(cmdline_len), )?; Ok(()) diff --git a/boot_loader/src/x86_64/standard_boot/elf.rs b/boot_loader/src/x86_64/standard_boot/elf.rs index 2817010a..3f852578 100644 --- a/boot_loader/src/x86_64/standard_boot/elf.rs +++ b/boot_loader/src/x86_64/standard_boot/elf.rs @@ -181,10 +181,11 @@ pub fn load_elf_kernel( let p_align = ph.p_align; let aligned_namesz = - round_up(note_hdr.namesz as u64, p_align).with_context(|| { + round_up(u64::from(note_hdr.namesz), p_align).with_context(|| { format!( "Overflows when align up: num 0x{:x}, alignment 0x{:x}", - note_hdr.namesz as u64, p_align, + u64::from(note_hdr.namesz), + p_align, ) })?; if note_hdr.type_ == XEN_ELFNOTE_PHYS32_ENTRY { @@ -195,11 +196,12 @@ pub fn load_elf_kernel( pvh_start_addr = Some(entry_addr); break; } else { - let aligned_descsz = - round_up(note_hdr.descsz as u64, p_align).with_context(|| { + let aligned_descsz = round_up(u64::from(note_hdr.descsz), p_align) + .with_context(|| { format!( "Overflows when align up, num 0x{:x}, alignment 0x{:x}", - note_hdr.descsz as u64, p_align, + u64::from(note_hdr.descsz), + p_align, ) })?; let tail_size = aligned_namesz + aligned_descsz; diff --git a/boot_loader/src/x86_64/standard_boot/mod.rs b/boot_loader/src/x86_64/standard_boot/mod.rs index 0c17349c..5ad697bf 100644 --- a/boot_loader/src/x86_64/standard_boot/mod.rs +++ b/boot_loader/src/x86_64/standard_boot/mod.rs @@ -59,7 +59,7 @@ fn load_kernel_image( header: &RealModeKernelHeader, fwcfg: &mut dyn FwCfgOps, ) -> Result> { - let mut setup_size = header.setup_sects as u64; + let mut setup_size = u64::from(header.setup_sects); if setup_size == 0 { setup_size = 4; } diff --git a/cpu/src/x86_64/mod.rs b/cpu/src/x86_64/mod.rs index 088d0eb0..9bf91313 100644 --- a/cpu/src/x86_64/mod.rs +++ b/cpu/src/x86_64/mod.rs @@ -221,9 +221,9 @@ impl X86CPUState { /// /// * `topology` - X86 CPU Topology pub fn set_cpu_topology(&mut self, topology: &X86CPUTopology) -> Result<()> { - self.nr_threads = topology.threads as u32; - self.nr_cores = topology.cores as u32; - self.nr_dies = topology.dies as u32; + self.nr_threads = u32::from(topology.threads); + self.nr_cores = u32::from(topology.cores); + self.nr_dies = u32::from(topology.dies); Ok(()) } @@ -271,17 +271,17 @@ impl X86CPUState { pub fn setup_sregs(&mut self, sregs: Sregs, boot_config: &X86CPUBootConfig) -> Result<()> { self.sregs = sregs; - self.sregs.cs.base = (boot_config.boot_selector as u64) << 4; + self.sregs.cs.base = u64::from(boot_config.boot_selector) << 4; self.sregs.cs.selector = boot_config.boot_selector; - self.sregs.ds.base = (boot_config.boot_selector as u64) << 4; + self.sregs.ds.base = u64::from(boot_config.boot_selector) << 4; self.sregs.ds.selector = boot_config.boot_selector; - self.sregs.es.base = (boot_config.boot_selector as u64) << 4; + self.sregs.es.base = u64::from(boot_config.boot_selector) << 4; self.sregs.es.selector = boot_config.boot_selector; - self.sregs.fs.base = (boot_config.boot_selector as u64) << 4; + self.sregs.fs.base = u64::from(boot_config.boot_selector) << 4; self.sregs.fs.selector = boot_config.boot_selector; - self.sregs.gs.base = (boot_config.boot_selector as u64) << 4; + self.sregs.gs.base = u64::from(boot_config.boot_selector) << 4; self.sregs.gs.selector = boot_config.boot_selector; - self.sregs.ss.base = (boot_config.boot_selector as u64) << 4; + self.sregs.ss.base = u64::from(boot_config.boot_selector) << 4; self.sregs.ss.selector = boot_config.boot_selector; if boot_config.prot64_mode { diff --git a/devices/src/acpi/power.rs b/devices/src/acpi/power.rs index 3a2a614c..8f066a80 100644 --- a/devices/src/acpi/power.rs +++ b/devices/src/acpi/power.rs @@ -356,7 +356,7 @@ impl AmlBuilder for PowerDev { acpi_bat_dev.append_child(method); let mut bst_pkg = AmlPackage::new(4); - bst_pkg.append_child(AmlInteger(ACPI_BATTERY_STATE_CHARGING as u64)); + bst_pkg.append_child(AmlInteger(u64::from(ACPI_BATTERY_STATE_CHARGING))); bst_pkg.append_child(AmlInteger(0xFFFFFFFF)); bst_pkg.append_child(AmlInteger(0xFFFFFFFF)); bst_pkg.append_child(AmlInteger(0xFFFFFFFF)); diff --git a/devices/src/interrupt_controller/aarch64/state.rs b/devices/src/interrupt_controller/aarch64/state.rs index 92609610..a099790b 100644 --- a/devices/src/interrupt_controller/aarch64/state.rs +++ b/devices/src/interrupt_controller/aarch64/state.rs @@ -280,7 +280,7 @@ impl GICv3 { ..Default::default() }; - let offset = dist.irq_base / (GIC_IRQ_INTERNAL as u64 / REGISTER_SIZE); + let offset = dist.irq_base / (u64::from(GIC_IRQ_INTERNAL) / REGISTER_SIZE); self.access_gic_distributor(GICD_IGROUPR + offset, &mut dist.gicd_igroupr, false)?; self.access_gic_distributor(GICD_ISENABLER + offset, &mut dist.gicd_isenabler, false)?; self.access_gic_distributor(dist.irq_base, &mut dist.line_level, false)?; @@ -290,7 +290,7 @@ impl GICv3 { // edge trigger for i in 0..NR_GICD_ICFGR { if ((i * GIC_IRQ_INTERNAL as usize / NR_GICD_ICFGR) as u64 + dist.irq_base) - > self.nr_irqs as u64 + > u64::from(self.nr_irqs) { break; } @@ -299,7 +299,7 @@ impl GICv3 { } for i in 0..NR_GICD_IPRIORITYR { - if (i as u64 * REGISTER_SIZE + dist.irq_base) > self.nr_irqs as u64 { + if (i as u64 * REGISTER_SIZE + dist.irq_base) > u64::from(self.nr_irqs) { break; } let offset = dist.irq_base + REGISTER_SIZE * i as u64; @@ -311,7 +311,7 @@ impl GICv3 { } for i in 0..NR_GICD_IROUTER { - if (i as u64 + dist.irq_base) > self.nr_irqs as u64 { + if (i as u64 + dist.irq_base) > u64::from(self.nr_irqs) { break; } let offset = dist.irq_base + i as u64; @@ -328,12 +328,12 @@ impl GICv3 { } fn set_dist(&self, mut dist: GICv3DistState) -> Result<()> { - let offset = dist.irq_base / (GIC_IRQ_INTERNAL as u64 / REGISTER_SIZE); + let offset = dist.irq_base / (u64::from(GIC_IRQ_INTERNAL) / REGISTER_SIZE); self.access_gic_distributor(GICD_ISENABLER + offset, &mut dist.gicd_isenabler, true)?; self.access_gic_distributor(GICD_IGROUPR + offset, &mut dist.gicd_igroupr, true)?; for i in 0..NR_GICD_IROUTER { - if (i as u64 + dist.irq_base) > self.nr_irqs as u64 { + if (i as u64 + dist.irq_base) > u64::from(self.nr_irqs) { break; } let offset = dist.irq_base + i as u64; @@ -349,7 +349,7 @@ impl GICv3 { // edge trigger for i in 0..NR_GICD_ICFGR { if ((i * GIC_IRQ_INTERNAL as usize / NR_GICD_ICFGR) as u64 + dist.irq_base) - > self.nr_irqs as u64 + > u64::from(self.nr_irqs) { break; } @@ -362,7 +362,7 @@ impl GICv3 { self.access_gic_distributor(GICD_ISACTIVER + offset, &mut dist.gicd_isactiver, true)?; for i in 0..NR_GICD_IPRIORITYR { - if (i as u64 * REGISTER_SIZE + dist.irq_base) > self.nr_irqs as u64 { + if (i as u64 * REGISTER_SIZE + dist.irq_base) > u64::from(self.nr_irqs) { break; } let offset = dist.irq_base + REGISTER_SIZE * i as u64; @@ -634,7 +634,7 @@ impl StateTransfer for GICv3 { .map_err(|e| MigrationError::GetGicRegsError("gicd_statusr", e.to_string()))?; for irq in (GIC_IRQ_INTERNAL..self.nr_irqs).step_by(32) { state.irq_dist[state.dist_len] = self - .get_dist(irq as u64) + .get_dist(u64::from(irq)) .map_err(|e| MigrationError::GetGicRegsError("dist", e.to_string()))?; state.dist_len += 1; } diff --git a/devices/src/legacy/fwcfg.rs b/devices/src/legacy/fwcfg.rs index 71258d93..d7a3d701 100644 --- a/devices/src/legacy/fwcfg.rs +++ b/devices/src/legacy/fwcfg.rs @@ -596,7 +596,7 @@ impl FwCfgCommon { &mem_space, GuestAddress(dma.address), data.as_slice(), - len as u64, + u64::from(len), ) .is_err() { @@ -619,7 +619,7 @@ impl FwCfgCommon { &mem_space, GuestAddress(dma.address), &entry.data[offset as usize..], - len as u64, + u64::from(len), ) .is_err() { @@ -629,7 +629,7 @@ impl FwCfgCommon { if is_write { let mut dma_read_error = false; let data = &mut entry.data[offset as usize..]; - if read_dma_memory(&mem_space, GuestAddress(dma.address), data, len as u64) + if read_dma_memory(&mem_space, GuestAddress(dma.address), data, u64::from(len)) .is_err() { dma_read_error = true; @@ -641,7 +641,7 @@ impl FwCfgCommon { if let Some(cb) = &entry.write_cb { cb.lock().unwrap().write_callback( data.to_vec(), - offset as u64, + u64::from(offset), len as usize, ); } @@ -650,7 +650,7 @@ impl FwCfgCommon { offset += len; } dma.length -= len; - dma.address += len as u64 + dma.address += u64::from(len) } self.cur_offset = offset; @@ -705,7 +705,7 @@ impl FwCfgCommon { fn dma_mem_read(&self, addr: u64, size: u32) -> Result { extract_u64( FW_CFG_DMA_SIGNATURE as u64, - ((8 - addr - size as u64) * 8) as u32, + ((8 - addr - u64::from(size)) * 8) as u32, size * 8, ) .with_context(|| "Failed to extract bits from u64") @@ -739,7 +739,7 @@ impl FwCfgCommon { && cur_offset < entry.data.len() as u32 { loop { - value = (value << 8) | entry.data[cur_offset as usize] as u64; + value = (value << 8) | u64::from(entry.data[cur_offset as usize]); cur_offset += 1; size -= 1; @@ -747,7 +747,7 @@ impl FwCfgCommon { break; } } - value <<= 8 * size as u64; + value <<= 8 * u64::from(size); } self.cur_offset = cur_offset; @@ -955,9 +955,9 @@ impl SysBusDevOps for FwCfgMem { fn write(&mut self, data: &[u8], _base: GuestAddress, offset: u64) -> bool { let size = data.len() as u32; let value = match size { - 1 => data[0] as u64, - 2 => BigEndian::read_u16(data) as u64, - 4 => BigEndian::read_u32(data) as u64, + 1 => u64::from(data[0]), + 2 => u64::from(BigEndian::read_u16(data)), + 4 => u64::from(BigEndian::read_u32(data)), 8 => BigEndian::read_u64(data), _ => 0, }; @@ -1127,9 +1127,9 @@ impl SysBusDevOps for FwCfgIO { } 4..=11 => { let value = match size { - 1 => data[0] as u64, - 2 => BigEndian::read_u16(data) as u64, - 4 => BigEndian::read_u32(data) as u64, + 1 => u64::from(data[0]), + 2 => u64::from(BigEndian::read_u16(data)), + 4 => u64::from(BigEndian::read_u32(data)), 8 => BigEndian::read_u64(data), _ => 0, }; diff --git a/devices/src/legacy/pflash.rs b/devices/src/legacy/pflash.rs index 5db5b9bc..67d8aacb 100644 --- a/devices/src/legacy/pflash.rs +++ b/devices/src/legacy/pflash.rs @@ -306,7 +306,7 @@ impl PFlash { } // Repeat data for PFlash device which supports x16-mode but works in x8-mode. for i in 1..self.max_device_width { - resp = deposit_u32(resp, 8 * i, 8, self.cfi_table[index as usize] as u32) + resp = deposit_u32(resp, 8 * i, 8, u32::from(self.cfi_table[index as usize])) .with_context(|| "Failed to deposit bits to u32")?; } } @@ -329,11 +329,11 @@ impl PFlash { } // Unwrap is safe, because after realize function, rom isn't none. let mr = self.rom.as_ref().unwrap(); - if offset + size as u64 > mr.size() { + if offset + u64::from(size) > mr.size() { return Err(anyhow!(LegacyError::PFlashWriteOverflow( mr.size(), offset, - size as u64 + u64::from(size) ))); } @@ -422,7 +422,7 @@ impl PFlash { trace::pflash_write("single byte program (0)".to_string(), cmd); } 0x20 => { - let offset_mask = offset & !(self.block_len as u64 - 1); + let offset_mask = offset & !(u64::from(self.block_len) - 1); trace::pflash_write_block_erase(offset, self.block_len); if !self.read_only { let all_one = vec![0xff_u8; self.block_len as usize]; @@ -618,7 +618,7 @@ impl PFlash { } self.status |= 0x80; if self.counter == 0 { - let mask: u64 = !(self.write_blk_size as u64 - 1); + let mask: u64 = !(u64::from(self.write_blk_size) - 1); trace::pflash_write("block write finished".to_string(), self.cmd); self.write_cycle = self.write_cycle.wrapping_add(1); if !self.read_only { @@ -740,15 +740,15 @@ impl SysBusDevOps for PFlash { // 0x70: Status Register. // 0xe8: Write block. // Just read status register, return every device status in bank. - ret = self.status as u32; + ret = u32::from(self.status); if self.device_width != 0 && data_len > self.device_width { let mut shift: u32 = self.device_width * 8; while shift + self.device_width * 8 <= data_len * 8 { - ret |= (self.status as u32) << shift; + ret |= u32::from(self.status) << shift; shift += self.device_width * 8; } } else if self.device_width == 0 && data_len > 2 { - ret |= (self.status as u32) << 16; + ret |= u32::from(self.status) << 16; } trace::pflash_read_status(ret); } @@ -782,7 +782,7 @@ impl SysBusDevOps for PFlash { // combine serval queries into one response. let mut i: u32 = 0; while i < data_len { - match self.query_devid(offset + (i * self.bank_width) as u64) { + match self.query_devid(offset + u64::from(i * self.bank_width)) { Err(e) => { error!("Failed to query devid {:?}", e); break; @@ -822,7 +822,7 @@ impl SysBusDevOps for PFlash { } else { let mut i: u32 = 0; while i < data_len { - match self.query_cfi(offset + (i * self.bank_width) as u64) { + match self.query_cfi(offset + u64::from(i * self.bank_width)) { Err(e) => { error!("Failed to query devid, {:?}", e); break; diff --git a/devices/src/legacy/pl011.rs b/devices/src/legacy/pl011.rs index b656b875..465173ba 100644 --- a/devices/src/legacy/pl011.rs +++ b/devices/src/legacy/pl011.rs @@ -97,7 +97,7 @@ impl PL011State { fn new() -> Self { PL011State { rfifo: [0; PL011_FIFO_SIZE], - flags: (PL011_FLAG_TXFE | PL011_FLAG_RXFE) as u32, + flags: u32::from(PL011_FLAG_TXFE | PL011_FLAG_RXFE), lcr: 0, rsr: 0, cr: 0x300, @@ -174,20 +174,20 @@ impl PL011 { impl InputReceiver for PL011 { fn receive(&mut self, data: &[u8]) { - self.state.flags &= !PL011_FLAG_RXFE as u32; + self.state.flags &= u32::from(!PL011_FLAG_RXFE); for val in data { let mut slot = (self.state.read_pos + self.state.read_count) as usize; if slot >= PL011_FIFO_SIZE { slot -= PL011_FIFO_SIZE; } - self.state.rfifo[slot] = *val as u32; + self.state.rfifo[slot] = u32::from(*val); self.state.read_count += 1; trace::pl011_receive(self.state.rfifo[slot], self.state.read_count); } // If in character-mode, or in FIFO-mode and FIFO is full, trigger the interrupt. if ((self.state.lcr & 0x10) == 0) || (self.state.read_count as usize == PL011_FIFO_SIZE) { - self.state.flags |= PL011_FLAG_RXFF as u32; + self.state.flags |= u32::from(PL011_FLAG_RXFF); trace::pl011_receive_full(); } if self.state.read_count >= self.state.read_trigger { @@ -254,7 +254,7 @@ impl SysBusDevOps for PL011 { // Data register. self.unpause_rx(); - self.state.flags &= !(PL011_FLAG_RXFF as u32); + self.state.flags &= !u32::from(PL011_FLAG_RXFF); let c = self.state.rfifo[self.state.read_pos as usize]; if self.state.read_count > 0 { @@ -265,7 +265,7 @@ impl SysBusDevOps for PL011 { } } if self.state.read_count == 0 { - self.state.flags |= PL011_FLAG_RXFE as u32; + self.state.flags |= u32::from(PL011_FLAG_RXFE); } if self.state.read_count == self.state.read_trigger - 1 { self.state.int_level &= !INT_RX; @@ -317,7 +317,7 @@ impl SysBusDevOps for PL011 { 0x3f8..=0x400 => { // Register 0xFE0~0xFFC is UART Peripheral Identification Registers // and PrimeCell Identification Registers. - ret = *self.state.id.get(((offset - 0xfe0) >> 2) as usize).unwrap() as u32; + ret = u32::from(*self.state.id.get(((offset - 0xfe0) >> 2) as usize).unwrap()); } _ => { error!("Failed to read pl011: Invalid offset 0x{:x}", offset); @@ -493,7 +493,7 @@ mod test { pl011_dev.receive(&data); assert_eq!(pl011_dev.state.read_count, data.len() as u32); for i in 0..data.len() { - assert_eq!(pl011_dev.state.rfifo[i], data[i] as u32); + assert_eq!(pl011_dev.state.rfifo[i], u32::from(data[i])); } assert_eq!(pl011_dev.state.flags, 0xC0); assert_eq!(pl011_dev.state.int_level, INT_RX); diff --git a/devices/src/legacy/pl031.rs b/devices/src/legacy/pl031.rs index a206a6fe..d6a97922 100644 --- a/devices/src/legacy/pl031.rs +++ b/devices/src/legacy/pl031.rs @@ -102,7 +102,7 @@ impl PL031 { /// Get current clock value. fn get_current_value(&self) -> u32 { - (self.base_time.elapsed().as_secs() as u128 + self.tick_offset as u128) as u32 + (u128::from(self.base_time.elapsed().as_secs()) + u128::from(self.tick_offset)) as u32 } } diff --git a/devices/src/legacy/rtc.rs b/devices/src/legacy/rtc.rs index 36934418..9fd4a089 100644 --- a/devices/src/legacy/rtc.rs +++ b/devices/src/legacy/rtc.rs @@ -95,7 +95,7 @@ fn bcd_to_bin(src: u8) -> u64 { return 0_u64; } - (((src >> 4) * 10) + (src & 0x0f)) as u64 + u64::from(((src >> 4) * 10) + (src & 0x0f)) } #[allow(clippy::upper_case_acronyms)] @@ -267,7 +267,7 @@ impl RTC { /// Get current clock value. fn get_current_value(&self) -> i64 { - (self.base_time.elapsed().as_secs() as i128 + self.tick_offset as i128) as i64 + (i128::from(self.base_time.elapsed().as_secs()) + i128::from(self.tick_offset)) as i64 } fn set_rtc_cmos(&mut self, tm: libc::tm) { diff --git a/devices/src/misc/ivshmem.rs b/devices/src/misc/ivshmem.rs index 2d132582..16ba7b22 100644 --- a/devices/src/misc/ivshmem.rs +++ b/devices/src/misc/ivshmem.rs @@ -202,7 +202,7 @@ impl Device for Ivshmem { self.dev_id .store(pci_bus.generate_dev_id(self.base.devfn), Ordering::Release); let dev = Arc::new(Mutex::new(self)); - locked_bus.attach_child(dev.lock().unwrap().base.devfn as u64, dev.clone())?; + locked_bus.attach_child(u64::from(dev.lock().unwrap().base.devfn), dev.clone())?; Ok(dev) } } diff --git a/devices/src/misc/pvpanic.rs b/devices/src/misc/pvpanic.rs index 366d0f45..23e200d0 100644 --- a/devices/src/misc/pvpanic.rs +++ b/devices/src/misc/pvpanic.rs @@ -143,7 +143,7 @@ impl PvPanicPci { } }); - matches!(cloned_pvpanic_write.handle_event(val as u32), Ok(())) + matches!(cloned_pvpanic_write.handle_event(u32::from(val)), Ok(())) }); let bar0_region_ops = RegionOps { @@ -220,7 +220,7 @@ impl Device for PvPanicPci { .unwrap() .dev_id .store(device_id, Ordering::Release); - locked_bus.attach_child(devfn as u64, dev.clone())?; + locked_bus.attach_child(u64::from(devfn), dev.clone())?; Ok(dev) } diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index 237d271a..54ac9341 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -146,7 +146,7 @@ pub fn get_record_authority() -> bool { impl ShmemStreamHeader { pub fn check(&self, last_end: u64) -> bool { - if (self.offset as u64) < last_end { + if u64::from(self.offset) < last_end { warn!( "Guest set bad offset {} exceeds last stream buffer end {}", self.offset, last_end @@ -221,7 +221,7 @@ impl ShmemStreamFmt { } else { AUDIO_SAMPLE_RATE_48KHZ }; - sample_rate * (self.rate % WINDOWS_SAMPLE_BASE_RATE) as u32 + sample_rate * u32::from(self.rate % WINDOWS_SAMPLE_BASE_RATE) } } @@ -334,8 +334,8 @@ impl StreamData { // The recording buffer is behind the playback buffer. Thereforce, the end position of // the playback buffer must be calculted to determine whether the two buffers overlap. if dir == ScreamDirection::Record && header.play.is_started != 0 { - last_end = header.play.offset as u64 - + header.play.chunk_size as u64 * header.play.max_chunks as u64; + last_end = u64::from(header.play.offset) + + u64::from(header.play.chunk_size) * u64::from(header.play.max_chunks); } if !stream_header.check(last_end) { @@ -357,10 +357,10 @@ impl StreamData { ) -> bool { self.audio_size = stream_header.chunk_size; self.audio_base = hva - + stream_header.offset as u64 - + (stream_header.chunk_size as u64) * (self.chunk_idx as u64); + + u64::from(stream_header.offset) + + u64::from(stream_header.chunk_size) * u64::from(self.chunk_idx); - if (self.audio_base + self.audio_size as u64) > (hva + shmem_size) { + if (self.audio_base + u64::from(self.audio_size)) > (hva + shmem_size) { error!( "Scream: wrong header: offset {} chunk_idx {} chunk_size {} max_chunks {}", stream_header.offset, @@ -429,7 +429,7 @@ impl StreamData { // of the address range during the header check. let header = &mut unsafe { std::slice::from_raw_parts_mut(hva as *mut ShmemHeader, 1) }[0]; let capt = &mut header.capt; - let addr = hva + capt.offset as u64; + let addr = hva + u64::from(capt.offset); interface.lock().unwrap().pre_receive(addr, capt); while capt.is_started != 0 { diff --git a/devices/src/pci/bus.rs b/devices/src/pci/bus.rs index 0ee81116..e4f730ab 100644 --- a/devices/src/pci/bus.rs +++ b/devices/src/pci/bus.rs @@ -126,7 +126,7 @@ impl PciBus { /// * `bus_num` - The bus number. /// * `devfn` - Slot number << 3 | Function number. pub fn get_device(&self, bus_num: u8, devfn: u8) -> Option>> { - if let Some(dev) = self.child_dev(devfn as u64) { + if let Some(dev) = self.child_dev(u64::from(devfn)) { return Some(dev.clone()); } debug!("Can't find device {}:{}", bus_num, devfn); @@ -232,7 +232,7 @@ impl PciBus { .unrealize() .with_context(|| format!("Failed to unrealize device {}", pci_dev.name()))?; - let devfn = pci_dev.pci_base().devfn as u64; + let devfn = u64::from(pci_dev.pci_base().devfn); let mut locked_bus = bus.lock().unwrap(); locked_bus .detach_child(devfn) @@ -260,7 +260,7 @@ impl PciBus { pub fn generate_dev_id(&self, devfn: u8) -> u16 { let bus_num = self.number(SECONDARY_BUS_NUM as usize); - ((bus_num as u16) << 8) | (devfn as u16) + (u16::from(bus_num) << 8) | u16::from(devfn) } pub fn update_dev_id(&self, devfn: u8, dev_id: &Arc) { diff --git a/devices/src/pci/config.rs b/devices/src/pci/config.rs index 2f041c4f..84bf48d1 100644 --- a/devices/src/pci/config.rs +++ b/devices/src/pci/config.rs @@ -433,11 +433,11 @@ impl PciConfig { write_mask: vec![0; config_size], write_clear_mask: vec![0; config_size], bars, - last_cap_end: PCI_CONFIG_HEAD_END as u16, + last_cap_end: u16::from(PCI_CONFIG_HEAD_END), last_ext_cap_offset: 0, last_ext_cap_end: PCI_CONFIG_SPACE_SIZE as u16, msix: None, - pci_express_cap_offset: PCI_CONFIG_HEAD_END as u16, + pci_express_cap_offset: u16::from(PCI_CONFIG_HEAD_END), intx: None, } } @@ -737,7 +737,7 @@ impl PciConfig { return BAR_SPACE_UNMAPPED; } let bar_val = le_read_u32(&self.config, offset).unwrap(); - return (bar_val & IO_BASE_ADDR_MASK) as u64; + return u64::from(bar_val & IO_BASE_ADDR_MASK); } if command & COMMAND_MEMORY_SPACE == 0 { @@ -747,7 +747,7 @@ impl PciConfig { RegionType::Io => BAR_SPACE_UNMAPPED, RegionType::Mem32Bit => { let bar_val = le_read_u32(&self.config, offset).unwrap(); - (bar_val & MEM_BASE_ADDR_MASK as u32) as u64 + u64::from(bar_val & MEM_BASE_ADDR_MASK as u32) } RegionType::Mem64Bit => { let bar_val = le_read_u64(&self.config, offset).unwrap(); @@ -1013,7 +1013,7 @@ impl PciConfig { le_write_u32( &mut self.config, offset, - id as u32 | (version << PCI_EXT_CAP_VER_SHIFT), + u32::from(id) | (version << PCI_EXT_CAP_VER_SHIFT), )?; if self.last_ext_cap_offset != 0 { let old_value = le_read_u32(&self.config, self.last_ext_cap_offset as usize)?; @@ -1040,7 +1040,7 @@ impl PciConfig { self.add_pci_cap(CapId::Pcie as u8, PCI_EXP_VER2_SIZEOF as usize)?; self.pci_express_cap_offset = cap_offset as u16; let mut offset: usize = cap_offset + PcieCap::CapReg as usize; - let pci_type = (dev_type << PCI_EXP_FLAGS_TYPE_SHIFT) as u16 & PCI_EXP_FLAGS_TYPE; + let pci_type = u16::from(dev_type << PCI_EXP_FLAGS_TYPE_SHIFT) & PCI_EXP_FLAGS_TYPE; le_write_u16( &mut self.config, offset, @@ -1065,7 +1065,7 @@ impl PciConfig { | PCI_EXP_LNKCAP_ASPMS_0S | PCI_EXP_LNKCAP_LBNC | PCI_EXP_LNKCAP_DLLLARC - | ((port_num as u32) << PCI_EXP_LNKCAP_PN_SHIFT), + | (u32::from(port_num) << PCI_EXP_LNKCAP_PN_SHIFT), )?; offset = cap_offset + PcieCap::LinkStat as usize; le_write_u16( @@ -1085,7 +1085,7 @@ impl PciConfig { | PCI_EXP_SLTCAP_PIP | PCI_EXP_SLTCAP_HPS | PCI_EXP_SLTCAP_HPC - | ((slot as u32) << PCI_EXP_SLTCAP_PSN_SHIFT), + | (u32::from(slot) << PCI_EXP_SLTCAP_PSN_SHIFT), )?; offset = cap_offset + PcieCap::SlotCtl as usize; le_write_u16( @@ -1184,8 +1184,8 @@ impl PciConfig { fn validate_bar_size(&self, bar_type: RegionType, size: u64) -> Result<()> { if !size.is_power_of_two() || (bar_type == RegionType::Io && size < MINIMUM_BAR_SIZE_FOR_PIO as u64) - || (bar_type == RegionType::Mem32Bit && size > u32::MAX as u64) - || (bar_type == RegionType::Io && size > u16::MAX as u64) + || (bar_type == RegionType::Mem32Bit && size > u64::from(u32::MAX)) + || (bar_type == RegionType::Io && size > u64::from(u16::MAX)) { return Err(anyhow!(PciError::InvalidConf( "Bar size of type ".to_string() + &bar_type.to_string(), @@ -1276,7 +1276,7 @@ mod tests { le_write_u32( &mut pci_config.config, BAR_0 as usize, - IO_BASE_ADDR_MASK | BAR_IO_SPACE as u32, + IO_BASE_ADDR_MASK | u32::from(BAR_IO_SPACE), ) .unwrap(); le_write_u32( @@ -1288,7 +1288,7 @@ mod tests { le_write_u64( &mut pci_config.config, BAR_0 as usize + 2 * REG_SIZE, - MEM_BASE_ADDR_MASK | (BAR_MEM_64BIT | BAR_PREFETCH) as u64, + MEM_BASE_ADDR_MASK | u64::from(BAR_MEM_64BIT | BAR_PREFETCH), ) .unwrap(); @@ -1298,7 +1298,7 @@ mod tests { { // I/O space access is enabled. le_write_u16(&mut pci_config.config, COMMAND as usize, COMMAND_IO_SPACE).unwrap(); - assert_eq!(pci_config.get_bar_address(0), IO_BASE_ADDR_MASK as u64); + assert_eq!(pci_config.get_bar_address(0), u64::from(IO_BASE_ADDR_MASK)); } assert_eq!(pci_config.get_bar_address(1), BAR_SPACE_UNMAPPED); assert_eq!(pci_config.get_bar_address(2), BAR_SPACE_UNMAPPED); @@ -1344,14 +1344,14 @@ mod tests { le_write_u32( &mut pci_config.config, BAR_0 as usize, - 2048_u32 | BAR_IO_SPACE as u32, + 2048_u32 | u32::from(BAR_IO_SPACE), ) .unwrap(); le_write_u32(&mut pci_config.config, BAR_0 as usize + REG_SIZE, 2048).unwrap(); le_write_u32( &mut pci_config.config, BAR_0 as usize + 2 * REG_SIZE, - 2048_u32 | BAR_MEM_64BIT as u32 | BAR_PREFETCH as u32, + 2048_u32 | u32::from(BAR_MEM_64BIT) | u32::from(BAR_PREFETCH), ) .unwrap(); le_write_u16( @@ -1401,14 +1401,14 @@ mod tests { le_write_u32( &mut pci_config.config, BAR_0 as usize, - 4096_u32 | BAR_IO_SPACE as u32, + 4096_u32 | u32::from(BAR_IO_SPACE), ) .unwrap(); le_write_u32(&mut pci_config.config, BAR_0 as usize + REG_SIZE, 4096).unwrap(); le_write_u32( &mut pci_config.config, BAR_0 as usize + 2 * REG_SIZE, - 4096_u32 | BAR_MEM_64BIT as u32 | BAR_PREFETCH as u32, + 4096_u32 | u32::from(BAR_MEM_64BIT) | u32::from(BAR_PREFETCH), ) .unwrap(); pci_config @@ -1436,7 +1436,7 @@ mod tests { // Capbility size is not multiple of DWORD. pci_config.add_pci_cap(0x12, 10).unwrap(); - assert_eq!(pci_config.last_cap_end, PCI_CONFIG_HEAD_END as u16 + 12); + assert_eq!(pci_config.last_cap_end, u16::from(PCI_CONFIG_HEAD_END) + 12); } #[test] @@ -1542,14 +1542,14 @@ mod tests { le_write_u32( &mut pci_config.config, BAR_0 as usize, - 2048 | BAR_IO_SPACE as u32, + 2048 | u32::from(BAR_IO_SPACE), ) .unwrap(); le_write_u32(&mut pci_config.config, BAR_0 as usize + REG_SIZE, 2048).unwrap(); le_write_u32( &mut pci_config.config, BAR_0 as usize + 2 * REG_SIZE, - 2048 | BAR_MEM_64BIT as u32 | BAR_PREFETCH as u32, + 2048 | u32::from(BAR_MEM_64BIT) | u32::from(BAR_PREFETCH), ) .unwrap(); le_write_u16( diff --git a/devices/src/pci/host.rs b/devices/src/pci/host.rs index 28481157..7f3b3d78 100644 --- a/devices/src/pci/host.rs +++ b/devices/src/pci/host.rs @@ -115,7 +115,7 @@ impl PciHost { let root_bus = self.child_bus().unwrap(); let locked_root_bus = root_bus.lock().unwrap(); if bus_num == 0 { - let dev = locked_root_bus.child_dev(devfn as u64)?; + let dev = locked_root_bus.child_dev(u64::from(devfn))?; return Some(dev.clone()); } @@ -123,7 +123,7 @@ impl PciHost { let child_bus = dev.lock().unwrap().child_bus(); if let Some(bus) = child_bus { if let Some(b) = PciBus::find_bus_by_num(&bus, bus_num) { - let dev = b.lock().unwrap().child_dev(devfn as u64)?.clone(); + let dev = b.lock().unwrap().child_dev(u64::from(devfn))?.clone(); return Some(dev); } } @@ -396,8 +396,8 @@ fn build_prt_for_aml(pci_bus: &mut AmlDevice, irq: i32) { (0..PCI_PIN_NUM).for_each(|pin| { let gsi = (pin + slot) % PCI_PIN_NUM; let mut pkg = AmlPackage::new(4); - pkg.append_child(AmlDWord((slot as u32) << 16 | 0xFFFF)); - pkg.append_child(AmlDWord(pin as u32)); + pkg.append_child(AmlDWord(u32::from(slot) << 16 | 0xFFFF)); + pkg.append_child(AmlDWord(u32::from(pin))); pkg.append_child(AmlName(format!("GSI{}", gsi))); pkg.append_child(AmlZero); prt_pkg.append_child(pkg); @@ -419,7 +419,7 @@ fn build_prt_for_aml(pci_bus: &mut AmlDevice, irq: i32) { AmlEdgeLevel::Level, AmlActiveLevel::High, AmlIntShare::Exclusive, - vec![irqs as u32], + vec![u32::from(irqs)], )); gsi.append_child(AmlNameDecl::new("_PRS", crs)); let mut crs = AmlResTemplate::new(); @@ -428,7 +428,7 @@ fn build_prt_for_aml(pci_bus: &mut AmlDevice, irq: i32) { AmlEdgeLevel::Level, AmlActiveLevel::High, AmlIntShare::Exclusive, - vec![irqs as u32], + vec![u32::from(irqs)], )); gsi.append_child(AmlNameDecl::new("_CRS", crs)); let method = AmlMethod::new("_SRS", 1, false); @@ -696,13 +696,13 @@ pub mod tests { let pci_dev = TestPciDevice::new("PCI device", 8, Arc::downgrade(&bus)); pci_dev.realize().unwrap(); - let addr: u64 = 8_u64 << ECAM_DEVFN_SHIFT | SECONDARY_BUS_NUM as u64; + let addr: u64 = 8_u64 << ECAM_DEVFN_SHIFT | u64::from(SECONDARY_BUS_NUM); let data = [1_u8]; (mmconfig_region_ops.write)(&data, GuestAddress(0), addr); let mut buf = [0_u8]; (mmconfig_region_ops.read)(&mut buf, GuestAddress(0), addr); assert_eq!(buf, data); - let addr: u64 = 16_u64 << ECAM_DEVFN_SHIFT | SECONDARY_BUS_NUM as u64; + let addr: u64 = 16_u64 << ECAM_DEVFN_SHIFT | u64::from(SECONDARY_BUS_NUM); let data = [2_u8]; (mmconfig_region_ops.write)(&data, GuestAddress(0), addr); let mut buf = [0_u8]; diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs index ccf1263a..20ba952c 100644 --- a/devices/src/pci/mod.rs +++ b/devices/src/pci/mod.rs @@ -202,7 +202,7 @@ pub trait PciDevOps: Device + Send { /// Device id to send MSI/MSI-X. fn set_dev_id(&self, bus_num: u8, devfn: u8) -> u16 { let bus_shift: u16 = 8; - ((bus_num as u16) << bus_shift) | (devfn as u16) + (u16::from(bus_num) << bus_shift) | u16::from(devfn) } /// Get the path of the PCI bus where the device resides. @@ -334,9 +334,9 @@ pub fn init_multifunction( parent_bus: Weak>, ) -> Result<()> { let mut header_type = - le_read_u16(config, HEADER_TYPE as usize)? & (!HEADER_TYPE_MULTIFUNC as u16); + le_read_u16(config, HEADER_TYPE as usize)? & u16::from(!HEADER_TYPE_MULTIFUNC); if multifunction { - header_type |= HEADER_TYPE_MULTIFUNC as u16; + header_type |= u16::from(HEADER_TYPE_MULTIFUNC); } le_write_u16(config, HEADER_TYPE as usize, header_type)?; @@ -348,7 +348,7 @@ pub fn init_multifunction( let bus = parent_bus.upgrade().unwrap(); PCI_BUS!(bus, locked_bus, pci_bus); if pci_func(devfn) != 0 { - let dev = pci_bus.child_dev(pci_devfn(slot, 0) as u64); + let dev = pci_bus.child_dev(u64::from(pci_devfn(slot, 0))); if dev.is_none() { return Ok(()); } @@ -356,7 +356,7 @@ pub fn init_multifunction( let mut data = vec![0_u8; 2]; PCI_BUS_DEVICE!(dev.unwrap(), locked_dev, pci_dev); pci_dev.read_config(HEADER_TYPE as usize, data.as_mut_slice()); - if LittleEndian::read_u16(&data) & HEADER_TYPE_MULTIFUNC as u16 == 0 { + if LittleEndian::read_u16(&data) & u16::from(HEADER_TYPE_MULTIFUNC) == 0 { // Function 0 should set multifunction bit. bail!( "PCI: single function device can't be populated in bus {} function {}.{}", @@ -374,7 +374,10 @@ pub fn init_multifunction( // If function 0 is set to single function, the rest function should be None. for func in 1..MAX_FUNC { - if pci_bus.child_dev(pci_devfn(slot, func) as u64).is_some() { + if pci_bus + .child_dev(u64::from(pci_devfn(slot, func))) + .is_some() + { bail!( "PCI: {}.0 indicates single function, but {}.{} is already populated", slot, @@ -390,7 +393,7 @@ pub fn init_multifunction( /// PCI-to-PCI bridge specification 9.1: Interrupt routing. pub fn swizzle_map_irq(devfn: u8, pin: u8) -> u32 { let pci_slot = devfn >> 3 & 0x1f; - ((pci_slot + pin) % PCI_PIN_NUM) as u32 + u32::from((pci_slot + pin) % PCI_PIN_NUM) } #[cfg(test)] @@ -422,7 +425,7 @@ mod tests { gen_base_func!(device_base, device_base_mut, DeviceBase, base.base); fn realize(mut self) -> Result>> { - let devfn = self.base.devfn as u64; + let devfn = u64::from(self.base.devfn); self.init_write_mask(false)?; self.init_write_clear_mask(false)?; diff --git a/devices/src/pci/msix.rs b/devices/src/pci/msix.rs index 7f960f44..428c4e83 100644 --- a/devices/src/pci/msix.rs +++ b/devices/src/pci/msix.rs @@ -188,7 +188,7 @@ impl Msix { fn is_vector_pending(&self, vector: u16) -> bool { let offset: usize = vector as usize / 64; - let pending_bit: u64 = 1 << (vector as u64 % 64); + let pending_bit: u64 = 1 << (u64::from(vector) % 64); let value = le_read_u64(&self.pba, offset).unwrap(); if value & pending_bit > 0 { return true; @@ -198,14 +198,14 @@ impl Msix { fn set_pending_vector(&mut self, vector: u16) { let offset: usize = vector as usize / 64; - let pending_bit: u64 = 1 << (vector as u64 % 64); + let pending_bit: u64 = 1 << (u64::from(vector) % 64); let old_val = le_read_u64(&self.pba, offset).unwrap(); le_write_u64(&mut self.pba, offset, old_val | pending_bit).unwrap(); } fn clear_pending_vector(&mut self, vector: u16) { let offset: usize = vector as usize / 64; - let pending_bit: u64 = !(1 << (vector as u64 % 64)); + let pending_bit: u64 = !(1 << (u64::from(vector) % 64)); let old_val = le_read_u64(&self.pba, offset).unwrap(); le_write_u64(&mut self.pba, offset, old_val & pending_bit).unwrap(); } @@ -231,7 +231,7 @@ impl Msix { msg_data: entry.data, masked: false, #[cfg(target_arch = "aarch64")] - dev_id: self.dev_id.load(Ordering::Acquire) as u32, + dev_id: u32::from(self.dev_id.load(Ordering::Acquire)), }; let irq_manager = self.msi_irq_manager.as_ref().unwrap(); @@ -261,7 +261,7 @@ impl Msix { msg_data: entry.data, masked: false, #[cfg(target_arch = "aarch64")] - dev_id: self.dev_id.load(Ordering::Acquire) as u32, + dev_id: u32::from(self.dev_id.load(Ordering::Acquire)), }; let irq_manager = self.msi_irq_manager.as_ref().unwrap(); @@ -407,11 +407,11 @@ impl Msix { msg_data: msg.data, masked: false, #[cfg(target_arch = "aarch64")] - dev_id: dev_id as u32, + dev_id: u32::from(dev_id), }; let irq_manager = self.msi_irq_manager.as_ref().unwrap(); - if let Err(e) = irq_manager.trigger(None, msix_vector, dev_id as u32) { + if let Err(e) = irq_manager.trigger(None, msix_vector, u32::from(dev_id)) { error!("Send msix error: {:?}", e); }; } @@ -517,7 +517,7 @@ impl MigrationHook for Msix { msg_data: msg.data, masked: false, #[cfg(target_arch = "aarch64")] - dev_id: self.dev_id.load(Ordering::Acquire) as u32, + dev_id: u32::from(self.dev_id.load(Ordering::Acquire)), }; let irq_manager = self.msi_irq_manager.as_ref().unwrap(); irq_manager.allocate_irq(msi_vector)?; @@ -554,7 +554,7 @@ pub fn init_msix( ) -> Result<()> { let config = &mut pcidev_base.config; let parent_bus = pcidev_base.base.parent.as_ref().unwrap(); - if vector_nr == 0 || vector_nr > MSIX_TABLE_SIZE_MAX as u32 + 1 { + if vector_nr == 0 || vector_nr > u32::from(MSIX_TABLE_SIZE_MAX) + 1 { bail!( "invalid msix vectors, which should be in [1, {}]", MSIX_TABLE_SIZE_MAX + 1 @@ -570,8 +570,8 @@ pub fn init_msix( MSIX_CAP_FUNC_MASK | MSIX_CAP_ENABLE, )?; offset = msix_cap_offset + MSIX_CAP_TABLE as usize; - let table_size = vector_nr * MSIX_TABLE_ENTRY_SIZE as u32; - let pba_size = ((round_up(vector_nr as u64, 64).unwrap() / 64) * 8) as u32; + let table_size = vector_nr * u32::from(MSIX_TABLE_ENTRY_SIZE); + let pba_size = ((round_up(u64::from(vector_nr), 64).unwrap() / 64) * 8) as u32; let (table_offset, pba_offset) = offset_opt.unwrap_or((0, table_size)); if ranges_overlap( table_offset as usize, @@ -607,19 +607,19 @@ pub fn init_msix( msix.clone(), region, dev_id, - table_offset as u64, - pba_offset as u64, + u64::from(table_offset), + u64::from(pba_offset), )?; } else { - let mut bar_size = ((table_size + pba_size) as u64).next_power_of_two(); + let mut bar_size = u64::from(table_size + pba_size).next_power_of_two(); bar_size = max(bar_size, MINIMUM_BAR_SIZE_FOR_MMIO as u64); let region = Region::init_container_region(bar_size, "Msix_region"); Msix::register_memory_region( msix.clone(), ®ion, dev_id, - table_offset as u64, - pba_offset as u64, + u64::from(table_offset), + u64::from(pba_offset), )?; config.register_bar(bar_id, region, RegionType::Mem32Bit, false, bar_size)?; } @@ -653,7 +653,7 @@ mod tests { assert!(init_msix( &mut base, 0, - MSIX_TABLE_SIZE_MAX as u32 + 2, + u32::from(MSIX_TABLE_SIZE_MAX) + 2, Arc::new(AtomicU16::new(0)), None, None, @@ -666,7 +666,7 @@ mod tests { init_msix(&mut base, 1, 2, Arc::new(AtomicU16::new(0)), None, None).unwrap(); let pci_config = base.config; let msix_cap_start = 64_u8; - assert_eq!(pci_config.last_cap_end, 64 + MSIX_CAP_SIZE as u16); + assert_eq!(pci_config.last_cap_end, 64 + u16::from(MSIX_CAP_SIZE)); // Capabilities pointer assert_eq!(pci_config.config[0x34], msix_cap_start); assert_eq!( @@ -690,7 +690,7 @@ mod tests { fn test_mask_vectors() { let nr_vector = 2_u32; let mut msix = Msix::new( - nr_vector * MSIX_TABLE_ENTRY_SIZE as u32, + nr_vector * u32::from(MSIX_TABLE_ENTRY_SIZE), 64, 64, Arc::new(AtomicU16::new(0)), @@ -712,7 +712,7 @@ mod tests { #[test] fn test_pending_vectors() { let mut msix = Msix::new( - MSIX_TABLE_ENTRY_SIZE as u32, + u32::from(MSIX_TABLE_ENTRY_SIZE), 64, 64, Arc::new(AtomicU16::new(0)), @@ -728,7 +728,7 @@ mod tests { #[test] fn test_get_message() { let mut msix = Msix::new( - MSIX_TABLE_ENTRY_SIZE as u32, + u32::from(MSIX_TABLE_ENTRY_SIZE), 64, 64, Arc::new(AtomicU16::new(0)), diff --git a/devices/src/pci/root_port.rs b/devices/src/pci/root_port.rs index 00bffd49..16808344 100644 --- a/devices/src/pci/root_port.rs +++ b/devices/src/pci/root_port.rs @@ -180,7 +180,7 @@ impl RootPort { if locked_msix.enabled { locked_msix.notify(0, self.dev_id.load(Ordering::Acquire)); } else if self.base.config.config[INTERRUPT_PIN as usize] != 0 { - intx.lock().unwrap().notify(self.hpev_notified as u8); + intx.lock().unwrap().notify(u8::from(self.hpev_notified)); } } @@ -277,7 +277,7 @@ impl RootPort { (cap_offset + PCI_EXP_SLTSTA) as usize, ) .unwrap(); - let val: u16 = data[0] as u16 + ((data[1] as u16) << 8); + let val: u16 = u16::from(data[0]) + (u16::from(data[1]) << 8); if (val & !old_status & PCI_EXP_SLOTSTA_EVENTS) != 0 { let tmpstat = (status & !PCI_EXP_SLOTSTA_EVENTS) | (old_status & PCI_EXP_SLOTSTA_EVENTS); @@ -400,7 +400,8 @@ impl Device for RootPort { PcieDevType::RootPort as u8, )?; - self.dev_id.store(self.base.devfn as u16, Ordering::SeqCst); + self.dev_id + .store(u16::from(self.base.devfn), Ordering::SeqCst); init_msix(&mut self.base, 0, 1, self.dev_id.clone(), None, None)?; init_intx( @@ -433,7 +434,7 @@ impl Device for RootPort { child_pci_bus.base.parent = Some(Arc::downgrade(&root_port) as Weak>); child_pci_bus.hotplug_controller = Some(Arc::downgrade(&root_port) as Weak>); - parent_pci_bus.attach_child(locked_root_port.base.devfn as u64, root_port.clone())?; + parent_pci_bus.attach_child(u64::from(locked_root_port.base.devfn), root_port.clone())?; // Need to drop locked_root_port in order to register root_port instance. drop(locked_root_port); MigrationManager::register_device_instance( @@ -653,7 +654,7 @@ impl HotplugOps for RootPort { bail!("Don't support hot-unplug!"); } PCI_BUS_DEVICE!(dev, locked_dev, pci_dev); - let devfn = pci_dev.pci_base().devfn as u64; + let devfn = u64::from(pci_dev.pci_base().devfn); pci_dev.unrealize()?; let child_bus = self.child_bus().unwrap(); child_bus.lock().unwrap().detach_child(devfn)?; diff --git a/devices/src/scsi/bus.rs b/devices/src/scsi/bus.rs index cc7c7269..277b09ab 100644 --- a/devices/src/scsi/bus.rs +++ b/devices/src/scsi/bus.rs @@ -373,7 +373,7 @@ pub enum ScsiXferMode { // Convert from (target, lun) to unique address in BusBase. pub fn get_scsi_key(target: u8, lun: u16) -> u64 { - (target as u64) << TARGET_ID_SHIFT | lun as u64 + u64::from(target) << TARGET_ID_SHIFT | u64::from(lun) } // Convert from unique address in BusBase to (target, lun). @@ -547,7 +547,7 @@ impl ScsiRequest { .with_context(|| "Too large offset IO!")?; offset - .checked_add(datalen as u64) + .checked_add(u64::from(datalen)) .filter(|&off| off <= disk_size) .with_context(|| { format!( @@ -802,8 +802,8 @@ pub fn scsi_cdb_xfer(cdb: &[u8; SCSI_CMD_BUF_SIZE], dev: Arc>) // 010b | Bytes[7-8]. | // 100b | Bytes[10-13]. | // 101b | Bytes[6-9]. | - 0 => cdb[4] as i32, - 1 | 2 => BigEndian::read_u16(&cdb[7..]) as i32, + 0 => i32::from(cdb[4]), + 1 | 2 => i32::from(BigEndian::read_u16(&cdb[7..])), 4 => BigEndian::read_u32(&cdb[10..]) as i32, 5 => BigEndian::read_u32(&cdb[6..]) as i32, _ => -1, @@ -841,8 +841,8 @@ fn scsi_cdb_lba(cdb: &[u8; SCSI_CMD_BUF_SIZE]) -> i64 { // 010b | Bytes[2-5]. | // 100b | Bytes[2-9]. | // 101b | Bytes[2-5]. | - 0 => (BigEndian::read_u32(&cdb[0..]) & 0x1fffff) as i64, - 1 | 2 | 5 => BigEndian::read_u32(&cdb[2..]) as i64, + 0 => i64::from(BigEndian::read_u32(&cdb[0..]) & 0x1fffff), + 1 | 2 | 5 => i64::from(BigEndian::read_u32(&cdb[2..])), 4 => BigEndian::read_u64(&cdb[2..]) as i64, _ => -1, } @@ -992,7 +992,7 @@ fn scsi_command_emulate_vpd_page( outbuf[4] = 1; let max_xfer_length: u32 = u32::MAX / 512; BigEndian::write_u32(&mut outbuf[8..12], max_xfer_length); - BigEndian::write_u64(&mut outbuf[36..44], max_xfer_length as u64); + BigEndian::write_u64(&mut outbuf[36..44], u64::from(max_xfer_length)); buflen = outbuf.len(); } 0xb1 => { @@ -1436,7 +1436,7 @@ fn scsi_command_emulate_service_action_in_16( let block_size = scsi_dev.block_size; let mut outbuf: Vec = vec![0; 32]; let mut nb_sectors = scsi_dev.disk_sectors; - nb_sectors /= (block_size / DEFAULT_SECTOR_SIZE) as u64; + nb_sectors /= u64::from(block_size / DEFAULT_SECTOR_SIZE); nb_sectors -= 1; drop(locked_dev); @@ -1577,7 +1577,7 @@ fn scsi_command_emulate_get_configuration( // Bytes[4-5]: Reserved. // Bytes[6-7]: Current Profile. BigEndian::write_u32(&mut outbuf[0..4], 36); - let current = if scsi_dev.disk_sectors > CD_MAX_SECTORS as u64 { + let current = if scsi_dev.disk_sectors > u64::from(CD_MAX_SECTORS) { GC_PROFILE_DVD_ROM } else { GC_PROFILE_CD_ROM @@ -1600,9 +1600,9 @@ fn scsi_command_emulate_get_configuration( outbuf[10] = 0x03; outbuf[11] = 8; BigEndian::write_u16(&mut outbuf[12..14], GC_PROFILE_CD_ROM); - outbuf[14] |= (current == GC_PROFILE_CD_ROM) as u8; + outbuf[14] |= u8::from(current == GC_PROFILE_CD_ROM); BigEndian::write_u16(&mut outbuf[16..18], GC_PROFILE_DVD_ROM); - outbuf[18] |= (current == GC_PROFILE_DVD_ROM) as u8; + outbuf[18] |= u8::from(current == GC_PROFILE_DVD_ROM); // Bytes[8-n]: Feature Descriptor(s): // Bytes[20-31]: Feature 1: Core Feature: diff --git a/devices/src/smbios/smbios_table.rs b/devices/src/smbios/smbios_table.rs index f476025b..2751e6c9 100644 --- a/devices/src/smbios/smbios_table.rs +++ b/devices/src/smbios/smbios_table.rs @@ -866,11 +866,11 @@ impl SmbiosTable { table4.header.core_count = mach_cfg.nr_cores; table4.header.core_enabled = mach_cfg.nr_cores; - table4.header.core_count2 = (mach_cfg.nr_cores as u16).to_le_bytes(); - table4.header.core_enabled2 = (mach_cfg.nr_cores as u16).to_le_bytes(); + table4.header.core_count2 = u16::from(mach_cfg.nr_cores).to_le_bytes(); + table4.header.core_enabled2 = u16::from(mach_cfg.nr_cores).to_le_bytes(); table4.header.thread_count = mach_cfg.nr_threads; - table4.header.thread_count2 = (mach_cfg.nr_threads as u16).to_le_bytes(); + table4.header.thread_count2 = u16::from(mach_cfg.nr_threads).to_le_bytes(); table4.finish(); self.entries.append(&mut table4.header.as_bytes().to_vec()); @@ -946,7 +946,7 @@ impl SmbiosTable { let start_kb = start / 1024; let end_kb = (start + size - 1) / 1024; - if start_kb < u32::MAX as u64 && end_kb < u32::MAX as u64 { + if start_kb < u64::from(u32::MAX) && end_kb < u64::from(u32::MAX) { table19.header.starting_address = (start_kb as u32).to_le_bytes(); table19.header.ending_address = (end_kb as u32).to_le_bytes(); } else { @@ -994,7 +994,7 @@ impl SmbiosTable { let smbios_sockets = mach_cfg.nr_cpus / (mach_cfg.nr_cores * mach_cfg.nr_threads); for i in 0..smbios_sockets { - self.build_type4(smbios.type4.clone(), i as u16, mach_cfg); + self.build_type4(smbios.type4.clone(), u16::from(i), mach_cfg); } let mem_num = ((mach_cfg.mem_config.mem_size + 16 * GB_SIZE - 1) / (16 * GB_SIZE)) as u16; self.build_type16(mach_cfg.mem_config.mem_size, mem_num); diff --git a/devices/src/usb/descriptor.rs b/devices/src/usb/descriptor.rs index 3864464d..0f56753b 100644 --- a/devices/src/usb/descriptor.rs +++ b/devices/src/usb/descriptor.rs @@ -257,7 +257,7 @@ impl UsbDescriptor { let mut ifs = self.get_interfaces_descriptor(conf.interfaces.as_ref())?; config_desc.wTotalLength = - config_desc.bLength as u16 + iads.len() as u16 + ifs.len() as u16; + u16::from(config_desc.bLength) + iads.len() as u16 + ifs.len() as u16; let mut buf = config_desc.as_bytes().to_vec(); buf.append(&mut iads); @@ -369,7 +369,7 @@ impl UsbDescriptor { } fn get_bos_descriptor(&self, speed: u32) -> Result> { - let mut total = USB_DT_BOS_SIZE as u16; + let mut total = u16::from(USB_DT_BOS_SIZE); let mut cap = Vec::new(); let mut cap_num = 0; @@ -483,7 +483,7 @@ impl UsbDescriptorOps for UsbDeviceBase { for i in 0..num as usize { if desc.configs[i].config_desc.bConfigurationValue == v { self.descriptor.interface_number = - desc.configs[i].config_desc.bNumInterfaces as u32; + u32::from(desc.configs[i].config_desc.bNumInterfaces); self.descriptor.configuration_selected = Some(desc.configs[i].clone()); found = true; } diff --git a/devices/src/usb/hid.rs b/devices/src/usb/hid.rs index 5706cdda..513005ef 100644 --- a/devices/src/usb/hid.rs +++ b/devices/src/usb/hid.rs @@ -264,7 +264,7 @@ impl Hid { self.num -= 1; let keycode = self.keyboard.keycodes[slot as usize]; let key = keycode & 0x7f; - let index = key | ((self.keyboard.modifiers as u32 & (1 << 8)) >> 1); + let index = key | ((u32::from(self.keyboard.modifiers) & (1 << 8)) >> 1); let hid_code = HID_CODE[index as usize]; self.keyboard.modifiers &= !(1 << 8); trace::usb_convert_to_hid_code(&hid_code, &index, &key); diff --git a/devices/src/usb/keyboard.rs b/devices/src/usb/keyboard.rs index 4c6847a3..418d6043 100644 --- a/devices/src/usb/keyboard.rs +++ b/devices/src/usb/keyboard.rs @@ -152,14 +152,14 @@ impl KeyboardOpts for UsbKeyboardAdapter { let mut scan_codes = Vec::new(); let mut keycode = keycode; if keycode & SCANCODE_GREY != 0 { - scan_codes.push(SCANCODE_EMUL0 as u32); + scan_codes.push(u32::from(SCANCODE_EMUL0)); keycode &= !SCANCODE_GREY; } if !down { keycode |= SCANCODE_UP; } - scan_codes.push(keycode as u32); + scan_codes.push(u32::from(keycode)); let mut locked_kbd = self.usb_kbd.lock().unwrap(); if scan_codes.len() as u32 + locked_kbd.hid.num > QUEUE_LENGTH { diff --git a/devices/src/usb/mod.rs b/devices/src/usb/mod.rs index f8dc2f90..f5c14996 100644 --- a/devices/src/usb/mod.rs +++ b/devices/src/usb/mod.rs @@ -104,7 +104,7 @@ impl UsbEndpoint { _ => 1, }; - self.max_packet_size = size as u32 * micro_frames; + self.max_packet_size = u32::from(size) * micro_frames; } } @@ -208,9 +208,9 @@ impl UsbDeviceBase { packet: &mut UsbPacket, device_req: &UsbDeviceRequest, ) -> Result { - let value = device_req.value as u32; - let index = device_req.index as u32; - let length = device_req.length as u32; + let value = u32::from(device_req.value); + let index = u32::from(device_req.index); + let length = u32::from(device_req.length); match device_req.request_type { USB_DEVICE_IN_REQUEST => match device_req.request { USB_REQUEST_GET_DESCRIPTOR => { @@ -473,7 +473,7 @@ pub fn notify_controller(dev: &Arc>, ep_id: u8) -> Result<( locked_xhci.port_notify(&usb_port, PORTSC_PLC)?; } } - if let Err(e) = locked_xhci.wakeup_endpoint(slot_id as u32, ep_id as u32, 0) { + if let Err(e) = locked_xhci.wakeup_endpoint(u32::from(slot_id), u32::from(ep_id), 0) { error!("Failed to wakeup endpoint {:?}", e); } Ok(()) @@ -607,7 +607,7 @@ mod tests { let buf = [0_u8; 10]; let hva = buf.as_ptr() as u64; let mut packet = UsbPacket::default(); - packet.pid = USB_TOKEN_IN as u32; + packet.pid = u32::from(USB_TOKEN_IN); packet.iovecs.push(Iovec::new(hva, 4)); packet.iovecs.push(Iovec::new(hva + 4, 2)); let mut data: Vec = vec![1, 2, 3, 4, 5, 6]; @@ -621,7 +621,7 @@ mod tests { let buf = [0_u8; 10]; let hva = buf.as_ptr() as u64; let mut packet = UsbPacket::default(); - packet.pid = USB_TOKEN_IN as u32; + packet.pid = u32::from(USB_TOKEN_IN); packet.iovecs.push(Iovec::new(hva, 4)); let mut data: Vec = vec![1, 2, 3, 4, 5, 6]; @@ -635,7 +635,7 @@ mod tests { let buf = [0_u8; 10]; let hva = buf.as_ptr() as u64; let mut packet = UsbPacket::default(); - packet.pid = USB_TOKEN_IN as u32; + packet.pid = u32::from(USB_TOKEN_IN); packet.iovecs.push(Iovec::new(hva, 4)); let mut data: Vec = vec![1, 2, 3, 4, 5, 6]; @@ -649,7 +649,7 @@ mod tests { let buf = [0_u8; 10]; let hva = buf.as_ptr() as u64; let mut packet = UsbPacket::default(); - packet.pid = USB_TOKEN_IN as u32; + packet.pid = u32::from(USB_TOKEN_IN); packet.iovecs.push(Iovec::new(hva, 10)); let mut data: Vec = vec![1, 2, 3, 4, 5, 6]; @@ -663,7 +663,7 @@ mod tests { let buf: [u8; 10] = [1, 2, 3, 4, 5, 6, 0, 0, 0, 0]; let hva = buf.as_ptr() as u64; let mut packet = UsbPacket::default(); - packet.pid = USB_TOKEN_OUT as u32; + packet.pid = u32::from(USB_TOKEN_OUT); packet.iovecs.push(Iovec::new(hva, 4)); packet.iovecs.push(Iovec::new(hva + 4, 2)); @@ -678,7 +678,7 @@ mod tests { let buf: [u8; 10] = [1, 2, 3, 4, 5, 6, 0, 0, 0, 0]; let hva = buf.as_ptr() as u64; let mut packet = UsbPacket::default(); - packet.pid = USB_TOKEN_OUT as u32; + packet.pid = u32::from(USB_TOKEN_OUT); packet.iovecs.push(Iovec::new(hva, 4)); packet.iovecs.push(Iovec::new(hva + 4, 2)); @@ -693,7 +693,7 @@ mod tests { let buf: [u8; 10] = [1, 2, 3, 4, 5, 6, 0, 0, 0, 0]; let hva = buf.as_ptr() as u64; let mut packet = UsbPacket::default(); - packet.pid = USB_TOKEN_OUT as u32; + packet.pid = u32::from(USB_TOKEN_OUT); packet.iovecs.push(Iovec::new(hva, 4)); let mut data = [0_u8; 10]; @@ -707,7 +707,7 @@ mod tests { let buf: [u8; 10] = [1, 2, 3, 4, 5, 6, 0, 0, 0, 0]; let hva = buf.as_ptr() as u64; let mut packet = UsbPacket::default(); - packet.pid = USB_TOKEN_OUT as u32; + packet.pid = u32::from(USB_TOKEN_OUT); packet.iovecs.push(Iovec::new(hva, 6)); let mut data = [0_u8; 2]; diff --git a/devices/src/usb/storage.rs b/devices/src/usb/storage.rs index e8765ea9..986e6741 100644 --- a/devices/src/usb/storage.rs +++ b/devices/src/usb/storage.rs @@ -382,7 +382,7 @@ impl UsbStorage { match self.state.mode { UsbMsdMode::Cbw => { - if packet.get_iovecs_size() < CBW_SIZE as u64 { + if packet.get_iovecs_size() < u64::from(CBW_SIZE) { bail!("Bad CBW size {}", packet.get_iovecs_size()); } self.state.check_cdb_exist(false)?; @@ -436,7 +436,7 @@ impl UsbStorage { bail!("Not supported usb packet(Token_in and data_out)."); } UsbMsdMode::Csw => { - if packet.get_iovecs_size() < CSW_SIZE as u64 { + if packet.get_iovecs_size() < u64::from(CSW_SIZE) { bail!("Bad CSW size {}", packet.get_iovecs_size()); } self.state.check_cdb_exist(true)?; diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index 2114f607..4dc652a9 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -685,8 +685,8 @@ impl XhciEvent { XhciTRB { parameter: self.ptr, status: self.length | (self.ccode as u32) << EVENT_TRB_CCODE_SHIFT, - control: (self.slot_id as u32) << EVENT_TRB_SLOT_ID_SHIFT - | (self.ep_id as u32) << EVENT_TRB_EP_ID_SHIFT + control: u32::from(self.slot_id) << EVENT_TRB_SLOT_ID_SHIFT + | u32::from(self.ep_id) << EVENT_TRB_EP_ID_SHIFT | self.flags | (self.trb_type as u32) << TRB_TYPE_SHIFT, addr: 0, @@ -1056,7 +1056,7 @@ impl XhciDevice { pub fn stop(&mut self) { trace::usb_xhci_stop(); self.oper.set_usb_status_flag(USB_STS_HCH); - self.oper.cmd_ring_ctrl &= !(CMD_RING_CTRL_CRR as u64); + self.oper.cmd_ring_ctrl &= !u64::from(CMD_RING_CTRL_CRR); } pub fn running(&self) -> bool { @@ -1136,7 +1136,7 @@ impl XhciDevice { return Ok(()); } let mut evt = XhciEvent::new(TRBType::ErPortStatusChange, TRBCCode::Success); - evt.ptr = ((locked_port.port_id as u32) << PORT_EVENT_ID_SHIFT) as u64; + evt.ptr = u64::from(u32::from(locked_port.port_id) << PORT_EVENT_ID_SHIFT); self.intrs[0].lock().unwrap().send_event(&evt)?; Ok(()) } @@ -1445,7 +1445,7 @@ impl XhciDevice { let packet_id = self.generate_packet_id(); let p = Arc::new(Mutex::new(UsbPacket::new( packet_id, - USB_TOKEN_OUT as u32, + u32::from(USB_TOKEN_OUT), 0, 0, Vec::new(), @@ -1459,8 +1459,10 @@ impl XhciDevice { fn get_device_context_addr(&self, slot_id: u32) -> Result { self.oper .dcbaap - .checked_add((8 * slot_id) as u64) - .with_context(|| UsbError::MemoryAccessOverflow(self.oper.dcbaap, (8 * slot_id) as u64)) + .checked_add(u64::from(8 * slot_id)) + .with_context(|| { + UsbError::MemoryAccessOverflow(self.oper.dcbaap, u64::from(8 * slot_id)) + }) } fn configure_endpoint(&mut self, slot_id: u32, trb: &XhciTRB) -> Result { @@ -1658,7 +1660,7 @@ impl XhciDevice { output_ctx: DmaAddr, ) -> Result { trace::usb_xhci_enable_endpoint(&slot_id, &ep_id); - let entry_offset = (ep_id - 1) as u64 * EP_INPUT_CTX_ENTRY_SIZE; + let entry_offset = u64::from(ep_id - 1) * EP_INPUT_CTX_ENTRY_SIZE; let mut ep_ctx = XhciEpCtx::default(); dma_read_u32( &self.mem_space, @@ -2076,16 +2078,17 @@ impl XhciDevice { let epctx = &self.slots[(xfer.slotid - 1) as usize].endpoints[(xfer.epid - 1) as usize]; if xfer.td[0].control & TRB_TR_SIA != 0 { - let asap = ((mfindex as u32 + epctx.interval - 1) & !(epctx.interval - 1)) as u64; - if asap >= epctx.mfindex_last && asap <= epctx.mfindex_last + epctx.interval as u64 * 4 + let asap = u64::from((mfindex as u32 + epctx.interval - 1) & !(epctx.interval - 1)); + if asap >= epctx.mfindex_last + && asap <= epctx.mfindex_last + u64::from(epctx.interval) * 4 { - xfer.mfindex_kick = epctx.mfindex_last + epctx.interval as u64; + xfer.mfindex_kick = epctx.mfindex_last + u64::from(epctx.interval); } else { xfer.mfindex_kick = asap; } } else { xfer.mfindex_kick = - (((xfer.td[0].control >> TRB_TR_FRAMEID_SHIFT) & TRB_TR_FRAMEID_MASK) as u64) << 3; + u64::from((xfer.td[0].control >> TRB_TR_FRAMEID_SHIFT) & TRB_TR_FRAMEID_MASK) << 3; xfer.mfindex_kick |= mfindex & !(MFINDEX_WRAP_NUM - 1); if xfer.mfindex_kick + 0x100 < mfindex { xfer.mfindex_kick += MFINDEX_WRAP_NUM; @@ -2213,7 +2216,7 @@ impl XhciDevice { self.mem_space.get_address_map( &None, GuestAddress(dma_addr), - chunk as u64, + u64::from(chunk), &mut vec, )?; } @@ -2232,7 +2235,7 @@ impl XhciDevice { let xfer_ops = Arc::downgrade(xfer) as Weak>; let packet = UsbPacket::new( packet_id, - dir as u32, + u32::from(dir), ep_number, stream, vec, @@ -2373,7 +2376,10 @@ impl XhciDevice { let base_addr = GuestAddress(addr64_from_u32(seg.addr_lo, seg.addr_hi)); // SAFETY: seg size is a 16 bit register, will not overflow. let er_len = seg.size * TRB_SIZE; - if !self.mem_space.address_in_memory(base_addr, er_len as u64) { + if !self + .mem_space + .address_in_memory(base_addr, u64::from(er_len)) + { bail!("The event ring does not locate in guest ram"); } @@ -2508,7 +2514,7 @@ pub fn dma_write_u32( } fn addr64_from_u32(low: u32, high: u32) -> u64 { - (((high << 16) as u64) << 16) | low as u64 + (u64::from(high << 16) << 16) | u64::from(low) } // | ep id | < = > | ep direction | ep number | diff --git a/devices/src/usb/xhci/xhci_pci.rs b/devices/src/usb/xhci/xhci_pci.rs index 602cf136..f91461e3 100644 --- a/devices/src/usb/xhci/xhci_pci.rs +++ b/devices/src/usb/xhci/xhci_pci.rs @@ -120,7 +120,7 @@ impl XhciPciDevice { xhci: XhciDevice::new(mem_space, config), dev_id: Arc::new(AtomicU16::new(0)), mem_region: Region::init_container_region( - XHCI_PCI_CONFIG_LENGTH as u64, + u64::from(XHCI_PCI_CONFIG_LENGTH), "XhciPciContainer", ), doorbell_fd: Arc::new(create_new_eventfd().unwrap()), @@ -131,57 +131,57 @@ impl XhciPciDevice { fn mem_region_init(&mut self) -> Result<()> { let cap_region = Region::init_io_region( - XHCI_PCI_CAP_LENGTH as u64, + u64::from(XHCI_PCI_CAP_LENGTH), build_cap_ops(&self.xhci), "XhciPciCapRegion", ); self.mem_region - .add_subregion(cap_region, XHCI_PCI_CAP_OFFSET as u64) + .add_subregion(cap_region, u64::from(XHCI_PCI_CAP_OFFSET)) .with_context(|| "Failed to register cap region.")?; let mut oper_region = Region::init_io_region( - XHCI_PCI_OPER_LENGTH as u64, + u64::from(XHCI_PCI_OPER_LENGTH), build_oper_ops(&self.xhci), "XhciPciOperRegion", ); oper_region.set_access_size(4); self.mem_region - .add_subregion(oper_region, XHCI_PCI_OPER_OFFSET as u64) + .add_subregion(oper_region, u64::from(XHCI_PCI_OPER_OFFSET)) .with_context(|| "Failed to register oper region.")?; let port_num = self.xhci.lock().unwrap().usb_ports.len(); for i in 0..port_num { let port = &self.xhci.lock().unwrap().usb_ports[i]; let port_region = Region::init_io_region( - XHCI_PCI_PORT_LENGTH as u64, + u64::from(XHCI_PCI_PORT_LENGTH), build_port_ops(port), "XhciPciPortRegion", ); - let offset = (XHCI_PCI_PORT_OFFSET + XHCI_PCI_PORT_LENGTH * i as u32) as u64; + let offset = u64::from(XHCI_PCI_PORT_OFFSET + XHCI_PCI_PORT_LENGTH * i as u32); self.mem_region .add_subregion(port_region, offset) .with_context(|| "Failed to register port region.")?; } let mut runtime_region = Region::init_io_region( - XHCI_PCI_RUNTIME_LENGTH as u64, + u64::from(XHCI_PCI_RUNTIME_LENGTH), build_runtime_ops(&self.xhci), "XhciPciRuntimeRegion", ); runtime_region.set_access_size(4); self.mem_region - .add_subregion(runtime_region, XHCI_PCI_RUNTIME_OFFSET as u64) + .add_subregion(runtime_region, u64::from(XHCI_PCI_RUNTIME_OFFSET)) .with_context(|| "Failed to register runtime region.")?; let doorbell_region = Region::init_io_region( - XHCI_PCI_DOORBELL_LENGTH as u64, + u64::from(XHCI_PCI_DOORBELL_LENGTH), build_doorbell_ops(&self.xhci), "XhciPciDoorbellRegion", ); doorbell_region.set_ioeventfds(&self.ioeventfds()); self.mem_region - .add_subregion(doorbell_region, XHCI_PCI_DOORBELL_OFFSET as u64) + .add_subregion(doorbell_region, u64::from(XHCI_PCI_DOORBELL_OFFSET)) .with_context(|| "Failed to register doorbell region.")?; Ok(()) } @@ -276,7 +276,8 @@ impl Device for XhciPciDevice { PCI_SERIAL_BUS_RELEASE_VERSION_3_0; self.base.config.config[PCI_FRAME_LENGTH_ADJUSTMENT as usize] = PCI_NO_FRAME_LENGTH_TIMING_CAP; - self.dev_id.store(self.base.devfn as u16, Ordering::SeqCst); + self.dev_id + .store(u16::from(self.base.devfn), Ordering::SeqCst); self.mem_region_init()?; let handler = Arc::new(Mutex::new(DoorbellHandler::new( @@ -308,7 +309,7 @@ impl Device for XhciPciDevice { self.base.devfn, )?; - let mut mem_region_size = (XHCI_PCI_CONFIG_LENGTH as u64).next_power_of_two(); + let mut mem_region_size = u64::from(XHCI_PCI_CONFIG_LENGTH).next_power_of_two(); mem_region_size = max(mem_region_size, MINIMUM_BAR_SIZE_FOR_MMIO as u64); self.base.config.register_bar( 0_usize, @@ -318,7 +319,7 @@ impl Device for XhciPciDevice { mem_region_size, )?; - let devfn = self.base.devfn as u64; + let devfn = u64::from(self.base.devfn); // It is safe to unwrap, because it is initialized in init_msix. let cloned_msix = self.base.config.msix.as_ref().unwrap().clone(); let cloned_intx = self.base.config.intx.as_ref().unwrap().clone(); diff --git a/devices/src/usb/xhci/xhci_regs.rs b/devices/src/usb/xhci/xhci_regs.rs index 28186170..7062d52c 100644 --- a/devices/src/usb/xhci/xhci_regs.rs +++ b/devices/src/usb/xhci/xhci_regs.rs @@ -141,7 +141,7 @@ impl XhciOperReg { /// Run the command ring. pub fn start_cmd_ring(&mut self) { - self.cmd_ring_ctrl |= CMD_RING_CTRL_CRR as u64; + self.cmd_ring_ctrl |= u64::from(CMD_RING_CTRL_CRR); } pub fn set_usb_cmd(&mut self, value: u32) { @@ -247,11 +247,11 @@ impl XhciInterrupter { pub fn send_event(&mut self, evt: &XhciEvent) -> Result<()> { let er_end = self .er_start - .checked_add((TRB_SIZE * self.er_size) as u64) + .checked_add(u64::from(TRB_SIZE * self.er_size)) .ok_or_else(|| { UsbError::MemoryAccessOverflow( self.er_start.raw_value(), - (TRB_SIZE * self.er_size) as u64, + u64::from(TRB_SIZE * self.er_size), ) })?; if self.erdp < self.er_start.raw_value() || self.erdp >= er_end.raw_value() { @@ -262,12 +262,12 @@ impl XhciInterrupter { self.er_size ); } - let dp_idx = (self.erdp - self.er_start.raw_value()) / TRB_SIZE as u64; - if ((self.er_ep_idx + 2) % self.er_size) as u64 == dp_idx { + let dp_idx = (self.erdp - self.er_start.raw_value()) / u64::from(TRB_SIZE); + if u64::from((self.er_ep_idx + 2) % self.er_size) == dp_idx { debug!("Event ring full error, idx {}", dp_idx); let event = XhciEvent::new(TRBType::ErHostController, TRBCCode::EventRingFullError); self.write_event(&event)?; - } else if ((self.er_ep_idx + 1) % self.er_size) as u64 == dp_idx { + } else if u64::from((self.er_ep_idx + 1) % self.er_size) == dp_idx { debug!("Event Ring full, drop Event."); } else { self.write_event(evt)?; @@ -336,11 +336,11 @@ impl XhciInterrupter { fn write_trb(&mut self, trb: &XhciTRB) -> Result<()> { let addr = self .er_start - .checked_add((TRB_SIZE * self.er_ep_idx) as u64) + .checked_add(u64::from(TRB_SIZE * self.er_ep_idx)) .ok_or_else(|| { UsbError::MemoryAccessOverflow( self.er_start.raw_value(), - (TRB_SIZE * self.er_ep_idx) as u64, + u64::from(TRB_SIZE * self.er_ep_idx), ) })?; let cycle = trb.control as u8; @@ -375,7 +375,7 @@ pub fn build_cap_ops(xhci_dev: &Arc>) -> RegionOps { XHCI_VERSION << hci_version_offset | XHCI_CAP_LENGTH } XHCI_CAP_REG_HCSPARAMS1 => { - (max_ports as u32) << CAP_HCSP_NP_SHIFT + u32::from(max_ports) << CAP_HCSP_NP_SHIFT | max_intrs << CAP_HCSP_NI_SHIFT | (locked_dev.slots.len() as u32) << CAP_HCSP_NDS_SHIFT } @@ -396,18 +396,18 @@ pub fn build_cap_ops(xhci_dev: &Arc>) -> RegionOps { 0x20 => { CAP_EXT_USB_REVISION_2_0 << CAP_EXT_REVISION_SHIFT | 0x4 << CAP_EXT_NEXT_CAP_POINTER_SHIFT - | CAP_EXT_CAP_ID_SUPPORT_PROTOCOL as u32 + | u32::from(CAP_EXT_CAP_ID_SUPPORT_PROTOCOL) } 0x24 => CAP_EXT_USB_NAME_STRING, - 0x28 => ((locked_dev.numports_2 as u32) << 8) | 1, + 0x28 => (u32::from(locked_dev.numports_2) << 8) | 1, 0x2c => 0x0, // Extended capabilities (USB 3.0) 0x30 => { CAP_EXT_USB_REVISION_3_0 << CAP_EXT_REVISION_SHIFT - | CAP_EXT_CAP_ID_SUPPORT_PROTOCOL as u32 + | u32::from(CAP_EXT_CAP_ID_SUPPORT_PROTOCOL) } 0x34 => CAP_EXT_USB_NAME_STRING, - 0x38 => ((locked_dev.numports_3 as u32) << 8) | (locked_dev.numports_2 + 1) as u32, + 0x38 => (u32::from(locked_dev.numports_3) << 8) | u32::from(locked_dev.numports_2 + 1), 0x3c => 0x0, _ => { error!("Failed to read xhci cap: not implemented"); @@ -515,7 +515,7 @@ pub fn build_oper_ops(xhci_dev: &Arc>) -> RegionOps { write_u64_low(locked_xhci.oper.cmd_ring_ctrl, crc_lo); } XHCI_OPER_REG_CMD_RING_CTRL_HI => { - let crc_hi = (value as u64) << 32; + let crc_hi = u64::from(value) << 32; let mut crc_lo = read_u32(locked_xhci.oper.cmd_ring_ctrl, 0); if crc_lo & (CMD_RING_CTRL_CA | CMD_RING_CTRL_CS) != 0 && (crc_lo & CMD_RING_CTRL_CRR) == CMD_RING_CTRL_CRR @@ -527,7 +527,7 @@ pub fn build_oper_ops(xhci_dev: &Arc>) -> RegionOps { error!("Failed to send event: {:?}", e); } } else { - let addr = (crc_hi | crc_lo as u64) & XHCI_CRCR_CRP_MASK; + let addr = (crc_hi | u64::from(crc_lo)) & XHCI_CRCR_CRP_MASK; locked_xhci.cmd_ring.init(addr); } crc_lo &= !(CMD_RING_CTRL_CA | CMD_RING_CTRL_CS); @@ -648,21 +648,21 @@ pub fn build_runtime_ops(xhci_dev: &Arc>) -> RegionOps { let erdp = locked_intr.erdp; let er_end = if let Some(addr) = locked_intr .er_start - .checked_add((TRB_SIZE * locked_intr.er_size) as u64) + .checked_add(u64::from(TRB_SIZE * locked_intr.er_size)) { addr } else { error!( "Memory access overflow, addr {:x} offset {:x}", locked_intr.er_start.raw_value(), - (TRB_SIZE * locked_intr.er_size) as u64 + u64::from(TRB_SIZE * locked_intr.er_size) ); return false; }; if erdp >= locked_intr.er_start.raw_value() && erdp < er_end.raw_value() - && (erdp - locked_intr.er_start.raw_value()) / TRB_SIZE as u64 - != locked_intr.er_ep_idx as u64 + && (erdp - locked_intr.er_start.raw_value()) / u64::from(TRB_SIZE) + != u64::from(locked_intr.er_ep_idx) { drop(locked_intr); xhci.intrs[idx as usize].lock().unwrap().send_intr(); diff --git a/devices/src/usb/xhci/xhci_ring.rs b/devices/src/usb/xhci/xhci_ring.rs index 6fd9d85c..86deba80 100644 --- a/devices/src/usb/xhci/xhci_ring.rs +++ b/devices/src/usb/xhci/xhci_ring.rs @@ -101,8 +101,8 @@ impl XhciCommandRing { self.ccs = !self.ccs; } } else { - self.dequeue = self.dequeue.checked_add(TRB_SIZE as u64).ok_or( - UsbError::MemoryAccessOverflow(self.dequeue, TRB_SIZE as u64), + self.dequeue = self.dequeue.checked_add(u64::from(TRB_SIZE)).ok_or( + UsbError::MemoryAccessOverflow(self.dequeue, u64::from(TRB_SIZE)), )?; return Ok(Some(trb)); } @@ -181,8 +181,8 @@ impl XhciTransferRing { } else { td.push(trb); dequeue = dequeue - .checked_add(TRB_SIZE as u64) - .ok_or(UsbError::MemoryAccessOverflow(dequeue, TRB_SIZE as u64))?; + .checked_add(u64::from(TRB_SIZE)) + .ok_or(UsbError::MemoryAccessOverflow(dequeue, u64::from(TRB_SIZE)))?; if trb_type == TRBType::TrSetup { ctrl_td = true; } else if trb_type == TRBType::TrStatus { @@ -214,7 +214,7 @@ impl XhciTransferRing { pub fn update_dequeue_to_ctx(&self, ctx: &mut [u32]) { let dequeue = self.get_dequeue_ptr(); - ctx[0] = dequeue as u32 | self.get_cycle_bit() as u32; + ctx[0] = dequeue as u32 | u32::from(self.get_cycle_bit()); ctx[1] = (dequeue >> 32) as u32; } } diff --git a/hypervisor/src/kvm/aarch64/gicv2.rs b/hypervisor/src/kvm/aarch64/gicv2.rs index abe70dd4..58758142 100644 --- a/hypervisor/src/kvm/aarch64/gicv2.rs +++ b/hypervisor/src/kvm/aarch64/gicv2.rs @@ -84,10 +84,10 @@ impl GICv2Access for KvmGICv2 { } fn vcpu_gicr_attr(&self, offset: u64, cpu: usize) -> u64 { - (((cpu as u64) << kvm_bindings::KVM_DEV_ARM_VGIC_CPUID_SHIFT as u64) + (((cpu as u64) << u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_CPUID_SHIFT)) & kvm_bindings::KVM_DEV_ARM_VGIC_CPUID_MASK) - | ((offset << kvm_bindings::KVM_DEV_ARM_VGIC_OFFSET_SHIFT as u64) - & kvm_bindings::KVM_DEV_ARM_VGIC_OFFSET_MASK as u64) + | ((offset << u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_OFFSET_SHIFT)) + & u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_OFFSET_MASK)) } fn access_gic_distributor(&self, offset: u64, gicd_value: &mut u32, write: bool) -> Result<()> { @@ -122,7 +122,7 @@ impl GICv2Access for KvmGICv2 { KvmDevice::kvm_device_access( &self.fd, kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL, - kvm_bindings::KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES as u64, + u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES), 0, true, ) diff --git a/hypervisor/src/kvm/aarch64/gicv3.rs b/hypervisor/src/kvm/aarch64/gicv3.rs index 942c2b6e..5f8c9ede 100644 --- a/hypervisor/src/kvm/aarch64/gicv3.rs +++ b/hypervisor/src/kvm/aarch64/gicv3.rs @@ -56,7 +56,7 @@ impl GICv3Access for KvmGICv3 { KvmDevice::kvm_device_check( &self.fd, kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ADDR, - kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION as u64, + u64::from(kvm_bindings::KVM_VGIC_V3_ADDR_TYPE_REDIST_REGION), ) .with_context(|| { "Multiple redistributors are acquired while KVM does not provide support." @@ -196,7 +196,7 @@ impl GICv3Access for KvmGICv3 { KvmDevice::kvm_device_access( &self.fd, kvm_bindings::KVM_DEV_ARM_VGIC_GRP_CTRL, - kvm_bindings::KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES as u64, + u64::from(kvm_bindings::KVM_DEV_ARM_VGIC_SAVE_PENDING_TABLES), 0, true, ) @@ -259,7 +259,7 @@ impl GICv3ItsAccess for KvmGICv3Its { KvmDevice::kvm_device_access( &self.fd, kvm_bindings::KVM_DEV_ARM_VGIC_GRP_ITS_REGS, - attr as u64, + u64::from(attr), its_value as *const u64 as u64, write, ) @@ -267,9 +267,9 @@ impl GICv3ItsAccess for KvmGICv3Its { fn access_gic_its_tables(&self, save: bool) -> Result<()> { let attr = if save { - kvm_bindings::KVM_DEV_ARM_ITS_SAVE_TABLES as u64 + u64::from(kvm_bindings::KVM_DEV_ARM_ITS_SAVE_TABLES) } else { - kvm_bindings::KVM_DEV_ARM_ITS_RESTORE_TABLES as u64 + u64::from(kvm_bindings::KVM_DEV_ARM_ITS_RESTORE_TABLES) }; KvmDevice::kvm_device_access( &self.fd, diff --git a/hypervisor/src/kvm/aarch64/mod.rs b/hypervisor/src/kvm/aarch64/mod.rs index 3befdd7c..3e6c8461 100644 --- a/hypervisor/src/kvm/aarch64/mod.rs +++ b/hypervisor/src/kvm/aarch64/mod.rs @@ -95,7 +95,7 @@ impl KvmCpu { pub fn arch_init_pmu(&self) -> Result<()> { let pmu_attr = kvm_device_attr { group: KVM_ARM_VCPU_PMU_V3_CTRL, - attr: KVM_ARM_VCPU_PMU_V3_INIT as u64, + attr: u64::from(KVM_ARM_VCPU_PMU_V3_INIT), addr: 0, flags: 0, }; @@ -108,7 +108,7 @@ impl KvmCpu { let irq = PMU_INTR + PPI_BASE; let pmu_irq_attr = kvm_device_attr { group: KVM_ARM_VCPU_PMU_V3_CTRL, - attr: KVM_ARM_VCPU_PMU_V3_IRQ as u64, + attr: u64::from(KVM_ARM_VCPU_PMU_V3_IRQ), addr: &irq as *const u32 as u64, flags: 0, }; @@ -302,8 +302,11 @@ impl KvmCpu { } RegsIndex::VtimerCount => { if locked_arch_cpu.vtimer_cnt_valid { - self.set_one_reg(KVM_REG_ARM_TIMER_CNT, locked_arch_cpu.vtimer_cnt as u128) - .with_context(|| "Failed to set virtual timer count")?; + self.set_one_reg( + KVM_REG_ARM_TIMER_CNT, + u128::from(locked_arch_cpu.vtimer_cnt), + ) + .with_context(|| "Failed to set virtual timer count")?; locked_arch_cpu.vtimer_cnt_valid = false; } } @@ -362,24 +365,36 @@ impl KvmCpu { /// * `vcpu_fd` - the VcpuFd in KVM mod. /// * `core_regs` - kvm_regs state to be written. fn set_core_regs(&self, core_regs: kvm_regs) -> Result<()> { - self.set_one_reg(Arm64CoreRegs::UserPTRegSp.into(), core_regs.regs.sp as u128)?; - self.set_one_reg(Arm64CoreRegs::KvmSpEl1.into(), core_regs.sp_el1 as u128)?; + self.set_one_reg( + Arm64CoreRegs::UserPTRegSp.into(), + u128::from(core_regs.regs.sp), + )?; + self.set_one_reg(Arm64CoreRegs::KvmSpEl1.into(), u128::from(core_regs.sp_el1))?; self.set_one_reg( Arm64CoreRegs::UserPTRegPState.into(), - core_regs.regs.pstate as u128, + u128::from(core_regs.regs.pstate), + )?; + self.set_one_reg( + Arm64CoreRegs::UserPTRegPc.into(), + u128::from(core_regs.regs.pc), + )?; + self.set_one_reg( + Arm64CoreRegs::KvmElrEl1.into(), + u128::from(core_regs.elr_el1), )?; - self.set_one_reg(Arm64CoreRegs::UserPTRegPc.into(), core_regs.regs.pc as u128)?; - self.set_one_reg(Arm64CoreRegs::KvmElrEl1.into(), core_regs.elr_el1 as u128)?; for i in 0..KVM_NR_REGS as usize { self.set_one_reg( Arm64CoreRegs::UserPTRegRegs(i).into(), - core_regs.regs.regs[i] as u128, + u128::from(core_regs.regs.regs[i]), )?; } for i in 0..KVM_NR_SPSR as usize { - self.set_one_reg(Arm64CoreRegs::KvmSpsr(i).into(), core_regs.spsr[i] as u128)?; + self.set_one_reg( + Arm64CoreRegs::KvmSpsr(i).into(), + u128::from(core_regs.spsr[i]), + )?; } // State save and restore is not supported for SVE for now, so we just skip it. @@ -394,11 +409,11 @@ impl KvmCpu { self.set_one_reg( Arm64CoreRegs::UserFPSIMDStateFpsr.into(), - core_regs.fp_regs.fpsr as u128, + u128::from(core_regs.fp_regs.fpsr), )?; self.set_one_reg( Arm64CoreRegs::UserFPSIMDStateFpcr.into(), - core_regs.fp_regs.fpcr as u128, + u128::from(core_regs.fp_regs.fpcr), )?; Ok(()) diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs index d8a8da8f..e7e75d7f 100644 --- a/hypervisor/src/kvm/mod.rs +++ b/hypervisor/src/kvm/mod.rs @@ -229,7 +229,7 @@ impl HypervisorOps for KvmHypervisor { .vm_fd .as_ref() .unwrap() - .create_vcpu(vcpu_id as u64) + .create_vcpu(u64::from(vcpu_id)) .with_context(|| "Create vcpu failed")?; Ok(Arc::new(KvmCpu::new( vcpu_id, diff --git a/hypervisor/src/test/mod.rs b/hypervisor/src/test/mod.rs index 7120bb9e..06f3e931 100644 --- a/hypervisor/src/test/mod.rs +++ b/hypervisor/src/test/mod.rs @@ -153,7 +153,7 @@ impl CPUHypervisorOps for TestCpu { ) -> Result<()> { #[cfg(target_arch = "aarch64")] { - arch_cpu.lock().unwrap().mpidr = self.id as u64; + arch_cpu.lock().unwrap().mpidr = u64::from(self.id); arch_cpu.lock().unwrap().set_core_reg(boot_config); } Ok(()) @@ -390,8 +390,8 @@ impl MsiIrqManager for TestInterruptManager { _dev_id: u32, ) -> Result<()> { let data = vector.msg_data; - let mut addr: u64 = vector.msg_addr_hi as u64; - addr = (addr << 32) + vector.msg_addr_lo as u64; + let mut addr: u64 = u64::from(vector.msg_addr_hi); + addr = (addr << 32) + u64::from(vector.msg_addr_lo); add_msix_msg(addr, data); Ok(()) } diff --git a/image/src/img.rs b/image/src/img.rs index 3d4738a4..fcfebffb 100644 --- a/image/src/img.rs +++ b/image/src/img.rs @@ -600,7 +600,7 @@ mod test { let mut buf = vec![0; QcowHeader::len()]; assert!(file.read_at(&mut buf, 0).is_ok()); let header = QcowHeader::from_vec(&buf).unwrap(); - assert_eq!(header.cluster_bits as u64, cluster_bits); + assert_eq!(u64::from(header.cluster_bits), cluster_bits); Self { header, @@ -897,14 +897,14 @@ mod test { let file_len = test_image.file_len(); let l1_size = test_image.header.l1_size; let reftable_clusters = test_image.header.refcount_table_clusters; - let reftable_size = reftable_clusters as u64 * cluster_size / ENTRY_SIZE; + let reftable_size = u64::from(reftable_clusters) * cluster_size / ENTRY_SIZE; let refblock_size = cluster_size / (refcount_bits / 8); assert_ne!(l1_size, 0); assert_ne!(reftable_clusters, 0); - assert!(l1_size as u64 * cluster_size * cluster_size / ENTRY_SIZE >= image_size); + assert!(u64::from(l1_size) * cluster_size * cluster_size / ENTRY_SIZE >= image_size); assert!(reftable_size * refblock_size * cluster_size >= file_len); - assert_eq!(test_image.header.cluster_bits as u64, cluster_bits); + assert_eq!(u64::from(test_image.header.cluster_bits), cluster_bits); assert_eq!(test_image.header.size, image_size); // Check refcount. diff --git a/machine/src/aarch64/fdt.rs b/machine/src/aarch64/fdt.rs index 7bf0c2c9..f015ad1f 100644 --- a/machine/src/aarch64/fdt.rs +++ b/machine/src/aarch64/fdt.rs @@ -311,7 +311,7 @@ impl CompileFDTHelper for MachineBase { let dist: u32 = if id as u32 == *i { 10 } else if let Some(distance) = distances.get(i) { - *distance as u32 + u32::from(*distance) } else { 20 }; diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index 74d24c52..69363507 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -242,7 +242,7 @@ impl StdMachine { if self.base.cpu_topo.threads > 1 { let core_offset = pptt.table_len(); let core_hierarchy_node = - ProcessorHierarchyNode::new(0x0, cluster_offset, core as u32, 3); + ProcessorHierarchyNode::new(0x0, cluster_offset, u32::from(core), 3); pptt.append_child(&core_hierarchy_node.aml_bytes()); processor_append_priv_res(pptt, priv_resources); for _thread in 0..self.base.cpu_topo.threads { @@ -264,7 +264,7 @@ impl StdMachine { for cluster in 0..self.base.cpu_topo.clusters { let cluster_offset = pptt.table_len(); let cluster_hierarchy_node = - ProcessorHierarchyNode::new(0x0, socket_offset, cluster as u32, 0); + ProcessorHierarchyNode::new(0x0, socket_offset, u32::from(cluster), 0); pptt.append_child(&cluster_hierarchy_node.aml_bytes()); self.build_pptt_cores(pptt, cluster_offset as u32, uid); } @@ -277,7 +277,7 @@ impl StdMachine { pptt.append_child(&cache_hierarchy_node.aml_bytes()); let socket_offset = pptt.table_len(); - let socket_hierarchy_node = ProcessorHierarchyNode::new(0x1, 0, socket as u32, 1); + let socket_hierarchy_node = ProcessorHierarchyNode::new(0x1, 0, u32::from(socket), 1); pptt.append_child(&socket_hierarchy_node.aml_bytes()); processor_append_priv_res(pptt, priv_resources); @@ -923,7 +923,7 @@ impl AcpiBuilder for StdMachine { // Mapping counts of Root Complex Node iort.set_field(80, 1_u32); // Mapping offset of Root Complex Node - iort.set_field(84, ROOT_COMPLEX_ENTRY_SIZE as u32); + iort.set_field(84, u32::from(ROOT_COMPLEX_ENTRY_SIZE)); // Cache of coherent device iort.set_field(88, 1_u32); // Memory flags of coherent device @@ -1087,7 +1087,7 @@ impl AcpiBuilder for StdMachine { type_id: 3_u8, length: size_of::() as u8, proximity_domain, - process_uid: *cpu as u32, + process_uid: u32::from(*cpu), flags: 1, clock_domain: 0_u32, } diff --git a/machine/src/lib.rs b/machine/src/lib.rs index fbb6f14e..c2774570 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -259,7 +259,7 @@ impl MachineBase { use crate::x86_64::ich9_lpc::SLEEP_CTRL_OFFSET; let count = data.len() as u64; - if addr == SLEEP_CTRL_OFFSET as u64 { + if addr == u64::from(SLEEP_CTRL_OFFSET) { if let Err(e) = self.cpus[0].pause() { log::error!("Fail to pause bsp, {:?}", e); } @@ -1176,7 +1176,7 @@ pub trait MachineOps: MachineLifecycle { vm_config.machine_config.nr_cpus, MAX_VIRTIO_QUEUE, ); - device_cfg.num_queues = Some(queues_auto as u32); + device_cfg.num_queues = Some(u32::from(queues_auto)); } let device = Arc::new(Mutex::new(ScsiCntlr::new(device_cfg.clone()))); diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index 4af265d9..64f11384 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -412,7 +412,7 @@ pub(crate) trait AcpiBuilder { table_end - table_begin, )?; - Ok(table_begin as u64) + Ok(u64::from(table_begin)) } /// Build ACPI DSDT table, returns the offset of ACPI DSDT table in `acpi_data`. @@ -583,7 +583,7 @@ pub(crate) trait AcpiBuilder { mcfg_begin, mcfg_end - mcfg_begin, )?; - Ok(mcfg_begin as u64) + Ok(u64::from(mcfg_begin)) } /// Build ACPI FADT table, returns the offset of ACPI FADT table in `acpi_data`. @@ -646,24 +646,24 @@ pub(crate) trait AcpiBuilder { // Reset Register bit, offset is 116. fadt.set_field(116, 0x01_u8); fadt.set_field(117, 0x08_u8); - fadt.set_field(120, RST_CTRL_OFFSET as u64); + fadt.set_field(120, u64::from(RST_CTRL_OFFSET)); fadt.set_field(128, 0x0F_u8); // PM1a event register bit, offset is 148. fadt.set_field(148, 0x01_u8); fadt.set_field(149, 0x20_u8); - fadt.set_field(152, PM_EVENT_OFFSET as u64); + fadt.set_field(152, u64::from(PM_EVENT_OFFSET)); // PM1a control register bit, offset is 172. fadt.set_field(172, 0x01_u8); fadt.set_field(173, 0x10_u8); - fadt.set_field(176, PM_CTRL_OFFSET as u64); + fadt.set_field(176, u64::from(PM_CTRL_OFFSET)); // Sleep control register, offset is 244. fadt.set_field(244, 0x01_u8); fadt.set_field(245, 0x08_u8); - fadt.set_field(248, SLEEP_CTRL_OFFSET as u64); + fadt.set_field(248, u64::from(SLEEP_CTRL_OFFSET)); // Sleep status tegister, offset is 256. fadt.set_field(256, 0x01_u8); fadt.set_field(257, 0x08_u8); - fadt.set_field(260, SLEEP_CTRL_OFFSET as u64); + fadt.set_field(260, u64::from(SLEEP_CTRL_OFFSET)); } let mut locked_acpi_data = acpi_data.lock().unwrap(); @@ -703,7 +703,7 @@ pub(crate) trait AcpiBuilder { fadt_end - fadt_begin, )?; - Ok(fadt_begin as u64) + Ok(u64::from(fadt_begin)) } /// Get the Hardware Signature used to build FACS table. @@ -741,7 +741,7 @@ pub(crate) trait AcpiBuilder { locked_acpi_data.extend(facs_data); drop(locked_acpi_data); - Ok(facs_begin as u64) + Ok(u64::from(facs_begin)) } /// Build ACPI SRAT CPU table. @@ -861,7 +861,7 @@ pub(crate) trait AcpiBuilder { xsdt_end - xsdt_begin, )?; - Ok(xsdt_begin as u64) + Ok(u64::from(xsdt_begin)) } /// Build ACPI RSDP and add it to FwCfg as file-entry. diff --git a/machine/src/x86_64/ich9_lpc.rs b/machine/src/x86_64/ich9_lpc.rs index b27b8276..e4c40c58 100644 --- a/machine/src/x86_64/ich9_lpc.rs +++ b/machine/src/x86_64/ich9_lpc.rs @@ -94,9 +94,10 @@ impl LPCBridge { self.base .config .read(PM_BASE_OFFSET as usize, pm_base_addr.as_mut_bytes()); - self.sys_io - .root() - .add_subregion(pmtmr_region, pm_base_addr as u64 + PM_TIMER_OFFSET as u64)?; + self.sys_io.root().add_subregion( + pmtmr_region, + u64::from(pm_base_addr) + u64::from(PM_TIMER_OFFSET), + )?; Ok(()) } @@ -143,7 +144,7 @@ impl LPCBridge { let rst_ctrl_region = Region::init_io_region(0x1, ops, "RstCtrlRegion"); self.sys_io .root() - .add_subregion(rst_ctrl_region, RST_CTRL_OFFSET as u64)?; + .add_subregion(rst_ctrl_region, u64::from(RST_CTRL_OFFSET))?; Ok(()) } @@ -170,7 +171,7 @@ impl LPCBridge { let sleep_reg_region = Region::init_io_region(0x1, ops, "SleepReg"); self.sys_io .root() - .add_subregion(sleep_reg_region, SLEEP_CTRL_OFFSET as u64)?; + .add_subregion(sleep_reg_region, u64::from(SLEEP_CTRL_OFFSET))?; Ok(()) } @@ -192,7 +193,7 @@ impl LPCBridge { let pm_evt_region = Region::init_io_region(0x4, ops, "PmEvtRegion"); self.sys_io .root() - .add_subregion(pm_evt_region, PM_EVENT_OFFSET as u64)?; + .add_subregion(pm_evt_region, u64::from(PM_EVENT_OFFSET))?; Ok(()) } @@ -222,7 +223,7 @@ impl LPCBridge { let pm_ctrl_region = Region::init_io_region(0x4, ops, "PmCtrl"); self.sys_io .root() - .add_subregion(pm_ctrl_region, PM_CTRL_OFFSET as u64)?; + .add_subregion(pm_ctrl_region, u64::from(PM_CTRL_OFFSET))?; Ok(()) } @@ -258,7 +259,7 @@ impl Device for LPCBridge { le_write_u16( &mut self.base.config.config, HEADER_TYPE as usize, - (HEADER_TYPE_BRIDGE | HEADER_TYPE_MULTIFUNC) as u16, + u16::from(HEADER_TYPE_BRIDGE | HEADER_TYPE_MULTIFUNC), )?; self.init_sleep_reg() diff --git a/machine_manager/src/config/machine_config.rs b/machine_manager/src/config/machine_config.rs index 25d3b7c1..05c428e6 100644 --- a/machine_manager/src/config/machine_config.rs +++ b/machine_manager/src/config/machine_config.rs @@ -587,7 +587,7 @@ fn get_host_nodes(nodes: &str) -> Result> { "host_nodes".to_string(), 0, true, - MAX_NODES as u64, + u64::from(MAX_NODES), false, ))); } diff --git a/machine_manager/src/config/network.rs b/machine_manager/src/config/network.rs index 9f203010..7b02a4c9 100644 --- a/machine_manager/src/config/network.rs +++ b/machine_manager/src/config/network.rs @@ -199,7 +199,7 @@ impl NetworkInterfaceConfig { fn valid_network_queue_size(s: &str) -> Result { let size: u64 = s.parse()?; - valid_virtqueue_size(size, DEFAULT_VIRTQUEUE_SIZE as u64, MAX_QUEUE_SIZE_NET)?; + valid_virtqueue_size(size, u64::from(DEFAULT_VIRTQUEUE_SIZE), MAX_QUEUE_SIZE_NET)?; Ok(size as u16) } diff --git a/machine_manager/src/qmp/qmp_channel.rs b/machine_manager/src/qmp/qmp_channel.rs index a0839501..51063331 100644 --- a/machine_manager/src/qmp/qmp_channel.rs +++ b/machine_manager/src/qmp/qmp_channel.rs @@ -73,7 +73,7 @@ pub fn create_timestamp() -> TimeStamp { .expect("Time went backwards"); let seconds = u128::from(since_the_epoch.as_secs()); let microseconds = - (since_the_epoch.as_nanos() - seconds * (NANOSECONDS_PER_SECOND as u128)) / (1_000_u128); + (since_the_epoch.as_nanos() - seconds * u128::from(NANOSECONDS_PER_SECOND)) / (1_000_u128); TimeStamp { seconds: seconds as u64, microseconds: microseconds as u64, diff --git a/machine_manager/src/socket.rs b/machine_manager/src/socket.rs index 6bca5b21..4c083eb4 100644 --- a/machine_manager/src/socket.rs +++ b/machine_manager/src/socket.rs @@ -96,7 +96,7 @@ impl SocketRWHandler { fn parse_fd(&mut self, mhdr: &msghdr) { // At least it should has one RawFd. // SAFETY: The input parameter is constant. - let min_cmsg_len = unsafe { CMSG_LEN(size_of::() as u32) as u64 }; + let min_cmsg_len = unsafe { u64::from(CMSG_LEN(size_of::() as u32)) }; if (mhdr.msg_controllen as u64) < min_cmsg_len { return; } @@ -111,8 +111,8 @@ impl SocketRWHandler { { // SAFETY: The pointer of scm can be guaranteed not null. let fds = unsafe { - let fd_num = - (scm.cmsg_len as u64 - CMSG_LEN(0) as u64) as usize / size_of::(); + let fd_num = (scm.cmsg_len as u64 - u64::from(CMSG_LEN(0))) as usize + / size_of::(); std::slice::from_raw_parts(CMSG_DATA(scm) as *const RawFd, fd_num) }; self.scm_fd.append(&mut fds.to_vec()); diff --git a/migration/migration_derive/src/attr_parser.rs b/migration/migration_derive/src/attr_parser.rs index ef1269f2..23794984 100644 --- a/migration/migration_derive/src/attr_parser.rs +++ b/migration/migration_derive/src/attr_parser.rs @@ -129,7 +129,7 @@ fn version_to_u32(version_str: &str) -> u32 { panic!("Version str is illegal."); } - (version_vec[2] as u32) + ((version_vec[1] as u32) << 8) + ((version_vec[0] as u32) << 16) + u32::from(version_vec[2]) + (u32::from(version_vec[1]) << 8) + (u32::from(version_vec[0]) << 16) } #[cfg(test)] diff --git a/migration/src/manager.rs b/migration/src/manager.rs index d381ae31..3b081e97 100644 --- a/migration/src/manager.rs +++ b/migration/src/manager.rs @@ -266,7 +266,7 @@ impl MigrationManager { let name = cpu_desc.name.clone() + "/" + &id.to_string(); let mut copied_cpu_desc = cpu_desc.clone(); copied_cpu_desc.name = name.clone(); - copied_cpu_desc.alias = cpu_desc.alias + id as u64; + copied_cpu_desc.alias = cpu_desc.alias + u64::from(id); Self::register_device_desc(copied_cpu_desc); let mut locked_vmm = MIGRATION_MANAGER.vmm.write().unwrap(); diff --git a/migration/src/protocol.rs b/migration/src/protocol.rs index 0d57220f..b00e486f 100644 --- a/migration/src/protocol.rs +++ b/migration/src/protocol.rs @@ -977,10 +977,10 @@ pub mod tests { device_v3.set_state_mut(¤t_slice).unwrap(); assert!(state_3_desc.current_version > state_2_desc.current_version); - assert_eq!(device_v3.state.ier, device_v2.state.ier as u64); - assert_eq!(device_v3.state.iir, device_v2.state.iir as u64); - assert_eq!(device_v3.state.lcr, device_v2.state.lcr as u64); - assert_eq!(device_v3.state.mcr, device_v2.state.mcr as u64); + assert_eq!(device_v3.state.ier, u64::from(device_v2.state.ier)); + assert_eq!(device_v3.state.iir, u64::from(device_v2.state.iir)); + assert_eq!(device_v3.state.lcr, u64::from(device_v2.state.lcr)); + assert_eq!(device_v3.state.mcr, u64::from(device_v2.state.mcr)); } #[test] @@ -1102,7 +1102,7 @@ pub mod tests { device_v5.set_state_mut(¤t_slice).unwrap(); assert!(state_5_desc.current_version > state_2_desc.current_version); - assert_eq!(device_v5.state.rii, device_v2.state.iir as u64); + assert_eq!(device_v5.state.rii, u64::from(device_v2.state.iir)); } #[test] diff --git a/tests/mod_test/src/libdriver/pci.rs b/tests/mod_test/src/libdriver/pci.rs index e78f7d67..02fc6d92 100644 --- a/tests/mod_test/src/libdriver/pci.rs +++ b/tests/mod_test/src/libdriver/pci.rs @@ -133,13 +133,13 @@ impl TestPciDev { pub fn enable(&self) { let mut cmd = self.config_readw(PCI_COMMAND); - cmd |= (PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER) as u16; + cmd |= u16::from(PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER); self.config_writew(PCI_COMMAND, cmd); cmd = self.config_readw(PCI_COMMAND); - assert!(cmd & PCI_COMMAND_IO as u16 == PCI_COMMAND_IO as u16); - assert!(cmd & PCI_COMMAND_MEMORY as u16 == PCI_COMMAND_MEMORY as u16); - assert!(cmd & PCI_COMMAND_MASTER as u16 == PCI_COMMAND_MASTER as u16); + assert!(cmd & u16::from(PCI_COMMAND_IO) == u16::from(PCI_COMMAND_IO)); + assert!(cmd & u16::from(PCI_COMMAND_MEMORY) == u16::from(PCI_COMMAND_MEMORY)); + assert!(cmd & u16::from(PCI_COMMAND_MASTER) == u16::from(PCI_COMMAND_MASTER)); } pub fn find_capability(&self, id: u8, start_addr: u8) -> u8 { @@ -200,7 +200,7 @@ impl TestPciDev { } else { self.io_map(bar_table as u8) }; - self.msix_table_off = (table & !PCI_MSIX_TABLE_BIR) as u64; + self.msix_table_off = u64::from(table & !PCI_MSIX_TABLE_BIR); let table = self.config_readl(addr + PCI_MSIX_PBA); let bar_pba = table & PCI_MSIX_TABLE_BIR; @@ -209,7 +209,7 @@ impl TestPciDev { } else { self.msix_pba_bar = self.msix_table_bar; } - self.msix_pba_off = (table & !PCI_MSIX_TABLE_BIR) as u64; + self.msix_pba_off = u64::from(table & !PCI_MSIX_TABLE_BIR); self.msix_enabled = true; } @@ -413,7 +413,7 @@ impl TestPciDev { impl PciMsixOps for TestPciDev { fn set_msix_vector(&self, msix_entry: u16, msix_addr: u64, msix_data: u32) { assert!(self.msix_enabled); - let offset = self.msix_table_off + (msix_entry * 16) as u64; + let offset = self.msix_table_off + u64::from(msix_entry * 16); let msix_table_bar = self.msix_table_bar; self.io_writel( diff --git a/tests/mod_test/src/libdriver/pci_bus.rs b/tests/mod_test/src/libdriver/pci_bus.rs index 1a146ebf..db0889db 100644 --- a/tests/mod_test/src/libdriver/pci_bus.rs +++ b/tests/mod_test/src/libdriver/pci_bus.rs @@ -64,7 +64,8 @@ impl TestPciBus { } fn get_addr(&self, bus_num: u8, devfn: u8, offset: u8) -> u64 { - self.ecam_alloc_ptr + ((bus_num as u32) << 20 | (devfn as u32) << 12 | offset as u32) as u64 + self.ecam_alloc_ptr + + u64::from(u32::from(bus_num) << 20 | u32::from(devfn) << 12 | u32::from(offset)) } pub fn pci_auto_bus_scan(&self, root_port_num: u8) { @@ -106,11 +107,13 @@ impl TestPciBus { impl PciBusOps for TestPciBus { fn memread(&self, addr: u32, len: usize) -> Vec { - self.test_state.borrow().memread(addr as u64, len as u64) + self.test_state + .borrow() + .memread(u64::from(addr), len as u64) } fn memwrite(&self, addr: u32, buf: &[u8]) { - self.test_state.borrow().memwrite(addr as u64, buf); + self.test_state.borrow().memwrite(u64::from(addr), buf); } fn config_readb(&self, bus_num: u8, devfn: u8, offset: u8) -> u8 { diff --git a/tests/mod_test/src/libdriver/qcow2.rs b/tests/mod_test/src/libdriver/qcow2.rs index ca07a609..86cc9c0c 100644 --- a/tests/mod_test/src/libdriver/qcow2.rs +++ b/tests/mod_test/src/libdriver/qcow2.rs @@ -236,7 +236,7 @@ pub fn create_qcow2_img(image_path: String, image_size: u64) { .custom_flags(libc::O_CREAT | libc::O_TRUNC) .open(image_path.clone()) .unwrap(); - file.set_len(cluster_sz * 3 + header.l1_size as u64 * ENTRY_SIZE) + file.set_len(cluster_sz * 3 + u64::from(header.l1_size) * ENTRY_SIZE) .unwrap(); file.write_all(&header.to_vec()).unwrap(); diff --git a/tests/mod_test/src/libdriver/usb.rs b/tests/mod_test/src/libdriver/usb.rs index 0a03dd21..be1db39b 100644 --- a/tests/mod_test/src/libdriver/usb.rs +++ b/tests/mod_test/src/libdriver/usb.rs @@ -174,11 +174,11 @@ impl TestNormalTRB { pub fn generate_setup_td(device_req: &UsbDeviceRequest) -> TestNormalTRB { let mut setup_trb = TestNormalTRB::default(); - setup_trb.parameter = (device_req.length as u64) << 48 - | (device_req.index as u64) << 32 - | (device_req.value as u64) << 16 - | (device_req.request as u64) << 8 - | device_req.request_type as u64; + setup_trb.parameter = u64::from(device_req.length) << 48 + | u64::from(device_req.index) << 32 + | u64::from(device_req.value) << 16 + | u64::from(device_req.request) << 8 + | u64::from(device_req.request_type); setup_trb.set_idt_flag(true); setup_trb.set_ch_flag(true); setup_trb.set_trb_type(TRBType::TrSetup as u32); @@ -193,7 +193,7 @@ impl TestNormalTRB { data_trb.set_ch_flag(true); data_trb.set_dir_flag(in_dir); data_trb.set_trb_type(TRBType::TrData as u32); - data_trb.set_trb_transfer_length(len as u32); + data_trb.set_trb_transfer_length(u32::from(len)); data_trb } @@ -503,21 +503,21 @@ impl TestXhciPciDevice { pub fn run(&mut self) { let status = self.pci_dev.io_readl( self.bar_addr, - XHCI_PCI_OPER_OFFSET as u64 + XHCI_OPER_REG_USBSTS as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_USBSTS as u64, ); assert!(status & USB_STS_HCH == USB_STS_HCH); let cmd = self.pci_dev.io_readl( self.bar_addr, - XHCI_PCI_OPER_OFFSET as u64 + XHCI_OPER_REG_USBCMD as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_USBCMD as u64, ); self.pci_dev.io_writel( self.bar_addr, - XHCI_PCI_OPER_OFFSET as u64 + XHCI_OPER_REG_USBCMD as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_USBCMD as u64, cmd | USB_CMD_RUN, ); let status = self.pci_dev.io_readl( self.bar_addr, - XHCI_PCI_OPER_OFFSET as u64 + XHCI_OPER_REG_USBSTS as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_USBSTS as u64, ); assert!(status & USB_STS_HCH != USB_STS_HCH); } @@ -589,7 +589,7 @@ impl TestXhciPciDevice { self.doorbell_write(slot_id, CONTROL_ENDPOINT_ID); let evt = self.fetch_event(PRIMARY_INTERRUPTER_ID).unwrap(); assert_eq!(evt.ccode, TRBCCode::ShortPacket as u32); - let buf = self.get_transfer_data_indirect(evt.ptr - TRB_SIZE as u64, 1); + let buf = self.get_transfer_data_indirect(evt.ptr - u64::from(TRB_SIZE), 1); assert_eq!(buf[0], 0); // configure endpoint self.configure_endpoint(slot_id, false); @@ -643,18 +643,21 @@ impl TestXhciPciDevice { pub fn oper_regs_read(&self, offset: u64) -> u32 { self.pci_dev - .io_readl(self.bar_addr, XHCI_PCI_OPER_OFFSET as u64 + offset) + .io_readl(self.bar_addr, u64::from(XHCI_PCI_OPER_OFFSET) + offset) } pub fn oper_regs_write(&mut self, offset: u64, value: u32) { - self.pci_dev - .io_writel(self.bar_addr, XHCI_PCI_OPER_OFFSET as u64 + offset, value); + self.pci_dev.io_writel( + self.bar_addr, + u64::from(XHCI_PCI_OPER_OFFSET) + offset, + value, + ); } pub fn interrupter_regs_read(&self, intr_idx: u64, offset: u64) -> u32 { self.pci_dev.io_readl( self.bar_addr, - XHCI_PCI_RUNTIME_OFFSET as u64 + u64::from(XHCI_PCI_RUNTIME_OFFSET) + XHCI_INTR_REG_SIZE + intr_idx * XHCI_INTR_REG_SIZE + offset, @@ -664,7 +667,7 @@ impl TestXhciPciDevice { pub fn interrupter_regs_write(&mut self, intr_idx: u64, offset: u64, value: u32) { self.pci_dev.io_writel( self.bar_addr, - XHCI_PCI_RUNTIME_OFFSET as u64 + u64::from(XHCI_PCI_RUNTIME_OFFSET) + RUNTIME_REGS_INTERRUPT_OFFSET + intr_idx * XHCI_INTR_REG_SIZE + offset, @@ -675,7 +678,7 @@ impl TestXhciPciDevice { pub fn interrupter_regs_readq(&self, intr_idx: u64, offset: u64) -> u64 { self.pci_dev.io_readq( self.bar_addr, - XHCI_PCI_RUNTIME_OFFSET as u64 + u64::from(XHCI_PCI_RUNTIME_OFFSET) + XHCI_INTR_REG_SIZE + intr_idx * XHCI_INTR_REG_SIZE + offset, @@ -685,7 +688,7 @@ impl TestXhciPciDevice { pub fn interrupter_regs_writeq(&mut self, intr_idx: u64, offset: u64, value: u64) { self.pci_dev.io_writeq( self.bar_addr, - XHCI_PCI_RUNTIME_OFFSET as u64 + u64::from(XHCI_PCI_RUNTIME_OFFSET) + RUNTIME_REGS_INTERRUPT_OFFSET + intr_idx * XHCI_INTR_REG_SIZE + offset, @@ -696,14 +699,14 @@ impl TestXhciPciDevice { pub fn port_regs_read(&self, port_id: u32, offset: u64) -> u32 { self.pci_dev.io_readl( self.bar_addr, - (XHCI_PCI_PORT_OFFSET + XHCI_PCI_PORT_LENGTH * (port_id - 1) as u32) as u64 + offset, + u64::from(XHCI_PCI_PORT_OFFSET + XHCI_PCI_PORT_LENGTH * (port_id - 1) as u32) + offset, ) } pub fn port_regs_write(&mut self, port_id: u32, offset: u64, value: u32) { self.pci_dev.io_writel( self.bar_addr, - (XHCI_PCI_PORT_OFFSET + XHCI_PCI_PORT_LENGTH * (port_id - 1) as u32) as u64 + offset, + u64::from(XHCI_PCI_PORT_OFFSET + XHCI_PCI_PORT_LENGTH * (port_id - 1) as u32) + offset, value, ); } @@ -711,7 +714,7 @@ impl TestXhciPciDevice { pub fn doorbell_write(&mut self, slot_id: u32, target: u32) { self.pci_dev.io_writel( self.bar_addr, - XHCI_PCI_DOORBELL_OFFSET as u64 + (slot_id << 2) as u64, + u64::from(XHCI_PCI_DOORBELL_OFFSET) + u64::from(slot_id << 2), target, ); } @@ -741,84 +744,84 @@ impl TestXhciPciDevice { // Interface Version Number let cap = self .pci_dev - .io_readl(self.bar_addr, XHCI_PCI_CAP_OFFSET as u64); + .io_readl(self.bar_addr, u64::from(XHCI_PCI_CAP_OFFSET)); assert!(cap & 0x01000000 == 0x01000000); // HCSPARAMS1 let hcsparams1 = self .pci_dev - .io_readl(self.bar_addr, (XHCI_PCI_CAP_OFFSET + 0x4) as u64); + .io_readl(self.bar_addr, u64::from(XHCI_PCI_CAP_OFFSET + 0x4)); assert_eq!(hcsparams1 & 0xffffff, 0x000140); // HCSPARAMS2 let hcsparams2 = self .pci_dev - .io_readl(self.bar_addr, (XHCI_PCI_CAP_OFFSET + 0x8) as u64); + .io_readl(self.bar_addr, u64::from(XHCI_PCI_CAP_OFFSET + 0x8)); assert_eq!(hcsparams2, 0xf); // HCSPARAMS3 let hcsparams3 = self .pci_dev - .io_readl(self.bar_addr, (XHCI_PCI_CAP_OFFSET + 0xc) as u64); + .io_readl(self.bar_addr, u64::from(XHCI_PCI_CAP_OFFSET + 0xc)); assert_eq!(hcsparams3, 0); // HCCPARAMS1 let hccparams1 = self .pci_dev - .io_readl(self.bar_addr, (XHCI_PCI_CAP_OFFSET + 0x10) as u64); + .io_readl(self.bar_addr, u64::from(XHCI_PCI_CAP_OFFSET + 0x10)); // AC64 = 1 assert_eq!(hccparams1 & 1, 1); // doorbell offset let db_offset = self .pci_dev - .io_readl(self.bar_addr, (XHCI_PCI_CAP_OFFSET + 0x14) as u64); + .io_readl(self.bar_addr, u64::from(XHCI_PCI_CAP_OFFSET + 0x14)); assert_eq!(db_offset, 0x2000); // runtime offset let runtime_offset = self .pci_dev - .io_readl(self.bar_addr, (XHCI_PCI_CAP_OFFSET + 0x18) as u64); + .io_readl(self.bar_addr, u64::from(XHCI_PCI_CAP_OFFSET + 0x18)); assert_eq!(runtime_offset, 0x1000); // HCCPARAMS2 let hccparams2 = self .pci_dev - .io_readl(self.bar_addr, (XHCI_PCI_CAP_OFFSET + 0x1c) as u64); + .io_readl(self.bar_addr, u64::from(XHCI_PCI_CAP_OFFSET + 0x1c)); assert_eq!(hccparams2, 0); // USB 2.0 let usb2_version = self .pci_dev - .io_readl(self.bar_addr, (XHCI_PCI_CAP_OFFSET + 0x20) as u64); + .io_readl(self.bar_addr, u64::from(XHCI_PCI_CAP_OFFSET + 0x20)); assert!(usb2_version & 0x02000000 == 0x02000000); let usb2_name = self .pci_dev - .io_readl(self.bar_addr, (XHCI_PCI_CAP_OFFSET + 0x24) as u64); + .io_readl(self.bar_addr, u64::from(XHCI_PCI_CAP_OFFSET + 0x24)); assert_eq!(usb2_name, 0x20425355); let usb2_port = self .pci_dev - .io_readl(self.bar_addr, (XHCI_PCI_CAP_OFFSET + 0x28) as u64); + .io_readl(self.bar_addr, u64::from(XHCI_PCI_CAP_OFFSET + 0x28)); let usb2_port_num = (usb2_port >> 8) & 0xff; // extend capability end let end = self .pci_dev - .io_readl(self.bar_addr, (XHCI_PCI_CAP_OFFSET + 0x2c) as u64); + .io_readl(self.bar_addr, u64::from(XHCI_PCI_CAP_OFFSET + 0x2c)); assert_eq!(end, 0); // USB 3.0 let usb3_version = self .pci_dev - .io_readl(self.bar_addr, (XHCI_PCI_CAP_OFFSET + 0x30) as u64); + .io_readl(self.bar_addr, u64::from(XHCI_PCI_CAP_OFFSET + 0x30)); assert!(usb3_version & 0x03000000 == 0x03000000); let usb3_name = self .pci_dev - .io_readl(self.bar_addr, (XHCI_PCI_CAP_OFFSET + 0x34) as u64); + .io_readl(self.bar_addr, u64::from(XHCI_PCI_CAP_OFFSET + 0x34)); assert_eq!(usb3_name, 0x20425355); let usb3_port = self .pci_dev - .io_readl(self.bar_addr, (XHCI_PCI_CAP_OFFSET + 0x38) as u64); + .io_readl(self.bar_addr, u64::from(XHCI_PCI_CAP_OFFSET + 0x38)); let usb3_port_num = (usb3_port >> 8) & 0xff; // extend capability end let end = self .pci_dev - .io_readl(self.bar_addr, (XHCI_PCI_CAP_OFFSET + 0x3c) as u64); + .io_readl(self.bar_addr, u64::from(XHCI_PCI_CAP_OFFSET + 0x3c)); assert_eq!(end, 0); // Max ports let hcsparams1 = self .pci_dev - .io_readl(self.bar_addr, (XHCI_PCI_CAP_OFFSET + 0x4) as u64); + .io_readl(self.bar_addr, u64::from(XHCI_PCI_CAP_OFFSET + 0x4)); assert_eq!(hcsparams1 >> 24, usb2_port_num + usb3_port_num); } @@ -827,36 +830,36 @@ impl TestXhciPciDevice { let enabled_slot = USB_CONFIG_MAX_SLOTS_ENABLED & USB_CONFIG_MAX_SLOTS_EN_MASK; self.pci_dev.io_writel( self.bar_addr, - XHCI_PCI_OPER_OFFSET as u64 + XHCI_OPER_REG_CONFIG as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_CONFIG as u64, enabled_slot, ); let config = self.pci_dev.io_readl( self.bar_addr, - XHCI_PCI_OPER_OFFSET as u64 + XHCI_OPER_REG_CONFIG as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_CONFIG as u64, ); assert_eq!(config, enabled_slot); } pub fn init_device_context_base_address_array_pointer(&mut self) { let dcba = DEVICE_CONTEXT_ENTRY_SIZE * (USB_CONFIG_MAX_SLOTS_ENABLED + 1); - let dcbaap = self.allocator.borrow_mut().alloc(dcba as u64); + let dcbaap = self.allocator.borrow_mut().alloc(u64::from(dcba)); self.pci_dev.io_writeq( self.bar_addr, - XHCI_PCI_OPER_OFFSET as u64 + XHCI_OPER_REG_DCBAAP as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_DCBAAP as u64, dcbaap, ); let value = self.pci_dev.io_readq( self.bar_addr, - XHCI_PCI_OPER_OFFSET as u64 + XHCI_OPER_REG_DCBAAP as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_DCBAAP as u64, ); assert_eq!(value, dcbaap); self.xhci.dcbaap = value; } pub fn init_command_ring_dequeue_pointer(&mut self) { - let cmd_ring_sz = TRB_SIZE as u64 * COMMAND_RING_LEN; + let cmd_ring_sz = u64::from(TRB_SIZE) * COMMAND_RING_LEN; let cmd_ring = self.allocator.borrow_mut().alloc(cmd_ring_sz); self.pci_dev .pci_bus @@ -867,13 +870,13 @@ impl TestXhciPciDevice { self.xhci.cmd_ring.init(cmd_ring, cmd_ring_sz); self.pci_dev.io_writeq( self.bar_addr, - XHCI_PCI_OPER_OFFSET as u64 + XHCI_OPER_REG_CMD_RING_CTRL as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_CMD_RING_CTRL as u64, cmd_ring, ); // Read dequeue pointer return 0. let cmd_ring = self.pci_dev.io_readq( self.bar_addr, - XHCI_PCI_OPER_OFFSET as u64 + XHCI_OPER_REG_CMD_RING_CTRL as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_CMD_RING_CTRL as u64, ); assert_eq!(cmd_ring, 0); } @@ -904,7 +907,7 @@ impl TestXhciPciDevice { pub fn reset_port(&mut self, port_id: u32) { assert!(port_id > 0); let port_offset = - (XHCI_PCI_PORT_OFFSET + XHCI_PCI_PORT_LENGTH * (port_id - 1) as u32) as u64; + u64::from(XHCI_PCI_PORT_OFFSET + XHCI_PCI_PORT_LENGTH * (port_id - 1) as u32); self.pci_dev.io_writel( self.bar_addr, port_offset + XHCI_PORTSC_OFFSET, @@ -954,14 +957,14 @@ impl TestXhciPciDevice { let ep0_tr_ring = self .allocator .borrow_mut() - .alloc(TRB_SIZE as u64 * TRANSFER_RING_LEN); + .alloc(u64::from(TRB_SIZE) * TRANSFER_RING_LEN); ep0_ctx.set_tr_dequeue_pointer(ep0_tr_ring | 1); ep0_ctx.set_ep_state(0); ep0_ctx.set_ep_type(4); self.mem_write_u32(input_ctx_addr + 0x40, ep0_ctx.as_dwords()); self.xhci.device_slot[slot_id as usize].endpoints[(CONTROL_ENDPOINT_ID - 1) as usize] .transfer_ring - .init(ep0_tr_ring, TRB_SIZE as u64 * TRANSFER_RING_LEN); + .init(ep0_tr_ring, u64::from(TRB_SIZE) * TRANSFER_RING_LEN); let mut trb = TestNormalTRB::default(); trb.parameter = input_ctx_addr; @@ -1030,7 +1033,7 @@ impl TestXhciPciDevice { { TD_TRB_LIMIT } else { - TRB_SIZE as u64 * TRANSFER_RING_LEN + u64::from(TRB_SIZE) * TRANSFER_RING_LEN }; for i in 0..endpoint_id.len() { @@ -1137,7 +1140,7 @@ impl TestXhciPciDevice { self.interrupter_regs_writeq( intr_idx as u64, XHCI_INTR_REG_ERDP_LO, - self.xhci.interrupter[intr_idx].er_pointer | ERDP_EHB as u64, + self.xhci.interrupter[intr_idx].er_pointer | u64::from(ERDP_EHB), ); self.event_list.push_back(event); } else { @@ -1156,7 +1159,10 @@ impl TestXhciPciDevice { let mut setup_trb = TestNormalTRB::generate_setup_td(&device_req); self.queue_trb(slot_id, CONTROL_ENDPOINT_ID, &mut setup_trb); // Data Stage. - let ptr = self.allocator.borrow_mut().alloc(device_req.length as u64); + let ptr = self + .allocator + .borrow_mut() + .alloc(u64::from(device_req.length)); let in_dir = device_req.request_type & USB_DIRECTION_DEVICE_TO_HOST == USB_DIRECTION_DEVICE_TO_HOST; let mut data_trb = TestNormalTRB::generate_data_td(ptr, device_req.length, in_dir); @@ -1311,7 +1317,7 @@ impl TestXhciPciDevice { let output_ctx_addr = self.get_device_context_address(slot_id); let mut ep_ctx = XhciEpCtx::default(); self.mem_read_u32( - output_ctx_addr + 0x20 * ep_id as u64, + output_ctx_addr + 0x20 * u64::from(ep_id), ep_ctx.as_mut_dwords(), ); ep_ctx @@ -1383,11 +1389,11 @@ impl TestXhciPciDevice { assert_eq!(data, erstsz); // ERSTBA let table_size = EVENT_RING_SEGMENT_TABLE_ENTRY_SIZE * erstsz; - let evt_ring_seg_table = self.allocator.borrow_mut().alloc(table_size as u64); + let evt_ring_seg_table = self.allocator.borrow_mut().alloc(u64::from(table_size)); self.xhci.interrupter[intr_idx].erstba = evt_ring_seg_table; // NOTE: Only support one Segment now. let mut seg = TestEventRingSegment::new(); - let evt_ring_sz = (TRB_SIZE * ersz) as u64; + let evt_ring_sz = u64::from(TRB_SIZE * ersz); let evt_ring = self.allocator.borrow_mut().alloc(evt_ring_sz); seg.init(evt_ring, ersz); self.pci_dev @@ -1480,7 +1486,7 @@ impl TestXhciPciDevice { fn increase_event_ring(&mut self, intr_idx: usize) { self.xhci.interrupter[intr_idx].trb_count -= 1; - self.xhci.interrupter[intr_idx].er_pointer += TRB_SIZE as u64; + self.xhci.interrupter[intr_idx].er_pointer += u64::from(TRB_SIZE); if self.xhci.interrupter[intr_idx].trb_count == 0 { self.xhci.interrupter[intr_idx].segment_index += 1; if self.xhci.interrupter[intr_idx].segment_index @@ -1503,7 +1509,7 @@ impl TestXhciPciDevice { fn read_segment_entry(&self, intr_idx: usize, index: u32) -> TestEventRingSegment { assert!(index <= self.xhci.interrupter[intr_idx].erstsz); - let addr = self.xhci.interrupter[intr_idx].erstba + (TRB_SIZE * index) as u64; + let addr = self.xhci.interrupter[intr_idx].erstba + u64::from(TRB_SIZE * index); let evt_seg_buf = self.mem_read(addr, TRB_SIZE as usize); let mut evt_seg = TestEventRingSegment::new(); evt_seg.addr = LittleEndian::read_u64(&evt_seg_buf); @@ -1513,14 +1519,14 @@ impl TestXhciPciDevice { } fn set_device_context_address(&mut self, slot_id: u32, addr: u64) { - let device_ctx_addr = self.xhci.dcbaap + (slot_id * DEVICE_CONTEXT_ENTRY_SIZE) as u64; + let device_ctx_addr = self.xhci.dcbaap + u64::from(slot_id * DEVICE_CONTEXT_ENTRY_SIZE); let mut buf = [0_u8; 8]; LittleEndian::write_u64(&mut buf, addr); self.mem_write(device_ctx_addr, &buf); } fn get_device_context_address(&self, slot_id: u32) -> u64 { - let device_ctx_addr = self.xhci.dcbaap + (slot_id * DEVICE_CONTEXT_ENTRY_SIZE) as u64; + let device_ctx_addr = self.xhci.dcbaap + u64::from(slot_id * DEVICE_CONTEXT_ENTRY_SIZE); let mut buf = self.mem_read(device_ctx_addr, 8); let addr = LittleEndian::read_u64(&mut buf); addr @@ -1537,21 +1543,25 @@ impl TestXhciPciDevice { fn increase_command_ring(&mut self) { let cmd_ring = self.xhci.cmd_ring; - if cmd_ring.pointer + TRB_SIZE as u64 >= cmd_ring.start + cmd_ring.size * TRB_SIZE as u64 { + if cmd_ring.pointer + u64::from(TRB_SIZE) + >= cmd_ring.start + cmd_ring.size * u64::from(TRB_SIZE) + { self.queue_link_trb(0, 0, cmd_ring.start, true); } - self.xhci.cmd_ring.pointer += TRB_SIZE as u64; + self.xhci.cmd_ring.pointer += u64::from(TRB_SIZE); } fn increase_transfer_ring(&mut self, slot_id: u32, ep_id: u32, len: u64) { let tr_ring = self.xhci.device_slot[slot_id as usize].endpoints[(ep_id - 1) as usize].transfer_ring; - if tr_ring.pointer + TRB_SIZE as u64 >= tr_ring.start + tr_ring.size * TRB_SIZE as u64 { + if tr_ring.pointer + u64::from(TRB_SIZE) + >= tr_ring.start + tr_ring.size * u64::from(TRB_SIZE) + { self.queue_link_trb(slot_id, ep_id, tr_ring.start, true); } self.xhci.device_slot[slot_id as usize].endpoints[(ep_id - 1) as usize] .transfer_ring - .increase_pointer(TRB_SIZE as u64 * len); + .increase_pointer(u64::from(TRB_SIZE) * len); } fn write_trb(&mut self, addr: u64, trb: &TestNormalTRB) { @@ -1607,7 +1617,7 @@ impl TestXhciPciDevice { } // 1. IAD header descriptor - *offset += USB_DT_CONFIG_SIZE as u64; + *offset += u64::from(USB_DT_CONFIG_SIZE); let buf = self.get_transfer_data_indirect_with_offset(addr, 8 as usize, *offset); // descriptor type @@ -1631,7 +1641,7 @@ impl TestXhciPciDevice { assert_eq!(buf[6], SC_VIDEOCONTROL); // get total vc length from its header descriptor - *offset += USB_DT_INTERFACE_SIZE as u64; + *offset += u64::from(USB_DT_INTERFACE_SIZE); let buf = self.get_transfer_data_indirect_with_offset(addr, 0xd as usize, *offset); let total = u16::from_le_bytes(buf[5..7].try_into().unwrap()); @@ -1641,7 +1651,7 @@ impl TestXhciPciDevice { let _buf = self.get_transfer_data_indirect_with_offset(addr, remained as usize, *offset); // 3. VS interface - *offset += remained as u64; + *offset += u64::from(remained); let buf = self.get_transfer_data_indirect_with_offset( addr, USB_DT_INTERFACE_SIZE as usize, @@ -1653,7 +1663,7 @@ impl TestXhciPciDevice { assert_eq!(buf[6], SC_VIDEOSTREAMING); // get total vs length from its header descriptor - *offset += USB_DT_INTERFACE_SIZE as u64; + *offset += u64::from(USB_DT_INTERFACE_SIZE); let buf = self.get_transfer_data_indirect_with_offset(addr, 0xf as usize, *offset); let total = u16::from_le_bytes(buf[4..6].try_into().unwrap()); let remained = total - 0xf; @@ -1668,7 +1678,7 @@ impl TestXhciPciDevice { return; } - *offset += USB_DT_CONFIG_SIZE as u64; + *offset += u64::from(USB_DT_CONFIG_SIZE); let buf = self.get_transfer_data_indirect_with_offset( addr, USB_DT_INTERFACE_SIZE as usize, @@ -1692,7 +1702,7 @@ impl TestXhciPciDevice { match usb_device_type { UsbDeviceType::Tablet => { // hid descriptor - *offset += USB_DT_INTERFACE_SIZE as u64; + *offset += u64::from(USB_DT_INTERFACE_SIZE); let buf = self.get_transfer_data_indirect_with_offset(addr, 9, *offset); assert_eq!( buf, @@ -1711,14 +1721,14 @@ impl TestXhciPciDevice { } UsbDeviceType::Keyboard => { // hid descriptor - *offset += USB_DT_INTERFACE_SIZE as u64; + *offset += u64::from(USB_DT_INTERFACE_SIZE); let buf = self.get_transfer_data_indirect_with_offset(addr, 9, *offset); assert_eq!(buf, [0x09, 0x21, 0x11, 0x01, 0x00, 0x01, 0x22, 0x3f, 0]); } _ => {} } - *offset += USB_DT_INTERFACE_SIZE as u64; + *offset += u64::from(USB_DT_INTERFACE_SIZE); // endpoint descriptor let buf = self.get_transfer_data_indirect_with_offset( addr, @@ -1738,7 +1748,7 @@ impl TestXhciPciDevice { assert_eq!(buf[1], USB_DESCRIPTOR_TYPE_ENDPOINT); // endpoint address assert_eq!(buf[2], USB_DIRECTION_DEVICE_TO_HOST | 0x01); - *offset += USB_DT_ENDPOINT_SIZE as u64; + *offset += u64::from(USB_DT_ENDPOINT_SIZE); // endpoint descriptor let buf = self.get_transfer_data_indirect_with_offset( addr, @@ -1761,7 +1771,7 @@ impl TestXhciPciDevice { assert_eq!(evt.ccode, TRBCCode::ShortPacket as u32); let len = name.len() * 2 + 2; - let buf = self.get_transfer_data_indirect(evt.ptr - TRB_SIZE as u64, len as u64); + let buf = self.get_transfer_data_indirect(evt.ptr - u64::from(TRB_SIZE), len as u64); for i in 0..name.len() { assert_eq!(buf[2 * i + 2], name.as_bytes()[i]); } @@ -1774,8 +1784,10 @@ impl TestXhciPciDevice { self.doorbell_write(slot_id, CONTROL_ENDPOINT_ID); let evt = self.fetch_event(PRIMARY_INTERRUPTER_ID).unwrap(); assert_eq!(evt.ccode, TRBCCode::ShortPacket as u32); - let buf = - self.get_transfer_data_indirect(evt.ptr - TRB_SIZE as u64, USB_DT_DEVICE_SIZE as u64); + let buf = self.get_transfer_data_indirect( + evt.ptr - u64::from(TRB_SIZE), + u64::from(USB_DT_DEVICE_SIZE), + ); // descriptor type assert_eq!(buf[1], USB_DESCRIPTOR_TYPE_DEVICE); // bcdUSB @@ -1796,7 +1808,7 @@ impl TestXhciPciDevice { self.doorbell_write(slot_id, CONTROL_ENDPOINT_ID); let evt = self.fetch_event(PRIMARY_INTERRUPTER_ID).unwrap(); assert_eq!(evt.ccode, TRBCCode::ShortPacket as u32); - let addr = evt.ptr - TRB_SIZE as u64; + let addr = evt.ptr - u64::from(TRB_SIZE); let mut offset = 0; let buf = self.get_transfer_data_indirect_with_offset(addr, USB_DT_CONFIG_SIZE as usize, offset); @@ -1842,7 +1854,7 @@ impl TestXhciPciDevice { self.doorbell_write(slot_id, CONTROL_ENDPOINT_ID); let evt = self.fetch_event(PRIMARY_INTERRUPTER_ID).unwrap(); assert_eq!(evt.ccode, TRBCCode::Success as u32); - let buf = self.get_transfer_data_indirect(evt.ptr - TRB_SIZE as u64, 63); + let buf = self.get_transfer_data_indirect(evt.ptr - u64::from(TRB_SIZE), 63); assert_eq!( buf, [ @@ -1856,13 +1868,13 @@ impl TestXhciPciDevice { ); } UsbDeviceType::Tablet => { - self.get_hid_report_descriptor(slot_id, HID_POINTER_REPORT_LEN as u16); + self.get_hid_report_descriptor(slot_id, u16::from(HID_POINTER_REPORT_LEN)); self.doorbell_write(slot_id, CONTROL_ENDPOINT_ID); let evt = self.fetch_event(PRIMARY_INTERRUPTER_ID).unwrap(); assert_eq!(evt.ccode, TRBCCode::Success as u32); let buf = self.get_transfer_data_indirect( - evt.ptr - TRB_SIZE as u64, - HID_POINTER_REPORT_LEN as u64, + evt.ptr - u64::from(TRB_SIZE), + u64::from(HID_POINTER_REPORT_LEN), ); assert_eq!( buf, @@ -1887,7 +1899,7 @@ impl TestXhciPciDevice { let device_req = UsbDeviceRequest { request_type: USB_DEVICE_IN_REQUEST, request: USB_REQUEST_GET_DESCRIPTOR, - value: (USB_DT_DEVICE as u16) << 8, + value: u16::from(USB_DT_DEVICE) << 8, index: 0, length: buf_len, }; @@ -1899,7 +1911,7 @@ impl TestXhciPciDevice { let device_req = UsbDeviceRequest { request_type: USB_DEVICE_IN_REQUEST, request: USB_REQUEST_GET_DESCRIPTOR, - value: (USB_DT_CONFIGURATION as u16) << 8, + value: u16::from(USB_DT_CONFIGURATION) << 8, index: 0, length: buf_len, }; @@ -1911,7 +1923,7 @@ impl TestXhciPciDevice { let device_req = UsbDeviceRequest { request_type: USB_DEVICE_IN_REQUEST, request: USB_REQUEST_GET_DESCRIPTOR, - value: (USB_DT_STRING as u16) << 8 | index, + value: u16::from(USB_DT_STRING) << 8 | index, index: 0, length: buf_len, }; @@ -2189,7 +2201,7 @@ impl TestXhciPciDevice { let device_req = UsbDeviceRequest { request_type: USB_INTERFACE_CLASS_IN_REQUEST, request: GET_INFO, - value: (VS_PROBE_CONTROL as u16) << 8, + value: u16::from(VS_PROBE_CONTROL) << 8, index: VS_INTERFACE_NUM, length: 1, }; @@ -2197,7 +2209,7 @@ impl TestXhciPciDevice { self.doorbell_write(slot_id, CONTROL_ENDPOINT_ID); let evt = self.fetch_event(PRIMARY_INTERRUPTER_ID).unwrap(); assert_eq!(evt.ccode, TRBCCode::Success as u32); - let buf = self.get_transfer_data_indirect(evt.ptr - TRB_SIZE as u64, 1); + let buf = self.get_transfer_data_indirect(evt.ptr - u64::from(TRB_SIZE), 1); buf[0] } @@ -2206,7 +2218,7 @@ impl TestXhciPciDevice { let device_req = UsbDeviceRequest { request_type: USB_INTERFACE_CLASS_IN_REQUEST, request: GET_CUR, - value: (VS_PROBE_CONTROL as u16) << 8, + value: u16::from(VS_PROBE_CONTROL) << 8, index: VS_INTERFACE_NUM, length: len, }; @@ -2214,7 +2226,7 @@ impl TestXhciPciDevice { self.doorbell_write(slot_id, CONTROL_ENDPOINT_ID); let evt = self.fetch_event(PRIMARY_INTERRUPTER_ID).unwrap(); assert_eq!(evt.ccode, TRBCCode::Success as u32); - let buf = self.get_transfer_data_indirect(evt.ptr - TRB_SIZE as u64, len as u64); + let buf = self.get_transfer_data_indirect(evt.ptr - u64::from(TRB_SIZE), u64::from(len)); let mut vs_control = VideoStreamingControl::default(); vs_control.as_mut_bytes().copy_from_slice(&buf); vs_control @@ -2228,7 +2240,7 @@ impl TestXhciPciDevice { let device_req = UsbDeviceRequest { request_type: USB_INTERFACE_CLASS_OUT_REQUEST, request: SET_CUR, - value: (VS_PROBE_CONTROL as u16) << 8, + value: u16::from(VS_PROBE_CONTROL) << 8, index: VS_INTERFACE_NUM, length: len, }; @@ -2243,7 +2255,7 @@ impl TestXhciPciDevice { let device_req = UsbDeviceRequest { request_type: USB_INTERFACE_CLASS_OUT_REQUEST, request: SET_CUR, - value: (VS_COMMIT_CONTROL as u16) << 8, + value: u16::from(VS_COMMIT_CONTROL) << 8, index: VS_INTERFACE_NUM, length: 0, }; @@ -2287,16 +2299,16 @@ impl TestXhciPciDevice { let cnt = (total + TRB_MAX_LEN - 1) / TRB_MAX_LEN; let mut data = Vec::new(); for _ in 0..cnt { - self.queue_indirect_td(slot_id, ep_id, TRB_MAX_LEN as u64); + self.queue_indirect_td(slot_id, ep_id, u64::from(TRB_MAX_LEN)); self.doorbell_write(slot_id, ep_id); // wait for frame done. std::thread::sleep(std::time::Duration::from_millis(FRAME_WAIT_MS)); let evt = self.fetch_event(PRIMARY_INTERRUPTER_ID).unwrap(); if evt.ccode == TRBCCode::Success as u32 { - let mut buf = self.get_transfer_data_indirect(evt.ptr, TRB_MAX_LEN as u64); + let mut buf = self.get_transfer_data_indirect(evt.ptr, u64::from(TRB_MAX_LEN)); data.append(&mut buf); } else if evt.ccode == TRBCCode::ShortPacket as u32 { - let copied = (TRB_MAX_LEN - evt.length) as u64; + let copied = u64::from(TRB_MAX_LEN - evt.length); let mut buf = self.get_transfer_data_indirect(evt.ptr, copied); data.append(&mut buf); if total == data.len() as u32 { diff --git a/tests/mod_test/src/libdriver/virtio.rs b/tests/mod_test/src/libdriver/virtio.rs index 1c9297b7..991b5a6b 100644 --- a/tests/mod_test/src/libdriver/virtio.rs +++ b/tests/mod_test/src/libdriver/virtio.rs @@ -258,7 +258,7 @@ impl TestVringIndirectDesc { let mut flags = test_state.borrow().readw( self.desc - + (size_of::() as u64 * self.index as u64) + + (size_of::() as u64 * u64::from(self.index)) + offset_of!(VringDesc, flags) as u64, ); @@ -359,7 +359,7 @@ impl TestVirtQueue { test_state.borrow().writew( self.used + offset_of!(VringUsed, ring) as u64 - + (size_of::() as u64 * self.size as u64), + + (size_of::() as u64 * u64::from(self.size)), 0, ); } @@ -376,7 +376,7 @@ impl TestVirtQueue { let features = virtio_dev.get_guest_features(); virtio_dev.queue_select(index); - let queue_size = virtio_dev.get_queue_size() as u32; + let queue_size = u32::from(virtio_dev.get_queue_size()); assert!(queue_size != 0); assert!(queue_size & (queue_size - 1) == 0); @@ -390,12 +390,12 @@ impl TestVirtQueue { let addr = alloc .borrow_mut() - .alloc(get_vring_size(self.size, self.align) as u64); + .alloc(u64::from(get_vring_size(self.size, self.align))); self.desc = addr; - self.avail = self.desc + (self.size * size_of::() as u32) as u64; + self.avail = self.desc + u64::from(self.size * size_of::() as u32); self.used = round_up( - self.avail + (size_of::() as u32 * (3 + self.size)) as u64, - self.align as u64, + self.avail + u64::from(size_of::() as u32 * (3 + self.size)), + u64::from(self.align), ) .unwrap(); } @@ -413,7 +413,7 @@ impl TestVirtQueue { let elem_addr = self.used + offset_of!(VringUsed, ring) as u64 - + (self.last_used_idx as u32 % self.size) as u64 + + u64::from(u32::from(self.last_used_idx) % self.size) * size_of::() as u64; let id_addr = elem_addr + offset_of!(VringUsedElem, id) as u64; @@ -434,7 +434,7 @@ impl TestVirtQueue { test_state.borrow().readw( self.used + offset_of!(VringUsed, ring) as u64 - + (size_of::() as u64 * self.size as u64), + + (size_of::() as u64 * u64::from(self.size)), ) } @@ -442,7 +442,7 @@ impl TestVirtQueue { test_state.borrow().writew( self.avail + offset_of!(VringAvail, ring) as u64 - + (size_of::() as u64 * self.size as u64), + + (size_of::() as u64 * u64::from(self.size)), index, ); } @@ -466,7 +466,7 @@ impl TestVirtQueue { test_state.borrow().writew( self.avail + offset_of!(VringAvail, ring) as u64 - + (size_of::() * (idx as u32 % self.size) as usize) as u64, + + (size_of::() * (u32::from(idx) % self.size) as usize) as u64, desc_idx, ); } @@ -551,7 +551,7 @@ impl TestVirtQueue { let free_head = self.free_head; let desc_elem = VringDesc { addr: indirect.desc, - len: size_of::() as u32 * indirect.elem as u32, + len: size_of::() as u32 * u32::from(indirect.elem), flags: VRING_DESC_F_INDIRECT, next: 0, }; @@ -565,7 +565,7 @@ impl TestVirtQueue { // Add a vring desc elem to desc table. fn add_elem_to_desc(&mut self, test_state: Rc>, elem: VringDesc) { self.num_free -= 1; - let desc_elem_addr = self.desc + VRING_DESC_SIZE * self.free_head as u64; + let desc_elem_addr = self.desc + VRING_DESC_SIZE * u64::from(self.free_head); test_state .borrow() .memwrite(desc_elem_addr, elem.as_bytes()); @@ -591,7 +591,7 @@ impl TestVirtioDev { #[inline] pub fn get_vring_size(num: u32, align: u32) -> u32 { let desc_avail = - (size_of::() as u32 * num + size_of::() as u32 * (3 + num)) as u64; - let desc_avail_align = round_up(desc_avail, align as u64).unwrap() as u32; + u64::from(size_of::() as u32 * num + size_of::() as u32 * (3 + num)); + let desc_avail_align = round_up(desc_avail, u64::from(align)).unwrap() as u32; desc_avail_align + size_of::() as u32 * 3 + size_of::() as u32 * num } diff --git a/tests/mod_test/src/libdriver/virtio_block.rs b/tests/mod_test/src/libdriver/virtio_block.rs index 67340432..e284e3ad 100644 --- a/tests/mod_test/src/libdriver/virtio_block.rs +++ b/tests/mod_test/src/libdriver/virtio_block.rs @@ -188,7 +188,7 @@ pub fn virtio_blk_request( .alloc((size_of::() + data_size + 512) as u64); let data_addr = if align { - round_up(addr + REQ_ADDR_LEN as u64, 512).unwrap() + round_up(addr + u64::from(REQ_ADDR_LEN), 512).unwrap() } else { addr + REQ_DATA_OFFSET }; @@ -237,7 +237,7 @@ pub fn add_blk_request( // Desc elem: [addr, len, flags, next]. let data_addr = if align { - round_up(req_addr + REQ_ADDR_LEN as u64, 512).unwrap() + round_up(req_addr + u64::from(REQ_ADDR_LEN), 512).unwrap() } else { req_addr + REQ_DATA_OFFSET }; @@ -254,7 +254,7 @@ pub fn add_blk_request( write: read, }); data_entries.push(TestVringDescEntry { - data: data_addr + REQ_DATA_LEN as u64, + data: data_addr + u64::from(REQ_DATA_LEN), len: REQ_STATUS_LEN, write: true, }); @@ -300,7 +300,7 @@ pub fn virtio_blk_write( ); let status_addr = if align { - round_up(req_addr + REQ_ADDR_LEN as u64, 512).unwrap() + REQ_DATA_LEN as u64 + round_up(req_addr + u64::from(REQ_ADDR_LEN), 512).unwrap() + u64::from(REQ_DATA_LEN) } else { req_addr + REQ_STATUS_OFFSET }; @@ -339,13 +339,13 @@ pub fn virtio_blk_read( ); let data_addr = if align { - round_up(req_addr + REQ_ADDR_LEN as u64, 512).unwrap() + round_up(req_addr + u64::from(REQ_ADDR_LEN), 512).unwrap() } else { - req_addr + REQ_ADDR_LEN as u64 + req_addr + u64::from(REQ_ADDR_LEN) }; let status_addr = if align { - round_up(req_addr + REQ_ADDR_LEN as u64, 512).unwrap() + REQ_DATA_LEN as u64 + round_up(req_addr + u64::from(REQ_ADDR_LEN), 512).unwrap() + u64::from(REQ_DATA_LEN) } else { req_addr + REQ_STATUS_OFFSET }; @@ -377,7 +377,7 @@ pub fn virtio_blk_read_write_zeroes( read = false; } let req_addr = virtio_blk_request(test_state.clone(), alloc.clone(), blk_req, false); - let data_addr = req_addr + REQ_ADDR_LEN as u64; + let data_addr = req_addr + u64::from(REQ_ADDR_LEN); let data_entries: Vec = vec![ TestVringDescEntry { data: req_addr, @@ -407,7 +407,7 @@ pub fn virtio_blk_read_write_zeroes( &mut None, true, ); - let status_addr = req_addr + REQ_ADDR_LEN as u64 + data_len as u64; + let status_addr = req_addr + u64::from(REQ_ADDR_LEN) + data_len as u64; let status = test_state.borrow().readb(status_addr); assert_eq!(status, VIRTIO_BLK_S_OK); diff --git a/tests/mod_test/src/libdriver/virtio_gpu.rs b/tests/mod_test/src/libdriver/virtio_gpu.rs index b8bd09d7..802155d1 100644 --- a/tests/mod_test/src/libdriver/virtio_gpu.rs +++ b/tests/mod_test/src/libdriver/virtio_gpu.rs @@ -697,7 +697,7 @@ pub fn current_curosr_check(dpy: &Rc>, local: &Vec>, local: &Vec u8 { self.pci_dev - .io_readb(self.bar, self.device_base as u64 + addr) + .io_readb(self.bar, u64::from(self.device_base) + addr) } fn config_readw(&self, addr: u64) -> u16 { self.pci_dev - .io_readw(self.bar, self.device_base as u64 + addr) + .io_readw(self.bar, u64::from(self.device_base) + addr) } fn config_readl(&self, addr: u64) -> u32 { self.pci_dev - .io_readl(self.bar, self.device_base as u64 + addr) + .io_readl(self.bar, u64::from(self.device_base) + addr) } fn config_readq(&self, addr: u64) -> u64 { self.pci_dev - .io_readq(self.bar, self.device_base as u64 + addr) + .io_readq(self.bar, u64::from(self.device_base) + addr) } #[allow(unused)] fn config_writeb(&self, addr: u64, value: u8) { self.pci_dev - .io_writeb(self.bar, self.device_base as u64 + addr, value) + .io_writeb(self.bar, u64::from(self.device_base) + addr, value) } #[allow(unused)] fn config_writew(&self, addr: u64, value: u16) { self.pci_dev - .io_writew(self.bar, self.device_base as u64 + addr, value) + .io_writew(self.bar, u64::from(self.device_base) + addr, value) } #[allow(unused)] fn config_writel(&self, addr: u64, value: u32) { self.pci_dev - .io_writel(self.bar, self.device_base as u64 + addr, value) + .io_writel(self.bar, u64::from(self.device_base) + addr, value) } #[allow(unused)] fn config_writeq(&self, addr: u64, value: u64) { self.pci_dev - .io_writeq(self.bar, self.device_base as u64 + addr, value) + .io_writeq(self.bar, u64::from(self.device_base) + addr, value) } fn isr_readb(&self) -> u8 { - self.pci_dev.io_readb(self.bar, self.isr_base as u64) + self.pci_dev.io_readb(self.bar, u64::from(self.isr_base)) } fn enable_interrupt(&mut self) { @@ -345,46 +345,50 @@ impl VirtioDeviceOps for TestVirtioPciDev { fn get_device_features(&self) -> u64 { self.pci_dev.io_writel( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, device_feature_select) as u64, + u64::from(self.common_base) + + offset_of!(VirtioPciCommonCfg, device_feature_select) as u64, 0, ); - let lo: u64 = self.pci_dev.io_readl( + let lo: u64 = u64::from(self.pci_dev.io_readl( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, device_feature) as u64, - ) as u64; + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, device_feature) as u64, + )); self.pci_dev.io_writel( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, device_feature_select) as u64, + u64::from(self.common_base) + + offset_of!(VirtioPciCommonCfg, device_feature_select) as u64, 1, ); - let hi: u64 = self.pci_dev.io_readl( + let hi: u64 = u64::from(self.pci_dev.io_readl( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, device_feature) as u64, - ) as u64; + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, device_feature) as u64, + )); (hi << 32) | lo } fn set_guest_features(&self, features: u64) { self.pci_dev.io_writel( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, guest_feature_select) as u64, + u64::from(self.common_base) + + offset_of!(VirtioPciCommonCfg, guest_feature_select) as u64, 0, ); self.pci_dev.io_writel( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, guest_feature) as u64, + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, guest_feature) as u64, features as u32, ); self.pci_dev.io_writel( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, guest_feature_select) as u64, + u64::from(self.common_base) + + offset_of!(VirtioPciCommonCfg, guest_feature_select) as u64, 1, ); self.pci_dev.io_writel( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, guest_feature) as u64, + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, guest_feature) as u64, (features >> 32) as u32, ); } @@ -392,36 +396,38 @@ impl VirtioDeviceOps for TestVirtioPciDev { fn get_guest_features(&self) -> u64 { self.pci_dev.io_writel( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, guest_feature_select) as u64, + u64::from(self.common_base) + + offset_of!(VirtioPciCommonCfg, guest_feature_select) as u64, 0, ); - let lo: u64 = self.pci_dev.io_readl( + let lo: u64 = u64::from(self.pci_dev.io_readl( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, guest_feature) as u64, - ) as u64; + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, guest_feature) as u64, + )); self.pci_dev.io_writel( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, guest_feature_select) as u64, + u64::from(self.common_base) + + offset_of!(VirtioPciCommonCfg, guest_feature_select) as u64, 1, ); - let hi: u64 = self.pci_dev.io_readl( + let hi: u64 = u64::from(self.pci_dev.io_readl( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, guest_feature) as u64, - ) as u64; + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, guest_feature) as u64, + )); (hi << 32) | lo } fn get_status(&self) -> u8 { self.pci_dev.io_readb( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, device_status) as u64, + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, device_status) as u64, ) } fn set_status(&self, status: u8) { self.pci_dev.io_writeb( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, device_status) as u64, + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, device_status) as u64, status, ) } @@ -429,21 +435,21 @@ impl VirtioDeviceOps for TestVirtioPciDev { fn get_generation(&self) -> u8 { self.pci_dev.io_readb( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, config_generation) as u64, + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, config_generation) as u64, ) } fn get_queue_nums(&self) -> u16 { self.pci_dev.io_readw( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, num_queues) as u64, + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, num_queues) as u64, ) } fn queue_select(&self, index: u16) { self.pci_dev.io_writew( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, queue_select) as u64, + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, queue_select) as u64, index, ); } @@ -451,14 +457,14 @@ impl VirtioDeviceOps for TestVirtioPciDev { fn get_queue_select(&self) -> u16 { self.pci_dev.io_readw( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, queue_select) as u64, + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, queue_select) as u64, ) } fn set_queue_size(&self, size: u16) { self.pci_dev.io_writew( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, queue_size) as u64, + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, queue_size) as u64, size, ) } @@ -466,39 +472,39 @@ impl VirtioDeviceOps for TestVirtioPciDev { fn get_queue_size(&self) -> u16 { self.pci_dev.io_readw( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, queue_size) as u64, + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, queue_size) as u64, ) } fn activate_queue(&self, desc: u64, avail: u64, used: u64) { self.pci_dev.io_writel( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, queue_desc_lo) as u64, + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, queue_desc_lo) as u64, desc as u32, ); self.pci_dev.io_writel( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, queue_desc_hi) as u64, + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, queue_desc_hi) as u64, (desc >> 32) as u32, ); self.pci_dev.io_writel( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, queue_avail_lo) as u64, + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, queue_avail_lo) as u64, avail as u32, ); self.pci_dev.io_writel( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, queue_avail_hi) as u64, + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, queue_avail_hi) as u64, (avail >> 32) as u32, ); self.pci_dev.io_writel( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, queue_used_lo) as u64, + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, queue_used_lo) as u64, used as u32, ); self.pci_dev.io_writel( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, queue_used_hi) as u64, + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, queue_used_hi) as u64, (used >> 32) as u32, ); } @@ -555,15 +561,15 @@ impl VirtioDeviceOps for TestVirtioPciDev { let notify_off = self.pci_dev.io_readw( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, queue_notify_off) as u64, + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, queue_notify_off) as u64, ); - virtqueue.borrow_mut().queue_notify_off = - self.notify_base as u64 + notify_off as u64 * self.notify_off_multiplier as u64; + virtqueue.borrow_mut().queue_notify_off = u64::from(self.notify_base) + + u64::from(notify_off) * u64::from(self.notify_off_multiplier); self.pci_dev.io_writew( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, queue_enable) as u64, + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, queue_enable) as u64, 1, ); @@ -681,12 +687,12 @@ impl VirtioPCIMSIXOps for TestVirtioPciDev { fn set_config_vector(&self, vector: u16) { self.pci_dev.io_writew( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, msix_config) as u64, + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, msix_config) as u64, vector, ); let vector_get: u16 = self.pci_dev.io_readw( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, msix_config) as u64, + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, msix_config) as u64, ); assert_eq!( vector, vector_get, @@ -699,12 +705,12 @@ impl VirtioPCIMSIXOps for TestVirtioPciDev { self.queue_select(vq_idx); self.pci_dev.io_writew( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, queue_msix_vector) as u64, + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, queue_msix_vector) as u64, vector, ); let vector_get: u16 = self.pci_dev.io_readw( self.bar, - self.common_base as u64 + offset_of!(VirtioPciCommonCfg, queue_msix_vector) as u64, + u64::from(self.common_base) + offset_of!(VirtioPciCommonCfg, queue_msix_vector) as u64, ); if vector_get != vector { println!("WARN: set vector {}, get vector {}", vector, vector_get); diff --git a/tests/mod_test/src/utils.rs b/tests/mod_test/src/utils.rs index 228247e2..b393cc37 100644 --- a/tests/mod_test/src/utils.rs +++ b/tests/mod_test/src/utils.rs @@ -60,14 +60,14 @@ pub fn swap_u16(value: u16) -> u16 { } pub fn swap_u32(value: u32) -> u32 { - let lower_u16 = swap_u16(value as u16) as u32; - let higher_u16 = swap_u16((value >> 16) as u16) as u32; + let lower_u16 = u32::from(swap_u16(value as u16)); + let higher_u16 = u32::from(swap_u16((value >> 16) as u16)); lower_u16 << 16 | higher_u16 } pub fn swap_u64(value: u64) -> u64 { - let lower_u32 = swap_u32(value as u32) as u64; - let higher_u32 = swap_u32((value >> 32) as u32) as u64; + let lower_u32 = u64::from(swap_u32(value as u32)); + let higher_u32 = u64::from(swap_u32((value >> 32) as u32)); lower_u32 << 32 | higher_u32 } diff --git a/tests/mod_test/tests/aarch64/acpi_test.rs b/tests/mod_test/tests/aarch64/acpi_test.rs index 6ef32b64..563d5ebc 100644 --- a/tests/mod_test/tests/aarch64/acpi_test.rs +++ b/tests/mod_test/tests/aarch64/acpi_test.rs @@ -140,12 +140,12 @@ fn check_madt(data: &[u8], cpu: u8) { offset += mem::size_of::(); for i in 0..cpu { assert_eq!(data[offset + 1], 80); // The length of this structure - assert_eq!(LittleEndian::read_u32(&data[(offset + 4)..]), i as u32); // CPU interface number - assert_eq!(LittleEndian::read_u32(&data[(offset + 8)..]), i as u32); // ACPI processor UID + assert_eq!(LittleEndian::read_u32(&data[(offset + 4)..]), u32::from(i)); // CPU interface number + assert_eq!(LittleEndian::read_u32(&data[(offset + 8)..]), u32::from(i)); // ACPI processor UID assert_eq!(LittleEndian::read_u32(&data[(offset + 12)..]), 5); // Flags assert_eq!(LittleEndian::read_u32(&data[(offset + 20)..]), 23); // Performance monitoring interrupts assert_eq!(LittleEndian::read_u64(&data[(offset + 56)..]), 25); // Virtual GIC maintenance interrupt - assert_eq!(LittleEndian::read_u64(&data[(offset + 68)..]), i as u64); // MPIDR + assert_eq!(LittleEndian::read_u64(&data[(offset + 68)..]), u64::from(i)); // MPIDR offset += mem::size_of::(); } @@ -462,7 +462,7 @@ fn check_madt_of_two_gicr( let len = LittleEndian::read_u32(&read_data[(madt_addr + offset + 12)..]); assert_eq!( MEM_LAYOUT[LayoutEntryType::HighGicRedist as usize].1, - len as u64 + u64::from(len) ); } diff --git a/tests/mod_test/tests/balloon_test.rs b/tests/mod_test/tests/balloon_test.rs index b67453e3..9ac0a6fe 100644 --- a/tests/mod_test/tests/balloon_test.rs +++ b/tests/mod_test/tests/balloon_test.rs @@ -327,18 +327,18 @@ fn balloon_fun(shared: bool, huge: bool) { let free_page = balloon .allocator .borrow_mut() - .alloc(page_num as u64 * PAGE_SIZE_UNIT); + .alloc(u64::from(page_num) * PAGE_SIZE_UNIT); let pfn = (free_page >> 12) as u32; let pfn_addr = balloon.allocator.borrow_mut().alloc(PAGE_SIZE_UNIT); while idx < page_num { balloon .state .borrow_mut() - .writel(pfn_addr + 4 * idx as u64, pfn + idx); + .writel(pfn_addr + 4 * u64::from(idx), pfn + idx); balloon .state .borrow_mut() - .writeb(free_page + PAGE_SIZE_UNIT * idx as u64, 1); + .writeb(free_page + PAGE_SIZE_UNIT * u64::from(idx), 1); idx += 1; } @@ -348,7 +348,7 @@ fn balloon_fun(shared: bool, huge: bool) { while loop_num < page_num { let entry = TestVringDescEntry { - data: pfn_addr + (loop_num as u64 * 4), + data: pfn_addr + (u64::from(loop_num) * 4), len: 4, write: false, }; @@ -377,7 +377,7 @@ fn balloon_fun(shared: bool, huge: bool) { while loop_num < page_num { let entry = TestVringDescEntry { - data: pfn_addr + (loop_num as u64 * 4), + data: pfn_addr + (u64::from(loop_num) * 4), len: 4, write: false, }; @@ -655,18 +655,18 @@ fn balloon_fpr_fun(shared: bool) { let free_page = balloon .allocator .borrow_mut() - .alloc(page_num as u64 * PAGE_SIZE_UNIT); + .alloc(u64::from(page_num) * PAGE_SIZE_UNIT); let pfn = (free_page >> 12) as u32; let pfn_addr = balloon.allocator.borrow_mut().alloc(PAGE_SIZE_UNIT); while idx < page_num { balloon .state .borrow_mut() - .writel(pfn_addr + 4 * idx as u64, pfn + idx); + .writel(pfn_addr + 4 * u64::from(idx), pfn + idx); balloon .state .borrow_mut() - .writeb(free_page + PAGE_SIZE_UNIT * idx as u64, 1); + .writeb(free_page + PAGE_SIZE_UNIT * u64::from(idx), 1); idx += 1; } // balloon Illegal addresses @@ -694,7 +694,7 @@ fn balloon_fpr_fun(shared: bool) { while loop_num < page_num { let entry = TestVringDescEntry { - data: pfn_addr + (loop_num as u64 * 4), + data: pfn_addr + (u64::from(loop_num) * 4), len: 4, write: true, }; @@ -940,7 +940,7 @@ fn balloon_deactive_001() { let balloon = VirtioBalloonTest::new(1024, PAGE_SIZE_UNIT, false, false, cfg); let bar = balloon.device.borrow().bar; - let common_base = balloon.device.borrow().common_base as u64; + let common_base = u64::from(balloon.device.borrow().common_base); balloon.device.borrow().pci_dev.io_writel( bar, @@ -1070,11 +1070,11 @@ fn balloon_numa1() { balloon .state .borrow_mut() - .writel(pfn_addr + 4 * idx as u64, pfn + idx); + .writel(pfn_addr + 4 * u64::from(idx), pfn + idx); balloon .state .borrow_mut() - .writeb(free_page + PAGE_SIZE_UNIT * idx as u64, 1); + .writeb(free_page + PAGE_SIZE_UNIT * u64::from(idx), 1); idx += 1; } @@ -1084,7 +1084,7 @@ fn balloon_numa1() { while loop_num < page_num { let entry = TestVringDescEntry { - data: pfn_addr + (loop_num as u64 * 4), + data: pfn_addr + (u64::from(loop_num) * 4), len: 4, write: false, }; @@ -1113,7 +1113,7 @@ fn balloon_numa1() { while loop_num < page_num { let entry = TestVringDescEntry { - data: pfn_addr + (loop_num as u64 * 4), + data: pfn_addr + (u64::from(loop_num) * 4), len: 4, write: false, }; diff --git a/tests/mod_test/tests/block_test.rs b/tests/mod_test/tests/block_test.rs index dc2395be..c716ebf3 100644 --- a/tests/mod_test/tests/block_test.rs +++ b/tests/mod_test/tests/block_test.rs @@ -169,11 +169,12 @@ fn virtio_blk_get_id( true, ); - let status_addr = round_up(req_addr + REQ_ADDR_LEN as u64, 512).unwrap() + REQ_DATA_LEN as u64; + let status_addr = + round_up(req_addr + u64::from(REQ_ADDR_LEN), 512).unwrap() + u64::from(REQ_DATA_LEN); let status = test_state.borrow().readb(status_addr); assert_eq!(status, VIRTIO_BLK_S_OK); - let data_addr = round_up(req_addr + REQ_ADDR_LEN as u64, 512).unwrap(); + let data_addr = round_up(req_addr + u64::from(REQ_ADDR_LEN), 512).unwrap(); assert_eq!( String::from_utf8( test_state @@ -210,7 +211,8 @@ fn virtio_blk_flush( true, ); - let status_addr = round_up(req_addr + REQ_ADDR_LEN as u64, 512).unwrap() + REQ_DATA_LEN as u64; + let status_addr = + round_up(req_addr + u64::from(REQ_ADDR_LEN), 512).unwrap() + u64::from(REQ_DATA_LEN); let status = test_state.borrow().readb(status_addr); assert_eq!(status, VIRTIO_BLK_S_OK); } @@ -240,7 +242,8 @@ fn virtio_blk_illegal_req( true, ); - let status_addr = round_up(req_addr + REQ_ADDR_LEN as u64, 512).unwrap() + REQ_DATA_LEN as u64; + let status_addr = + round_up(req_addr + u64::from(REQ_ADDR_LEN), 512).unwrap() + u64::from(REQ_DATA_LEN); let status = test_state.borrow().readb(status_addr); assert_eq!(status, VIRTIO_BLK_S_UNSUPP); } @@ -265,7 +268,7 @@ fn blk_basic() { .init_device(test_state.clone(), alloc.clone(), features, 1); let capacity = blk.borrow().config_readq(0); - assert_eq!(capacity, TEST_IMAGE_SIZE / REQ_DATA_LEN as u64); + assert_eq!(capacity, TEST_IMAGE_SIZE / u64::from(REQ_DATA_LEN)); virtio_blk_write( blk.clone(), @@ -436,7 +439,7 @@ fn blk_feature_ro() { .init_device(test_state.clone(), alloc.clone(), features, 1); let capacity = blk.borrow().config_readq(0); - assert_eq!(capacity, TEST_IMAGE_SIZE / REQ_DATA_LEN as u64); + assert_eq!(capacity, TEST_IMAGE_SIZE / u64::from(REQ_DATA_LEN)); virtio_blk_write( blk.clone(), @@ -473,7 +476,7 @@ fn blk_feature_ro() { .init_device(test_state.clone(), alloc.clone(), features, 1); let capacity = blk.borrow().config_readq(0); - assert_eq!(capacity, TEST_IMAGE_SIZE / REQ_DATA_LEN as u64); + assert_eq!(capacity, TEST_IMAGE_SIZE / u64::from(REQ_DATA_LEN)); virtio_blk_read( blk.clone(), @@ -503,7 +506,7 @@ fn blk_feature_ro() { ); let status_addr = - round_up(req_addr + REQ_ADDR_LEN as u64, 512).unwrap() + REQ_DATA_LEN as u64; + round_up(req_addr + u64::from(REQ_ADDR_LEN), 512).unwrap() + u64::from(REQ_DATA_LEN); let status = test_state.borrow().readb(status_addr); assert_eq!(status, VIRTIO_BLK_S_IOERR); @@ -623,7 +626,7 @@ fn blk_feature_mq() { true, )); - let data_addr = round_up(req_addr[i] + REQ_ADDR_LEN as u64, 512).unwrap(); + let data_addr = round_up(req_addr[i] + u64::from(REQ_ADDR_LEN), 512).unwrap(); let mut data_entries: Vec = Vec::with_capacity(3); data_entries.push(TestVringDescEntry { @@ -637,7 +640,7 @@ fn blk_feature_mq() { write: false, }); data_entries.push(TestVringDescEntry { - data: data_addr + REQ_DATA_LEN as u64, + data: data_addr + u64::from(REQ_DATA_LEN), len: REQ_STATUS_LEN, write: true, }); @@ -666,8 +669,8 @@ fn blk_feature_mq() { } for i in 0..num_queues { - let status_addr = - round_up(req_addr[i] + REQ_ADDR_LEN as u64, 512).unwrap() + REQ_DATA_LEN as u64; + let status_addr = round_up(req_addr[i] + u64::from(REQ_ADDR_LEN), 512).unwrap() + + u64::from(REQ_DATA_LEN); let status = test_state.borrow().readb(status_addr); assert_eq!(status, VIRTIO_BLK_S_OK); } @@ -798,13 +801,13 @@ fn blk_small_file_511b() { .init_device(test_state.clone(), alloc.clone(), features, 1); let capacity = blk.borrow().config_readq(0); - assert_eq!(capacity, size / REQ_DATA_LEN as u64); + assert_eq!(capacity, size / u64::from(REQ_DATA_LEN)); let mut blk_req = TestVirtBlkReq::new(VIRTIO_BLK_T_OUT, 1, 0, REQ_DATA_LEN as usize); blk_req.data.push_str("TEST"); let req_addr = virtio_blk_request(test_state.clone(), alloc.clone(), blk_req, true); - let data_addr = round_up(req_addr + REQ_ADDR_LEN as u64, 512).unwrap(); + let data_addr = round_up(req_addr + u64::from(REQ_ADDR_LEN), 512).unwrap(); let mut data_entries: Vec = Vec::with_capacity(3); data_entries.push(TestVringDescEntry { @@ -818,7 +821,7 @@ fn blk_small_file_511b() { write: false, }); data_entries.push(TestVringDescEntry { - data: data_addr + REQ_DATA_LEN as u64, + data: data_addr + u64::from(REQ_DATA_LEN), len: REQ_STATUS_LEN, write: true, }); @@ -838,7 +841,7 @@ fn blk_small_file_511b() { ); let status_addr = - round_up(req_addr + REQ_ADDR_LEN as u64, 512).unwrap() + REQ_DATA_LEN as u64; + round_up(req_addr + u64::from(REQ_ADDR_LEN), 512).unwrap() + u64::from(REQ_DATA_LEN); let status = test_state.borrow().readb(status_addr); assert_eq!(status, VIRTIO_BLK_S_IOERR); @@ -863,7 +866,7 @@ fn blk_small_file_511b() { ); let status_addr = - round_up(req_addr + REQ_ADDR_LEN as u64, 512).unwrap() + REQ_DATA_LEN as u64; + round_up(req_addr + u64::from(REQ_ADDR_LEN), 512).unwrap() + u64::from(REQ_DATA_LEN); let status = test_state.borrow().readb(status_addr); assert_eq!(status, VIRTIO_BLK_S_IOERR); @@ -1001,7 +1004,7 @@ fn blk_iops() { } let status_addr = - round_up(req_addr + REQ_ADDR_LEN as u64, 512).unwrap() + REQ_DATA_LEN as u64; + round_up(req_addr + u64::from(REQ_ADDR_LEN), 512).unwrap() + u64::from(REQ_DATA_LEN); let status = test_state.borrow().readb(status_addr); assert_ne!(status, VIRTIO_BLK_S_OK); @@ -1020,7 +1023,7 @@ fn blk_iops() { } let status_addr = - round_up(req_addr + REQ_ADDR_LEN as u64, 512).unwrap() + REQ_DATA_LEN as u64; + round_up(req_addr + u64::from(REQ_ADDR_LEN), 512).unwrap() + u64::from(REQ_DATA_LEN); let status = test_state.borrow().readb(status_addr); assert_eq!(status, VIRTIO_BLK_S_OK); @@ -1226,7 +1229,7 @@ fn blk_rw_config() { .init_device(test_state.clone(), alloc.clone(), features, 1); let capacity = blk.borrow().config_readq(0); - assert_eq!(capacity, TEST_IMAGE_SIZE / REQ_DATA_LEN as u64); + assert_eq!(capacity, TEST_IMAGE_SIZE / u64::from(REQ_DATA_LEN)); blk.borrow().config_writeq(0, 1024); let capacity = blk.borrow().config_readq(0); @@ -1597,8 +1600,8 @@ fn blk_parallel_req() { ); for i in 0..4 { - let status_addr = - round_up(req_addr_vec[i] + REQ_ADDR_LEN as u64, 512).unwrap() + REQ_DATA_LEN as u64; + let status_addr = round_up(req_addr_vec[i] + u64::from(REQ_ADDR_LEN), 512).unwrap() + + u64::from(REQ_DATA_LEN); let status = test_state.borrow().readb(status_addr); assert_eq!(status, VIRTIO_BLK_S_OK); } @@ -1633,7 +1636,7 @@ fn blk_exceed_capacity() { .init_device(test_state.clone(), alloc.clone(), features, 1); let capacity = blk.borrow().config_readq(0); - assert_eq!(capacity, TEST_IMAGE_SIZE / REQ_DATA_LEN as u64); + assert_eq!(capacity, TEST_IMAGE_SIZE / u64::from(REQ_DATA_LEN)); let (free_head, req_addr) = add_blk_request( test_state.clone(), @@ -1655,7 +1658,7 @@ fn blk_exceed_capacity() { ); let status_addr = - round_up(req_addr + REQ_ADDR_LEN as u64, 512).unwrap() + REQ_DATA_LEN as u64; + round_up(req_addr + u64::from(REQ_ADDR_LEN), 512).unwrap() + u64::from(REQ_DATA_LEN); let status = test_state.borrow().readb(status_addr); assert_eq!(status, VIRTIO_BLK_S_IOERR); @@ -1767,16 +1770,16 @@ fn blk_feature_discard() { ); if image_type == ImageType::Raw && status == VIRTIO_BLK_S_OK { let image_size = get_disk_size(image_path.clone()); - assert_eq!(image_size, full_disk_size - num_sectors as u64 / 2); + assert_eq!(image_size, full_disk_size - u64::from(num_sectors) / 2); } else if image_type == ImageType::Qcow2 && status == VIRTIO_BLK_S_OK - && (num_sectors as u64 * 512 & CLUSTER_SIZE - 1) == 0 + && (u64::from(num_sectors) * 512 & CLUSTER_SIZE - 1) == 0 { // If the disk format is equal to Qcow2. // the length of the num sectors needs to be aligned with the cluster size, // otherwise the calculated file size is not accurate. let image_size = get_disk_size(image_path.clone()); - let delete_num = (num_sectors as u64 * 512) >> 10; + let delete_num = (u64::from(num_sectors) * 512) >> 10; assert_eq!(image_size, full_disk_size - delete_num); } @@ -1937,17 +1940,17 @@ fn blk_feature_write_zeroes() { && (write_zeroes == "unmap" && discard == "unmap" && flags == 1 || len != wz_len) { let image_size = get_disk_size(image_path.clone()); - assert_eq!(image_size, full_disk_size - num_sectors as u64 / 2); + assert_eq!(image_size, full_disk_size - u64::from(num_sectors) / 2); } else if image_type == ImageType::Qcow2 && status == VIRTIO_BLK_S_OK && (write_zeroes == "unmap" && discard == "unmap" && flags == 1 || len != wz_len) - && (num_sectors as u64 * 512 & CLUSTER_SIZE - 1) == 0 + && (u64::from(num_sectors) * 512 & CLUSTER_SIZE - 1) == 0 { // If the disk format is equal to Qcow2. // the length of the num sectors needs to be aligned with the cluster size, // otherwise the calculated file size is not accurate. let image_size = get_disk_size(image_path.clone()); - let delete_num = (num_sectors as u64 * 512) >> 10; + let delete_num = (u64::from(num_sectors) * 512) >> 10; assert_eq!(image_size, full_disk_size - delete_num); } diff --git a/tests/mod_test/tests/net_test.rs b/tests/mod_test/tests/net_test.rs index 4062ce83..5d400a6a 100644 --- a/tests/mod_test/tests/net_test.rs +++ b/tests/mod_test/tests/net_test.rs @@ -552,8 +552,8 @@ fn poll_used_ring( let mut idx = test_state .borrow() .readw(vq.borrow().used + offset_of!(VringUsed, idx) as u64); - while start < idx as u64 { - for i in start..idx as u64 { + while start < u64::from(idx) { + for i in start..u64::from(idx) { let len = test_state.borrow().readw( vq.borrow().used + offset_of!(VringUsed, ring) as u64 @@ -567,8 +567,8 @@ fn poll_used_ring( let addr = test_state .borrow() - .readq(vq.borrow().desc + id as u64 * VRING_DESC_SIZE); - let packets = test_state.borrow().memread(addr, len as u64); + .readq(vq.borrow().desc + u64::from(id) * VRING_DESC_SIZE); + let packets = test_state.borrow().memread(addr, u64::from(len)); let src_mac_pos = VIRTIO_NET_HDR_SIZE + ETHERNET_HDR_SIZE + ARP_HDR_SIZE; let dst_mac_pos = src_mac_pos + 10; if arp_request[src_mac_pos..src_mac_pos + MAC_ADDR_LEN] @@ -582,7 +582,7 @@ fn poll_used_ring( } } } - start = idx as u64; + start = u64::from(idx); vq.borrow().set_used_event(test_state.clone(), start as u16); idx = test_state .borrow() @@ -958,7 +958,7 @@ fn net_config_mac_rw( /// Virtio net configure is not allowed to change except mac. fn write_net_config_check(net: Rc>, offset: u64, value: u64, size: u8) { - let origin_value = net.borrow().config_readw(offset) as u64; + let origin_value = u64::from(net.borrow().config_readw(offset)); assert_ne!(origin_value, value); match size { 1 => net.borrow().config_writeb(offset, value as u8), @@ -966,7 +966,7 @@ fn write_net_config_check(net: Rc>, offset: u64, value 4 => net.borrow().config_writel(offset, value as u32), _ => (), }; - let value = net.borrow().config_readw(offset) as u64; + let value = u64::from(net.borrow().config_readw(offset)); assert_eq!(origin_value, value); } @@ -1015,38 +1015,38 @@ fn virtio_net_write_and_check_config() { write_net_config_check( net.clone(), offset_of!(VirtioNetConfig, status) as u64, - u16::MAX as u64, + u64::from(u16::MAX), 2, ); write_net_config_check( net.clone(), offset_of!(VirtioNetConfig, max_virtqueue_pairs) as u64, - u16::MAX as u64, + u64::from(u16::MAX), 2, ); write_net_config_check( net.clone(), offset_of!(VirtioNetConfig, mtu) as u64, - u16::MAX as u64, + u64::from(u16::MAX), 2, ); write_net_config_check( net.clone(), offset_of!(VirtioNetConfig, speed) as u64, - u32::MAX as u64, + u64::from(u32::MAX), 4, ); write_net_config_check( net.clone(), offset_of!(VirtioNetConfig, duplex) as u64, - u8::MAX as u64, + u64::from(u8::MAX), 1, ); write_net_config_check( net.clone(), size_of:: as u64 + 1, - u8::MAX as u64, + u64::from(u8::MAX), 1, ); @@ -1571,7 +1571,7 @@ fn virtio_net_ctrl_rx_test() { alloc.clone(), vqs.clone(), 0, - value as u32, + u32::from(value), VIRTIO_NET_OK, ); arp_request.arp_packet.src_mac[0] += 1; @@ -2071,12 +2071,12 @@ fn virtio_net_abnormal_rx_tx_test_3() { let notify_off = net.borrow().pci_dev.io_readw( net.borrow().bar, - net.borrow().common_base as u64 + u64::from(net.borrow().common_base) + offset_of!(VirtioPciCommonCfg, queue_notify_off) as u64, ); - vq.borrow_mut().queue_notify_off = net.borrow().notify_base as u64 - + notify_off as u64 * net.borrow().notify_off_multiplier as u64; + vq.borrow_mut().queue_notify_off = u64::from(net.borrow().notify_base) + + u64::from(notify_off) * u64::from(net.borrow().notify_off_multiplier); net.borrow() .setup_virtqueue_intr((i + 1) as u16, alloc.clone(), vq.clone()); diff --git a/tests/mod_test/tests/pci_test.rs b/tests/mod_test/tests/pci_test.rs index bdd4da48..60239ac8 100644 --- a/tests/mod_test/tests/pci_test.rs +++ b/tests/mod_test/tests/pci_test.rs @@ -728,7 +728,7 @@ fn unmask_msix_global(pci_dev: TestPciDev) { } fn mask_msix_vector(pci_dev: TestPciDev, vector: u16) { - let offset: u64 = pci_dev.msix_table_off + (vector * PCI_MSIX_ENTRY_SIZE) as u64; + let offset: u64 = pci_dev.msix_table_off + u64::from(vector * PCI_MSIX_ENTRY_SIZE); let vector_mask = pci_dev.io_readl( pci_dev.msix_table_bar, @@ -743,7 +743,7 @@ fn mask_msix_vector(pci_dev: TestPciDev, vector: u16) { } fn unmask_msix_vector(pci_dev: TestPciDev, vector: u16) { - let offset: u64 = pci_dev.msix_table_off + (vector * PCI_MSIX_ENTRY_SIZE) as u64; + let offset: u64 = pci_dev.msix_table_off + u64::from(vector * PCI_MSIX_ENTRY_SIZE); let vector_control = pci_dev.io_readl( pci_dev.msix_table_bar, @@ -1268,13 +1268,13 @@ fn test_pci_type1_reset() { let root_port = RootPort::new(machine.clone(), alloc.clone(), 0, 1 << 3 | 0); let command = root_port.rp_dev.config_readw(PCI_COMMAND); - let cmd_memory = command & PCI_COMMAND_MEMORY as u16; + let cmd_memory = command & u16::from(PCI_COMMAND_MEMORY); // Bitwise inversion of memory space enable. let write_cmd = if cmd_memory != 0 { - command & !PCI_COMMAND_MEMORY as u16 + command & u16::from(!PCI_COMMAND_MEMORY) } else { - command | PCI_COMMAND_MEMORY as u16 + command | u16::from(PCI_COMMAND_MEMORY) }; root_port.rp_dev.config_writew(PCI_COMMAND, write_cmd); let old_command = root_port.rp_dev.config_readw(PCI_COMMAND); @@ -1304,7 +1304,7 @@ fn test_out_boundary_config_access() { let devfn = 1 << 3 | 1; let addr = machine.borrow().pci_bus.borrow().ecam_alloc_ptr - + ((0 as u32) << 20 | (devfn as u32) << 12 | 0 as u32) as u64 + + u64::from((0 as u32) << 20 | (devfn as u32) << 12 | 0 as u32) - 1; let write_value = u16::max_value(); @@ -1333,7 +1333,7 @@ fn test_out_size_config_access() { let value = root_port.rp_dev.config_readq(0); assert_ne!( value, - (vendor_device_id as u64) << 32 | command_status as u64 + u64::from(vendor_device_id) << 32 | u64::from(command_status) ); tear_down(None, test_state, alloc, None, Some(image_paths)); @@ -2953,7 +2953,7 @@ fn test_pci_combine_001() { // set memory enabled = 0 let mut val = dev_locked.config_readw(PCI_COMMAND); - val &= !(PCI_COMMAND_MEMORY as u16); + val &= !u16::from(PCI_COMMAND_MEMORY); dev_locked.config_writew(PCI_COMMAND, val); // mmio r/w stops working. @@ -2962,7 +2962,7 @@ fn test_pci_combine_001() { assert_ne!(out, 10); // set memory enabled = 1 - val |= PCI_COMMAND_MEMORY as u16; + val |= u16::from(PCI_COMMAND_MEMORY); dev_locked.config_writew(PCI_COMMAND, val); // mmio r/w gets back to work. diff --git a/tests/mod_test/tests/rng_test.rs b/tests/mod_test/tests/rng_test.rs index c7a98221..3a120b57 100644 --- a/tests/mod_test/tests/rng_test.rs +++ b/tests/mod_test/tests/rng_test.rs @@ -90,7 +90,7 @@ fn virtio_rng_read_batch( ); assert!(len.unwrap() >= 1); - assert!(len.unwrap() as u64 <= bytes); + assert!(u64::from(len.unwrap()) <= bytes); test_state.borrow().memread(req_addr, RNG_DATA_BYTES) } @@ -131,7 +131,7 @@ fn virtio_rng_read_chained( ); assert!(len.unwrap() >= 1); - assert!(len.unwrap() as u64 <= bytes * DEFAULT_RNG_REQS); + assert!(u64::from(len.unwrap()) <= bytes * DEFAULT_RNG_REQS); test_state.borrow().memread(req_addr, RNG_DATA_BYTES) } diff --git a/tests/mod_test/tests/scream_test.rs b/tests/mod_test/tests/scream_test.rs index 6a7d76c0..ad2c9e68 100644 --- a/tests/mod_test/tests/scream_test.rs +++ b/tests/mod_test/tests/scream_test.rs @@ -241,7 +241,7 @@ fn scream_playback_basic_test() { // write one audio chunk for i in 0..AUDIO_CHUNK_SIZE { ivshmem.borrow_mut().writeb( - PLAY_DADA_OFFSET + (AUDIO_CHUNK_SIZE + i) as u64, + PLAY_DADA_OFFSET + u64::from(AUDIO_CHUNK_SIZE + i), AUDIO_DEFAULT_DATA[i as usize], ); } @@ -257,9 +257,10 @@ fn scream_playback_basic_test() { // When four consecutive frames of data are written, only the last two frames of data can be // read. for i in 0..AUDIO_CHUNK_SIZE { - ivshmem - .borrow_mut() - .writeb(PLAY_DADA_OFFSET + i as u64, AUDIO_DEFAULT_DATA[i as usize]); + ivshmem.borrow_mut().writeb( + PLAY_DADA_OFFSET + u64::from(i), + AUDIO_DEFAULT_DATA[i as usize], + ); } // update play header chunk_idx @@ -374,7 +375,10 @@ fn scream_record_basic_test() { let offset = RECORD_BASE + offset_of!(ShmemStreamHeader, chunk_idx) as u64; chunk_idx = ivshmem.borrow_mut().readw(offset); - assert_eq!(chunk_idx as u32, AUDIO_CHUNK_CNT % (AUDIO_CHUNK_CNT - 1)); + assert_eq!( + u32::from(chunk_idx), + AUDIO_CHUNK_CNT % (AUDIO_CHUNK_CNT - 1) + ); let audio_data = ivshmem.borrow_mut().readl(RECORD_DATA_OFFSET); let mut check_data = 0; @@ -498,7 +502,7 @@ fn scream_exception_002() { // write one audio chunk for i in 0..AUDIO_CHUNK_SIZE { ivshmem.borrow_mut().writeb( - PLAY_DADA_OFFSET + (AUDIO_CHUNK_SIZE + i) as u64, + PLAY_DADA_OFFSET + u64::from(AUDIO_CHUNK_SIZE + i), AUDIO_DEFAULT_DATA[i as usize], ); } diff --git a/tests/mod_test/tests/scsi_test.rs b/tests/mod_test/tests/scsi_test.rs index 61fb6805..5ec46385 100644 --- a/tests/mod_test/tests/scsi_test.rs +++ b/tests/mod_test/tests/scsi_test.rs @@ -202,7 +202,7 @@ impl VirtioScsiTest { if let Some(data) = data_out { let out_len = data.len() as u32; let out_bytes = data.as_bytes().to_vec(); - let out_addr = self.alloc.borrow_mut().alloc(out_len as u64); + let out_addr = self.alloc.borrow_mut().alloc(u64::from(out_len)); self.state.borrow().memwrite(out_addr, out_bytes.as_slice()); data_entries.push(TestVringDescEntry { data: out_addr, @@ -216,7 +216,7 @@ impl VirtioScsiTest { let resp_addr = self .alloc .borrow_mut() - .alloc(cmdresp_len + data_in_len as u64); + .alloc(cmdresp_len + u64::from(data_in_len)); let resp_bytes = resp.as_bytes(); self.state.borrow().memwrite(resp_addr, resp_bytes); @@ -264,7 +264,7 @@ impl VirtioScsiTest { data_in.append( self.state .borrow() - .memread(resp_addr + cmdresp_len, data_in_len as u64) + .memread(resp_addr + cmdresp_len, u64::from(data_in_len)) .as_mut(), ); } @@ -667,7 +667,7 @@ fn scsi_hd_basic_test() { for i in 0..32 { // Test 1 Result: Only response 0 for target == 31. Otherwise response // VIRTIO_SCSI_S_BAD_TARGET. - let expect_result = if i == target as u16 { + let expect_result = if i == u16::from(target) { VIRTIO_SCSI_S_OK } else { VIRTIO_SCSI_S_BAD_TARGET @@ -677,7 +677,7 @@ fn scsi_hd_basic_test() { target: i as u8, lun: 0, data_out: None, - data_in_length: INQUIRY_DATA_LEN as u32, + data_in_length: u32::from(INQUIRY_DATA_LEN), expect_response: expect_result, expect_status: GOOD, expect_result_data: None, @@ -707,7 +707,7 @@ fn scsi_hd_basic_test() { target, lun, data_out: None, - data_in_length: REPORT_LUNS_DATA_LEN as u32, + data_in_length: u32::from(REPORT_LUNS_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: GOOD, expect_result_data: Some(expect_result_vec), @@ -742,7 +742,7 @@ fn scsi_hd_basic_test() { target, lun, data_out: None, - data_in_length: READ_CAPACITY_10_DATA_LEN as u32, + data_in_length: u32::from(READ_CAPACITY_10_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: GOOD, expect_result_data: None, @@ -755,8 +755,12 @@ fn scsi_hd_basic_test() { // Bytes[4-7]: Logical Block Length In Bytes. // Total size = (last logical block address + 1) * block length. assert_eq!( - (u32::from_be_bytes(data_in.as_ref().unwrap()[0..4].try_into().unwrap()) as u64 + 1) - * (u32::from_be_bytes(data_in.as_ref().unwrap()[4..8].try_into().unwrap()) as u64), + (u64::from(u32::from_be_bytes( + data_in.as_ref().unwrap()[0..4].try_into().unwrap() + )) + 1) + * u64::from(u32::from_be_bytes( + data_in.as_ref().unwrap()[4..8].try_into().unwrap() + )), TEST_IMAGE_SIZE ); @@ -795,7 +799,7 @@ fn scsi_hd_basic_test() { target, lun, data_out: None, - data_in_length: MODE_SENSE_PAGE_CACHE_LEN_DATA_LEN as u32, + data_in_length: u32::from(MODE_SENSE_PAGE_CACHE_LEN_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: GOOD, expect_result_data: Some(expect_result_vec), @@ -840,7 +844,7 @@ fn scsi_hd_basic_test() { target, lun, data_out: None, - data_in_length: MODE_SENSE_PAGE_ALL_DATA_LEN as u32, + data_in_length: u32::from(MODE_SENSE_PAGE_ALL_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: GOOD, expect_result_data: Some(expect_result_vec), @@ -863,7 +867,7 @@ fn scsi_hd_basic_test() { target, lun, data_out: None, - data_in_length: INQUIRY_DATA_LEN as u32, + data_in_length: u32::from(INQUIRY_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: GOOD, expect_result_data: None, @@ -887,7 +891,7 @@ fn scsi_hd_basic_test() { target, lun, data_out: None, - data_in_length: INQUIRY_SUPPORTED_VPD_PAGES_DATA_LEN as u32, + data_in_length: u32::from(INQUIRY_SUPPORTED_VPD_PAGES_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: GOOD, expect_result_data: Some(expect_result_vec), @@ -908,7 +912,7 @@ fn scsi_hd_basic_test() { target, lun, data_out: None, - data_in_length: INQUIRY_UNIT_SERIAL_NUMBER_DATA_LEN as u32, + data_in_length: u32::from(INQUIRY_UNIT_SERIAL_NUMBER_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: GOOD, expect_result_data: None, @@ -933,7 +937,7 @@ fn scsi_hd_basic_test() { target, lun, data_out: None, - data_in_length: INQUIRY_DEVICE_IDENTIFICATION_DATA_LEN as u32, + data_in_length: u32::from(INQUIRY_DEVICE_IDENTIFICATION_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: GOOD, expect_result_data: None, @@ -955,7 +959,7 @@ fn scsi_hd_basic_test() { target, lun, data_out: None, - data_in_length: INQUIRY_BLOCK_LIMITS_DATA_LEN as u32, + data_in_length: u32::from(INQUIRY_BLOCK_LIMITS_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: GOOD, expect_result_data: None, @@ -983,7 +987,7 @@ fn scsi_hd_basic_test() { target, lun, data_out: None, - data_in_length: INQUIRY_BLOCK_DEVICE_CHARACTERISTICS_DATA_LEN as u32, + data_in_length: u32::from(INQUIRY_BLOCK_DEVICE_CHARACTERISTICS_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: GOOD, expect_result_data: Some(expect_result_vec), @@ -1012,7 +1016,7 @@ fn scsi_hd_basic_test() { target, lun, data_out: None, - data_in_length: INQUIRY_LOGICAL_BLOCK_PROVISIONING_DATA_LEN as u32, + data_in_length: u32::from(INQUIRY_LOGICAL_BLOCK_PROVISIONING_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: GOOD, expect_result_data: Some(expect_result_vec), @@ -1033,7 +1037,7 @@ fn scsi_hd_basic_test() { target, lun, data_out: None, - data_in_length: INQUIRY_REFERRALS_DATA_LEN as u32, + data_in_length: u32::from(INQUIRY_REFERRALS_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: CHECK_CONDITION, expect_result_data: None, @@ -1112,7 +1116,7 @@ fn scsi_cd_basic_test() { target, lun, data_out: None, - data_in_length: MODE_SENSE_LEN_DATA_LEN as u32, + data_in_length: u32::from(MODE_SENSE_LEN_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: GOOD, expect_result_data: Some(expect_result_vec), @@ -1174,7 +1178,7 @@ fn scsi_cd_basic_test() { target, lun, data_out: None, - data_in_length: READ_TOC_DATA_LEN as u32, + data_in_length: u32::from(READ_TOC_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: GOOD, expect_result_data: Some(expect_result_vec), @@ -1207,7 +1211,7 @@ fn scsi_cd_basic_test() { target, lun, data_out: None, - data_in_length: READ_TOC_MSF_DATA_LEN as u32, + data_in_length: u32::from(READ_TOC_MSF_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: GOOD, expect_result_data: Some(expect_result_vec), @@ -1231,7 +1235,7 @@ fn scsi_cd_basic_test() { target, lun, data_out: None, - data_in_length: READ_TOC_FORMAT_DATA_LEN as u32, + data_in_length: u32::from(READ_TOC_FORMAT_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: GOOD, expect_result_data: Some(expect_result_vec), @@ -1272,7 +1276,7 @@ fn scsi_cd_basic_test() { target, lun, data_out: None, - data_in_length: READ_DISC_INFORMATION_DATA_LEN as u32, + data_in_length: u32::from(READ_DISC_INFORMATION_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: GOOD, expect_result_data: Some(expect_result_vec), @@ -1341,7 +1345,7 @@ fn scsi_cd_basic_test() { target, lun, data_out: None, - data_in_length: GET_CONFIGURATION_DATA_LEN as u32, + data_in_length: u32::from(GET_CONFIGURATION_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: GOOD, expect_result_data: Some(expect_result_vec), @@ -1377,7 +1381,7 @@ fn scsi_cd_basic_test() { target, lun, data_out: None, - data_in_length: GET_EVENT_STATUS_NOTIFICATION_DATA_LEN as u32, + data_in_length: u32::from(GET_EVENT_STATUS_NOTIFICATION_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: GOOD, expect_result_data: Some(expect_result_vec), @@ -1425,7 +1429,7 @@ fn scsi_target_cdb_test() { target, lun: req_lun, data_out: None, - data_in_length: REPORT_LUNS_DATA_LEN as u32, + data_in_length: u32::from(REPORT_LUNS_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: GOOD, expect_result_data: Some(expect_result_vec), @@ -1449,7 +1453,7 @@ fn scsi_target_cdb_test() { target, lun: req_lun, data_out: None, - data_in_length: INQUIRY_TARGET_DATA_LEN as u32, + data_in_length: u32::from(INQUIRY_TARGET_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: GOOD, expect_result_data: Some(expect_result_vec), @@ -1482,7 +1486,7 @@ fn scsi_target_cdb_test() { target, lun: 0, data_out: None, - data_in_length: INQUIRY_TARGET_DATA_LEN as u32, + data_in_length: u32::from(INQUIRY_TARGET_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: GOOD, expect_result_data: Some(expect_result_vec), @@ -1505,7 +1509,7 @@ fn scsi_target_cdb_test() { target, lun: req_lun, data_out: None, - data_in_length: INQUIRY_TARGET_DATA_LEN as u32, + data_in_length: u32::from(INQUIRY_TARGET_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: GOOD, expect_result_data: None, @@ -1526,7 +1530,7 @@ fn scsi_target_cdb_test() { target, lun: 0, data_out: None, - data_in_length: INQUIRY_TARGET_DATA_LEN as u32, + data_in_length: u32::from(INQUIRY_TARGET_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: CHECK_CONDITION, expect_result_data: None, @@ -1547,7 +1551,7 @@ fn scsi_target_cdb_test() { target, lun: req_lun, data_out: None, - data_in_length: INQUIRY_TARGET_DATA_LEN as u32, + data_in_length: u32::from(INQUIRY_TARGET_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: CHECK_CONDITION, expect_result_data: None, @@ -1621,7 +1625,7 @@ fn scsi_target_cdb_test() { target, lun: req_lun, data_out: None, - data_in_length: READ_CAPACITY_10_DATA_LEN as u32, + data_in_length: u32::from(READ_CAPACITY_10_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: CHECK_CONDITION, expect_result_data: None, @@ -2250,7 +2254,7 @@ fn send_cd_command_to_hd_test() { target, lun, data_out: None, - data_in_length: MODE_SENSE_LEN_DATA_LEN as u32, + data_in_length: u32::from(MODE_SENSE_LEN_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: CHECK_CONDITION, expect_result_data: None, @@ -2269,7 +2273,7 @@ fn send_cd_command_to_hd_test() { target, lun, data_out: None, - data_in_length: READ_DISC_INFORMATION_DATA_LEN as u32, + data_in_length: u32::from(READ_DISC_INFORMATION_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: CHECK_CONDITION, expect_result_data: None, @@ -2287,7 +2291,7 @@ fn send_cd_command_to_hd_test() { target, lun, data_out: None, - data_in_length: GET_CONFIGURATION_DATA_LEN as u32, + data_in_length: u32::from(GET_CONFIGURATION_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: CHECK_CONDITION, expect_result_data: None, @@ -2309,7 +2313,7 @@ fn send_cd_command_to_hd_test() { target, lun, data_out: None, - data_in_length: GET_EVENT_STATUS_NOTIFICATION_DATA_LEN as u32, + data_in_length: u32::from(GET_EVENT_STATUS_NOTIFICATION_DATA_LEN), expect_response: VIRTIO_SCSI_S_OK, expect_status: CHECK_CONDITION, expect_result_data: None, diff --git a/tests/mod_test/tests/serial_test.rs b/tests/mod_test/tests/serial_test.rs index ac46ce51..8336cfd9 100644 --- a/tests/mod_test/tests/serial_test.rs +++ b/tests/mod_test/tests/serial_test.rs @@ -214,7 +214,8 @@ impl SerialTest { // Port Ready. for port in self.ports.clone().iter() { - let ready_msg = VirtioConsoleControl::new(*port.0 as u32, VIRTIO_CONSOLE_PORT_READY, 1); + let ready_msg = + VirtioConsoleControl::new(u32::from(*port.0), VIRTIO_CONSOLE_PORT_READY, 1); self.out_control_event(ready_msg); // If it's a console port. @@ -258,7 +259,7 @@ impl SerialTest { // driver -> device: port open. let open_msg: VirtioConsoleControl = - VirtioConsoleControl::new(*port.0 as u32, VIRTIO_CONSOLE_PORT_OPEN, 1); + VirtioConsoleControl::new(u32::from(*port.0), VIRTIO_CONSOLE_PORT_OPEN, 1); self.out_control_event(open_msg); } } @@ -321,7 +322,7 @@ impl SerialTest { // Connect Guest. // driver -> device: port open. let open_msg: VirtioConsoleControl = - VirtioConsoleControl::new(port.nr as u32, VIRTIO_CONSOLE_PORT_OPEN, 1); + VirtioConsoleControl::new(u32::from(port.nr), VIRTIO_CONSOLE_PORT_OPEN, 1); self.out_control_event(open_msg); // IO: Guest -> Host. @@ -461,7 +462,7 @@ fn create_serial(ports_config: Vec, pci_slot: u8, pci_fn: u8) -> Ser fn verify_output_data(test_state: Rc>, addr: u64, len: u32, test_data: &String) { let mut data_buf: Vec = Vec::with_capacity(len as usize); - data_buf.append(test_state.borrow().memread(addr, len as u64).as_mut()); + data_buf.append(test_state.borrow().memread(addr, u64::from(len)).as_mut()); let data = String::from_utf8(data_buf).unwrap(); assert_eq!(data, *test_data); } @@ -662,12 +663,13 @@ fn virtconsole_pty_err_out_control_msg() { // Error out control msg which has invalid event. Just discard this invalid msg. Nothing // happened. - let invalid_event_msg = VirtioConsoleControl::new(nr as u32, VIRTIO_CONSOLE_PORT_NAME, 1); + let invalid_event_msg = VirtioConsoleControl::new(u32::from(nr), VIRTIO_CONSOLE_PORT_NAME, 1); st.out_control_event(invalid_event_msg); // Error out control msg which has non-existed port id. Just discard this invalid msg. Nothing // happened. - let invalid_event_msg = VirtioConsoleControl::new((nr + 5) as u32, VIRTIO_CONSOLE_PORT_OPEN, 1); + let invalid_event_msg = + VirtioConsoleControl::new(u32::from(nr + 5), VIRTIO_CONSOLE_PORT_OPEN, 1); st.out_control_event(invalid_event_msg); // Error out control msg which size is illegal. diff --git a/tests/mod_test/tests/usb_camera_test.rs b/tests/mod_test/tests/usb_camera_test.rs index 72539614..7773200e 100644 --- a/tests/mod_test/tests/usb_camera_test.rs +++ b/tests/mod_test/tests/usb_camera_test.rs @@ -155,7 +155,7 @@ fn check_multi_frames( slot_id, VS_ENDPOINT_ID, frame_len, - UVC_HEADER_LEN as u32, + u32::from(UVC_HEADER_LEN), max_payload, ); for buf in &payload_list { @@ -314,7 +314,7 @@ fn test_xhci_camera_invalid_frame_len() { slot_id, VS_ENDPOINT_ID, len as u32, - UVC_HEADER_LEN as u32, + u32::from(UVC_HEADER_LEN), cur.dwMaxPayloadTransferSize, ); for item in payload_list { diff --git a/tests/mod_test/tests/usb_storage_test.rs b/tests/mod_test/tests/usb_storage_test.rs index 472d91ef..54e35e2c 100644 --- a/tests/mod_test/tests/usb_storage_test.rs +++ b/tests/mod_test/tests/usb_storage_test.rs @@ -83,7 +83,7 @@ fn cbw_phase( } let mut iovecs = Vec::new(); - let ptr = guest_allocator.alloc(CBW_SIZE as u64); + let ptr = guest_allocator.alloc(u64::from(CBW_SIZE)); xhci.mem_write(ptr, &cbw_buf); let iovec = TestIovec::new(ptr, len as usize, false); @@ -142,7 +142,7 @@ fn csw_phase( sig_check: bool, ) -> u64 { let mut iovecs = Vec::new(); - let ptr = guest_allocator.alloc(len as u64); + let ptr = guest_allocator.alloc(u64::from(len)); let iovec = TestIovec::new(ptr, len as usize, false); iovecs.push(iovec); @@ -335,7 +335,7 @@ fn usb_storage_functional_get_max_lun() { xhci.doorbell_write(slot_id, CONTROL_ENDPOINT_ID); let evt = xhci.fetch_event(PRIMARY_INTERRUPTER_ID).unwrap(); assert_eq!(evt.ccode, TRBCCode::Success as u32); - let buf = xhci.get_transfer_data_indirect(evt.ptr - TRB_SIZE as u64, 1); + let buf = xhci.get_transfer_data_indirect(evt.ptr - u64::from(TRB_SIZE), 1); assert_eq!(buf, [0]); @@ -878,7 +878,7 @@ fn usb_storage_cbw_invalid_endpoint() { LittleEndian::write_u32(&mut cbw_buf[0..4], cbw.sig); let mut iovecs = Vec::new(); - let ptr = guest_allocator.borrow_mut().alloc(CBW_SIZE as u64); + let ptr = guest_allocator.borrow_mut().alloc(u64::from(CBW_SIZE)); xhci.mem_write(ptr, &cbw_buf); let iovec = TestIovec::new(ptr, CBW_SIZE as usize, false); @@ -927,7 +927,7 @@ fn usb_storage_csw_invalid_endpoint() { // Test 2: CSW phase. let mut iovecs = Vec::new(); - let ptr = guest_allocator.borrow_mut().alloc(CSW_SIZE as u64); + let ptr = guest_allocator.borrow_mut().alloc(u64::from(CSW_SIZE)); let iovec = TestIovec::new(ptr, CSW_SIZE as usize, false); iovecs.push(iovec); diff --git a/tests/mod_test/tests/usb_test.rs b/tests/mod_test/tests/usb_test.rs index 8e7070fa..a8713926 100644 --- a/tests/mod_test/tests/usb_test.rs +++ b/tests/mod_test/tests/usb_test.rs @@ -487,7 +487,7 @@ fn test_xhci_keyboard_over_ring_limit() { xhci.queue_link_trb( slot_id, HID_DEVICE_ENDPOINT_ID, - org_ptr + TRB_SIZE as u64 * 64, + org_ptr + u64::from(TRB_SIZE) * 64, false, ); } else if i == 1 { @@ -948,58 +948,59 @@ fn test_xhci_keyboard_controller_init_invalid_register() { xhci.read_capability(); let old_value = xhci .pci_dev - .io_readl(xhci.bar_addr, XHCI_PCI_CAP_OFFSET as u64 + 0x2c); + .io_readl(xhci.bar_addr, u64::from(XHCI_PCI_CAP_OFFSET) + 0x2c); xhci.pci_dev - .io_writel(xhci.bar_addr, XHCI_PCI_CAP_OFFSET as u64 + 0x2c, 0xffff); + .io_writel(xhci.bar_addr, u64::from(XHCI_PCI_CAP_OFFSET) + 0x2c, 0xffff); let value = xhci .pci_dev - .io_readl(xhci.bar_addr, XHCI_PCI_CAP_OFFSET as u64 + 0x2c); + .io_readl(xhci.bar_addr, u64::from(XHCI_PCI_CAP_OFFSET) + 0x2c); assert_eq!(value, old_value); // Case 3: write invalid slot. xhci.pci_dev.io_writel( xhci.bar_addr, - XHCI_PCI_OPER_OFFSET as u64 + XHCI_OPER_REG_CONFIG as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_CONFIG as u64, 0xffff, ); let config = xhci.pci_dev.io_readl( xhci.bar_addr, - XHCI_PCI_OPER_OFFSET as u64 + XHCI_OPER_REG_CONFIG as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_CONFIG as u64, ); assert_ne!(config, 0xffff); // Case 4: invalid oper xhci.pci_dev.io_writel( xhci.bar_addr, - XHCI_PCI_OPER_OFFSET as u64 + XHCI_OPER_REG_USBSTS as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_USBSTS as u64, 0xffff, ); let status = xhci.pci_dev.io_readl( xhci.bar_addr, - XHCI_PCI_OPER_OFFSET as u64 + XHCI_OPER_REG_USBSTS as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_USBSTS as u64, ); assert_ne!(status, 0xffff); // Device Notify Control xhci.pci_dev.io_writel( xhci.bar_addr, - XHCI_PCI_OPER_OFFSET as u64 + XHCI_OPER_REG_DNCTRL as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_DNCTRL as u64, 0x12345, ); let ndctrl = xhci.pci_dev.io_readl( xhci.bar_addr, - XHCI_PCI_OPER_OFFSET as u64 + XHCI_OPER_REG_DNCTRL as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_DNCTRL as u64, ); assert_eq!(ndctrl, 0x12345 & XHCI_OPER_NE_MASK); // invalid port offset. let invalid_offset = 0x7; xhci.pci_dev.io_writel( xhci.bar_addr, - XHCI_PCI_PORT_OFFSET as u64 + invalid_offset, + u64::from(XHCI_PCI_PORT_OFFSET) + invalid_offset, 0xff, ); - let invalid_offset = xhci - .pci_dev - .io_readl(xhci.bar_addr, XHCI_PCI_PORT_OFFSET as u64 + invalid_offset); + let invalid_offset = xhci.pci_dev.io_readl( + xhci.bar_addr, + u64::from(XHCI_PCI_PORT_OFFSET) + invalid_offset, + ); assert_eq!(invalid_offset, 0); xhci.init_device_context_base_address_array_pointer(); @@ -1010,25 +1011,28 @@ fn test_xhci_keyboard_controller_init_invalid_register() { xhci.interrupter_regs_writeq(0, XHCI_INTR_REG_ERSTBA_LO, 0); // micro frame index. xhci.pci_dev - .io_writel(xhci.bar_addr, XHCI_PCI_RUNTIME_OFFSET as u64, 0xf); + .io_writel(xhci.bar_addr, u64::from(XHCI_PCI_RUNTIME_OFFSET), 0xf); let mf_index = xhci .pci_dev - .io_readl(xhci.bar_addr, XHCI_PCI_RUNTIME_OFFSET as u64); + .io_readl(xhci.bar_addr, u64::from(XHCI_PCI_RUNTIME_OFFSET)); assert!(mf_index <= 0x3fff); // invalid offset - xhci.pci_dev - .io_writel(xhci.bar_addr, XHCI_PCI_RUNTIME_OFFSET as u64 + 0x1008, 0xf); + xhci.pci_dev.io_writel( + xhci.bar_addr, + u64::from(XHCI_PCI_RUNTIME_OFFSET) + 0x1008, + 0xf, + ); let over_offset = xhci .pci_dev - .io_readl(xhci.bar_addr, XHCI_PCI_RUNTIME_OFFSET as u64 + 0x1008); + .io_readl(xhci.bar_addr, u64::from(XHCI_PCI_RUNTIME_OFFSET) + 0x1008); assert_eq!(over_offset, 0); // Case 6: invalid doorbell xhci.pci_dev - .io_writel(xhci.bar_addr, XHCI_PCI_DOORBELL_OFFSET as u64, 0xf); + .io_writel(xhci.bar_addr, u64::from(XHCI_PCI_DOORBELL_OFFSET), 0xf); let invalid_db = xhci .pci_dev - .io_readl(xhci.bar_addr, XHCI_PCI_DOORBELL_OFFSET as u64); + .io_readl(xhci.bar_addr, u64::from(XHCI_PCI_DOORBELL_OFFSET)); assert_eq!(invalid_db, 0); // Case 7: invalid size @@ -1468,7 +1472,7 @@ fn test_xhci_keyboard_device_init_invalid_request() { let device_req = UsbDeviceRequest { request_type: USB_DEVICE_IN_REQUEST, request: USB_REQUEST_GET_DESCRIPTOR, - value: (USB_DT_CONFIGURATION as u16) << 8 | 6, + value: u16::from(USB_DT_CONFIGURATION) << 8 | 6, index: 10, length: 10, }; @@ -1545,13 +1549,15 @@ fn test_xhci_keyboard_device_init_invalid_control() { let device_req = UsbDeviceRequest { request_type: USB_DEVICE_IN_REQUEST, request: USB_REQUEST_GET_DESCRIPTOR, - value: (USB_DT_CONFIGURATION as u16) << 8, + value: u16::from(USB_DT_CONFIGURATION) << 8, index: 0, length: 64, }; // Case 1: no SetUp Stage. // Data Stage. - let ptr = guest_allocator.borrow_mut().alloc(device_req.length as u64); + let ptr = guest_allocator + .borrow_mut() + .alloc(u64::from(device_req.length)); let in_dir = device_req.request_type & USB_DIRECTION_DEVICE_TO_HOST == USB_DIRECTION_DEVICE_TO_HOST; let mut data_trb = TestNormalTRB::generate_data_td(ptr, device_req.length, in_dir); @@ -1569,7 +1575,9 @@ fn test_xhci_keyboard_device_init_invalid_control() { let mut setup_trb = TestNormalTRB::generate_setup_td(&device_req); xhci.queue_trb(slot_id, CONTROL_ENDPOINT_ID, &mut setup_trb); // Data Stage. - let ptr = guest_allocator.borrow_mut().alloc(device_req.length as u64); + let ptr = guest_allocator + .borrow_mut() + .alloc(u64::from(device_req.length)); let in_dir = device_req.request_type & USB_DIRECTION_DEVICE_TO_HOST == USB_DIRECTION_DEVICE_TO_HOST; let mut data_trb = TestNormalTRB::generate_data_td(ptr, device_req.length, in_dir); @@ -1587,7 +1595,9 @@ fn test_xhci_keyboard_device_init_invalid_control() { setup_trb.set_idt_flag(false); xhci.queue_trb(slot_id, CONTROL_ENDPOINT_ID, &mut setup_trb); // Data Stage. - let ptr = guest_allocator.borrow_mut().alloc(device_req.length as u64); + let ptr = guest_allocator + .borrow_mut() + .alloc(u64::from(device_req.length)); let in_dir = device_req.request_type & USB_DIRECTION_DEVICE_TO_HOST == USB_DIRECTION_DEVICE_TO_HOST; let mut data_trb = TestNormalTRB::generate_data_td(ptr, device_req.length, in_dir); @@ -1605,7 +1615,9 @@ fn test_xhci_keyboard_device_init_invalid_control() { setup_trb.set_trb_transfer_length(11); xhci.queue_trb(slot_id, CONTROL_ENDPOINT_ID, &mut setup_trb); // Data Stage. - let ptr = guest_allocator.borrow_mut().alloc(device_req.length as u64); + let ptr = guest_allocator + .borrow_mut() + .alloc(u64::from(device_req.length)); let in_dir = device_req.request_type & USB_DIRECTION_DEVICE_TO_HOST == USB_DIRECTION_DEVICE_TO_HOST; let mut data_trb = TestNormalTRB::generate_data_td(ptr, device_req.length, in_dir); @@ -1622,7 +1634,9 @@ fn test_xhci_keyboard_device_init_invalid_control() { let mut setup_trb = TestNormalTRB::generate_setup_td(&device_req); xhci.queue_trb(slot_id, CONTROL_ENDPOINT_ID, &mut setup_trb); // Data Stage. - let ptr = guest_allocator.borrow_mut().alloc(device_req.length as u64); + let ptr = guest_allocator + .borrow_mut() + .alloc(u64::from(device_req.length)); let in_dir = device_req.request_type & USB_DIRECTION_DEVICE_TO_HOST == USB_DIRECTION_DEVICE_TO_HOST; let mut data_trb = TestNormalTRB::generate_data_td(ptr, device_req.length, in_dir); @@ -1871,7 +1885,7 @@ fn test_xhci_keyboard_device_init_device_request_repeat() { xhci.doorbell_write(slot_id, CONTROL_ENDPOINT_ID); let evt = xhci.fetch_event(PRIMARY_INTERRUPTER_ID).unwrap(); assert_eq!(evt.ccode, TRBCCode::ShortPacket as u32); - let buf = xhci.get_transfer_data_indirect(evt.ptr - TRB_SIZE as u64, 2); + let buf = xhci.get_transfer_data_indirect(evt.ptr - u64::from(TRB_SIZE), 2); assert_eq!(buf, [0, 0]); // set configuration xhci.set_configuration(slot_id, 1); @@ -1883,7 +1897,7 @@ fn test_xhci_keyboard_device_init_device_request_repeat() { xhci.doorbell_write(slot_id, CONTROL_ENDPOINT_ID); let evt = xhci.fetch_event(PRIMARY_INTERRUPTER_ID).unwrap(); assert_eq!(evt.ccode, TRBCCode::ShortPacket as u32); - let buf = xhci.get_transfer_data_indirect(evt.ptr - TRB_SIZE as u64, 2); + let buf = xhci.get_transfer_data_indirect(evt.ptr - u64::from(TRB_SIZE), 2); assert_eq!(buf[0], 1); // Set remote wakeup. xhci.set_feature(slot_id, USB_DEVICE_REMOTE_WAKEUP as u16); @@ -1895,7 +1909,7 @@ fn test_xhci_keyboard_device_init_device_request_repeat() { xhci.doorbell_write(slot_id, CONTROL_ENDPOINT_ID); let evt = xhci.fetch_event(PRIMARY_INTERRUPTER_ID).unwrap(); assert_eq!(evt.ccode, TRBCCode::ShortPacket as u32); - let buf = xhci.get_transfer_data_indirect(evt.ptr - TRB_SIZE as u64, 2); + let buf = xhci.get_transfer_data_indirect(evt.ptr - u64::from(TRB_SIZE), 2); assert_eq!(buf, [2, 0]); // Clear remote wakeup. xhci.clear_feature(slot_id, USB_DEVICE_REMOTE_WAKEUP as u16); @@ -2162,7 +2176,7 @@ fn test_xhci_tablet_over_ring_limit() { xhci.queue_link_trb( slot_id, HID_DEVICE_ENDPOINT_ID, - org_ptr + TRB_SIZE as u64 * 64, + org_ptr + u64::from(TRB_SIZE) * 64, false, ); } else if i == 1 { @@ -2236,7 +2250,7 @@ fn test_xhci_tablet_device_init_control_command() { xhci.doorbell_write(slot_id, CONTROL_ENDPOINT_ID); let evt = xhci.fetch_event(PRIMARY_INTERRUPTER_ID).unwrap(); assert_eq!(evt.ccode, TRBCCode::ShortPacket as u32); - let buf = xhci.get_transfer_data_indirect(evt.ptr - TRB_SIZE as u64, HID_POINTER_LEN); + let buf = xhci.get_transfer_data_indirect(evt.ptr - u64::from(TRB_SIZE), HID_POINTER_LEN); assert_eq!(buf, [0, 0, 0, 0, 0, 0, 0]); xhci.test_pointer_event(slot_id, test_state.clone()); diff --git a/tests/mod_test/tests/virtio_test.rs b/tests/mod_test/tests/virtio_test.rs index 0e7cb237..2acebf3f 100644 --- a/tests/mod_test/tests/virtio_test.rs +++ b/tests/mod_test/tests/virtio_test.rs @@ -180,7 +180,7 @@ fn check_req_result( fn check_queue(blk: Rc>, desc: u64, avail: u64, used: u64) { let bar = blk.borrow().bar; - let common_base = blk.borrow().common_base as u64; + let common_base = u64::from(blk.borrow().common_base); let reqs = [ (offset_of!(VirtioPciCommonCfg, queue_desc_lo), desc), (offset_of!(VirtioPciCommonCfg, queue_desc_hi), desc >> 32), @@ -452,7 +452,7 @@ fn virtio_feature_indirect() { free_head = vqs[0] .borrow_mut() .add(test_state.clone(), req_addr, 8, false); - let offset = free_head as u64 * VRING_DESC_SIZE + offset_of!(VringDesc, flags) as u64; + let offset = u64::from(free_head) * VRING_DESC_SIZE + offset_of!(VringDesc, flags) as u64; test_state .borrow() .writew(vqs[0].borrow().desc + offset as u64, VRING_DESC_F_NEXT); @@ -485,7 +485,7 @@ fn virtio_feature_indirect() { free_head = vqs[0] .borrow_mut() .add(test_state.clone(), req_addr, 8, false); - let offset = free_head as u64 * VRING_DESC_SIZE + offset_of!(VringDesc, flags) as u64; + let offset = u64::from(free_head) * VRING_DESC_SIZE + offset_of!(VringDesc, flags) as u64; test_state .borrow() .writew(vqs[0].borrow().desc + offset as u64, VRING_DESC_F_NEXT); @@ -498,7 +498,7 @@ fn virtio_feature_indirect() { indirect_req.add_desc(test_state.clone(), req_addr + 8, 8, false); indirect_req.add_desc( test_state.clone(), - req_addr + REQ_ADDR_LEN as u64, + req_addr + u64::from(REQ_ADDR_LEN), 513, true, ); @@ -523,7 +523,7 @@ fn virtio_feature_indirect() { String::from_utf8( test_state .borrow() - .memread(req_addr + REQ_ADDR_LEN as u64, 4) + .memread(req_addr + u64::from(REQ_ADDR_LEN), 4) ) .unwrap(), "TEST" @@ -595,7 +595,7 @@ fn virtio_feature_indirect_and_event_idx() { let free_head = vqs[0] .borrow_mut() .add(test_state.clone(), req_addr, REQ_ADDR_LEN, false); - let offset = free_head as u64 * VRING_DESC_SIZE + offset_of!(VringDesc, flags) as u64; + let offset = u64::from(free_head) * VRING_DESC_SIZE + offset_of!(VringDesc, flags) as u64; test_state .borrow() .writew(vqs[0].borrow().desc + offset as u64, VRING_DESC_F_NEXT); @@ -608,7 +608,7 @@ fn virtio_feature_indirect_and_event_idx() { indirect_req.setup(alloc.clone(), test_state.clone(), 2); indirect_req.add_desc( test_state.clone(), - req_addr + REQ_ADDR_LEN as u64, + req_addr + u64::from(REQ_ADDR_LEN), REQ_DATA_LEN, false, ); @@ -874,12 +874,12 @@ fn virtio_init_device_abnormal_features() { fn virtio_init_device_abnormal_vring_info() { // (err_type, value, ack, device_status) let reqs = [ - (0, u16::MAX as u64, 0, 0), + (0, u64::from(u16::MAX), 0, 0), (0, 2, 0, 0), (1, 0_u64, 0xff, 0), (1, 255, 0xff, 0), (1, 1 << 15, 0xff, 0), - (1, u16::MAX as u64, 0xff, 0), + (1, u64::from(u16::MAX), 0xff, 0), (2, 0, 0xff, 0), (3, 0, 0xff, 0), (4, 0, 0xff, 0), @@ -921,7 +921,7 @@ fn virtio_init_device_abnormal_vring_info() { blk.borrow().queue_select(value as u16); } - let queue_size = blk.borrow().get_queue_size() as u32; + let queue_size = u32::from(blk.borrow().get_queue_size()); // Set invalid queue size. if err_type == 1 { @@ -937,18 +937,19 @@ fn virtio_init_device_abnormal_vring_info() { vq.borrow_mut().indirect = (features & (1 << VIRTIO_RING_F_INDIRECT_DESC)) != 0; vq.borrow_mut().event = (features & (1 << VIRTIO_RING_F_EVENT_IDX)) != 0; - let addr = alloc - .borrow_mut() - .alloc(get_vring_size(queue_size, VIRTIO_PCI_VRING_ALIGN) as u64); + let addr = alloc.borrow_mut().alloc(u64::from(get_vring_size( + queue_size, + VIRTIO_PCI_VRING_ALIGN, + ))); vq.borrow_mut().desc = addr; - let avail = addr + (queue_size * size_of::() as u32) as u64 + 16; + let avail = addr + u64::from(queue_size * size_of::() as u32) + 16; vq.borrow_mut().avail = avail; let used = (avail - + (size_of::() as u32 * (3 + queue_size)) as u64 - + VIRTIO_PCI_VRING_ALIGN as u64 + + u64::from(size_of::() as u32 * (3 + queue_size)) + + u64::from(VIRTIO_PCI_VRING_ALIGN) - 1) - & !(VIRTIO_PCI_VRING_ALIGN as u64 - 1) + 16; + & !(u64::from(VIRTIO_PCI_VRING_ALIGN) - 1) + 16; vq.borrow_mut().used = used + 16; match err_type { @@ -1015,32 +1016,32 @@ fn virtio_init_device_abnormal_vring_info() { let notify_off = blk.borrow().pci_dev.io_readw( blk.borrow().bar, - blk.borrow().common_base as u64 + u64::from(blk.borrow().common_base) + offset_of!(VirtioPciCommonCfg, queue_notify_off) as u64, ); - vq.borrow_mut().queue_notify_off = blk.borrow().notify_base as u64 - + notify_off as u64 * blk.borrow().notify_off_multiplier as u64; + vq.borrow_mut().queue_notify_off = u64::from(blk.borrow().notify_base) + + u64::from(notify_off) * u64::from(blk.borrow().notify_off_multiplier); let offset = offset_of!(VirtioPciCommonCfg, queue_enable) as u64; // TEST enable vq with 0 if err_type == 9 { blk.borrow().pci_dev.io_writew( blk.borrow().bar, - blk.borrow().common_base as u64 + offset, + u64::from(blk.borrow().common_base) + offset, 0, ); } else { blk.borrow().pci_dev.io_writew( blk.borrow().bar, - blk.borrow().common_base as u64 + u64::from(blk.borrow().common_base) + offset_of!(VirtioPciCommonCfg, queue_enable) as u64, 1, ); if err_type == 10 { - let status = blk - .borrow() - .pci_dev - .io_readw(blk.borrow().bar, blk.borrow().common_base as u64 + offset); + let status = blk.borrow().pci_dev.io_readw( + blk.borrow().bar, + u64::from(blk.borrow().common_base) + offset, + ); assert_eq!(status, 1); } } @@ -1481,11 +1482,11 @@ fn virtio_io_abnormal_desc_len() { if length == 16 { test_state.borrow().writel( indirect_desc + offset_of!(VringDesc, len) as u64, - u16::MAX as u32 * (VRING_DESC_SIZE as u32 + 1), + u32::from(u16::MAX) * (VRING_DESC_SIZE as u32 + 1), ); test_state.borrow().writel( indirect_desc + offset_of!(VringDesc, flags) as u64, - (VRING_DESC_F_INDIRECT | VRING_DESC_F_NEXT) as u32, + u32::from(VRING_DESC_F_INDIRECT | VRING_DESC_F_NEXT), ); } } @@ -1595,7 +1596,7 @@ fn virtio_io_abnormal_desc_flags_2() { let free_head = vqs[0] .borrow_mut() .add(test_state.clone(), req_addr, REQ_ADDR_LEN, false); - let offset = free_head as u64 * VRING_DESC_SIZE + offset_of!(VringDesc, flags) as u64; + let offset = u64::from(free_head) * VRING_DESC_SIZE + offset_of!(VringDesc, flags) as u64; test_state .borrow() .writew(vqs[0].borrow().desc + offset as u64, VRING_DESC_F_NEXT); @@ -1607,7 +1608,7 @@ fn virtio_io_abnormal_desc_flags_2() { indirect_req.setup(alloc.clone(), test_state.clone(), 2); indirect_req.add_desc( test_state.clone(), - req_addr + REQ_ADDR_LEN as u64, + req_addr + u64::from(REQ_ADDR_LEN), REQ_DATA_LEN, false, ); @@ -1670,7 +1671,7 @@ fn virtio_io_abnormal_desc_flags_3() { .borrow_mut() .add(test_state.clone(), req_addr, 8, false); - let offset = free_head as u64 * VRING_DESC_SIZE + offset_of!(VringDesc, flags) as u64; + let offset = u64::from(free_head) * VRING_DESC_SIZE + offset_of!(VringDesc, flags) as u64; test_state .borrow() .writew(vqs[0].borrow().desc + offset as u64, VRING_DESC_F_NEXT); @@ -1687,7 +1688,7 @@ fn virtio_io_abnormal_desc_flags_3() { .add_indirect(test_state.clone(), indirect_req, true); // Add VRING_DESC_F_WRITE or VRING_DESC_F_NEXT to desc[0]->flags; - let addr = vqs[0].borrow().desc + 16_u64 * (free_head + 1) as u64 + 12; + let addr = vqs[0].borrow().desc + 16_u64 * u64::from(free_head + 1) + 12; let flags = test_state.borrow().readw(addr) | flag; test_state.borrow().writew(addr, flags); blk.borrow().virtqueue_notify(vqs[0].clone()); @@ -1871,7 +1872,7 @@ fn virtio_io_abnormal_indirect_desc_elem_num() { let free_head = vqs[0] .borrow_mut() .add(test_state.clone(), req_addr, REQ_ADDR_LEN, false); - let offset = free_head as u64 * VRING_DESC_SIZE + offset_of!(VringDesc, flags) as u64; + let offset = u64::from(free_head) * VRING_DESC_SIZE + offset_of!(VringDesc, flags) as u64; test_state .borrow() .writew(vqs[0].borrow().desc + offset as u64, VRING_DESC_F_NEXT); diff --git a/tests/mod_test/tests/virtiofs_test.rs b/tests/mod_test/tests/virtiofs_test.rs index 544c8808..941626a4 100644 --- a/tests/mod_test/tests/virtiofs_test.rs +++ b/tests/mod_test/tests/virtiofs_test.rs @@ -1326,7 +1326,7 @@ fn get_xattr(fs: &VirtioFsTest, name: String, nodeid: u64) -> (FuseOutHeader, St let fuse_read_out = fs .state .borrow() - .memread(outbodyaddr, DEFAULT_XATTR_SIZE as u64); + .memread(outbodyaddr, u64::from(DEFAULT_XATTR_SIZE)); let attr = String::from_utf8(fuse_read_out).unwrap(); (out_header, attr) @@ -1804,7 +1804,7 @@ fn regularfile_xattr_test() { let attr_list = fs .state .borrow() - .memread(outbodyaddr, DEFAULT_XATTR_SIZE as u64); + .memread(outbodyaddr, u64::from(DEFAULT_XATTR_SIZE)); // The first attr is "security.selinux" let (_attr1, next1) = read_cstring(attr_list.clone(), 0); // The next attrs are what we set by FUSE_SETXATTR. Check it. diff --git a/tests/mod_test/tests/vnc_test.rs b/tests/mod_test/tests/vnc_test.rs index e4f4fdf1..f6065c6a 100644 --- a/tests/mod_test/tests/vnc_test.rs +++ b/tests/mod_test/tests/vnc_test.rs @@ -554,12 +554,12 @@ fn test_vnc_kbd_mouse() { assert!(vnc_client.connect(TestAuthType::VncAuthNone).is_ok()); // Key event. for &(name, keysym, keycode) in KEYEVENTLIST.iter() { - assert!(vnc_client.test_key_event(0, keysym as u32).is_ok()); + assert!(vnc_client.test_key_event(0, u32::from(keysym)).is_ok()); let msg = input.borrow_mut().read_input_event(); println!("key {:?}: {:?}", name, msg); assert_eq!(msg.keycode, keycode); assert_eq!(msg.down, 0); - assert!(vnc_client.test_key_event(1, keysym as u32).is_ok()); + assert!(vnc_client.test_key_event(1, u32::from(keysym)).is_ok()); let msg = input.borrow_mut().read_input_event(); println!("key {:?}: {:?}", name, msg); diff --git a/ui/src/console.rs b/ui/src/console.rs index 97dc06e9..8977f1a2 100644 --- a/ui/src/console.rs +++ b/ui/src/console.rs @@ -777,8 +777,8 @@ pub fn console_select(con_id: Option) -> Result<()> { /// * `height` - height of image. /// * `msg` - test messages showed in display. pub fn create_msg_surface(width: i32, height: i32, msg: String) -> Option { - if !(0..MAX_WINDOW_WIDTH as i32).contains(&width) - || !(0..MAX_WINDOW_HEIGHT as i32).contains(&height) + if !(0..i32::from(MAX_WINDOW_WIDTH)).contains(&width) + || !(0..i32::from(MAX_WINDOW_HEIGHT)).contains(&height) { error!("The size of image is invalid!"); return None; diff --git a/ui/src/pixman.rs b/ui/src/pixman.rs index 8c5a2008..21632106 100644 --- a/ui/src/pixman.rs +++ b/ui/src/pixman.rs @@ -36,7 +36,7 @@ pub struct ColorInfo { impl ColorInfo { pub fn set_color_info(&mut self, shift: u8, max: u16) { - self.mask = (max as u32) << (shift as u32); + self.mask = u32::from(max) << u32::from(shift); self.shift = shift; self.max = if max == 0 { 0xFF } else { max as u8 }; self.bits = max.popcnt() as u8; @@ -84,10 +84,14 @@ impl PixelFormat { self.green.max = ((1 << self.green.bits) - 1) as u8; self.blue.max = ((1 << self.blue.bits) - 1) as u8; - self.alpha_chl.mask = self.alpha_chl.max.wrapping_shl(self.alpha_chl.shift as u32) as u32; - self.red.mask = self.red.max.wrapping_shl(self.red.shift as u32) as u32; - self.green.mask = self.green.max.wrapping_shl(self.green.shift as u32) as u32; - self.blue.mask = self.blue.max.wrapping_shl(self.blue.shift as u32) as u32; + self.alpha_chl.mask = u32::from( + self.alpha_chl + .max + .wrapping_shl(u32::from(self.alpha_chl.shift)), + ); + self.red.mask = u32::from(self.red.max.wrapping_shl(u32::from(self.red.shift))); + self.green.mask = u32::from(self.green.max.wrapping_shl(u32::from(self.green.shift))); + self.blue.mask = u32::from(self.blue.max.wrapping_shl(u32::from(self.blue.shift))); } pub fn is_default_pixel_format(&self) -> bool { diff --git a/util/src/aio/mod.rs b/util/src/aio/mod.rs index a9427f67..ec978d80 100644 --- a/util/src/aio/mod.rs +++ b/util/src/aio/mod.rs @@ -278,14 +278,14 @@ impl AioCb { pub fn is_misaligned(&self) -> bool { if self.direct && (self.opcode == OpCode::Preadv || self.opcode == OpCode::Pwritev) { - if (self.offset as u64) & (self.req_align as u64 - 1) != 0 { + if (self.offset as u64) & (u64::from(self.req_align) - 1) != 0 { return true; } for iov in self.iovec.iter() { - if iov.iov_base & (self.buf_align as u64 - 1) != 0 { + if iov.iov_base & (u64::from(self.buf_align) - 1) != 0 { return true; } - if iov.iov_len & (self.req_align as u64 - 1) != 0 { + if iov.iov_len & (u64::from(self.req_align) - 1) != 0 { return true; } } @@ -295,8 +295,8 @@ impl AioCb { pub fn handle_misaligned(&mut self) -> Result { let max_len = round_down( - self.nbytes + self.req_align as u64 * 2, - self.req_align as u64, + self.nbytes + u64::from(self.req_align) * 2, + u64::from(self.req_align), ) .with_context(|| "Failed to round down request length.")?; // Set upper limit of buffer length to avoid OOM. @@ -327,10 +327,10 @@ impl AioCb { bounce_buffer: *mut c_void, buffer_len: u64, ) -> Result<()> { - let offset_align = round_down(self.offset as u64, self.req_align as u64) + let offset_align = round_down(self.offset as u64, u64::from(self.req_align)) .with_context(|| "Failed to round down request offset.")?; let high = self.offset as u64 + self.nbytes; - let high_align = round_up(high, self.req_align as u64) + let high_align = round_up(high, u64::from(self.req_align)) .with_context(|| "Failed to round up request high edge.")?; match self.opcode { @@ -403,7 +403,7 @@ impl AioCb { head_loaded = true; } // Is head and tail in the same alignment section? - let same_section = (offset_align + self.req_align as u64) >= high; + let same_section = (offset_align + u64::from(self.req_align)) >= high; let need_tail = !(same_section && head_loaded) && (high_align > high); let mut offset = offset_align; @@ -419,7 +419,7 @@ impl AioCb { if real_high == high && need_tail { let len = raw_read( self.file_fd, - bounce_buffer as u64 + nbytes - self.req_align as u64, + bounce_buffer as u64 + nbytes - u64::from(self.req_align), self.req_align as usize, (offset + nbytes) as usize - self.req_align as usize, ); @@ -574,7 +574,7 @@ impl Aio { -1 } }; - return (self.complete_func)(&cb, ret as i64); + return (self.complete_func)(&cb, i64::from(ret)); } cb.try_convert_to_write_zero(); @@ -586,7 +586,7 @@ impl Aio { OpCode::WriteZeroes | OpCode::WriteZeroesUnmap => cb.write_zeroes_sync(), OpCode::Noop => return Err(anyhow!("Aio opcode is not specified.")), }; - (self.complete_func)(&cb, ret as i64) + (self.complete_func)(&cb, i64::from(ret)) } pub fn flush_request(&mut self) -> Result<()> { @@ -941,7 +941,7 @@ mod tests { let fsize: usize = 2 << 20; // perform sync rw in the same alignment section. - let minor_align = align as u64 - 100; + let minor_align = u64::from(align) - 100; perform_sync_rw(fsize, 0, minor_align, opcode, direct, align); perform_sync_rw(fsize, 50, minor_align, opcode, direct, align); perform_sync_rw(fsize, 100, minor_align, opcode, direct, align); diff --git a/util/src/aio/threads.rs b/util/src/aio/threads.rs index cab4fe08..1aecf948 100644 --- a/util/src/aio/threads.rs +++ b/util/src/aio/threads.rs @@ -63,7 +63,7 @@ impl ThreadsTasks { let aio_event = AioEvent { user_data: task.user_data, status: 0, - res: res as i64, + res: i64::from(res), }; self.complete_lists.lock().unwrap().push(aio_event); self.notify_event diff --git a/util/src/aio/uring.rs b/util/src/aio/uring.rs index 367a85eb..f1d373a6 100644 --- a/util/src/aio/uring.rs +++ b/util/src/aio/uring.rs @@ -105,7 +105,7 @@ impl AioContext for IoUringContext { self.events.push(AioEvent { user_data: cqe.user_data(), status: 0, - res: cqe.result() as i64, + res: i64::from(cqe.result()), }); } &self.events diff --git a/util/src/edid.rs b/util/src/edid.rs index 17080d70..f124d6d6 100644 --- a/util/src/edid.rs +++ b/util/src/edid.rs @@ -495,7 +495,7 @@ impl EdidInfo { fn fullfill_checksum(&mut self, edid_array: &mut [u8]) { let mut sum: u32 = 0; for elem in edid_array.iter() { - sum += *elem as u32; + sum += u32::from(*elem); } sum &= 0xff; if sum != 0 { diff --git a/util/src/file.rs b/util/src/file.rs index 0fd94450..fd06c78e 100644 --- a/util/src/file.rs +++ b/util/src/file.rs @@ -92,7 +92,7 @@ pub fn get_file_alignment(file: &File, direct: bool) -> (u32, u32) { while align <= MAX_FILE_ALIGN { if is_io_aligned( file, - aligned_buffer as u64 + align as u64, + aligned_buffer as u64 + u64::from(align), MAX_FILE_ALIGN as usize, ) { buf_align = align; diff --git a/util/src/leak_bucket.rs b/util/src/leak_bucket.rs index cde308c4..9390e17b 100644 --- a/util/src/leak_bucket.rs +++ b/util/src/leak_bucket.rs @@ -75,7 +75,7 @@ impl LeakBucket { // update the water level let now = get_current_time(); let nanos = (now - self.prev_time).as_nanos(); - if nanos > (self.level * NANOSECONDS_PER_SECOND / self.capacity) as u128 { + if nanos > u128::from(self.level * NANOSECONDS_PER_SECOND / self.capacity) { self.level = 0; } else { self.level -= nanos as u64 * self.capacity / NANOSECONDS_PER_SECOND; diff --git a/util/src/logger.rs b/util/src/logger.rs index 889e788f..1652d83c 100644 --- a/util/src/logger.rs +++ b/util/src/logger.rs @@ -34,7 +34,7 @@ fn format_now() -> String { println!("{:?}", e); (0, 0) }); - let format_time = get_format_time(sec as i64); + let format_time = get_format_time(i64::from(sec)); format!( "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}.{:09}", @@ -63,7 +63,7 @@ impl FileRotate { self.current_size += Wrapping(size_inc); let sec = gettime()?.0; - let today = get_format_time(sec as i64)[2]; + let today = get_format_time(i64::from(sec))[2]; if self.current_size < Wrapping(LOG_ROTATE_SIZE_MAX) && self.create_day == today { return Ok(()); } diff --git a/util/src/num_ops.rs b/util/src/num_ops.rs index 2be535ae..bf193ce3 100644 --- a/util/src/num_ops.rs +++ b/util/src/num_ops.rs @@ -243,7 +243,7 @@ pub fn extract_u64(value: u64, start: u32, length: u32) -> Option { return None; } - Some((value >> start as u64) & (!(0_u64) >> (64 - length) as u64)) + Some((value >> u64::from(start)) & (!(0_u64) >> u64::from(64 - length))) } /// Deposit @fieldval into the 32 bit @value at the bit field specified @@ -371,8 +371,8 @@ pub fn write_data_u32(data: &mut [u8], value: u32) -> bool { /// ``` pub fn read_data_u32(data: &[u8], value: &mut u32) -> bool { *value = match data.len() { - 1 => data[0] as u32, - 2 => LittleEndian::read_u16(data) as u32, + 1 => u32::from(data[0]), + 2 => u32::from(LittleEndian::read_u16(data)), 4 => LittleEndian::read_u32(data), _ => { error!("Invalid data length: data len {}", data.len()); @@ -401,7 +401,7 @@ pub fn read_data_u32(data: &[u8], value: &mut u32) -> bool { /// ``` pub fn read_data_u16(data: &[u8], value: &mut u16) -> bool { *value = match data.len() { - 1 => data[0] as u16, + 1 => u16::from(data[0]), 2 => LittleEndian::read_u16(data), _ => { error!("Invalid data length: data len {}", data.len()); diff --git a/util/src/tap.rs b/util/src/tap.rs index 462de289..a523873e 100644 --- a/util/src/tap.rs +++ b/util/src/tap.rs @@ -140,7 +140,7 @@ impl Tap { pub fn set_offload(&self, flags: u32) -> Result<()> { let ret = // SAFETY: The parameter of file can be guaranteed to be legal, and other parameters are constant. - unsafe { ioctl_with_val(self.file.as_ref(), TUNSETOFFLOAD(), flags as libc::c_ulong) }; + unsafe { ioctl_with_val(self.file.as_ref(), TUNSETOFFLOAD(), u64::from(flags)) }; if ret < 0 { return Err(anyhow!("ioctl TUNSETOFFLOAD failed.".to_string())); } @@ -162,7 +162,7 @@ impl Tap { let flags = TUN_F_CSUM | TUN_F_UFO; ( // SAFETY: The parameter of file can be guaranteed to be legal, and other parameters are constant. - unsafe { ioctl_with_val(self.file.as_ref(), TUNSETOFFLOAD(), flags as libc::c_ulong) } + unsafe { ioctl_with_val(self.file.as_ref(), TUNSETOFFLOAD(), u64::from(flags)) } ) >= 0 } diff --git a/util/src/unix.rs b/util/src/unix.rs index 6a723ed2..ae1b1a41 100644 --- a/util/src/unix.rs +++ b/util/src/unix.rs @@ -278,7 +278,9 @@ impl UnixSock { let nex_cmsg_pos = (next_cmsg as *mut u8).wrapping_sub(msghdr.msg_control as usize) as u64; // SAFETY: Parameter is constant. - if nex_cmsg_pos.wrapping_add(unsafe { CMSG_LEN(0) } as u64) > msghdr.msg_controllen as u64 { + if nex_cmsg_pos.wrapping_add(u64::from(unsafe { CMSG_LEN(0) })) + > msghdr.msg_controllen as u64 + { null_mut() } else { next_cmsg @@ -420,7 +422,7 @@ impl UnixSock { if cmsg.cmsg_level == SOL_SOCKET && cmsg.cmsg_type == SCM_RIGHTS { // SAFETY: Input parameter is constant. - let fd_count = (cmsg.cmsg_len as u64 - unsafe { CMSG_LEN(0) } as u64) as usize + let fd_count = (cmsg.cmsg_len as u64 - u64::from(unsafe { CMSG_LEN(0) })) as usize / size_of::(); // SAFETY: // 1. the pointer of cmsg_ptr was created in this function and can be guaranteed not be null. diff --git a/vfio/src/vfio_pci.rs b/vfio/src/vfio_pci.rs index 5dad8163..aea7891c 100644 --- a/vfio/src/vfio_pci.rs +++ b/vfio/src/vfio_pci.rs @@ -230,13 +230,13 @@ impl VfioPciDevice { self.vfio_device.lock().unwrap().write_region( data.as_slice(), self.config_offset, - COMMAND as u64, + u64::from(COMMAND), )?; for i in 0..PCI_ROM_SLOT { let offset = BAR_0 as usize + REG_SIZE * i as usize; let v = le_read_u32(&self.base.config.config, offset)?; - if v & BAR_IO_SPACE as u32 != 0 { + if v & u32::from(BAR_IO_SPACE) != 0 { le_write_u32(&mut self.base.config.config, offset, v & !IO_BASE_ADDR_MASK)?; } else { le_write_u32( @@ -274,8 +274,8 @@ impl VfioPciDevice { Ok(VfioMsixInfo { table: MsixTable { table_bar: (table as u16 & MSIX_TABLE_BIR) as u8, - table_offset: (table & MSIX_TABLE_OFFSET) as u64, - table_size: (entries * MSIX_TABLE_ENTRY_SIZE) as u64, + table_offset: u64::from(table & MSIX_TABLE_OFFSET), + table_size: u64::from(entries * MSIX_TABLE_ENTRY_SIZE), }, entries, }) @@ -295,13 +295,13 @@ impl VfioPciDevice { locked_dev.read_region( data.as_mut_slice(), self.config_offset, - (BAR_0 + (REG_SIZE as u8) * i) as u64, + u64::from(BAR_0 + (REG_SIZE as u8) * i), )?; let mut region_type = RegionType::Mem32Bit; let pci_bar = LittleEndian::read_u32(&data); - if pci_bar & BAR_IO_SPACE as u32 != 0 { + if pci_bar & u32::from(BAR_IO_SPACE) != 0 { region_type = RegionType::Io; - } else if pci_bar & BAR_MEM_64BIT as u32 != 0 { + } else if pci_bar & u32::from(BAR_MEM_64BIT) != 0 { region_type = RegionType::Mem64Bit; } let vfio_region = infos.remove(0); @@ -515,7 +515,7 @@ impl VfioPciDevice { let mut locked_msix = msix.lock().unwrap(); locked_msix.table[offset as usize..(offset as usize + data.len())] .copy_from_slice(data); - let vector = offset / MSIX_TABLE_ENTRY_SIZE as u64; + let vector = offset / u64::from(MSIX_TABLE_ENTRY_SIZE); if locked_msix.is_vector_masked(vector as u16) { return true; } @@ -530,7 +530,7 @@ impl VfioPciDevice { msg_data: entry.data, masked: false, #[cfg(target_arch = "aarch64")] - dev_id: dev_id.load(Ordering::Acquire) as u32, + dev_id: u32::from(dev_id.load(Ordering::Acquire)), }; let mut locked_gsi_routes = cloned_gsi_routes.lock().unwrap(); @@ -737,7 +737,7 @@ impl VfioPciDevice { let gsi_route = GsiMsiRoute { irq_fd: None, gsi: -1, - nr: i as u32, + nr: u32::from(i), }; gsi_routes.push(gsi_route); } @@ -864,7 +864,7 @@ impl Device for VfioPciDevice { )?)); Result::with_context(self.register_bars(), || "Failed to register bars")?; - let devfn = self.base.devfn as u64; + let devfn = u64::from(self.base.devfn); let dev = Arc::new(Mutex::new(self)); let parent_bus = dev.lock().unwrap().parent_bus().unwrap().upgrade().unwrap(); let mut locked_bus = parent_bus.lock().unwrap(); @@ -971,7 +971,8 @@ impl PciDevOps for VfioPciDevice { ); if ranges_overlap(offset, size, COMMAND as usize, REG_SIZE).unwrap() { - if le_read_u32(&self.base.config.config, offset).unwrap() & COMMAND_MEMORY_SPACE as u32 + if le_read_u32(&self.base.config.config, offset).unwrap() + & u32::from(COMMAND_MEMORY_SPACE) != 0 { if let Err(e) = self.setup_bars_mmap() { diff --git a/virtio/src/device/balloon.rs b/virtio/src/device/balloon.rs index 4c981c18..4dd36fc0 100644 --- a/virtio/src/device/balloon.rs +++ b/virtio/src/device/balloon.rs @@ -218,7 +218,7 @@ impl Request { for elem_iov in iovec { request.iovec.push(GuestIovec { iov_base: elem_iov.addr, - iov_len: elem_iov.len as u64, + iov_len: u64::from(elem_iov.len), }); request.elem_cnt += elem_iov.len; } @@ -280,7 +280,7 @@ impl Request { while let Some(pfn) = iov_to_buf::(address_space, iov, offset) { offset += std::mem::size_of::() as u64; - let gpa: GuestAddress = GuestAddress((pfn as u64) << VIRTIO_BALLOON_PFN_SHIFT); + let gpa: GuestAddress = GuestAddress(u64::from(pfn) << VIRTIO_BALLOON_PFN_SHIFT); let (hva, shared) = match mem.lock().unwrap().get_host_address(gpa) { Some((addr, mem_share)) => (addr, mem_share), None => { @@ -741,7 +741,7 @@ impl BalloonIoHandler { /// Get the memory size of balloon. fn get_balloon_memory_size(&self) -> u64 { - (self.balloon_actual.load(Ordering::Acquire) as u64) << VIRTIO_BALLOON_PFN_SHIFT + u64::from(self.balloon_actual.load(Ordering::Acquire)) << VIRTIO_BALLOON_PFN_SHIFT } } @@ -916,9 +916,9 @@ impl ConfigCheck for BalloonConfig { { return Err(anyhow!(ConfigError::IllegalValue( "balloon membuf-percent".to_string(), - MEM_BUFFER_PERCENT_MIN as u64, + u64::from(MEM_BUFFER_PERCENT_MIN), false, - MEM_BUFFER_PERCENT_MAX as u64, + u64::from(MEM_BUFFER_PERCENT_MAX), false, ))); } @@ -927,9 +927,9 @@ impl ConfigCheck for BalloonConfig { { return Err(anyhow!(ConfigError::IllegalValue( "balloon monitor-interval".to_string(), - MONITOR_INTERVAL_SECOND_MIN as u64, + u64::from(MONITOR_INTERVAL_SECOND_MIN), false, - MONITOR_INTERVAL_SECOND_MAX as u64, + u64::from(MONITOR_INTERVAL_SECOND_MAX), false, ))); } @@ -1036,7 +1036,7 @@ impl Balloon { /// Get the size of memory that reclaimed by balloon. fn get_balloon_memory_size(&self) -> u64 { - (self.actual.load(Ordering::Acquire) as u64) << VIRTIO_BALLOON_PFN_SHIFT + u64::from(self.actual.load(Ordering::Acquire)) << VIRTIO_BALLOON_PFN_SHIFT } /// Get the actual memory size of guest. @@ -1291,13 +1291,13 @@ mod tests { bln.base.device_features = 1 | 1 << 32; bln.set_driver_features(0, 1); assert_eq!(bln.base.driver_features, 1); - assert_eq!(bln.base.driver_features, bln.driver_features(0) as u64); + assert_eq!(bln.base.driver_features, u64::from(bln.driver_features(0))); bln.base.driver_features = 1 << 32; bln.set_driver_features(1, 1); assert_eq!(bln.base.driver_features, 1 << 32); assert_eq!( bln.base.driver_features, - (bln.driver_features(1) as u64) << 32 + u64::from(bln.driver_features(1)) << 32 ); // Test methods of balloon. diff --git a/virtio/src/device/block.rs b/virtio/src/device/block.rs index cb0a51c0..d64c56fe 100644 --- a/virtio/src/device/block.rs +++ b/virtio/src/device/block.rs @@ -299,7 +299,7 @@ impl Request { ); } // Note: addr plus len has been checked not overflow in virtqueue. - let in_header = GuestAddress(in_iov_elem.addr.0 + in_iov_elem.len as u64 - 1); + let in_header = GuestAddress(in_iov_elem.addr.0 + u64::from(in_iov_elem.len) - 1); let mut request = Request { desc_index: elem.index, @@ -464,7 +464,7 @@ impl Request { let sector = LittleEndian::read_u64(segment.sector.as_bytes()); let num_sectors = LittleEndian::read_u32(segment.num_sectors.as_bytes()); if sector - .checked_add(num_sectors as u64) + .checked_add(u64::from(num_sectors)) .filter(|&off| off <= iohandler.disk_sectors) .is_none() || num_sectors > MAX_REQUEST_SECTORS @@ -485,7 +485,7 @@ impl Request { let block_backend = iohandler.block_backend.as_ref().unwrap(); let mut locked_backend = block_backend.lock().unwrap(); let offset = (sector as usize) << SECTOR_SHIFT; - let nbytes = (num_sectors as u64) << SECTOR_SHIFT; + let nbytes = u64::from(num_sectors) << SECTOR_SHIFT; trace::virtio_blk_handle_discard_write_zeroes_req(&opcode, flags, offset, nbytes); if opcode == OpCode::Discard { if flags == VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP { @@ -1068,7 +1068,7 @@ impl Block { // capacity: 64bits self.config_space.capacity = self.disk_sectors; // seg_max = queue_size - 2: 32bits - self.config_space.seg_max = self.queue_size_max() as u32 - 2; + self.config_space.seg_max = u32::from(self.queue_size_max()) - 2; if self.blk_cfg.num_queues.unwrap_or(1) > 1 { self.config_space.num_queues = self.blk_cfg.num_queues.unwrap_or(1); @@ -1547,14 +1547,14 @@ mod tests { let page = 0_u32; block.set_driver_features(page, driver_feature); assert_eq!(block.base.driver_features, 0_u64); - assert_eq!(block.driver_features(page) as u64, 0_u64); + assert_eq!(u64::from(block.driver_features(page)), 0_u64); assert_eq!(block.device_features(0_u32), 0_u32); let driver_feature: u32 = 0xFF; let page = 1_u32; block.set_driver_features(page, driver_feature); assert_eq!(block.base.driver_features, 0_u64); - assert_eq!(block.driver_features(page) as u64, 0_u64); + assert_eq!(u64::from(block.driver_features(page)), 0_u64); assert_eq!(block.device_features(1_u32), 0_u32); // If both the device feature bit and the front-end driver feature bit are @@ -1569,7 +1569,7 @@ mod tests { (1_u64 << VIRTIO_F_RING_INDIRECT_DESC) ); assert_eq!( - block.driver_features(page) as u64, + u64::from(block.driver_features(page)), (1_u64 << VIRTIO_F_RING_INDIRECT_DESC) ); assert_eq!( @@ -1663,10 +1663,10 @@ mod tests { queue_config.desc_table = GuestAddress(0); queue_config.addr_cache.desc_table_host = mem_space.get_host_address(queue_config.desc_table).unwrap(); - queue_config.avail_ring = GuestAddress(16 * DEFAULT_VIRTQUEUE_SIZE as u64); + queue_config.avail_ring = GuestAddress(16 * u64::from(DEFAULT_VIRTQUEUE_SIZE)); queue_config.addr_cache.avail_ring_host = mem_space.get_host_address(queue_config.avail_ring).unwrap(); - queue_config.used_ring = GuestAddress(32 * DEFAULT_VIRTQUEUE_SIZE as u64); + queue_config.used_ring = GuestAddress(32 * u64::from(DEFAULT_VIRTQUEUE_SIZE)); queue_config.addr_cache.used_ring_host = mem_space.get_host_address(queue_config.used_ring).unwrap(); queue_config.size = DEFAULT_VIRTQUEUE_SIZE; diff --git a/virtio/src/device/gpu.rs b/virtio/src/device/gpu.rs index d2c1078b..1145a30f 100644 --- a/virtio/src/device/gpu.rs +++ b/virtio/src/device/gpu.rs @@ -670,8 +670,8 @@ pub fn cal_image_hostmem(format: u32, width: u32, height: u32) -> (Option } }; let bpp = pixman_format_bpp(pixman_format as u32); - let stride = ((width as u64 * bpp as u64 + 0x1f) >> 5) * (size_of::() as u64); - match stride.checked_mul(height as u64) { + let stride = ((u64::from(width) * u64::from(bpp) + 0x1f) >> 5) * (size_of::() as u64); + match stride.checked_mul(u64::from(height)) { None => { error!( "stride * height is overflow: width {} height {} stride {} bpp {}", @@ -1172,7 +1172,7 @@ impl GpuIoHandler { } let pixman_format = get_image_format(res.pixman_image); - let bpp = (pixman_format_bpp(pixman_format as u32) as u32 + 8 - 1) / 8; + let bpp = (u32::from(pixman_format_bpp(pixman_format as u32)) + 8 - 1) / 8; let pixman_stride = get_image_stride(res.pixman_image); let offset = info_set_scanout.rect.x_coord * bpp + info_set_scanout.rect.y_coord * pixman_stride as u32; @@ -1301,10 +1301,10 @@ impl GpuIoHandler { let extents = pixman_region_extents(final_reg_ptr); display_graphic_update( &scanout.con, - (*extents).x1 as i32, - (*extents).y1 as i32, - ((*extents).x2 - (*extents).x1) as i32, - ((*extents).y2 - (*extents).y1) as i32, + i32::from((*extents).x1), + i32::from((*extents).y1), + i32::from((*extents).x2 - (*extents).x1), + i32::from((*extents).y2 - (*extents).y1), )?; pixman_region_fini(rect_reg_ptr); pixman_region_fini(final_reg_ptr); @@ -1359,7 +1359,7 @@ impl GpuIoHandler { let res = &mut self.resources_list[res_idx]; let pixman_format = get_image_format(res.pixman_image); let width = get_image_width(res.pixman_image) as u32; - let bpp = (pixman_format_bpp(pixman_format as u32) as u32 + 8 - 1) / 8; + let bpp = (u32::from(pixman_format_bpp(pixman_format as u32)) + 8 - 1) / 8; let stride = get_image_stride(res.pixman_image) as u32; let data = get_image_data(res.pixman_image).cast() as *mut u8; @@ -1452,9 +1452,9 @@ impl GpuIoHandler { } let entries = info_attach_backing.nr_entries; - let ents_size = size_of::() as u64 * entries as u64; + let ents_size = size_of::() as u64 * u64::from(entries); let head_size = size_of::() as u64; - if (req.out_len as u64) < (ents_size + head_size) { + if u64::from(req.out_len) < (ents_size + head_size) { error!( "GuestError: The nr_entries {} in resource attach backing request is larger than total len {}.", info_attach_backing.nr_entries, req.out_len, diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index 689e9c59..a7794fe8 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -244,7 +244,7 @@ impl CtrlInfo { continue; } - let size = entries as u64 * MAC_ADDR_LEN as u64; + let size = u64::from(entries) * MAC_ADDR_LEN as u64; let res_len = Element::iovec_size(data_iovec); if size > res_len { bail!("Invalid request for setting mac table."); @@ -366,7 +366,7 @@ impl CtrlInfo { data_iovec: &mut Vec, ) -> u8 { let mut ack = VIRTIO_NET_OK; - if cmd as u16 == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET { + if u16::from(cmd) == VIRTIO_NET_CTRL_MQ_VQ_PAIRS_SET { let mut queue_pairs: u16 = 0; *data_iovec = get_buf_and_discard(mem_space, data_iovec, queue_pairs.as_mut_bytes()) .unwrap_or_else(|e| { @@ -1609,7 +1609,7 @@ impl VirtioDevice for Net { // The features about offload is included in bits 0 to 31. let features = self.driver_features(0_u32); - let flags = get_tap_offload_flags(features as u64); + let flags = get_tap_offload_flags(u64::from(features)); let mut senders = Vec::new(); let queue_pairs = queue_num / 2; @@ -1699,7 +1699,7 @@ impl VirtioDevice for Net { // Set tap offload. // The features about offload is included in bits 0 to 31. let features = self.driver_features(0_u32); - let flags = get_tap_offload_flags(features as u64); + let flags = get_tap_offload_flags(u64::from(features)); if let Some(taps) = &self.taps { for (_, tap) in taps.iter().enumerate() { tap.set_offload(flags) diff --git a/virtio/src/device/rng.rs b/virtio/src/device/rng.rs index 557e759c..f0fcc4e1 100644 --- a/virtio/src/device/rng.rs +++ b/virtio/src/device/rng.rs @@ -139,7 +139,7 @@ impl RngHandler { .write( &mut buffer[offset..].as_ref(), iov.addr, - min(size - offset as u32, iov.len) as u64, + u64::from(min(size - offset as u32, iov.len)), ) .with_context(|| "Failed to write request data for virtio rng")?; @@ -166,7 +166,7 @@ impl RngHandler { get_req_data_size(&elem.in_iovec).with_context(|| "Failed to get request size")?; if let Some(leak_bucket) = self.leak_bucket.as_mut() { - if leak_bucket.throttled(EventLoop::get_ctx(None).unwrap(), size as u64) { + if leak_bucket.throttled(EventLoop::get_ctx(None).unwrap(), u64::from(size)) { queue_lock.vring.push_back(); break; } @@ -326,7 +326,7 @@ impl VirtioDevice for Rng { } fn init_config_features(&mut self) -> Result<()> { - self.base.device_features = 1 << VIRTIO_F_VERSION_1 as u64; + self.base.device_features = 1 << u64::from(VIRTIO_F_VERSION_1); Ok(()) } @@ -494,30 +494,30 @@ mod tests { let page = 0_u32; rng.set_driver_features(page, driver_feature); assert_eq!(rng.base.driver_features, 0_u64); - assert_eq!(rng.driver_features(page) as u64, 0_u64); + assert_eq!(u64::from(rng.driver_features(page)), 0_u64); assert_eq!(rng.device_features(0_u32), 0_u32); let driver_feature: u32 = 0xFF; let page = 1_u32; rng.set_driver_features(page, driver_feature); assert_eq!(rng.base.driver_features, 0_u64); - assert_eq!(rng.driver_features(page) as u64, 0_u64); + assert_eq!(u64::from(rng.driver_features(page)), 0_u64); assert_eq!(rng.device_features(1_u32), 0_u32); // If both the device feature bit and the front-end driver feature bit are // supported at the same time, this driver feature bit is supported. rng.base.device_features = - 1_u64 << VIRTIO_F_VERSION_1 | 1_u64 << VIRTIO_F_RING_INDIRECT_DESC as u64; + 1_u64 << VIRTIO_F_VERSION_1 | 1_u64 << u64::from(VIRTIO_F_RING_INDIRECT_DESC); let driver_feature: u32 = 1_u32 << VIRTIO_F_RING_INDIRECT_DESC; let page = 0_u32; rng.set_driver_features(page, driver_feature); assert_eq!( rng.base.driver_features, - (1_u64 << VIRTIO_F_RING_INDIRECT_DESC as u64) + (1_u64 << u64::from(VIRTIO_F_RING_INDIRECT_DESC)) ); assert_eq!( - rng.driver_features(page) as u64, - (1_u64 << VIRTIO_F_RING_INDIRECT_DESC as u64) + u64::from(rng.driver_features(page)), + (1_u64 << u64::from(VIRTIO_F_RING_INDIRECT_DESC)) ); assert_eq!( rng.device_features(page), @@ -543,7 +543,7 @@ mod tests { len: u32::max_value(), }, ElemIovec { - addr: GuestAddress(u32::max_value() as u64), + addr: GuestAddress(u64::from(u32::max_value())), len: 1_u32, }, ]; @@ -557,7 +557,7 @@ mod tests { len, }, ElemIovec { - addr: GuestAddress(u32::max_value() as u64), + addr: GuestAddress(u64::from(u32::max_value())), len, }, ]; @@ -591,10 +591,10 @@ mod tests { queue_config.desc_table = GuestAddress(0); queue_config.addr_cache.desc_table_host = mem_space.get_host_address(queue_config.desc_table).unwrap(); - queue_config.avail_ring = GuestAddress(16 * DEFAULT_VIRTQUEUE_SIZE as u64); + queue_config.avail_ring = GuestAddress(16 * u64::from(DEFAULT_VIRTQUEUE_SIZE)); queue_config.addr_cache.avail_ring_host = mem_space.get_host_address(queue_config.avail_ring).unwrap(); - queue_config.used_ring = GuestAddress(32 * DEFAULT_VIRTQUEUE_SIZE as u64); + queue_config.used_ring = GuestAddress(32 * u64::from(DEFAULT_VIRTQUEUE_SIZE)); queue_config.addr_cache.used_ring_host = mem_space.get_host_address(queue_config.used_ring).unwrap(); queue_config.size = DEFAULT_VIRTQUEUE_SIZE; @@ -639,7 +639,7 @@ mod tests { .read( &mut read_buffer.as_mut_slice(), GuestAddress(0x40000), - data_len as u64 + u64::from(data_len) ) .is_ok()); assert_eq!(read_buffer, buffer); @@ -674,10 +674,10 @@ mod tests { queue_config.desc_table = GuestAddress(0); queue_config.addr_cache.desc_table_host = mem_space.get_host_address(queue_config.desc_table).unwrap(); - queue_config.avail_ring = GuestAddress(16 * DEFAULT_VIRTQUEUE_SIZE as u64); + queue_config.avail_ring = GuestAddress(16 * u64::from(DEFAULT_VIRTQUEUE_SIZE)); queue_config.addr_cache.avail_ring_host = mem_space.get_host_address(queue_config.avail_ring).unwrap(); - queue_config.used_ring = GuestAddress(32 * DEFAULT_VIRTQUEUE_SIZE as u64); + queue_config.used_ring = GuestAddress(32 * u64::from(DEFAULT_VIRTQUEUE_SIZE)); queue_config.addr_cache.used_ring_host = mem_space.get_host_address(queue_config.used_ring).unwrap(); queue_config.size = DEFAULT_VIRTQUEUE_SIZE; @@ -742,7 +742,7 @@ mod tests { .read( &mut read_buffer.as_mut_slice(), GuestAddress(0x40000), - data_len as u64 + u64::from(data_len) ) .is_ok()); assert_eq!(read_buffer, buffer1_check); @@ -750,7 +750,7 @@ mod tests { .read( &mut read_buffer.as_mut_slice(), GuestAddress(0x50000), - data_len as u64 + u64::from(data_len) ) .is_ok()); assert_eq!(read_buffer, buffer2_check); diff --git a/virtio/src/device/scsi_cntlr.rs b/virtio/src/device/scsi_cntlr.rs index 3970bf64..6863b60c 100644 --- a/virtio/src/device/scsi_cntlr.rs +++ b/virtio/src/device/scsi_cntlr.rs @@ -194,7 +194,7 @@ impl VirtioDevice for ScsiCntlr { // cmd_per_lun: maximum number of linked commands can be sent to one LUN. 32bit. self.config_space.cmd_per_lun = 128; // seg_max: queue size - 2, 32 bit. - self.config_space.seg_max = self.queue_size_max() as u32 - 2; + self.config_space.seg_max = u32::from(self.queue_size_max()) - 2; self.config_space.max_target = VIRTIO_SCSI_MAX_TARGET; self.config_space.max_lun = VIRTIO_SCSI_MAX_LUN; // num_queues: request queues number. @@ -753,7 +753,7 @@ impl ScsiRequestOps for CmdQueueRequest { // | Byte 0 | Byte 1 | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6 | Byte 7 | // | 1 | target | lun | 0 | fn virtio_scsi_get_lun_id(lun: [u8; 8]) -> u16 { - (((lun[2] as u16) << 8) | (lun[3] as u16)) & 0x3FFF + ((u16::from(lun[2]) << 8) | u16::from(lun[3])) & 0x3FFF } struct ScsiCmdQueueHandler { diff --git a/virtio/src/device/serial.rs b/virtio/src/device/serial.rs index f8a1e35f..5bf3aae8 100644 --- a/virtio/src/device/serial.rs +++ b/virtio/src/device/serial.rs @@ -1018,13 +1018,13 @@ mod tests { let page = 0_u32; serial.set_driver_features(page, driver_feature); assert_eq!(serial.base.driver_features, 0_u64); - assert_eq!(serial.driver_features(page) as u64, 0_u64); + assert_eq!(u64::from(serial.driver_features(page)), 0_u64); let driver_feature: u32 = 0xFF; let page = 1_u32; serial.set_driver_features(page, driver_feature); assert_eq!(serial.base.driver_features, 0_u64); - assert_eq!(serial.driver_features(page) as u64, 0_u64); + assert_eq!(u64::from(serial.driver_features(page)), 0_u64); // If both the device feature bit and the front-end driver feature bit are // supported at the same time, this driver feature bit is supported. @@ -1037,7 +1037,7 @@ mod tests { (1_u64 << VIRTIO_CONSOLE_F_SIZE) ); assert_eq!( - serial.driver_features(page) as u64, + u64::from(serial.driver_features(page)), (1_u64 << VIRTIO_CONSOLE_F_SIZE) ); serial.base.driver_features = 0; @@ -1075,7 +1075,7 @@ mod tests { classtype: "virtio-serial-pci".to_string(), id: "serial".to_string(), multifunction: Some(false), - max_ports: max_ports as u32, + max_ports: u32::from(max_ports), bus: Some("pcie.0".to_string()), addr: Some((0, 0)), }); diff --git a/virtio/src/lib.rs b/virtio/src/lib.rs index 4c3e8e87..f4cc3c15 100644 --- a/virtio/src/lib.rs +++ b/virtio/src/lib.rs @@ -547,9 +547,9 @@ pub trait VirtioDevice: Send + AsAny { } let features = if page == 0 { - (self.driver_features(1) as u64) << 32 | (v as u64) + u64::from(self.driver_features(1)) << 32 | u64::from(v) } else { - (v as u64) << 32 | (self.driver_features(0) as u64) + u64::from(v) << 32 | u64::from(self.driver_features(0)) }; self.virtio_base_mut().driver_features = features; } @@ -819,7 +819,7 @@ pub fn iov_to_buf( for iov in iovec { let mut addr_map = Vec::new(); - mem_space.get_address_map(cache, iov.addr, iov.len as u64, &mut addr_map)?; + mem_space.get_address_map(cache, iov.addr, u64::from(iov.len), &mut addr_map)?; for addr in addr_map.into_iter() { end = cmp::min(start + addr.iov_len as usize, buf.len()); mem_to_buf(&mut buf[start..end], addr.iov_base)?; @@ -835,12 +835,12 @@ pub fn iov_to_buf( /// Discard "size" bytes of the front of iovec. pub fn iov_discard_front(iovec: &mut [ElemIovec], mut size: u64) -> Option<&mut [ElemIovec]> { for (index, iov) in iovec.iter_mut().enumerate() { - if iov.len as u64 > size { + if u64::from(iov.len) > size { iov.addr.0 += size; iov.len -= size as u32; return Some(&mut iovec[index..]); } - size -= iov.len as u64; + size -= u64::from(iov.len); } None } @@ -849,11 +849,11 @@ pub fn iov_discard_front(iovec: &mut [ElemIovec], mut size: u64) -> Option<&mut pub fn iov_discard_back(iovec: &mut [ElemIovec], mut size: u64) -> Option<&mut [ElemIovec]> { let len = iovec.len(); for (index, iov) in iovec.iter_mut().rev().enumerate() { - if iov.len as u64 > size { + if u64::from(iov.len) > size { iov.len -= size as u32; return Some(&mut iovec[..(len - index)]); } - size -= iov.len as u64; + size -= u64::from(iov.len); } None } @@ -869,8 +869,8 @@ fn gpa_hva_iovec_map( let mut hva_iovec = Vec::with_capacity(gpa_elemiovec.len()); for elem in gpa_elemiovec.iter() { - mem_space.get_address_map(cache, elem.addr, elem.len as u64, &mut hva_iovec)?; - iov_size += elem.len as u64; + mem_space.get_address_map(cache, elem.addr, u64::from(elem.len), &mut hva_iovec)?; + iov_size += u64::from(elem.len); } Ok((iov_size, hva_iovec)) diff --git a/virtio/src/queue/mod.rs b/virtio/src/queue/mod.rs index 1e612b29..93d95044 100644 --- a/virtio/src/queue/mod.rs +++ b/virtio/src/queue/mod.rs @@ -91,7 +91,7 @@ impl Element { pub fn iovec_size(iovec: &[ElemIovec]) -> u64 { let mut size: u64 = 0; for elem in iovec.iter() { - size += elem.len as u64; + size += u64::from(elem.len); } size } diff --git a/virtio/src/queue/split.rs b/virtio/src/queue/split.rs index 643693b5..74d81d6b 100644 --- a/virtio/src/queue/split.rs +++ b/virtio/src/queue/split.rs @@ -116,7 +116,7 @@ impl QueueConfig { } fn get_desc_size(&self) -> u64 { - min(self.size, self.max_size) as u64 * DESCRIPTOR_LEN + u64::from(min(self.size, self.max_size)) * DESCRIPTOR_LEN } fn get_used_size(&self, features: u64) -> u64 { @@ -126,7 +126,7 @@ impl QueueConfig { 0_u64 }; - size + VRING_FLAGS_AND_IDX_LEN + (min(self.size, self.max_size) as u64) * USEDELEM_LEN + size + VRING_FLAGS_AND_IDX_LEN + u64::from(min(self.size, self.max_size)) * USEDELEM_LEN } fn get_avail_size(&self, features: u64) -> u64 { @@ -137,7 +137,7 @@ impl QueueConfig { }; size + VRING_FLAGS_AND_IDX_LEN - + (min(self.size, self.max_size) as u64) * (size_of::() as u64) + + u64::from(min(self.size, self.max_size)) * (size_of::() as u64) } pub fn reset(&mut self) { @@ -290,7 +290,7 @@ impl SplitVringDesc { let mut miss_cached = true; if let Some(reg_cache) = cache { let base = self.addr.0; - let offset = self.len as u64; + let offset = u64::from(self.len); let end = match base.checked_add(offset) { Some(addr) => addr, None => { @@ -361,7 +361,7 @@ impl SplitVringDesc { fn is_valid_indirect_desc(&self) -> bool { if self.len == 0 || u64::from(self.len) % DESCRIPTOR_LEN != 0 - || u64::from(self.len) / DESCRIPTOR_LEN > u16::MAX as u64 + || u64::from(self.len) / DESCRIPTOR_LEN > u64::from(u16::MAX) { error!("The indirect descriptor is invalid, len: {}", self.len); return false; @@ -435,7 +435,7 @@ impl SplitVringDesc { elem.out_iovec.push(iovec); } elem.desc_num += 1; - desc_total_len += iovec.len as u64; + desc_total_len += u64::from(iovec.len); if desc.has_next() { desc = Self::next_desc(sys_mem, desc_table_host, queue_size, desc.next, cache)?; @@ -1030,7 +1030,7 @@ mod tests { return Err(anyhow!(VirtioError::QueueIndex(index, self.size))); } - let desc_addr_offset = DESCRIPTOR_LEN * index as u64; + let desc_addr_offset = DESCRIPTOR_LEN * u64::from(index); let desc = SplitVringDesc { addr, len, @@ -1065,7 +1065,7 @@ mod tests { avail_pos: u16, desc_index: u16, ) -> Result<()> { - let avail_idx_offset = VRING_FLAGS_AND_IDX_LEN + AVAILELEM_LEN * (avail_pos as u64); + let avail_idx_offset = VRING_FLAGS_AND_IDX_LEN + AVAILELEM_LEN * u64::from(avail_pos); sys_mem.write_object::( &desc_index, GuestAddress(self.avail_ring.0 + avail_idx_offset), @@ -1075,14 +1075,14 @@ mod tests { fn get_avail_event(&self, sys_mem: &Arc) -> Result { let avail_event_idx_offset = - VRING_FLAGS_AND_IDX_LEN + USEDELEM_LEN * (self.actual_size() as u64); + VRING_FLAGS_AND_IDX_LEN + USEDELEM_LEN * u64::from(self.actual_size()); let event_idx = sys_mem .read_object::(GuestAddress(self.used_ring.0 + avail_event_idx_offset))?; Ok(event_idx) } fn get_used_elem(&self, sys_mem: &Arc, index: u16) -> Result { - let used_elem_offset = VRING_FLAGS_AND_IDX_LEN + USEDELEM_LEN * (index as u64); + let used_elem_offset = VRING_FLAGS_AND_IDX_LEN + USEDELEM_LEN * u64::from(index); let used_elem = sys_mem .read_object::(GuestAddress(self.used_ring.0 + used_elem_offset))?; Ok(used_elem) @@ -1103,7 +1103,7 @@ mod tests { fn set_used_event_idx(&self, sys_mem: &Arc, idx: u16) -> Result<()> { let event_idx_offset = - VRING_FLAGS_AND_IDX_LEN + AVAILELEM_LEN * (self.actual_size() as u64); + VRING_FLAGS_AND_IDX_LEN + AVAILELEM_LEN * u64::from(self.actual_size()); sys_mem .write_object::(&idx, GuestAddress(self.avail_ring.0 + event_idx_offset))?; Ok(()) @@ -1154,11 +1154,11 @@ mod tests { // it is valid queue_config.desc_table = GuestAddress(0); - queue_config.avail_ring = GuestAddress((QUEUE_SIZE as u64) * DESCRIPTOR_LEN); + queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); queue_config.used_ring = GuestAddress(align( - (QUEUE_SIZE as u64) * DESCRIPTOR_LEN + u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + VRING_AVAIL_LEN_EXCEPT_AVAILELEM - + AVAILELEM_LEN * (QUEUE_SIZE as u64), + + AVAILELEM_LEN * u64::from(QUEUE_SIZE), 4096, )); queue_config.ready = true; @@ -1194,11 +1194,11 @@ mod tests { let mut queue_config = QueueConfig::new(QUEUE_SIZE); queue_config.desc_table = GuestAddress(0); - queue_config.avail_ring = GuestAddress((QUEUE_SIZE as u64) * DESCRIPTOR_LEN); + queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); queue_config.used_ring = GuestAddress(align( - (QUEUE_SIZE as u64) * DESCRIPTOR_LEN + u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + VRING_AVAIL_LEN_EXCEPT_AVAILELEM - + AVAILELEM_LEN * (QUEUE_SIZE as u64), + + AVAILELEM_LEN * u64::from(QUEUE_SIZE), 4096, )); queue_config.ready = true; @@ -1208,7 +1208,7 @@ mod tests { // it is invalid when the address of descriptor table is out of bound queue_config.desc_table = - GuestAddress(SYSTEM_SPACE_SIZE - (QUEUE_SIZE as u64) * DESCRIPTOR_LEN + 1 as u64); + GuestAddress(SYSTEM_SPACE_SIZE - u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + 1 as u64); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); assert_eq!(queue.is_valid(&sys_space), false); // recover the address for valid queue @@ -1219,29 +1219,29 @@ mod tests { // it is invalid when the address of avail ring is out of bound queue_config.avail_ring = GuestAddress( SYSTEM_SPACE_SIZE - - (VRING_AVAIL_LEN_EXCEPT_AVAILELEM + AVAILELEM_LEN * (QUEUE_SIZE as u64)) + - (VRING_AVAIL_LEN_EXCEPT_AVAILELEM + AVAILELEM_LEN * u64::from(QUEUE_SIZE)) + 1 as u64, ); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); assert_eq!(queue.is_valid(&sys_space), false); // recover the address for valid queue - queue_config.avail_ring = GuestAddress((QUEUE_SIZE as u64) * DESCRIPTOR_LEN); + queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); assert_eq!(queue.is_valid(&sys_space), true); // it is invalid when the address of used ring is out of bound queue_config.used_ring = GuestAddress( SYSTEM_SPACE_SIZE - - (VRING_USED_LEN_EXCEPT_USEDELEM + USEDELEM_LEN * (QUEUE_SIZE as u64)) + - (VRING_USED_LEN_EXCEPT_USEDELEM + USEDELEM_LEN * u64::from(QUEUE_SIZE)) + 1 as u64, ); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); assert_eq!(queue.is_valid(&sys_space), false); // recover the address for valid queue queue_config.used_ring = GuestAddress(align( - (QUEUE_SIZE as u64) * DESCRIPTOR_LEN + u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + VRING_AVAIL_LEN_EXCEPT_AVAILELEM - + AVAILELEM_LEN * (QUEUE_SIZE as u64), + + AVAILELEM_LEN * u64::from(QUEUE_SIZE), 4096, )); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); @@ -1254,11 +1254,11 @@ mod tests { let mut queue_config = QueueConfig::new(QUEUE_SIZE); queue_config.desc_table = GuestAddress(0); - queue_config.avail_ring = GuestAddress((QUEUE_SIZE as u64) * DESCRIPTOR_LEN); + queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); queue_config.used_ring = GuestAddress(align( - (QUEUE_SIZE as u64) * DESCRIPTOR_LEN + u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + VRING_AVAIL_LEN_EXCEPT_AVAILELEM - + AVAILELEM_LEN * (QUEUE_SIZE as u64), + + AVAILELEM_LEN * u64::from(QUEUE_SIZE), 4096, )); queue_config.ready = true; @@ -1271,29 +1271,29 @@ mod tests { let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); assert_eq!(queue.is_valid(&sys_space), false); // recover the address for valid queue - queue_config.avail_ring = GuestAddress((QUEUE_SIZE as u64) * DESCRIPTOR_LEN); + queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); assert_eq!(queue.is_valid(&sys_space), true); // it is invalid when the address of descriptor table is overlapped to the address of avail // ring. - queue_config.avail_ring = GuestAddress((QUEUE_SIZE as u64) * DESCRIPTOR_LEN - 1); + queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN - 1); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); assert_eq!(queue.is_valid(&sys_space), false); // recover the address for valid queue - queue_config.avail_ring = GuestAddress((QUEUE_SIZE as u64) * DESCRIPTOR_LEN); + queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); assert_eq!(queue.is_valid(&sys_space), true); // it is invalid when the address of avail ring is equal to the address of used ring - queue_config.used_ring = GuestAddress((QUEUE_SIZE as u64) * DESCRIPTOR_LEN); + queue_config.used_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); assert_eq!(queue.is_valid(&sys_space), false); // recover the address for valid queue queue_config.used_ring = GuestAddress(align( - (QUEUE_SIZE as u64) * DESCRIPTOR_LEN + u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + VRING_AVAIL_LEN_EXCEPT_AVAILELEM - + AVAILELEM_LEN * (QUEUE_SIZE as u64), + + AVAILELEM_LEN * u64::from(QUEUE_SIZE), 4096, )); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); @@ -1301,18 +1301,18 @@ mod tests { // it is invalid when the address of avail ring is overlapped to the address of used ring queue_config.used_ring = GuestAddress( - (QUEUE_SIZE as u64) * DESCRIPTOR_LEN + u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + VRING_AVAIL_LEN_EXCEPT_AVAILELEM - + AVAILELEM_LEN * (QUEUE_SIZE as u64) + + AVAILELEM_LEN * u64::from(QUEUE_SIZE) - 1, ); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); assert_eq!(queue.is_valid(&sys_space), false); // recover the address for valid queue queue_config.used_ring = GuestAddress(align( - (QUEUE_SIZE as u64) * DESCRIPTOR_LEN + u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + VRING_AVAIL_LEN_EXCEPT_AVAILELEM - + AVAILELEM_LEN * (QUEUE_SIZE as u64), + + AVAILELEM_LEN * u64::from(QUEUE_SIZE), 4096, )); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); @@ -1325,11 +1325,11 @@ mod tests { let mut queue_config = QueueConfig::new(QUEUE_SIZE); queue_config.desc_table = GuestAddress(0); - queue_config.avail_ring = GuestAddress((QUEUE_SIZE as u64) * DESCRIPTOR_LEN); + queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); queue_config.used_ring = GuestAddress(align( - (QUEUE_SIZE as u64) * DESCRIPTOR_LEN + u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + VRING_AVAIL_LEN_EXCEPT_AVAILELEM - + AVAILELEM_LEN * (QUEUE_SIZE as u64), + + AVAILELEM_LEN * u64::from(QUEUE_SIZE), 4096, )); queue_config.ready = true; @@ -1347,28 +1347,28 @@ mod tests { assert_eq!(queue.is_valid(&sys_space), true); // it is invalid when the address of avail ring is not aligned to 2 - queue_config.avail_ring = GuestAddress((QUEUE_SIZE as u64) * DESCRIPTOR_LEN + 1); + queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + 1); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); assert_eq!(queue.is_valid(&sys_space), false); // recover the address for valid queue - queue_config.avail_ring = GuestAddress((QUEUE_SIZE as u64) * DESCRIPTOR_LEN); + queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); assert_eq!(queue.is_valid(&sys_space), true); // it is invalid when the address of used ring is not aligned to 4 queue_config.used_ring = GuestAddress( - (QUEUE_SIZE as u64) * DESCRIPTOR_LEN + u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + VRING_AVAIL_LEN_EXCEPT_AVAILELEM - + AVAILELEM_LEN * (QUEUE_SIZE as u64) + + AVAILELEM_LEN * u64::from(QUEUE_SIZE) + 3, ); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); assert_eq!(queue.is_valid(&sys_space), false); // recover the address for valid queue queue_config.used_ring = GuestAddress(align( - (QUEUE_SIZE as u64) * DESCRIPTOR_LEN + u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + VRING_AVAIL_LEN_EXCEPT_AVAILELEM - + AVAILELEM_LEN * (QUEUE_SIZE as u64), + + AVAILELEM_LEN * u64::from(QUEUE_SIZE), 4096, )); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); @@ -1383,13 +1383,13 @@ mod tests { queue_config.desc_table = GuestAddress(0); queue_config.addr_cache.desc_table_host = sys_space.get_host_address(queue_config.desc_table).unwrap(); - queue_config.avail_ring = GuestAddress((QUEUE_SIZE as u64) * DESCRIPTOR_LEN); + queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); queue_config.addr_cache.avail_ring_host = sys_space.get_host_address(queue_config.avail_ring).unwrap(); queue_config.used_ring = GuestAddress(align( - (QUEUE_SIZE as u64) * DESCRIPTOR_LEN + u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + VRING_AVAIL_LEN_EXCEPT_AVAILELEM - + AVAILELEM_LEN * (QUEUE_SIZE as u64), + + AVAILELEM_LEN * u64::from(QUEUE_SIZE), 4096, )); queue_config.addr_cache.used_ring_host = @@ -1434,7 +1434,7 @@ mod tests { // set 1 to the idx of avail ring vring.set_avail_ring_idx(&sys_space, 1).unwrap(); - let features = 1 << VIRTIO_F_RING_EVENT_IDX as u64; + let features = 1 << u64::from(VIRTIO_F_RING_EVENT_IDX); let elem = match vring.pop_avail(&sys_space, features) { Ok(ret) => ret, Err(_) => Element { @@ -1473,13 +1473,13 @@ mod tests { queue_config.desc_table = GuestAddress(0); queue_config.addr_cache.desc_table_host = sys_space.get_host_address(queue_config.desc_table).unwrap(); - queue_config.avail_ring = GuestAddress((QUEUE_SIZE as u64) * DESCRIPTOR_LEN); + queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); queue_config.addr_cache.avail_ring_host = sys_space.get_host_address(queue_config.avail_ring).unwrap(); queue_config.used_ring = GuestAddress(align( - (QUEUE_SIZE as u64) * DESCRIPTOR_LEN + u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + VRING_AVAIL_LEN_EXCEPT_AVAILELEM - + AVAILELEM_LEN * (QUEUE_SIZE as u64), + + AVAILELEM_LEN * u64::from(QUEUE_SIZE), 4096, )); queue_config.addr_cache.used_ring_host = @@ -1540,7 +1540,7 @@ mod tests { // set 1 to the idx of avail ring vring.set_avail_ring_idx(&sys_space, 1).unwrap(); - let features = 1 << VIRTIO_F_RING_EVENT_IDX as u64; + let features = 1 << u64::from(VIRTIO_F_RING_EVENT_IDX); let elem = match vring.pop_avail(&sys_space, features) { Ok(ret) => ret, Err(_) => Element { @@ -1573,13 +1573,13 @@ mod tests { queue_config.desc_table = GuestAddress(0); queue_config.addr_cache.desc_table_host = sys_space.get_host_address(queue_config.desc_table).unwrap(); - queue_config.avail_ring = GuestAddress((QUEUE_SIZE as u64) * DESCRIPTOR_LEN); + queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); queue_config.addr_cache.avail_ring_host = sys_space.get_host_address(queue_config.avail_ring).unwrap(); queue_config.used_ring = GuestAddress(align( - (QUEUE_SIZE as u64) * DESCRIPTOR_LEN + u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + VRING_AVAIL_LEN_EXCEPT_AVAILELEM - + AVAILELEM_LEN * (QUEUE_SIZE as u64), + + AVAILELEM_LEN * u64::from(QUEUE_SIZE), 4096, )); queue_config.addr_cache.used_ring_host = @@ -1592,7 +1592,7 @@ mod tests { // it is error when the idx of avail ring which is equal to next_avail // set 0 to the idx of avail ring which is equal to next_avail vring.set_avail_ring_idx(&sys_space, 0).unwrap(); - let features = 1 << VIRTIO_F_RING_EVENT_IDX as u64; + let features = 1 << u64::from(VIRTIO_F_RING_EVENT_IDX); if let Ok(elem) = vring.pop_avail(&sys_space, features) { if elem.desc_num != 0 { assert!(false); @@ -1768,13 +1768,13 @@ mod tests { queue_config.desc_table = GuestAddress(0); queue_config.addr_cache.desc_table_host = sys_space.get_host_address(queue_config.desc_table).unwrap(); - queue_config.avail_ring = GuestAddress((QUEUE_SIZE as u64) * DESCRIPTOR_LEN); + queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); queue_config.addr_cache.avail_ring_host = sys_space.get_host_address(queue_config.avail_ring).unwrap(); queue_config.used_ring = GuestAddress(align( - (QUEUE_SIZE as u64) * DESCRIPTOR_LEN + u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + VRING_AVAIL_LEN_EXCEPT_AVAILELEM - + AVAILELEM_LEN * (QUEUE_SIZE as u64), + + AVAILELEM_LEN * u64::from(QUEUE_SIZE), 4096, )); queue_config.addr_cache.used_ring_host = @@ -1835,7 +1835,7 @@ mod tests { // Set 1 to the idx of avail ring. vring.set_avail_ring_idx(&sys_space, 1).unwrap(); - let features = 1 << VIRTIO_F_RING_EVENT_IDX as u64; + let features = 1 << u64::from(VIRTIO_F_RING_EVENT_IDX); if let Err(err) = vring.pop_avail(&sys_space, features) { assert_eq!(err.to_string(), "Failed to get vring element"); } else { @@ -1932,13 +1932,13 @@ mod tests { queue_config.desc_table = GuestAddress(0); queue_config.addr_cache.desc_table_host = sys_space.get_host_address(queue_config.desc_table).unwrap(); - queue_config.avail_ring = GuestAddress((QUEUE_SIZE as u64) * DESCRIPTOR_LEN); + queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); queue_config.addr_cache.avail_ring_host = sys_space.get_host_address(queue_config.avail_ring).unwrap(); queue_config.used_ring = GuestAddress(align( - (QUEUE_SIZE as u64) * DESCRIPTOR_LEN + u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + VRING_AVAIL_LEN_EXCEPT_AVAILELEM - + AVAILELEM_LEN * (QUEUE_SIZE as u64), + + AVAILELEM_LEN * u64::from(QUEUE_SIZE), 4096, )); queue_config.addr_cache.used_ring_host = @@ -1976,13 +1976,13 @@ mod tests { queue_config.desc_table = GuestAddress(0); queue_config.addr_cache.desc_table_host = sys_space.get_host_address(queue_config.desc_table).unwrap(); - queue_config.avail_ring = GuestAddress((QUEUE_SIZE as u64) * DESCRIPTOR_LEN); + queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); queue_config.addr_cache.avail_ring_host = sys_space.get_host_address(queue_config.avail_ring).unwrap(); queue_config.used_ring = GuestAddress(align( - (QUEUE_SIZE as u64) * DESCRIPTOR_LEN + u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + VRING_AVAIL_LEN_EXCEPT_AVAILELEM - + AVAILELEM_LEN * (QUEUE_SIZE as u64), + + AVAILELEM_LEN * u64::from(QUEUE_SIZE), 4096, )); queue_config.addr_cache.used_ring_host = @@ -2007,7 +2007,7 @@ mod tests { // it's true when the feature of event idx is open and // (new - event_idx - Wrapping(1) < new -old) - let features = 1 << VIRTIO_F_RING_EVENT_IDX as u64; + let features = 1 << u64::from(VIRTIO_F_RING_EVENT_IDX); vring.last_signal_used = Wrapping(5); // old assert!(vring.set_used_ring_idx(&sys_space, 10).is_ok()); // new assert!(vring.set_used_event_idx(&sys_space, 6).is_ok()); // event_idx diff --git a/virtio/src/transport/virtio_mmio.rs b/virtio/src/transport/virtio_mmio.rs index 42892b0d..f8895221 100644 --- a/virtio/src/transport/virtio_mmio.rs +++ b/virtio/src/transport/virtio_mmio.rs @@ -271,10 +271,10 @@ impl VirtioMmioDevice { .map(|config| u32::from(config.max_size))?, QUEUE_READY_REG => locked_device .queue_config() - .map(|config| config.ready as u32)?, + .map(|config| u32::from(config.ready))?, INTERRUPT_STATUS_REG => locked_device.interrupt_status(), STATUS_REG => locked_device.device_status(), - CONFIG_GENERATION_REG => locked_device.config_generation() as u32, + CONFIG_GENERATION_REG => u32::from(locked_device.config_generation()), // SHM_SEL is unimplemented. According to the Virtio v1.2 spec: Reading from a non-existent // region(i.e. where the ID written to SHMSel is unused) results in a length of -1. SHM_LEN_LOW | SHM_LEN_HIGH => u32::MAX, @@ -745,7 +745,7 @@ mod tests { virtio_mmio_device.read(&mut buf[..], addr, QUEUE_NUM_MAX_REG), true ); - assert_eq!(LittleEndian::read_u32(&buf[..]), QUEUE_SIZE as u32); + assert_eq!(LittleEndian::read_u32(&buf[..]), u32::from(QUEUE_SIZE)); // for queue_select as 1 let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; virtio_device.lock().unwrap().set_queue_select(1); @@ -753,7 +753,7 @@ mod tests { virtio_mmio_device.read(&mut buf[..], addr, QUEUE_NUM_MAX_REG), true ); - assert_eq!(LittleEndian::read_u32(&buf[..]), QUEUE_SIZE as u32); + assert_eq!(LittleEndian::read_u32(&buf[..]), u32::from(QUEUE_SIZE)); // read the register representing the status of queue // for queue_select as 0 @@ -1179,9 +1179,9 @@ mod tests { locked_device.set_device_status(CONFIG_STATUS_FEATURES_OK); if let Ok(config) = locked_device.queue_config_mut(true) { config.desc_table = GuestAddress(0); - config.avail_ring = GuestAddress((QUEUE_SIZE as u64) * 16); + config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * 16); config.used_ring = GuestAddress(align( - (QUEUE_SIZE as u64) * 16 + 8 + 2 * (QUEUE_SIZE as u64), + u64::from(QUEUE_SIZE) * 16 + 8 + 2 * u64::from(QUEUE_SIZE), 4096, )); config.size = QUEUE_SIZE; @@ -1190,9 +1190,9 @@ mod tests { locked_device.set_queue_select(1); if let Ok(config) = locked_device.queue_config_mut(true) { config.desc_table = GuestAddress(0); - config.avail_ring = GuestAddress((QUEUE_SIZE as u64) * 16); + config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * 16); config.used_ring = GuestAddress(align( - (QUEUE_SIZE as u64) * 16 + 8 + 2 * (QUEUE_SIZE as u64), + u64::from(QUEUE_SIZE) * 16 + 8 + 2 * u64::from(QUEUE_SIZE), 4096, )); config.size = QUEUE_SIZE / 2; diff --git a/virtio/src/transport/virtio_pci.rs b/virtio/src/transport/virtio_pci.rs index 149cb329..22f69ca2 100644 --- a/virtio/src/transport/virtio_pci.rs +++ b/virtio/src/transport/virtio_pci.rs @@ -574,11 +574,11 @@ impl VirtioPciDevice { 0 } } - COMMON_MSIX_REG => locked_device.config_vector() as u32, + COMMON_MSIX_REG => u32::from(locked_device.config_vector()), COMMON_NUMQ_REG => locked_device.virtio_base().queues_config.len() as u32, COMMON_STATUS_REG => locked_device.device_status(), - COMMON_CFGGENERATION_REG => locked_device.config_generation() as u32, - COMMON_Q_SELECT_REG => locked_device.queue_select() as u32, + COMMON_CFGGENERATION_REG => u32::from(locked_device.config_generation()), + COMMON_Q_SELECT_REG => u32::from(locked_device.queue_select()), COMMON_Q_SIZE_REG => locked_device .queue_config() .map(|config| u32::from(config.size))?, @@ -588,7 +588,7 @@ impl VirtioPciDevice { COMMON_Q_ENABLE_REG => locked_device .queue_config() .map(|config| u32::from(config.ready))?, - COMMON_Q_NOFF_REG => locked_device.queue_select() as u32, + COMMON_Q_NOFF_REG => u32::from(locked_device.queue_select()), COMMON_Q_DESCLO_REG => locked_device .queue_config() .map(|config| config.desc_table.0 as u32)?, @@ -645,7 +645,7 @@ impl VirtioPciDevice { locked_device.set_driver_features(gfeatures_sel, value); if gfeatures_sel == 1 { - let features = (locked_device.driver_features(1) as u64) << 32; + let features = u64::from(locked_device.driver_features(1)) << 32; if virtio_has_feature(features, VIRTIO_F_RING_PACKED) { locked_device.set_queue_type(QUEUE_TYPE_PACKED_VRING); } else { @@ -663,7 +663,7 @@ impl VirtioPciDevice { } COMMON_STATUS_REG => { if value & CONFIG_STATUS_FEATURES_OK != 0 && value & CONFIG_STATUS_DRIVER_OK == 0 { - let features = (locked_device.driver_features(1) as u64) << 32; + let features = u64::from(locked_device.driver_features(1)) << 32; if !virtio_has_feature(features, VIRTIO_F_VERSION_1) { error!( "Device {} is modern only, but the driver not support VIRTIO_F_VERSION_1", self.base.base.id @@ -924,8 +924,8 @@ impl VirtioPciDevice { warn!("The offset {} of VirtioPciCfgAccessCap is not aligned", off); return; } - if (off as u64) - .checked_add(len as u64) + if u64::from(off) + .checked_add(u64::from(len)) .filter(|&end| end <= self.base.config.bars[bar as usize].size) .is_none() { @@ -935,12 +935,18 @@ impl VirtioPciDevice { let result = if is_write { let mut data = self.base.config.config[pci_cfg_data_offset..].as_ref(); - self.sys_mem - .write(&mut data, GuestAddress(bar_base + off as u64), len as u64) + self.sys_mem.write( + &mut data, + GuestAddress(bar_base + u64::from(off)), + u64::from(len), + ) } else { let mut data = self.base.config.config[pci_cfg_data_offset..].as_mut(); - self.sys_mem - .read(&mut data, GuestAddress(bar_base + off as u64), len as u64) + self.sys_mem.read( + &mut data, + GuestAddress(bar_base + u64::from(off)), + u64::from(len), + ) }; if let Err(e) = result { error!( @@ -955,7 +961,7 @@ impl VirtioPciDevice { // its own request completion. i.e, If the vq is not enough, vcpu A will // receive completion of request that submitted by vcpu B, then A needs // to IPI B. - min(queues_max as u16 - queues_fixed, nr_cpus as u16) + min(queues_max as u16 - queues_fixed, u16::from(nr_cpus)) } fn queues_register_irqfd(&self, call_fds: &[Arc]) -> bool { @@ -1148,11 +1154,11 @@ impl Device for VirtioPciDevice { .with_context(|| "Failed to realize virtio device")?; let name = self.name(); - let devfn = self.base.devfn as u64; + let devfn = u64::from(self.base.devfn); let dev = Arc::new(Mutex::new(self)); - let mut mem_region_size = ((VIRTIO_PCI_CAP_NOTIFY_OFFSET + VIRTIO_PCI_CAP_NOTIFY_LENGTH) - as u64) - .next_power_of_two(); + let mut mem_region_size = + u64::from(VIRTIO_PCI_CAP_NOTIFY_OFFSET + VIRTIO_PCI_CAP_NOTIFY_LENGTH) + .next_power_of_two(); mem_region_size = max(mem_region_size, MINIMUM_BAR_SIZE_FOR_MMIO as u64); let modern_mem_region = Region::init_container_region(mem_region_size, "VirtioPciModernMem"); @@ -1655,7 +1661,7 @@ mod tests { .iter_mut() { queue_cfg.desc_table = GuestAddress(0); - queue_cfg.avail_ring = GuestAddress((VIRTIO_DEVICE_QUEUE_SIZE as u64) * 16); + queue_cfg.avail_ring = GuestAddress(u64::from(VIRTIO_DEVICE_QUEUE_SIZE) * 16); queue_cfg.used_ring = GuestAddress(2 * 4096); queue_cfg.ready = true; queue_cfg.size = VIRTIO_DEVICE_QUEUE_SIZE; @@ -1704,6 +1710,6 @@ mod tests { .is_ok()); let header_type = le_read_u16(&virtio_pci.base.config.config, HEADER_TYPE as usize).unwrap(); - assert_eq!(header_type, HEADER_TYPE_MULTIFUNC as u16); + assert_eq!(header_type, u16::from(HEADER_TYPE_MULTIFUNC)); } } diff --git a/virtio/src/vhost/kernel/net.rs b/virtio/src/vhost/kernel/net.rs index d55376cf..52dbb85a 100644 --- a/virtio/src/vhost/kernel/net.rs +++ b/virtio/src/vhost/kernel/net.rs @@ -466,7 +466,7 @@ mod tests { let page: u32 = 0x0; let value: u32 = 0xff; vhost_net.set_driver_features(page, value); - assert_eq!(vhost_net.driver_features(page) as u64, 0_u64); + assert_eq!(u64::from(vhost_net.driver_features(page)), 0_u64); let new_page = vhost_net.device_features(page); assert_eq!(new_page, page); @@ -474,7 +474,7 @@ mod tests { let page: u32 = 0x0; let value: u32 = 0xff; vhost_net.set_driver_features(page, value); - assert_eq!(vhost_net.driver_features(page) as u64, 0xff_u64); + assert_eq!(u64::from(vhost_net.driver_features(page)), 0xff_u64); let new_page = vhost_net.device_features(page); assert_ne!(new_page, page); diff --git a/virtio/src/vhost/kernel/vsock.rs b/virtio/src/vhost/kernel/vsock.rs index e6580ffa..18d3f56b 100644 --- a/virtio/src/vhost/kernel/vsock.rs +++ b/virtio/src/vhost/kernel/vsock.rs @@ -464,11 +464,11 @@ mod tests { vsock.base.device_features = 0x0123_4567_89ab_cdef; // check for unsupported feature vsock.set_driver_features(0, 0x7000_0000); - assert_eq!(vsock.driver_features(0) as u64, 0_u64); + assert_eq!(u64::from(vsock.driver_features(0)), 0_u64); assert_eq!(vsock.base.device_features, 0x0123_4567_89ab_cdef); // check for supported feature vsock.set_driver_features(0, 0x8000_0000); - assert_eq!(vsock.driver_features(0) as u64, 0x8000_0000_u64); + assert_eq!(u64::from(vsock.driver_features(0)), 0x8000_0000_u64); assert_eq!(vsock.base.device_features, 0x0123_4567_89ab_cdef); // test vsock read_config @@ -510,7 +510,7 @@ mod tests { let backend = vsock.backend.unwrap(); assert_eq!(backend.set_guest_cid(3).is_ok(), true); assert_eq!( - backend.set_guest_cid(u32::max_value() as u64).is_ok(), + backend.set_guest_cid(u64::from(u32::max_value())).is_ok(), false ); assert_eq!(backend.set_guest_cid(2).is_ok(), false); diff --git a/virtio/src/vhost/user/block.rs b/virtio/src/vhost/user/block.rs index 8ccce18e..4e0757f9 100644 --- a/virtio/src/vhost/user/block.rs +++ b/virtio/src/vhost/user/block.rs @@ -146,7 +146,7 @@ impl VirtioDevice for Block { .set_protocol_features(self.protocol_features) .with_context(|| "Failed to set protocol features for vhost-user blk")?; - if virtio_has_feature(protocol_features, VHOST_USER_PROTOCOL_F_CONFIG as u32) { + if virtio_has_feature(protocol_features, u32::from(VHOST_USER_PROTOCOL_F_CONFIG)) { let config = locked_client .get_virtio_blk_config() .with_context(|| "Failed to get config for vhost-user blk")?; @@ -158,7 +158,7 @@ impl VirtioDevice for Block { ); } - if virtio_has_feature(protocol_features, VHOST_USER_PROTOCOL_F_MQ as u32) { + if virtio_has_feature(protocol_features, u32::from(VHOST_USER_PROTOCOL_F_MQ)) { let max_queue_num = locked_client .get_max_queue_num() .with_context(|| "Failed to get queue num for vhost-user blk")?; diff --git a/virtio/src/vhost/user/client.rs b/virtio/src/vhost/user/client.rs index b32bf72c..469871f1 100644 --- a/virtio/src/vhost/user/client.rs +++ b/virtio/src/vhost/user/client.rs @@ -482,7 +482,7 @@ impl VhostUserClient { .with_context(|| "Failed to get protocol features for vhost-user blk")?; if virtio_has_feature( protocol_feature, - VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD as u32, + u32::from(VHOST_USER_PROTOCOL_F_INFLIGHT_SHMFD), ) { if self.inflight.is_none() { // Expect 1 fd. @@ -903,7 +903,7 @@ impl VhostOps for VhostUserClient { size_of::() as u32, ); let payload_opt: Option<&[u8]> = None; - let vring_state = VhostUserVringState::new(queue_idx as u32, num as u32); + let vring_state = VhostUserVringState::new(queue_idx as u32, u32::from(num)); client .sock .send_msg(Some(&hdr), Some(&vring_state), payload_opt, &[]) @@ -982,7 +982,7 @@ impl VhostOps for VhostUserClient { size_of::() as u32, ); let payload_opt: Option<&[u8]> = None; - let vring_state = VhostUserVringState::new(queue_idx as u32, last_avail_idx as u32); + let vring_state = VhostUserVringState::new(queue_idx as u32, u32::from(last_avail_idx)); client .sock .send_msg(Some(&hdr), Some(&vring_state), payload_opt, &[]) @@ -1058,7 +1058,7 @@ impl VhostOps for VhostUserClient { size_of::() as u32, ); let payload_opt: Option<&[u8]> = None; - let vring_state = VhostUserVringState::new(queue_idx as u32, status as u32); + let vring_state = VhostUserVringState::new(queue_idx as u32, u32::from(status)); client .sock .send_msg(Some(&hdr), Some(&vring_state), payload_opt, &[]) -- Gitee From 5fe777ac77685080df21dc3498e5a3a64c25a5bf Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Fri, 16 Aug 2024 13:35:22 +0800 Subject: [PATCH 253/489] xhci: Fix `or-fun-call` clippy warnings error: use of `ok_or` followed by a function call --> devices/src/usb/xhci/xhci_ring.rs:104:78 | 104 | self.dequeue = self.dequeue.checked_add(u64::from(TRB_SIZE)).ok_or( | ______________________________________________________________________________^ 105 | | UsbError::MemoryAccessOverflow(self.dequeue, u64::from(TRB_SIZE)), 106 | | )?; | |_________________^ help: try this: `ok_or_else(|| UsbError::MemoryAccessOverflow(self.dequeue, u64::from(TRB_SIZE)))` | = note: `-D clippy::or-fun-call` implied by `-D warnings` = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#or_fun_call error: use of `ok_or` followed by a function call --> devices/src/usb/xhci/xhci_ring.rs:185:22 | 185 | .ok_or(UsbError::MemoryAccessOverflow(dequeue, u64::from(TRB_SIZE)))?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `ok_or_else(|| UsbError::MemoryAccessOverflow(dequeue, u64::from(TRB_SIZE)))` | = help: for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#or_fun_call error: could not compile `devices` due to 2 previous errors --- devices/src/usb/xhci/xhci_ring.rs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/devices/src/usb/xhci/xhci_ring.rs b/devices/src/usb/xhci/xhci_ring.rs index 86deba80..061fd48f 100644 --- a/devices/src/usb/xhci/xhci_ring.rs +++ b/devices/src/usb/xhci/xhci_ring.rs @@ -101,9 +101,12 @@ impl XhciCommandRing { self.ccs = !self.ccs; } } else { - self.dequeue = self.dequeue.checked_add(u64::from(TRB_SIZE)).ok_or( - UsbError::MemoryAccessOverflow(self.dequeue, u64::from(TRB_SIZE)), - )?; + self.dequeue = self + .dequeue + .checked_add(u64::from(TRB_SIZE)) + .ok_or_else(|| { + UsbError::MemoryAccessOverflow(self.dequeue, u64::from(TRB_SIZE)) + })?; return Ok(Some(trb)); } } @@ -182,7 +185,7 @@ impl XhciTransferRing { td.push(trb); dequeue = dequeue .checked_add(u64::from(TRB_SIZE)) - .ok_or(UsbError::MemoryAccessOverflow(dequeue, u64::from(TRB_SIZE)))?; + .ok_or_else(|| UsbError::MemoryAccessOverflow(dequeue, u64::from(TRB_SIZE)))?; if trb_type == TRBType::TrSetup { ctrl_td = true; } else if trb_type == TRBType::TrStatus { -- Gitee From 93392921913ff5b7566329fc2350f28626353ee6 Mon Sep 17 00:00:00 2001 From: sujerry1991 Date: Thu, 15 Aug 2024 19:46:11 +0800 Subject: [PATCH 254/489] virtio: add GPAChecked lable while using gpa addr Add GPAChecked lable which means using gpa addr is valid. Signed-off-by: Yan Wang --- virtio/src/device/balloon.rs | 1 + virtio/src/device/serial.rs | 1 + virtio/src/queue/split.rs | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/virtio/src/device/balloon.rs b/virtio/src/device/balloon.rs index 4dd36fc0..19fb5dfa 100644 --- a/virtio/src/device/balloon.rs +++ b/virtio/src/device/balloon.rs @@ -160,6 +160,7 @@ fn iov_to_buf( return None; } + // GPAChecked: the iov has been checked in pop_avail(). match address_space.read_object::(GuestAddress(iov.iov_base.raw_value() + offset)) { Ok(dat) => Some(dat), Err(ref e) => { diff --git a/virtio/src/device/serial.rs b/virtio/src/device/serial.rs index 5bf3aae8..50491861 100644 --- a/virtio/src/device/serial.rs +++ b/virtio/src/device/serial.rs @@ -589,6 +589,7 @@ impl SerialPortHandler { let write_end = written_count + len; let mut source_slice = &buffer[written_count..write_end]; + // GPAChecked: the elem_iov has been checked in pop_avail(). self.mem_space .write(&mut source_slice, elem_iov.addr, len as u64) .with_context(|| { diff --git a/virtio/src/queue/split.rs b/virtio/src/queue/split.rs index 74d81d6b..255e966d 100644 --- a/virtio/src/queue/split.rs +++ b/virtio/src/queue/split.rs @@ -298,6 +298,7 @@ impl SplitVringDesc { return false; } }; + // GPAChecked: the vring desc [addr, addr+len] must locate in guest ram. if base > reg_cache.start && end < reg_cache.end { miss_cached = false; } @@ -311,6 +312,7 @@ impl SplitVringDesc { } if miss_cached { + // GPAChecked: the vring desc addr must locate in guest ram. if let Err(ref e) = checked_offset_mem(sys_mem, self.addr, u64::from(self.len)) { error!("The memory of descriptor is invalid, {:?} ", e); return false; @@ -642,6 +644,7 @@ impl SplitVring { } fn is_invalid_memory(&self, sys_mem: &Arc, actual_size: u64) -> bool { + // GPAChecked: the desc ring table must locate in guest ram. let desc_table_end = match checked_offset_mem(sys_mem, self.desc_table, DESCRIPTOR_LEN * actual_size) { Ok(addr) => addr, @@ -656,6 +659,7 @@ impl SplitVring { } }; + // GPAChecked: the avail ring table must locate in guest ram. let desc_avail_end = match checked_offset_mem( sys_mem, self.avail_ring, @@ -673,6 +677,7 @@ impl SplitVring { } }; + // GPAChecked: the used ring table must locate in guest ram. let desc_used_end = match checked_offset_mem( sys_mem, self.used_ring, -- Gitee From 9ffe4e1b90a87a506ea333c1e53180d9625404d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=BA=A2=E5=8D=8E?= Date: Sat, 17 Aug 2024 14:27:27 +0800 Subject: [PATCH 255/489] Vfio: Add vfio feature control Add vfio feature to control vfio function. Signed-off-by:Yihua Jin --- Cargo.toml | 2 ++ hypervisor/Cargo.toml | 4 ++++ hypervisor/src/kvm/mod.rs | 5 ++++- hypervisor/src/lib.rs | 2 ++ hypervisor/src/test/mod.rs | 2 ++ machine/Cargo.toml | 3 ++- machine/src/lib.rs | 7 +++++-- machine/src/standard_common/mod.rs | 1 + machine/src/standard_common/syscall.rs | 24 ++++++++++++++---------- 9 files changed, 36 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 3277768c..1af042fe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,6 +15,7 @@ machine_manager = { path = "machine_manager" } util = { path = "util" } trace = { path = "trace" } hisysevent = { path = "hisysevent" } +hypervisor = { path = "hypervisor" } [workspace] members = [ @@ -44,6 +45,7 @@ trace_to_logger = ["trace/trace_to_logger"] trace_to_ftrace = ["trace/trace_to_ftrace"] trace_to_hitrace = ["trace/trace_to_hitrace"] hisysevent = ["hisysevent/hisysevent"] +vfio = ["machine/vfio_device", "hypervisor/vfio_device"] [package.metadata.rpm.cargo] buildflags = ["--release"] diff --git a/hypervisor/Cargo.toml b/hypervisor/Cargo.toml index ccdf1305..95c92558 100644 --- a/hypervisor/Cargo.toml +++ b/hypervisor/Cargo.toml @@ -21,3 +21,7 @@ migration = { path = "../migration" } migration_derive = { path = "../migration/migration_derive" } util = { path = "../util" } trace = { path = "../trace" } + +[features] +default = [] +vfio_device = [] diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs index e7e75d7f..9dca1743 100644 --- a/hypervisor/src/kvm/mod.rs +++ b/hypervisor/src/kvm/mod.rs @@ -36,9 +36,11 @@ use anyhow::anyhow; use anyhow::{bail, Context, Result}; use kvm_bindings::kvm_userspace_memory_region as KvmMemSlot; use kvm_bindings::*; +#[cfg(feature = "vfio_device")] +use kvm_ioctls::DeviceFd; #[cfg(not(test))] use kvm_ioctls::VcpuExit; -use kvm_ioctls::{Cap, DeviceFd, Kvm, VcpuFd, VmFd}; +use kvm_ioctls::{Cap, Kvm, VcpuFd, VmFd}; use libc::{c_int, c_void, siginfo_t}; use log::{error, info, warn}; use vmm_sys_util::{ @@ -259,6 +261,7 @@ impl HypervisorOps for KvmHypervisor { }) } + #[cfg(feature = "vfio_device")] fn create_vfio_device(&self) -> Option { let mut device = kvm_create_device { type_: kvm_device_type_KVM_DEV_TYPE_VFIO, diff --git a/hypervisor/src/lib.rs b/hypervisor/src/lib.rs index 25fc90ef..a156d9af 100644 --- a/hypervisor/src/lib.rs +++ b/hypervisor/src/lib.rs @@ -22,6 +22,7 @@ use std::any::Any; use std::sync::Arc; use anyhow::Result; +#[cfg(feature = "vfio_device")] use kvm_ioctls::DeviceFd; use address_space::AddressSpace; @@ -56,5 +57,6 @@ pub trait HypervisorOps: Send + Sync + Any { fn create_irq_manager(&mut self) -> Result; + #[cfg(feature = "vfio_device")] fn create_vfio_device(&self) -> Option; } diff --git a/hypervisor/src/test/mod.rs b/hypervisor/src/test/mod.rs index 06f3e931..99abb06e 100644 --- a/hypervisor/src/test/mod.rs +++ b/hypervisor/src/test/mod.rs @@ -21,6 +21,7 @@ use std::thread; use std::time::Duration; use anyhow::{anyhow, Context, Result}; +#[cfg(feature = "vfio_device")] use kvm_ioctls::DeviceFd; use log::info; use vmm_sys_util::eventfd::EventFd; @@ -115,6 +116,7 @@ impl HypervisorOps for TestHypervisor { }) } + #[cfg(feature = "vfio_device")] fn create_vfio_device(&self) -> Option { None } diff --git a/machine/Cargo.toml b/machine/Cargo.toml index e5d9253a..ce455c71 100644 --- a/machine/Cargo.toml +++ b/machine/Cargo.toml @@ -24,7 +24,7 @@ migration = { path = "../migration" } migration_derive = { path = "../migration/migration_derive" } util = { path = "../util" } virtio = { path = "../virtio" } -vfio = { path = "../vfio" } +vfio = { path = "../vfio" , optional = true } block_backend = { path = "../block_backend" } ui = { path = "../ui" } trace = { path = "../trace" } @@ -50,3 +50,4 @@ vnc_auth = ["vnc"] ohui_srv = ["windows_emu_pid", "ui/ohui_srv", "machine_manager/ohui_srv", "virtio/ohui_srv"] ramfb = ["devices/ramfb", "machine_manager/ramfb"] virtio_gpu = ["virtio/virtio_gpu", "machine_manager/virtio_gpu"] +vfio_device = ["vfio"] diff --git a/machine/src/lib.rs b/machine/src/lib.rs index c2774570..882db2b8 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -99,6 +99,7 @@ use util::loop_context::{ gen_delete_notifiers, EventNotifier, NotifierCallback, NotifierOperation, }; use util::seccomp::{BpfRule, SeccompOpt, SyscallFilter}; +#[cfg(feature = "vfio_device")] use vfio::{vfio_register_pcidevops_type, VfioConfig, VfioDevice, VfioPciDevice, KVM_DEVICE_FD}; #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] use virtio::VirtioDeviceQuirk; @@ -1384,7 +1385,7 @@ pub trait MachineOps: MachineLifecycle { .with_context(|| "Failed to add vhost user block device")?; Ok(()) } - + #[cfg(feature = "vfio_device")] fn add_vfio_device(&mut self, cfg_args: &str, hotplug: bool) -> Result<()> { let hypervisor = self.get_hypervisor(); let locked_hypervisor = hypervisor.lock().unwrap(); @@ -1898,12 +1899,13 @@ pub trait MachineOps: MachineLifecycle { ("virtio-serial-device" | "virtio-serial-pci", add_virtio_serial, vm_config, cfg_args), ("virtconsole" | "virtserialport", add_virtio_serial_port, vm_config, cfg_args), ("virtio-rng-device" | "virtio-rng-pci", add_virtio_rng, vm_config, cfg_args), - ("vfio-pci", add_vfio_device, cfg_args, false), ("vhost-user-blk-device",add_vhost_user_blk_device, vm_config, cfg_args), ("vhost-user-blk-pci",add_vhost_user_blk_pci, vm_config, cfg_args, false), ("vhost-user-fs-pci" | "vhost-user-fs-device", add_virtio_fs, vm_config, cfg_args), ("nec-usb-xhci", add_usb_xhci, cfg_args), ("usb-kbd" | "usb-storage" | "usb-uas" | "usb-tablet" | "usb-camera" | "usb-host", add_usb_device, vm_config, cfg_args); + #[cfg(feature = "vfio_device")] + ("vfio-pci", add_vfio_device, cfg_args, false), #[cfg(feature = "virtio_gpu")] ("virtio-gpu-pci", add_virtio_pci_gpu, cfg_args), #[cfg(feature = "ramfb")] @@ -2461,6 +2463,7 @@ pub fn type_init() -> Result<()> { // Register all pci devices type. machine_register_pcidevops_type()?; + #[cfg(feature = "vfio_device")] vfio_register_pcidevops_type()?; virtio_register_pcidevops_type()?; devices_register_pcidevops_type()?; diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index 64f11384..806e5516 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -1252,6 +1252,7 @@ impl DeviceInterface for StdMachine { ); } } + #[cfg(feature = "vfio_device")] "vfio-pci" => { let cfg_args = locked_vmconfig.add_device_config(args.as_ref()); if let Err(e) = self.add_vfio_device(&cfg_args, true) { diff --git a/machine/src/standard_common/syscall.rs b/machine/src/standard_common/syscall.rs index d665f314..30e1998e 100644 --- a/machine/src/standard_common/syscall.rs +++ b/machine/src/standard_common/syscall.rs @@ -23,6 +23,7 @@ use util::v4l2::{ VIDIOC_G_FMT, VIDIOC_QBUF, VIDIOC_QUERYBUF, VIDIOC_QUERYCAP, VIDIOC_REQBUFS, VIDIOC_STREAMOFF, VIDIOC_STREAMON, VIDIOC_S_FMT, VIDIOC_S_PARM, }; +#[cfg(feature = "vfio_device")] use vfio::{ VFIO_CHECK_EXTENSION, VFIO_DEVICE_GET_INFO, VFIO_DEVICE_GET_REGION_INFO, VFIO_DEVICE_RESET, VFIO_DEVICE_SET_IRQS, VFIO_GET_API_VERSION, VFIO_GROUP_GET_DEVICE_FD, VFIO_GROUP_GET_STATUS, @@ -226,6 +227,18 @@ fn ioctl_allow_list() -> BpfRule { .add_constraint(SeccompCmpOpt::Eq, 1, TUNSETOFFLOAD() as u32) .add_constraint(SeccompCmpOpt::Eq, 1, TUNSETVNETHDRSZ() as u32) .add_constraint(SeccompCmpOpt::Eq, 1, TUNSETQUEUE() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_GSI_ROUTING() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_IRQFD() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_CREATE_DEVICE() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_API_VERSION() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_MP_STATE() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_VCPU_EVENTS() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_DIRTY_LOG() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_MP_STATE() as u32) + .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_VCPU_EVENTS() as u32); + + #[cfg(feature = "vfio_device")] + let bpf_rule = bpf_rule .add_constraint(SeccompCmpOpt::Eq, 1, VFIO_DEVICE_SET_IRQS() as u32) .add_constraint(SeccompCmpOpt::Eq, 1, VFIO_GROUP_GET_STATUS() as u32) .add_constraint(SeccompCmpOpt::Eq, 1, VFIO_GET_API_VERSION() as u32) @@ -237,16 +250,7 @@ fn ioctl_allow_list() -> BpfRule { .add_constraint(SeccompCmpOpt::Eq, 1, VFIO_GROUP_GET_DEVICE_FD() as u32) .add_constraint(SeccompCmpOpt::Eq, 1, VFIO_DEVICE_GET_INFO() as u32) .add_constraint(SeccompCmpOpt::Eq, 1, VFIO_DEVICE_RESET() as u32) - .add_constraint(SeccompCmpOpt::Eq, 1, VFIO_DEVICE_GET_REGION_INFO() as u32) - .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_GSI_ROUTING() as u32) - .add_constraint(SeccompCmpOpt::Eq, 1, KVM_IRQFD() as u32) - .add_constraint(SeccompCmpOpt::Eq, 1, KVM_CREATE_DEVICE() as u32) - .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_API_VERSION() as u32) - .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_MP_STATE() as u32) - .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_VCPU_EVENTS() as u32) - .add_constraint(SeccompCmpOpt::Eq, 1, KVM_GET_DIRTY_LOG() as u32) - .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_MP_STATE() as u32) - .add_constraint(SeccompCmpOpt::Eq, 1, KVM_SET_VCPU_EVENTS() as u32); + .add_constraint(SeccompCmpOpt::Eq, 1, VFIO_DEVICE_GET_REGION_INFO() as u32); #[cfg(feature = "usb_camera_v4l2")] let bpf_rule = bpf_rule -- Gitee From bce2055d3894fe52b7137af013344a7a7a9c607a Mon Sep 17 00:00:00 2001 From: zhanghan64 Date: Fri, 16 Aug 2024 14:28:48 +0800 Subject: [PATCH 256/489] ohcamera:support multi-cameras To support multi-cameras on OHOS, we use "camera ID" accquired by OH camera API instead of index of supported camera list to specify a target camera. And we record related callback info for every camera, avoiding old camera callback info is covered by new one. Signed-off-by: zhanghan64 --- devices/src/camera_backend/ohcam.rs | 114 +++++++++++++++----- tests/mod_test/tests/usb_camera_test.rs | 2 +- util/src/ohos_binding/camera.rs | 50 ++++----- util/src/ohos_binding/hwf_adapter/camera.rs | 19 ++-- 4 files changed, 112 insertions(+), 73 deletions(-) diff --git a/devices/src/camera_backend/ohcam.rs b/devices/src/camera_backend/ohcam.rs index 096f24b1..04ba1b4f 100755 --- a/devices/src/camera_backend/ohcam.rs +++ b/devices/src/camera_backend/ohcam.rs @@ -10,6 +10,8 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. +use std::collections::HashMap; +use std::ffi::CStr; use std::sync::RwLock; use anyhow::{bail, Context, Result}; @@ -29,8 +31,8 @@ use trace::trace_scope::Scope; use util::aio::Iovec; use util::ohos_binding::camera::*; -type OhCamCB = RwLock; -static OHCAM_CALLBACK: Lazy = Lazy::new(|| RwLock::new(OhCamCallBack::default())); +type OhCamCB = RwLock>; +static OHCAM_CALLBACKS: Lazy = Lazy::new(|| RwLock::new(HashMap::new())); // In UVC, interval's unit is 100ns. // So, fps * interval / 10_000_000 == 1. @@ -114,8 +116,10 @@ impl OhCameraAsyncScope { #[derive(Clone)] pub struct OhCameraBackend { + // ID for this OhCameraBackend. id: String, - camidx: u8, + // ID of OH camera device. + camid: String, profile_cnt: u8, ctx: OhCamera, fmt_list: Vec, @@ -148,17 +152,20 @@ fn cam_fmt_from_oh(t: i32) -> Result { Ok(fmt) } -impl OhCameraBackend { - pub fn new(id: String, camid: String) -> Result { - let idx = camid.parse::().with_context(|| "Invalid PATH format")?; - let ctx = OhCamera::new(idx as i32)?; +impl Drop for OhCameraBackend { + fn drop(&mut self) { + OHCAM_CALLBACKS.write().unwrap().remove_entry(&self.camid); + } +} - let profile_cnt = ctx.get_fmt_nums(idx as i32)? as u8; +impl OhCameraBackend { + pub fn new(id: String, cam_name: String) -> Result { + let (ctx, profile_cnt) = OhCamera::new(cam_name.clone())?; Ok(OhCameraBackend { id, - camidx: idx, - profile_cnt, + camid: cam_name, + profile_cnt: profile_cnt as u8, ctx, fmt_list: vec![], selected_profile: 0, @@ -193,8 +200,7 @@ impl CameraBackend for OhCameraBackend { } self.selected_profile = fmt.fmt_index - 1; - self.ctx - .set_fmt(self.camidx as i32, self.selected_profile as i32)?; + self.ctx.set_fmt(i32::from(self.selected_profile))?; return Ok(()); } } @@ -213,7 +219,9 @@ impl CameraBackend for OhCameraBackend { fn video_stream_off(&mut self) -> Result<()> { self.ctx.stop_stream(); - OHCAM_CALLBACK.write().unwrap().clear_buffer(); + if let Some(cb) = OHCAM_CALLBACKS.write().unwrap().get_mut(&self.camid) { + cb.clear_buffer(); + } self.stream_on = false; #[cfg(any( feature = "trace_to_logger", @@ -228,7 +236,7 @@ impl CameraBackend for OhCameraBackend { let mut fmt_list: Vec = Vec::new(); for idx in 0..self.profile_cnt { - match self.ctx.get_profile(self.camidx as i32, idx as i32) { + match self.ctx.get_profile(idx as i32) { Ok((fmt, width, height, fps)) => { if !FRAME_FORMAT_WHITELIST.iter().any(|&x| x == fmt) || !RESOLUTION_WHITELIST.iter().any(|&x| x == (width, height)) @@ -257,8 +265,12 @@ impl CameraBackend for OhCameraBackend { } fn reset(&mut self) { - OHCAM_CALLBACK.write().unwrap().clear_buffer(); - self.ctx.reset_camera(); + if let Some(cb) = OHCAM_CALLBACKS.write().unwrap().get_mut(&self.camid) { + cb.clear_buffer(); + } + if let Err(e) = self.ctx.reset_camera(self.camid.clone()) { + error!("OHCAM: reset failed, err: {e}"); + } #[cfg(any( feature = "trace_to_logger", feature = "trace_to_ftrace", @@ -300,7 +312,10 @@ impl CameraBackend for OhCameraBackend { } fn get_frame_size(&self) -> usize { - OHCAM_CALLBACK.read().unwrap().get_buffer().1 as usize + if let Some(cb) = OHCAM_CALLBACKS.read().unwrap().get(&self.camid) { + return cb.get_buffer().1 as usize; + } + 0 } fn next_frame(&mut self) -> Result<()> { @@ -311,12 +326,20 @@ impl CameraBackend for OhCameraBackend { ))] self.async_scope.start(); self.ctx.next_frame(); - OHCAM_CALLBACK.write().unwrap().clear_buffer(); + if let Some(cb) = OHCAM_CALLBACKS.write().unwrap().get_mut(&self.camid) { + cb.clear_buffer(); + } Ok(()) } fn get_frame(&self, iovecs: &[Iovec], frame_offset: usize, len: usize) -> Result { - let (src, src_len) = OHCAM_CALLBACK.read().unwrap().get_buffer(); + let (src, src_len) = OHCAM_CALLBACKS + .read() + .unwrap() + .get(&self.camid) + .with_context(|| "Invalid camid in callback table")? + .get_buffer(); + if src_len == 0 { bail!("Invalid frame src_len {}", src_len); } @@ -344,11 +367,21 @@ impl CameraBackend for OhCameraBackend { } fn register_notify_cb(&mut self, cb: CameraNotifyCallback) { - OHCAM_CALLBACK.write().unwrap().set_notify_cb(cb); + OHCAM_CALLBACKS + .write() + .unwrap() + .entry(self.camid.clone()) + .or_insert(OhCamCallBack::default()) + .set_notify_cb(cb); } fn register_broken_cb(&mut self, cb: CameraBrokenCallback) { - OHCAM_CALLBACK.write().unwrap().set_broken_cb(cb); + OHCAM_CALLBACKS + .write() + .unwrap() + .entry(self.camid.clone()) + .or_insert(OhCamCallBack::default()) + .set_broken_cb(cb); } fn pause(&mut self, paused: bool) { @@ -376,16 +409,39 @@ impl CameraBackend for OhCameraBackend { } } +fn cstr_to_string(src: *const u8) -> Result { + if src.is_null() { + bail!("cstr_to_string: src is null"); + } + // SAFETY: we promise that 'src' ends with "null" symbol. + let src_cstr = unsafe { CStr::from_ptr(src) }; + let target_string = src_cstr + .to_str() + .with_context(|| "cstr_to_string: failed to transfer camid")? + .to_owned(); + + Ok(target_string) +} + // SAFETY: use RW lock to ensure the security of resources. -unsafe extern "C" fn on_buffer_available(src_buffer: u64, length: i32) { - OHCAM_CALLBACK - .write() - .unwrap() - .set_buffer(src_buffer, length); - OHCAM_CALLBACK.read().unwrap().notify(); +unsafe extern "C" fn on_buffer_available(src_buffer: u64, length: i32, camid: *const u8) { + let cam = cstr_to_string(camid).unwrap_or_else(|e| { + error!("{e}"); + "".to_string() + }); + if let Some(cb) = OHCAM_CALLBACKS.write().unwrap().get_mut(&cam) { + cb.set_buffer(src_buffer, length); + cb.notify(); + } } // SAFETY: use RW lock to ensure the security of resources. -unsafe extern "C" fn on_broken() { - OHCAM_CALLBACK.read().unwrap().broken(); +unsafe extern "C" fn on_broken(camid: *const u8) { + let cam = cstr_to_string(camid).unwrap_or_else(|e| { + error!("{e}"); + "".to_string() + }); + if let Some(cb) = OHCAM_CALLBACKS.read().unwrap().get(&cam) { + cb.broken(); + } } diff --git a/tests/mod_test/tests/usb_camera_test.rs b/tests/mod_test/tests/usb_camera_test.rs index 7773200e..70316d0d 100644 --- a/tests/mod_test/tests/usb_camera_test.rs +++ b/tests/mod_test/tests/usb_camera_test.rs @@ -563,7 +563,7 @@ fn test_xhci_camera_hotplug_invalid() { #[cfg(not(target_env = "ohos"))] assert_eq!(desc, "Failed to open v4l2 backend /tmp/not-existed."); #[cfg(target_env = "ohos")] - assert_eq!(desc, "Invalid PATH format"); + assert_eq!(desc, "OH Camera: failed to init cameras"); // Invalid device id. let value = qmp_unplug_camera(&test_state.clone(), "usbcam0"); let desc = value["error"]["desc"].as_str().unwrap().to_string(); diff --git a/util/src/ohos_binding/camera.rs b/util/src/ohos_binding/camera.rs index e481e887..eadeb0d1 100644 --- a/util/src/ohos_binding/camera.rs +++ b/util/src/ohos_binding/camera.rs @@ -10,11 +10,12 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. +use std::ffi::CString; use std::os::raw::{c_int, c_void}; use std::ptr; use std::sync::Arc; -use anyhow::{bail, Result}; +use anyhow::{bail, Context, Result}; use super::hwf_adapter::camera::{ BrokenProcessFn, BufferProcessFn, CamFuncTable, OhCameraCtx, ProfileRecorder, @@ -45,42 +46,30 @@ impl Drop for OhCamera { } impl OhCamera { - pub fn new(idx: i32) -> Result { + pub fn new(id: String) -> Result<(OhCamera, i32)> { let capi = hwf_adapter_camera_api(); // SAFETY: We call related API sequentially for specified ctx. let mut ctx = unsafe { (capi.create_ctx)() }; if ctx.is_null() { bail!("OH Camera: failed to create camera ctx"); } + let id_c = CString::new(id).with_context(|| "failed to create CString id")?; + let fmt_cnt; // SAFETY: We call related API sequentially for specified ctx. unsafe { - let n = (capi.init_cameras)(ctx); + let n = (capi.init_camera)(ctx, id_c.as_ptr()); if n < 0 { (capi.destroy_ctx)(ptr::addr_of_mut!(ctx)); bail!("OH Camera: failed to init cameras"); - } else if idx >= n { - (capi.destroy_ctx)(ptr::addr_of_mut!(ctx)); - bail!( - "OH Camera: invalid idx {}, valid num is less than {}", - idx, - n - ); } - if (capi.init_profiles)(ctx) < 0 { + + fmt_cnt = (capi.init_profiles)(ctx); + if fmt_cnt < 0 { (capi.destroy_ctx)(ptr::addr_of_mut!(ctx)); bail!("OH Camera: failed to init profiles"); } } - Ok(Self { ctx, capi }) - } - - pub fn get_fmt_nums(&self, idx: i32) -> Result { - // SAFETY: We call related API sequentially for specified ctx. - let ret = unsafe { (self.capi.get_profile_size)(self.ctx, idx as c_int) }; - if ret < 0 { - bail!("OH Camera: invalid camera idx {}", idx); - } - Ok(ret) + Ok((Self { ctx, capi }, fmt_cnt)) } pub fn release_camera(&self) { @@ -93,10 +82,10 @@ impl OhCamera { unsafe { (self.capi.destroy_ctx)(ptr::addr_of_mut!(self.ctx)) } } - pub fn set_fmt(&self, cam_idx: i32, profile_idx: i32) -> Result<()> { + pub fn set_fmt(&self, profile_idx: i32) -> Result<()> { let ret = // SAFETY: We call related API sequentially for specified ctx. - unsafe { (self.capi.set_profile)(self.ctx, cam_idx as c_int, profile_idx as c_int) }; + unsafe { (self.capi.set_profile)(self.ctx, profile_idx as c_int) }; if ret < 0 { bail!("OH Camera: failed to get camera profile"); } @@ -123,12 +112,14 @@ impl OhCamera { Ok(()) } - pub fn reset_camera(&self) { + pub fn reset_camera(&self, id: String) -> Result<()> { + let id_cstr = CString::new(id).with_context(|| "failed to create CString id")?; // SAFETY: We call related API sequentially for specified ctx. unsafe { - (self.capi.init_cameras)(self.ctx); + (self.capi.init_camera)(self.ctx, id_cstr.as_ptr()); (self.capi.init_profiles)(self.ctx); } + Ok(()) } pub fn stop_stream(&self) { @@ -139,22 +130,17 @@ impl OhCamera { } } - pub fn get_profile(&self, cam_idx: i32, profile_idx: i32) -> Result<(i32, i32, i32, i32)> { + pub fn get_profile(&self, profile_idx: i32) -> Result<(i32, i32, i32, i32)> { let pr = ProfileRecorder::default(); // SAFETY: We call related API sequentially for specified ctx. unsafe { let ret = (self.capi.get_profile)( self.ctx, - cam_idx as c_int, profile_idx as c_int, ptr::addr_of!(pr) as *mut c_void, ); if ret < 0 { - bail!( - "OH Camera: failed to get camera {} profile {}", - cam_idx, - profile_idx - ); + bail!("OH Camera: failed to get profile {}", profile_idx); } } Ok((pr.fmt, pr.width, pr.height, pr.fps)) diff --git a/util/src/ohos_binding/hwf_adapter/camera.rs b/util/src/ohos_binding/hwf_adapter/camera.rs index 0fdc9ee7..bbb20742 100644 --- a/util/src/ohos_binding/hwf_adapter/camera.rs +++ b/util/src/ohos_binding/hwf_adapter/camera.rs @@ -10,7 +10,7 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use std::os::raw::{c_int, c_void}; +use std::os::raw::{c_char, c_int, c_void}; use anyhow::{Context, Result}; use libloading::os::unix::Symbol as RawSymbol; @@ -33,17 +33,16 @@ pub struct ProfileRecorder { pub fps: i32, } -pub type BufferProcessFn = unsafe extern "C" fn(src_buffer: u64, length: i32); -pub type BrokenProcessFn = unsafe extern "C" fn(); +pub type BufferProcessFn = unsafe extern "C" fn(src_buffer: u64, length: i32, camid: *const c_char); +pub type BrokenProcessFn = unsafe extern "C" fn(camid: *const c_char); type OhcamCreateCtxFn = unsafe extern "C" fn() -> *mut OhCameraCtx; type OhcamCreateSessionFn = unsafe extern "C" fn(*mut OhCameraCtx) -> c_int; type OhcamReleaseSessionFn = unsafe extern "C" fn(*mut OhCameraCtx); -type OhcamInitCamerasFn = unsafe extern "C" fn(*mut OhCameraCtx) -> c_int; +type OhcamInitCameraFn = unsafe extern "C" fn(*mut OhCameraCtx, *const c_char) -> c_int; type OhcamInitProfilesFn = unsafe extern "C" fn(*mut OhCameraCtx) -> c_int; -type OhcamGetProfileSizeFn = unsafe extern "C" fn(*mut OhCameraCtx, c_int) -> c_int; -type OhcamGetProfileFn = unsafe extern "C" fn(*mut OhCameraCtx, c_int, c_int, *mut c_void) -> c_int; -type OhcamSetProfileFn = unsafe extern "C" fn(*mut OhCameraCtx, c_int, c_int) -> c_int; +type OhcamGetProfileFn = unsafe extern "C" fn(*mut OhCameraCtx, c_int, *mut c_void) -> c_int; +type OhcamSetProfileFn = unsafe extern "C" fn(*mut OhCameraCtx, c_int) -> c_int; type OhcamPreStartFn = unsafe extern "C" fn(*mut OhCameraCtx, BufferProcessFn, BrokenProcessFn) -> c_int; type OhcamStartFn = unsafe extern "C" fn(*mut OhCameraCtx) -> c_int; @@ -56,9 +55,8 @@ pub struct CamFuncTable { pub create_ctx: RawSymbol, pub create_session: RawSymbol, pub release_session: RawSymbol, - pub init_cameras: RawSymbol, + pub init_camera: RawSymbol, pub init_profiles: RawSymbol, - pub get_profile_size: RawSymbol, pub get_profile: RawSymbol, pub set_profile: RawSymbol, pub pre_start: RawSymbol, @@ -75,9 +73,8 @@ impl CamFuncTable { create_ctx: get_libfn!(library, OhcamCreateCtxFn, OhcamCreateCtx), create_session: get_libfn!(library, OhcamCreateSessionFn, OhcamCreateSession), release_session: get_libfn!(library, OhcamReleaseSessionFn, OhcamReleaseSession), - init_cameras: get_libfn!(library, OhcamInitCamerasFn, OhcamInitCameras), + init_camera: get_libfn!(library, OhcamInitCameraFn, OhcamInitCamera), init_profiles: get_libfn!(library, OhcamInitProfilesFn, OhcamInitProfiles), - get_profile_size: get_libfn!(library, OhcamGetProfileSizeFn, OhcamGetProfileSize), get_profile: get_libfn!(library, OhcamGetProfileFn, OhcamGetProfile), set_profile: get_libfn!(library, OhcamSetProfileFn, OhcamSetProfile), pre_start: get_libfn!(library, OhcamPreStartFn, OhcamPreStart), -- Gitee From 8c480d3b00c2c46c07ae50937c4070bbe47aaec2 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Sat, 17 Aug 2024 11:44:44 +0800 Subject: [PATCH 257/489] clippy: Fix clippy warnings from high version clippy Signed-off-by: Keqian Zhu --- acpi/src/aml_compiler.rs | 6 +- acpi/src/table_loader.rs | 4 +- address_space/src/address_space.rs | 16 +- address_space/src/region.rs | 2 +- block_backend/src/lib.rs | 2 +- block_backend/src/qcow2/cache.rs | 10 +- block_backend/src/qcow2/check.rs | 4 +- block_backend/src/qcow2/header.rs | 28 +- block_backend/src/qcow2/mod.rs | 9 +- block_backend/src/qcow2/refcount.rs | 10 +- cpu/src/lib.rs | 2 +- devices/src/acpi/power.rs | 2 +- devices/src/pci/mod.rs | 6 +- devices/src/usb/mod.rs | 2 +- hypervisor/src/kvm/interrupt.rs | 6 +- hypervisor/src/kvm/listener.rs | 14 +- hypervisor/src/kvm/mod.rs | 4 +- image/src/cmdline.rs | 14 +- image/src/img.rs | 129 ++++----- machine_manager/src/config/boot_source.rs | 6 +- machine_manager/src/config/camera.rs | 4 +- machine_manager/src/config/chardev.rs | 2 +- machine_manager/src/config/display.rs | 8 +- machine_manager/src/config/drive.rs | 37 +-- machine_manager/src/config/machine_config.rs | 26 +- machine_manager/src/config/mod.rs | 5 +- machine_manager/src/config/network.rs | 28 +- machine_manager/src/config/numa.rs | 4 +- machine_manager/src/config/sasl_auth.rs | 4 +- machine_manager/src/config/tls_creds.rs | 8 +- machine_manager/src/config/vnc.rs | 4 +- machine_manager/src/qmp/qmp_response.rs | 2 +- machine_manager/src/qmp/qmp_schema.rs | 2 +- machine_manager/src/qmp/qmp_socket.rs | 25 +- machine_manager/src/socket.rs | 2 +- migration/src/protocol.rs | 49 ++-- src/main.rs | 8 +- tests/mod_test/src/libdriver/pci.rs | 13 +- tests/mod_test/src/libdriver/qcow2.rs | 25 +- tests/mod_test/src/libdriver/usb.rs | 98 +++---- tests/mod_test/src/libdriver/virtio_gpu.rs | 22 +- .../src/libdriver/virtio_pci_modern.rs | 4 +- tests/mod_test/src/libdriver/vnc.rs | 51 +--- tests/mod_test/src/libtest.rs | 4 +- tests/mod_test/src/utils.rs | 12 +- tests/mod_test/tests/balloon_test.rs | 39 +-- tests/mod_test/tests/block_test.rs | 23 +- tests/mod_test/tests/fwcfg_test.rs | 44 +-- tests/mod_test/tests/memory_test.rs | 8 +- tests/mod_test/tests/net_test.rs | 92 +++---- tests/mod_test/tests/pci_test.rs | 98 ++++--- tests/mod_test/tests/pvpanic_test.rs | 2 +- tests/mod_test/tests/scsi_test.rs | 16 +- tests/mod_test/tests/serial_test.rs | 12 +- tests/mod_test/tests/usb_camera_test.rs | 2 +- tests/mod_test/tests/usb_storage_test.rs | 4 +- tests/mod_test/tests/usb_test.rs | 43 ++- tests/mod_test/tests/virtio_gpu_test.rs | 18 +- tests/mod_test/tests/virtio_test.rs | 61 ++--- tests/mod_test/tests/virtiofs_test.rs | 258 +++++++++--------- tests/mod_test/tests/vnc_test.rs | 36 ++- .../mod_test/tests/x86_64/cpu_hotplug_test.rs | 7 +- ui/src/console.rs | 8 +- ui/src/input.rs | 6 +- ui/src/utils.rs | 10 +- ui/src/vnc/encoding/enc_hextile.rs | 12 +- util/src/aio/mod.rs | 19 +- util/src/arg_parser.rs | 10 +- util/src/bitmap.rs | 56 ++-- util/src/daemonize.rs | 1 + util/src/logger.rs | 1 - util/src/loop_context.rs | 14 +- util/src/num_ops.rs | 4 +- util/src/unix.rs | 6 +- util/src/v4l2.rs | 2 +- virtio/src/device/balloon.rs | 10 +- virtio/src/device/block.rs | 19 +- virtio/src/device/gpu.rs | 8 +- virtio/src/device/net.rs | 40 +-- virtio/src/device/rng.rs | 12 +- virtio/src/device/scsi_cntlr.rs | 2 +- virtio/src/device/serial.rs | 4 +- virtio/src/queue/split.rs | 112 ++++---- virtio/src/transport/virtio_mmio.rs | 228 ++++------------ virtio/src/transport/virtio_pci.rs | 10 +- virtio/src/vhost/kernel/net.rs | 12 +- virtio/src/vhost/kernel/vsock.rs | 25 +- 87 files changed, 929 insertions(+), 1188 deletions(-) diff --git a/acpi/src/aml_compiler.rs b/acpi/src/aml_compiler.rs index b7aa0a9a..f97216ae 100644 --- a/acpi/src/aml_compiler.rs +++ b/acpi/src/aml_compiler.rs @@ -1819,7 +1819,7 @@ mod test { let elem4 = AmlFieldUnit::new(Some("FLD3"), 4); let elem5 = AmlFieldUnit::new(Some("FLD4"), 12); - for e in vec![elem1, elem2, elem3, elem4, elem5] { + for e in [elem1, elem2, elem3, elem4, elem5] { field.append_child(e); } @@ -1991,7 +1991,7 @@ mod test { if_scope1.append_child(AmlReturn::new()); method1.append_child(if_scope1); - let store1 = AmlStore::new(AmlArg(0), AmlLocal(0).clone()); + let store1 = AmlStore::new(AmlArg(0), AmlLocal(0)); method1.append_child(store1); let mut while_scope = AmlWhile::new(AmlLLess::new(AmlLocal(0), AmlArg(1))); @@ -2031,7 +2031,7 @@ mod test { method2.append_child(store2); let mut pkg1 = AmlPackage::new(3); - vec![0x01, 0x03F8, 0x03FF].iter().for_each(|&x| { + [0x01, 0x03F8, 0x03FF].iter().for_each(|&x| { pkg1.append_child(AmlInteger(x as u64)); }); let named_pkg1 = AmlNameDecl::new("PKG1", pkg1); diff --git a/acpi/src/table_loader.rs b/acpi/src/table_loader.rs index 74a9d173..e968e4d0 100644 --- a/acpi/src/table_loader.rs +++ b/acpi/src/table_loader.rs @@ -382,7 +382,7 @@ mod test { let file_bytes = file_name.as_bytes(); // SATETY: The "alloc" field of union consists of u8 members, so the access is safe. - let alloc = unsafe { &table_loader.cmds.get(0).unwrap().entry.alloc }; + let alloc = unsafe { &table_loader.cmds.first().unwrap().entry.alloc }; assert_eq!( alloc.file[0..file_bytes.len()].to_vec(), file_bytes.to_vec() @@ -450,7 +450,7 @@ mod test { .add_cksum_entry(&file, 0_u32, 0_u32, file_len + 1) .is_err()); assert!(table_loader - .add_cksum_entry(&file, (file_len - 1) as u32, 80, 20) + .add_cksum_entry(&file, file_len - 1, 80, 20) .is_ok()); assert!(table_loader .add_cksum_entry(&file, file_len - 1, 0, 50) diff --git a/address_space/src/address_space.rs b/address_space/src/address_space.rs index d19e6c3d..84f1be4e 100644 --- a/address_space/src/address_space.rs +++ b/address_space/src/address_space.rs @@ -984,7 +984,7 @@ mod test { space.unregister_listener(listener2).unwrap(); assert_eq!(space.listeners.lock().unwrap().len(), 1); for listener in space.listeners.lock().unwrap().iter() { - assert_eq!(listener.lock().unwrap().enabled(), true); + assert!(listener.lock().unwrap().enabled()); } } @@ -1024,7 +1024,7 @@ mod test { .reqs .lock() .unwrap() - .get(0) + .first() .unwrap() .1, AddressRange::new(region_c.offset(), region_c.size()) @@ -1047,7 +1047,7 @@ mod test { assert_eq!(locked_listener.reqs.lock().unwrap().len(), 4); // delete flat-range 0~6000 first, belonging to region_c assert_eq!( - locked_listener.reqs.lock().unwrap().get(0).unwrap().1, + locked_listener.reqs.lock().unwrap().first().unwrap().1, AddressRange::new(region_c.offset(), region_c.size()) ); // add range 0~2000, belonging to region_c @@ -1197,8 +1197,8 @@ mod test { ram2.start_address().unchecked_add(ram2.size()) ); assert!(space.address_in_memory(GuestAddress(0), 0)); - assert_eq!(space.address_in_memory(GuestAddress(1000), 0), false); - assert_eq!(space.address_in_memory(GuestAddress(1500), 0), false); + assert!(!space.address_in_memory(GuestAddress(1000), 0)); + assert!(!space.address_in_memory(GuestAddress(1500), 0)); assert!(space.address_in_memory(GuestAddress(2900), 0)); assert_eq!( @@ -1227,9 +1227,9 @@ mod test { ram2.start_address().unchecked_add(ram2.size()) ); assert!(space.address_in_memory(GuestAddress(0), 0)); - assert_eq!(space.address_in_memory(GuestAddress(1000), 0), false); - assert_eq!(space.address_in_memory(GuestAddress(1500), 0), false); - assert_eq!(space.address_in_memory(GuestAddress(2400), 0), false); + assert!(!space.address_in_memory(GuestAddress(1000), 0)); + assert!(!space.address_in_memory(GuestAddress(1500), 0)); + assert!(!space.address_in_memory(GuestAddress(2400), 0)); assert!(space.address_in_memory(GuestAddress(2900), 0)); assert_eq!( diff --git a/address_space/src/region.rs b/address_space/src/region.rs index f5e7c77a..64ad7fba 100644 --- a/address_space/src/region.rs +++ b/address_space/src/region.rs @@ -1323,7 +1323,7 @@ mod test { .subregions .read() .unwrap() - .get(0) + .first() .unwrap() .priority(), 10 diff --git a/block_backend/src/lib.rs b/block_backend/src/lib.rs index c571f292..525c1c66 100644 --- a/block_backend/src/lib.rs +++ b/block_backend/src/lib.rs @@ -154,7 +154,7 @@ impl CreateOptions { // Transform size into string with storage units. fn size_to_string(size: f64) -> Result { - let units = vec!["", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"]; + let units = ["", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB"]; // Switch to higher power if the integer part is >= 1000, // For example: 1000 * 2^30 bytes diff --git a/block_backend/src/qcow2/cache.rs b/block_backend/src/qcow2/cache.rs index c46bc5d9..f3ca26b8 100644 --- a/block_backend/src/qcow2/cache.rs +++ b/block_backend/src/qcow2/cache.rs @@ -262,7 +262,7 @@ mod test { for i in 0..buf.len() { vec.append(&mut buf[i].to_be_bytes().to_vec()); } - let mut entry = CacheTable::new(0x00 as u64, vec, ENTRY_SIZE_U64).unwrap(); + let mut entry = CacheTable::new(0x00_u64, vec, ENTRY_SIZE_U64).unwrap(); assert_eq!(entry.get_entry_map(0).unwrap(), 0x00); assert_eq!(entry.get_entry_map(3).unwrap(), 0x03); assert_eq!(entry.get_entry_map(4).unwrap(), 0x04); @@ -279,19 +279,19 @@ mod test { vec.append(&mut buf[i].to_be_bytes().to_vec()); } let entry_0 = Rc::new(RefCell::new( - CacheTable::new(0x00 as u64, vec.clone(), ENTRY_SIZE_U64).unwrap(), + CacheTable::new(0x00_u64, vec.clone(), ENTRY_SIZE_U64).unwrap(), )); entry_0.borrow_mut().lru_count = 0; let entry_1 = Rc::new(RefCell::new( - CacheTable::new(0x00 as u64, vec.clone(), ENTRY_SIZE_U64).unwrap(), + CacheTable::new(0x00_u64, vec.clone(), ENTRY_SIZE_U64).unwrap(), )); entry_1.borrow_mut().lru_count = 1; let entry_2 = Rc::new(RefCell::new( - CacheTable::new(0x00 as u64, vec.clone(), ENTRY_SIZE_U64).unwrap(), + CacheTable::new(0x00_u64, vec.clone(), ENTRY_SIZE_U64).unwrap(), )); entry_2.borrow_mut().lru_count = 2; let entry_3 = Rc::new(RefCell::new( - CacheTable::new(0x00 as u64, vec.clone(), ENTRY_SIZE_U64).unwrap(), + CacheTable::new(0x00_u64, vec.clone(), ENTRY_SIZE_U64).unwrap(), )); entry_3.borrow_mut().lru_count = 3; diff --git a/block_backend/src/qcow2/check.rs b/block_backend/src/qcow2/check.rs index c148178c..35e4f350 100644 --- a/block_backend/src/qcow2/check.rs +++ b/block_backend/src/qcow2/check.rs @@ -1124,8 +1124,8 @@ mod test { assert!(refblock.set_refcount(9, 9).is_ok()); // Get inner dat - let mut vec_1 = (1 as u16).to_be_bytes().to_vec(); - let mut vec_2 = (7 as u16).to_be_bytes().to_vec(); + let mut vec_1 = 1_u16.to_be_bytes().to_vec(); + let mut vec_2 = 7_u16.to_be_bytes().to_vec(); vec_1.append(&mut vec_2); let buf = refblock.get_data(0, 2); assert_eq!(buf, vec_1); diff --git a/block_backend/src/qcow2/header.rs b/block_backend/src/qcow2/header.rs index 99404b9f..fa3681d9 100644 --- a/block_backend/src/qcow2/header.rs +++ b/block_backend/src/qcow2/header.rs @@ -320,21 +320,21 @@ mod test { fn invalid_header_list() -> Vec<(Vec, String)> { let mut list = Vec::new(); // Invalid buffer length. - list.push((vec![0_u8; 16], format!("Invalid header len"))); + list.push((vec![0_u8; 16], "Invalid header len".to_string())); // Invalid buffer length for v3. let buf = valid_header_v3(); list.push(( buf[0..90].to_vec(), - format!("Invalid header len for version 3"), + "Invalid header len for version 3".to_string(), )); // Invalid magic. let mut buf = valid_header_v2(); BigEndian::write_u32(&mut buf[0..4], 1234); - list.push((buf, format!("Invalid format"))); + list.push((buf, "Invalid format".to_string())); // Invalid version. let mut buf = valid_header_v3(); BigEndian::write_u32(&mut buf[4..8], 1); - list.push((buf, format!("Invalid version"))); + list.push((buf, "Invalid version".to_string())); // Large header length. let mut buf = valid_header_v3(); BigEndian::write_u32(&mut buf[100..104], 0x10000000_u32); @@ -345,23 +345,23 @@ mod test { // Small cluster bit. let mut buf = valid_header_v3(); BigEndian::write_u32(&mut buf[20..24], 0); - list.push((buf, format!("Invalid cluster bit"))); + list.push((buf, "Invalid cluster bit".to_string())); // Large cluster bit. let mut buf = valid_header_v3(); BigEndian::write_u32(&mut buf[20..24], 65); - list.push((buf, format!("Invalid cluster bit"))); + list.push((buf, "Invalid cluster bit".to_string())); // Invalid backing file offset. let mut buf = valid_header_v3(); BigEndian::write_u32(&mut buf[8..16], 0x2000); - list.push((buf, format!("Don't support backing file offset"))); + list.push((buf, "Don't support backing file offset".to_string())); // Invalid refcount order. let mut buf = valid_header_v3(); BigEndian::write_u32(&mut buf[96..100], 5); - list.push((buf, format!("Invalid refcount order"))); + list.push((buf, "Invalid refcount order".to_string())); // Refcount table offset is not aligned. let mut buf = valid_header_v3(); BigEndian::write_u64(&mut buf[48..56], 0x1234); - list.push((buf, format!("Refcount table offset not aligned"))); + list.push((buf, "Refcount table offset not aligned".to_string())); // Refcount table offset is large. let mut buf = valid_header_v3(); BigEndian::write_u32(&mut buf[36..40], 4 * 1024 * 1024); @@ -377,15 +377,15 @@ mod test { // Invalid refcount table cluster. let mut buf = valid_header_v3(); BigEndian::write_u32(&mut buf[56..60], 256); - list.push((buf, format!("Refcount table size over limit"))); + list.push((buf, "Refcount table size over limit".to_string())); // Refcount table cluster is 0. let mut buf = valid_header_v3(); BigEndian::write_u32(&mut buf[56..60], 0); - list.push((buf, format!("Refcount table clusters is zero"))); + list.push((buf, "Refcount table clusters is zero".to_string())); // L1 table offset is not aligned. let mut buf = valid_header_v3(); BigEndian::write_u64(&mut buf[40..48], 0x123456); - list.push((buf, format!("L1 table offset not aligned"))); + list.push((buf, "L1 table offset not aligned".to_string())); // L1 table offset is large. let mut buf = valid_header_v3(); BigEndian::write_u32(&mut buf[36..40], 4 * 1024 * 1024); @@ -401,12 +401,12 @@ mod test { // Invalid l1 table size. let mut buf = valid_header_v3(); BigEndian::write_u32(&mut buf[36..40], 0xffff_0000_u32); - list.push((buf, format!("L1 table size over limit"))); + list.push((buf, "L1 table size over limit".to_string())); // File size is large than l1 table size. let mut buf = valid_header_v3(); BigEndian::write_u64(&mut buf[24..32], 0xffff_ffff_ffff_0000_u64); BigEndian::write_u32(&mut buf[36..40], 10); - list.push((buf, format!("L1 table is too small"))); + list.push((buf, "L1 table is too small".to_string())); list } diff --git a/block_backend/src/qcow2/mod.rs b/block_backend/src/qcow2/mod.rs index 3edc388e..7c14cb98 100644 --- a/block_backend/src/qcow2/mod.rs +++ b/block_backend/src/qcow2/mod.rs @@ -1994,10 +1994,10 @@ mod test { file.write_all(&header.to_vec()).unwrap(); // Cluster 1 is the refcount table. - assert_eq!(header.refcount_table_offset, cluster_sz * 1); + assert_eq!(header.refcount_table_offset, cluster_sz); let mut refcount_table = [0_u8; ENTRY_SIZE as usize]; BigEndian::write_u64(&mut refcount_table, cluster_sz * 2); - file.seek(SeekFrom::Start(cluster_sz * 1)).unwrap(); + file.seek(SeekFrom::Start(cluster_sz)).unwrap(); file.write_all(&refcount_table).unwrap(); // Clusters which has been allocated. @@ -2357,7 +2357,7 @@ mod test { riovec, wiovec, data: test_data, - offset: 1 * CLUSTER_SIZE as usize, + offset: CLUSTER_SIZE as usize, sz: CLUSTER_SIZE, }); let test_data = vec![TestData::new(5, CLUSTER_SIZE as usize)]; @@ -2743,9 +2743,8 @@ mod test { .borrow_mut() .get_entry_map(l2_index as usize) .unwrap(); - let host_offset = l2_entry & L2_TABLE_OFFSET_MASK; - host_offset + l2_entry & L2_TABLE_OFFSET_MASK } // Change snapshot table offset to unaligned address which will lead to error in refcount update diff --git a/block_backend/src/qcow2/refcount.rs b/block_backend/src/qcow2/refcount.rs index 67c4c1e2..7c60ce31 100644 --- a/block_backend/src/qcow2/refcount.rs +++ b/block_backend/src/qcow2/refcount.rs @@ -890,7 +890,7 @@ mod test { for j in (i + 1)..len { let addr2 = res_data[j].0 as usize; let size2 = res_data[j].1 as usize; - assert_eq!(ranges_overlap(addr1, size1, addr2, size2).unwrap(), false); + assert!(!ranges_overlap(addr1, size1, addr2, size2).unwrap()); } } @@ -936,7 +936,7 @@ mod test { let mut new_rc_table = vec![0_u8; new_rct_size]; cloned_file .as_ref() - .read_at(&mut new_rc_table, new_rct_offset as u64) + .read_at(&mut new_rc_table, new_rct_offset) .unwrap(); for i in 0..old_rct_size { assert_eq!(old_rc_table[i], new_rc_table[i]); @@ -992,7 +992,7 @@ mod test { &Qcow2DiscardType::Never, ); if let Err(err) = ret { - let err_msg = format!("Invalid refcount block address 0x0, index is 2"); + let err_msg = "Invalid refcount block address 0x0, index is 2".to_string(); assert_eq!(err.to_string(), err_msg); } else { assert!(false); @@ -1016,7 +1016,7 @@ mod test { // Test refcount overflow. let ret = refcount.set_refcount(0, 0, 1, 65535, &Qcow2DiscardType::Never); if let Err(err) = ret { - let err_msg = format!("Refcount 2 add 65535 cause overflows, index is 0"); + let err_msg = "Refcount 2 add 65535 cause overflows, index is 0".to_string(); assert_eq!(err.to_string(), err_msg); } else { assert!(false); @@ -1025,7 +1025,7 @@ mod test { // Test refcount underflow. let ret = refcount.set_refcount(0, 0, 1, -65535, &Qcow2DiscardType::Never); if let Err(err) = ret { - let err_msg = format!("Refcount 2 sub 65535 cause overflows, index is 0"); + let err_msg = "Refcount 2 sub 65535 cause overflows, index is 0".to_string(); assert_eq!(err.to_string(), err_msg); } else { assert!(false); diff --git a/cpu/src/lib.rs b/cpu/src/lib.rs index 2690c1c2..b141334e 100644 --- a/cpu/src/lib.rs +++ b/cpu/src/lib.rs @@ -462,7 +462,7 @@ pub struct CPUThreadWorker { } impl CPUThreadWorker { - thread_local!(static LOCAL_THREAD_VCPU: RefCell> = RefCell::new(None)); + thread_local!(static LOCAL_THREAD_VCPU: RefCell> = const { RefCell::new(None) }); /// Allocates a new `CPUThreadWorker`. fn new(thread_cpu: Arc) -> Self { diff --git a/devices/src/acpi/power.rs b/devices/src/acpi/power.rs index 8f066a80..ae3d0bf6 100644 --- a/devices/src/acpi/power.rs +++ b/devices/src/acpi/power.rs @@ -385,7 +385,7 @@ impl AmlBuilder for PowerDev { acpi_acad_dev .aml_bytes() .into_iter() - .chain(acpi_bat_dev.aml_bytes().into_iter()) + .chain(acpi_bat_dev.aml_bytes()) .collect() } } diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs index 20ba952c..e2b64ff8 100644 --- a/devices/src/pci/mod.rs +++ b/devices/src/pci/mod.rs @@ -208,7 +208,8 @@ pub trait PciDevOps: Device + Send { /// Get the path of the PCI bus where the device resides. fn get_parent_dev_path(&self, parent_bus: Arc>) -> String { PCI_BUS!(parent_bus, locked_bus, pci_bus); - let parent_dev_path = if pci_bus.name().eq("pcie.0") { + + if pci_bus.name().eq("pcie.0") { String::from("/pci@ffffffffffffffff") } else { // This else branch will not be executed currently, @@ -217,8 +218,7 @@ pub trait PciDevOps: Device + Send { let parent_bridge = pci_bus.parent_device().unwrap().upgrade().unwrap(); ROOT_PORT!(parent_bridge, locked_bridge, rootport); rootport.get_dev_path().unwrap() - }; - parent_dev_path + } } /// Fill the device path according to parent device path and device function. diff --git a/devices/src/usb/mod.rs b/devices/src/usb/mod.rs index f5c14996..5ddaef9e 100644 --- a/devices/src/usb/mod.rs +++ b/devices/src/usb/mod.rs @@ -237,7 +237,7 @@ impl UsbDeviceBase { .as_ref() .with_context(|| "Device descriptor not found")?; desc.configs - .get(0) + .first() .with_context(|| "Config descriptor not found")? .clone() }; diff --git a/hypervisor/src/kvm/interrupt.rs b/hypervisor/src/kvm/interrupt.rs index ea9e7790..6a9f8f8f 100644 --- a/hypervisor/src/kvm/interrupt.rs +++ b/hypervisor/src/kvm/interrupt.rs @@ -236,7 +236,7 @@ mod tests { #[test] fn test_get_maximum_gsi_cnt() { - let kvm_hyp = KvmHypervisor::new().unwrap_or(KvmHypervisor::default()); + let kvm_hyp = KvmHypervisor::new().unwrap_or_default(); if kvm_hyp.vm_fd.is_none() { return; } @@ -245,11 +245,11 @@ mod tests { #[test] fn test_alloc_and_release_gsi() { - let kvm_hyp = KvmHypervisor::new().unwrap_or(KvmHypervisor::default()); + let kvm_hyp = KvmHypervisor::new().unwrap_or_default(); if kvm_hyp.vm_fd.is_none() { return; } - let irq_route_table = Mutex::new(IrqRouteTable::new(&kvm_hyp.fd.as_ref().unwrap())); + let irq_route_table = Mutex::new(IrqRouteTable::new(kvm_hyp.fd.as_ref().unwrap())); let irq_manager = Arc::new(KVMInterruptManager::new( true, kvm_hyp.vm_fd.clone().unwrap(), diff --git a/hypervisor/src/kvm/listener.rs b/hypervisor/src/kvm/listener.rs index 713b7238..aab93039 100644 --- a/hypervisor/src/kvm/listener.rs +++ b/hypervisor/src/kvm/listener.rs @@ -628,7 +628,7 @@ mod test { #[test] fn test_alloc_slot() { - let kvm_hyp = KvmHypervisor::new().unwrap_or(KvmHypervisor::default()); + let kvm_hyp = KvmHypervisor::new().unwrap_or_default(); if kvm_hyp.vm_fd.is_none() { return; } @@ -652,7 +652,7 @@ mod test { #[test] fn test_add_del_ram_region() { - let kvm_hyp = KvmHypervisor::new().unwrap_or(KvmHypervisor::default()); + let kvm_hyp = KvmHypervisor::new().unwrap_or_default(); if kvm_hyp.vm_fd.is_none() { return; } @@ -678,7 +678,7 @@ mod test { #[test] fn test_add_region_align() { - let kvm_hyp = KvmHypervisor::new().unwrap_or(KvmHypervisor::default()); + let kvm_hyp = KvmHypervisor::new().unwrap_or_default(); if kvm_hyp.vm_fd.is_none() { return; } @@ -700,7 +700,7 @@ mod test { #[test] fn test_add_del_ioeventfd() { - let kvm_hyp = KvmHypervisor::new().unwrap_or(KvmHypervisor::default()); + let kvm_hyp = KvmHypervisor::new().unwrap_or_default(); if kvm_hyp.vm_fd.is_none() { return; } @@ -746,7 +746,7 @@ mod test { #[test] fn test_ioeventfd_with_data_match() { - let kvm_hyp = KvmHypervisor::new().unwrap_or(KvmHypervisor::default()); + let kvm_hyp = KvmHypervisor::new().unwrap_or_default(); if kvm_hyp.vm_fd.is_none() { return; } @@ -767,7 +767,7 @@ mod test { // Delete ioeventfd with wrong address will cause an error. let mut evtfd_to_del = evtfd.clone(); - evtfd_to_del.addr_range.base.0 = evtfd_to_del.addr_range.base.0 - 2; + evtfd_to_del.addr_range.base.0 -= 2; assert!(kml .handle_request(None, Some(&evtfd_to_del), ListenerReqType::DeleteIoeventfd) .is_err()); @@ -800,7 +800,7 @@ mod test { #[test] #[cfg(target_arch = "x86_64")] fn test_kvm_io_listener() { - let kvm_hyp = KvmHypervisor::new().unwrap_or(KvmHypervisor::default()); + let kvm_hyp = KvmHypervisor::new().unwrap_or_default(); if kvm_hyp.vm_fd.is_none() { return; } diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs index 9dca1743..e57ad943 100644 --- a/hypervisor/src/kvm/mod.rs +++ b/hypervisor/src/kvm/mod.rs @@ -1005,7 +1005,7 @@ mod test { #[cfg(target_arch = "x86_64")] #[test] fn test_x86_64_kvm_cpu() { - let kvm_hyp = KvmHypervisor::new().unwrap_or(KvmHypervisor::default()); + let kvm_hyp = KvmHypervisor::new().unwrap_or_default(); if kvm_hyp.vm_fd.is_none() { return; } @@ -1113,7 +1113,7 @@ mod test { #[test] #[allow(unused)] fn test_cpu_lifecycle_with_kvm() { - let kvm_hyp = KvmHypervisor::new().unwrap_or(KvmHypervisor::default()); + let kvm_hyp = KvmHypervisor::new().unwrap_or_default(); if kvm_hyp.vm_fd.is_none() { return; } diff --git a/image/src/cmdline.rs b/image/src/cmdline.rs index 8235ff5d..c991366c 100644 --- a/image/src/cmdline.rs +++ b/image/src/cmdline.rs @@ -162,20 +162,16 @@ mod test { fn test_arg_parse() { let mut arg_parser = ArgsParse::create(vec!["q", "h", "help"], vec!["f"], vec!["o"]); let cmd_line = "-f qcow2 -q -h --help -o cluster_size=512 -o refcount_bits=16 img_path +1G"; - let cmd_args: Vec = cmd_line - .split(' ') - .into_iter() - .map(|str| str.to_string()) - .collect(); + let cmd_args: Vec = cmd_line.split(' ').map(|str| str.to_string()).collect(); let ret = arg_parser.parse(cmd_args); println!("{:?}", ret); assert!(ret.is_ok()); - assert_eq!(arg_parser.opt_present("f"), true); - assert_eq!(arg_parser.opt_present("q"), true); - assert_eq!(arg_parser.opt_present("h"), true); - assert_eq!(arg_parser.opt_present("help"), true); + assert!(arg_parser.opt_present("f")); + assert!(arg_parser.opt_present("q")); + assert!(arg_parser.opt_present("h")); + assert!(arg_parser.opt_present("help")); let values = arg_parser.opt_strs("o"); assert!(values.contains(&"cluster_size=512".to_string())); diff --git a/image/src/img.rs b/image/src/img.rs index fcfebffb..3e359a3f 100644 --- a/image/src/img.rs +++ b/image/src/img.rs @@ -86,7 +86,7 @@ impl ImageFile { detect_fmt: DiskFormat, ) -> Result { let real_fmt = match input_fmt { - Some(fmt) if fmt == DiskFormat::Raw => DiskFormat::Raw, + Some(DiskFormat::Raw) => DiskFormat::Raw, Some(fmt) => { if fmt != detect_fmt { bail!( @@ -588,11 +588,8 @@ mod test { "-f qcow2 -o cluster_size={} -o refcount_bits={} {} {}", cluster_size, refcount_bits, path, img_size, ); - let create_args: Vec = create_str - .split(' ') - .into_iter() - .map(|str| str.to_string()) - .collect(); + let create_args: Vec = + create_str.split(' ').map(|str| str.to_string()).collect(); assert!(image_create(create_args).is_ok()); // Read header. @@ -627,8 +624,8 @@ mod test { format: DiskFormat::Qcow2, ..Default::default() }; - let qcow2_driver = create_qcow2_driver_for_check(file, conf).unwrap(); - qcow2_driver + + create_qcow2_driver_for_check(file, conf).unwrap() } fn read_data(&self, guest_offset: u64, buf: &Vec) -> Result<()> { @@ -694,11 +691,8 @@ mod test { impl TestRawImage { fn create(path: String, img_size: String) -> Self { let create_str = format!("-f raw {} {}", path, img_size); - let create_args: Vec = create_str - .split(' ') - .into_iter() - .map(|str| str.to_string()) - .collect(); + let create_args: Vec = + create_str.split(' ').map(|str| str.to_string()).collect(); assert!(image_create(create_args).is_ok()); Self { path } @@ -710,8 +704,8 @@ mod test { let aio = Aio::new(Arc::new(SyncAioInfo::complete_func), AioEngine::Off, None).unwrap(); let file = open_file(&self.path, false, false).unwrap(); - let raw_driver = RawDriver::new(Arc::new(file), aio, conf); - raw_driver + + RawDriver::new(Arc::new(file), aio, conf) } } @@ -801,11 +795,8 @@ mod test { for case in test_case { let create_str = case.0.replace("img_path", path); println!("Create options: {}", create_str); - let create_args: Vec = create_str - .split(' ') - .into_iter() - .map(|str| str.to_string()) - .collect(); + let create_args: Vec = + create_str.split(' ').map(|str| str.to_string()).collect(); if case.1 { assert!(image_create(create_args).is_ok()); @@ -836,11 +827,7 @@ mod test { for case in test_case { let cmd_str = case.0.replace("img_path", path); - let args: Vec = cmd_str - .split(' ') - .into_iter() - .map(|str| str.to_string()) - .collect(); + let args: Vec = cmd_str.split(' ').map(|str| str.to_string()).collect(); // Query image info with type of qcow2. assert!(image_create(vec![ @@ -908,7 +895,7 @@ mod test { assert_eq!(test_image.header.size, image_size); // Check refcount. - assert_eq!(test_image.check_image(false, 0), true); + assert!(test_image.check_image(false, 0)); } } @@ -928,20 +915,13 @@ mod test { ("-f qcow2 path +1G", DiskFormat::Qcow2), ]; let check_str = format!("-f raw {}", path); - let check_args: Vec = check_str - .split(' ') - .into_iter() - .map(|str| str.to_string()) - .collect(); + let check_args: Vec = check_str.split(' ').map(|str| str.to_string()).collect(); for case in test_case { let create_str = case.0.replace("path", path); println!("stratovirt-img {}", create_str); - let create_args: Vec = create_str - .split(' ') - .into_iter() - .map(|str| str.to_string()) - .collect(); + let create_args: Vec = + create_str.split(' ').map(|str| str.to_string()).collect(); assert!(image_create(create_args).is_ok()); let image_file = ImageFile::create(path, false).unwrap(); @@ -981,18 +961,13 @@ mod test { let create_string = create_str.replace("disk_fmt", case.0); let create_args: Vec = create_string .split(' ') - .into_iter() .map(|str| str.to_string()) .collect(); println!("Create args: {}", create_string); assert!(image_create(create_args.clone()).is_ok()); let check_str = case.1.replace("img_path", path); - let check_args: Vec = check_str - .split(' ') - .into_iter() - .map(|str| str.to_string()) - .collect(); + let check_args: Vec = check_str.split(' ').map(|str| str.to_string()).collect(); println!("Check args: {}", check_str); if case.2 { @@ -1254,7 +1229,7 @@ mod test { let l2_idx = qcow2_driver.table.get_l2_table_index(guest_offset) as usize; let cache_entry = qcow2_driver.get_table_cluster(guest_offset).unwrap(); let mut l2_entry = cache_entry.borrow_mut().get_entry_map(l2_idx).unwrap(); - l2_entry = l2_entry & !QCOW2_OFFSET_COPIED; + l2_entry &= !QCOW2_OFFSET_COPIED; assert!(cache_entry .borrow_mut() .set_entry_map(l2_idx, l2_entry) @@ -1605,18 +1580,14 @@ mod test { let create_string = create_str.replace("disk_fmt", case.0); let create_args: Vec = create_string .split(' ') - .into_iter() .map(|str| str.to_string()) .collect(); println!("Create args: {}", create_string); assert!(image_create(create_args).is_ok()); let snapshot_str = case.1.replace("img_path", path); - let snapshot_args: Vec = snapshot_str - .split(' ') - .into_iter() - .map(|str| str.to_string()) - .collect(); + let snapshot_args: Vec = + snapshot_str.split(' ').map(|str| str.to_string()).collect(); let ret = image_snapshot(snapshot_args); if case.2 { assert!(ret.is_ok()); @@ -1648,10 +1619,10 @@ mod test { let quite = false; let fix = FIX_ERRORS | FIX_LEAKS; - assert_eq!(test_image.check_image(quite, fix), true); + assert!(test_image.check_image(quite, fix)); let buf = vec![1_u8; cluster_size as usize]; assert!(test_image.write_data(0, &buf).is_ok()); - assert_eq!(test_image.check_image(quite, fix), true); + assert!(test_image.check_image(quite, fix)); // Create a snapshot named test_snapshot0 assert!(image_snapshot(vec![ @@ -1661,10 +1632,10 @@ mod test { ]) .is_ok()); - assert_eq!(test_image.check_image(quite, fix), true); + assert!(test_image.check_image(quite, fix)); let buf = vec![2_u8; cluster_size as usize]; assert!(test_image.write_data(0, &buf).is_ok()); - assert_eq!(test_image.check_image(quite, fix), true); + assert!(test_image.check_image(quite, fix)); // Create as snapshot named test_snapshot1. assert!(image_snapshot(vec![ @@ -1674,10 +1645,10 @@ mod test { ]) .is_ok()); - assert_eq!(test_image.check_image(quite, fix), true); + assert!(test_image.check_image(quite, fix)); let buf = vec![3_u8; cluster_size as usize]; assert!(test_image.write_data(0, &buf).is_ok()); - assert_eq!(test_image.check_image(quite, fix), true); + assert!(test_image.check_image(quite, fix)); // Apply snapshot named test_snapshot0. assert!(image_snapshot(vec![ @@ -1687,7 +1658,7 @@ mod test { ]) .is_ok()); - assert_eq!(test_image.check_image(quite, fix), true); + assert!(test_image.check_image(quite, fix)); let buf = vec![0_u8; cluster_size as usize]; assert!(test_image.read_data(0, &buf).is_ok()); for elem in buf { @@ -1695,7 +1666,7 @@ mod test { } let buf = vec![4_u8; cluster_size as usize]; assert!(test_image.write_data(0, &buf).is_ok()); - assert_eq!(test_image.check_image(quite, fix), true); + assert!(test_image.check_image(quite, fix)); // Apply snapshot named test_snapshot1 assert!(image_snapshot(vec![ @@ -1704,7 +1675,7 @@ mod test { path.to_string() ]) .is_ok()); - assert_eq!(test_image.check_image(quite, fix), true); + assert!(test_image.check_image(quite, fix)); let buf = vec![0_u8; cluster_size as usize]; assert!(test_image.read_data(0, &buf).is_ok()); for elem in buf { @@ -1754,14 +1725,10 @@ mod test { // Apply resize operation. let cmd = cmd.replace("img_path", path); - let args: Vec = cmd - .split(' ') - .into_iter() - .map(|str| str.to_string()) - .collect(); + let args: Vec = cmd.split(' ').map(|str| str.to_string()).collect(); assert_eq!(image_resize(args).is_ok(), res); - assert!(remove_file(path.to_string()).is_ok()); + assert!(remove_file(path).is_ok()); } } @@ -1788,7 +1755,7 @@ mod test { let buf = vec![1; 10240]; let mut driver = test_image.create_driver(); while offset < 10 * M as usize { - assert!(image_write(&mut driver, offset as usize, &buf).is_ok()); + assert!(image_write(&mut driver, offset, &buf).is_ok()); offset += 10240; } drop(driver); @@ -1806,7 +1773,7 @@ mod test { let buf = vec![2; 10240]; let mut driver = test_image.create_driver(); while offset < (10 + 10) * M as usize { - assert!(image_write(&mut driver, offset as usize, &buf).is_ok()); + assert!(image_write(&mut driver, offset, &buf).is_ok()); offset += 10240; } @@ -1903,7 +1870,7 @@ mod test { let mut driver = test_image.create_driver(); let buf = vec![1; 1024 * 1024]; assert!(image_write(&mut driver, 0, &buf).is_ok()); - assert_eq!(driver.header.size, 1 * G); + assert_eq!(driver.header.size, G); drop(driver); let quite = false; let fix = FIX_ERRORS | FIX_LEAKS; @@ -1914,13 +1881,13 @@ mod test { path.to_string() ]) .is_ok()); - assert_eq!(test_image.check_image(quite, fix), true); + assert!(test_image.check_image(quite, fix)); let mut driver = test_image.create_driver(); let buf = vec![2; 1024 * 1024]; assert!(image_write(&mut driver, 0, &buf).is_ok()); - assert_eq!(driver.header.size, 1 * G); + assert_eq!(driver.header.size, G); drop(driver); - assert_eq!(test_image.check_image(quite, fix), true); + assert!(test_image.check_image(quite, fix)); assert!(image_resize(vec![ "-f".to_string(), @@ -1929,7 +1896,7 @@ mod test { "+20G".to_string(), ]) .is_ok()); - assert_eq!(test_image.check_image(quite, fix), true); + assert!(test_image.check_image(quite, fix)); let mut driver = test_image.create_driver(); let buf = vec![3; 1024 * 1024]; assert!(image_write(&mut driver, 20 * G as usize, &buf).is_ok()); @@ -1938,7 +1905,7 @@ mod test { assert!(vec_is_fill_with(&buf, 2)); assert_eq!(driver.header.size, 21 * G); drop(driver); - assert_eq!(test_image.check_image(quite, fix), true); + assert!(test_image.check_image(quite, fix)); assert!(image_snapshot(vec![ "-c".to_string(), @@ -1946,13 +1913,13 @@ mod test { path.to_string() ]) .is_ok()); - assert_eq!(test_image.check_image(quite, fix), true); + assert!(test_image.check_image(quite, fix)); let mut driver = test_image.create_driver(); let buf = vec![4; 1024 * 1024]; assert!(image_write(&mut driver, 20 * G as usize, &buf).is_ok()); assert_eq!(driver.header.size, 21 * G); drop(driver); - assert_eq!(test_image.check_image(quite, fix), true); + assert!(test_image.check_image(quite, fix)); assert!(image_resize(vec![ "-f".to_string(), @@ -1961,7 +1928,7 @@ mod test { "+10G".to_string(), ]) .is_ok()); - assert_eq!(test_image.check_image(quite, fix), true); + assert!(test_image.check_image(quite, fix)); let mut driver = test_image.create_driver(); let buf = vec![5; 1024 * 1024]; assert!(image_write(&mut driver, 30 * G as usize, &buf).is_ok()); @@ -1970,7 +1937,7 @@ mod test { assert!(vec_is_fill_with(&buf, 4)); assert_eq!(driver.header.size, 31 * G); drop(driver); - assert_eq!(test_image.check_image(quite, fix), true); + assert!(test_image.check_image(quite, fix)); assert!(image_snapshot(vec![ "-a".to_string(), @@ -1978,14 +1945,14 @@ mod test { path.to_string() ]) .is_ok()); - assert_eq!(test_image.check_image(quite, fix), true); + assert!(test_image.check_image(quite, fix)); let mut driver = test_image.create_driver(); let buf = vec![0; 1024 * 1024]; assert!(image_read(&mut driver, 0, &buf).is_ok()); assert!(vec_is_fill_with(&buf, 1)); - assert_eq!(driver.header.size, 1 * G); + assert_eq!(driver.header.size, G); drop(driver); - assert_eq!(test_image.check_image(quite, fix), true); + assert!(test_image.check_image(quite, fix)); assert!(image_snapshot(vec![ "-a".to_string(), @@ -1993,13 +1960,13 @@ mod test { path.to_string() ]) .is_ok()); - assert_eq!(test_image.check_image(quite, fix), true); + assert!(test_image.check_image(quite, fix)); let mut driver = test_image.create_driver(); let buf = vec![0; 1024 * 1024]; assert!(image_read(&mut driver, 20 * G as usize, &buf).is_ok()); assert!(vec_is_fill_with(&buf, 3)); assert_eq!(driver.header.size, 21 * G); drop(driver); - assert_eq!(test_image.check_image(quite, fix), true); + assert!(test_image.check_image(quite, fix)); } } diff --git a/machine_manager/src/config/boot_source.rs b/machine_manager/src/config/boot_source.rs index 6f7c227a..997b8410 100644 --- a/machine_manager/src/config/boot_source.rs +++ b/machine_manager/src/config/boot_source.rs @@ -239,8 +239,8 @@ mod tests { test_kernel_param.push(Param::from_str("maxcpus=8")); assert_eq!(test_kernel_param.params.len(), 6); - assert_eq!(test_kernel_param.contains("maxcpus"), true); - assert_eq!(test_kernel_param.contains("cpus"), false); + assert!(test_kernel_param.contains("maxcpus")); + assert!(!test_kernel_param.contains("cpus")); assert_eq!( test_kernel_param.to_string(), "reboot=k panic=1 pci=off nomodules 8250.nr_uarts=0 maxcpus=8" @@ -257,7 +257,7 @@ mod tests { initrd_file.set_len(100_u64).unwrap(); let mut vm_config = VmConfig::default(); assert!(vm_config.add_kernel(&kernel_path).is_ok()); - vm_config.add_kernel_cmdline(&vec![ + vm_config.add_kernel_cmdline(&[ String::from("console=ttyS0"), String::from("reboot=k"), String::from("panic=1"), diff --git a/machine_manager/src/config/camera.rs b/machine_manager/src/config/camera.rs index 43af312c..b3964f4f 100644 --- a/machine_manager/src/config/camera.rs +++ b/machine_manager/src/config/camera.rs @@ -93,10 +93,10 @@ impl VmConfig { } pub fn del_cameradev_by_id(&mut self, id: &str) -> Result<()> { - if self.camera_backend.get(&id.to_string()).is_none() { + if !self.camera_backend.contains_key(id) { bail!("no cameradev with id {}", id); } - self.camera_backend.remove(&id.to_string()); + self.camera_backend.remove(id); Ok(()) } diff --git a/machine_manager/src/config/chardev.rs b/machine_manager/src/config/chardev.rs index 0ea4d49b..1eb0d489 100644 --- a/machine_manager/src/config/chardev.rs +++ b/machine_manager/src/config/chardev.rs @@ -265,7 +265,7 @@ impl VmConfig { /// * `conf` - The chardev config to be added to the vm. pub fn add_chardev_with_config(&mut self, conf: ChardevConfig) -> Result<()> { let chardev_id = conf.id(); - if self.chardev.get(&chardev_id).is_some() { + if self.chardev.contains_key(&chardev_id) { bail!("Chardev {:?} has been added", chardev_id); } self.chardev.insert(chardev_id, conf); diff --git a/machine_manager/src/config/display.rs b/machine_manager/src/config/display.rs index 743a476c..7369e429 100644 --- a/machine_manager/src/config/display.rs +++ b/machine_manager/src/config/display.rs @@ -123,28 +123,28 @@ mod tests { assert!(vm_config.add_display(config_line).is_ok()); let display_config = vm_config.display.unwrap(); assert_eq!(display_config.display_type, "gtk"); - assert_eq!(display_config.full_screen, false); + assert!(!display_config.full_screen); let mut vm_config = VmConfig::default(); let config_line = "gtk,full-screen=on"; assert!(vm_config.add_display(config_line).is_ok()); let display_config = vm_config.display.unwrap(); assert_eq!(display_config.display_type, "gtk"); - assert_eq!(display_config.full_screen, true); + assert!(display_config.full_screen); let mut vm_config = VmConfig::default(); let config_line = "gtk,full-screen=off"; assert!(vm_config.add_display(config_line).is_ok()); let display_config = vm_config.display.unwrap(); assert_eq!(display_config.display_type, "gtk"); - assert_eq!(display_config.full_screen, false); + assert!(!display_config.full_screen); let mut vm_config = VmConfig::default(); let config_line = "gtk,app-name=desktopappengine"; assert!(vm_config.add_display(config_line).is_ok()); let display_config = vm_config.display.unwrap(); assert_eq!(display_config.display_type, "gtk"); - assert_eq!(display_config.full_screen, false); + assert!(!display_config.full_screen); assert_eq!( display_config.app_name, Some("desktopappengine".to_string()) diff --git a/machine_manager/src/config/drive.rs b/machine_manager/src/config/drive.rs index a6f9fd75..a9a132eb 100644 --- a/machine_manager/src/config/drive.rs +++ b/machine_manager/src/config/drive.rs @@ -10,6 +10,7 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. +use std::fmt::Display; use std::fs::{metadata, File}; use std::os::linux::fs::MetadataExt; use std::path::Path; @@ -79,11 +80,11 @@ impl FromStr for DiskFormat { } } -impl ToString for DiskFormat { - fn to_string(&self) -> String { - match *self { - DiskFormat::Raw => "raw".to_string(), - DiskFormat::Qcow2 => "qcow2".to_string(), +impl Display for DiskFormat { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + DiskFormat::Raw => write!(f, "raw"), + DiskFormat::Qcow2 => write!(f, "qcow2"), } } } @@ -291,7 +292,7 @@ impl VmConfig { /// * `drive_conf` - The drive config to be added to the vm. pub fn add_drive_with_config(&mut self, drive_conf: DriveConfig) -> Result<()> { let drive_id = drive_conf.id.clone(); - if self.drives.get(&drive_id).is_some() { + if self.drives.contains_key(&drive_id) { bail!("Drive {} has been added", drive_id); } self.drives.insert(drive_id, drive_conf); @@ -304,7 +305,7 @@ impl VmConfig { /// /// * `drive_id` - Drive id. pub fn del_drive_by_id(&mut self, drive_id: &str) -> Result { - if self.drives.get(drive_id).is_some() { + if self.drives.contains_key(drive_id) { Ok(self.drives.remove(drive_id).unwrap().path_on_host) } else { bail!("Drive {} not found", drive_id); @@ -347,7 +348,7 @@ mod tests { let pflash_cfg = &pflash[0]; assert_eq!(pflash_cfg.unit.unwrap(), 0); assert_eq!(pflash_cfg.path_on_host, "flash0.fd".to_string()); - assert_eq!(pflash_cfg.readonly, true); + assert!(pflash_cfg.readonly); // Test2: Change parameters sequence. let mut vm_config = VmConfig::default(); @@ -376,11 +377,11 @@ mod tests { let pflash_cfg = &pflash[0]; assert_eq!(pflash_cfg.unit.unwrap(), 0); assert_eq!(pflash_cfg.path_on_host, "flash0.fd".to_string()); - assert_eq!(pflash_cfg.readonly, true); + assert!(pflash_cfg.readonly); let pflash_cfg = &pflash[1]; assert_eq!(pflash_cfg.unit.unwrap(), 1); assert_eq!(pflash_cfg.path_on_host, "flash1.fd".to_string()); - assert_eq!(pflash_cfg.readonly, false); + assert!(!pflash_cfg.readonly); // Test4: Illegal parameters unit/format. let mut vm_config = VmConfig::default(); @@ -412,10 +413,10 @@ mod tests { assert_eq!(drive_cfg.id, "rootfs"); assert_eq!(drive_cfg.path_on_host, "/path/to/rootfs"); assert_eq!(drive_cfg.format.to_string(), "qcow2"); - assert_eq!(drive_cfg.readonly, false); - assert_eq!(drive_cfg.direct, true); + assert!(!drive_cfg.readonly); + assert!(drive_cfg.direct); assert_eq!(drive_cfg.iops.unwrap(), 200); - assert_eq!(drive_cfg.discard, true); + assert!(drive_cfg.discard); assert_eq!( drive_cfg.write_zeroes, WriteZeroesState::from_str("unmap").unwrap() @@ -502,7 +503,7 @@ mod tests { let mut drive_conf = DriveConfig::default(); drive_conf.id = String::from(*id); assert!(vm_config.drives.get(*id).is_some()); - assert!(vm_config.del_drive_by_id(*id).is_ok()); + assert!(vm_config.del_drive_by_id(id).is_ok()); assert!(vm_config.drives.get(*id).is_none()); } } @@ -513,19 +514,19 @@ mod tests { let drive_conf = vm_config .add_drive("id=rootfs,file=/path/to/rootfs,discard=ignore") .unwrap(); - assert_eq!(drive_conf.discard, false); + assert!(!drive_conf.discard); let mut vm_config = VmConfig::default(); let drive_conf = vm_config .add_drive("id=rootfs,file=/path/to/rootfs,discard=unmap") .unwrap(); - assert_eq!(drive_conf.discard, true); + assert!(drive_conf.discard); let mut vm_config = VmConfig::default(); let ret = vm_config .add_drive("id=rootfs,file=/path/to/rootfs,discard=invalid") .is_err(); - assert_eq!(ret, true); + assert!(ret); } #[test] @@ -552,6 +553,6 @@ mod tests { let ret = vm_config .add_drive("id=rootfs,file=/path/to/rootfs,detect-zeroes=invalid") .is_err(); - assert_eq!(ret, true); + assert!(ret); } } diff --git a/machine_manager/src/config/machine_config.rs b/machine_manager/src/config/machine_config.rs index 05c428e6..6163f111 100644 --- a/machine_manager/src/config/machine_config.rs +++ b/machine_manager/src/config/machine_config.rs @@ -481,7 +481,7 @@ impl VmConfig { bail!("Object type: {} config path err", zone_config.mem_type); } - if self.object.mem_object.get(&zone_config.id).is_some() { + if self.object.mem_object.contains_key(&zone_config.id) { bail!("Object: {} has been added", zone_config.id); } self.object @@ -632,9 +632,9 @@ mod tests { machine_config.nr_cpus = MIN_NR_CPUS as u8; machine_config.mem_config.mem_size = MIN_MEMSIZE - 1; - assert!(!machine_config.check().is_ok()); + assert!(machine_config.check().is_err()); machine_config.mem_config.mem_size = MAX_MEMSIZE + 1; - assert!(!machine_config.check().is_ok()); + assert!(machine_config.check().is_err()); machine_config.mem_config.mem_size = MIN_MEMSIZE; assert!(machine_config.check().is_ok()); @@ -831,8 +831,8 @@ mod tests { assert!(machine_cfg_ret.is_ok()); let machine_cfg = vm_config.machine_config; assert_eq!(machine_cfg.mach_type, MachineType::None); - assert_eq!(machine_cfg.mem_config.dump_guest_core, true); - assert_eq!(machine_cfg.mem_config.mem_share, true); + assert!(machine_cfg.mem_config.dump_guest_core); + assert!(machine_cfg.mem_config.mem_share); let mut vm_config = VmConfig::default(); let memory_cfg_str = "none,dump-guest-core=off,mem-share=off,accel=kvm,usb=off"; @@ -841,8 +841,8 @@ mod tests { let machine_cfg = vm_config.machine_config; assert_eq!(machine_cfg.mach_type, MachineType::None); assert_eq!(machine_cfg.hypervisor, HypervisorType::Kvm); - assert_eq!(machine_cfg.mem_config.dump_guest_core, false); - assert_eq!(machine_cfg.mem_config.mem_share, false); + assert!(!machine_cfg.mem_config.dump_guest_core); + assert!(!machine_cfg.mem_config.mem_share); let mut vm_config = VmConfig::default(); let memory_cfg_str = "type=none,accel=kvm-tcg"; @@ -903,10 +903,10 @@ mod tests { let mut vm_config = VmConfig::default(); let mem_prealloc = vm_config.machine_config.mem_config.mem_prealloc; // default value is false. - assert_eq!(mem_prealloc, false); + assert!(!mem_prealloc); vm_config.enable_mem_prealloc(); let mem_prealloc = vm_config.machine_config.mem_config.mem_prealloc; - assert_eq!(mem_prealloc, true); + assert!(mem_prealloc); } #[test] @@ -961,18 +961,18 @@ mod tests { .add_mem_zone("memory-backend-ram,size=2M,id=mem3,share=on") .unwrap(); assert_eq!(zone_config_3.size, 2 * 1024 * 1024); - assert_eq!(zone_config_3.share, true); + assert!(zone_config_3.share); let zone_config_4 = vm_config .add_mem_zone("memory-backend-ram,size=2M,id=mem4") .unwrap(); - assert_eq!(zone_config_4.share, false); - assert_eq!(zone_config_4.memfd(), false); + assert!(!zone_config_4.share); + assert!(!zone_config_4.memfd()); let zone_config_5 = vm_config .add_mem_zone("memory-backend-memfd,size=2M,id=mem5") .unwrap(); - assert_eq!(zone_config_5.memfd(), true); + assert!(zone_config_5.memfd()); } #[test] diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index 2aff9801..ce4c313b 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -39,7 +39,6 @@ pub use boot_source::*; #[cfg(feature = "usb_camera")] pub use camera::*; pub use chardev::*; -pub use devices::*; #[cfg(any(feature = "gtk", feature = "ohui_srv"))] pub use display::*; pub use drive::*; @@ -217,7 +216,7 @@ impl VmConfig { let rng_cfg = RngObjConfig::try_parse_from(str_slip_to_clap(object_args, true, false))?; let id = rng_cfg.id.clone(); - if self.object.rng_object.get(&id).is_some() { + if self.object.rng_object.contains_key(&id) { bail!("Object: {} has been added", id); } self.object.rng_object.insert(id, rng_cfg); @@ -252,7 +251,7 @@ impl VmConfig { if let Some(fast_unplug_value) = global_config.fast_unplug { let fast_unplug_key = String::from("pcie-root-port.fast-unplug"); - if self.global_config.get(&fast_unplug_key).is_some() { + if self.global_config.contains_key(&fast_unplug_key) { bail!("Global config {} has been added", fast_unplug_key); } self.global_config diff --git a/machine_manager/src/config/network.rs b/machine_manager/src/config/network.rs index 7b02a4c9..30f1ec80 100644 --- a/machine_manager/src/config/network.rs +++ b/machine_manager/src/config/network.rs @@ -189,10 +189,10 @@ impl NetworkInterfaceConfig { pub fn auto_iothread(&mut self) { // If rx_iothread or tx_iothread is not configured, the default iothread will be used. if self.rx_iothread.is_none() { - self.rx_iothread = self.iothread.clone(); + self.rx_iothread.clone_from(&self.iothread); } if self.tx_iothread.is_none() { - self.tx_iothread = self.iothread.clone(); + self.tx_iothread.clone_from(&self.iothread); } } } @@ -317,7 +317,7 @@ impl VmConfig { pub fn add_netdev_with_config(&mut self, conf: NetDevcfg) -> Result<()> { let netdev_id = conf.id.clone(); - if self.netdevs.get(&netdev_id).is_some() { + if self.netdevs.contains_key(&netdev_id) { bail!("Netdev {:?} has been added", netdev_id); } self.netdevs.insert(netdev_id, conf); @@ -398,7 +398,7 @@ mod tests { assert_eq!(netdev_cfg.id, "eth0"); assert_eq!(netdev_cfg.ifname, "tap0"); assert!(netdev_cfg.tap_fds.is_none()); - assert_eq!(netdev_cfg.vhost_kernel, false); + assert!(!netdev_cfg.vhost_kernel); assert!(netdev_cfg.vhost_fds.is_none()); assert_eq!(netdev_cfg.queues, 2); assert!(netdev_cfg.vhost_type().is_none()); @@ -465,7 +465,7 @@ mod tests { assert_eq!(net_cfg.addr.unwrap(), (1, 2)); assert_eq!(net_cfg.mac.unwrap(), "12:34:56:78:9A:BC"); assert_eq!(net_cfg.vectors, 6); - assert_eq!(net_cfg.mq, true); + assert!(net_cfg.mq); assert_eq!(net_cfg.queue_size, 2048); assert_eq!(net_cfg.multifunction, Some(true)); let netdev_cfg = vm_config.netdevs.get(&net_cfg.netdev).unwrap(); @@ -479,7 +479,7 @@ mod tests { let net_cfg = NetworkInterfaceConfig::try_parse_from(str_slip_to_clap(net_cmd, true, false)).unwrap(); assert_eq!(net_cfg.queue_size, 256); - assert_eq!(net_cfg.mq, false); + assert!(!net_cfg.mq); assert_eq!(net_cfg.vectors, 0); let netdev_cfg = vm_config.netdevs.get(&net_cfg.netdev).unwrap(); assert_eq!(netdev_cfg.vhost_type().unwrap(), "vhost-user"); @@ -561,7 +561,7 @@ mod tests { let mut net_conf = NetDevcfg::default(); net_conf.id = String::from(*id); assert!(vm_config.netdevs.get(*id).is_some()); - assert!(vm_config.del_netdev_by_id(*id).is_ok()); + assert!(vm_config.del_netdev_by_id(id).is_ok()); assert!(vm_config.netdevs.get(*id).is_none()); } } @@ -664,7 +664,7 @@ mod tests { queues: Some(u16::MAX), ..qmp_schema::NetDevAddArgument::default() }); - check_err_msg(netdev, &err_msgs[0]); + check_err_msg(netdev, err_msgs[0]); // Abnornal test with invalid 'queues': MAX_QUEUE_PAIRS + 1. let netdev = Box::new(qmp_schema::NetDevAddArgument { @@ -683,7 +683,7 @@ mod tests { vhostfds: Some("21:22:23:24".to_string()), ..qmp_schema::NetDevAddArgument::default() }); - check_err_msg(netdev, &err_msgs[1]); + check_err_msg(netdev, err_msgs[1]); // Abnornal test with 'fds' and 'vhostfd'. let netdev = Box::new(qmp_schema::NetDevAddArgument { @@ -691,7 +691,7 @@ mod tests { vhostfd: Some("21".to_string()), ..qmp_schema::NetDevAddArgument::default() }); - check_err_msg(netdev, &err_msgs[2]); + check_err_msg(netdev, err_msgs[2]); // Abnornal test with different num of 'fds' and 'vhostfds'. let netdev = Box::new(qmp_schema::NetDevAddArgument { @@ -699,7 +699,7 @@ mod tests { vhostfds: Some("21:22:23".to_string()), ..qmp_schema::NetDevAddArgument::default() }); - check_err_msg(netdev, &err_msgs[3]); + check_err_msg(netdev, err_msgs[3]); // Abnornal test with 'net_type=vhost-user'. let netdev = Box::new(qmp_schema::NetDevAddArgument { @@ -709,7 +709,7 @@ mod tests { net_type: Some("vhost-user".to_string()), ..qmp_schema::NetDevAddArgument::default() }); - check_err_msg(netdev, &err_msgs[4]); + check_err_msg(netdev, err_msgs[4]); // Abnornal test with 'fds/vhostfds' and no 'vhost'. let netdev = Box::new(qmp_schema::NetDevAddArgument { @@ -717,13 +717,13 @@ mod tests { vhostfds: Some("21:22:23:24".to_string()), ..qmp_schema::NetDevAddArgument::default() }); - check_err_msg(netdev, &err_msgs[5]); + check_err_msg(netdev, err_msgs[5]); // Abnornal test with all default value. let netdev = Box::new(qmp_schema::NetDevAddArgument { ..qmp_schema::NetDevAddArgument::default() }); - check_err_msg(netdev, &err_msgs[6]); + check_err_msg(netdev, err_msgs[6]); // Abnornal test with invalid fd value. let netdev = Box::new(qmp_schema::NetDevAddArgument { diff --git a/machine_manager/src/config/numa.rs b/machine_manager/src/config/numa.rs index 664b1803..f628fef7 100644 --- a/machine_manager/src/config/numa.rs +++ b/machine_manager/src/config/numa.rs @@ -209,7 +209,7 @@ mod tests { .add_numa("node,nodeid=0,cpus=[0-1:3-5],memdev=mem0") .is_ok()); - let numa = vm_config.numa_nodes.get(0).unwrap(); + let numa = vm_config.numa_nodes.first().unwrap(); let numa_config = parse_numa_mem(numa.1.as_str()).unwrap(); assert_eq!(numa_config.cpus, vec![0, 1]); assert_eq!(numa_config.mem_dev, "mem0"); @@ -235,7 +235,7 @@ mod tests { assert!(vm_config.add_numa("dist,src=0,dst=1").is_ok()); assert!(vm_config.add_numa("dist,src=0,dst=1,val=10").is_ok()); - let numa = vm_config.numa_nodes.get(0).unwrap(); + let numa = vm_config.numa_nodes.first().unwrap(); let dist_cfg = parse_numa_distance(numa.1.as_str()).unwrap(); assert_eq!(dist_cfg.numa_id, 0); assert_eq!(dist_cfg.destination, 1); diff --git a/machine_manager/src/config/sasl_auth.rs b/machine_manager/src/config/sasl_auth.rs index 37b47bc7..f01699a1 100644 --- a/machine_manager/src/config/sasl_auth.rs +++ b/machine_manager/src/config/sasl_auth.rs @@ -33,7 +33,7 @@ impl VmConfig { let saslauth = SaslAuthObjConfig::try_parse_from(str_slip_to_clap(saslauth_config, true, false))?; let id = saslauth.id.clone(); - if self.object.sasl_object.get(&id).is_some() { + if self.object.sasl_object.contains_key(&id) { return Err(anyhow!(ConfigError::IdRepeat("saslauth".to_string(), id))); } self.object.sasl_object.insert(id, saslauth); @@ -62,7 +62,7 @@ mod tests { assert!(vm_config.add_object("authz-simple,id=authz0").is_ok()); assert!(vm_config.object.sasl_object.get(&id).is_some()); if let Some(obj_cfg) = vm_config.object.sasl_object.get(&id) { - assert!(obj_cfg.identity == "".to_string()); + assert!(obj_cfg.identity == *""); } } } diff --git a/machine_manager/src/config/tls_creds.rs b/machine_manager/src/config/tls_creds.rs index 92903161..a3b7396c 100644 --- a/machine_manager/src/config/tls_creds.rs +++ b/machine_manager/src/config/tls_creds.rs @@ -36,7 +36,7 @@ impl VmConfig { let tlscred = TlsCredObjConfig::try_parse_from(str_slip_to_clap(tlscred_config, true, false))?; let id = tlscred.id.clone(); - if self.object.tls_object.get(&id).is_some() { + if self.object.tls_object.contains_key(&id) { return Err(anyhow!(ConfigError::IdRepeat("tlscred".to_string(), id))); } self.object.tls_object.insert(id, tlscred); @@ -58,7 +58,7 @@ mod tests { if !dir.is_dir() { fs::create_dir(dir.clone()).unwrap(); } - assert_eq!(dir.is_dir(), true); + assert!(dir.is_dir()); // Certificate directory is exist. let tls_config: String = format!( @@ -72,12 +72,12 @@ mod tests { if let Some(tls_cred_cfg) = vm_config.object.tls_object.get(&id) { assert_eq!(tls_cred_cfg.dir, dir.to_str().unwrap()); assert_eq!(tls_cred_cfg.endpoint, Some("server".to_string())); - assert_eq!(tls_cred_cfg.verifypeer, false); + assert!(!tls_cred_cfg.verifypeer); } // Delete file. fs::remove_dir(dir.clone()).unwrap(); - assert_eq!(dir.is_dir(), false); + assert!(!dir.is_dir()); // Certificate directory does not exist. let mut vm_config = VmConfig::default(); assert!(vm_config.add_object(tls_config.as_str()).is_err()); diff --git a/machine_manager/src/config/vnc.rs b/machine_manager/src/config/vnc.rs index ca1fd104..f257ae07 100644 --- a/machine_manager/src/config/vnc.rs +++ b/machine_manager/src/config/vnc.rs @@ -86,14 +86,14 @@ mod tests { assert_eq!(vnc_config.addr.0, String::from("0.0.0.0")); assert_eq!(vnc_config.addr.1, 5901); assert_eq!(vnc_config.tls_creds, String::from("vnc-tls-creds0")); - assert_eq!(vnc_config.sasl, true); + assert!(vnc_config.sasl); assert_eq!(vnc_config.sasl_authz, String::from("authz0")); let mut vm_config = VmConfig::default(); let config_line = "0.0.0.0:5900,tls-creds=vnc-tls-creds0"; assert!(vm_config.add_vnc(config_line).is_ok()); let vnc_config = vm_config.vnc.unwrap(); - assert_eq!(vnc_config.sasl, false); + assert!(!vnc_config.sasl); assert_eq!(vnc_config.addr.1, 11800); let mut vm_config = VmConfig::default(); diff --git a/machine_manager/src/qmp/qmp_response.rs b/machine_manager/src/qmp/qmp_response.rs index 54fe538a..8db50f9a 100644 --- a/machine_manager/src/qmp/qmp_response.rs +++ b/machine_manager/src/qmp/qmp_response.rs @@ -226,7 +226,7 @@ mod tests { running: true, status: qmp_schema::RunState::running, }; - let resp = Response::create_response(serde_json::to_value(&resp_value).unwrap(), None); + let resp = Response::create_response(serde_json::to_value(resp_value).unwrap(), None); let json_msg = r#"{"return":{"running":true,"singlestep":false,"status":"running"}}"#; assert_eq!(serde_json::to_string(&resp).unwrap(), json_msg); diff --git a/machine_manager/src/qmp/qmp_schema.rs b/machine_manager/src/qmp/qmp_schema.rs index d520bd6a..ba43fc01 100644 --- a/machine_manager/src/qmp/qmp_schema.rs +++ b/machine_manager/src/qmp/qmp_schema.rs @@ -2010,7 +2010,7 @@ mod tests { fn test_qmp_event_msg() { let event_json = r#"{"event":"STOP","data":{},"timestamp":{"seconds":1575531524,"microseconds":91519}}"#; - let qmp_event: QmpEvent = serde_json::from_str(&event_json).unwrap(); + let qmp_event: QmpEvent = serde_json::from_str(event_json).unwrap(); match qmp_event { QmpEvent::Stop { data: _, diff --git a/machine_manager/src/qmp/qmp_socket.rs b/machine_manager/src/qmp/qmp_socket.rs index 24993aa2..d2ed4992 100644 --- a/machine_manager/src/qmp/qmp_socket.rs +++ b/machine_manager/src/qmp/qmp_socket.rs @@ -10,6 +10,7 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. +use std::fmt::Display; use std::net::IpAddr; use std::os::unix::io::{AsRawFd, RawFd}; use std::rc::Rc; @@ -62,13 +63,13 @@ impl QmpSocketPath { } } -impl ToString for QmpSocketPath { - fn to_string(&self) -> String { +impl Display for QmpSocketPath { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { QmpSocketPath::Tcp { host, port } => { - format!("{}:{}", &host, &port) + write!(f, "{}:{}", &host, &port) } - QmpSocketPath::Unix { path } => path.clone(), + QmpSocketPath::Unix { path } => write!(f, "{}", path), } } } @@ -591,7 +592,7 @@ mod tests { // Environment Recovery for UnixSocket fn recover_unix_socket_environment(socket_id: &str) { let socket_name: String = format!("test_{}.sock", socket_id); - std::fs::remove_file(&socket_name).unwrap(); + std::fs::remove_file(socket_name).unwrap(); } #[test] @@ -602,20 +603,20 @@ mod tests { // life cycle test // 1.Unconnected - assert_eq!(socket.is_connected(), false); + assert!(!socket.is_connected()); // 2.Connected socket.bind_stream(server); - assert_eq!(socket.is_connected(), true); + assert!(socket.is_connected()); // 3.Unbind SocketStream, reset state socket.drop_stream(); - assert_eq!(socket.is_connected(), false); + assert!(!socket.is_connected()); // 4.Accept and reconnect a new UnixStream let _new_client = UnixStream::connect("test_04.sock"); socket.accept(); - assert_eq!(socket.is_connected(), true); + assert!(socket.is_connected()); // After test. Environment Recover recover_unix_socket_environment("04"); @@ -663,7 +664,7 @@ mod tests { serde_json::from_str(&(String::from_utf8_lossy(&buffer[..length]))).unwrap(); match qmp_event { qmp_schema::QmpEvent::Shutdown { data, timestamp: _ } => { - assert_eq!(data.guest, true); + assert!(data.guest); assert_eq!(data.reason, "guest-shutdown".to_string()); } _ => assert!(false), @@ -692,7 +693,7 @@ mod tests { serde_json::from_str(&(String::from_utf8_lossy(&buffer[..length]))).unwrap(); let qmp_greeting = QmpGreeting::create_greeting(1, 0, 5); assert_eq!(qmp_greeting, qmp_response); - assert_eq!(res.is_err(), false); + assert!(res.is_ok()); // 2.send empty response let res = socket.send_response(false); @@ -701,7 +702,7 @@ mod tests { serde_json::from_str(&(String::from_utf8_lossy(&buffer[..length]))).unwrap(); let qmp_empty_response = Response::create_empty_response(); assert_eq!(qmp_empty_response, qmp_response); - assert_eq!(res.is_err(), false); + assert!(res.is_ok()); // After test. Environment Recover recover_unix_socket_environment("07"); diff --git a/machine_manager/src/socket.rs b/machine_manager/src/socket.rs index 4c083eb4..a2c0f336 100644 --- a/machine_manager/src/socket.rs +++ b/machine_manager/src/socket.rs @@ -406,7 +406,7 @@ mod tests { // Environment Recovery for UnixSocket fn recover_unix_socket_environment(socket_id: &str) { let socket_name: String = format!("test_{}.sock", socket_id); - std::fs::remove_file(&socket_name).unwrap(); + std::fs::remove_file(socket_name).unwrap(); } fn socket_basic_rw(client_fd: RawFd, server_fd: RawFd) -> bool { diff --git a/migration/src/protocol.rs b/migration/src/protocol.rs index b00e486f..ca8e23c2 100644 --- a/migration/src/protocol.rs +++ b/migration/src/protocol.rs @@ -920,12 +920,9 @@ pub mod tests { ); let mut current_slice = device_v1.get_state_vec().unwrap(); - assert_eq!( - state_2_desc - .add_padding(&state_1_desc, &mut current_slice) - .is_ok(), - true - ); + assert!(state_2_desc + .add_padding(&state_1_desc, &mut current_slice) + .is_ok()); let mut device_v2 = DeviceV2 { state: DeviceV2State::default(), @@ -964,12 +961,9 @@ pub mod tests { ); let mut current_slice = device_v2.get_state_vec().unwrap(); - assert_eq!( - state_3_desc - .add_padding(&state_2_desc, &mut current_slice) - .is_ok(), - true - ); + assert!(state_3_desc + .add_padding(&state_2_desc, &mut current_slice) + .is_ok()); let mut device_v3 = DeviceV3 { state: DeviceV3State::default(), @@ -1007,12 +1001,9 @@ pub mod tests { ); let mut current_slice = device_v3.get_state_vec().unwrap(); - assert_eq!( - state_4_desc - .add_padding(&state_3_desc, &mut current_slice) - .is_ok(), - true - ); + assert!(state_4_desc + .add_padding(&state_3_desc, &mut current_slice) + .is_ok()); let mut device_v4 = DeviceV4 { state: DeviceV4State::default(), @@ -1050,12 +1041,9 @@ pub mod tests { ); let mut current_slice = device_v4.get_state_vec().unwrap(); - assert_eq!( - state_5_desc - .add_padding(&state_4_desc, &mut current_slice) - .is_ok(), - true - ); + assert!(state_5_desc + .add_padding(&state_4_desc, &mut current_slice) + .is_ok()); let mut device_v5 = DeviceV5 { state: DeviceV5State::default(), @@ -1089,12 +1077,9 @@ pub mod tests { ); let mut current_slice = device_v2.get_state_vec().unwrap(); - assert_eq!( - state_5_desc - .add_padding(&state_2_desc, &mut current_slice) - .is_ok(), - true - ); + assert!(state_5_desc + .add_padding(&state_2_desc, &mut current_slice) + .is_ok()); let mut device_v5 = DeviceV5 { state: DeviceV5State::default(), @@ -1107,11 +1092,11 @@ pub mod tests { #[test] fn test_check_header() { - if !Kvm::new().is_ok() { + if Kvm::new().is_err() { return; } let header = MigrationHeader::default(); - assert_eq!(header.check_header().is_ok(), true); + assert!(header.check_header().is_ok()); } } diff --git a/src/main.rs b/src/main.rs index cff73cbe..c2e81909 100644 --- a/src/main.rs +++ b/src/main.rs @@ -180,11 +180,9 @@ fn real_main(cmd_args: &arg_parser::ArgMatches, vm_config: &mut VmConfig) -> Res if is_test_enabled() { let sock_path = cmd_args.value_of("mod-test"); - let test_sock = Some(TestSock::new(sock_path.unwrap().as_str(), vm.clone())); + let test_sock = TestSock::new(sock_path.unwrap().as_str(), vm.clone()); EventLoop::update_event( - EventNotifierHelper::internal_notifiers(Arc::new(Mutex::new( - test_sock.unwrap(), - ))), + EventNotifierHelper::internal_notifiers(Arc::new(Mutex::new(test_sock))), None, ) .with_context(|| "Failed to add test socket to MainLoop")?; @@ -211,7 +209,7 @@ fn real_main(cmd_args: &arg_parser::ArgMatches, vm_config: &mut VmConfig) -> Res } }; - let balloon_switch_on = vm_config.dev_name.get("balloon").is_some(); + let balloon_switch_on = vm_config.dev_name.contains_key("balloon"); if !cmd_args.is_present("disable-seccomp") { vm.lock() .unwrap() diff --git a/tests/mod_test/src/libdriver/pci.rs b/tests/mod_test/src/libdriver/pci.rs index 02fc6d92..1fc0ad10 100644 --- a/tests/mod_test/src/libdriver/pci.rs +++ b/tests/mod_test/src/libdriver/pci.rs @@ -334,21 +334,16 @@ impl TestPciDev { } pub fn io_map(&self, barnum: u8) -> u64 { - let addr: u32; - let size: u64; - let location: u64; - let bar_addr: PCIBarAddr; - assert!(barnum <= 5); let bar_offset: u8 = BAR_MAP[barnum as usize]; self.config_writel(bar_offset, 0xFFFFFFFF); - addr = self.config_readl(bar_offset) & !(0x0F_u32); + let addr: u32 = self.config_readl(bar_offset) & !(0x0F_u32); assert!(addr != 0); let mut pci_bus = self.pci_bus.borrow_mut(); - size = 1 << addr.trailing_zeros(); - location = (pci_bus.mmio_alloc_ptr + size - 1) / size * size; + let size: u64 = 1 << addr.trailing_zeros(); + let location: u64 = (pci_bus.mmio_alloc_ptr + size - 1) / size * size; if location < pci_bus.mmio_alloc_ptr || location + size > pci_bus.mmio_limit { return INVALID_BAR_ADDR; } @@ -356,7 +351,7 @@ impl TestPciDev { pci_bus.mmio_alloc_ptr = location + size; drop(pci_bus); self.config_writel(bar_offset, location as u32); - bar_addr = location; + let bar_addr: PCIBarAddr = location; bar_addr } diff --git a/tests/mod_test/src/libdriver/qcow2.rs b/tests/mod_test/src/libdriver/qcow2.rs index 86cc9c0c..61160a64 100644 --- a/tests/mod_test/src/libdriver/qcow2.rs +++ b/tests/mod_test/src/libdriver/qcow2.rs @@ -66,21 +66,21 @@ impl Qcow2Driver { fn raw_read(&self, offset: u64, buf: &mut [u8]) -> i64 { let ptr = buf.as_mut_ptr() as u64; let cnt = buf.len() as u64; - let iovec = vec![Iovec::new(ptr, cnt)]; - let ret = unsafe { + let iovec = [Iovec::new(ptr, cnt)]; + + unsafe { preadv( self.file.as_raw_fd() as c_int, iovec.as_ptr() as *const iovec, iovec.len() as c_int, offset as off_t, ) as i64 - }; - ret + } } fn raw_write(&mut self, offset: u64, buf: &mut [u8]) { self.file.seek(SeekFrom::Start(offset)).unwrap(); - self.file.write_all(&buf).unwrap(); + self.file.write_all(buf).unwrap(); } } @@ -192,12 +192,7 @@ impl QcowHeader { // From size to bits. fn size_to_bits(size: u64) -> Option { - for i in 0..63 { - if size >> i == 1 { - return Some(i); - } - } - return None; + (0..63).find(|&i| size >> i == 1) } /// Create a qcow2 format image for test. @@ -241,10 +236,10 @@ pub fn create_qcow2_img(image_path: String, image_size: u64) { file.write_all(&header.to_vec()).unwrap(); // Cluster 1 is the refcount table. - assert_eq!(header.refcount_table_offset, cluster_sz * 1); + assert_eq!(header.refcount_table_offset, cluster_sz); let mut refcount_table = [0_u8; ENTRY_SIZE as usize]; BigEndian::write_u64(&mut refcount_table, cluster_sz * 2); - file.seek(SeekFrom::Start(cluster_sz * 1)).unwrap(); + file.seek(SeekFrom::Start(cluster_sz)).unwrap(); file.write_all(&refcount_table).unwrap(); // Clusters which has been allocated. @@ -281,7 +276,7 @@ fn write_full_disk(image_path: String) { // Write l2 table. let mut refcount_block: Vec = Vec::new(); let mut l1_table = [0_u8; ENTRY_SIZE as usize]; - BigEndian::write_u64(&mut l1_table, cluster_size * 4 | QCOW2_OFFSET_COPIED); + BigEndian::write_u64(&mut l1_table, (cluster_size * 4) | QCOW2_OFFSET_COPIED); let mut l2_table: Vec = Vec::new(); for _ in 0..5 { refcount_block.push(0x00); @@ -318,7 +313,7 @@ pub fn delete_snapshot(state: Rc>, device: &str, snap: &str) pub fn query_snapshot(state: Rc>) -> Value { let qmp_str = - format!("{{\"execute\":\"human-monitor-command\",\"arguments\":{{\"command-line\":\"info snapshots\"}}}}"); + "{\"execute\":\"human-monitor-command\",\"arguments\":{\"command-line\":\"info snapshots\"}}".to_string(); let value = state.borrow_mut().qmp(&qmp_str); value diff --git a/tests/mod_test/src/libdriver/usb.rs b/tests/mod_test/src/libdriver/usb.rs index be1db39b..c3633b48 100644 --- a/tests/mod_test/src/libdriver/usb.rs +++ b/tests/mod_test/src/libdriver/usb.rs @@ -395,6 +395,12 @@ pub struct TestEventRingSegment { pub reserved: u32, } +impl Default for TestEventRingSegment { + fn default() -> Self { + Self::new() + } +} + impl TestEventRingSegment { pub fn new() -> Self { Self { @@ -503,21 +509,21 @@ impl TestXhciPciDevice { pub fn run(&mut self) { let status = self.pci_dev.io_readl( self.bar_addr, - u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_USBSTS as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_USBSTS, ); assert!(status & USB_STS_HCH == USB_STS_HCH); let cmd = self.pci_dev.io_readl( self.bar_addr, - u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_USBCMD as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_USBCMD, ); self.pci_dev.io_writel( self.bar_addr, - u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_USBCMD as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_USBCMD, cmd | USB_CMD_RUN, ); let status = self.pci_dev.io_readl( self.bar_addr, - u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_USBSTS as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_USBSTS, ); assert!(status & USB_STS_HCH != USB_STS_HCH); } @@ -627,7 +633,7 @@ impl TestXhciPciDevice { pub fn reset_controller(&mut self, auto_run: bool) { // reset xhci self.oper_regs_write(0, USB_CMD_HCRST); - let status = self.oper_regs_read(XHCI_OPER_REG_USBSTS as u64); + let status = self.oper_regs_read(XHCI_OPER_REG_USBSTS); assert!(status & USB_STS_HCE != USB_STS_HCE); if auto_run { self.init_host_controller(XHCI_PCI_SLOT_NUM, XHCI_PCI_FUN_NUM); @@ -699,14 +705,14 @@ impl TestXhciPciDevice { pub fn port_regs_read(&self, port_id: u32, offset: u64) -> u32 { self.pci_dev.io_readl( self.bar_addr, - u64::from(XHCI_PCI_PORT_OFFSET + XHCI_PCI_PORT_LENGTH * (port_id - 1) as u32) + offset, + u64::from(XHCI_PCI_PORT_OFFSET + XHCI_PCI_PORT_LENGTH * (port_id - 1)) + offset, ) } pub fn port_regs_write(&mut self, port_id: u32, offset: u64, value: u32) { self.pci_dev.io_writel( self.bar_addr, - u64::from(XHCI_PCI_PORT_OFFSET + XHCI_PCI_PORT_LENGTH * (port_id - 1) as u32) + offset, + u64::from(XHCI_PCI_PORT_OFFSET + XHCI_PCI_PORT_LENGTH * (port_id - 1)) + offset, value, ); } @@ -830,13 +836,13 @@ impl TestXhciPciDevice { let enabled_slot = USB_CONFIG_MAX_SLOTS_ENABLED & USB_CONFIG_MAX_SLOTS_EN_MASK; self.pci_dev.io_writel( self.bar_addr, - u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_CONFIG as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_CONFIG, enabled_slot, ); let config = self.pci_dev.io_readl( self.bar_addr, - u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_CONFIG as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_CONFIG, ); assert_eq!(config, enabled_slot); } @@ -846,13 +852,13 @@ impl TestXhciPciDevice { let dcbaap = self.allocator.borrow_mut().alloc(u64::from(dcba)); self.pci_dev.io_writeq( self.bar_addr, - u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_DCBAAP as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_DCBAAP, dcbaap, ); let value = self.pci_dev.io_readq( self.bar_addr, - u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_DCBAAP as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_DCBAAP, ); assert_eq!(value, dcbaap); self.xhci.dcbaap = value; @@ -870,13 +876,13 @@ impl TestXhciPciDevice { self.xhci.cmd_ring.init(cmd_ring, cmd_ring_sz); self.pci_dev.io_writeq( self.bar_addr, - u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_CMD_RING_CTRL as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_CMD_RING_CTRL, cmd_ring, ); // Read dequeue pointer return 0. let cmd_ring = self.pci_dev.io_readq( self.bar_addr, - u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_CMD_RING_CTRL as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_CMD_RING_CTRL, ); assert_eq!(cmd_ring, 0); } @@ -906,13 +912,9 @@ impl TestXhciPciDevice { pub fn reset_port(&mut self, port_id: u32) { assert!(port_id > 0); - let port_offset = - u64::from(XHCI_PCI_PORT_OFFSET + XHCI_PCI_PORT_LENGTH * (port_id - 1) as u32); - self.pci_dev.io_writel( - self.bar_addr, - port_offset + XHCI_PORTSC_OFFSET, - PORTSC_PR as u32, - ); + let port_offset = u64::from(XHCI_PCI_PORT_OFFSET + XHCI_PCI_PORT_LENGTH * (port_id - 1)); + self.pci_dev + .io_writel(self.bar_addr, port_offset + XHCI_PORTSC_OFFSET, PORTSC_PR); self.oper_regs_write(XHCI_OPER_REG_USBSTS, USB_STS_PCD); let status = self.oper_regs_read(XHCI_OPER_REG_USBSTS); assert!(status & USB_STS_PCD != USB_STS_PCD); @@ -1156,7 +1158,7 @@ impl TestXhciPciDevice { pub fn queue_device_request(&mut self, slot_id: u32, device_req: &UsbDeviceRequest) -> u64 { // Setup Stage. - let mut setup_trb = TestNormalTRB::generate_setup_td(&device_req); + let mut setup_trb = TestNormalTRB::generate_setup_td(device_req); self.queue_trb(slot_id, CONTROL_ENDPOINT_ID, &mut setup_trb); // Data Stage. let ptr = self @@ -1258,16 +1260,15 @@ impl TestXhciPciDevice { // Read data from parameter directly. pub fn get_transfer_data_direct(&self, addr: u64, len: u64) -> Vec { - let buf = self.mem_read(addr, len as usize); - buf + self.mem_read(addr, len as usize) } // Read data from parameter as address. pub fn get_transfer_data_indirect(&self, addr: u64, len: u64) -> Vec { let buf = self.mem_read(addr, 8); let mem = LittleEndian::read_u64(&buf); - let buf = self.mem_read(mem, len as usize); - buf + + self.mem_read(mem, len as usize) } pub fn get_transfer_data_indirect_with_offset( @@ -1278,8 +1279,8 @@ impl TestXhciPciDevice { ) -> Vec { let buf = self.mem_read(addr, 8); let mem = LittleEndian::read_u64(&buf); - let buf = self.mem_read(mem + offset, len); - buf + + self.mem_read(mem + offset, len) } pub fn get_command_pointer(&self) -> u64 { @@ -1345,7 +1346,7 @@ impl TestXhciPciDevice { trb.set_cycle_bit(self.get_cycle_bit(slot_id, ep_id)); } let en_ptr = self.get_transfer_pointer(slot_id, ep_id); - self.write_trb(en_ptr, &trb); + self.write_trb(en_ptr, trb); self.increase_transfer_ring(slot_id, ep_id, 1); } @@ -1426,7 +1427,7 @@ impl TestXhciPciDevice { assert_eq!(data, self.get_event_pointer(intr_idx)); // enable USB_CMD_INTE - let value = self.oper_regs_read(XHCI_OPER_REG_USBCMD as u64); + let value = self.oper_regs_read(XHCI_OPER_REG_USBCMD); self.oper_regs_write(XHCI_OPER_REG_USBCMD, value | USB_CMD_INTE); // enable INTE let value = self.interrupter_regs_read(intr_idx as u64, XHCI_INTR_REG_IMAN); @@ -1528,8 +1529,8 @@ impl TestXhciPciDevice { fn get_device_context_address(&self, slot_id: u32) -> u64 { let device_ctx_addr = self.xhci.dcbaap + u64::from(slot_id * DEVICE_CONTEXT_ENTRY_SIZE); let mut buf = self.mem_read(device_ctx_addr, 8); - let addr = LittleEndian::read_u64(&mut buf); - addr + + LittleEndian::read_u64(&mut buf) } fn has_msix(&mut self, msix_addr: u64, msix_data: u32) -> bool { @@ -1595,7 +1596,7 @@ impl TestXhciPciDevice { // Descriptor impl TestXhciPciDevice { fn get_usb_device_type(&mut self) -> UsbDeviceType { - let usb_device_type = if *self.device_config.get("tablet").unwrap_or(&false) { + if *self.device_config.get("tablet").unwrap_or(&false) { UsbDeviceType::Tablet } else if *self.device_config.get("keyboard").unwrap_or(&false) { UsbDeviceType::Keyboard @@ -1605,9 +1606,7 @@ impl TestXhciPciDevice { UsbDeviceType::Camera } else { UsbDeviceType::Other - }; - - usb_device_type + } } fn get_iad_desc(&mut self, offset: &mut u64, addr: u64) { @@ -1618,7 +1617,7 @@ impl TestXhciPciDevice { // 1. IAD header descriptor *offset += u64::from(USB_DT_CONFIG_SIZE); - let buf = self.get_transfer_data_indirect_with_offset(addr, 8 as usize, *offset); + let buf = self.get_transfer_data_indirect_with_offset(addr, 8_usize, *offset); // descriptor type assert_eq!(buf[1], USB_DT_INTERFACE_ASSOCIATION); @@ -1642,7 +1641,7 @@ impl TestXhciPciDevice { // get total vc length from its header descriptor *offset += u64::from(USB_DT_INTERFACE_SIZE); - let buf = self.get_transfer_data_indirect_with_offset(addr, 0xd as usize, *offset); + let buf = self.get_transfer_data_indirect_with_offset(addr, 0xd_usize, *offset); let total = u16::from_le_bytes(buf[5..7].try_into().unwrap()); let remained = total - 0xd; @@ -1664,7 +1663,7 @@ impl TestXhciPciDevice { // get total vs length from its header descriptor *offset += u64::from(USB_DT_INTERFACE_SIZE); - let buf = self.get_transfer_data_indirect_with_offset(addr, 0xf as usize, *offset); + let buf = self.get_transfer_data_indirect_with_offset(addr, 0xf_usize, *offset); let total = u16::from_le_bytes(buf[4..6].try_into().unwrap()); let remained = total - 0xf; @@ -2131,7 +2130,7 @@ impl TestXhciPciDevice { // Memory operation impl TestXhciPciDevice { pub fn mem_read_u32(&self, addr: u64, buf: &mut [u32]) { - let vec_len = size_of::() * buf.len(); + let vec_len = std::mem::size_of_val(buf); let tmp = self.mem_read(addr, vec_len); for i in 0..buf.len() { buf[i] = LittleEndian::read_u32(&tmp[(size_of::() * i)..]); @@ -2139,7 +2138,7 @@ impl TestXhciPciDevice { } pub fn mem_write_u32(&self, addr: u64, buf: &[u32]) { - let vec_len = size_of::() * buf.len(); + let vec_len = std::mem::size_of_val(buf); let mut vec = vec![0_u8; vec_len]; let tmp = vec.as_mut_slice(); for i in 0..buf.len() { @@ -2330,6 +2329,12 @@ pub struct TestUsbBuilder { config: HashMap, } +impl Default for TestUsbBuilder { + fn default() -> Self { + Self::new() + } +} + impl TestUsbBuilder { pub fn new() -> Self { let mut args = Vec::new(); @@ -2386,7 +2391,7 @@ impl TestUsbBuilder { } pub fn with_usb_storage(mut self, image_path: &str, media: &str) -> Self { - let args = format!("-device usb-storage,drive=drive0,id=storage0"); + let args = "-device usb-storage,drive=drive0,id=storage0".to_string(); let args: Vec<&str> = args[..].split(' ').collect(); let mut args = args.into_iter().map(|s| s.to_string()).collect(); self.args.append(&mut args); @@ -2492,8 +2497,7 @@ pub fn qmp_plug_keyboard_event(test_state: RefMut, num: u32) -> Value str += &num_str; str += "\",\"bus\":\"usb.0\",\"port\":\"1\"}}"; - let value = test_state.qmp(&str); - value + test_state.qmp(&str) } pub fn qmp_plug_tablet_event(test_state: RefMut, num: u32) -> Value { @@ -2504,8 +2508,7 @@ pub fn qmp_plug_tablet_event(test_state: RefMut, num: u32) -> Value { str += &num_str; str += "\",\"bus\":\"usb.0\",\"port\":\"2\"}}"; - let value = test_state.qmp(&str); - value + test_state.qmp(&str) } pub fn qmp_unplug_usb_event(test_state: RefMut, num: u32) -> Value { @@ -2514,8 +2517,7 @@ pub fn qmp_unplug_usb_event(test_state: RefMut, num: u32) -> Value { str += &num_str; str += "\"}}"; - let value = test_state.qmp(&str); - value + test_state.qmp(&str) } pub fn qmp_event_read(test_state: RefMut) { @@ -2524,6 +2526,6 @@ pub fn qmp_event_read(test_state: RefMut) { pub fn clear_iovec(test_state: RefMut, iovecs: &Vec) { for iov in iovecs.iter() { - test_state.memwrite(iov.io_base, &vec![0; iov.io_len as usize]); + test_state.memwrite(iov.io_base, &vec![0; iov.io_len]); } } diff --git a/tests/mod_test/src/libdriver/virtio_gpu.rs b/tests/mod_test/src/libdriver/virtio_gpu.rs index 802155d1..e985cc7d 100644 --- a/tests/mod_test/src/libdriver/virtio_gpu.rs +++ b/tests/mod_test/src/libdriver/virtio_gpu.rs @@ -671,7 +671,7 @@ pub fn get_display_info(gpu: &Rc>) -> VirtioGpuDisplayInf gpu.borrow_mut() .request_complete(true, hdr.as_bytes(), None, None, Some(&mut resp)); - return resp; + resp } // VIRTIO_GPU_CMD_GET_EDID @@ -689,7 +689,7 @@ pub fn get_edid(gpu: &Rc>, hdr_ctx: VirtioGpuGetEdid) -> None, Some(&mut resp), ); - return resp; + resp } pub fn current_curosr_check(dpy: &Rc>, local: &Vec) -> bool { @@ -740,7 +740,7 @@ pub fn resource_create( None, Some(&mut resp), ); - return resp; + resp } // VIRTIO_GPU_CMD_RESOURCE_UNREF @@ -761,7 +761,7 @@ pub fn resource_unref( None, Some(&mut resp), ); - return resp; + resp } // VIRTIO_GPU_CMD_RESOURCE_FLUSH @@ -782,7 +782,7 @@ pub fn resource_flush( None, Some(&mut resp), ); - return resp; + resp } // VIRTIO_GPU_CMD_UPDATE_CURSOR @@ -831,7 +831,7 @@ pub fn resource_attach_backing( Some(&ctx), Some(&mut resp), ); - return resp; + resp } pub fn resource_attach_backing_with_invalid_ctx_len( @@ -851,7 +851,7 @@ pub fn resource_attach_backing_with_invalid_ctx_len( None, Some(&mut resp), ); - return resp; + resp } // VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING @@ -872,7 +872,7 @@ pub fn resource_detach_backing( None, Some(&mut resp), ); - return resp; + resp } // VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D @@ -892,7 +892,7 @@ pub fn transfer_to_host( None, Some(&mut resp), ); - return resp; + resp } // VIRTIO_GPU_CMD_SET_SCANOUT @@ -913,7 +913,7 @@ pub fn set_scanout( None, Some(&mut resp), ); - return resp; + resp } pub fn invalid_cmd_test(gpu: &Rc>) -> VirtioGpuCtrlHdr { @@ -924,5 +924,5 @@ pub fn invalid_cmd_test(gpu: &Rc>) -> VirtioGpuCtrlHdr { gpu.borrow_mut() .request_complete(true, hdr.as_bytes(), None, None, Some(&mut resp)); - return resp; + resp } diff --git a/tests/mod_test/src/libdriver/virtio_pci_modern.rs b/tests/mod_test/src/libdriver/virtio_pci_modern.rs index bc5b9287..7e55fee2 100644 --- a/tests/mod_test/src/libdriver/virtio_pci_modern.rs +++ b/tests/mod_test/src/libdriver/virtio_pci_modern.rs @@ -263,7 +263,7 @@ impl TestVirtioPciDev { } fn has_msix(&self, msix_addr: u64, msix_data: u32) -> bool { - return self.pci_dev.has_msix(msix_addr, msix_data); + self.pci_dev.has_msix(msix_addr, msix_data) } pub fn setup_virtqueue_intr( @@ -597,7 +597,7 @@ impl VirtioDeviceOps for TestVirtioPciDev { let vq = virtqueue.borrow(); let idx: u16 = test_state.borrow().readw(vq.avail + 2); - if (!vq.event) || (idx >= vq.get_avail_event(test_state.clone()) + 1) { + if (!vq.event) || (idx > vq.get_avail_event(test_state.clone())) { self.virtqueue_notify(virtqueue.clone()); } } diff --git a/tests/mod_test/src/libdriver/vnc.rs b/tests/mod_test/src/libdriver/vnc.rs index 3158c5ee..83ada875 100644 --- a/tests/mod_test/src/libdriver/vnc.rs +++ b/tests/mod_test/src/libdriver/vnc.rs @@ -57,19 +57,14 @@ pub const PIXMAN_YUY2: u32 = 4; pub const REFRESH_TIME_INTERVAL: u64 = 3000 * 1000 * 1000; /// Input event. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Default)] pub enum InputEvent { KbdEvent = 0, MouseEvent = 1, + #[default] InvalidEvent = 255, } -impl Default for InputEvent { - fn default() -> Self { - InputEvent::InvalidEvent - } -} - impl From for InputEvent { fn from(v: u8) -> Self { match v { @@ -91,21 +86,16 @@ pub struct InputMessage { } /// GPU device Event. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Default)] pub enum GpuEvent { ReplaceSurface = 0, ReplaceCursor = 1, GraphicUpdateArea = 2, GraphicUpdateDirty = 3, + #[default] Deactive = 4, } -impl Default for GpuEvent { - fn default() -> Self { - GpuEvent::Deactive - } -} - #[derive(Debug, Clone, Copy, Default)] pub struct TestGpuCmd { pub event_type: GpuEvent, @@ -691,7 +681,7 @@ impl VncClient { pub fn epoll_ctl(&mut self, event: EpollEvent) -> io::Result<()> { self.epoll - .ctl(ControlOperation::Add, self.stream.as_raw_fd() as i32, event) + .ctl(ControlOperation::Add, self.stream.as_raw_fd(), event) } /// Wait for events on the epoll. @@ -701,13 +691,8 @@ impl VncClient { /// 2. Return if event happen or time out. pub fn epoll_wait(&mut self, event_set: EventSet) -> io::Result { let event = EpollEvent::new(event_set, self.stream.as_raw_fd() as u64); - if let Err(e) = self.epoll.ctl( - ControlOperation::Modify, - self.stream.as_raw_fd() as i32, - event, - ) { - return Err(e); - } + self.epoll + .ctl(ControlOperation::Modify, self.stream.as_raw_fd(), event)?; self.epoll .wait(EPOLL_DEFAULT_TIMEOUT, &mut self.ready_events[..]) } @@ -716,11 +701,8 @@ impl VncClient { pub fn stream_read_to_end(&mut self) -> Result<()> { let mut buf: Vec = Vec::new(); let event = EpollEvent::new(EventSet::IN, self.stream.as_raw_fd() as u64); - self.epoll.ctl( - ControlOperation::Modify, - self.stream.as_raw_fd() as i32, - event, - )?; + self.epoll + .ctl(ControlOperation::Modify, self.stream.as_raw_fd(), event)?; match self .epoll @@ -787,7 +769,7 @@ impl VncClient { if "RFB 003.008\n".as_bytes().to_vec() != buf[..12].to_vec() { bail!("Unsupported RFB version"); } - self.write_msg(&"RFB 003.008\n".as_bytes().to_vec())?; + self.write_msg("RFB 003.008\n".as_bytes())?; buf.drain(..12); // Step 2: Auth num is 1. @@ -800,7 +782,7 @@ impl VncClient { bail!("Unsupported security type!"); } buf.drain(..auth_num as usize); - self.write_msg(&(sec_type as u8).to_be_bytes().to_vec())?; + self.write_msg((sec_type as u8).to_be_bytes().as_ref())?; match sec_type { TestAuthType::VncAuthNone => { @@ -810,7 +792,7 @@ impl VncClient { if buf[..4].to_vec() != [0_u8; 4].to_vec() { bail!("Reject by vnc server"); } - self.write_msg(&0_u8.to_be_bytes().to_vec())?; + self.write_msg(0_u8.to_be_bytes().as_ref())?; buf.drain(..4); // Step 4. display mode information init: width + height + pixelformat + app_name. @@ -856,10 +838,7 @@ impl VncClient { let mut test_event = TestSetupEncoding::new(); if let Some(encoding) = enc { test_event.encs.push(encoding); - test_event.num_encodings = match enc_num { - Some(num) => num, - None => 1_u16, - }; + test_event.num_encodings = enc_num.unwrap_or(1_u16); } else { for encoding in EncodingType::ENCODINGTYPE { test_event.encs.push(encoding); @@ -1020,7 +999,7 @@ impl VncClient { let message_len: usize = frame_buff.w as usize * frame_buff.h as usize * (pf.bit_per_pixel as usize / 8); println!("Total bytes of image data: {:?}", message_len); - self.read_msg(buf, message_len as usize)?; + self.read_msg(buf, message_len)?; buf.drain(..message_len); Ok(()) } @@ -1211,7 +1190,7 @@ impl TestDemoGpuDevice { test_state.borrow_mut().writel(addr + 13, cmd.h); test_state.borrow_mut().writel(addr + 17, cmd.data_len); // Write to specific address. - self.pci_dev.io_writeq(self.bar_addr, 0 as u64, addr); + self.pci_dev.io_writeq(self.bar_addr, 0_u64, addr); test_state.borrow().clock_step_ns(REFRESH_TIME_INTERVAL); println!("cmd : {:?}", cmd); } diff --git a/tests/mod_test/src/libtest.rs b/tests/mod_test/src/libtest.rs index 3aa95723..c98c3224 100644 --- a/tests/mod_test/src/libtest.rs +++ b/tests/mod_test/src/libtest.rs @@ -138,7 +138,7 @@ impl TestState { let resp: Value = serde_json::from_slice(self.qmp_sock.read_line(timeout).as_bytes()).unwrap(); assert!(resp.get("event").is_some()); - return resp; + resp } pub fn qmp(&self, cmd: &str) -> Value { @@ -205,7 +205,7 @@ impl TestState { pub fn readq(&self, addr: u64) -> u64 { let cmd = format!("readq 0x{:x}", addr); - self.send_read_cmd(&cmd) as u64 + self.send_read_cmd(&cmd) } pub fn memread(&self, addr: u64, size: u64) -> Vec { diff --git a/tests/mod_test/src/utils.rs b/tests/mod_test/src/utils.rs index b393cc37..06a2118a 100644 --- a/tests/mod_test/src/utils.rs +++ b/tests/mod_test/src/utils.rs @@ -56,7 +56,7 @@ pub fn read_le_u64(input: &mut &[u8]) -> u64 { } pub fn swap_u16(value: u16) -> u16 { - return value << 8 | value >> 8; + value << 8 | value >> 8 } pub fn swap_u32(value: u32) -> u32 { @@ -143,15 +143,11 @@ pub fn support_numa() -> bool { } } } - if has_nodes { - return true; - } else { - return false; - } + has_nodes } - Err(_) => return false, + Err(_) => false, } } else { - return false; + false } } diff --git a/tests/mod_test/tests/balloon_test.rs b/tests/mod_test/tests/balloon_test.rs index 9ac0a6fe..63dafe6c 100644 --- a/tests/mod_test/tests/balloon_test.rs +++ b/tests/mod_test/tests/balloon_test.rs @@ -39,7 +39,7 @@ const ADDRESS_BASE: u64 = 0x4000_0000; fn read_lines(filename: String) -> io::Lines> { let file = File::open(filename).unwrap(); - return io::BufReader::new(file).lines(); + io::BufReader::new(file).lines() } fn get_hugesize() -> u64 { @@ -48,12 +48,12 @@ fn get_hugesize() -> u64 { for line in lines { if let Ok(info) = line { if info.starts_with("HugePages_Free:") { - let free: Vec<&str> = info.split(":").collect(); + let free: Vec<&str> = info.split(':').collect(); free_page = free[1].trim().parse::().unwrap(); } if info.starts_with("Hugepagesize:") { - let huges: Vec<&str> = info.split(":").collect(); - let sizes: Vec<&str> = huges[1].trim().split(" ").collect(); + let huges: Vec<&str> = info.split(':').collect(); + let sizes: Vec<&str> = huges[1].trim().split(' ').collect(); let size = sizes[0].trim().parse::().unwrap(); return free_page * size; } @@ -91,7 +91,7 @@ impl VirtioBalloonTest { let mut extra_args: Vec<&str> = Vec::new(); let mut fpr_switch = String::from("false"); let mut auto_switch = String::from("false"); - let mem_path = format!("-mem-path /tmp/stratovirt/hugepages"); + let mem_path = "-mem-path /tmp/stratovirt/hugepages".to_string(); let mut machine_args = MACHINE_TYPE_ARG.to_string(); if shared { @@ -130,8 +130,7 @@ impl VirtioBalloonTest { dev.borrow_mut().init(pci_slot, 0); let features = dev.borrow_mut().get_device_features(); - let inf_queue; - let def_queue; + let mut fpr_queue = None; let mut auto_queue = None; let mut que_num = 2_usize; @@ -145,8 +144,8 @@ impl VirtioBalloonTest { let ques = dev.borrow_mut() .init_device(test_state.clone(), allocator.clone(), features, que_num); - inf_queue = ques[0].clone(); - def_queue = ques[1].clone(); + let inf_queue = ques[0].clone(); + let def_queue = ques[1].clone(); if cfg.fpr { fpr_queue = Some(ques[idx].clone()); idx += 1; @@ -213,14 +212,12 @@ impl VirtioBalloonTest { dev.borrow_mut().init(4, 0); let features = dev.borrow_mut().get_device_features(); - let inf_queue; - let def_queue; let ques = dev .borrow_mut() .init_device(test_state.clone(), allocator.clone(), features, 2); - inf_queue = ques[0].clone(); - def_queue = ques[1].clone(); + let inf_queue = ques[0].clone(); + let def_queue = ques[1].clone(); VirtioBalloonTest { device: dev, @@ -779,7 +776,7 @@ fn query() { assert_eq!( *ret.get("return").unwrap(), - json!({"actual": 2147483648 as u64}) + json!({"actual": 2147483648_u64}) ); balloon.state.borrow_mut().stop(); @@ -835,10 +832,7 @@ fn balloon_config_001() { let ten_millis = time::Duration::from_millis(10); thread::sleep(ten_millis); let ret = balloon.state.borrow_mut().qmp_read(); - assert_eq!( - *ret.get("data").unwrap(), - json!({"actual": 536870912 as u64}) - ); + assert_eq!(*ret.get("data").unwrap(), json!({"actual": 536870912_u64})); balloon .state @@ -906,10 +900,7 @@ fn balloon_config_002() { let ten_millis = time::Duration::from_millis(10); thread::sleep(ten_millis); let ret = balloon.state.borrow_mut().qmp_read(); - assert_eq!( - *ret.get("data").unwrap(), - json!({"actual": 536870912 as u64}) - ); + assert_eq!(*ret.get("data").unwrap(), json!({"actual": 536870912_u64})); balloon .state @@ -957,7 +948,7 @@ fn balloon_deactive_001() { .qmp("{\"execute\": \"query-balloon\"}"); assert_eq!( *ret.get("return").unwrap(), - json!({"actual": 1073741824 as u64}) + json!({"actual": 1073741824_u64}) ); balloon.state.borrow_mut().stop(); } @@ -1009,7 +1000,7 @@ fn auto_balloon_test_001() { balloon .state .borrow_mut() - .memwrite(msg_addr, &stat.as_bytes()); + .memwrite(msg_addr, stat.as_bytes()); let auto_queue = balloon.auto_queue.unwrap(); diff --git a/tests/mod_test/tests/block_test.rs b/tests/mod_test/tests/block_test.rs index c716ebf3..78d590bf 100644 --- a/tests/mod_test/tests/block_test.rs +++ b/tests/mod_test/tests/block_test.rs @@ -1014,10 +1014,9 @@ fn blk_iops() { if blk.borrow().queue_was_notified(virtqueues[0].clone()) && virtqueues[0].borrow_mut().get_buf(test_state.clone()) + && virtqueues[0].borrow().desc_len.contains_key(&free_head) { - if virtqueues[0].borrow().desc_len.contains_key(&free_head) { - break; - } + break; } assert!(Instant::now() <= time_out); } @@ -1062,7 +1061,7 @@ fn blk_with_different_aio() { let image_path = Rc::new(create_img(TEST_IMAGE_SIZE_1M, 1, &image_type)); let device_args = Rc::new(String::from("")); let drive_args = if aio_probe(aio_engine).is_ok() { - Rc::new(format!(",direct={},aio={}", direct, aio_engine.to_string())) + Rc::new(format!(",direct={},aio={}", direct, aio_engine)) } else { continue; }; @@ -1773,7 +1772,7 @@ fn blk_feature_discard() { assert_eq!(image_size, full_disk_size - u64::from(num_sectors) / 2); } else if image_type == ImageType::Qcow2 && status == VIRTIO_BLK_S_OK - && (u64::from(num_sectors) * 512 & CLUSTER_SIZE - 1) == 0 + && ((u64::from(num_sectors) * 512) & (CLUSTER_SIZE - 1)) == 0 { // If the disk format is equal to Qcow2. // the length of the num sectors needs to be aligned with the cluster size, @@ -1906,7 +1905,7 @@ fn blk_feature_write_zeroes() { test_state.clone(), alloc.clone(), virtqueues[0].clone(), - &req_data.as_bytes().to_vec(), + req_data.as_bytes(), status, true, false, @@ -1944,7 +1943,7 @@ fn blk_feature_write_zeroes() { } else if image_type == ImageType::Qcow2 && status == VIRTIO_BLK_S_OK && (write_zeroes == "unmap" && discard == "unmap" && flags == 1 || len != wz_len) - && (u64::from(num_sectors) * 512 & CLUSTER_SIZE - 1) == 0 + && ((u64::from(num_sectors) * 512) & (CLUSTER_SIZE - 1)) == 0 { // If the disk format is equal to Qcow2. // the length of the num sectors needs to be aligned with the cluster size, @@ -1983,7 +1982,7 @@ fn blk_snapshot_basic() { .init_device(test_state.clone(), alloc.clone(), features, 1); create_snapshot(test_state.clone(), "drive0", "snap0"); - assert_eq!(check_snapshot(test_state.clone(), "snap0"), true); + assert!(check_snapshot(test_state.clone(), "snap0")); virtio_blk_write( blk.clone(), @@ -2003,7 +2002,7 @@ fn blk_snapshot_basic() { ); delete_snapshot(test_state.clone(), "drive0", "snap0"); - assert_eq!(check_snapshot(test_state.clone(), "snap0"), false); + assert!(!check_snapshot(test_state.clone(), "snap0")); virtio_blk_write( blk.clone(), @@ -2052,7 +2051,7 @@ fn blk_snapshot_basic2() { .borrow_mut() .init_device(test_state.clone(), alloc.clone(), features, 1); create_snapshot(test_state.clone(), "drive0", "snap0"); - assert_eq!(check_snapshot(test_state.clone(), "snap0"), true); + assert!(check_snapshot(test_state.clone(), "snap0")); tear_down( blk.clone(), test_state.clone(), @@ -2095,10 +2094,10 @@ fn blk_snapshot_basic2() { ); create_snapshot(test_state.clone(), "drive0", "snap1"); - assert_eq!(check_snapshot(test_state.clone(), "snap1"), true); + assert!(check_snapshot(test_state.clone(), "snap1")); delete_snapshot(test_state.clone(), "drive0", "snap0"); - assert_eq!(check_snapshot(test_state.clone(), "snap0"), false); + assert!(!check_snapshot(test_state.clone(), "snap0")); virtio_blk_write( blk.clone(), diff --git a/tests/mod_test/tests/fwcfg_test.rs b/tests/mod_test/tests/fwcfg_test.rs index f8208325..da210b04 100644 --- a/tests/mod_test/tests/fwcfg_test.rs +++ b/tests/mod_test/tests/fwcfg_test.rs @@ -34,7 +34,7 @@ fn test_signature() { let mut test_state = test_init(args); let mut read_data: Vec = Vec::with_capacity(4); - let target_data: [u8; 4] = ['Q' as u8, 'E' as u8, 'M' as u8, 'U' as u8]; + let target_data: [u8; 4] = [b'Q', b'E', b'M', b'U']; // Select Signature entry and read it. test_state.fw_cfg_read_bytes(FwCfgEntryType::Signature as u16, &mut read_data, 4); @@ -251,12 +251,12 @@ fn test_smbios_type0() { &mut allocator.borrow_mut(), anchor_file, &mut read_data, - 24 as u32, + 24_u32, ); - assert_eq!(anchor_size, 24 as u32); + assert_eq!(anchor_size, 24_u32); assert_eq!(String::from_utf8_lossy(&read_data[..5]), "_SM3_"); - assert_eq!(read_data[6], 24 as u8); + assert_eq!(read_data[6], 24_u8); let talble_len = LittleEndian::read_u32(&read_data[12..]); assert_eq!(talble_len, 372); @@ -315,12 +315,12 @@ fn test_smbios_type1() { &mut allocator.borrow_mut(), anchor_file, &mut read_data, - 24 as u32, + 24_u32, ); - assert_eq!(anchor_size, 24 as u32); + assert_eq!(anchor_size, 24_u32); assert_eq!(String::from_utf8_lossy(&read_data[..5]), "_SM3_"); - assert_eq!(read_data[6], 24 as u8); + assert_eq!(read_data[6], 24_u8); let talble_len = LittleEndian::read_u32(&read_data[12..]); assert_eq!(talble_len, 414); @@ -342,7 +342,7 @@ fn test_smbios_type1() { "version0" ); assert_eq!(read_table_date[48], 1); - assert_eq!(read_table_date[49], 27 as u8); + assert_eq!(read_table_date[49], 27_u8); let handle1 = LittleEndian::read_u16(&read_table_date[50..]); assert_eq!(handle1, 0x100); @@ -420,12 +420,12 @@ fn test_smbios_type2() { &mut allocator.borrow_mut(), anchor_file, &mut read_data, - 24 as u32, + 24_u32, ); - assert_eq!(anchor_size, 24 as u32); + assert_eq!(anchor_size, 24_u32); assert_eq!(String::from_utf8_lossy(&read_data[..5]), "_SM3_"); - assert_eq!(read_data[6], 24 as u8); + assert_eq!(read_data[6], 24_u8); let talble_len = LittleEndian::read_u32(&read_data[12..]); let mut read_table_date: Vec = Vec::with_capacity(talble_len as usize); @@ -495,12 +495,12 @@ fn test_smbios_type3() { &mut allocator.borrow_mut(), anchor_file, &mut read_data, - 24 as u32, + 24_u32, ); - assert_eq!(anchor_size, 24 as u32); + assert_eq!(anchor_size, 24_u32); assert_eq!(String::from_utf8_lossy(&read_data[..5]), "_SM3_"); - assert_eq!(read_data[6], 24 as u8); + assert_eq!(read_data[6], 24_u8); let talble_len = LittleEndian::read_u32(&read_data[12..]); let mut read_table_date: Vec = Vec::with_capacity(talble_len as usize); @@ -547,7 +547,7 @@ fn test_smbios_type4() { let mut args: Vec<&str> = Vec::new(); bios_args(&mut args); - let cpu_args = format!("-smp 8,maxcpus=8,sockets=2,cores=2,threads=2"); + let cpu_args = "-smp 8,maxcpus=8,sockets=2,cores=2,threads=2".to_string(); let mut extra_args = cpu_args.split(' ').collect(); args.append(&mut extra_args); @@ -570,12 +570,12 @@ fn test_smbios_type4() { &mut allocator.borrow_mut(), anchor_file, &mut read_data, - 24 as u32, + 24_u32, ); - assert_eq!(anchor_size, 24 as u32); + assert_eq!(anchor_size, 24_u32); assert_eq!(String::from_utf8_lossy(&read_data[..5]), "_SM3_"); - assert_eq!(read_data[6], 24 as u8); + assert_eq!(read_data[6], 24_u8); let talble_len = LittleEndian::read_u32(&read_data[12..]); let mut read_table_date: Vec = Vec::with_capacity(talble_len as usize); @@ -631,7 +631,7 @@ fn test_smbios_type17() { let mut args: Vec<&str> = Vec::new(); bios_args(&mut args); - let cpu_args = format!("-smp 8,maxcpus=8,sockets=2,cores=2,threads=2"); + let cpu_args = "-smp 8,maxcpus=8,sockets=2,cores=2,threads=2".to_string(); let mut extra_args = cpu_args.split(' ').collect(); args.append(&mut extra_args); @@ -655,12 +655,12 @@ fn test_smbios_type17() { &mut allocator.borrow_mut(), anchor_file, &mut read_data, - 24 as u32, + 24_u32, ); - assert_eq!(anchor_size, 24 as u32); + assert_eq!(anchor_size, 24_u32); assert_eq!(String::from_utf8_lossy(&read_data[..5]), "_SM3_"); - assert_eq!(read_data[6], 24 as u8); + assert_eq!(read_data[6], 24_u8); let talble_len = LittleEndian::read_u32(&read_data[12..]); assert_eq!(talble_len, 467); diff --git a/tests/mod_test/tests/memory_test.rs b/tests/mod_test/tests/memory_test.rs index ed7dca58..4b7544a1 100644 --- a/tests/mod_test/tests/memory_test.rs +++ b/tests/mod_test/tests/memory_test.rs @@ -270,7 +270,7 @@ fn rom_device_region_readwrite() { // Add a dummy rom device by qmp. The function of the device is to multiply the written value by // 2 through the write interface and save it, and read the saved value through the read // interface. - let file = File::create(&ROM_DEV_PATH).unwrap(); + let file = File::create(ROM_DEV_PATH).unwrap(); file.set_len(PAGE_SIZE).unwrap(); let qmp_str = format!( "{{ \"execute\": \"update_region\", @@ -309,7 +309,7 @@ fn rom_device_region_readwrite() { // device. The device can set the write mode to writable according to the device status during // the write operation, or directly return an error indicating that the write is not allowed. // The read operation is the same as that of IO region. - let file = File::create(&ROM_DEV_PATH).unwrap(); + let file = File::create(ROM_DEV_PATH).unwrap(); file.set_len(PAGE_SIZE).unwrap(); let qmp_str = format!( "{{ \"execute\": \"update_region\", @@ -352,7 +352,7 @@ fn ram_device_region_readwrite() { let memory_test = MemoryTest::new(MEM_SIZE, PAGE_SIZE, false, false, None, None); let addr = 0x1_0000_0000; // 4GB - let file = File::create(&RAM_DEV_PATH).unwrap(); + let file = File::create(RAM_DEV_PATH).unwrap(); file.set_len(PAGE_SIZE).unwrap(); let qmp_str = format!( "{{ \"execute\": \"update_region\", @@ -719,7 +719,7 @@ fn ram_readwrite_numa1() { assert_eq!(str, String::from_utf8(ret.clone()).unwrap()); test_state.borrow_mut().qmp("{\"execute\": \"query-mem\"}"); - let file = File::create(&RAM_DEV_PATH).unwrap(); + let file = File::create(RAM_DEV_PATH).unwrap(); file.set_len(PAGE_SIZE).unwrap(); let qmp_str = format!( "{{ \"execute\": \"update_region\", diff --git a/tests/mod_test/tests/net_test.rs b/tests/mod_test/tests/net_test.rs index 5d400a6a..ff6a7c99 100644 --- a/tests/mod_test/tests/net_test.rs +++ b/tests/mod_test/tests/net_test.rs @@ -343,7 +343,7 @@ fn execute_cmd(cmd: String, check: bool) { let output = cmd_exe .output() - .expect(format!("Failed to execute {}", cmd).as_str()); + .unwrap_or_else(|_| panic!("Failed to execute {}", cmd)); println!("{:?}", args); if check { assert!(output.status.success()); @@ -361,25 +361,21 @@ fn execute_cmd_checked(cmd: String) { fn create_tap(id: u8, mq: bool) { let br_name = "mst_net_qbr".to_string() + &id.to_string(); let tap_name = "mst_net_qtap".to_string() + &id.to_string(); - execute_cmd_checked("ip link add name ".to_string() + &br_name + &" type bridge".to_string()); + execute_cmd_checked("ip link add name ".to_string() + &br_name + " type bridge"); if mq { - execute_cmd_checked( - "ip tuntap add ".to_string() + &tap_name + &" mode tap multi_queue".to_string(), - ); + execute_cmd_checked("ip tuntap add ".to_string() + &tap_name + " mode tap multi_queue"); } else { - execute_cmd_checked("ip tuntap add ".to_string() + &tap_name + &" mode tap".to_string()); + execute_cmd_checked("ip tuntap add ".to_string() + &tap_name + " mode tap"); } - execute_cmd_checked( - "ip link set ".to_string() + &tap_name + &" master ".to_string() + &br_name, - ); - execute_cmd_checked("ip link set ".to_string() + &br_name + &" up".to_string()); - execute_cmd_checked("ip link set ".to_string() + &tap_name + &" up".to_string()); + execute_cmd_checked("ip link set ".to_string() + &tap_name + " master " + &br_name); + execute_cmd_checked("ip link set ".to_string() + &br_name + " up"); + execute_cmd_checked("ip link set ".to_string() + &tap_name + " up"); execute_cmd_checked( "ip address add ".to_string() + &id.to_string() - + &".1.1.".to_string() + + ".1.1." + &id.to_string() - + &"/24 dev ".to_string() + + "/24 dev " + &br_name, ); } @@ -387,16 +383,14 @@ fn create_tap(id: u8, mq: bool) { fn clear_tap(id: u8, mq: bool) { let br_name = "mst_net_qbr".to_string() + &id.to_string(); let tap_name = "mst_net_qtap".to_string() + &id.to_string(); - execute_cmd_unchecked("ip link set ".to_string() + &tap_name + &" down".to_string()); - execute_cmd_unchecked("ip link set ".to_string() + &br_name + &" down".to_string()); + execute_cmd_unchecked("ip link set ".to_string() + &tap_name + " down"); + execute_cmd_unchecked("ip link set ".to_string() + &br_name + " down"); if mq { - execute_cmd_unchecked( - "ip tuntap del ".to_string() + &tap_name + &" mode tap multi_queue".to_string(), - ); + execute_cmd_unchecked("ip tuntap del ".to_string() + &tap_name + " mode tap multi_queue"); } else { - execute_cmd_unchecked("ip tuntap del ".to_string() + &tap_name + &" mode tap".to_string()); + execute_cmd_unchecked("ip tuntap del ".to_string() + &tap_name + " mode tap"); } - execute_cmd_unchecked("ip link delete ".to_string() + &br_name + &" type bridge".to_string()); + execute_cmd_unchecked("ip link delete ".to_string() + &br_name + " type bridge"); } #[allow(unused)] @@ -718,13 +712,13 @@ fn send_arp_request( test_state.clone(), alloc.clone(), vqs[1].clone(), - &arp_request, + arp_request, ); check_arp_mac( net.clone(), test_state.clone(), vqs[0].clone(), - &arp_request, + arp_request, need_reply, ); } @@ -750,7 +744,7 @@ fn check_device_status(net: Rc>, status: u8) { /// 1/2/3: success. #[test] fn virtio_net_rx_tx_test() { - let id = 1 * TEST_MAC_ADDR_NUMS; + let id = TEST_MAC_ADDR_NUMS; let (net, test_state, alloc) = set_up(id, false, 0, false); // Three virtqueues: tx/rx/ctrl. @@ -768,7 +762,7 @@ fn virtio_net_rx_tx_test() { test_state.clone(), alloc.clone(), vqs.clone(), - &arp_request.as_bytes(), + arp_request.as_bytes(), true, ); @@ -809,7 +803,7 @@ fn virtio_net_rx_tx_test_iothread() { test_state.clone(), alloc.clone(), vqs.clone(), - &arp_request.as_bytes(), + arp_request.as_bytes(), true, ); @@ -877,7 +871,7 @@ fn virtio_net_ctrl_mq_test() { class: VIRTIO_NET_CTRL_MQ, cmd, }; - test_state.borrow().memwrite(addr, &ctrl_hdr.as_bytes()); + test_state.borrow().memwrite(addr, ctrl_hdr.as_bytes()); test_state .borrow() .writew(addr + size_of::() as u64, vq_pairs); @@ -1072,7 +1066,7 @@ fn send_ctrl_vq_request( ) { let ctrl_vq = &vqs[2]; let addr = alloc.borrow_mut().alloc(ctrl_data.len() as u64); - test_state.borrow().memwrite(addr, &ctrl_data); + test_state.borrow().memwrite(addr, ctrl_data); let data_entries: Vec = vec![ TestVringDescEntry { data: addr, @@ -1187,7 +1181,7 @@ fn ctrl_vq_set_mac_address( test_state.clone(), alloc.clone(), vqs.clone(), - &ctrl_mac_addr.as_bytes(), + ctrl_mac_addr.as_bytes(), VIRTIO_NET_OK, ); // Check mac address result. @@ -1231,7 +1225,7 @@ fn virtio_net_ctrl_vlan_test() { test_state.clone(), alloc.clone(), vqs.clone(), - &ctrl_rx_info.as_bytes(), + ctrl_rx_info.as_bytes(), VIRTIO_NET_OK, ); @@ -1250,7 +1244,7 @@ fn virtio_net_ctrl_vlan_test() { test_state.clone(), alloc.clone(), vqs.clone(), - &ctrl_vlan_info.as_bytes(), + ctrl_vlan_info.as_bytes(), ack, ); } @@ -1262,7 +1256,7 @@ fn virtio_net_ctrl_vlan_test() { test_state.clone(), alloc.clone(), vqs.clone(), - &ctrl_vlan_info.as_bytes(), + ctrl_vlan_info.as_bytes(), ack, ); } @@ -1273,7 +1267,7 @@ fn virtio_net_ctrl_vlan_test() { test_state.clone(), alloc.clone(), vqs.clone(), - &ctrl_vlan_info.as_bytes(), + ctrl_vlan_info.as_bytes(), VIRTIO_NET_ERR, ); // Test invalid cmd. @@ -1283,7 +1277,7 @@ fn virtio_net_ctrl_vlan_test() { test_state.clone(), alloc.clone(), vqs.clone(), - &ctrl_vlan_info.as_bytes(), + ctrl_vlan_info.as_bytes(), VIRTIO_NET_ERR, ); // Test invalid vid length. @@ -1303,7 +1297,7 @@ fn virtio_net_ctrl_vlan_test() { test_state.clone(), alloc.clone(), vqs.clone(), - &get_arp_request(id).as_bytes(), + get_arp_request(id).as_bytes(), true, ); send_arp_request( @@ -1311,7 +1305,7 @@ fn virtio_net_ctrl_vlan_test() { test_state.clone(), alloc.clone(), vqs.clone(), - &get_arp_request_vlan(id).as_bytes(), + get_arp_request_vlan(id).as_bytes(), false, ); @@ -1406,7 +1400,7 @@ fn virtio_net_ctrl_mac_test() { test_state.clone(), alloc.clone(), vqs.clone(), - &ctrl_rx_info.as_bytes(), + ctrl_rx_info.as_bytes(), VIRTIO_NET_OK, ); @@ -1470,7 +1464,7 @@ fn virtio_net_ctrl_mac_test() { test_state.clone(), alloc.clone(), vqs.clone(), - &arp_request.as_bytes(), + arp_request.as_bytes(), true, ); @@ -1556,7 +1550,7 @@ fn virtio_net_ctrl_rx_test() { test_state.clone(), alloc.clone(), vqs.clone(), - &ctrl_rx_info.as_bytes(), + ctrl_rx_info.as_bytes(), VIRTIO_NET_OK, ); let mut ctrl_rx_info = CtrlRxInfo::new(VIRTIO_NET_CTRL_RX, 0, 0); @@ -1602,7 +1596,7 @@ fn virtio_net_ctrl_rx_test() { test_state.clone(), alloc.clone(), vqs.clone(), - &ctrl_rx_info.as_bytes(), + ctrl_rx_info.as_bytes(), ack, ); } @@ -1617,7 +1611,7 @@ fn virtio_net_ctrl_rx_test() { test_state.clone(), alloc.clone(), vqs.clone(), - &arp_request.as_bytes(), + arp_request.as_bytes(), need_reply, ); @@ -1663,7 +1657,7 @@ fn virtio_net_ctrl_abnormal_test() { for i in 0..test_num { let ctrl_vq = &vqs[2]; let addr = alloc.borrow_mut().alloc(ctrl_data.len() as u64); - test_state.borrow().memwrite(addr, &ctrl_data); + test_state.borrow().memwrite(addr, ctrl_data); // ctrl_rx_info.switch: u8 let mut data_len = 1; @@ -1750,7 +1744,7 @@ fn virtio_net_abnormal_rx_tx_test() { assert_eq!(size, QUEUE_SIZE_NET); for _ in 0..size { let addr = alloc.borrow_mut().alloc(length); - test_state.borrow().memwrite(addr, &request.as_bytes()); + test_state.borrow().memwrite(addr, request.as_bytes()); vqs[1] .borrow_mut() .add(test_state.clone(), addr, length as u32, false); @@ -1830,7 +1824,7 @@ fn virtio_net_abnormal_rx_tx_test_2() { let request = get_arp_request(id); let length = request.as_bytes().len() as u64; let addr = alloc.borrow_mut().alloc(length); - test_state.borrow().memwrite(addr, &request.as_bytes()); + test_state.borrow().memwrite(addr, request.as_bytes()); vqs[1] .borrow_mut() .add(test_state.clone(), addr, length as u32, false); @@ -1897,7 +1891,7 @@ fn virtio_net_set_abnormal_feature() { test_state.clone(), alloc.clone(), vqs.clone(), - &arp_request.as_bytes(), + arp_request.as_bytes(), true, ); @@ -1943,7 +1937,7 @@ fn virtio_net_send_abnormal_packet() { test_state.clone(), alloc.clone(), vqs.clone(), - &arp_request.as_bytes(), + arp_request.as_bytes(), false, ); @@ -1961,7 +1955,7 @@ fn virtio_net_send_abnormal_packet() { test_state.clone(), alloc.clone(), vqs[1].clone(), - &data_bytes, + data_bytes, ); } @@ -2022,7 +2016,7 @@ fn virtio_net_rx_tx_mq_test() { test_state.clone(), alloc.clone(), vqs[i as usize * 2 + 1].clone(), - &get_arp_request(id + i as u8 * TEST_MAC_ADDR_NUMS).as_bytes(), + get_arp_request(id + i as u8 * TEST_MAC_ADDR_NUMS).as_bytes(), ); } @@ -2079,7 +2073,7 @@ fn virtio_net_abnormal_rx_tx_test_3() { + u64::from(notify_off) * u64::from(net.borrow().notify_off_multiplier); net.borrow() - .setup_virtqueue_intr((i + 1) as u16, alloc.clone(), vq.clone()); + .setup_virtqueue_intr(i + 1, alloc.clone(), vq.clone()); vqs.push(vq); } fill_rx_vq(test_state.clone(), alloc.clone(), vqs[0].clone()); @@ -2091,7 +2085,7 @@ fn virtio_net_abnormal_rx_tx_test_3() { let request = get_arp_request(id); let length = request.as_bytes().len() as u64; let addr = alloc.borrow_mut().alloc(length); - test_state.borrow().memwrite(addr, &request.as_bytes()); + test_state.borrow().memwrite(addr, request.as_bytes()); vqs[1] .borrow_mut() .add(test_state.clone(), addr, length as u32, false); diff --git a/tests/mod_test/tests/pci_test.rs b/tests/mod_test/tests/pci_test.rs index 60239ac8..831d6288 100644 --- a/tests/mod_test/tests/pci_test.rs +++ b/tests/mod_test/tests/pci_test.rs @@ -74,7 +74,7 @@ fn init_demo_dev(cfg: DemoDev, dev_num: u8) -> (Rc>, Rc = "-D /tmp/oscar.log".split(' ').collect(); demo_dev_args.append(&mut args); - let demo_str = fmt_demo_deves(cfg.clone(), dev_num); + let demo_str = fmt_demo_deves(cfg, dev_num); args = demo_str[..].split(' ').collect(); demo_dev_args.append(&mut args); @@ -169,7 +169,7 @@ fn build_root_port_args(root_port_nums: u8) -> Vec { if multifunc { addr = bus / 8 + 1; func += 1; - func = func % 8; + func %= 8; } else { addr += 1; func = 0; @@ -287,7 +287,7 @@ fn build_all_device_args( ) -> Vec { let mut device_args: Vec = Vec::new(); let mut root_port_args = build_root_port_args(root_port_nums); - if root_port_args.len() != 0 { + if !root_port_args.is_empty() { device_args.append(&mut root_port_args); } @@ -366,7 +366,7 @@ fn create_machine( .borrow() .pci_bus .borrow() - .pci_auto_bus_scan(root_port_nums as u8); + .pci_auto_bus_scan(root_port_nums); let allocator = machine.borrow().allocator.clone(); (test_state, machine, allocator) @@ -413,7 +413,7 @@ fn tear_down( test_state.borrow_mut().stop(); if let Some(img_paths) = image_paths { - img_paths.iter().enumerate().for_each(|(_i, image_path)| { + img_paths.iter().for_each(|image_path| { cleanup_img(image_path.to_string()); }) } @@ -690,8 +690,8 @@ fn lookup_all_cap_addr(cap_id: u8, pci_dev: TestPciDev) -> Vec { fn get_msix_flag(pci_dev: TestPciDev) -> u16 { let addr = pci_dev.find_capability(PCI_CAP_ID_MSIX, 0); assert_ne!(addr, 0); - let old_value = pci_dev.config_readw(addr + PCI_MSIX_MSG_CTL); - old_value + + pci_dev.config_readw(addr + PCI_MSIX_MSG_CTL) } fn set_msix_enable(pci_dev: TestPciDev) { @@ -730,14 +730,11 @@ fn unmask_msix_global(pci_dev: TestPciDev) { fn mask_msix_vector(pci_dev: TestPciDev, vector: u16) { let offset: u64 = pci_dev.msix_table_off + u64::from(vector * PCI_MSIX_ENTRY_SIZE); - let vector_mask = pci_dev.io_readl( - pci_dev.msix_table_bar, - offset + PCI_MSIX_ENTRY_VECTOR_CTRL as u64, - ); + let vector_mask = pci_dev.io_readl(pci_dev.msix_table_bar, offset + PCI_MSIX_ENTRY_VECTOR_CTRL); pci_dev.io_writel( pci_dev.msix_table_bar, - offset + PCI_MSIX_ENTRY_VECTOR_CTRL as u64, + offset + PCI_MSIX_ENTRY_VECTOR_CTRL, vector_mask | PCI_MSIX_ENTRY_CTRL_MASKBIT, ); } @@ -745,14 +742,12 @@ fn mask_msix_vector(pci_dev: TestPciDev, vector: u16) { fn unmask_msix_vector(pci_dev: TestPciDev, vector: u16) { let offset: u64 = pci_dev.msix_table_off + u64::from(vector * PCI_MSIX_ENTRY_SIZE); - let vector_control = pci_dev.io_readl( - pci_dev.msix_table_bar, - offset + PCI_MSIX_ENTRY_VECTOR_CTRL as u64, - ); + let vector_control = + pci_dev.io_readl(pci_dev.msix_table_bar, offset + PCI_MSIX_ENTRY_VECTOR_CTRL); pci_dev.io_writel( pci_dev.msix_table_bar, - offset + PCI_MSIX_ENTRY_VECTOR_CTRL as u64, + offset + PCI_MSIX_ENTRY_VECTOR_CTRL, vector_control & !PCI_MSIX_ENTRY_CTRL_MASKBIT, ); } @@ -910,7 +905,7 @@ fn test_pci_device_discovery_001() { validate_config_value_2byte( blk.borrow().pci_dev.pci_bus.clone(), 1, - 1 << 3 | 0, + 1 << 3, PCI_VENDOR_ID, 0xFFFF, 0xFFFF, @@ -952,7 +947,7 @@ fn test_pci_device_discovery_002() { machine.clone(), alloc.clone(), 0, - 1 << 3 | 0, + 1 << 3, ))); // Create a root port whose bdf is 0:2:0. @@ -960,7 +955,7 @@ fn test_pci_device_discovery_002() { machine.clone(), alloc.clone(), 0, - 2 << 3 | 0, + 2 << 3, ))); // Create a block device whose bdf is 1:0:0. @@ -1018,7 +1013,7 @@ fn test_pci_device_discovery_003() { machine.clone(), alloc.clone(), 0, - 1 << 3 | 0, + 1 << 3, ))); // Verify the vendor id for the virtio block device hotplugged. @@ -1069,7 +1064,7 @@ fn test_pci_device_discovery_004() { machine.clone(), alloc.clone(), 0, - 1 << 3 | 0, + 1 << 3, ))); let blk_id = 0; @@ -1249,7 +1244,7 @@ fn test_pci_type1_config() { let (test_state, machine, alloc, image_paths) = set_up(root_port_nums, blk_nums, true, false); // Create a root port whose bdf is 0:1:0. - let root_port = RootPort::new(machine.clone(), alloc.clone(), 0, 1 << 3 | 0); + let root_port = RootPort::new(machine.clone(), alloc.clone(), 0, 1 << 3); assert_eq!(root_port.rp_dev.config_readb(PCI_PRIMARY_BUS), 0); assert_ne!(root_port.rp_dev.config_readb(PCI_SECONDARY_BUS), 0); @@ -1265,7 +1260,7 @@ fn test_pci_type1_reset() { let (test_state, machine, alloc, image_paths) = set_up(root_port_nums, blk_nums, true, false); // Create a root port whose bdf is 0:1:0. - let root_port = RootPort::new(machine.clone(), alloc.clone(), 0, 1 << 3 | 0); + let root_port = RootPort::new(machine.clone(), alloc.clone(), 0, 1 << 3); let command = root_port.rp_dev.config_readw(PCI_COMMAND); let cmd_memory = command & u16::from(PCI_COMMAND_MEMORY); @@ -1303,9 +1298,8 @@ fn test_out_boundary_config_access() { let (test_state, machine, alloc, image_paths) = set_up(root_port_nums, blk_nums, true, false); let devfn = 1 << 3 | 1; - let addr = machine.borrow().pci_bus.borrow().ecam_alloc_ptr - + u64::from((0 as u32) << 20 | (devfn as u32) << 12 | 0 as u32) - - 1; + let addr = + machine.borrow().pci_bus.borrow().ecam_alloc_ptr + u64::from((devfn as u32) << 12) - 1; let write_value = u16::max_value(); let buf = write_value.to_le_bytes(); @@ -1326,7 +1320,7 @@ fn test_out_size_config_access() { let (test_state, machine, alloc, image_paths) = set_up(root_port_nums, blk_nums, true, false); // Create a root port whose bdf is 0:1:0. - let root_port = RootPort::new(machine.clone(), alloc.clone(), 0, 1 << 3 | 0); + let root_port = RootPort::new(machine.clone(), alloc.clone(), 0, 1 << 3); let vendor_device_id = root_port.rp_dev.config_readl(PCI_VENDOR_ID); let command_status = root_port.rp_dev.config_readl(PCI_COMMAND); @@ -1347,7 +1341,7 @@ fn test_out_boundary_msix_access() { let (test_state, machine, alloc, image_paths) = set_up(root_port_nums, blk_nums, true, false); // Create a root port whose bdf is 0:1:0. - let root_port = RootPort::new(machine.clone(), alloc.clone(), 0, 1 << 3 | 0); + let root_port = RootPort::new(machine.clone(), alloc.clone(), 0, 1 << 3); // Out-of-bounds access to the msix table. let write_value = u32::max_value(); @@ -1608,7 +1602,7 @@ fn test_alloc_abnormal_vector() { let virtqueue = blk .borrow() - .setup_virtqueue(test_state.clone(), alloc.clone(), 0 as u16); + .setup_virtqueue(test_state.clone(), alloc.clone(), 0_u16); blk.borrow() .setup_virtqueue_intr((queue_num + 2) as u16, alloc.clone(), virtqueue.clone()); blk.borrow().set_driver_ok(); @@ -1643,11 +1637,11 @@ fn test_intx_basic() { blk.borrow_mut().set_features_ok(); set_msix_disable(blk.borrow().pci_dev.clone()); - blk.borrow_mut().pci_dev.set_intx_irq_num(1 as u8); + blk.borrow_mut().pci_dev.set_intx_irq_num(1_u8); let virtqueue = blk .borrow() - .setup_virtqueue(test_state.clone(), alloc.clone(), 0 as u16); + .setup_virtqueue(test_state.clone(), alloc.clone(), 0_u16); blk.borrow().set_driver_ok(); let free_head = simple_blk_io_req( @@ -1702,11 +1696,11 @@ fn test_intx_disable() { blk.borrow_mut().set_features_ok(); set_msix_disable(blk.borrow().pci_dev.clone()); - blk.borrow_mut().pci_dev.set_intx_irq_num(1 as u8); + blk.borrow_mut().pci_dev.set_intx_irq_num(1_u8); let virtqueue = blk .borrow() - .setup_virtqueue(test_state.clone(), alloc.clone(), 0 as u16); + .setup_virtqueue(test_state.clone(), alloc.clone(), 0_u16); blk.borrow().set_driver_ok(); // Disable INTx. @@ -1784,7 +1778,7 @@ fn test_pci_hotplug_001() { machine.clone(), alloc.clone(), 0, - 1 << 3 | 0, + 1 << 3, ))); // Hotplug a block device whose id is 1 and bdf is 1:0:0. @@ -1825,7 +1819,7 @@ fn test_pci_hotplug_002() { machine.clone(), alloc.clone(), 0, - 1 << 3 | 0, + 1 << 3, ))); // Create a root port whose bdf is 0:2:0. @@ -1833,7 +1827,7 @@ fn test_pci_hotplug_002() { machine.clone(), alloc.clone(), 0, - 2 << 3 | 0, + 2 << 3, ))); // Hotplug a block device whose id is 1 and bdf is 1:0:0. @@ -1971,11 +1965,11 @@ fn test_pci_hotplug_007() { machine.clone(), alloc.clone(), 0, - 1 << 3 | 0, + 1 << 3, ))); set_msix_disable(root_port.borrow().rp_dev.clone()); - root_port.borrow_mut().rp_dev.set_intx_irq_num(1 as u8); + root_port.borrow_mut().rp_dev.set_intx_irq_num(1_u8); // Hotplug a block device whose id is 1 and bdf is 1:0:0. let bus = 1; @@ -2039,7 +2033,7 @@ fn test_pci_hotunplug_001() { machine.clone(), alloc.clone(), 0, - 1 << 3 | 0, + 1 << 3, ))); // Create a block device whose bdf is 1:0:0. @@ -2080,7 +2074,7 @@ fn test_pci_hotunplug_003() { machine.clone(), alloc.clone(), 0, - 1 << 3 | 0, + 1 << 3, ))); // Create a block device whose bdf is 1:0:0. @@ -2163,7 +2157,7 @@ fn test_pci_hotunplug_004() { machine.clone(), alloc.clone(), 0, - 1 << 3 | 0, + 1 << 3, ))); // Create root port whose bdf is 0:2:0. @@ -2171,7 +2165,7 @@ fn test_pci_hotunplug_004() { machine.clone(), alloc.clone(), 0, - 2 << 3 | 0, + 2 << 3, ))); // Create a block device whose bdf is 1:0:0. @@ -2248,7 +2242,7 @@ fn test_pci_hotunplug_005() { machine.clone(), alloc.clone(), 0, - 1 << 3 | 0, + 1 << 3, ))); let blk = create_blk(machine.clone(), 1, 0, 0); @@ -2291,7 +2285,7 @@ fn test_pci_hotunplug_007() { machine.clone(), alloc.clone(), 0, - 1 << 3 | 0, + 1 << 3, ))); // Create a block device whose bdf is 1:0:0. @@ -2338,11 +2332,11 @@ fn test_pci_hotunplug_008() { machine.clone(), alloc.clone(), 0, - 1 << 3 | 0, + 1 << 3, ))); set_msix_disable(root_port.borrow().rp_dev.clone()); - root_port.borrow_mut().rp_dev.set_intx_irq_num(1 as u8); + root_port.borrow_mut().rp_dev.set_intx_irq_num(1_u8); // Create a block device whose bdf is 1:0:0. let blk = create_blk(machine.clone(), 1, 0, 0); @@ -2399,7 +2393,7 @@ fn test_pci_hotplug_combine_001() { machine.clone(), alloc.clone(), 0, - 1 << 3 | 0, + 1 << 3, ))); let hotplug_blk_id = 0; @@ -2539,7 +2533,7 @@ fn test_pci_hotplug_combine_002() { machine.clone(), alloc.clone(), 0, - 1 << 3 | 0, + 1 << 3, ))); let hotplug_blk_id = 0; @@ -2629,7 +2623,7 @@ fn test_pci_hotplug_combine_003() { machine.clone(), alloc.clone(), 0, - 1 << 3 | 0, + 1 << 3, ))); let hotunplug_blk_id = 0; @@ -2695,7 +2689,7 @@ fn test_pci_root_port_exp_cap() { machine.clone(), alloc.clone(), 0, - 1 << 3 | 0, + 1 << 3, ))); let cap_exp_addr = root_port.borrow().rp_dev.find_capability(PCI_CAP_ID_EXP, 0); @@ -2987,7 +2981,7 @@ fn test_pci_combine_002() { machine.clone(), alloc.clone(), 0, - 1 << 3 | 0, + 1 << 3, ))); let blk = Rc::new(RefCell::new(TestVirtioPciDev::new( machine.borrow().pci_bus.clone(), diff --git a/tests/mod_test/tests/pvpanic_test.rs b/tests/mod_test/tests/pvpanic_test.rs index 03dfc678..01583a83 100644 --- a/tests/mod_test/tests/pvpanic_test.rs +++ b/tests/mod_test/tests/pvpanic_test.rs @@ -59,7 +59,7 @@ impl PvPanicDevCfg { test_machine_args.append(&mut args); } - let pvpanic_str = fmt_pvpanic_deves(self.clone()); + let pvpanic_str = fmt_pvpanic_deves(*self); args = pvpanic_str[..].split(' ').collect(); test_machine_args.append(&mut args); diff --git a/tests/mod_test/tests/scsi_test.rs b/tests/mod_test/tests/scsi_test.rs index 5ec46385..443ce74f 100644 --- a/tests/mod_test/tests/scsi_test.rs +++ b/tests/mod_test/tests/scsi_test.rs @@ -134,11 +134,7 @@ impl VirtioScsiTest { use_iothread: iothread, }; - let readonly = if scsi_type == ScsiDeviceType::ScsiHd { - false - } else { - true - }; + let readonly = scsi_type != ScsiDeviceType::ScsiHd; let scsi_devices: Vec = vec![ScsiDeviceConfig { cntlr_id: 0, device_type: scsi_type, @@ -258,7 +254,7 @@ impl VirtioScsiTest { size_of::(), ) }; - *resp = slice[0].clone(); + *resp = slice[0]; if data_in_len > 0 { data_in.append( @@ -440,8 +436,8 @@ impl TestVirtioScsiCmdReq { let mut target_lun = [0_u8; 8]; target_lun[0] = 1; target_lun[1] = target; - target_lun[2] = (lun >> 8) as u8 & 0xff; - target_lun[3] = lun as u8 & 0xff; + target_lun[2] = (lun >> 8) as u8; + target_lun[3] = lun as u8; req.lun = target_lun; req.cdb = cdb; @@ -1135,7 +1131,7 @@ fn scsi_cd_basic_test() { target, lun, data_out: None, - data_in_length: TEST_SCSI_SENSE_LEN as u32, + data_in_length: TEST_SCSI_SENSE_LEN, expect_response: VIRTIO_SCSI_S_OK, expect_status: GOOD, expect_result_data: None, @@ -2340,7 +2336,7 @@ fn send_cd_command_to_hd_test() { fn wrong_io_test() { let target = 0xff; let lun = 0xff; - let size = 1 * 1024; // Disk size: 1K. + let size = 1024; // Disk size: 1K. let mut vst = VirtioScsiTest::testcase_start_with_config(ScsiDeviceType::ScsiHd, target, lun, size, true); diff --git a/tests/mod_test/tests/serial_test.rs b/tests/mod_test/tests/serial_test.rs index 8336cfd9..0efbc529 100644 --- a/tests/mod_test/tests/serial_test.rs +++ b/tests/mod_test/tests/serial_test.rs @@ -111,7 +111,7 @@ impl SerialTest { fn get_pty_path(&mut self) -> String { let ret = self.state.borrow().qmp("{\"execute\": \"query-chardev\"}"); - if (*ret.get("return").unwrap()).as_array().unwrap().len() != 0 + if !(*ret.get("return").unwrap()).as_array().unwrap().is_empty() && (*ret.get("return").unwrap())[0].get("filename").is_some() { let filename = (*ret.get("return").unwrap())[0] @@ -120,9 +120,9 @@ impl SerialTest { .to_string() .replace('"', ""); let mut file_path: Vec<&str> = filename.split("pty:").collect(); - return file_path.pop().unwrap().to_string(); + file_path.pop().unwrap().to_string() } else { - return String::from(""); + String::from("") } } @@ -315,7 +315,7 @@ impl SerialTest { server: _, nowait: _, } => { - stream = self.connect_socket_host(&path); + stream = self.connect_socket_host(path); } } @@ -355,9 +355,9 @@ impl SerialTest { let result = match port.chardev_type { ChardevType::Pty => { let output = self.connect_pty_host(true); - output.unwrap().write(&test_data.as_bytes()) + output.unwrap().write(test_data.as_bytes()) } - _ => stream.as_ref().unwrap().write(&test_data.as_bytes()), + _ => stream.as_ref().unwrap().write(test_data.as_bytes()), }; match result { Ok(_num) => { diff --git a/tests/mod_test/tests/usb_camera_test.rs b/tests/mod_test/tests/usb_camera_test.rs index 70316d0d..13ce8c2b 100644 --- a/tests/mod_test/tests/usb_camera_test.rs +++ b/tests/mod_test/tests/usb_camera_test.rs @@ -234,7 +234,7 @@ fn qmp_plug_camera(test_state: &Rc>, id: &str, camdev: &str) let test_state = test_state.borrow_mut(); let cmd = r#"{"execute": "device_add", "arguments": {"id": "ID", "driver": "usb-camera", "cameradev": "CAMDEV"}}"#; let cmd = cmd.replace("ID", id); - let cmd = cmd.replace("CAMDEV", &camdev); + let cmd = cmd.replace("CAMDEV", camdev); test_state.qmp(&cmd) } diff --git a/tests/mod_test/tests/usb_storage_test.rs b/tests/mod_test/tests/usb_storage_test.rs index 54e35e2c..38a45a7c 100644 --- a/tests/mod_test/tests/usb_storage_test.rs +++ b/tests/mod_test/tests/usb_storage_test.rs @@ -104,10 +104,10 @@ fn data_phase( ) { let mut iovecs = Vec::new(); let ptr = guest_allocator.alloc(buf.len() as u64); - let iovec = TestIovec::new(ptr, buf.len() as usize, false); + let iovec = TestIovec::new(ptr, buf.len(), false); if !to_host { - xhci.mem_write(ptr, &buf); + xhci.mem_write(ptr, buf); } iovecs.push(iovec); diff --git a/tests/mod_test/tests/usb_test.rs b/tests/mod_test/tests/usb_test.rs index a8713926..8a5f8114 100644 --- a/tests/mod_test/tests/usb_test.rs +++ b/tests/mod_test/tests/usb_test.rs @@ -544,7 +544,7 @@ fn test_xhci_keyboard_reorder() { let buf = xhci.get_transfer_data_indirect(evt.ptr, HID_KEYBOARD_LEN); assert_eq!(buf, [0, 0, 30, 31, 32, 33, 0, 0]); // 1 2 3 4 Up - let key_list = vec![ + let key_list = [ KEYCODE_NUM1, KEYCODE_NUM1 + 1, KEYCODE_NUM1 + 2, @@ -736,7 +736,7 @@ fn test_xhci_keyboard_invalid_value() { xhci.queue_trb(slot_id, HID_DEVICE_ENDPOINT_ID, &mut trb); xhci.doorbell_write(slot_id, HID_DEVICE_ENDPOINT_ID); // NOTE: no HCE, only primary interrupter supported now. - let status = xhci.oper_regs_read(XHCI_OPER_REG_USBSTS as u64); + let status = xhci.oper_regs_read(XHCI_OPER_REG_USBSTS); assert!(status & USB_STS_HCE != USB_STS_HCE); test_state.borrow_mut().stop(); @@ -845,7 +845,7 @@ fn test_xhci_keyboard_over_transfer_ring() { xhci.queue_link_trb(slot_id, HID_DEVICE_ENDPOINT_ID, ptr, false); xhci.doorbell_write(slot_id, HID_DEVICE_ENDPOINT_ID); // Host Controller Error - let status = xhci.oper_regs_read(XHCI_OPER_REG_USBSTS as u64); + let status = xhci.oper_regs_read(XHCI_OPER_REG_USBSTS); assert!(status & USB_STS_HCE == USB_STS_HCE); xhci.reset_controller(true); @@ -856,7 +856,7 @@ fn test_xhci_keyboard_over_transfer_ring() { xhci.queue_td_by_iovec(slot_id, HID_DEVICE_ENDPOINT_ID, &mut iovecs, false); xhci.doorbell_write(slot_id, HID_DEVICE_ENDPOINT_ID); // Host Controller Error - let status = xhci.oper_regs_read(XHCI_OPER_REG_USBSTS as u64); + let status = xhci.oper_regs_read(XHCI_OPER_REG_USBSTS); assert!(status & USB_STS_HCE == USB_STS_HCE); xhci.reset_controller(true); @@ -959,35 +959,35 @@ fn test_xhci_keyboard_controller_init_invalid_register() { // Case 3: write invalid slot. xhci.pci_dev.io_writel( xhci.bar_addr, - u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_CONFIG as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_CONFIG, 0xffff, ); let config = xhci.pci_dev.io_readl( xhci.bar_addr, - u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_CONFIG as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_CONFIG, ); assert_ne!(config, 0xffff); // Case 4: invalid oper xhci.pci_dev.io_writel( xhci.bar_addr, - u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_USBSTS as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_USBSTS, 0xffff, ); let status = xhci.pci_dev.io_readl( xhci.bar_addr, - u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_USBSTS as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_USBSTS, ); assert_ne!(status, 0xffff); // Device Notify Control xhci.pci_dev.io_writel( xhci.bar_addr, - u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_DNCTRL as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_DNCTRL, 0x12345, ); let ndctrl = xhci.pci_dev.io_readl( xhci.bar_addr, - u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_DNCTRL as u64, + u64::from(XHCI_PCI_OPER_OFFSET) + XHCI_OPER_REG_DNCTRL, ); assert_eq!(ndctrl, 0x12345 & XHCI_OPER_NE_MASK); // invalid port offset. @@ -1084,7 +1084,7 @@ fn test_xhci_keyboard_controller_init_miss_step() { xhci.enable_slot(); assert!(xhci.fetch_event(PRIMARY_INTERRUPTER_ID).is_none()); // Host Controller Error - let status = xhci.oper_regs_read(XHCI_OPER_REG_USBSTS as u64); + let status = xhci.oper_regs_read(XHCI_OPER_REG_USBSTS); assert!(status & USB_STS_HCE == USB_STS_HCE); xhci.reset_controller(false); @@ -1108,7 +1108,7 @@ fn test_xhci_keyboard_controller_init_miss_step() { xhci.address_device(slot_id, false, port_id); assert!(xhci.fetch_event(PRIMARY_INTERRUPTER_ID).is_none()); // Host Controller Error - let status = xhci.oper_regs_read(XHCI_OPER_REG_USBSTS as u64); + let status = xhci.oper_regs_read(XHCI_OPER_REG_USBSTS); assert!(status & USB_STS_HCE == USB_STS_HCE); xhci.reset_controller(false); @@ -1330,7 +1330,7 @@ fn test_xhci_keyboard_over_command_ring() { xhci.queue_link_trb(0, 0, ptr, false); xhci.doorbell_write(0, 0); // Host Controller Error - let status = xhci.oper_regs_read(XHCI_OPER_REG_USBSTS as u64); + let status = xhci.oper_regs_read(XHCI_OPER_REG_USBSTS); assert!(status & USB_STS_HCE == USB_STS_HCE); xhci.reset_controller(true); @@ -1766,7 +1766,7 @@ fn test_xhci_keyboard_device_init_reset_device() { let slot_id = evt.get_slot_id(); // Case 1: reset after enable slot. xhci.reset_device(slot_id); - let status = xhci.oper_regs_read(XHCI_OPER_REG_USBSTS as u64); + let status = xhci.oper_regs_read(XHCI_OPER_REG_USBSTS); assert!(status & USB_STS_HCE == USB_STS_HCE); xhci.reset_controller(true); @@ -2040,9 +2040,9 @@ fn test_xhci_tablet_basic() { [ i as u8 % 3, (i * 10) as u8, - (i * 10 >> 8) as u8, + ((i * 10) >> 8) as u8, (i * 20) as u8, - (i * 20 >> 8) as u8, + ((i * 20) >> 8) as u8, 0, 0 ] @@ -2053,9 +2053,9 @@ fn test_xhci_tablet_basic() { [ 0, (i * 10) as u8, - (i * 10 >> 8) as u8, + ((i * 10) >> 8) as u8, (i * 20) as u8, - (i * 20 >> 8) as u8, + ((i * 20) >> 8) as u8, 0, 0 ] @@ -2433,11 +2433,11 @@ fn test_xhci_disable_interrupt() { // Case: disable USB_CMD_INTE qmp_send_pointer_event(test_state.borrow_mut(), 100, 200, 0, true); xhci.queue_direct_td(slot_id, HID_DEVICE_ENDPOINT_ID, HID_POINTER_LEN); - let value = xhci.oper_regs_read(XHCI_OPER_REG_USBCMD as u64); + let value = xhci.oper_regs_read(XHCI_OPER_REG_USBCMD); xhci.oper_regs_write(XHCI_OPER_REG_USBCMD, value & !USB_CMD_INTE); xhci.doorbell_write(slot_id, HID_DEVICE_ENDPOINT_ID); assert!(xhci.fetch_event(PRIMARY_INTERRUPTER_ID).is_none()); - let value = xhci.oper_regs_read(XHCI_OPER_REG_USBCMD as u64); + let value = xhci.oper_regs_read(XHCI_OPER_REG_USBCMD); xhci.oper_regs_write(XHCI_OPER_REG_USBCMD, value | USB_CMD_INTE); let evt = xhci.fetch_event(PRIMARY_INTERRUPTER_ID).unwrap(); assert_eq!(evt.ccode, TRBCCode::Success as u32); @@ -2447,8 +2447,7 @@ fn test_xhci_disable_interrupt() { // Case: disable IMAN_IE qmp_send_pointer_event(test_state.borrow_mut(), 100, 200, 0, true); xhci.queue_direct_td(slot_id, HID_DEVICE_ENDPOINT_ID, HID_POINTER_LEN); - let value = - xhci.interrupter_regs_read(PRIMARY_INTERRUPTER_ID as u64, XHCI_INTR_REG_IMAN as u64); + let value = xhci.interrupter_regs_read(PRIMARY_INTERRUPTER_ID as u64, XHCI_INTR_REG_IMAN); xhci.interrupter_regs_write( PRIMARY_INTERRUPTER_ID as u64, XHCI_INTR_REG_IMAN, diff --git a/tests/mod_test/tests/virtio_gpu_test.rs b/tests/mod_test/tests/virtio_gpu_test.rs index 26d9c1c5..c9baef23 100644 --- a/tests/mod_test/tests/virtio_gpu_test.rs +++ b/tests/mod_test/tests/virtio_gpu_test.rs @@ -60,19 +60,19 @@ fn image_display_fun() { let (dpy, gpu) = set_up(&gpu_cfg); let image_addr = gpu.borrow_mut().allocator.borrow_mut().alloc(image_size); - let image_byte_0 = vec![0 as u8; 1]; - let image_byte_1 = vec![1 as u8; 1]; - let image_0 = vec![0 as u8; image_size as usize]; + let image_byte_0 = vec![0_u8; 1]; + let image_byte_1 = vec![1_u8; 1]; + let image_0 = vec![0_u8; image_size as usize]; // image with half data 1 - let mut image_half_1 = vec![0 as u8; image_size as usize]; + let mut image_half_1 = vec![0_u8; image_size as usize]; let mut i = 0; while i < image_size / 2 { image_half_1[i as usize] = 1; i += 1; } // image with quarter data1 - let mut image_quarter_1 = vec![0 as u8; image_size as usize]; + let mut image_quarter_1 = vec![0_u8; image_size as usize]; let mut i = 0; while i < image_size / 4 { image_quarter_1[i as usize] = 1; @@ -190,9 +190,9 @@ fn image_display_fun() { #[test] fn cursor_display_fun() { - let image_0: Vec = vec![0 as u8; D_CURSOR_IMG_SIZE as usize]; - let image_1: Vec = vec![1 as u8; D_CURSOR_IMG_SIZE as usize]; - let image_byte_1 = vec![1 as u8; 1]; + let image_0: Vec = vec![0_u8; D_CURSOR_IMG_SIZE as usize]; + let image_1: Vec = vec![1_u8; D_CURSOR_IMG_SIZE as usize]; + let image_byte_1 = vec![1_u8; 1]; let image_size = cal_image_hostmem(D_FMT, D_CURSOR_WIDTH, D_CURSOR_HEIGHT); let image_size = image_size.0.unwrap() as u64; @@ -676,7 +676,7 @@ fn cursor_update_dfx() { gpu.borrow_mut().allocator.borrow_mut().alloc(image_size); let image_empty: Vec = vec![]; - let image_0: Vec = vec![0 as u8; D_CURSOR_IMG_SIZE as usize]; + let image_0: Vec = vec![0_u8; D_CURSOR_IMG_SIZE as usize]; // invalid scanout id assert!(current_curosr_check(&dpy, &image_empty)); diff --git a/tests/mod_test/tests/virtio_test.rs b/tests/mod_test/tests/virtio_test.rs index 2acebf3f..0c4a12f4 100644 --- a/tests/mod_test/tests/virtio_test.rs +++ b/tests/mod_test/tests/virtio_test.rs @@ -128,7 +128,6 @@ fn init_device_step( vqs = blk .borrow_mut() .init_virtqueue(test_state.clone(), alloc.clone(), 1); - () } 8 => { blk.borrow().set_driver_ok(); @@ -140,7 +139,7 @@ fn init_device_step( // Try to send write and read request to StratoVirt, ignore // the interrupt from device. - if vqs.len() > 0 { + if !vqs.is_empty() { let (_, _) = add_request( test_state.clone(), alloc.clone(), @@ -193,7 +192,7 @@ fn check_queue(blk: Rc>, desc: u64, avail: u64, used: let addr = blk .borrow() .pci_dev - .io_readl(bar, common_base as u64 + offset as u64); + .io_readl(bar, common_base + offset as u64); assert_eq!(addr, value as u32); } } @@ -455,11 +454,10 @@ fn virtio_feature_indirect() { let offset = u64::from(free_head) * VRING_DESC_SIZE + offset_of!(VringDesc, flags) as u64; test_state .borrow() - .writew(vqs[0].borrow().desc + offset as u64, VRING_DESC_F_NEXT); - test_state.borrow().writew( - vqs[0].borrow().desc + offset as u64 + 2, - free_head as u16 + 1, - ); + .writew(vqs[0].borrow().desc + offset, VRING_DESC_F_NEXT); + test_state + .borrow() + .writew(vqs[0].borrow().desc + offset + 2, free_head as u16 + 1); let mut indirect_req = TestVringIndirectDesc::new(); indirect_req.setup(alloc.clone(), test_state.clone(), 2); indirect_req.add_desc(test_state.clone(), req_addr + 8, 520, false); @@ -488,11 +486,10 @@ fn virtio_feature_indirect() { let offset = u64::from(free_head) * VRING_DESC_SIZE + offset_of!(VringDesc, flags) as u64; test_state .borrow() - .writew(vqs[0].borrow().desc + offset as u64, VRING_DESC_F_NEXT); - test_state.borrow().writew( - vqs[0].borrow().desc + offset as u64 + 2, - free_head as u16 + 1, - ); + .writew(vqs[0].borrow().desc + offset, VRING_DESC_F_NEXT); + test_state + .borrow() + .writew(vqs[0].borrow().desc + offset + 2, free_head as u16 + 1); let mut indirect_req = TestVringIndirectDesc::new(); indirect_req.setup(alloc.clone(), test_state.clone(), 2); indirect_req.add_desc(test_state.clone(), req_addr + 8, 8, false); @@ -598,11 +595,10 @@ fn virtio_feature_indirect_and_event_idx() { let offset = u64::from(free_head) * VRING_DESC_SIZE + offset_of!(VringDesc, flags) as u64; test_state .borrow() - .writew(vqs[0].borrow().desc + offset as u64, VRING_DESC_F_NEXT); - test_state.borrow().writew( - vqs[0].borrow().desc + offset as u64 + 2, - free_head as u16 + 1, - ); + .writew(vqs[0].borrow().desc + offset, VRING_DESC_F_NEXT); + test_state + .borrow() + .writew(vqs[0].borrow().desc + offset + 2, free_head as u16 + 1); // 2 desc elems in indirect desc table. let mut indirect_req = TestVringIndirectDesc::new(); indirect_req.setup(alloc.clone(), test_state.clone(), 2); @@ -949,7 +945,7 @@ fn virtio_init_device_abnormal_vring_info() { + u64::from(size_of::() as u32 * (3 + queue_size)) + u64::from(VIRTIO_PCI_VRING_ALIGN) - 1) - & !(u64::from(VIRTIO_PCI_VRING_ALIGN) - 1) + 16; + & (!(u64::from(VIRTIO_PCI_VRING_ALIGN) - 1) + 16); vq.borrow_mut().used = used + 16; match err_type { @@ -1599,11 +1595,10 @@ fn virtio_io_abnormal_desc_flags_2() { let offset = u64::from(free_head) * VRING_DESC_SIZE + offset_of!(VringDesc, flags) as u64; test_state .borrow() - .writew(vqs[0].borrow().desc + offset as u64, VRING_DESC_F_NEXT); - test_state.borrow().writew( - vqs[0].borrow().desc + offset as u64 + 2, - free_head as u16 + 1, - ); + .writew(vqs[0].borrow().desc + offset, VRING_DESC_F_NEXT); + test_state + .borrow() + .writew(vqs[0].borrow().desc + offset + 2, free_head as u16 + 1); let mut indirect_req = TestVringIndirectDesc::new(); indirect_req.setup(alloc.clone(), test_state.clone(), 2); indirect_req.add_desc( @@ -1674,11 +1669,10 @@ fn virtio_io_abnormal_desc_flags_3() { let offset = u64::from(free_head) * VRING_DESC_SIZE + offset_of!(VringDesc, flags) as u64; test_state .borrow() - .writew(vqs[0].borrow().desc + offset as u64, VRING_DESC_F_NEXT); - test_state.borrow().writew( - vqs[0].borrow().desc + offset as u64 + 2, - free_head as u16 + 1, - ); + .writew(vqs[0].borrow().desc + offset, VRING_DESC_F_NEXT); + test_state + .borrow() + .writew(vqs[0].borrow().desc + offset + 2, free_head as u16 + 1); let mut indirect_req = TestVringIndirectDesc::new(); indirect_req.setup(alloc.clone(), test_state.clone(), 2); indirect_req.add_desc(test_state.clone(), req_addr + 8, 520, false); @@ -1875,11 +1869,10 @@ fn virtio_io_abnormal_indirect_desc_elem_num() { let offset = u64::from(free_head) * VRING_DESC_SIZE + offset_of!(VringDesc, flags) as u64; test_state .borrow() - .writew(vqs[0].borrow().desc + offset as u64, VRING_DESC_F_NEXT); - test_state.borrow().writew( - vqs[0].borrow().desc + offset as u64 + 2, - free_head as u16 + 1, - ); + .writew(vqs[0].borrow().desc + offset, VRING_DESC_F_NEXT); + test_state + .borrow() + .writew(vqs[0].borrow().desc + offset + 2, free_head as u16 + 1); let mut indirect_req = TestVringIndirectDesc::new(); indirect_req.setup(alloc.clone(), test_state.clone(), queue_size as u16 + 1); for i in 0..queue_size { diff --git a/tests/mod_test/tests/virtiofs_test.rs b/tests/mod_test/tests/virtiofs_test.rs index 941626a4..99105aab 100644 --- a/tests/mod_test/tests/virtiofs_test.rs +++ b/tests/mod_test/tests/virtiofs_test.rs @@ -156,7 +156,7 @@ impl VirtioFsTest { if let Some(member) = reqmember { let member_size = member.len() as u64; let member_addr = self.allocator.borrow_mut().alloc(member_size); - self.state.borrow().memwrite(member_addr, &member); + self.state.borrow().memwrite(member_addr, member); data_entries.push(TestVringDescEntry { data: member_addr, len: member_size as u32, @@ -299,7 +299,7 @@ impl VirtioFsTest { if let Some(path) = absolute_virtiofs_sock { let path_clone = path.clone(); let sock_path = Path::new(&path_clone); - assert_eq!(sock_path.exists(), true); + assert!(sock_path.exists()); self.state.borrow_mut().stop(); } else { self.state.borrow_mut().stop(); @@ -339,10 +339,10 @@ fn fuse_init(fs: &VirtioFsTest) -> (FuseOutHeader, FuseInitOut) { let fuse_out_head = FuseOutHeader::default(); let fuse_init_out = FuseInitOut::default(); let (outheaderaddr, outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), - &fuse_init_in.as_bytes(), - &fuse_out_head.as_bytes(), - &fuse_init_out.as_bytes(), + fuse_in_head.as_bytes(), + fuse_init_in.as_bytes(), + fuse_out_head.as_bytes(), + fuse_init_out.as_bytes(), ); let out_header = read_obj::(fs.state.clone(), outheaderaddr); @@ -356,15 +356,13 @@ fn fuse_destroy(fs: &VirtioFsTest) -> FuseOutHeader { let fuse_in_head = FuseInHeader::new(len as u32, FUSE_DESTROY, 0, 0, 0, 0, 0, 0); let fuse_out_head = FuseOutHeader::default(); let (_, _, outheaderaddr, _outbodyaddr) = fs.do_virtio_request( - Some(&fuse_in_head.as_bytes()), + Some(fuse_in_head.as_bytes()), None, - Some(&fuse_out_head.as_bytes()), + Some(fuse_out_head.as_bytes()), None, ); - let out_header = read_obj::(fs.state.clone(), outheaderaddr.unwrap()); - - out_header + read_obj::(fs.state.clone(), outheaderaddr.unwrap()) } fn fuse_lookup(fs: &VirtioFsTest, name: String) -> u64 { @@ -375,10 +373,10 @@ fn fuse_lookup(fs: &VirtioFsTest, name: String) -> u64 { let fuse_out_head = FuseOutHeader::default(); let fuse_lookup_out = FuseEntryOut::default(); let (_outheaderaddr, outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), + fuse_in_head.as_bytes(), &fuse_lookup_in.as_bytes(), - &fuse_out_head.as_bytes(), - &fuse_lookup_out.as_bytes(), + fuse_out_head.as_bytes(), + fuse_lookup_out.as_bytes(), ); let entry_out = read_obj::(fs.state.clone(), outbodyaddr); @@ -396,10 +394,10 @@ fn fuse_open(fs: &VirtioFsTest, nodeid: u64) -> u64 { let fuse_out_head = FuseOutHeader::default(); let fuse_open_out = FuseOpenOut::default(); let (outheaderaddr, outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), - &fuse_open_in.as_bytes(), - &fuse_out_head.as_bytes(), - &fuse_open_out.as_bytes(), + fuse_in_head.as_bytes(), + fuse_open_in.as_bytes(), + fuse_out_head.as_bytes(), + fuse_open_out.as_bytes(), ); let out_header = read_obj::(fs.state.clone(), outheaderaddr); @@ -419,10 +417,10 @@ fn fuse_open_dir(fs: &VirtioFsTest, nodeid: u64) -> u64 { let fuse_out_head = FuseOutHeader::default(); let fuse_open_out = FuseOpenOut::default(); let (outheaderaddr, outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), - &fuse_open_in.as_bytes(), - &fuse_out_head.as_bytes(), - &fuse_open_out.as_bytes(), + fuse_in_head.as_bytes(), + fuse_open_in.as_bytes(), + fuse_out_head.as_bytes(), + fuse_open_out.as_bytes(), ); let out_header = read_obj::(fs.state.clone(), outheaderaddr); @@ -452,10 +450,10 @@ fn fuse_lseek( let len = (size_of::() + trim_lseek_in_len) as u32; let fuse_in_head = FuseInHeader::new(len, FUSE_LSEEK, 0, nodeid, 0, 0, 0, 0); let (outheaderaddr, outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), + fuse_in_head.as_bytes(), &fuse_lseek_in.as_bytes()[0..lseek_in_len - trim], - &fuse_out_head.as_bytes(), - &fuse_lseek_out.as_bytes(), + fuse_out_head.as_bytes(), + fuse_lseek_out.as_bytes(), ); let out_header = read_obj::(fs.state.clone(), outheaderaddr); @@ -475,10 +473,10 @@ fn fuse_getattr(fs: &VirtioFsTest, nodeid: u64, fh: u64) -> (FuseOutHeader, Fuse let fuse_out_head = FuseOutHeader::default(); let fuse_getattr_out = FuseAttrOut::default(); let (outheaderaddr, outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), - &fuse_getattr_in.as_bytes(), - &fuse_out_head.as_bytes(), - &fuse_getattr_out.as_bytes(), + fuse_in_head.as_bytes(), + fuse_getattr_in.as_bytes(), + fuse_out_head.as_bytes(), + fuse_getattr_out.as_bytes(), ); let out_header = read_obj::(fs.state.clone(), outheaderaddr); @@ -568,10 +566,10 @@ fn mkdir_test() { let fuse_out_head = FuseOutHeader::default(); let fuse_mkdir_out = FuseEntryOut::default(); let (outheaderaddr, _outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), + fuse_in_head.as_bytes(), &fuse_mkdir_in.as_bytes(), - &fuse_out_head.as_bytes(), - &fuse_mkdir_out.as_bytes(), + fuse_out_head.as_bytes(), + fuse_mkdir_out.as_bytes(), ); // Check. @@ -582,7 +580,7 @@ fn mkdir_test() { linkpath.push_str("/shared/dir"); let linkpath_clone = linkpath.clone(); let link_path = Path::new(&linkpath_clone); - assert_eq!(link_path.is_dir(), true); + assert!(link_path.is_dir()); // kill process and clean env. fs.testcase_end(virtiofs_test_dir); @@ -619,9 +617,9 @@ fn sync_fun() { }; let fuse_out_head = FuseOutHeader::default(); let (_, _, outheader, _outbodyaddr) = fs.do_virtio_request( - Some(&fuse_in_head.as_bytes()), - Some(&fuse_fallocate_in.as_bytes()), - Some(&fuse_out_head.as_bytes()), + Some(fuse_in_head.as_bytes()), + Some(fuse_fallocate_in.as_bytes()), + Some(fuse_out_head.as_bytes()), None, ); @@ -654,9 +652,9 @@ fn syncdir_test() { }; let fuse_out_head = FuseOutHeader::default(); let (_, _, outheader, _outbodyaddr) = fs.do_virtio_request( - Some(&fuse_in_head.as_bytes()), - Some(&fuse_fallocate_in.as_bytes()), - Some(&fuse_out_head.as_bytes()), + Some(fuse_in_head.as_bytes()), + Some(fuse_fallocate_in.as_bytes()), + Some(fuse_out_head.as_bytes()), None, ); @@ -684,9 +682,9 @@ fn invalid_fuse_test() { let fuse_out_head = FuseOutHeader::default(); let fake_fuse_out_body = [0]; let (outheaderaddr, _outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), + fuse_in_head.as_bytes(), &fake_fuse_in_body, - &fuse_out_head.as_bytes(), + fuse_out_head.as_bytes(), &fake_fuse_out_body, ); @@ -805,9 +803,9 @@ fn ls_test() { let fuse_out_head = FuseOutHeader::default(); let fuse_read_out = [0; DEFAULT_READ_SIZE]; let (outheaderaddr, _outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), - &fuse_read_in.as_bytes(), - &fuse_out_head.as_bytes(), + fuse_in_head.as_bytes(), + fuse_read_in.as_bytes(), + fuse_out_head.as_bytes(), &fuse_read_out, ); let out_header = read_obj::(fs.state.clone(), outheaderaddr); @@ -820,10 +818,10 @@ fn ls_test() { let fuse_out_head = FuseOutHeader::default(); let fuse_forget_out = FuseForgetOut::default(); let (outheaderaddr, _outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), - &fuse_read_in.as_bytes(), - &fuse_out_head.as_bytes(), - &fuse_forget_out.as_bytes(), + fuse_in_head.as_bytes(), + fuse_read_in.as_bytes(), + fuse_out_head.as_bytes(), + fuse_forget_out.as_bytes(), ); let out_header = read_obj::(fs.state.clone(), outheaderaddr); assert_eq!(out_header.error, 0); @@ -840,9 +838,9 @@ fn ls_test() { let fuse_out_head = FuseOutHeader::default(); let fuse_read_out = [0_u8; DEFAULT_READ_SIZE]; let (outheaderaddr, _outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), - &fuse_read_in.as_bytes(), - &fuse_out_head.as_bytes(), + fuse_in_head.as_bytes(), + fuse_read_in.as_bytes(), + fuse_out_head.as_bytes(), &fuse_read_out, ); let out_header = read_obj::(fs.state.clone(), outheaderaddr); @@ -858,9 +856,9 @@ fn ls_test() { let fuse_out_head = FuseOutHeader::default(); let fuse_read_out = [0_u8; DEFAULT_READ_SIZE]; let (outheaderaddr, _outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), - &fuse_read_in.as_bytes(), - &fuse_out_head.as_bytes(), + fuse_in_head.as_bytes(), + fuse_read_in.as_bytes(), + fuse_out_head.as_bytes(), &fuse_read_out, ); @@ -881,10 +879,10 @@ fn fuse_setattr( let fuse_out_head = FuseOutHeader::default(); let fuse_attr_out = FuseAttrOut::default(); let (outheaderaddr, outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), - &fuse_setattr_in.as_bytes(), - &fuse_out_head.as_bytes(), - &fuse_attr_out.as_bytes(), + fuse_in_head.as_bytes(), + fuse_setattr_in.as_bytes(), + fuse_out_head.as_bytes(), + fuse_attr_out.as_bytes(), ); let out_header = read_obj::(fs.state.clone(), outheaderaddr); @@ -1012,10 +1010,10 @@ fn unlink_test() { let fuse_out_head = FuseOutHeader::default(); let fuse_unlink_out = FuseEntryOut::default(); let (outheaderaddr, _outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), + fuse_in_head.as_bytes(), &fuse_unlink_in.as_bytes(), - &fuse_out_head.as_bytes(), - &fuse_unlink_out.as_bytes(), + fuse_out_head.as_bytes(), + fuse_unlink_out.as_bytes(), ); // Check. @@ -1026,7 +1024,7 @@ fn unlink_test() { linkpath.push_str("/shared/testfile"); let linkpath_clone = linkpath.clone(); let link_path = Path::new(&linkpath_clone); - assert_eq!(link_path.exists(), false); + assert!(!link_path.exists()); // kill process and clean env. fs.testcase_end(virtiofs_test_dir); @@ -1060,10 +1058,10 @@ fn rmdir_test() { let fuse_out_head = FuseOutHeader::default(); let fuse_unlink_out = FuseEntryOut::default(); let (outheaderaddr, _outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), + fuse_in_head.as_bytes(), &fuse_unlink_in.as_bytes(), - &fuse_out_head.as_bytes(), - &fuse_unlink_out.as_bytes(), + fuse_out_head.as_bytes(), + fuse_unlink_out.as_bytes(), ); // Check. @@ -1074,7 +1072,7 @@ fn rmdir_test() { linkpath.push_str("/shared/dir"); let linkpath_clone = linkpath.clone(); let link_path = Path::new(&linkpath_clone); - assert_eq!(link_path.exists(), false); + assert!(!link_path.exists()); // kill process and clean env. fs.testcase_end(virtiofs_test_dir); @@ -1100,10 +1098,10 @@ fn symlink_test() { let fuse_out_head = FuseOutHeader::default(); let fuse_init_out = FuseEntryOut::default(); let (outheaderaddr, outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), + fuse_in_head.as_bytes(), &fuse_init_in.as_bytes(), - &fuse_out_head.as_bytes(), - &fuse_init_out.as_bytes(), + fuse_out_head.as_bytes(), + fuse_init_out.as_bytes(), ); // Check. @@ -1117,7 +1115,7 @@ fn symlink_test() { linkpath.push_str("/shared/link"); let linkpath_clone = linkpath.clone(); let link_path = Path::new(&linkpath_clone); - assert_eq!(link_path.is_symlink(), true); + assert!(link_path.is_symlink()); // Read link let node_id = fuse_lookup(&fs, linkname.clone()); @@ -1126,9 +1124,9 @@ fn symlink_test() { let fuse_out_head = FuseOutHeader::default(); let fuse_read_link_out = [0_u8; 1024]; let (_, _, outheader, outbodyaddr) = fs.do_virtio_request( - Some(&fuse_in_head.as_bytes()), + Some(fuse_in_head.as_bytes()), None, - Some(&fuse_out_head.as_bytes()), + Some(fuse_out_head.as_bytes()), Some(&fuse_read_link_out), ); @@ -1168,9 +1166,9 @@ fn fallocate_test() { }; let fuse_out_head = FuseOutHeader::default(); let (_, _, outheader, _outbodyaddr) = fs.do_virtio_request( - Some(&fuse_in_head.as_bytes()), - Some(&fuse_fallocate_in.as_bytes()), - Some(&fuse_out_head.as_bytes()), + Some(fuse_in_head.as_bytes()), + Some(fuse_fallocate_in.as_bytes()), + Some(fuse_out_head.as_bytes()), None, ); @@ -1214,10 +1212,10 @@ fn posix_file_lock_test() { let fuse_out_head = FuseOutHeader::default(); let fuse_lk_out = FuseLkOut::default(); let (outheaderaddr, outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), - &fuse_lk_in.as_bytes(), - &fuse_out_head.as_bytes(), - &fuse_lk_out.as_bytes(), + fuse_in_head.as_bytes(), + fuse_lk_in.as_bytes(), + fuse_out_head.as_bytes(), + fuse_lk_out.as_bytes(), ); // Check file is unlock. @@ -1244,10 +1242,10 @@ fn posix_file_lock_test() { let fuse_out_head = FuseOutHeader::default(); let fuse_lk_out = FuseLkOut::default(); let (outheaderaddr, _outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), - &fuse_lk_in.as_bytes(), - &fuse_out_head.as_bytes(), - &fuse_lk_out.as_bytes(), + fuse_in_head.as_bytes(), + fuse_lk_in.as_bytes(), + fuse_out_head.as_bytes(), + fuse_lk_out.as_bytes(), ); // check. @@ -1281,10 +1279,10 @@ fn mknod_test() { let fuse_out_head = FuseOutHeader::default(); let fuse_init_out = FuseEntryOut::default(); let (outheaderaddr, outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), + fuse_in_head.as_bytes(), &fuse_mknod_in.as_bytes(), - &fuse_out_head.as_bytes(), - &fuse_init_out.as_bytes(), + fuse_out_head.as_bytes(), + fuse_init_out.as_bytes(), ); // Check. @@ -1316,9 +1314,9 @@ fn get_xattr(fs: &VirtioFsTest, name: String, nodeid: u64) -> (FuseOutHeader, St let fuse_out_head = FuseOutHeader::default(); let fuse_out = [0_u8; DEFAULT_XATTR_SIZE as usize]; let (outheaderaddr, outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), + fuse_in_head.as_bytes(), &fuse_in.as_bytes(), - &fuse_out_head.as_bytes(), + fuse_out_head.as_bytes(), &fuse_out, ); @@ -1343,9 +1341,9 @@ fn flush_file(fs: &VirtioFsTest, nodeid: u64, fh: u64) { }; let fuse_out_head = FuseOutHeader::default(); let (_, _, outheader, _) = fs.do_virtio_request( - Some(&fuse_in_head.as_bytes()), - Some(&fuse_in.as_bytes()), - Some(&fuse_out_head.as_bytes()), + Some(fuse_in_head.as_bytes()), + Some(fuse_in.as_bytes()), + Some(fuse_out_head.as_bytes()), None, ); @@ -1361,10 +1359,10 @@ fn write_file(fs: &VirtioFsTest, nodeid: u64, fh: u64, write_buf: String) { let fuse_out_head = FuseOutHeader::default(); let fuse_write_out = FuseWriteOut::default(); let (outheaderaddr, outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), + fuse_in_head.as_bytes(), &fuse_write_in.as_bytes(), - &fuse_out_head.as_bytes(), - &fuse_write_out.as_bytes(), + fuse_out_head.as_bytes(), + fuse_write_out.as_bytes(), ); let out_header = read_obj::(fs.state.clone(), outheaderaddr); @@ -1384,9 +1382,9 @@ fn release_file(fs: &VirtioFsTest, nodeid: u64, fh: u64) { }; let fuse_out_head = FuseOutHeader::default(); let (_, _, outheader, _) = fs.do_virtio_request( - Some(&fuse_in_head.as_bytes()), - Some(&fuse_read_in.as_bytes()), - Some(&fuse_out_head.as_bytes()), + Some(fuse_in_head.as_bytes()), + Some(fuse_read_in.as_bytes()), + Some(fuse_out_head.as_bytes()), None, ); @@ -1407,10 +1405,10 @@ fn create_file(fs: &VirtioFsTest, name: String) -> (FuseOutHeader, FuseCreateOut let fuse_out_head = FuseOutHeader::default(); let fuse_out = FuseCreateOut::default(); let (outheaderaddr, outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), + fuse_in_head.as_bytes(), &fuse_in.as_bytes(), - &fuse_out_head.as_bytes(), - &fuse_out.as_bytes(), + fuse_out_head.as_bytes(), + fuse_out.as_bytes(), ); // Check. @@ -1470,9 +1468,9 @@ fn read_file(fs: &VirtioFsTest, nodeid: u64, fh: u64) -> String { let fuse_out_head = FuseOutHeader::default(); let fuse_out = [0_u8; DEFAULT_READ_SIZE]; let (outheaderaddr, outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), - &fuse_in.as_bytes(), - &fuse_out_head.as_bytes(), + fuse_in_head.as_bytes(), + fuse_in.as_bytes(), + fuse_out_head.as_bytes(), &fuse_out, ); @@ -1480,9 +1478,8 @@ fn read_file(fs: &VirtioFsTest, nodeid: u64, fh: u64) -> String { let out_header = read_obj::(fs.state.clone(), outheaderaddr); assert_eq!(out_header.error, 0); let fuse_read_out = fs.state.borrow().memread(outbodyaddr, 5); - let str = String::from_utf8(fuse_read_out).unwrap(); - str + String::from_utf8(fuse_read_out).unwrap() } #[test] @@ -1537,9 +1534,9 @@ fn rename_test() { let fuse_in_head = FuseInHeader::new(len, FUSE_RENAME, 0, PARENT_NODEID, 0, 0, 0, 0); let fuse_out_head = FuseOutHeader::default(); let (_, _, outheader, _outbodyaddr) = fs.do_virtio_request( - Some(&fuse_in_head.as_bytes()), + Some(fuse_in_head.as_bytes()), Some(&fuse_rename_in.as_bytes()), - Some(&fuse_out_head.as_bytes()), + Some(fuse_out_head.as_bytes()), None, ); @@ -1575,10 +1572,10 @@ fn link_test() { let fuse_out_head = FuseOutHeader::default(); let fuse_entry_out = FuseEntryOut::default(); let (outheaderaddr, outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), + fuse_in_head.as_bytes(), &fuse_rename_in.as_bytes(), - &fuse_out_head.as_bytes(), - &fuse_entry_out.as_bytes(), + fuse_out_head.as_bytes(), + fuse_entry_out.as_bytes(), ); // Check. @@ -1607,10 +1604,10 @@ fn statfs_test() { let fuse_out_head = FuseOutHeader::default(); let fuse_statfs_out = FuseKstatfs::default(); let (_, _, outheader, _outbodyaddr) = fs.do_virtio_request( - Some(&fuse_in_head.as_bytes()), + Some(fuse_in_head.as_bytes()), None, - Some(&fuse_out_head.as_bytes()), - Some(&fuse_statfs_out.as_bytes()), + Some(fuse_out_head.as_bytes()), + Some(fuse_statfs_out.as_bytes()), ); // Check. @@ -1640,9 +1637,9 @@ fn virtio_fs_fuse_ioctl_test() { let fuse_in_head = FuseInHeader::new(len, FUSE_IOCTL, 0, nodeid, 0, 0, 0, 0); let fuse_out_head = FuseOutHeader::default(); let (outheaderaddr, _outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), + fuse_in_head.as_bytes(), &[0], - &fuse_out_head.as_bytes(), + fuse_out_head.as_bytes(), &[0], ); @@ -1670,9 +1667,9 @@ fn virtio_fs_fuse_abnormal_test() { let fuse_out_head = FuseOutHeader::default(); let (outheaderaddr, _outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), + fuse_in_head.as_bytes(), &[0], - &fuse_out_head.as_bytes(), + fuse_out_head.as_bytes(), &[0], ); @@ -1716,15 +1713,13 @@ fn fuse_setxattr(fs: &VirtioFsTest, name: String, value: String, nodeid: u64) -> }; let fuse_out_head = FuseOutHeader::default(); let (_, _, outheader, _outbodyaddr) = fs.do_virtio_request( - Some(&fuse_in_head.as_bytes()), + Some(fuse_in_head.as_bytes()), Some(&fuse_setxattr_in.as_bytes()), - Some(&fuse_out_head.as_bytes()), + Some(fuse_out_head.as_bytes()), None, ); - let out_header = read_obj::(fs.state.clone(), outheader.unwrap()); - - out_header + read_obj::(fs.state.clone(), outheader.unwrap()) } fn fuse_removexattr(fs: &VirtioFsTest, name: String, nodeid: u64) -> FuseOutHeader { @@ -1733,14 +1728,13 @@ fn fuse_removexattr(fs: &VirtioFsTest, name: String, nodeid: u64) -> FuseOutHead let fuse_removexattr_in = FuseRemoveXattrIn { name }; let fuse_out_head = FuseOutHeader::default(); let (_, _, outheader, _outbodyaddr) = fs.do_virtio_request( - Some(&fuse_in_head.as_bytes()), + Some(fuse_in_head.as_bytes()), Some(&fuse_removexattr_in.as_bytes()), - Some(&fuse_out_head.as_bytes()), + Some(fuse_out_head.as_bytes()), None, ); - let out_header = read_obj::(fs.state.clone(), outheader.unwrap()); - out_header + read_obj::(fs.state.clone(), outheader.unwrap()) } fn fuse_listxattr(fs: &VirtioFsTest, nodeid: u64) -> (FuseOutHeader, u64) { @@ -1755,9 +1749,9 @@ fn fuse_listxattr(fs: &VirtioFsTest, nodeid: u64) -> (FuseOutHeader, u64) { let fuse_out_head = FuseOutHeader::default(); let fuse_out = [0_u8; DEFAULT_XATTR_SIZE as usize]; let (outheaderaddr, outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), + fuse_in_head.as_bytes(), &fuse_in.as_bytes(), - &fuse_out_head.as_bytes(), + fuse_out_head.as_bytes(), &fuse_out, ); @@ -1917,7 +1911,7 @@ fn fuse_batch_forget(fs: &VirtioFsTest, nodeid: u64, trim: usize) { ] .concat(); let (_, _) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), + fuse_in_head.as_bytes(), &data_bytes[0..data_bytes.len() - trim], &[0], &[0], @@ -2009,9 +2003,9 @@ fn virtio_fs_fuse_setlkw_test() { } let (outheaderaddr, _outbodyaddr) = fs.virtiofs_do_virtio_request( - &fuse_in_head.as_bytes(), - &fuse_lk_in_bytes, - &fuse_out_head.as_bytes(), + fuse_in_head.as_bytes(), + fuse_lk_in_bytes, + fuse_out_head.as_bytes(), &[0], ); diff --git a/tests/mod_test/tests/vnc_test.rs b/tests/mod_test/tests/vnc_test.rs index f6065c6a..d8423030 100644 --- a/tests/mod_test/tests/vnc_test.rs +++ b/tests/mod_test/tests/vnc_test.rs @@ -77,7 +77,7 @@ fn test_set_area_dirty() { let pf = RfbPixelFormat::new(32, 8, 0_u8, 1_u8, 255, 255, 255, 16, 8, 0); assert!(vnc_client.test_set_pixel_format(pf).is_ok()); assert!(vnc_client - .test_update_request(UpdateState::Incremental, 0, 0, 640 as u16, 480 as u16,) + .test_update_request(UpdateState::Incremental, 0, 0, 640_u16, 480_u16,) .is_ok()); demo_gpu.borrow_mut().update_image_area(0, 0, 64, 64); demo_gpu.borrow_mut().set_area_dirty(0, 0, 64, 64); @@ -93,7 +93,7 @@ fn test_set_area_dirty() { demo_gpu.borrow_mut().update_image_area(0, 0, 64, 64); demo_gpu.borrow_mut().set_area_dirty(0, 0, 64, 64); assert!(vnc_client - .test_update_request(UpdateState::Incremental, 0, 0, 640 as u16, 480 as u16,) + .test_update_request(UpdateState::Incremental, 0, 0, 640_u16, 480_u16,) .is_ok()); let res = vnc_client.test_recv_server_data(pf); @@ -110,7 +110,7 @@ fn test_set_area_dirty() { let pf = RfbPixelFormat::new(32, 8, 0_u8, 1_u8, 255, 255, 255, 16, 8, 0); assert!(vnc_client.test_set_pixel_format(pf).is_ok()); assert!(vnc_client - .test_update_request(UpdateState::Incremental, 0, 0, 640 as u16, 480 as u16,) + .test_update_request(UpdateState::Incremental, 0, 0, 640_u16, 480_u16,) .is_ok()); demo_gpu.borrow_mut().update_image_area(0, 0, 64, 64); demo_gpu.borrow_mut().set_area_dirty(0, 0, 64, 64); @@ -171,7 +171,7 @@ fn test_set_multiple_area_dirty() { demo_gpu.borrow_mut().update_image_area(119, 120, 160, 160); demo_gpu.borrow_mut().set_area_dirty(0, 0, 640, 480); assert!(vnc_client - .test_update_request(UpdateState::NotIncremental, 0, 0, 640 as u16, 480 as u16,) + .test_update_request(UpdateState::NotIncremental, 0, 0, 640_u16, 480_u16,) .is_ok()); let res = vnc_client.test_recv_server_data(pf); @@ -193,7 +193,7 @@ fn test_set_multiple_area_dirty() { demo_gpu.borrow_mut().update_image_area(119, 120, 160, 160); demo_gpu.borrow_mut().set_area_dirty(0, 0, 640, 480); assert!(vnc_client - .test_update_request(UpdateState::NotIncremental, 0, 0, 640 as u16, 480 as u16,) + .test_update_request(UpdateState::NotIncremental, 0, 0, 640_u16, 480_u16,) .is_ok()); let res = vnc_client.test_recv_server_data(pf); @@ -418,7 +418,7 @@ fn test_set_pixel_format() { // Raw + bit_per_pixel=32 + true_color_flag=1. let pf = RfbPixelFormat::new(32, 8, 0_u8, 1_u8, 255, 255, 255, 16, 8, 0); - assert!(vnc_client.test_set_pixel_format(pf.clone()).is_ok()); + assert!(vnc_client.test_set_pixel_format(pf).is_ok()); assert!(vnc_client .test_update_request(UpdateState::NotIncremental, 0, 0, 2560, 2048) .is_ok()); @@ -430,7 +430,7 @@ fn test_set_pixel_format() { // Raw + bit_per_pixel=16 + true_color_flag=1. let pf = RfbPixelFormat::new(16, 8, 0_u8, 1_u8, 255, 255, 255, 16, 8, 0); - assert!(vnc_client.test_set_pixel_format(pf.clone()).is_ok()); + assert!(vnc_client.test_set_pixel_format(pf).is_ok()); assert!(vnc_client .test_update_request(UpdateState::NotIncremental, 0, 0, 2560, 2048) .is_ok()); @@ -443,12 +443,12 @@ fn test_set_pixel_format() { // Raw + bit_per_pixel=8 + true_color_flag=0. let pf = RfbPixelFormat::new(8, 8, 0_u8, 0_u8, 255, 255, 255, 16, 8, 0); - assert!(vnc_client.test_set_pixel_format(pf.clone()).is_ok()); + assert!(vnc_client.test_set_pixel_format(pf).is_ok()); assert!(vnc_client .test_update_request(UpdateState::NotIncremental, 0, 0, 2560, 2048) .is_ok()); - let res = vnc_client.test_recv_server_data(pf.clone()); + let res = vnc_client.test_recv_server_data(pf); assert!(res.is_ok()); let res = res.unwrap(); assert!(res.contains(&(RfbServerMsg::FramebufferUpdate, EncodingType::EncodingRaw))); @@ -463,7 +463,7 @@ fn test_set_pixel_format() { .is_ok()); assert!(vnc_client.stream_read_to_end().is_ok()); let pf = RfbPixelFormat::new(32, 8, 0_u8, 1_u8, 255, 255, 255, 16, 8, 0); - assert!(vnc_client.test_set_pixel_format(pf.clone()).is_ok()); + assert!(vnc_client.test_set_pixel_format(pf).is_ok()); assert!(vnc_client .test_update_request(UpdateState::NotIncremental, 0, 0, 2560, 2048) .is_ok()); @@ -481,7 +481,7 @@ fn test_set_pixel_format() { .is_ok()); assert!(vnc_client.stream_read_to_end().is_ok()); let pf = RfbPixelFormat::new(8, 8, 0_u8, 1_u8, 255, 255, 255, 16, 8, 0); - assert!(vnc_client.test_set_pixel_format(pf.clone()).is_ok()); + assert!(vnc_client.test_set_pixel_format(pf).is_ok()); assert!(vnc_client .test_update_request(UpdateState::NotIncremental, 0, 0, 2560, 2048) .is_ok()); @@ -498,7 +498,7 @@ fn test_set_pixel_format() { .is_ok()); assert!(vnc_client.stream_read_to_end().is_ok()); let pf = RfbPixelFormat::new(8, 8, 0_u8, 0_u8, 255, 255, 255, 16, 8, 0); - assert!(vnc_client.test_set_pixel_format(pf.clone()).is_ok()); + assert!(vnc_client.test_set_pixel_format(pf).is_ok()); assert!(vnc_client .test_update_request(UpdateState::NotIncremental, 0, 0, 2560, 2048) .is_ok()); @@ -715,9 +715,7 @@ fn test_rfb_version_abnormal(test_state: Rc>, port: u16) -> R assert!(vnc_client.read_msg(&mut buf, 12).is_ok()); assert_eq!(buf[..12].to_vec(), "RFB 003.008\n".as_bytes().to_vec()); println!("Client Rfb version: RFB 003.010"); - assert!(vnc_client - .write_msg(&"RFB 003.010\n".as_bytes().to_vec()) - .is_ok()); + assert!(vnc_client.write_msg("RFB 003.010\n".as_bytes()).is_ok()); buf.drain(..12); // VNC server closed connection. let res = vnc_client.epoll_wait(EventSet::READ_HANG_UP); @@ -738,9 +736,7 @@ fn test_unsupported_sec_type(test_state: Rc>, port: u16) -> R println!("Connect to server."); assert!(vnc_client.read_msg(&mut buf, 12).is_ok()); assert_eq!(buf[..12].to_vec(), "RFB 003.008\n".as_bytes().to_vec()); - assert!(vnc_client - .write_msg(&"RFB 003.008\n".as_bytes().to_vec()) - .is_ok()); + assert!(vnc_client.write_msg("RFB 003.008\n".as_bytes()).is_ok()); buf.drain(..12); // Step 2: Auth num is 1. @@ -751,7 +747,7 @@ fn test_unsupported_sec_type(test_state: Rc>, port: u16) -> R assert!(vnc_client.read_msg(&mut buf, auth_num as usize).is_ok()); buf.drain(..auth_num as usize); assert!(vnc_client - .write_msg(&(TestAuthType::Invalid as u8).to_be_bytes().to_vec()) + .write_msg((TestAuthType::Invalid as u8).to_be_bytes().as_ref()) .is_ok()); // VNC server close the connection. let res = vnc_client.epoll_wait(EventSet::READ_HANG_UP); @@ -770,7 +766,7 @@ fn test_set_pixel_format_abnormal(test_state: Rc>, port: u16) let mut vnc_client = create_new_client(test_state, port).unwrap(); assert!(vnc_client.connect(TestAuthType::VncAuthNone).is_ok()); let pf = RfbPixelFormat::new(17, 8, 0_u8, 1_u8, 255, 255, 255, 16, 8, 0); - assert!(vnc_client.test_set_pixel_format(pf.clone()).is_ok()); + assert!(vnc_client.test_set_pixel_format(pf).is_ok()); // VNC server close the connection. let res = vnc_client.epoll_wait(EventSet::READ_HANG_UP)?; diff --git a/tests/mod_test/tests/x86_64/cpu_hotplug_test.rs b/tests/mod_test/tests/x86_64/cpu_hotplug_test.rs index b3b14123..6a279843 100644 --- a/tests/mod_test/tests/x86_64/cpu_hotplug_test.rs +++ b/tests/mod_test/tests/x86_64/cpu_hotplug_test.rs @@ -40,7 +40,7 @@ fn set_up(cpu: u8, max_cpus: Option) -> TestState { args = cpu_args[..].split(' ').collect(); extra_args.append(&mut args); - let mem_args = format!("-m 512"); + let mem_args = "-m 512".to_string(); args = mem_args[..].split(' ').collect(); extra_args.append(&mut args); @@ -48,11 +48,12 @@ fn set_up(cpu: u8, max_cpus: Option) -> TestState { extra_args.push("root=/dev/vda panic=1"); let uefi_drive = - format!("-drive file=/usr/share/edk2/ovmf/OVMF_CODE.fd,if=pflash,unit=0,readonly=true"); + "-drive file=/usr/share/edk2/ovmf/OVMF_CODE.fd,if=pflash,unit=0,readonly=true".to_string(); args = uefi_drive[..].split(' ').collect(); extra_args.append(&mut args); - let root_device = format!("-device pcie-root-port,port=0x0,addr=0x1.0x0,bus=pcie.0,id=pcie.1"); + let root_device = + "-device pcie-root-port,port=0x0,addr=0x1.0x0,bus=pcie.0,id=pcie.1".to_string(); args = root_device[..].split(' ').collect(); extra_args.append(&mut args); diff --git a/ui/src/console.rs b/ui/src/console.rs index 8977f1a2..40c02c3f 100644 --- a/ui/src/console.rs +++ b/ui/src/console.rs @@ -844,22 +844,22 @@ mod tests { #[test] fn test_console_select() { let con_opts = Arc::new(HwOpts {}); - let dev_name0 = format!("test_device0"); + let dev_name0 = "test_device0".to_string(); let con_0 = console_init(dev_name0, ConsoleType::Graphic, con_opts.clone()); let clone_con = con_0.clone(); assert_eq!( clone_con.unwrap().upgrade().unwrap().lock().unwrap().con_id, 0 ); - let dev_name1 = format!("test_device1"); + let dev_name1 = "test_device1".to_string(); let con_1 = console_init(dev_name1, ConsoleType::Graphic, con_opts.clone()); assert_eq!(con_1.unwrap().upgrade().unwrap().lock().unwrap().con_id, 1); - let dev_name2 = format!("test_device2"); + let dev_name2 = "test_device2".to_string(); let con_2 = console_init(dev_name2, ConsoleType::Graphic, con_opts.clone()); assert_eq!(con_2.unwrap().upgrade().unwrap().lock().unwrap().con_id, 2); assert!(console_close(&con_0).is_ok()); assert_eq!(CONSOLES.lock().unwrap().activate_id, Some(1)); - let dev_name3 = format!("test_device3"); + let dev_name3 = "test_device3".to_string(); let con_3 = console_init(dev_name3, ConsoleType::Graphic, con_opts.clone()); assert_eq!(con_3.unwrap().upgrade().unwrap().lock().unwrap().con_id, 3); assert!(console_select(Some(0)).is_ok()); diff --git a/ui/src/input.rs b/ui/src/input.rs index 59f2b931..a04f65b5 100644 --- a/ui/src/input.rs +++ b/ui/src/input.rs @@ -598,7 +598,7 @@ mod tests { assert!(key_event(12, true).is_ok()); assert_eq!(test_kdb.lock().unwrap().keycode, 12); - assert_eq!(test_kdb.lock().unwrap().down, true); + assert!(test_kdb.lock().unwrap().down); // Test point event. assert_eq!(test_mouse.lock().unwrap().button, 0); @@ -642,14 +642,14 @@ mod tests { let keysym_lists: Vec = vec![0x07D0, 0x07E1, 0x0802]; let keycode_lists: Vec = keysym_lists .iter() - .map(|x| *keysym2qkeycode.get(&x).unwrap()) + .map(|x| *keysym2qkeycode.get(x).unwrap()) .collect(); for idx in 0..keysym_lists.len() { let keysym = keycode_lists[idx]; let keycode = keycode_lists[idx]; assert!(do_key_event(true, keysym as i32, keycode).is_ok()); assert_eq!(test_kdb.lock().unwrap().keycode, keycode); - assert_eq!(test_kdb.lock().unwrap().down, true); + assert!(test_kdb.lock().unwrap().down); } let locked_input = INPUTS.lock().unwrap(); diff --git a/ui/src/utils.rs b/ui/src/utils.rs index 7bb7844d..c61ae855 100644 --- a/ui/src/utils.rs +++ b/ui/src/utils.rs @@ -182,12 +182,12 @@ mod tests { fn test_buffpool_base() { let mut buffpool = BuffPool::new(); buffpool.set_limit(Some(7)); - buffpool.append_limit((0x12345678 as u32).to_be_bytes().to_vec()); - buffpool.append_limit((0x12 as u8).to_be_bytes().to_vec()); - buffpool.append_limit((0x1234 as u16).to_be_bytes().to_vec()); - assert!(buffpool.len() == 7 as usize); + buffpool.append_limit(0x12345678_u32.to_be_bytes().to_vec()); + buffpool.append_limit(0x12_u8.to_be_bytes().to_vec()); + buffpool.append_limit(0x1234_u16.to_be_bytes().to_vec()); + assert!(buffpool.len() == 7_usize); buffpool.remove_front(1); - assert!(buffpool.len() == 6 as usize); + assert!(buffpool.len() == 6_usize); let mut buf: Vec = vec![0_u8; 4]; buffpool.read_front(&mut buf, 4); assert!(buf == vec![52, 86, 120, 18]); diff --git a/ui/src/vnc/encoding/enc_hextile.rs b/ui/src/vnc/encoding/enc_hextile.rs index 0bada3d5..d6b31f69 100644 --- a/ui/src/vnc/encoding/enc_hextile.rs +++ b/ui/src/vnc/encoding/enc_hextile.rs @@ -396,8 +396,8 @@ mod tests { let image = create_pixman_image( pixman_format_code_t::PIXMAN_x8r8g8b8, - image_width as i32, - image_height as i32, + image_width, + image_height, image_data.as_ptr() as *mut u32, image_stride, ); @@ -427,8 +427,8 @@ mod tests { let image = create_pixman_image( pixman_format_code_t::PIXMAN_x8r8g8b8, - image_width as i32, - image_height as i32, + image_width, + image_height, image_data.as_ptr() as *mut u32, image_stride, ); @@ -458,8 +458,8 @@ mod tests { let image = create_pixman_image( pixman_format_code_t::PIXMAN_x8r8g8b8, - image_width as i32, - image_height as i32, + image_width, + image_height, image_data.as_ptr() as *mut u32, image_stride, ); diff --git a/util/src/aio/mod.rs b/util/src/aio/mod.rs index ec978d80..cc666f23 100644 --- a/util/src/aio/mod.rs +++ b/util/src/aio/mod.rs @@ -18,6 +18,7 @@ mod uring; pub use raw::*; use std::clone::Clone; +use std::fmt::Display; use std::io::Write; use std::os::unix::io::RawFd; use std::sync::atomic::{AtomicI64, AtomicU32, AtomicU64, Ordering}; @@ -80,13 +81,13 @@ impl FromStr for AioEngine { } } -impl ToString for AioEngine { - fn to_string(&self) -> String { - match *self { - AioEngine::Off => "off".to_string(), - AioEngine::Native => "native".to_string(), - AioEngine::IoUring => "io_uring".to_string(), - AioEngine::Threads => "threads".to_string(), +impl Display for AioEngine { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + AioEngine::Off => write!(f, "off"), + AioEngine::Native => write!(f, "native"), + AioEngine::IoUring => write!(f, "io_uring"), + AioEngine::Threads => write!(f, "threads"), } } } @@ -862,7 +863,7 @@ mod tests { assert!(opcode == OpCode::Preadv || opcode == OpCode::Pwritev); // Init a file with special content. let mut content = vec![0u8; fsize]; - for (index, elem) in content.as_mut_slice().into_iter().enumerate() { + for (index, elem) in content.as_mut_slice().iter_mut().enumerate() { *elem = index as u8; } let tmp_file = TempFile::new().unwrap(); @@ -955,7 +956,7 @@ mod tests { fn test_sync_rw_all_align(opcode: OpCode, direct: bool) { let basic_align = 512; - test_sync_rw(opcode, direct, basic_align << 0); + test_sync_rw(opcode, direct, basic_align); test_sync_rw(opcode, direct, basic_align << 1); test_sync_rw(opcode, direct, basic_align << 2); test_sync_rw(opcode, direct, basic_align << 3); diff --git a/util/src/arg_parser.rs b/util/src/arg_parser.rs index ad7d1fcb..9ab97169 100644 --- a/util/src/arg_parser.rs +++ b/util/src/arg_parser.rs @@ -800,7 +800,7 @@ mod tests { arg_parser.output_help(&mut buffer.inner); let help_str = buffer.get_msg_vec(); - let help_msg = help_str.split("\n").collect::>(); + let help_msg = help_str.split('\n').collect::>(); assert_eq!(help_msg[0], "StratoVirt 1.0.0"); assert_eq!(help_msg[1], "Huawei Technologies Co., Ltd"); assert_eq!(help_msg[2], "A light kvm-based hypervisor."); @@ -832,10 +832,10 @@ mod tests { arg.possible_values.as_ref().unwrap(), &vec!["vm1", "vm2", "vm3"] ); - assert_eq!(arg.required, false); - assert_eq!(arg.presented, true); - assert_eq!(arg.hiddable, false); - assert_eq!(arg.can_no_value, false); + assert!(!arg.required); + assert!(arg.presented); + assert!(!arg.hiddable); + assert!(!arg.can_no_value); assert_eq!(arg.value.as_ref().unwrap(), "vm1"); let (help_msg, help_type) = arg.help_message(); diff --git a/util/src/bitmap.rs b/util/src/bitmap.rs index fed47e0f..ae6afeb2 100644 --- a/util/src/bitmap.rs +++ b/util/src/bitmap.rs @@ -434,12 +434,12 @@ mod tests { let mut bitmap = Bitmap::::new(1); assert!(bitmap.set(15).is_ok()); assert!(bitmap.set(16).is_err()); - assert_eq!(bitmap.contain(15).unwrap(), true); + assert!(bitmap.contain(15).unwrap()); assert_eq!(bitmap.count_front_bits(16).unwrap(), 1); assert_eq!(bitmap.count_front_bits(15).unwrap(), 0); assert!(bitmap.change(15).is_ok()); assert!(bitmap.change(16).is_err()); - assert_eq!(bitmap.contain(15).unwrap(), false); + assert!(!bitmap.contain(15).unwrap()); } #[test] @@ -451,25 +451,25 @@ mod tests { bitmap.clear_all(); assert!(bitmap.set_range(65, 10).is_ok()); - assert_eq!(bitmap.contain(64).unwrap(), false); - assert_eq!(bitmap.contain(65).unwrap(), true); - assert_eq!(bitmap.contain(70).unwrap(), true); - assert_eq!(bitmap.contain(74).unwrap(), true); - assert_eq!(bitmap.contain(75).unwrap(), false); + assert!(!bitmap.contain(64).unwrap()); + assert!(bitmap.contain(65).unwrap()); + assert!(bitmap.contain(70).unwrap()); + assert!(bitmap.contain(74).unwrap()); + assert!(!bitmap.contain(75).unwrap()); bitmap.clear_all(); assert!(bitmap.set_range(63, 1).is_ok()); - assert_eq!(bitmap.contain(62).unwrap(), false); - assert_eq!(bitmap.contain(63).unwrap(), true); - assert_eq!(bitmap.contain(64).unwrap(), false); + assert!(!bitmap.contain(62).unwrap()); + assert!(bitmap.contain(63).unwrap()); + assert!(!bitmap.contain(64).unwrap()); bitmap.clear_all(); assert!(bitmap.set_range(63, 66).is_ok()); - assert_eq!(bitmap.contain(62).unwrap(), false); - assert_eq!(bitmap.contain(63).unwrap(), true); - assert_eq!(bitmap.contain(67).unwrap(), true); - assert_eq!(bitmap.contain(128).unwrap(), true); - assert_eq!(bitmap.contain(129).unwrap(), false); + assert!(!bitmap.contain(62).unwrap()); + assert!(bitmap.contain(63).unwrap()); + assert!(bitmap.contain(67).unwrap()); + assert!(bitmap.contain(128).unwrap()); + assert!(!bitmap.contain(129).unwrap()); bitmap.clear_all(); } @@ -483,25 +483,25 @@ mod tests { assert!(bitmap.set_range(0, 256).is_ok()); assert!(bitmap.clear_range(65, 10).is_ok()); - assert_eq!(bitmap.contain(64).unwrap(), true); - assert_eq!(bitmap.contain(65).unwrap(), false); - assert_eq!(bitmap.contain(70).unwrap(), false); - assert_eq!(bitmap.contain(74).unwrap(), false); - assert_eq!(bitmap.contain(75).unwrap(), true); + assert!(bitmap.contain(64).unwrap()); + assert!(!bitmap.contain(65).unwrap()); + assert!(!bitmap.contain(70).unwrap()); + assert!(!bitmap.contain(74).unwrap()); + assert!(bitmap.contain(75).unwrap()); assert!(bitmap.set_range(0, 256).is_ok()); assert!(bitmap.clear_range(63, 1).is_ok()); - assert_eq!(bitmap.contain(62).unwrap(), true); - assert_eq!(bitmap.contain(63).unwrap(), false); - assert_eq!(bitmap.contain(64).unwrap(), true); + assert!(bitmap.contain(62).unwrap()); + assert!(!bitmap.contain(63).unwrap()); + assert!(bitmap.contain(64).unwrap()); assert!(bitmap.set_range(0, 256).is_ok()); assert!(bitmap.clear_range(63, 66).is_ok()); - assert_eq!(bitmap.contain(62).unwrap(), true); - assert_eq!(bitmap.contain(63).unwrap(), false); - assert_eq!(bitmap.contain(67).unwrap(), false); - assert_eq!(bitmap.contain(128).unwrap(), false); - assert_eq!(bitmap.contain(129).unwrap(), true); + assert!(bitmap.contain(62).unwrap()); + assert!(!bitmap.contain(63).unwrap()); + assert!(!bitmap.contain(67).unwrap()); + assert!(!bitmap.contain(128).unwrap()); + assert!(bitmap.contain(129).unwrap()); assert!(bitmap.clear_range(0, 256).is_ok()); } diff --git a/util/src/daemonize.rs b/util/src/daemonize.rs index d6244065..f693abb4 100644 --- a/util/src/daemonize.rs +++ b/util/src/daemonize.rs @@ -50,6 +50,7 @@ fn create_pid_file(path: &str) -> Result<()> { let mut pid_file: File = OpenOptions::new() .write(true) .create(true) + .truncate(true) .mode(0o600) .open(path)?; write!(pid_file, "{}", pid)?; diff --git a/util/src/logger.rs b/util/src/logger.rs index 1652d83c..c5f6aec7 100644 --- a/util/src/logger.rs +++ b/util/src/logger.rs @@ -193,7 +193,6 @@ fn init_logger_with_env(logfile: Box, logfile_path: String) -> fn open_log_file(path: &str) -> Result { std::fs::OpenOptions::new() .read(false) - .write(true) .append(true) .create(true) .mode(0o640) diff --git a/util/src/loop_context.rs b/util/src/loop_context.rs index 957fdb4c..ced2af40 100644 --- a/util/src/loop_context.rs +++ b/util/src/loop_context.rs @@ -675,7 +675,7 @@ impl EventLoopContext { match ppoll(&mut pollfds, time_out_spec, None) { Ok(_) => time_out = Some(Duration::ZERO), - Err(e) if e == Errno::EINTR => time_out = Some(Duration::ZERO), + Err(Errno::EINTR) => time_out = Some(Duration::ZERO), Err(e) => return Err(anyhow!(UtilError::EpollWait(e.into()))), }; } @@ -757,12 +757,9 @@ mod test { impl EventLoopContext { fn check_existence(&self, fd: RawFd) -> Option { let events_map = self.events.read().unwrap(); - match events_map.get(&fd) { - None => { - return None; - } - Some(notifier) => Some(*notifier.status.lock().unwrap() == EventStatus::Alive), - } + events_map + .get(&fd) + .map(|notifier| *notifier.status.lock().unwrap() == EventStatus::Alive) } fn create_event(&mut self) -> i32 { @@ -803,8 +800,7 @@ mod test { let fd1_related = EventFd::new(EFD_NONBLOCK).unwrap(); let handler1 = generate_handler(fd1_related.as_raw_fd()); - let mut handlers = Vec::new(); - handlers.push(handler1); + let handlers = vec![handler1]; let event1 = EventNotifier::new( NotifierOperation::AddShared, fd1.as_raw_fd(), diff --git a/util/src/num_ops.rs b/util/src/num_ops.rs index bf193ce3..558f57bf 100644 --- a/util/src/num_ops.rs +++ b/util/src/num_ops.rs @@ -496,13 +496,13 @@ mod test { #[test] fn round_up_test() { - let result = round_up(10001 as u64, 100 as u64); + let result = round_up(10001_u64, 100_u64); assert_eq!(result, Some(10100)); } #[test] fn round_down_test() { - let result = round_down(10001 as u64, 100 as u64); + let result = round_down(10001_u64, 100_u64); assert_eq!(result, Some(10000)); } diff --git a/util/src/unix.rs b/util/src/unix.rs index ae1b1a41..2640d948 100644 --- a/util/src/unix.rs +++ b/util/src/unix.rs @@ -113,7 +113,7 @@ pub fn do_mmap( // SAFETY: The return value is checked. let hva = unsafe { libc::mmap( - std::ptr::null_mut() as *mut libc::c_void, + std::ptr::null_mut(), len as libc::size_t, prot, flags, @@ -418,7 +418,7 @@ impl UnixSock { while !cmsg_ptr.is_null() { // SAFETY: The pointer of cmsg_ptr was created in this function and // can be guaranteed not be null. - let cmsg = unsafe { (cmsg_ptr as *mut cmsghdr).read_unaligned() }; + let cmsg = unsafe { cmsg_ptr.read_unaligned() }; if cmsg.cmsg_level == SOL_SOCKET && cmsg.cmsg_type == SCM_RIGHTS { // SAFETY: Input parameter is constant. @@ -488,7 +488,7 @@ mod tests { assert_ne!(stream.get_stream_raw_fd(), 0); assert!(listener.accept().is_ok()); - assert_eq!(listener.is_accepted(), true); + assert!(listener.is_accepted()); if sock_path.exists() { fs::remove_file("./test_socket1.sock").unwrap(); diff --git a/util/src/v4l2.rs b/util/src/v4l2.rs index 545e264e..1e289050 100644 --- a/util/src/v4l2.rs +++ b/util/src/v4l2.rs @@ -136,7 +136,7 @@ impl V4l2Backend { // 2. buf can be guaranteed not be null. let ret = unsafe { libc::mmap( - std::ptr::null_mut() as *mut libc::c_void, + std::ptr::null_mut(), buf.length as libc::size_t, libc::PROT_WRITE | libc::PROT_READ, libc::MAP_SHARED, diff --git a/virtio/src/device/balloon.rs b/virtio/src/device/balloon.rs index 19fb5dfa..aa19e88a 100644 --- a/virtio/src/device/balloon.rs +++ b/virtio/src/device/balloon.rs @@ -1497,10 +1497,10 @@ mod tests { .write_object::(&ele, GuestAddress(0x2000)) .unwrap(); mem_space - .write_object::(&0, GuestAddress(queue_config_inf.avail_ring.0 + 4 as u64)) + .write_object::(&0, GuestAddress(queue_config_inf.avail_ring.0 + 4_u64)) .unwrap(); mem_space - .write_object::(&1, GuestAddress(queue_config_inf.avail_ring.0 + 2 as u64)) + .write_object::(&1, GuestAddress(queue_config_inf.avail_ring.0 + 2_u64)) .unwrap(); assert!(handler.process_balloon_queue(BALLOON_INFLATE_EVENT).is_ok()); @@ -1523,10 +1523,10 @@ mod tests { .write_object::(&ele, GuestAddress(0x3000)) .unwrap(); mem_space - .write_object::(&0, GuestAddress(queue_config_def.avail_ring.0 + 4 as u64)) + .write_object::(&0, GuestAddress(queue_config_def.avail_ring.0 + 4_u64)) .unwrap(); mem_space - .write_object::(&1, GuestAddress(queue_config_def.avail_ring.0 + 2 as u64)) + .write_object::(&1, GuestAddress(queue_config_def.avail_ring.0 + 2_u64)) .unwrap(); assert!(handler.process_balloon_queue(BALLOON_DEFLATE_EVENT).is_ok()); @@ -1556,7 +1556,7 @@ mod tests { let mut queue_evts: Vec> = Vec::new(); for i in 0..QUEUE_NUM_BALLOON as u64 { let mut queue_config_inf = QueueConfig::new(QUEUE_SIZE); - queue_config_inf.desc_table = GuestAddress(12288 * i + 0); + queue_config_inf.desc_table = GuestAddress(12288 * i); queue_config_inf.avail_ring = GuestAddress(12288 * i + 4096); queue_config_inf.used_ring = GuestAddress(12288 * i + 8192); queue_config_inf.ready = true; diff --git a/virtio/src/device/block.rs b/virtio/src/device/block.rs index d64c56fe..d07fc2bc 100644 --- a/virtio/src/device/block.rs +++ b/virtio/src/device/block.rs @@ -1594,18 +1594,18 @@ mod tests { fn test_serial_num_config() { let serial_num = "fldXlNNdCeqMvoIfEFogBxlL"; let serial_num_arr = serial_num.as_bytes(); - let id_bytes = get_serial_num_config(&serial_num); + let id_bytes = get_serial_num_config(serial_num); assert_eq!(id_bytes[..], serial_num_arr[..20]); assert_eq!(id_bytes.len(), 20); let serial_num = "7681194149"; let serial_num_arr = serial_num.as_bytes(); - let id_bytes = get_serial_num_config(&serial_num); + let id_bytes = get_serial_num_config(serial_num); assert_eq!(id_bytes[..10], serial_num_arr[..]); assert_eq!(id_bytes.len(), 20); let serial_num = ""; - let id_bytes_temp = get_serial_num_config(&serial_num); + let id_bytes_temp = get_serial_num_config(serial_num); assert_eq!(id_bytes_temp[..], [0; 20]); assert_eq!(id_bytes_temp.len(), 20); } @@ -1650,7 +1650,7 @@ mod tests { VirtioInterruptType::Config => VIRTIO_MMIO_INT_CONFIG, VirtioInterruptType::Vring => VIRTIO_MMIO_INT_VRING, }; - interrupt_status.fetch_or(status as u32, Ordering::SeqCst); + interrupt_status.fetch_or(status, Ordering::SeqCst); interrupt_evt .write(1) .with_context(|| VirtioError::EventFdWrite)?; @@ -1709,20 +1709,17 @@ mod tests { next: 2, }; mem_space - .write_object::( - &desc, - GuestAddress(queue_config.desc_table.0 + 16 as u64), - ) + .write_object::(&desc, GuestAddress(queue_config.desc_table.0 + 16_u64)) .unwrap(); // write avail_ring idx mem_space - .write_object::(&0, GuestAddress(queue_config.avail_ring.0 + 4 as u64)) + .write_object::(&0, GuestAddress(queue_config.avail_ring.0 + 4_u64)) .unwrap(); // write avail_ring id mem_space - .write_object::(&1, GuestAddress(queue_config.avail_ring.0 + 2 as u64)) + .write_object::(&1, GuestAddress(queue_config.avail_ring.0 + 2_u64)) .unwrap(); // imitating guest OS to send notification. @@ -1740,7 +1737,7 @@ mod tests { // get used_ring data let idx = mem_space - .read_object::(GuestAddress(queue_config.used_ring.0 + 2 as u64)) + .read_object::(GuestAddress(queue_config.used_ring.0 + 2_u64)) .unwrap(); if idx == 1 { break; diff --git a/virtio/src/device/gpu.rs b/virtio/src/device/gpu.rs index 1145a30f..1f8fa7a3 100644 --- a/virtio/src/device/gpu.rs +++ b/virtio/src/device/gpu.rs @@ -1900,9 +1900,9 @@ mod tests { assert_eq!(gpu_cfg.max_outputs, 5); assert_eq!(gpu_cfg.xres, 2048); assert_eq!(gpu_cfg.yres, 800); - assert_eq!(gpu_cfg.edid, false); + assert!(!gpu_cfg.edid); assert_eq!(gpu_cfg.max_hostmem, 268435457); - assert_eq!(gpu_cfg.enable_bar0, true); + assert!(gpu_cfg.enable_bar0); // Test2: Default. let gpu_cmd2 = "virtio-gpu-pci,id=gpu_1,bus=pcie.0,addr=0x4.0x0"; @@ -1911,9 +1911,9 @@ mod tests { assert_eq!(gpu_cfg.max_outputs, 1); assert_eq!(gpu_cfg.xres, 1024); assert_eq!(gpu_cfg.yres, 768); - assert_eq!(gpu_cfg.edid, true); + assert!(gpu_cfg.edid); assert_eq!(gpu_cfg.max_hostmem, VIRTIO_GPU_DEFAULT_MAX_HOSTMEM); - assert_eq!(gpu_cfg.enable_bar0, false); + assert!(!gpu_cfg.enable_bar0); // Test3/4: max_outputs is illegal. let gpu_cmd3 = "virtio-gpu-pci,id=gpu_1,bus=pcie.0,addr=0x4.0x0,max_outputs=17"; diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index a7794fe8..1ec3dc36 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -614,7 +614,7 @@ impl NetCtrlHandler { // Write result to the device writable iovec. let status = elem .in_iovec - .get(0) + .first() .with_context(|| "Failed to get device writable iovec")?; self.mem_space.write_object::(&ack, status.addr)?; @@ -1817,12 +1817,12 @@ mod tests { assert_eq!(net.base.device_features, 0); assert_eq!(net.base.driver_features, 0); - assert_eq!(net.taps.is_none(), true); - assert_eq!(net.senders.is_none(), true); - assert_eq!(net.net_cfg.mac.is_none(), true); - assert_eq!(net.netdev_cfg.tap_fds.is_none(), true); + assert!(net.taps.is_none()); + assert!(net.senders.is_none()); + assert!(net.net_cfg.mac.is_none()); + assert!(net.netdev_cfg.tap_fds.is_none()); assert!(net.netdev_cfg.vhost_type().is_none()); - assert_eq!(net.netdev_cfg.vhost_fds.is_none(), true); + assert!(net.netdev_cfg.vhost_fds.is_none()); // test net realize method net.realize().unwrap(); @@ -1850,25 +1850,25 @@ mod tests { let mut data: Vec = vec![0; 10]; let offset: u64 = len + 1; - assert_eq!(net.read_config(offset, &mut data).is_ok(), false); + assert!(net.read_config(offset, &mut data).is_err()); let offset: u64 = len; - assert_eq!(net.read_config(offset, &mut data).is_ok(), false); + assert!(net.read_config(offset, &mut data).is_err()); let offset: u64 = 0; - assert_eq!(net.read_config(offset, &mut data).is_ok(), true); + assert!(net.read_config(offset, &mut data).is_ok()); let offset: u64 = len; let mut data: Vec = vec![0; 1]; - assert_eq!(net.write_config(offset, &mut data).is_ok(), false); + assert!(net.write_config(offset, &mut data).is_err()); let offset: u64 = len - 1; let mut data: Vec = vec![0; 1]; - assert_eq!(net.write_config(offset, &mut data).is_ok(), false); + assert!(net.write_config(offset, &mut data).is_err()); let offset: u64 = 0; let mut data: Vec = vec![0; len as usize]; - assert_eq!(net.write_config(offset, &mut data).is_ok(), false); + assert!(net.write_config(offset, &mut data).is_err()); } #[test] @@ -1879,8 +1879,8 @@ mod tests { // Test create tap with net_fds and host_dev_name. let net_fds = vec![32, 33]; let tap_name = "tap0"; - if let Err(err) = create_tap(Some(&net_fds), Some(&tap_name), 1) { - let err_msg = format!("Failed to create tap, index is 0"); + if let Err(err) = create_tap(Some(&net_fds), Some(tap_name), 1) { + let err_msg = "Failed to create tap, index is 0".to_string(); assert_eq!(err.to_string(), err_msg); } else { assert!(false); @@ -1888,7 +1888,7 @@ mod tests { // Test create tap with empty net_fds. if let Err(err) = create_tap(Some(&vec![]), None, 1) { - let err_msg = format!("Failed to get fd from index 0"); + let err_msg = "Failed to get fd from index 0".to_string(); assert_eq!(err.to_string(), err_msg); } else { assert!(false); @@ -1897,7 +1897,7 @@ mod tests { // Test create tap with tap_name which is not exist. if let Err(err) = create_tap(None, Some("the_tap_is_not_exist"), 1) { let err_msg = - format!("Failed to create tap with name the_tap_is_not_exist, index is 0"); + "Failed to create tap with name the_tap_is_not_exist, index is 0".to_string(); assert_eq!(err.to_string(), err_msg); } else { assert!(false); @@ -1913,14 +1913,14 @@ mod tests { 0x00, 0x00, ]; // It has no vla vid, the packet is filtered. - assert_eq!(ctrl_info.filter_packets(&buf), true); + assert!(ctrl_info.filter_packets(&buf)); // It has valid vlan id, the packet is not filtered. let vid: u16 = 1023; buf[ETHERNET_HDR_LENGTH] = u16::to_be_bytes(vid)[0]; buf[ETHERNET_HDR_LENGTH + 1] = u16::to_be_bytes(vid)[1]; ctrl_info.vlan_map.insert(vid >> 5, 1 << (vid & 0x1f)); - assert_eq!(ctrl_info.filter_packets(&buf), false); + assert!(!ctrl_info.filter_packets(&buf)); } #[test] @@ -1928,12 +1928,12 @@ mod tests { let mut net_config = VirtioNetConfig::default(); // Parsing the normal mac address. let mac = "52:54:00:12:34:56"; - let ret = build_device_config_space(&mut net_config, &mac); + let ret = build_device_config_space(&mut net_config, mac); assert_eq!(ret, 1 << VIRTIO_NET_F_MAC); // Parsing the abnormale mac address. let mac = "52:54:00:12:34:"; - let ret = build_device_config_space(&mut net_config, &mac); + let ret = build_device_config_space(&mut net_config, mac); assert_eq!(ret, 0); } diff --git a/virtio/src/device/rng.rs b/virtio/src/device/rng.rs index f0fcc4e1..aaad7cb9 100644 --- a/virtio/src/device/rng.rs +++ b/virtio/src/device/rng.rs @@ -624,11 +624,11 @@ mod tests { .unwrap(); // write avail_ring idx mem_space - .write_object::(&0, GuestAddress(queue_config.avail_ring.0 + 4 as u64)) + .write_object::(&0, GuestAddress(queue_config.avail_ring.0 + 4_u64)) .unwrap(); // write avail_ring idx mem_space - .write_object::(&1, GuestAddress(queue_config.avail_ring.0 + 2 as u64)) + .write_object::(&1, GuestAddress(queue_config.avail_ring.0 + 2_u64)) .unwrap(); let buffer = vec![1_u8; data_len as usize]; @@ -645,7 +645,7 @@ mod tests { assert_eq!(read_buffer, buffer); let idx = mem_space - .read_object::(GuestAddress(queue_config.used_ring.0 + 2 as u64)) + .read_object::(GuestAddress(queue_config.used_ring.0 + 2_u64)) .unwrap(); assert_eq!(idx, 1); assert_eq!(cloned_interrupt_evt.read().unwrap(), 1); @@ -722,11 +722,11 @@ mod tests { // write avail_ring idx mem_space - .write_object::(&0, GuestAddress(queue_config.avail_ring.0 + 4 as u64)) + .write_object::(&0, GuestAddress(queue_config.avail_ring.0 + 4_u64)) .unwrap(); // write avail_ring idx mem_space - .write_object::(&1, GuestAddress(queue_config.avail_ring.0 + 2 as u64)) + .write_object::(&1, GuestAddress(queue_config.avail_ring.0 + 2_u64)) .unwrap(); let mut buffer1 = vec![1_u8; data_len as usize]; @@ -756,7 +756,7 @@ mod tests { assert_eq!(read_buffer, buffer2_check); let idx = mem_space - .read_object::(GuestAddress(queue_config.used_ring.0 + 2 as u64)) + .read_object::(GuestAddress(queue_config.used_ring.0 + 2_u64)) .unwrap(); assert_eq!(idx, 1); assert_eq!(cloned_interrupt_evt.read().unwrap(), 1); diff --git a/virtio/src/device/scsi_cntlr.rs b/virtio/src/device/scsi_cntlr.rs index 6863b60c..9f6fc01d 100644 --- a/virtio/src/device/scsi_cntlr.rs +++ b/virtio/src/device/scsi_cntlr.rs @@ -617,7 +617,7 @@ impl ScsiCtrlQueueHandler { let ctrl_desc = elem .out_iovec - .get(0) + .first() .with_context(|| "Error request in ctrl queue. Empty dataout buf!")?; let ctrl_type = self .mem_space diff --git a/virtio/src/device/serial.rs b/virtio/src/device/serial.rs index 50491861..ae76f87a 100644 --- a/virtio/src/device/serial.rs +++ b/virtio/src/device/serial.rs @@ -1084,13 +1084,13 @@ mod tests { // The offset of configuration that needs to be read exceeds the maximum. let offset = size_of::() as u64; let mut read_data: Vec = vec![0; 8]; - assert_eq!(serial.read_config(offset, &mut read_data).is_ok(), false); + assert!(serial.read_config(offset, &mut read_data).is_err()); // Check the configuration that needs to be read. let offset = 0_u64; let mut read_data: Vec = vec![0; 12]; let expect_data: Vec = vec![0, 0, 0, 0, max_ports, 0, 0, 0, 0, 0, 0, 0]; - assert_eq!(serial.read_config(offset, &mut read_data).is_ok(), true); + assert!(serial.read_config(offset, &mut read_data).is_ok()); assert_eq!(read_data, expect_data); } } diff --git a/virtio/src/queue/split.rs b/virtio/src/queue/split.rs index 255e966d..7c9d512e 100644 --- a/virtio/src/queue/split.rs +++ b/virtio/src/queue/split.rs @@ -1051,14 +1051,14 @@ mod tests { } fn set_avail_ring_idx(&self, sys_mem: &Arc, idx: u16) -> Result<()> { - let avail_idx_offset = 2 as u64; + let avail_idx_offset = 2_u64; sys_mem .write_object::(&idx, GuestAddress(self.avail_ring.0 + avail_idx_offset))?; Ok(()) } fn set_avail_ring_flags(&self, sys_mem: &Arc, flags: u16) -> Result<()> { - let avail_idx_offset = 0 as u64; + let avail_idx_offset = 0_u64; sys_mem .write_object::(&flags, GuestAddress(self.avail_ring.0 + avail_idx_offset))?; Ok(()) @@ -1134,7 +1134,7 @@ mod tests { } const SYSTEM_SPACE_SIZE: u64 = (1024 * 1024) as u64; - const QUEUE_SIZE: u16 = 256 as u16; + const QUEUE_SIZE: u16 = 256_u16; fn align(size: u64, alignment: u64) -> u64 { let align_adjust = if size % alignment != 0 { @@ -1142,7 +1142,7 @@ mod tests { } else { 0 }; - (size + align_adjust) as u64 + size + align_adjust } #[test] @@ -1169,28 +1169,28 @@ mod tests { queue_config.ready = true; queue_config.size = QUEUE_SIZE; let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), true); + assert!(queue.is_valid(&sys_space)); // it is invalid when the status is not ready queue_config.ready = false; let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), false); + assert!(!queue.is_valid(&sys_space)); queue_config.ready = true; // it is invalid when the size of virtual ring is more than the max size queue_config.size = QUEUE_SIZE + 1; let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), false); + assert!(!queue.is_valid(&sys_space)); // it is invalid when the size of virtual ring is zero queue_config.size = 0; let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), false); + assert!(!queue.is_valid(&sys_space)); // it is invalid when the size of virtual ring isn't power of 2 queue_config.size = 15; let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), false); + assert!(!queue.is_valid(&sys_space)); } #[test] @@ -1209,39 +1209,39 @@ mod tests { queue_config.ready = true; queue_config.size = QUEUE_SIZE; let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), true); + assert!(queue.is_valid(&sys_space)); // it is invalid when the address of descriptor table is out of bound queue_config.desc_table = - GuestAddress(SYSTEM_SPACE_SIZE - u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + 1 as u64); + GuestAddress(SYSTEM_SPACE_SIZE - u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + 1_u64); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), false); + assert!(!queue.is_valid(&sys_space)); // recover the address for valid queue queue_config.desc_table = GuestAddress(0); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), true); + assert!(queue.is_valid(&sys_space)); // it is invalid when the address of avail ring is out of bound queue_config.avail_ring = GuestAddress( SYSTEM_SPACE_SIZE - (VRING_AVAIL_LEN_EXCEPT_AVAILELEM + AVAILELEM_LEN * u64::from(QUEUE_SIZE)) - + 1 as u64, + + 1_u64, ); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), false); + assert!(!queue.is_valid(&sys_space)); // recover the address for valid queue queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), true); + assert!(queue.is_valid(&sys_space)); // it is invalid when the address of used ring is out of bound queue_config.used_ring = GuestAddress( SYSTEM_SPACE_SIZE - (VRING_USED_LEN_EXCEPT_USEDELEM + USEDELEM_LEN * u64::from(QUEUE_SIZE)) - + 1 as u64, + + 1_u64, ); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), false); + assert!(!queue.is_valid(&sys_space)); // recover the address for valid queue queue_config.used_ring = GuestAddress(align( u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN @@ -1250,7 +1250,7 @@ mod tests { 4096, )); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), true); + assert!(queue.is_valid(&sys_space)); } #[test] @@ -1269,31 +1269,31 @@ mod tests { queue_config.ready = true; queue_config.size = QUEUE_SIZE; let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), true); + assert!(queue.is_valid(&sys_space)); // it is invalid when the address of descriptor table is equal to the address of avail ring queue_config.avail_ring = GuestAddress(0); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), false); + assert!(!queue.is_valid(&sys_space)); // recover the address for valid queue queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), true); + assert!(queue.is_valid(&sys_space)); // it is invalid when the address of descriptor table is overlapped to the address of avail // ring. queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN - 1); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), false); + assert!(!queue.is_valid(&sys_space)); // recover the address for valid queue queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), true); + assert!(queue.is_valid(&sys_space)); // it is invalid when the address of avail ring is equal to the address of used ring queue_config.used_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), false); + assert!(!queue.is_valid(&sys_space)); // recover the address for valid queue queue_config.used_ring = GuestAddress(align( u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN @@ -1302,7 +1302,7 @@ mod tests { 4096, )); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), true); + assert!(queue.is_valid(&sys_space)); // it is invalid when the address of avail ring is overlapped to the address of used ring queue_config.used_ring = GuestAddress( @@ -1312,7 +1312,7 @@ mod tests { - 1, ); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), false); + assert!(!queue.is_valid(&sys_space)); // recover the address for valid queue queue_config.used_ring = GuestAddress(align( u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN @@ -1321,7 +1321,7 @@ mod tests { 4096, )); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), true); + assert!(queue.is_valid(&sys_space)); } #[test] @@ -1340,25 +1340,25 @@ mod tests { queue_config.ready = true; queue_config.size = QUEUE_SIZE; let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), true); + assert!(queue.is_valid(&sys_space)); // it is invalid when the address of descriptor table is not aligned to 16 - queue_config.desc_table = GuestAddress(15 as u64); + queue_config.desc_table = GuestAddress(15_u64); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), false); + assert!(!queue.is_valid(&sys_space)); // recover the address for valid queue queue_config.desc_table = GuestAddress(0); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), true); + assert!(queue.is_valid(&sys_space)); // it is invalid when the address of avail ring is not aligned to 2 queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + 1); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), false); + assert!(!queue.is_valid(&sys_space)); // recover the address for valid queue queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), true); + assert!(queue.is_valid(&sys_space)); // it is invalid when the address of used ring is not aligned to 4 queue_config.used_ring = GuestAddress( @@ -1368,7 +1368,7 @@ mod tests { + 3, ); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), false); + assert!(!queue.is_valid(&sys_space)); // recover the address for valid queue queue_config.used_ring = GuestAddress(align( u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN @@ -1377,7 +1377,7 @@ mod tests { 4096, )); let queue = Queue::new(queue_config, QUEUE_TYPE_SPLIT_VRING).unwrap(); - assert_eq!(queue.is_valid(&sys_space), true); + assert!(queue.is_valid(&sys_space)); } #[test] @@ -1402,7 +1402,7 @@ mod tests { queue_config.ready = true; queue_config.size = QUEUE_SIZE; let mut vring = SplitVring::new(queue_config); - assert_eq!(vring.is_valid(&sys_space), true); + assert!(vring.is_valid(&sys_space)); // it is ok when the descriptor chain is normal // set the information of index 0 for descriptor @@ -1452,11 +1452,11 @@ mod tests { assert_eq!(elem.index, 0); assert_eq!(elem.desc_num, 3); assert_eq!(elem.out_iovec.len(), 1); - let elem_iov = elem.out_iovec.get(0).unwrap(); + let elem_iov = elem.out_iovec.first().unwrap(); assert_eq!(elem_iov.addr, GuestAddress(0x111)); assert_eq!(elem_iov.len, 16); assert_eq!(elem.in_iovec.len(), 2); - let elem_iov = elem.in_iovec.get(0).unwrap(); + let elem_iov = elem.in_iovec.first().unwrap(); assert_eq!(elem_iov.addr, GuestAddress(0x222)); assert_eq!(elem_iov.len, 32); let elem_iov = elem.in_iovec.get(1).unwrap(); @@ -1492,7 +1492,7 @@ mod tests { queue_config.ready = true; queue_config.size = QUEUE_SIZE; let mut vring = SplitVring::new(queue_config); - assert_eq!(vring.is_valid(&sys_space), true); + assert!(vring.is_valid(&sys_space)); // it is ok when the descriptor chain is indirect // set the information for indirect descriptor @@ -1558,14 +1558,14 @@ mod tests { assert_eq!(elem.index, 0); assert_eq!(elem.desc_num, 3); assert_eq!(elem.out_iovec.len(), 2); - let elem_iov = elem.out_iovec.get(0).unwrap(); + let elem_iov = elem.out_iovec.first().unwrap(); assert_eq!(elem_iov.addr, GuestAddress(0x444)); assert_eq!(elem_iov.len, 100); let elem_iov = elem.out_iovec.get(1).unwrap(); assert_eq!(elem_iov.addr, GuestAddress(0x555)); assert_eq!(elem_iov.len, 200); assert_eq!(elem.in_iovec.len(), 1); - let elem_iov = elem.in_iovec.get(0).unwrap(); + let elem_iov = elem.in_iovec.first().unwrap(); assert_eq!(elem_iov.addr, GuestAddress(0x666)); assert_eq!(elem_iov.len, 300); } @@ -1592,7 +1592,7 @@ mod tests { queue_config.ready = true; queue_config.size = QUEUE_SIZE; let mut vring = SplitVring::new(queue_config); - assert_eq!(vring.is_valid(&sys_space), true); + assert!(vring.is_valid(&sys_space)); // it is error when the idx of avail ring which is equal to next_avail // set 0 to the idx of avail ring which is equal to next_avail @@ -1637,7 +1637,7 @@ mod tests { 0, ) .unwrap(); - if let Ok(_) = vring.pop_avail(&sys_space, features) { + if vring.pop_avail(&sys_space, features).is_ok() { assert!(false); } @@ -1787,7 +1787,7 @@ mod tests { queue_config.ready = true; queue_config.size = QUEUE_SIZE; let mut vring = SplitVring::new(queue_config); - assert_eq!(vring.is_valid(&sys_space), true); + assert!(vring.is_valid(&sys_space)); // Set the information of index 0 for normal descriptor. vring @@ -1906,7 +1906,7 @@ mod tests { // Two elem for reading. assert_eq!(elem.out_iovec.len(), 2); - let elem_iov = elem.out_iovec.get(0).unwrap(); + let elem_iov = elem.out_iovec.first().unwrap(); assert_eq!(elem_iov.addr, GuestAddress(0x111)); assert_eq!(elem_iov.len, 16); let elem_iov = elem.out_iovec.get(1).unwrap(); @@ -1915,7 +1915,7 @@ mod tests { // Two elem for writing. assert_eq!(elem.in_iovec.len(), 2); - let elem_iov = elem.in_iovec.get(0).unwrap(); + let elem_iov = elem.in_iovec.first().unwrap(); assert_eq!(elem_iov.addr, GuestAddress(0x444)); assert_eq!(elem_iov.len, 100); let elem_iov = elem.in_iovec.get(1).unwrap(); @@ -1951,7 +1951,7 @@ mod tests { queue_config.ready = true; queue_config.size = QUEUE_SIZE; let mut vring = SplitVring::new(queue_config); - assert_eq!(vring.is_valid(&sys_space), true); + assert!(vring.is_valid(&sys_space)); // it is false when the index is more than the size of queue if let Err(err) = vring.add_used(&sys_space, QUEUE_SIZE, 100) { @@ -1995,20 +1995,20 @@ mod tests { queue_config.ready = true; queue_config.size = QUEUE_SIZE; let mut vring = SplitVring::new(queue_config); - assert_eq!(vring.is_valid(&sys_space), true); + assert!(vring.is_valid(&sys_space)); // it's true when the feature of event idx and no interrupt for the avail ring is closed - let features = 0 as u64; + let features = 0_u64; assert!(vring.set_avail_ring_flags(&sys_space, 0).is_ok()); - assert_eq!(vring.should_notify(&sys_space, features), true); + assert!(vring.should_notify(&sys_space, features)); // it's false when the feature of event idx is closed and the feature of no interrupt for // the avail ring is open - let features = 0 as u64; + let features = 0_u64; assert!(vring .set_avail_ring_flags(&sys_space, VRING_AVAIL_F_NO_INTERRUPT) .is_ok()); - assert_eq!(vring.should_notify(&sys_space, features), false); + assert!(!vring.should_notify(&sys_space, features)); // it's true when the feature of event idx is open and // (new - event_idx - Wrapping(1) < new -old) @@ -2016,20 +2016,20 @@ mod tests { vring.last_signal_used = Wrapping(5); // old assert!(vring.set_used_ring_idx(&sys_space, 10).is_ok()); // new assert!(vring.set_used_event_idx(&sys_space, 6).is_ok()); // event_idx - assert_eq!(vring.should_notify(&sys_space, features), true); + assert!(vring.should_notify(&sys_space, features)); // it's false when the feature of event idx is open and // (new - event_idx - Wrapping(1) > new - old) vring.last_signal_used = Wrapping(5); // old assert!(vring.set_used_ring_idx(&sys_space, 10).is_ok()); // new assert!(vring.set_used_event_idx(&sys_space, 1).is_ok()); // event_idx - assert_eq!(vring.should_notify(&sys_space, features), false); + assert!(!vring.should_notify(&sys_space, features)); // it's false when the feature of event idx is open and // (new - event_idx - Wrapping(1) = new -old) vring.last_signal_used = Wrapping(5); // old assert!(vring.set_used_ring_idx(&sys_space, 10).is_ok()); // new assert!(vring.set_used_event_idx(&sys_space, 4).is_ok()); // event_idx - assert_eq!(vring.should_notify(&sys_space, features), false); + assert!(!vring.should_notify(&sys_space, features)); } } diff --git a/virtio/src/transport/virtio_mmio.rs b/virtio/src/transport/virtio_mmio.rs index f8895221..eb081e13 100644 --- a/virtio/src/transport/virtio_mmio.rs +++ b/virtio/src/transport/virtio_mmio.rs @@ -625,7 +625,7 @@ mod tests { check_config_space_rw(&self.config_space, offset, data)?; let data_len = data.len(); self.config_space[(offset as usize)..(offset as usize + data_len)] - .copy_from_slice(&data[..]); + .copy_from_slice(data); Ok(()) } @@ -662,7 +662,7 @@ mod tests { fn test_virtio_mmio_device_new() { let (virtio_device, virtio_mmio_device) = virtio_mmio_test_init(); let locked_device = virtio_device.lock().unwrap(); - assert_eq!(locked_device.device_activated(), false); + assert!(!locked_device.device_activated()); assert_eq!( virtio_mmio_device.host_notify_info.events.len(), locked_device.queue_num() @@ -682,34 +682,22 @@ mod tests { // read the register of magic value let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; - assert_eq!( - virtio_mmio_device.read(&mut buf[..], addr, MAGIC_VALUE_REG), - true - ); + assert!(virtio_mmio_device.read(&mut buf[..], addr, MAGIC_VALUE_REG)); assert_eq!(LittleEndian::read_u32(&buf[..]), MMIO_MAGIC_VALUE); // read the register of version let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; - assert_eq!( - virtio_mmio_device.read(&mut buf[..], addr, VERSION_REG), - true - ); + assert!(virtio_mmio_device.read(&mut buf[..], addr, VERSION_REG)); assert_eq!(LittleEndian::read_u32(&buf[..]), MMIO_VERSION); // read the register of device id let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; - assert_eq!( - virtio_mmio_device.read(&mut buf[..], addr, DEVICE_ID_REG), - true - ); + assert!(virtio_mmio_device.read(&mut buf[..], addr, DEVICE_ID_REG)); assert_eq!(LittleEndian::read_u32(&buf[..]), VIRTIO_TYPE_BLOCK); // read the register of vendor id let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; - assert_eq!( - virtio_mmio_device.read(&mut buf[..], addr, VENDOR_ID_REG), - true - ); + assert!(virtio_mmio_device.read(&mut buf[..], addr, VENDOR_ID_REG)); assert_eq!(LittleEndian::read_u32(&buf[..]), VENDOR_ID); // read the register of the features @@ -717,18 +705,12 @@ mod tests { let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; virtio_device.lock().unwrap().set_hfeatures_sel(0); virtio_device.lock().unwrap().base.device_features = 0x0000_00f8_0000_00fe; - assert_eq!( - virtio_mmio_device.read(&mut buf[..], addr, DEVICE_FEATURES_REG), - true - ); + assert!(virtio_mmio_device.read(&mut buf[..], addr, DEVICE_FEATURES_REG)); assert_eq!(LittleEndian::read_u32(&buf[..]), 0x0000_00fe); // get high 32bit of the features for device which supports VirtIO Version 1 let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; virtio_device.lock().unwrap().set_hfeatures_sel(1); - assert_eq!( - virtio_mmio_device.read(&mut buf[..], addr, DEVICE_FEATURES_REG), - true - ); + assert!(virtio_mmio_device.read(&mut buf[..], addr, DEVICE_FEATURES_REG)); assert_eq!(LittleEndian::read_u32(&buf[..]), 0x0000_00f9); } @@ -741,18 +723,12 @@ mod tests { // for queue_select as 0 let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; virtio_device.lock().unwrap().set_queue_select(0); - assert_eq!( - virtio_mmio_device.read(&mut buf[..], addr, QUEUE_NUM_MAX_REG), - true - ); + assert!(virtio_mmio_device.read(&mut buf[..], addr, QUEUE_NUM_MAX_REG)); assert_eq!(LittleEndian::read_u32(&buf[..]), u32::from(QUEUE_SIZE)); // for queue_select as 1 let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; virtio_device.lock().unwrap().set_queue_select(1); - assert_eq!( - virtio_mmio_device.read(&mut buf[..], addr, QUEUE_NUM_MAX_REG), - true - ); + assert!(virtio_mmio_device.read(&mut buf[..], addr, QUEUE_NUM_MAX_REG)); assert_eq!(LittleEndian::read_u32(&buf[..]), u32::from(QUEUE_SIZE)); // read the register representing the status of queue @@ -764,15 +740,9 @@ mod tests { .unwrap() .set_device_status(CONFIG_STATUS_FEATURES_OK); LittleEndian::write_u32(&mut buf[..], 1); - assert_eq!( - virtio_mmio_device.write(&buf[..], addr, QUEUE_READY_REG), - true - ); + assert!(virtio_mmio_device.write(&buf[..], addr, QUEUE_READY_REG)); let mut data: Vec = vec![0xff, 0xff, 0xff, 0xff]; - assert_eq!( - virtio_mmio_device.read(&mut data[..], addr, QUEUE_READY_REG), - true - ); + assert!(virtio_mmio_device.read(&mut data[..], addr, QUEUE_READY_REG)); assert_eq!(LittleEndian::read_u32(&data[..]), 1); // for queue_select as 1 let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; @@ -781,44 +751,29 @@ mod tests { .lock() .unwrap() .set_device_status(CONFIG_STATUS_FEATURES_OK); - assert_eq!( - virtio_mmio_device.read(&mut buf[..], addr, QUEUE_READY_REG), - true - ); + assert!(virtio_mmio_device.read(&mut buf[..], addr, QUEUE_READY_REG)); assert_eq!(LittleEndian::read_u32(&buf[..]), 0); // read the register representing the status of interrupt let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; - assert_eq!( - virtio_mmio_device.read(&mut buf[..], addr, INTERRUPT_STATUS_REG), - true - ); + assert!(virtio_mmio_device.read(&mut buf[..], addr, INTERRUPT_STATUS_REG)); assert_eq!(LittleEndian::read_u32(&buf[..]), 0); let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; virtio_device .lock() .unwrap() .set_interrupt_status(0b10_1111); - assert_eq!( - virtio_mmio_device.read(&mut buf[..], addr, INTERRUPT_STATUS_REG), - true - ); + assert!(virtio_mmio_device.read(&mut buf[..], addr, INTERRUPT_STATUS_REG)); assert_eq!(LittleEndian::read_u32(&buf[..]), 0b10_1111); // read the register representing the status of device let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; virtio_device.lock().unwrap().set_device_status(0); - assert_eq!( - virtio_mmio_device.read(&mut buf[..], addr, STATUS_REG), - true - ); + assert!(virtio_mmio_device.read(&mut buf[..], addr, STATUS_REG)); assert_eq!(LittleEndian::read_u32(&buf[..]), 0); let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; virtio_device.lock().unwrap().set_device_status(5); - assert_eq!( - virtio_mmio_device.read(&mut buf[..], addr, STATUS_REG), - true - ); + assert!(virtio_mmio_device.read(&mut buf[..], addr, STATUS_REG)); assert_eq!(LittleEndian::read_u32(&buf[..]), 5); } @@ -829,23 +784,17 @@ mod tests { // read the configuration atomic value let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; - assert_eq!( - virtio_mmio_device.read(&mut buf[..], addr, CONFIG_GENERATION_REG), - true - ); + assert!(virtio_mmio_device.read(&mut buf[..], addr, CONFIG_GENERATION_REG)); assert_eq!(LittleEndian::read_u32(&buf[..]), 0); let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; virtio_device.lock().unwrap().set_config_generation(10); - assert_eq!( - virtio_mmio_device.read(&mut buf[..], addr, CONFIG_GENERATION_REG), - true - ); + assert!(virtio_mmio_device.read(&mut buf[..], addr, CONFIG_GENERATION_REG)); assert_eq!(LittleEndian::read_u32(&buf[..]), 10); // read the unknown register let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; - assert_eq!(virtio_mmio_device.read(&mut buf[..], addr, 0xf1), false); - assert_eq!(virtio_mmio_device.read(&mut buf[..], addr, 0x1ff + 1), true); + assert!(!virtio_mmio_device.read(&mut buf[..], addr, 0xf1)); + assert!(virtio_mmio_device.read(&mut buf[..], addr, 0x1ff + 1)); assert_eq!(buf, [0xff, 0xff, 0xff, 0xff]); // read the configuration space of virtio device @@ -859,12 +808,12 @@ mod tests { .copy_from_slice(&result); let mut data: Vec = vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - assert_eq!(virtio_mmio_device.read(&mut data[..], addr, 0x100), true); + assert!(virtio_mmio_device.read(&mut data[..], addr, 0x100)); assert_eq!(data, result); let mut data: Vec = vec![0, 0, 0, 0, 0, 0, 0, 0]; let result: Vec = vec![9, 10, 11, 12, 13, 14, 15, 16]; - assert_eq!(virtio_mmio_device.read(&mut data[..], addr, 0x108), true); + assert!(virtio_mmio_device.read(&mut data[..], addr, 0x108)); assert_eq!(data, result); } @@ -876,10 +825,7 @@ mod tests { // write the selector for device features let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; LittleEndian::write_u32(&mut buf[..], 2); - assert_eq!( - virtio_mmio_device.write(&buf[..], addr, DEVICE_FEATURES_SEL_REG), - true - ); + assert!(virtio_mmio_device.write(&buf[..], addr, DEVICE_FEATURES_SEL_REG)); assert_eq!(virtio_device.lock().unwrap().hfeatures_sel(), 2); // write the device features @@ -889,25 +835,16 @@ mod tests { .lock() .unwrap() .set_device_status(CONFIG_STATUS_FEATURES_OK); - assert_eq!( - virtio_mmio_device.write(&buf[..], addr, DRIVER_FEATURES_REG), - false - ); + assert!(!virtio_mmio_device.write(&buf[..], addr, DRIVER_FEATURES_REG)); virtio_device .lock() .unwrap() .set_device_status(CONFIG_STATUS_FAILED); - assert_eq!( - virtio_mmio_device.write(&buf[..], addr, DRIVER_FEATURES_REG), - false - ); + assert!(!virtio_mmio_device.write(&buf[..], addr, DRIVER_FEATURES_REG)); virtio_device.lock().unwrap().set_device_status( CONFIG_STATUS_FEATURES_OK | CONFIG_STATUS_FAILED | CONFIG_STATUS_DRIVER, ); - assert_eq!( - virtio_mmio_device.write(&buf[..], addr, DRIVER_FEATURES_REG), - false - ); + assert!(!virtio_mmio_device.write(&buf[..], addr, DRIVER_FEATURES_REG)); // it is ok to write the low 32bit of device features virtio_device .lock() @@ -917,10 +854,7 @@ mod tests { virtio_device.lock().unwrap().set_gfeatures_sel(0); LittleEndian::write_u32(&mut buf[..], 0x0000_00fe); virtio_device.lock().unwrap().base.device_features = 0x0000_00fe; - assert_eq!( - virtio_mmio_device.write(&buf[..], addr, DRIVER_FEATURES_REG), - true - ); + assert!(virtio_mmio_device.write(&buf[..], addr, DRIVER_FEATURES_REG)); assert_eq!( virtio_device.lock().unwrap().base.driver_features as u32, 0x0000_00fe @@ -930,35 +864,26 @@ mod tests { virtio_device.lock().unwrap().set_gfeatures_sel(1); LittleEndian::write_u32(&mut buf[..], 0x0000_00ff); virtio_device.lock().unwrap().base.device_features = 0x0000_00ff_0000_0000; - assert_eq!( - virtio_mmio_device.write(&buf[..], addr, DRIVER_FEATURES_REG), - true - ); + assert!(virtio_mmio_device.write(&buf[..], addr, DRIVER_FEATURES_REG)); assert_eq!( virtio_device.lock().unwrap().queue_type(), QUEUE_TYPE_PACKED_VRING ); assert_eq!( - virtio_device.lock().unwrap().base.driver_features >> 32 as u32, + virtio_device.lock().unwrap().base.driver_features >> 32_u32, 0x0000_00ff ); // write the selector of driver features let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; LittleEndian::write_u32(&mut buf[..], 0x00ff_0000); - assert_eq!( - virtio_mmio_device.write(&buf[..], addr, DRIVER_FEATURES_SEL_REG), - true - ); + assert!(virtio_mmio_device.write(&buf[..], addr, DRIVER_FEATURES_SEL_REG)); assert_eq!(virtio_device.lock().unwrap().gfeatures_sel(), 0x00ff_0000); // write the selector of queue let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; LittleEndian::write_u32(&mut buf[..], 0x0000_ff00); - assert_eq!( - virtio_mmio_device.write(&buf[..], addr, QUEUE_SEL_REG), - true - ); + assert!(virtio_mmio_device.write(&buf[..], addr, QUEUE_SEL_REG)); assert_eq!(virtio_device.lock().unwrap().queue_select(), 0x0000_ff00); // write the size of queue @@ -969,10 +894,7 @@ mod tests { .unwrap() .set_device_status(CONFIG_STATUS_FEATURES_OK); LittleEndian::write_u32(&mut buf[..], 128); - assert_eq!( - virtio_mmio_device.write(&buf[..], addr, QUEUE_NUM_REG), - true - ); + assert!(virtio_mmio_device.write(&buf[..], addr, QUEUE_NUM_REG)); if let Ok(config) = virtio_device.lock().unwrap().queue_config() { assert_eq!(config.size, 128); } else { @@ -993,15 +915,9 @@ mod tests { .unwrap() .set_device_status(CONFIG_STATUS_FEATURES_OK); LittleEndian::write_u32(&mut buf[..], 1); - assert_eq!( - virtio_mmio_device.write(&buf[..], addr, QUEUE_READY_REG), - true - ); + assert!(virtio_mmio_device.write(&buf[..], addr, QUEUE_READY_REG)); let mut data: Vec = vec![0xff, 0xff, 0xff, 0xff]; - assert_eq!( - virtio_mmio_device.read(&mut data[..], addr, QUEUE_READY_REG), - true - ); + assert!(virtio_mmio_device.read(&mut data[..], addr, QUEUE_READY_REG)); assert_eq!(LittleEndian::read_u32(&data[..]), 1); let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; @@ -1011,15 +927,9 @@ mod tests { .unwrap() .set_device_status(CONFIG_STATUS_FEATURES_OK); LittleEndian::write_u32(&mut buf[..], 2); - assert_eq!( - virtio_mmio_device.write(&buf[..], addr, QUEUE_READY_REG), - true - ); + assert!(virtio_mmio_device.write(&buf[..], addr, QUEUE_READY_REG)); let mut data: Vec = vec![0xff, 0xff, 0xff, 0xff]; - assert_eq!( - virtio_mmio_device.read(&mut data[..], addr, QUEUE_READY_REG), - true - ); + assert!(virtio_mmio_device.read(&mut data[..], addr, QUEUE_READY_REG)); assert_eq!(LittleEndian::read_u32(&data[..]), 0); // write the interrupt status @@ -1033,15 +943,9 @@ mod tests { .unwrap() .set_interrupt_status(0b10_1111); LittleEndian::write_u32(&mut buf[..], 0b111); - assert_eq!( - virtio_mmio_device.write(&buf[..], addr, INTERRUPT_ACK_REG), - true - ); + assert!(virtio_mmio_device.write(&buf[..], addr, INTERRUPT_ACK_REG)); let mut data: Vec = vec![0xff, 0xff, 0xff, 0xff]; - assert_eq!( - virtio_mmio_device.read(&mut data[..], addr, INTERRUPT_STATUS_REG), - true - ); + assert!(virtio_mmio_device.read(&mut data[..], addr, INTERRUPT_STATUS_REG)); assert_eq!(LittleEndian::read_u32(&data[..]), 0b10_1000); } @@ -1058,10 +962,7 @@ mod tests { .set_device_status(CONFIG_STATUS_FEATURES_OK); let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; LittleEndian::write_u32(&mut buf[..], 0xffff_fefe); - assert_eq!( - virtio_mmio_device.write(&buf[..], addr, QUEUE_DESC_LOW_REG), - true - ); + assert!(virtio_mmio_device.write(&buf[..], addr, QUEUE_DESC_LOW_REG)); if let Ok(config) = virtio_mmio_device.device.lock().unwrap().queue_config() { assert_eq!(config.desc_table.0 as u32, 0xffff_fefe) } else { @@ -1076,10 +977,7 @@ mod tests { .set_device_status(CONFIG_STATUS_FEATURES_OK); let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; LittleEndian::write_u32(&mut buf[..], 0xfcfc_ffff); - assert_eq!( - virtio_mmio_device.write(&buf[..], addr, QUEUE_DESC_HIGH_REG), - true - ); + assert!(virtio_mmio_device.write(&buf[..], addr, QUEUE_DESC_HIGH_REG)); if let Ok(config) = virtio_device.lock().unwrap().queue_config() { assert_eq!((config.desc_table.0 >> 32) as u32, 0xfcfc_ffff) } else { @@ -1094,10 +992,7 @@ mod tests { .set_device_status(CONFIG_STATUS_FEATURES_OK); let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; LittleEndian::write_u32(&mut buf[..], 0xfcfc_fafa); - assert_eq!( - virtio_mmio_device.write(&buf[..], addr, QUEUE_AVAIL_LOW_REG), - true - ); + assert!(virtio_mmio_device.write(&buf[..], addr, QUEUE_AVAIL_LOW_REG)); if let Ok(config) = virtio_device.lock().unwrap().queue_config() { assert_eq!(config.avail_ring.0 as u32, 0xfcfc_fafa) } else { @@ -1112,10 +1007,7 @@ mod tests { .set_device_status(CONFIG_STATUS_FEATURES_OK); let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; LittleEndian::write_u32(&mut buf[..], 0xecec_fafa); - assert_eq!( - virtio_mmio_device.write(&buf[..], addr, QUEUE_AVAIL_HIGH_REG), - true - ); + assert!(virtio_mmio_device.write(&buf[..], addr, QUEUE_AVAIL_HIGH_REG)); if let Ok(config) = virtio_device.lock().unwrap().queue_config() { assert_eq!((config.avail_ring.0 >> 32) as u32, 0xecec_fafa) } else { @@ -1130,10 +1022,7 @@ mod tests { .set_device_status(CONFIG_STATUS_FEATURES_OK); let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; LittleEndian::write_u32(&mut buf[..], 0xacac_fafa); - assert_eq!( - virtio_mmio_device.write(&buf[..], addr, QUEUE_USED_LOW_REG), - true - ); + assert!(virtio_mmio_device.write(&buf[..], addr, QUEUE_USED_LOW_REG)); if let Ok(config) = virtio_device.lock().unwrap().queue_config() { assert_eq!(config.used_ring.0 as u32, 0xacac_fafa) } else { @@ -1148,10 +1037,7 @@ mod tests { .set_device_status(CONFIG_STATUS_FEATURES_OK); let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; LittleEndian::write_u32(&mut buf[..], 0xcccc_fafa); - assert_eq!( - virtio_mmio_device.write(&buf[..], addr, QUEUE_USED_HIGH_REG), - true - ); + assert!(virtio_mmio_device.write(&buf[..], addr, QUEUE_USED_HIGH_REG)); if let Ok(config) = virtio_device.lock().unwrap().queue_config() { assert_eq!((config.used_ring.0 >> 32) as u32, 0xcccc_fafa) } else { @@ -1165,7 +1051,7 @@ mod tests { } else { 0 }; - (size + align_adjust) as u64 + size + align_adjust } #[test] @@ -1203,13 +1089,10 @@ mod tests { // write the device status let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; LittleEndian::write_u32(&mut buf[..], CONFIG_STATUS_ACKNOWLEDGE); - assert_eq!(virtio_mmio_device.write(&buf[..], addr, STATUS_REG), true); - assert_eq!(virtio_device.lock().unwrap().device_activated(), false); + assert!(virtio_mmio_device.write(&buf[..], addr, STATUS_REG)); + assert!(!virtio_device.lock().unwrap().device_activated()); let mut data: Vec = vec![0xff, 0xff, 0xff, 0xff]; - assert_eq!( - virtio_mmio_device.read(&mut data[..], addr, STATUS_REG), - true - ); + assert!(virtio_mmio_device.read(&mut data[..], addr, STATUS_REG)); assert_eq!(LittleEndian::read_u32(&data[..]), CONFIG_STATUS_ACKNOWLEDGE); let mut buf: Vec = vec![0xff, 0xff, 0xff, 0xff]; @@ -1220,15 +1103,12 @@ mod tests { | CONFIG_STATUS_DRIVER_OK | CONFIG_STATUS_FEATURES_OK, ); - assert_eq!(virtio_device.lock().unwrap().b_active, false); - assert_eq!(virtio_mmio_device.write(&buf[..], addr, STATUS_REG), true); - assert_eq!(virtio_device.lock().unwrap().device_activated(), true); - assert_eq!(virtio_device.lock().unwrap().b_active, true); + assert!(!virtio_device.lock().unwrap().b_active); + assert!(virtio_mmio_device.write(&buf[..], addr, STATUS_REG)); + assert!(virtio_device.lock().unwrap().device_activated()); + assert!(virtio_device.lock().unwrap().b_active); let mut data: Vec = vec![0xff, 0xff, 0xff, 0xff]; - assert_eq!( - virtio_mmio_device.read(&mut data[..], addr, STATUS_REG), - true - ); + assert!(virtio_mmio_device.read(&mut data[..], addr, STATUS_REG)); assert_eq!( LittleEndian::read_u32(&data[..]), CONFIG_STATUS_ACKNOWLEDGE diff --git a/virtio/src/transport/virtio_pci.rs b/virtio/src/transport/virtio_pci.rs index 22f69ca2..d656d283 100644 --- a/virtio/src/transport/virtio_pci.rs +++ b/virtio/src/transport/virtio_pci.rs @@ -1582,7 +1582,7 @@ mod tests { .unwrap() .virtio_base() .queues_config - .get(0) + .first() .unwrap() .ready ); @@ -1673,7 +1673,7 @@ mod tests { let status = (CONFIG_STATUS_ACKNOWLEDGE | CONFIG_STATUS_DRIVER | CONFIG_STATUS_FEATURES_OK) .as_bytes(); (common_cfg_ops.write)(status, GuestAddress(0), COMMON_STATUS_REG); - assert_eq!(virtio_dev.lock().unwrap().device_activated(), false); + assert!(!virtio_dev.lock().unwrap().device_activated()); // Device status is not ok, failed to activate virtio device let status = (CONFIG_STATUS_ACKNOWLEDGE | CONFIG_STATUS_DRIVER @@ -1681,7 +1681,7 @@ mod tests { | CONFIG_STATUS_FEATURES_OK) .as_bytes(); (common_cfg_ops.write)(status, GuestAddress(0), COMMON_STATUS_REG); - assert_eq!(virtio_dev.lock().unwrap().device_activated(), false); + assert!(!virtio_dev.lock().unwrap().device_activated()); // Status is ok, virtio device is activated. let status = (CONFIG_STATUS_ACKNOWLEDGE | CONFIG_STATUS_DRIVER @@ -1689,11 +1689,11 @@ mod tests { | CONFIG_STATUS_FEATURES_OK) .as_bytes(); (common_cfg_ops.write)(status, GuestAddress(0), COMMON_STATUS_REG); - assert_eq!(virtio_dev.lock().unwrap().device_activated(), true); + assert!(virtio_dev.lock().unwrap().device_activated()); // If device status(not zero) is set to zero, reset the device (common_cfg_ops.write)(0_u32.as_bytes(), GuestAddress(0), COMMON_STATUS_REG); - assert_eq!(virtio_dev.lock().unwrap().device_activated(), false); + assert!(!virtio_dev.lock().unwrap().device_activated()); } #[test] diff --git a/virtio/src/vhost/kernel/net.rs b/virtio/src/vhost/kernel/net.rs index 52dbb85a..1131bac3 100644 --- a/virtio/src/vhost/kernel/net.rs +++ b/virtio/src/vhost/kernel/net.rs @@ -459,7 +459,7 @@ mod tests { } // without assigned value of tap_fd and vhost_fd, // vhost-net device can be realized successfully. - assert_eq!(vhost_net.realize().is_ok(), true); + assert!(vhost_net.realize().is_ok()); // test for get/set_driver_features vhost_net.base.device_features = 0; @@ -482,22 +482,22 @@ mod tests { let len = vhost_net.config_space.lock().unwrap().as_bytes().len() as u64; let offset: u64 = 0; let data: Vec = vec![1; len as usize]; - assert_eq!(vhost_net.write_config(offset, &data).is_ok(), true); + assert!(vhost_net.write_config(offset, &data).is_ok()); let mut read_data: Vec = vec![0; len as usize]; - assert_eq!(vhost_net.read_config(offset, &mut read_data).is_ok(), true); + assert!(vhost_net.read_config(offset, &mut read_data).is_ok()); assert_ne!(read_data, data); let offset: u64 = 1; let data: Vec = vec![1; len as usize]; - assert_eq!(vhost_net.write_config(offset, &data).is_ok(), true); + assert!(vhost_net.write_config(offset, &data).is_ok()); let offset: u64 = len + 1; let mut read_data: Vec = vec![0; len as usize]; - assert_eq!(vhost_net.read_config(offset, &mut read_data).is_ok(), false); + assert!(vhost_net.read_config(offset, &mut read_data).is_err()); let offset: u64 = len - 1; let mut read_data: Vec = vec![0; len as usize]; - assert_eq!(vhost_net.read_config(offset, &mut read_data).is_ok(), false); + assert!(vhost_net.read_config(offset, &mut read_data).is_err()); } } diff --git a/virtio/src/vhost/kernel/vsock.rs b/virtio/src/vhost/kernel/vsock.rs index 18d3f56b..8774fbeb 100644 --- a/virtio/src/vhost/kernel/vsock.rs +++ b/virtio/src/vhost/kernel/vsock.rs @@ -417,8 +417,8 @@ mod tests { ..Default::default() }; let sys_mem = address_space_init(); - let vsock = Vsock::new(&vsock_conf, &sys_mem); - vsock + + Vsock::new(&vsock_conf, &sys_mem) } #[test] @@ -473,23 +473,23 @@ mod tests { // test vsock read_config let mut buf: [u8; 8] = [0; 8]; - assert_eq!(vsock.read_config(0, &mut buf).is_ok(), true); + assert!(vsock.read_config(0, &mut buf).is_ok()); let value = LittleEndian::read_u64(&buf); assert_eq!(value, vsock.vsock_cfg.guest_cid); let mut buf: [u8; 4] = [0; 4]; - assert_eq!(vsock.read_config(0, &mut buf).is_ok(), true); + assert!(vsock.read_config(0, &mut buf).is_ok()); let value = LittleEndian::read_u32(&buf); assert_eq!(value, vsock.vsock_cfg.guest_cid as u32); let mut buf: [u8; 4] = [0; 4]; - assert_eq!(vsock.read_config(4, &mut buf).is_ok(), true); + assert!(vsock.read_config(4, &mut buf).is_ok()); let value = LittleEndian::read_u32(&buf); assert_eq!(value, (vsock.vsock_cfg.guest_cid >> 32) as u32); let mut buf: [u8; 4] = [0; 4]; - assert_eq!(vsock.read_config(5, &mut buf).is_err(), true); - assert_eq!(vsock.read_config(3, &mut buf).is_err(), true); + assert!(vsock.read_config(5, &mut buf).is_err()); + assert!(vsock.read_config(3, &mut buf).is_err()); } #[test] @@ -508,12 +508,9 @@ mod tests { // test vsock set_guest_cid let backend = vsock.backend.unwrap(); - assert_eq!(backend.set_guest_cid(3).is_ok(), true); - assert_eq!( - backend.set_guest_cid(u64::from(u32::max_value())).is_ok(), - false - ); - assert_eq!(backend.set_guest_cid(2).is_ok(), false); - assert_eq!(backend.set_guest_cid(0).is_ok(), false); + assert!(backend.set_guest_cid(3).is_ok()); + assert!(backend.set_guest_cid(u64::from(u32::max_value())).is_err()); + assert!(backend.set_guest_cid(2).is_err()); + assert!(backend.set_guest_cid(0).is_err()); } } -- Gitee From ea95c6a5cde430241b9e78d60757cd286f59d423 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=BA=A2=E5=8D=8E?= Date: Sat, 17 Aug 2024 14:34:33 +0800 Subject: [PATCH 258/489] Usb_uas: Add usb_uas feature control Add usb_uas faeture to control usb_uas function. Signed-off-by: Yihua Jin --- Cargo.toml | 1 + devices/Cargo.toml | 1 + devices/src/usb/mod.rs | 1 + machine/Cargo.toml | 1 + machine/src/lib.rs | 2 ++ 5 files changed, 6 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 1af042fe..abe616bb 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -46,6 +46,7 @@ trace_to_ftrace = ["trace/trace_to_ftrace"] trace_to_hitrace = ["trace/trace_to_hitrace"] hisysevent = ["hisysevent/hisysevent"] vfio = ["machine/vfio_device", "hypervisor/vfio_device"] +usb_uas = ["machine/usb_uas"] [package.metadata.rpm.cargo] buildflags = ["--release"] diff --git a/devices/Cargo.toml b/devices/Cargo.toml index 69dc546d..d411cc5c 100644 --- a/devices/Cargo.toml +++ b/devices/Cargo.toml @@ -53,3 +53,4 @@ usb_camera = ["machine_manager/usb_camera"] usb_camera_v4l2 = ["usb_camera", "dep:v4l2-sys-mit", "machine_manager/usb_camera_v4l2", "util/usb_camera_v4l2"] usb_camera_oh = ["usb_camera", "machine_manager/usb_camera_oh", "util/usb_camera_oh"] ramfb = ["ui/console", "util/pixman"] +usb_uas = [] diff --git a/devices/src/usb/mod.rs b/devices/src/usb/mod.rs index 5ddaef9e..5670f16f 100644 --- a/devices/src/usb/mod.rs +++ b/devices/src/usb/mod.rs @@ -20,6 +20,7 @@ pub mod hid; pub mod keyboard; pub mod storage; pub mod tablet; +#[cfg(feature = "usb_uas")] pub mod uas; #[cfg(feature = "usb_host")] pub mod usbhost; diff --git a/machine/Cargo.toml b/machine/Cargo.toml index ce455c71..d36c786b 100644 --- a/machine/Cargo.toml +++ b/machine/Cargo.toml @@ -51,3 +51,4 @@ ohui_srv = ["windows_emu_pid", "ui/ohui_srv", "machine_manager/ohui_srv", "virti ramfb = ["devices/ramfb", "machine_manager/ramfb"] virtio_gpu = ["virtio/virtio_gpu", "machine_manager/virtio_gpu"] vfio_device = ["vfio"] +usb_uas = ["devices/usb_uas"] diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 882db2b8..f820af3e 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -66,6 +66,7 @@ use devices::usb::camera::{UsbCamera, UsbCameraConfig}; use devices::usb::keyboard::{UsbKeyboard, UsbKeyboardConfig}; use devices::usb::storage::{UsbStorage, UsbStorageConfig}; use devices::usb::tablet::{UsbTablet, UsbTabletConfig}; +#[cfg(feature = "usb_uas")] use devices::usb::uas::{UsbUas, UsbUasConfig}; #[cfg(feature = "usb_host")] use devices::usb::usbhost::{UsbHost, UsbHostConfig}; @@ -1823,6 +1824,7 @@ pub trait MachineOps: MachineLifecycle { .realize() .with_context(|| "Failed to realize usb storage device")? } + #[cfg(feature = "usb_uas")] "usb-uas" => { let device_cfg = UsbUasConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; -- Gitee From 7bd78754a610080eae9c5446484cfb77e4f5b33d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=BA=A2=E5=8D=8E?= Date: Mon, 19 Aug 2024 15:38:45 +0800 Subject: [PATCH 259/489] Virtio: Add virtio rng feature Add virtio rng feature to control virtio rng function. Signed-off-by: Yihua Jin --- Cargo.toml | 1 + machine/Cargo.toml | 1 + machine/src/lib.rs | 13 ++++++++----- virtio/Cargo.toml | 1 + virtio/src/device/mod.rs | 1 + virtio/src/lib.rs | 1 + 6 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index abe616bb..dabc17f7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -47,6 +47,7 @@ trace_to_hitrace = ["trace/trace_to_hitrace"] hisysevent = ["hisysevent/hisysevent"] vfio = ["machine/vfio_device", "hypervisor/vfio_device"] usb_uas = ["machine/usb_uas"] +virtio_rng = ["machine/virtio_rng"] [package.metadata.rpm.cargo] buildflags = ["--release"] diff --git a/machine/Cargo.toml b/machine/Cargo.toml index d36c786b..2a73737e 100644 --- a/machine/Cargo.toml +++ b/machine/Cargo.toml @@ -52,3 +52,4 @@ ramfb = ["devices/ramfb", "machine_manager/ramfb"] virtio_gpu = ["virtio/virtio_gpu", "machine_manager/virtio_gpu"] vfio_device = ["vfio"] usb_uas = ["devices/usb_uas"] +virtio_rng = ["virtio/virtio_rng"] diff --git a/machine/src/lib.rs b/machine/src/lib.rs index f820af3e..3176432a 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -106,14 +106,15 @@ use vfio::{vfio_register_pcidevops_type, VfioConfig, VfioDevice, VfioPciDevice, use virtio::VirtioDeviceQuirk; use virtio::{ balloon_allow_list, find_port_by_nr, get_max_nr, vhost, virtio_register_pcidevops_type, - virtio_register_sysbusdevops_type, Balloon, BalloonConfig, Block, BlockState, Rng, RngConfig, - RngState, + virtio_register_sysbusdevops_type, Balloon, BalloonConfig, Block, BlockState, ScsiCntlr::{scsi_cntlr_create_scsi_bus, ScsiCntlr, ScsiCntlrConfig}, Serial, SerialPort, VhostKern, VhostUser, VirtioBlkDevConfig, VirtioDevice, VirtioMmioDevice, VirtioMmioState, VirtioNetState, VirtioPciDevice, VirtioSerialState, VIRTIO_TYPE_CONSOLE, }; #[cfg(feature = "virtio_gpu")] use virtio::{Gpu, GpuDevConfig}; +#[cfg(feature = "virtio_rng")] +use virtio::{Rng, RngConfig, RngState}; #[cfg(feature = "windows_emu_pid")] const WINDOWS_EMU_PID_DEFAULT_INTERVAL: u64 = 4000; @@ -290,7 +291,7 @@ macro_rules! create_device_add_matches { ( $command:expr; $controller: expr; $(($($driver_name:tt)|+, $function_name:tt, $($arg:tt),*)),*; $(#[cfg($($features: tt)*)] - ($driver_name1:tt, $function_name1:tt, $($arg1:tt),*)),* + ($($driver_name1:tt)|+, $function_name1:tt, $($arg1:tt),*)),* ) => { match $command { $( @@ -300,7 +301,7 @@ macro_rules! create_device_add_matches { )* $( #[cfg($($features)*)] - $driver_name1 => { + $($driver_name1)|+ => { $controller.$function_name1($($arg1),*).with_context(|| format!("add {} fail.", $command))?; }, )* @@ -856,6 +857,7 @@ pub trait MachineOps: MachineLifecycle { /// /// * `vm_config` - VM configuration. /// * `cfg_args` - Device configuration arguments. + #[cfg(feature = "virtio_rng")] fn add_virtio_rng(&mut self, vm_config: &mut VmConfig, cfg_args: &str) -> Result<()> { let rng_cfg = RngConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; rng_cfg.bytes_per_sec()?; @@ -1900,12 +1902,13 @@ pub trait MachineOps: MachineLifecycle { ("virtio-balloon-device" | "virtio-balloon-pci", add_virtio_balloon, vm_config, cfg_args), ("virtio-serial-device" | "virtio-serial-pci", add_virtio_serial, vm_config, cfg_args), ("virtconsole" | "virtserialport", add_virtio_serial_port, vm_config, cfg_args), - ("virtio-rng-device" | "virtio-rng-pci", add_virtio_rng, vm_config, cfg_args), ("vhost-user-blk-device",add_vhost_user_blk_device, vm_config, cfg_args), ("vhost-user-blk-pci",add_vhost_user_blk_pci, vm_config, cfg_args, false), ("vhost-user-fs-pci" | "vhost-user-fs-device", add_virtio_fs, vm_config, cfg_args), ("nec-usb-xhci", add_usb_xhci, cfg_args), ("usb-kbd" | "usb-storage" | "usb-uas" | "usb-tablet" | "usb-camera" | "usb-host", add_usb_device, vm_config, cfg_args); + #[cfg(feature = "virtio_rng")] + ("virtio-rng-device" | "virtio-rng-pci", add_virtio_rng, vm_config, cfg_args), #[cfg(feature = "vfio_device")] ("vfio-pci", add_vfio_device, cfg_args, false), #[cfg(feature = "virtio_gpu")] diff --git a/virtio/Cargo.toml b/virtio/Cargo.toml index 91c89cd0..8563bc81 100644 --- a/virtio/Cargo.toml +++ b/virtio/Cargo.toml @@ -31,4 +31,5 @@ clap = { version = "=4.1.4", default-features = false, features = ["std", "deriv [features] default = [] virtio_gpu = ["ui", "machine_manager/virtio_gpu", "util/pixman"] +virtio_rng = [] ohui_srv = [] diff --git a/virtio/src/device/mod.rs b/virtio/src/device/mod.rs index 11ea8ed9..410b4a75 100644 --- a/virtio/src/device/mod.rs +++ b/virtio/src/device/mod.rs @@ -15,6 +15,7 @@ pub mod block; #[cfg(feature = "virtio_gpu")] pub mod gpu; pub mod net; +#[cfg(feature = "virtio_rng")] pub mod rng; pub mod scsi_cntlr; pub mod serial; diff --git a/virtio/src/lib.rs b/virtio/src/lib.rs index f4cc3c15..76be0460 100644 --- a/virtio/src/lib.rs +++ b/virtio/src/lib.rs @@ -37,6 +37,7 @@ pub use device::block::{Block, BlockState, VirtioBlkConfig, VirtioBlkDevConfig}; #[cfg(feature = "virtio_gpu")] pub use device::gpu::*; pub use device::net::*; +#[cfg(feature = "virtio_rng")] pub use device::rng::{Rng, RngConfig, RngState}; pub use device::scsi_cntlr as ScsiCntlr; pub use device::serial::{find_port_by_nr, get_max_nr, Serial, SerialPort, VirtioSerialState}; -- Gitee From e1e14e3af372ba20a24a552e45677c957b17da2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=BA=A2=E5=8D=8E?= Date: Sat, 17 Aug 2024 16:49:00 +0800 Subject: [PATCH 260/489] Virtio: Add virtio scsi feature Add virtio scsi feature to control virtio scsi function. Signed-off-by: Yihua Jin --- Cargo.toml | 1 + machine/Cargo.toml | 1 + machine/src/lib.rs | 22 +++++++++++++++------- machine/src/standard_common/mod.rs | 1 + virtio/Cargo.toml | 1 + virtio/src/device/mod.rs | 1 + virtio/src/lib.rs | 1 + 7 files changed, 21 insertions(+), 7 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dabc17f7..dc409580 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,6 +48,7 @@ hisysevent = ["hisysevent/hisysevent"] vfio = ["machine/vfio_device", "hypervisor/vfio_device"] usb_uas = ["machine/usb_uas"] virtio_rng = ["machine/virtio_rng"] +virtio_scsi = ["machine/virtio_scsi"] [package.metadata.rpm.cargo] buildflags = ["--release"] diff --git a/machine/Cargo.toml b/machine/Cargo.toml index 2a73737e..6a2476c4 100644 --- a/machine/Cargo.toml +++ b/machine/Cargo.toml @@ -53,3 +53,4 @@ virtio_gpu = ["virtio/virtio_gpu", "machine_manager/virtio_gpu"] vfio_device = ["vfio"] usb_uas = ["devices/usb_uas"] virtio_rng = ["virtio/virtio_rng"] +virtio_scsi = ["virtio/virtio_scsi"] diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 3176432a..9210f390 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -74,9 +74,12 @@ use devices::usb::xhci::xhci_pci::{XhciConfig, XhciPciDevice}; use devices::usb::UsbDevice; #[cfg(target_arch = "aarch64")] use devices::InterruptController; -use devices::ScsiBus::get_scsi_key; -use devices::ScsiDisk::{ScsiDevConfig, ScsiDevice}; use devices::{convert_bus_ref, Bus, Device, PCI_BUS, SYS_BUS_DEVICE}; +#[cfg(feature = "virtio_scsi")] +use devices::{ + ScsiBus::get_scsi_key, + ScsiDisk::{ScsiDevConfig, ScsiDevice}, +}; use hypervisor::{kvm::KvmHypervisor, test::TestHypervisor, HypervisorOps}; #[cfg(feature = "usb_camera")] use machine_manager::config::get_cameradev_by_id; @@ -102,13 +105,14 @@ use util::loop_context::{ use util::seccomp::{BpfRule, SeccompOpt, SyscallFilter}; #[cfg(feature = "vfio_device")] use vfio::{vfio_register_pcidevops_type, VfioConfig, VfioDevice, VfioPciDevice, KVM_DEVICE_FD}; +#[cfg(feature = "virtio_scsi")] +use virtio::ScsiCntlr::{scsi_cntlr_create_scsi_bus, ScsiCntlr, ScsiCntlrConfig}; #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] use virtio::VirtioDeviceQuirk; use virtio::{ balloon_allow_list, find_port_by_nr, get_max_nr, vhost, virtio_register_pcidevops_type, - virtio_register_sysbusdevops_type, Balloon, BalloonConfig, Block, BlockState, - ScsiCntlr::{scsi_cntlr_create_scsi_bus, ScsiCntlr, ScsiCntlrConfig}, - Serial, SerialPort, VhostKern, VhostUser, VirtioBlkDevConfig, VirtioDevice, VirtioMmioDevice, + virtio_register_sysbusdevops_type, Balloon, BalloonConfig, Block, BlockState, Serial, + SerialPort, VhostKern, VhostUser, VirtioBlkDevConfig, VirtioDevice, VirtioMmioDevice, VirtioMmioState, VirtioNetState, VirtioPciDevice, VirtioSerialState, VIRTIO_TYPE_CONSOLE, }; #[cfg(feature = "virtio_gpu")] @@ -1164,6 +1168,7 @@ pub trait MachineOps: MachineLifecycle { Ok(()) } + #[cfg(feature = "virtio_scsi")] fn add_virtio_pci_scsi( &mut self, vm_config: &mut VmConfig, @@ -1195,6 +1200,7 @@ pub trait MachineOps: MachineLifecycle { Ok(()) } + #[cfg(feature = "virtio_scsi")] fn add_scsi_device(&mut self, vm_config: &mut VmConfig, cfg_args: &str) -> Result<()> { let device_cfg = ScsiDevConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; let drive_arg = vm_config @@ -1893,8 +1899,6 @@ pub trait MachineOps: MachineLifecycle { dev.0.as_str(); self; ("virtio-blk-device", add_virtio_mmio_block, vm_config, cfg_args), ("virtio-blk-pci", add_virtio_pci_blk, vm_config, cfg_args, false), - ("virtio-scsi-pci", add_virtio_pci_scsi, vm_config, cfg_args, false), - ("scsi-hd" | "scsi-cd", add_scsi_device, vm_config, cfg_args), ("virtio-net-device", add_virtio_mmio_net, vm_config, cfg_args), ("virtio-net-pci", add_virtio_pci_net, vm_config, cfg_args, false), ("pcie-root-port", add_pci_root_port, cfg_args), @@ -1913,6 +1917,10 @@ pub trait MachineOps: MachineLifecycle { ("vfio-pci", add_vfio_device, cfg_args, false), #[cfg(feature = "virtio_gpu")] ("virtio-gpu-pci", add_virtio_pci_gpu, cfg_args), + #[cfg(feature = "virtio_scsi")] + ("virtio-scsi-pci", add_virtio_pci_scsi, vm_config, cfg_args, false), + #[cfg(feature = "virtio_scsi")] + ("scsi-hd" | "scsi-cd", add_scsi_device, vm_config, cfg_args), #[cfg(feature = "ramfb")] ("ramfb", add_ramfb, cfg_args), #[cfg(feature = "demo_device")] diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index 806e5516..ced6372f 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -1216,6 +1216,7 @@ impl DeviceInterface for StdMachine { ); } } + #[cfg(feature = "virtio_scsi")] "virtio-scsi-pci" => { let cfg_args = locked_vmconfig.add_device_config(args.as_ref()); if let Err(e) = self.add_virtio_pci_scsi(&mut vm_config_clone, &cfg_args, true) { diff --git a/virtio/Cargo.toml b/virtio/Cargo.toml index 8563bc81..de0b7c61 100644 --- a/virtio/Cargo.toml +++ b/virtio/Cargo.toml @@ -32,4 +32,5 @@ clap = { version = "=4.1.4", default-features = false, features = ["std", "deriv default = [] virtio_gpu = ["ui", "machine_manager/virtio_gpu", "util/pixman"] virtio_rng = [] +virtio_scsi = [] ohui_srv = [] diff --git a/virtio/src/device/mod.rs b/virtio/src/device/mod.rs index 410b4a75..1f9ddba8 100644 --- a/virtio/src/device/mod.rs +++ b/virtio/src/device/mod.rs @@ -17,5 +17,6 @@ pub mod gpu; pub mod net; #[cfg(feature = "virtio_rng")] pub mod rng; +#[cfg(feature = "virtio_scsi")] pub mod scsi_cntlr; pub mod serial; diff --git a/virtio/src/lib.rs b/virtio/src/lib.rs index 76be0460..3245477d 100644 --- a/virtio/src/lib.rs +++ b/virtio/src/lib.rs @@ -39,6 +39,7 @@ pub use device::gpu::*; pub use device::net::*; #[cfg(feature = "virtio_rng")] pub use device::rng::{Rng, RngConfig, RngState}; +#[cfg(feature = "virtio_scsi")] pub use device::scsi_cntlr as ScsiCntlr; pub use device::serial::{find_port_by_nr, get_max_nr, Serial, SerialPort, VirtioSerialState}; pub use error::VirtioError; -- Gitee From 7418aba67ea0954d7a3bdb876fc4d41e6a429691 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=BA=A2=E5=8D=8E?= Date: Mon, 19 Aug 2024 16:00:07 +0800 Subject: [PATCH 261/489] Virtio: Add vhost vsock feature Add vhost vsock feature to control vhost vsock function. Signed-off-by: Yihua Jin --- Cargo.toml | 1 + machine/Cargo.toml | 1 + machine/src/lib.rs | 10 +++++++--- virtio/Cargo.toml | 1 + virtio/src/vhost/kernel/mod.rs | 2 ++ 5 files changed, 12 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index dc409580..4c8df16c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -49,6 +49,7 @@ vfio = ["machine/vfio_device", "hypervisor/vfio_device"] usb_uas = ["machine/usb_uas"] virtio_rng = ["machine/virtio_rng"] virtio_scsi = ["machine/virtio_scsi"] +vhost_vsock = ["machine/vhost_vsock"] [package.metadata.rpm.cargo] buildflags = ["--release"] diff --git a/machine/Cargo.toml b/machine/Cargo.toml index 6a2476c4..b76c0c2b 100644 --- a/machine/Cargo.toml +++ b/machine/Cargo.toml @@ -54,3 +54,4 @@ vfio_device = ["vfio"] usb_uas = ["devices/usb_uas"] virtio_rng = ["virtio/virtio_rng"] virtio_scsi = ["virtio/virtio_scsi"] +vhost_vsock = ["virtio/vhost_vsock"] diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 9210f390..c6ca238b 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -107,13 +107,15 @@ use util::seccomp::{BpfRule, SeccompOpt, SyscallFilter}; use vfio::{vfio_register_pcidevops_type, VfioConfig, VfioDevice, VfioPciDevice, KVM_DEVICE_FD}; #[cfg(feature = "virtio_scsi")] use virtio::ScsiCntlr::{scsi_cntlr_create_scsi_bus, ScsiCntlr, ScsiCntlrConfig}; +#[cfg(any(feature = "vhost_vsock"))] +use virtio::VhostKern; #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] use virtio::VirtioDeviceQuirk; use virtio::{ balloon_allow_list, find_port_by_nr, get_max_nr, vhost, virtio_register_pcidevops_type, virtio_register_sysbusdevops_type, Balloon, BalloonConfig, Block, BlockState, Serial, - SerialPort, VhostKern, VhostUser, VirtioBlkDevConfig, VirtioDevice, VirtioMmioDevice, - VirtioMmioState, VirtioNetState, VirtioPciDevice, VirtioSerialState, VIRTIO_TYPE_CONSOLE, + SerialPort, VhostUser, VirtioBlkDevConfig, VirtioDevice, VirtioMmioDevice, VirtioMmioState, + VirtioNetState, VirtioPciDevice, VirtioSerialState, VIRTIO_TYPE_CONSOLE, }; #[cfg(feature = "virtio_gpu")] use virtio::{Gpu, GpuDevConfig}; @@ -590,6 +592,7 @@ pub trait MachineOps: MachineLifecycle { /// # Arguments /// /// * `cfg_args` - Device configuration. + #[cfg(feature = "vhost_vsock")] fn add_virtio_vsock(&mut self, cfg_args: &str) -> Result<()> { let device_cfg = VhostKern::VsockConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; @@ -1902,7 +1905,6 @@ pub trait MachineOps: MachineLifecycle { ("virtio-net-device", add_virtio_mmio_net, vm_config, cfg_args), ("virtio-net-pci", add_virtio_pci_net, vm_config, cfg_args, false), ("pcie-root-port", add_pci_root_port, cfg_args), - ("vhost-vsock-pci" | "vhost-vsock-device", add_virtio_vsock, cfg_args), ("virtio-balloon-device" | "virtio-balloon-pci", add_virtio_balloon, vm_config, cfg_args), ("virtio-serial-device" | "virtio-serial-pci", add_virtio_serial, vm_config, cfg_args), ("virtconsole" | "virtserialport", add_virtio_serial_port, vm_config, cfg_args), @@ -1911,6 +1913,8 @@ pub trait MachineOps: MachineLifecycle { ("vhost-user-fs-pci" | "vhost-user-fs-device", add_virtio_fs, vm_config, cfg_args), ("nec-usb-xhci", add_usb_xhci, cfg_args), ("usb-kbd" | "usb-storage" | "usb-uas" | "usb-tablet" | "usb-camera" | "usb-host", add_usb_device, vm_config, cfg_args); + #[cfg(feature = "vhost_vsock")] + ("vhost-vsock-pci" | "vhost-vsock-device", add_virtio_vsock, cfg_args), #[cfg(feature = "virtio_rng")] ("virtio-rng-device" | "virtio-rng-pci", add_virtio_rng, vm_config, cfg_args), #[cfg(feature = "vfio_device")] diff --git a/virtio/Cargo.toml b/virtio/Cargo.toml index de0b7c61..5e632747 100644 --- a/virtio/Cargo.toml +++ b/virtio/Cargo.toml @@ -34,3 +34,4 @@ virtio_gpu = ["ui", "machine_manager/virtio_gpu", "util/pixman"] virtio_rng = [] virtio_scsi = [] ohui_srv = [] +vhost_vsock =[] diff --git a/virtio/src/vhost/kernel/mod.rs b/virtio/src/vhost/kernel/mod.rs index 2111e2bb..3e204989 100644 --- a/virtio/src/vhost/kernel/mod.rs +++ b/virtio/src/vhost/kernel/mod.rs @@ -11,9 +11,11 @@ // See the Mulan PSL v2 for more details. mod net; +#[cfg(feature = "vhost_vsock")] mod vsock; pub use net::Net; +#[cfg(feature = "vhost_vsock")] pub use vsock::{Vsock, VsockConfig, VsockState}; use std::fs::{File, OpenOptions}; -- Gitee From eb0c99f030734dd326bb8a6143b6cc30980493f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=BA=A2=E5=8D=8E?= Date: Sat, 17 Aug 2024 17:45:29 +0800 Subject: [PATCH 262/489] Virtio: Add vhost user block feature Add vhost user block feature to control vhost vsock function. Signed-off-by: Yihua Jin --- Cargo.toml | 1 + machine/Cargo.toml | 1 + machine/src/lib.rs | 8 ++++++-- machine/src/standard_common/mod.rs | 1 + virtio/Cargo.toml | 1 + virtio/src/vhost/user/mod.rs | 2 ++ 6 files changed, 12 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 4c8df16c..ec1ff2a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,6 +50,7 @@ usb_uas = ["machine/usb_uas"] virtio_rng = ["machine/virtio_rng"] virtio_scsi = ["machine/virtio_scsi"] vhost_vsock = ["machine/vhost_vsock"] +vhostuser_block = ["machine/vhostuser_block"] [package.metadata.rpm.cargo] buildflags = ["--release"] diff --git a/machine/Cargo.toml b/machine/Cargo.toml index b76c0c2b..e8bfa32b 100644 --- a/machine/Cargo.toml +++ b/machine/Cargo.toml @@ -55,3 +55,4 @@ usb_uas = ["devices/usb_uas"] virtio_rng = ["virtio/virtio_rng"] virtio_scsi = ["virtio/virtio_scsi"] vhost_vsock = ["virtio/vhost_vsock"] +vhostuser_block = ["virtio/vhostuser_block"] diff --git a/machine/src/lib.rs b/machine/src/lib.rs index c6ca238b..05c40c53 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -1317,6 +1317,7 @@ pub trait MachineOps: MachineLifecycle { Ok(()) } + #[cfg(feature = "vhostuser_block")] fn add_vhost_user_blk_pci( &mut self, vm_config: &mut VmConfig, @@ -1370,6 +1371,7 @@ pub trait MachineOps: MachineLifecycle { Ok(()) } + #[cfg(feature = "vhostuser_block")] fn add_vhost_user_blk_device( &mut self, vm_config: &mut VmConfig, @@ -1908,11 +1910,13 @@ pub trait MachineOps: MachineLifecycle { ("virtio-balloon-device" | "virtio-balloon-pci", add_virtio_balloon, vm_config, cfg_args), ("virtio-serial-device" | "virtio-serial-pci", add_virtio_serial, vm_config, cfg_args), ("virtconsole" | "virtserialport", add_virtio_serial_port, vm_config, cfg_args), - ("vhost-user-blk-device",add_vhost_user_blk_device, vm_config, cfg_args), - ("vhost-user-blk-pci",add_vhost_user_blk_pci, vm_config, cfg_args, false), ("vhost-user-fs-pci" | "vhost-user-fs-device", add_virtio_fs, vm_config, cfg_args), ("nec-usb-xhci", add_usb_xhci, cfg_args), ("usb-kbd" | "usb-storage" | "usb-uas" | "usb-tablet" | "usb-camera" | "usb-host", add_usb_device, vm_config, cfg_args); + #[cfg(feature = "vhostuser_block")] + ("vhost-user-blk-device",add_vhost_user_blk_device, vm_config, cfg_args), + #[cfg(feature = "vhostuser_block")] + ("vhost-user-blk-pci",add_vhost_user_blk_pci, vm_config, cfg_args, false), #[cfg(feature = "vhost_vsock")] ("vhost-vsock-pci" | "vhost-vsock-device", add_virtio_vsock, cfg_args), #[cfg(feature = "virtio_rng")] diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index ced6372f..70c36a49 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -1229,6 +1229,7 @@ impl DeviceInterface for StdMachine { ); } } + #[cfg(feature = "vhostuser_block")] "vhost-user-blk-pci" => { let cfg_args = locked_vmconfig.add_device_config(args.as_ref()); if let Err(e) = self.add_vhost_user_blk_pci(&mut vm_config_clone, &cfg_args, true) { diff --git a/virtio/Cargo.toml b/virtio/Cargo.toml index 5e632747..3c9d7c6b 100644 --- a/virtio/Cargo.toml +++ b/virtio/Cargo.toml @@ -35,3 +35,4 @@ virtio_rng = [] virtio_scsi = [] ohui_srv = [] vhost_vsock =[] +vhostuser_block = [] diff --git a/virtio/src/vhost/user/mod.rs b/virtio/src/vhost/user/mod.rs index 8a6e8d42..8476b97f 100644 --- a/virtio/src/vhost/user/mod.rs +++ b/virtio/src/vhost/user/mod.rs @@ -12,12 +12,14 @@ pub mod fs; +#[cfg(feature = "vhostuser_block")] mod block; mod client; mod message; mod net; mod sock; +#[cfg(feature = "vhostuser_block")] pub use self::block::{Block, VhostUserBlkDevConfig}; pub use self::client::*; pub use self::fs::*; -- Gitee From 378e7c3bcc47ec20ca8e3e523297cf0c408cba00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=BA=A2=E5=8D=8E?= Date: Sat, 17 Aug 2024 18:10:49 +0800 Subject: [PATCH 263/489] Virtio: Add vhost user net feature Add vhost user net feature to control vhost vsock function. Signed-off-by: Yihua Jin --- Cargo.toml | 1 + machine/Cargo.toml | 1 + machine/src/lib.rs | 46 ++++++++++++++++++------------- machine/src/micro_common/mod.rs | 48 ++++++++++++++++++++------------- virtio/Cargo.toml | 1 + virtio/src/vhost/user/mod.rs | 2 ++ 6 files changed, 61 insertions(+), 38 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ec1ff2a0..fb27ccea 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -51,6 +51,7 @@ virtio_rng = ["machine/virtio_rng"] virtio_scsi = ["machine/virtio_scsi"] vhost_vsock = ["machine/vhost_vsock"] vhostuser_block = ["machine/vhostuser_block"] +vhostuser_net = ["machine/vhostuser_net"] [package.metadata.rpm.cargo] buildflags = ["--release"] diff --git a/machine/Cargo.toml b/machine/Cargo.toml index e8bfa32b..bbab764d 100644 --- a/machine/Cargo.toml +++ b/machine/Cargo.toml @@ -56,3 +56,4 @@ virtio_rng = ["virtio/virtio_rng"] virtio_scsi = ["virtio/virtio_scsi"] vhost_vsock = ["virtio/vhost_vsock"] vhostuser_block = ["virtio/vhostuser_block"] +vhostuser_net = ["virtio/vhostuser_net"] diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 05c40c53..1e222677 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -83,12 +83,14 @@ use devices::{ use hypervisor::{kvm::KvmHypervisor, test::TestHypervisor, HypervisorOps}; #[cfg(feature = "usb_camera")] use machine_manager::config::get_cameradev_by_id; +#[cfg(feature = "vhostuser_net")] +use machine_manager::config::get_chardev_socket_path; use machine_manager::config::{ - complete_numa_node, get_chardev_socket_path, get_class_type, get_pci_bdf, - get_value_of_parameter, parse_numa_distance, parse_numa_mem, str_slip_to_clap, BootIndexInfo, - BootSource, ConfigCheck, DriveConfig, DriveFile, Incoming, MachineMemConfig, MigrateMode, - NetworkInterfaceConfig, NumaNode, NumaNodes, PciBdf, SerialConfig, VirtioSerialInfo, - VirtioSerialPortCfg, VmConfig, FAST_UNPLUG_ON, MAX_VIRTIO_QUEUE, + complete_numa_node, get_class_type, get_pci_bdf, get_value_of_parameter, parse_numa_distance, + parse_numa_mem, str_slip_to_clap, BootIndexInfo, BootSource, ConfigCheck, DriveConfig, + DriveFile, Incoming, MachineMemConfig, MigrateMode, NetworkInterfaceConfig, NumaNode, + NumaNodes, PciBdf, SerialConfig, VirtioSerialInfo, VirtioSerialPortCfg, VmConfig, + FAST_UNPLUG_ON, MAX_VIRTIO_QUEUE, }; use machine_manager::event_loop::EventLoop; use machine_manager::machine::{HypervisorType, MachineInterface, MachineLifecycle, VmState}; @@ -1286,20 +1288,26 @@ pub trait MachineOps: MachineLifecycle { self.get_sys_mem(), ))) } else { - let chardev = netdev_cfg.chardev.clone().with_context(|| { - format!("Chardev not configured for netdev {:?}", netdev_cfg.id) - })?; - let chardev_cfg = vm_config - .chardev - .remove(&chardev) - .with_context(|| format!("Chardev: {:?} not found for netdev", chardev))?; - let sock_path = get_chardev_socket_path(chardev_cfg)?; - Arc::new(Mutex::new(VhostUser::Net::new( - &net_cfg, - netdev_cfg, - sock_path, - self.get_sys_mem(), - ))) + #[cfg(not(feature = "vhostuser_net"))] + bail!("Unsupported Vhostuser_net"); + + #[cfg(feature = "vhostuser_net")] + { + let chardev = netdev_cfg.chardev.clone().with_context(|| { + format!("Chardev not configured for netdev {:?}", netdev_cfg.id) + })?; + let chardev_cfg = vm_config + .chardev + .remove(&chardev) + .with_context(|| format!("Chardev: {:?} not found for netdev", chardev))?; + let sock_path = get_chardev_socket_path(chardev_cfg)?; + Arc::new(Mutex::new(VhostUser::Net::new( + &net_cfg, + netdev_cfg, + sock_path, + self.get_sys_mem(), + ))) + } } } else { let device = Arc::new(Mutex::new(virtio::Net::new(net_cfg.clone(), netdev_cfg))); diff --git a/machine/src/micro_common/mod.rs b/machine/src/micro_common/mod.rs index 8410e96b..18746a1d 100644 --- a/machine/src/micro_common/mod.rs +++ b/machine/src/micro_common/mod.rs @@ -52,11 +52,13 @@ use cpu::CpuLifecycleState; use devices::sysbus::SysBusDevOps; use devices::sysbus::{IRQ_BASE, IRQ_MAX}; use devices::Device; +#[cfg(feature = "vhostuser_net")] +use machine_manager::config::get_chardev_socket_path; #[cfg(target_arch = "x86_64")] use machine_manager::config::Param; use machine_manager::config::{ - get_chardev_socket_path, parse_incoming_uri, str_slip_to_clap, ConfigCheck, DriveConfig, - MigrateMode, NetDevcfg, NetworkInterfaceConfig, VmConfig, + parse_incoming_uri, str_slip_to_clap, ConfigCheck, DriveConfig, MigrateMode, NetDevcfg, + NetworkInterfaceConfig, VmConfig, }; use machine_manager::machine::{ DeviceInterface, MachineAddressInterface, MachineExternalInterface, MachineInterface, @@ -70,9 +72,11 @@ use migration::MigrationManager; use util::loop_context::{create_new_eventfd, EventLoopManager}; use util::{num_ops::str_to_num, set_termi_canon_mode}; use virtio::device::block::VirtioBlkDevConfig; +#[cfg(feature = "vhostuser_net")] +use virtio::VhostUser; use virtio::{ - create_tap, qmp_balloon, qmp_query_balloon, Block, BlockState, Net, VhostKern, VhostUser, - VirtioDevice, VirtioMmioDevice, VirtioMmioState, VirtioNetState, + create_tap, qmp_balloon, qmp_query_balloon, Block, BlockState, Net, VhostKern, VirtioDevice, + VirtioMmioDevice, VirtioMmioState, VirtioNetState, }; // The replaceable block device maximum count. @@ -422,21 +426,27 @@ impl LightMachine { ))); self.add_virtio_mmio_device(net_cfg.id.clone(), net)?; } else { - let chardev = netdev_cfg.chardev.clone().with_context(|| { - format!("Chardev not configured for netdev {:?}", netdev_cfg.id) - })?; - let chardev_cfg = vm_config - .chardev - .remove(&chardev) - .with_context(|| format!("Chardev: {:?} not found for netdev", chardev))?; - let sock_path = get_chardev_socket_path(chardev_cfg)?; - let net = Arc::new(Mutex::new(VhostUser::Net::new( - &net_cfg, - netdev_cfg, - sock_path, - &self.base.sys_mem, - ))); - self.add_virtio_mmio_device(net_cfg.id.clone(), net)?; + #[cfg(not(feature = "vhostuser_net"))] + bail!("Unsupported Vhostuser_Net"); + + #[cfg(feature = "vhostuser_net")] + { + let chardev = netdev_cfg.chardev.clone().with_context(|| { + format!("Chardev not configured for netdev {:?}", netdev_cfg.id) + })?; + let chardev_cfg = vm_config + .chardev + .remove(&chardev) + .with_context(|| format!("Chardev: {:?} not found for netdev", chardev))?; + let sock_path = get_chardev_socket_path(chardev_cfg)?; + let net = Arc::new(Mutex::new(VhostUser::Net::new( + &net_cfg, + netdev_cfg, + sock_path, + &self.base.sys_mem, + ))); + self.add_virtio_mmio_device(net_cfg.id.clone(), net)?; + } }; } else { let index = MMIO_REPLACEABLE_BLK_NR + self.replaceable_info.net_count; diff --git a/virtio/Cargo.toml b/virtio/Cargo.toml index 3c9d7c6b..20d02d9e 100644 --- a/virtio/Cargo.toml +++ b/virtio/Cargo.toml @@ -36,3 +36,4 @@ virtio_scsi = [] ohui_srv = [] vhost_vsock =[] vhostuser_block = [] +vhostuser_net = [] diff --git a/virtio/src/vhost/user/mod.rs b/virtio/src/vhost/user/mod.rs index 8476b97f..68a0b166 100644 --- a/virtio/src/vhost/user/mod.rs +++ b/virtio/src/vhost/user/mod.rs @@ -16,6 +16,7 @@ pub mod fs; mod block; mod client; mod message; +#[cfg(feature = "vhostuser_net")] mod net; mod sock; @@ -24,6 +25,7 @@ pub use self::block::{Block, VhostUserBlkDevConfig}; pub use self::client::*; pub use self::fs::*; pub use self::message::*; +#[cfg(feature = "vhostuser_net")] pub use self::net::Net; pub use self::sock::*; -- Gitee From 912a7b3fc31f7609ebbdbbb04ace658a8a0f215a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=BA=A2=E5=8D=8E?= Date: Sat, 17 Aug 2024 18:37:13 +0800 Subject: [PATCH 264/489] Virtio: Add vhost net feature Add vhost net feature to control vhost vsock function. Signed-off-by: Yihua Jin --- Cargo.toml | 1 + machine/Cargo.toml | 1 + machine/src/lib.rs | 28 ++++++++++++++++++++-------- machine/src/micro_common/mod.rs | 22 +++++++++++++++------- virtio/Cargo.toml | 1 + virtio/src/vhost/kernel/mod.rs | 2 ++ 6 files changed, 40 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index fb27ccea..8bb44175 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,6 +52,7 @@ virtio_scsi = ["machine/virtio_scsi"] vhost_vsock = ["machine/vhost_vsock"] vhostuser_block = ["machine/vhostuser_block"] vhostuser_net = ["machine/vhostuser_net"] +vhost_net = ["machine/vhost_net"] [package.metadata.rpm.cargo] buildflags = ["--release"] diff --git a/machine/Cargo.toml b/machine/Cargo.toml index bbab764d..dbb25016 100644 --- a/machine/Cargo.toml +++ b/machine/Cargo.toml @@ -57,3 +57,4 @@ virtio_scsi = ["virtio/virtio_scsi"] vhost_vsock = ["virtio/vhost_vsock"] vhostuser_block = ["virtio/vhostuser_block"] vhostuser_net = ["virtio/vhostuser_net"] +vhost_net = ["virtio/vhost_net"] diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 1e222677..9e24bfd2 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -109,14 +109,16 @@ use util::seccomp::{BpfRule, SeccompOpt, SyscallFilter}; use vfio::{vfio_register_pcidevops_type, VfioConfig, VfioDevice, VfioPciDevice, KVM_DEVICE_FD}; #[cfg(feature = "virtio_scsi")] use virtio::ScsiCntlr::{scsi_cntlr_create_scsi_bus, ScsiCntlr, ScsiCntlrConfig}; -#[cfg(any(feature = "vhost_vsock"))] +#[cfg(any(feature = "vhost_vsock", feature = "vhost_net"))] use virtio::VhostKern; +#[cfg(any(feature = "vhostuser_block", feature = "vhostuser_net"))] +use virtio::VhostUser; #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] use virtio::VirtioDeviceQuirk; use virtio::{ balloon_allow_list, find_port_by_nr, get_max_nr, vhost, virtio_register_pcidevops_type, virtio_register_sysbusdevops_type, Balloon, BalloonConfig, Block, BlockState, Serial, - SerialPort, VhostUser, VirtioBlkDevConfig, VirtioDevice, VirtioMmioDevice, VirtioMmioState, + SerialPort, VirtioBlkDevConfig, VirtioDevice, VirtioMmioDevice, VirtioMmioState, VirtioNetState, VirtioPciDevice, VirtioSerialState, VIRTIO_TYPE_CONSOLE, }; #[cfg(feature = "virtio_gpu")] @@ -1278,21 +1280,31 @@ pub trait MachineOps: MachineLifecycle { let bdf = PciBdf::new(net_cfg.bus.clone().unwrap(), net_cfg.addr.unwrap()); let multi_func = net_cfg.multifunction.unwrap_or_default(); + #[cfg(all(not(feature = "vhost_net"), not(feature = "vhostuser_net")))] + let need_irqfd = false; + #[cfg(any(feature = "vhost_net", feature = "vhostuser_net"))] let mut need_irqfd = false; let device: Arc> = if netdev_cfg.vhost_type().is_some() { - need_irqfd = true; if netdev_cfg.vhost_type().unwrap() == "vhost-kernel" { - Arc::new(Mutex::new(VhostKern::Net::new( - &net_cfg, - netdev_cfg, - self.get_sys_mem(), - ))) + #[cfg(not(feature = "vhost_net"))] + bail!("Unsupported Vhost_net"); + + #[cfg(feature = "vhost_net")] + { + need_irqfd = true; + Arc::new(Mutex::new(VhostKern::Net::new( + &net_cfg, + netdev_cfg, + self.get_sys_mem(), + ))) + } } else { #[cfg(not(feature = "vhostuser_net"))] bail!("Unsupported Vhostuser_net"); #[cfg(feature = "vhostuser_net")] { + need_irqfd = true; let chardev = netdev_cfg.chardev.clone().with_context(|| { format!("Chardev not configured for netdev {:?}", netdev_cfg.id) })?; diff --git a/machine/src/micro_common/mod.rs b/machine/src/micro_common/mod.rs index 18746a1d..34c12318 100644 --- a/machine/src/micro_common/mod.rs +++ b/machine/src/micro_common/mod.rs @@ -72,10 +72,12 @@ use migration::MigrationManager; use util::loop_context::{create_new_eventfd, EventLoopManager}; use util::{num_ops::str_to_num, set_termi_canon_mode}; use virtio::device::block::VirtioBlkDevConfig; +#[cfg(feature = "vhost_net")] +use virtio::VhostKern; #[cfg(feature = "vhostuser_net")] use virtio::VhostUser; use virtio::{ - create_tap, qmp_balloon, qmp_query_balloon, Block, BlockState, Net, VhostKern, VirtioDevice, + create_tap, qmp_balloon, qmp_query_balloon, Block, BlockState, Net, VirtioDevice, VirtioMmioDevice, VirtioMmioState, VirtioNetState, }; @@ -419,12 +421,18 @@ impl LightMachine { .with_context(|| format!("Netdev: {:?} not found for net device", &net_cfg.netdev))?; if netdev_cfg.vhost_type().is_some() { if netdev_cfg.vhost_type().unwrap() == "vhost-kernel" { - let net = Arc::new(Mutex::new(VhostKern::Net::new( - &net_cfg, - netdev_cfg, - &self.base.sys_mem, - ))); - self.add_virtio_mmio_device(net_cfg.id.clone(), net)?; + #[cfg(not(feature = "vhost_net"))] + bail!("Unsupported Vhost_Net"); + + #[cfg(feature = "vhost_net")] + { + let net = Arc::new(Mutex::new(VhostKern::Net::new( + &net_cfg, + netdev_cfg, + &self.base.sys_mem, + ))); + self.add_virtio_mmio_device(net_cfg.id.clone(), net)?; + } } else { #[cfg(not(feature = "vhostuser_net"))] bail!("Unsupported Vhostuser_Net"); diff --git a/virtio/Cargo.toml b/virtio/Cargo.toml index 20d02d9e..b8692b39 100644 --- a/virtio/Cargo.toml +++ b/virtio/Cargo.toml @@ -37,3 +37,4 @@ ohui_srv = [] vhost_vsock =[] vhostuser_block = [] vhostuser_net = [] +vhost_net = [] diff --git a/virtio/src/vhost/kernel/mod.rs b/virtio/src/vhost/kernel/mod.rs index 3e204989..cca3cedc 100644 --- a/virtio/src/vhost/kernel/mod.rs +++ b/virtio/src/vhost/kernel/mod.rs @@ -10,10 +10,12 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. +#[cfg(feature = "vhost_net")] mod net; #[cfg(feature = "vhost_vsock")] mod vsock; +#[cfg(feature = "vhost_net")] pub use net::Net; #[cfg(feature = "vhost_vsock")] pub use vsock::{Vsock, VsockConfig, VsockState}; -- Gitee From 89f68bb83809c2856c4f611d50936fa897de567e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=87=91=E6=BA=A2=E5=8D=8E?= Date: Mon, 19 Aug 2024 16:22:33 +0800 Subject: [PATCH 265/489] Vifo: Change the dependency position Change the hypervisor vfio dependency position. Signed-off-by: Yihua Jin --- Cargo.toml | 3 +-- machine/Cargo.toml | 2 +- machine/src/lib.rs | 1 + 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8bb44175..bf79c900 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,7 +15,6 @@ machine_manager = { path = "machine_manager" } util = { path = "util" } trace = { path = "trace" } hisysevent = { path = "hisysevent" } -hypervisor = { path = "hypervisor" } [workspace] members = [ @@ -45,7 +44,7 @@ trace_to_logger = ["trace/trace_to_logger"] trace_to_ftrace = ["trace/trace_to_ftrace"] trace_to_hitrace = ["trace/trace_to_hitrace"] hisysevent = ["hisysevent/hisysevent"] -vfio = ["machine/vfio_device", "hypervisor/vfio_device"] +vfio = ["machine/vfio_device"] usb_uas = ["machine/usb_uas"] virtio_rng = ["machine/virtio_rng"] virtio_scsi = ["machine/virtio_scsi"] diff --git a/machine/Cargo.toml b/machine/Cargo.toml index dbb25016..c53a050e 100644 --- a/machine/Cargo.toml +++ b/machine/Cargo.toml @@ -50,7 +50,7 @@ vnc_auth = ["vnc"] ohui_srv = ["windows_emu_pid", "ui/ohui_srv", "machine_manager/ohui_srv", "virtio/ohui_srv"] ramfb = ["devices/ramfb", "machine_manager/ramfb"] virtio_gpu = ["virtio/virtio_gpu", "machine_manager/virtio_gpu"] -vfio_device = ["vfio"] +vfio_device = ["vfio", "hypervisor/vfio_device"] usb_uas = ["devices/usb_uas"] virtio_rng = ["virtio/virtio_rng"] virtio_scsi = ["virtio/virtio_scsi"] diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 9e24bfd2..dd4bbc3a 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -29,6 +29,7 @@ use std::net::TcpListener; use std::ops::Deref; use std::os::unix::io::AsRawFd; use std::os::unix::net::UnixListener; +#[cfg(any(feature = "windows_emu_pid", feature = "vfio_device"))] use std::path::Path; use std::rc::Rc; use std::sync::{Arc, Barrier, Condvar, Mutex, RwLock, Weak}; -- Gitee From f12d58fdf25c5579fc016cfbb4be79eabfed24fe Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Sat, 17 Aug 2024 21:36:56 +0800 Subject: [PATCH 266/489] clippy: Fix some clippy warnings Signed-off-by: Keqian Zhu --- address_space/src/address_space.rs | 8 +- address_space/src/region.rs | 20 +- block_backend/src/qcow2/cache.rs | 2 +- block_backend/src/qcow2/table.rs | 2 +- hypervisor/Cargo.toml | 1 + hypervisor/src/kvm/interrupt.rs | 2 +- hypervisor/src/kvm/listener.rs | 12 +- hypervisor/src/kvm/mod.rs | 10 +- machine/Cargo.toml | 2 +- machine/src/lib.rs | 12 +- machine/src/standard_common/mod.rs | 2 + machine_manager/src/qmp/qmp_response.rs | 2 +- tests/mod_test/src/libdriver/qcow2.rs | 2 +- tests/mod_test/src/libdriver/virtio.rs | 6 +- tests/mod_test/src/libdriver/virtio_block.rs | 20 +- tests/mod_test/src/libdriver/virtio_gpu.rs | 10 +- .../src/libdriver/virtio_pci_modern.rs | 2 +- tests/mod_test/src/libdriver/virtio_rng.rs | 2 +- tests/mod_test/src/libdriver/vnc.rs | 35 ++-- tests/mod_test/tests/balloon_test.rs | 16 +- tests/mod_test/tests/block_test.rs | 40 ++-- tests/mod_test/tests/fwcfg_test.rs | 16 +- tests/mod_test/tests/memory_test.rs | 8 +- tests/mod_test/tests/net_test.rs | 133 +++---------- tests/mod_test/tests/pci_test.rs | 178 ++++++++---------- tests/mod_test/tests/pvpanic_test.rs | 2 +- tests/mod_test/tests/rng_test.rs | 16 +- tests/mod_test/tests/scsi_test.rs | 12 +- tests/mod_test/tests/serial_test.rs | 10 +- tests/mod_test/tests/usb_camera_test.rs | 2 +- tests/mod_test/tests/virtio_test.rs | 159 +++------------- tests/mod_test/tests/virtiofs_test.rs | 14 +- tests/mod_test/tests/vnc_test.rs | 4 +- ui/src/console.rs | 7 +- virtio/src/device/balloon.rs | 2 +- virtio/src/queue/split.rs | 9 +- virtio/src/transport/virtio_pci.rs | 6 +- 37 files changed, 263 insertions(+), 523 deletions(-) diff --git a/address_space/src/address_space.rs b/address_space/src/address_space.rs index 84f1be4e..0689aaea 100644 --- a/address_space/src/address_space.rs +++ b/address_space/src/address_space.rs @@ -930,10 +930,10 @@ mod test { let listener3 = Arc::new(Mutex::new(ListenerPrior3::default())); let listener4 = Arc::new(Mutex::new(ListenerPrior4::default())); let listener5 = Arc::new(Mutex::new(ListenerNeg::default())); - space.register_listener(listener1.clone()).unwrap(); + space.register_listener(listener1).unwrap(); space.register_listener(listener3.clone()).unwrap(); - space.register_listener(listener5.clone()).unwrap(); - space.register_listener(listener2.clone()).unwrap(); + space.register_listener(listener5).unwrap(); + space.register_listener(listener2).unwrap(); space.register_listener(listener4.clone()).unwrap(); let mut pre_prior = std::i32::MIN; @@ -978,7 +978,7 @@ mod test { let space = AddressSpace::new(root, "space", None).unwrap(); let listener1 = Arc::new(Mutex::new(ListenerPrior0::default())); let listener2 = Arc::new(Mutex::new(ListenerPrior0::default())); - space.register_listener(listener1.clone()).unwrap(); + space.register_listener(listener1).unwrap(); space.register_listener(listener2.clone()).unwrap(); space.unregister_listener(listener2).unwrap(); diff --git a/address_space/src/region.rs b/address_space/src/region.rs index 64ad7fba..52e5f43f 100644 --- a/address_space/src/region.rs +++ b/address_space/src/region.rs @@ -1208,7 +1208,7 @@ mod test { let mut device_locked = test_dev_clone.lock().unwrap(); device_locked.read(data, addr, offset) }; - let test_dev_clone = test_dev.clone(); + let test_dev_clone = test_dev; let write_ops = move |data: &[u8], addr: GuestAddress, offset: u64| -> bool { let mut device_locked = test_dev_clone.lock().unwrap(); device_locked.write(data, addr, offset) @@ -1219,7 +1219,7 @@ mod test { write: Arc::new(write_ops), }; - let io_region = Region::init_io_region(16, test_dev_ops.clone(), "io_region"); + let io_region = Region::init_io_region(16, test_dev_ops, "io_region"); let data = [0x01u8; 8]; let mut data_res = [0x0u8; 8]; let count = data.len() as u64; @@ -1299,7 +1299,7 @@ mod test { }; let io_region = Region::init_io_region(1 << 4, default_ops.clone(), "io1"); - let io_region2 = Region::init_io_region(1 << 4, default_ops.clone(), "io2"); + let io_region2 = Region::init_io_region(1 << 4, default_ops, "io2"); io_region2.set_priority(10); // add duplicate io-region or ram-region will fail @@ -1364,9 +1364,9 @@ mod test { region_b.set_priority(2); region_c.set_priority(1); region_a.add_subregion(region_b.clone(), 2000).unwrap(); - region_a.add_subregion(region_c.clone(), 0).unwrap(); - region_b.add_subregion(region_d.clone(), 0).unwrap(); - region_b.add_subregion(region_e.clone(), 2000).unwrap(); + region_a.add_subregion(region_c, 0).unwrap(); + region_b.add_subregion(region_d, 0).unwrap(); + region_b.add_subregion(region_e, 2000).unwrap(); let addr_range = AddressRange::from((0u64, region_a.size())); let view = region_a @@ -1405,14 +1405,14 @@ mod test { let region_b = Region::init_container_region(5000, "region_b"); let region_c = Region::init_io_region(1000, default_ops.clone(), "regionc"); let region_d = Region::init_io_region(3000, default_ops.clone(), "region_d"); - let region_e = Region::init_io_region(2000, default_ops.clone(), "region_e"); + let region_e = Region::init_io_region(2000, default_ops, "region_e"); region_a.add_subregion(region_b.clone(), 2000).unwrap(); - region_a.add_subregion(region_c.clone(), 0).unwrap(); + region_a.add_subregion(region_c, 0).unwrap(); region_d.set_priority(2); region_e.set_priority(3); - region_b.add_subregion(region_d.clone(), 0).unwrap(); - region_b.add_subregion(region_e.clone(), 2000).unwrap(); + region_b.add_subregion(region_d, 0).unwrap(); + region_b.add_subregion(region_e, 2000).unwrap(); let addr_range = AddressRange::from((0u64, region_a.size())); let view = region_a diff --git a/block_backend/src/qcow2/cache.rs b/block_backend/src/qcow2/cache.rs index f3ca26b8..245bbe67 100644 --- a/block_backend/src/qcow2/cache.rs +++ b/block_backend/src/qcow2/cache.rs @@ -315,7 +315,7 @@ mod test { )); let mut qcow2_cache = Qcow2Cache::new(2); - qcow2_cache.lru_replace(addr, entry.clone()); + qcow2_cache.lru_replace(addr, entry); qcow2_cache.lru_count = u64::MAX - cnt / 2; // Not in cache. assert!(qcow2_cache.get(0).is_none()); diff --git a/block_backend/src/qcow2/table.rs b/block_backend/src/qcow2/table.rs index c791cfa0..3abd1fe4 100644 --- a/block_backend/src/qcow2/table.rs +++ b/block_backend/src/qcow2/table.rs @@ -269,7 +269,7 @@ mod test { let addr = qcow2.alloc_cluster(1, true).unwrap(); let l2_cluster: Vec = vec![0_u8; cluster_size]; let l2_table = Rc::new(RefCell::new( - CacheTable::new(addr, l2_cluster.clone(), ENTRY_SIZE_U64).unwrap(), + CacheTable::new(addr, l2_cluster, ENTRY_SIZE_U64).unwrap(), )); qcow2.table.cache_l2_table(l2_table.clone()).unwrap(); diff --git a/hypervisor/Cargo.toml b/hypervisor/Cargo.toml index 95c92558..44308ef4 100644 --- a/hypervisor/Cargo.toml +++ b/hypervisor/Cargo.toml @@ -25,3 +25,4 @@ trace = { path = "../trace" } [features] default = [] vfio_device = [] +boot_time = [] diff --git a/hypervisor/src/kvm/interrupt.rs b/hypervisor/src/kvm/interrupt.rs index 6a9f8f8f..4df7feb9 100644 --- a/hypervisor/src/kvm/interrupt.rs +++ b/hypervisor/src/kvm/interrupt.rs @@ -252,7 +252,7 @@ mod tests { let irq_route_table = Mutex::new(IrqRouteTable::new(kvm_hyp.fd.as_ref().unwrap())); let irq_manager = Arc::new(KVMInterruptManager::new( true, - kvm_hyp.vm_fd.clone().unwrap(), + kvm_hyp.vm_fd.unwrap(), irq_route_table, )); let mut irq_route_table = irq_manager.irq_route_table.lock().unwrap(); diff --git a/hypervisor/src/kvm/listener.rs b/hypervisor/src/kvm/listener.rs index aab93039..b05175c2 100644 --- a/hypervisor/src/kvm/listener.rs +++ b/hypervisor/src/kvm/listener.rs @@ -633,7 +633,7 @@ mod test { return; } - let kml = KvmMemoryListener::new(4, kvm_hyp.vm_fd.clone(), kvm_hyp.mem_slots.clone()); + let kml = KvmMemoryListener::new(4, kvm_hyp.vm_fd.clone(), kvm_hyp.mem_slots); let host_addr = 0u64; assert_eq!(kml.get_free_slot(0, 100, host_addr).unwrap(), 0); @@ -657,7 +657,7 @@ mod test { return; } - let kml = KvmMemoryListener::new(34, kvm_hyp.vm_fd.clone(), kvm_hyp.mem_slots.clone()); + let kml = KvmMemoryListener::new(34, kvm_hyp.vm_fd.clone(), kvm_hyp.mem_slots); let ram_size = host_page_size(); let ram_fr1 = create_ram_range(0, ram_size, 0); @@ -683,7 +683,7 @@ mod test { return; } - let kml = KvmMemoryListener::new(34, kvm_hyp.vm_fd.clone(), kvm_hyp.mem_slots.clone()); + let kml = KvmMemoryListener::new(34, kvm_hyp.vm_fd.clone(), kvm_hyp.mem_slots); // flat-range not aligned let page_size = host_page_size(); let ram_fr2 = create_ram_range(page_size, 2 * page_size, 1000); @@ -705,7 +705,7 @@ mod test { return; } - let kml = KvmMemoryListener::new(34, kvm_hyp.vm_fd.clone(), kvm_hyp.mem_slots.clone()); + let kml = KvmMemoryListener::new(34, kvm_hyp.vm_fd.clone(), kvm_hyp.mem_slots); let evtfd = generate_region_ioeventfd(4, NoDatamatch); assert!(kml .handle_request(None, Some(&evtfd), ListenerReqType::AddIoeventfd) @@ -751,7 +751,7 @@ mod test { return; } - let kml = KvmMemoryListener::new(34, kvm_hyp.vm_fd.clone(), kvm_hyp.mem_slots.clone()); + let kml = KvmMemoryListener::new(34, kvm_hyp.vm_fd.clone(), kvm_hyp.mem_slots); let evtfd_addr = 0x1000_u64; let mut evtfd = generate_region_ioeventfd(evtfd_addr, 64_u32); evtfd.addr_range.size = 3_u64; @@ -805,7 +805,7 @@ mod test { return; } - let iol = KvmIoListener::new(kvm_hyp.vm_fd.clone()); + let iol = KvmIoListener::new(kvm_hyp.vm_fd); let evtfd = generate_region_ioeventfd(4, NoDatamatch); assert!(iol .handle_request(None, Some(&evtfd), ListenerReqType::AddIoeventfd) diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs index e57ad943..209442ba 100644 --- a/hypervisor/src/kvm/mod.rs +++ b/hypervisor/src/kvm/mod.rs @@ -56,8 +56,6 @@ use crate::HypervisorError; #[cfg(target_arch = "aarch64")] use aarch64::cpu_caps::ArmCPUCaps as CPUCaps; use address_space::{AddressSpace, Listener}; -#[cfg(feature = "boot_time")] -use cpu::capture_boot_signal; #[cfg(target_arch = "aarch64")] use cpu::CPUFeatures; use cpu::{ @@ -427,7 +425,7 @@ impl KvmCpu { #[cfg(target_arch = "x86_64")] VcpuExit::IoOut(addr, data) => { #[cfg(feature = "boot_time")] - capture_boot_signal(addr as u64, data); + cpu::capture_boot_signal(addr as u64, data); vm.lock().unwrap().pio_out(u64::from(addr), data); } @@ -436,7 +434,7 @@ impl KvmCpu { } VcpuExit::MmioWrite(addr, data) => { #[cfg(all(target_arch = "aarch64", feature = "boot_time"))] - capture_boot_signal(addr, data); + cpu::capture_boot_signal(addr, data); vm.lock().unwrap().mmio_write(addr, data); } @@ -1069,7 +1067,7 @@ mod test { vcpu_fd, )); let x86_cpu = Arc::new(Mutex::new(ArchCPU::new(0, 1))); - let cpu = CPU::new(hypervisor_cpu.clone(), 0, x86_cpu, vm.clone()); + let cpu = CPU::new(hypervisor_cpu.clone(), 0, x86_cpu, vm); // test `set_boot_config` function assert!(hypervisor_cpu .set_boot_config(cpu.arch().clone(), &cpu_config) @@ -1131,7 +1129,7 @@ mod test { hypervisor_cpu.clone(), 0, Arc::new(Mutex::new(ArchCPU::default())), - vm.clone(), + vm, ); let (cpu_state, _) = &*cpu.state; assert_eq!(*cpu_state.lock().unwrap(), CpuLifecycleState::Created); diff --git a/machine/Cargo.toml b/machine/Cargo.toml index c53a050e..2c8a22b6 100644 --- a/machine/Cargo.toml +++ b/machine/Cargo.toml @@ -32,7 +32,7 @@ clap = { version = "=4.1.4", default-features = false, features = ["std", "deriv [features] default = [] -boot_time = ["cpu/boot_time"] +boot_time = ["cpu/boot_time", "hypervisor/boot_time"] scream = ["devices/scream", "machine_manager/scream"] scream_alsa = ["scream", "devices/scream_alsa", "machine_manager/scream_alsa"] scream_pulseaudio = ["scream", "devices/scream_pulseaudio","machine_manager/scream_pulseaudio"] diff --git a/machine/src/lib.rs b/machine/src/lib.rs index dd4bbc3a..73ada4da 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -35,6 +35,7 @@ use std::rc::Rc; use std::sync::{Arc, Barrier, Condvar, Mutex, RwLock, Weak}; #[cfg(feature = "windows_emu_pid")] use std::time::Duration; +use std::u64; use anyhow::{anyhow, bail, Context, Result}; use clap::Parser; @@ -185,12 +186,9 @@ impl MachineBase { vm_config.machine_config.nr_threads, vm_config.machine_config.max_cpus, ); - let machine_ram = Arc::new(Region::init_container_region( - u64::max_value(), - "MachineRam", - )); + let machine_ram = Arc::new(Region::init_container_region(u64::MAX, "MachineRam")); let sys_mem = AddressSpace::new( - Region::init_container_region(u64::max_value(), "SysMem"), + Region::init_container_region(u64::MAX, "SysMem"), "sys_mem", Some(machine_ram.clone()), ) @@ -408,7 +406,7 @@ pub trait MachineOps: MachineLifecycle { } let zones = mem_config.mem_zones.as_ref().unwrap(); let mut offset = 0_u64; - for (_, node) in numa_nodes.as_ref().unwrap().iter().enumerate() { + for node in numa_nodes.as_ref().unwrap().iter() { for zone in zones.iter() { if zone.id.eq(&node.1.mem_dev) { let ram = create_backend_mem(zone, thread_num)?; @@ -698,7 +696,7 @@ pub trait MachineOps: MachineLifecycle { } fn add_virtio_balloon(&mut self, vm_config: &mut VmConfig, cfg_args: &str) -> Result<()> { - if vm_config.dev_name.get("balloon").is_some() { + if vm_config.dev_name.contains_key("balloon") { bail!("Only one balloon device is supported for each vm."); } let config = BalloonConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index 70c36a49..f32bf7a1 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -327,6 +327,7 @@ pub(crate) trait StdMachineOps: AcpiBuilder + MachineOps { .with_context(|| "Failed to register event notifier.") } + #[cfg(target_arch = "aarch64")] fn register_pause_event( &self, pause_req: Arc, @@ -355,6 +356,7 @@ pub(crate) trait StdMachineOps: AcpiBuilder + MachineOps { .with_context(|| "Failed to register event notifier.") } + #[cfg(target_arch = "aarch64")] fn register_resume_event( &self, resume_req: Arc, diff --git a/machine_manager/src/qmp/qmp_response.rs b/machine_manager/src/qmp/qmp_response.rs index 8db50f9a..bbf2d41e 100644 --- a/machine_manager/src/qmp/qmp_response.rs +++ b/machine_manager/src/qmp/qmp_response.rs @@ -273,7 +273,7 @@ mod tests { let msg = ErrorMessage::new(&err_cls); assert_eq!(msg.desc, strange_msg); assert_eq!(msg.errorkind, "KVMMissingCap".to_string()); - let qmp_err = qmp_schema::QmpErrorClass::KVMMissingCap(strange_msg.clone()); + let qmp_err = qmp_schema::QmpErrorClass::KVMMissingCap(strange_msg); let resp = Response::create_error_response(qmp_err, None); assert_eq!(resp.error, Some(msg)); } diff --git a/tests/mod_test/src/libdriver/qcow2.rs b/tests/mod_test/src/libdriver/qcow2.rs index 61160a64..fb6ba768 100644 --- a/tests/mod_test/src/libdriver/qcow2.rs +++ b/tests/mod_test/src/libdriver/qcow2.rs @@ -321,7 +321,7 @@ pub fn query_snapshot(state: Rc>) -> Value { // Check if there exists snapshot with the specified name. pub fn check_snapshot(state: Rc>, snap: &str) -> bool { - let value = query_snapshot(state.clone()); + let value = query_snapshot(state); let str = (*value.get("return").unwrap()).as_str().unwrap(); let lines: Vec<&str> = str.split("\r\n").collect(); for line in lines { diff --git a/tests/mod_test/src/libdriver/virtio.rs b/tests/mod_test/src/libdriver/virtio.rs index 991b5a6b..c5d357e3 100644 --- a/tests/mod_test/src/libdriver/virtio.rs +++ b/tests/mod_test/src/libdriver/virtio.rs @@ -505,7 +505,7 @@ impl TestVirtQueue { next: 0, }; self.add_elem_to_desc(test_state.clone(), desc_elem); - self.update_avail(test_state.clone(), free_head); + self.update_avail(test_state, free_head); free_head } @@ -536,7 +536,7 @@ impl TestVirtQueue { }; self.add_elem_to_desc(test_state.clone(), desc_elem); } - self.update_avail(test_state.clone(), free_head); + self.update_avail(test_state, free_head); free_head } @@ -557,7 +557,7 @@ impl TestVirtQueue { }; self.add_elem_to_desc(test_state.clone(), desc_elem); if !mixed { - self.update_avail(test_state.clone(), free_head); + self.update_avail(test_state, free_head); } free_head } diff --git a/tests/mod_test/src/libdriver/virtio_block.rs b/tests/mod_test/src/libdriver/virtio_block.rs index e284e3ad..5cc5121c 100644 --- a/tests/mod_test/src/libdriver/virtio_block.rs +++ b/tests/mod_test/src/libdriver/virtio_block.rs @@ -154,7 +154,7 @@ pub fn create_blk( let machine = TestStdMachine::new(test_state.clone()); let allocator = machine.allocator.clone(); - let virtio_blk = Rc::new(RefCell::new(TestVirtioPciDev::new(machine.pci_bus.clone()))); + let virtio_blk = Rc::new(RefCell::new(TestVirtioPciDev::new(machine.pci_bus))); virtio_blk.borrow_mut().init(pci_slot, pci_fn); @@ -233,7 +233,7 @@ pub fn add_blk_request( read = false; } // Get addr and write to Stratovirt. - let req_addr = virtio_blk_request(test_state.clone(), alloc.clone(), blk_req, align); + let req_addr = virtio_blk_request(test_state.clone(), alloc, blk_req, align); // Desc elem: [addr, len, flags, next]. let data_addr = if align { @@ -259,9 +259,7 @@ pub fn add_blk_request( write: true, }); - let free_head = vq - .borrow_mut() - .add_chained(test_state.clone(), data_entries); + let free_head = vq.borrow_mut().add_chained(test_state, data_entries); (free_head, req_addr) } @@ -292,7 +290,7 @@ pub fn virtio_blk_write( .kick_virtqueue(test_state.clone(), virtqueue.clone()); blk.borrow().poll_used_elem( test_state.clone(), - virtqueue.clone(), + virtqueue, free_head, TIMEOUT_US, &mut None, @@ -320,7 +318,7 @@ pub fn virtio_blk_read( ) { let (free_head, req_addr) = add_blk_request( test_state.clone(), - alloc.clone(), + alloc, virtqueue.clone(), VIRTIO_BLK_T_IN, sector, @@ -331,7 +329,7 @@ pub fn virtio_blk_read( .kick_virtqueue(test_state.clone(), virtqueue.clone()); blk.borrow().poll_used_elem( test_state.clone(), - virtqueue.clone(), + virtqueue, free_head, TIMEOUT_US, &mut None, @@ -376,7 +374,7 @@ pub fn virtio_blk_read_write_zeroes( } read = false; } - let req_addr = virtio_blk_request(test_state.clone(), alloc.clone(), blk_req, false); + let req_addr = virtio_blk_request(test_state.clone(), alloc, blk_req, false); let data_addr = req_addr + u64::from(REQ_ADDR_LEN); let data_entries: Vec = vec![ TestVringDescEntry { @@ -401,7 +399,7 @@ pub fn virtio_blk_read_write_zeroes( blk.borrow().kick_virtqueue(test_state.clone(), vq.clone()); blk.borrow().poll_used_elem( test_state.clone(), - vq.clone(), + vq, free_head, TIMEOUT_US, &mut None, @@ -459,7 +457,7 @@ pub fn tear_down( vqs: Vec>>, image_path: Rc, ) { - blk.borrow_mut().destroy_device(alloc.clone(), vqs); + blk.borrow_mut().destroy_device(alloc, vqs); test_state.borrow_mut().stop(); if !image_path.is_empty() { cleanup_img(image_path.to_string()); diff --git a/tests/mod_test/src/libdriver/virtio_gpu.rs b/tests/mod_test/src/libdriver/virtio_gpu.rs index e985cc7d..ac5236d8 100644 --- a/tests/mod_test/src/libdriver/virtio_gpu.rs +++ b/tests/mod_test/src/libdriver/virtio_gpu.rs @@ -430,8 +430,8 @@ impl TestVirtioGpu { .borrow_mut() .setup_virtqueue_intr(2, self.allocator.clone(), cursor_q.clone()); - self.ctrl_q = ctrl_q.clone(); - self.cursor_q = cursor_q.clone(); + self.ctrl_q = ctrl_q; + self.cursor_q = cursor_q; self.device.borrow_mut().set_driver_ok(); } @@ -648,9 +648,9 @@ pub fn set_up( demo_dpy.borrow_mut().init(dpy_pci_slot); let virtgpu = Rc::new(RefCell::new(TestVirtioGpu::new( - machine.pci_bus.clone(), - allocator.clone(), - test_state.clone(), + machine.pci_bus, + allocator, + test_state, ))); virtgpu.borrow_mut().init(gpu_pci_slot, gpu_pci_fn); diff --git a/tests/mod_test/src/libdriver/virtio_pci_modern.rs b/tests/mod_test/src/libdriver/virtio_pci_modern.rs index 7e55fee2..dfc0f2ce 100644 --- a/tests/mod_test/src/libdriver/virtio_pci_modern.rs +++ b/tests/mod_test/src/libdriver/virtio_pci_modern.rs @@ -597,7 +597,7 @@ impl VirtioDeviceOps for TestVirtioPciDev { let vq = virtqueue.borrow(); let idx: u16 = test_state.borrow().readw(vq.avail + 2); - if (!vq.event) || (idx > vq.get_avail_event(test_state.clone())) { + if (!vq.event) || (idx > vq.get_avail_event(test_state)) { self.virtqueue_notify(virtqueue.clone()); } } diff --git a/tests/mod_test/src/libdriver/virtio_rng.rs b/tests/mod_test/src/libdriver/virtio_rng.rs index 9b7520cd..082d714a 100644 --- a/tests/mod_test/src/libdriver/virtio_rng.rs +++ b/tests/mod_test/src/libdriver/virtio_rng.rs @@ -49,7 +49,7 @@ pub fn create_rng( let machine = TestStdMachine::new(test_state.clone()); let allocator = machine.allocator.clone(); - let rng = Rc::new(RefCell::new(TestVirtioPciDev::new(machine.pci_bus.clone()))); + let rng = Rc::new(RefCell::new(TestVirtioPciDev::new(machine.pci_bus))); rng.borrow_mut().init(pci_slot, pci_fn); diff --git a/tests/mod_test/src/libdriver/vnc.rs b/tests/mod_test/src/libdriver/vnc.rs index 83ada875..bf703470 100644 --- a/tests/mod_test/src/libdriver/vnc.rs +++ b/tests/mod_test/src/libdriver/vnc.rs @@ -108,7 +108,7 @@ pub struct TestGpuCmd { // Encodings Type #[repr(u32)] -#[derive(Clone, Copy, PartialEq, Debug)] +#[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum EncodingType { EncodingRaw = 0x00000000, EncodingCopyrect = 0x00000001, @@ -180,7 +180,7 @@ impl From for EncodingType { } } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Eq)] pub enum RfbServerMsg { FramebufferUpdate = 0, SetColourMapEntries = 1, @@ -784,23 +784,20 @@ impl VncClient { buf.drain(..auth_num as usize); self.write_msg((sec_type as u8).to_be_bytes().as_ref())?; - match sec_type { - TestAuthType::VncAuthNone => { - // Step 3. Handle_auth: Authstate::No, Server accept auth and client send share - // mode. - self.read_msg(&mut buf, 4)?; - if buf[..4].to_vec() != [0_u8; 4].to_vec() { - bail!("Reject by vnc server"); - } - self.write_msg(0_u8.to_be_bytes().as_ref())?; - buf.drain(..4); - - // Step 4. display mode information init: width + height + pixelformat + app_name. - self.read_msg(&mut buf, 24)?; - self.display_mod.from_bytes(&mut buf); - self.display_mod.check(); + if let TestAuthType::VncAuthNone = sec_type { + // Step 3. Handle_auth: Authstate::No, Server accept auth and client send share + // mode. + self.read_msg(&mut buf, 4)?; + if buf[..4].to_vec() != [0_u8; 4].to_vec() { + bail!("Reject by vnc server"); } - _ => {} + self.write_msg(0_u8.to_be_bytes().as_ref())?; + buf.drain(..4); + + // Step 4. display mode information init: width + height + pixelformat + app_name. + self.read_msg(&mut buf, 24)?; + self.display_mod.from_bytes(&mut buf); + self.display_mod.check(); } self.stream_read_to_end()?; println!("Connection established!"); @@ -1355,7 +1352,7 @@ pub fn set_up( } let input = Rc::new(RefCell::new(TestDemoInputDevice::new( - machine.pci_bus.clone(), + machine.pci_bus, allocator, ))); input.borrow_mut().init(input_conf.pci_slot); diff --git a/tests/mod_test/tests/balloon_test.rs b/tests/mod_test/tests/balloon_test.rs index 63dafe6c..8fbc4002 100644 --- a/tests/mod_test/tests/balloon_test.rs +++ b/tests/mod_test/tests/balloon_test.rs @@ -126,7 +126,7 @@ impl VirtioBalloonTest { let machine = TestStdMachine::new_bymem(test_state.clone(), memsize * MBSIZE, page_size); let allocator = machine.allocator.clone(); - let dev = Rc::new(RefCell::new(TestVirtioPciDev::new(machine.pci_bus.clone()))); + let dev = Rc::new(RefCell::new(TestVirtioPciDev::new(machine.pci_bus))); dev.borrow_mut().init(pci_slot, 0); let features = dev.borrow_mut().get_device_features(); @@ -208,7 +208,7 @@ impl VirtioBalloonTest { let machine = TestStdMachine::new_bymem(test_state.clone(), 2 * MBSIZE, 4096); let allocator = machine.allocator.clone(); - let dev = Rc::new(RefCell::new(TestVirtioPciDev::new(machine.pci_bus.clone()))); + let dev = Rc::new(RefCell::new(TestVirtioPciDev::new(machine.pci_bus))); dev.borrow_mut().init(4, 0); let features = dev.borrow_mut().get_device_features(); @@ -567,12 +567,12 @@ fn balloon_feature_001() { let machine = TestStdMachine::new_bymem(test_state.clone(), 128 * MBSIZE, PAGE_SIZE_UNIT); let allocator = machine.allocator.clone(); - let dev = Rc::new(RefCell::new(TestVirtioPciDev::new(machine.pci_bus.clone()))); + let dev = Rc::new(RefCell::new(TestVirtioPciDev::new(machine.pci_bus))); dev.borrow_mut().init(pci_slot, pci_fn); dev.borrow_mut().pci_dev.enable_msix(None); dev.borrow_mut() - .setup_msix_configuration_vector(allocator.clone(), 0); + .setup_msix_configuration_vector(allocator, 0); let features = dev.borrow_mut().get_device_features(); @@ -614,12 +614,12 @@ fn balloon_feature_002() { let machine = TestStdMachine::new_bymem(test_state.clone(), 128 * MBSIZE, PAGE_SIZE_UNIT); let allocator = machine.allocator.clone(); - let dev = Rc::new(RefCell::new(TestVirtioPciDev::new(machine.pci_bus.clone()))); + let dev = Rc::new(RefCell::new(TestVirtioPciDev::new(machine.pci_bus))); dev.borrow_mut().init(pci_slot, pci_fn); dev.borrow_mut().pci_dev.enable_msix(None); dev.borrow_mut() - .setup_msix_configuration_vector(allocator.clone(), 0); + .setup_msix_configuration_vector(allocator, 0); let features = dev.borrow_mut().get_device_features(); @@ -705,7 +705,7 @@ fn balloon_fpr_fun(shared: bool) { .kick_virtqueue(balloon.state.clone(), fpr.clone()); balloon.device.borrow_mut().poll_used_elem( balloon.state.clone(), - fpr.clone(), + fpr, free_head, TIMEOUT_US, &mut None, @@ -1016,7 +1016,7 @@ fn auto_balloon_test_001() { .kick_virtqueue(balloon.state.clone(), auto_queue.clone()); balloon.device.borrow_mut().poll_used_elem( balloon.state.clone(), - auto_queue.clone(), + auto_queue, free_head, TIMEOUT_US, &mut None, diff --git a/tests/mod_test/tests/block_test.rs b/tests/mod_test/tests/block_test.rs index 78d590bf..1f0a513c 100644 --- a/tests/mod_test/tests/block_test.rs +++ b/tests/mod_test/tests/block_test.rs @@ -63,7 +63,7 @@ fn virtio_blk_discard_and_write_zeroes( TestVirtBlkReq::new(VIRTIO_BLK_T_WRITE_ZEROES, 1, 0, req_len) }; blk_req.data = unsafe { String::from_utf8_unchecked(req_data.to_vec()) }; - let req_addr = virtio_blk_request(test_state.clone(), alloc.clone(), blk_req, false); + let req_addr = virtio_blk_request(test_state.clone(), alloc, blk_req, false); let mut data_entries: Vec = Vec::with_capacity(3); data_entries.push(TestVringDescEntry { @@ -89,7 +89,7 @@ fn virtio_blk_discard_and_write_zeroes( if need_poll_elem { blk.borrow().poll_used_elem( test_state.clone(), - virtqueue.clone(), + virtqueue, free_head, TIMEOUT_US, &mut None, @@ -153,7 +153,7 @@ fn virtio_blk_get_id( ) { let (free_head, req_addr) = add_blk_request( test_state.clone(), - alloc.clone(), + alloc, virtqueue.clone(), VIRTIO_BLK_T_GET_ID, 0, @@ -162,7 +162,7 @@ fn virtio_blk_get_id( blk.borrow().virtqueue_notify(virtqueue.clone()); blk.borrow().poll_used_elem( test_state.clone(), - virtqueue.clone(), + virtqueue, free_head, TIMEOUT_US, &mut None, @@ -195,7 +195,7 @@ fn virtio_blk_flush( ) { let (free_head, req_addr) = add_blk_request( test_state.clone(), - alloc.clone(), + alloc, virtqueue.clone(), VIRTIO_BLK_T_FLUSH, sector, @@ -204,7 +204,7 @@ fn virtio_blk_flush( blk.borrow().virtqueue_notify(virtqueue.clone()); blk.borrow().poll_used_elem( test_state.clone(), - virtqueue.clone(), + virtqueue, free_head, TIMEOUT_US, &mut None, @@ -226,7 +226,7 @@ fn virtio_blk_illegal_req( ) { let (free_head, req_addr) = add_blk_request( test_state.clone(), - alloc.clone(), + alloc, virtqueue.clone(), req_type, 0, @@ -235,7 +235,7 @@ fn virtio_blk_illegal_req( blk.borrow().virtqueue_notify(virtqueue.clone()); blk.borrow().poll_used_elem( test_state.clone(), - virtqueue.clone(), + virtqueue, free_head, TIMEOUT_US, &mut None, @@ -2021,13 +2021,7 @@ fn blk_snapshot_basic() { true, ); - tear_down( - blk.clone(), - test_state.clone(), - alloc.clone(), - virtqueues, - image_path.clone(), - ); + tear_down(blk, test_state, alloc, virtqueues, image_path); } /// Block device whose backend file has snapshot sends I/O request. @@ -2052,13 +2046,7 @@ fn blk_snapshot_basic2() { .init_device(test_state.clone(), alloc.clone(), features, 1); create_snapshot(test_state.clone(), "drive0", "snap0"); assert!(check_snapshot(test_state.clone(), "snap0")); - tear_down( - blk.clone(), - test_state.clone(), - alloc.clone(), - virtqueues, - Rc::new("".to_string()), - ); + tear_down(blk, test_state, alloc, virtqueues, Rc::new("".to_string())); let device_args = Rc::new(String::from("")); let drive_args = Rc::new(String::from(",direct=false")); @@ -2116,11 +2104,5 @@ fn blk_snapshot_basic2() { true, ); - tear_down( - blk.clone(), - test_state.clone(), - alloc.clone(), - virtqueues, - image_path.clone(), - ); + tear_down(blk, test_state, alloc, virtqueues, image_path); } diff --git a/tests/mod_test/tests/fwcfg_test.rs b/tests/mod_test/tests/fwcfg_test.rs index da210b04..c51535a3 100644 --- a/tests/mod_test/tests/fwcfg_test.rs +++ b/tests/mod_test/tests/fwcfg_test.rs @@ -163,7 +163,7 @@ fn test_filedir_by_dma() { bios_args(&mut args); let test_state = Rc::new(RefCell::new(test_init(args))); let machine = TestStdMachine::new(test_state.clone()); - let allocator = machine.allocator.clone(); + let allocator = machine.allocator; let file_name = "etc/boot-fail-wait"; let mut read_data: Vec = Vec::with_capacity(mem::size_of::()); @@ -207,7 +207,7 @@ fn test_boot_index() { let test_state = Rc::new(RefCell::new(test_init(args))); let machine = TestStdMachine::new(test_state.clone()); - let allocator = machine.allocator.clone(); + let allocator = machine.allocator; let file_name = "bootorder"; let mut read_data: Vec = Vec::with_capacity(dev_path.len()); @@ -240,7 +240,7 @@ fn test_smbios_type0() { let test_state = Rc::new(RefCell::new(test_init(args))); let machine = TestStdMachine::new(test_state.clone()); - let allocator = machine.allocator.clone(); + let allocator = machine.allocator; let anchor_file = "etc/smbios/smbios-anchor"; let tables_file = "etc/smbios/smbios-tables"; @@ -304,7 +304,7 @@ fn test_smbios_type1() { let test_state = Rc::new(RefCell::new(test_init(args))); let machine = TestStdMachine::new(test_state.clone()); - let allocator = machine.allocator.clone(); + let allocator = machine.allocator; let anchor_file = "etc/smbios/smbios-anchor"; let tables_file = "etc/smbios/smbios-tables"; @@ -409,7 +409,7 @@ fn test_smbios_type2() { let test_state = Rc::new(RefCell::new(test_init(args))); let machine = TestStdMachine::new(test_state.clone()); - let allocator = machine.allocator.clone(); + let allocator = machine.allocator; let anchor_file = "etc/smbios/smbios-anchor"; let tables_file = "etc/smbios/smbios-tables"; @@ -484,7 +484,7 @@ fn test_smbios_type3() { let test_state = Rc::new(RefCell::new(test_init(args))); let machine = TestStdMachine::new(test_state.clone()); - let allocator = machine.allocator.clone(); + let allocator = machine.allocator; let anchor_file = "etc/smbios/smbios-anchor"; let tables_file = "etc/smbios/smbios-tables"; @@ -559,7 +559,7 @@ fn test_smbios_type4() { let test_state = Rc::new(RefCell::new(test_init(args))); let machine = TestStdMachine::new(test_state.clone()); - let allocator = machine.allocator.clone(); + let allocator = machine.allocator; let anchor_file = "etc/smbios/smbios-anchor"; let tables_file = "etc/smbios/smbios-tables"; @@ -644,7 +644,7 @@ fn test_smbios_type17() { let test_state = Rc::new(RefCell::new(test_init(args))); let machine = TestStdMachine::new(test_state.clone()); - let allocator = machine.allocator.clone(); + let allocator = machine.allocator; let anchor_file = "etc/smbios/smbios-anchor"; let tables_file = "etc/smbios/smbios-tables"; diff --git a/tests/mod_test/tests/memory_test.rs b/tests/mod_test/tests/memory_test.rs index 4b7544a1..9c553949 100644 --- a/tests/mod_test/tests/memory_test.rs +++ b/tests/mod_test/tests/memory_test.rs @@ -77,7 +77,7 @@ impl MemoryTest { let test_state = Rc::new(RefCell::new(test_init(extra_args))); let machine = TestStdMachine::new_bymem(test_state.clone(), memsize * 1024 * 1024, page_size); - let allocator = machine.allocator.clone(); + let allocator = machine.allocator; MemoryTest { state: test_state, @@ -98,7 +98,7 @@ fn ram_read_write(memory_test: &MemoryTest) { .state .borrow_mut() .memread(addr, str.len() as u64); - assert_eq!(str, String::from_utf8(ret.clone()).unwrap()); + assert_eq!(str, String::from_utf8(ret).unwrap()); memory_test.state.borrow_mut().stop(); } @@ -655,7 +655,7 @@ fn ram_readwrite_numa() { let ret = test_state .borrow_mut() .memread(start_base, str.len() as u64); - assert_eq!(str, String::from_utf8(ret.clone()).unwrap()); + assert_eq!(str, String::from_utf8(ret).unwrap()); test_state.borrow_mut().stop(); } @@ -716,7 +716,7 @@ fn ram_readwrite_numa1() { let ret = test_state .borrow_mut() .memread(start_base, str.len() as u64); - assert_eq!(str, String::from_utf8(ret.clone()).unwrap()); + assert_eq!(str, String::from_utf8(ret).unwrap()); test_state.borrow_mut().qmp("{\"execute\": \"query-mem\"}"); let file = File::create(RAM_DEV_PATH).unwrap(); diff --git a/tests/mod_test/tests/net_test.rs b/tests/mod_test/tests/net_test.rs index ff6a7c99..19fba808 100644 --- a/tests/mod_test/tests/net_test.rs +++ b/tests/mod_test/tests/net_test.rs @@ -445,7 +445,7 @@ pub fn create_net( let test_state = Rc::new(RefCell::new(test_init(extra_args))); let machine = TestStdMachine::new(test_state.clone()); let allocator = machine.allocator.clone(); - let virtio_net = Rc::new(RefCell::new(TestVirtioPciDev::new(machine.pci_bus.clone()))); + let virtio_net = Rc::new(RefCell::new(TestVirtioPciDev::new(machine.pci_bus))); virtio_net.borrow_mut().init(pci_slot, pci_fn); (virtio_net, test_state, allocator) @@ -490,7 +490,7 @@ fn tear_down( id: u8, mq: bool, ) { - net.borrow_mut().destroy_device(alloc.clone(), vqs); + net.borrow_mut().destroy_device(alloc, vqs); test_state.borrow_mut().stop(); clear_tap(id, mq); } @@ -507,7 +507,7 @@ fn fill_rx_vq( vq.borrow_mut() .add(test_state.clone(), addr, MAX_PACKET_LEN as u32, true); } - vq.borrow().set_used_event(test_state.clone(), 0); + vq.borrow().set_used_event(test_state, 0); } fn init_net_device( @@ -689,14 +689,8 @@ fn send_request( .borrow_mut() .add(test_state.clone(), addr, request.len() as u32, false); net.borrow().virtqueue_notify(vq.clone()); - net.borrow().poll_used_elem( - test_state.clone(), - vq, - free_head, - TIMEOUT_US, - &mut None, - true, - ); + net.borrow() + .poll_used_elem(test_state, vq, free_head, TIMEOUT_US, &mut None, true); } fn send_arp_request( @@ -710,17 +704,11 @@ fn send_arp_request( send_request( net.clone(), test_state.clone(), - alloc.clone(), + alloc, vqs[1].clone(), arp_request, ); - check_arp_mac( - net.clone(), - test_state.clone(), - vqs[0].clone(), - arp_request, - need_reply, - ); + check_arp_mac(net, test_state, vqs[0].clone(), arp_request, need_reply); } fn check_device_status(net: Rc>, status: u8) { @@ -766,14 +754,7 @@ fn virtio_net_rx_tx_test() { true, ); - tear_down( - net.clone(), - test_state.clone(), - alloc.clone(), - vqs, - id, - false, - ); + tear_down(net, test_state, alloc, vqs, id, false); } /// Send and receive packet test with iothread. @@ -807,14 +788,7 @@ fn virtio_net_rx_tx_test_iothread() { true, ); - tear_down( - net.clone(), - test_state.clone(), - alloc.clone(), - vqs, - id, - false, - ); + tear_down(net, test_state, alloc, vqs, id, false); } /// Test the control mq command. @@ -919,14 +893,7 @@ fn virtio_net_ctrl_mq_test() { assert_eq!(ack, status); } - tear_down( - net.clone(), - test_state.clone(), - alloc.clone(), - vqs, - id, - true, - ); + tear_down(net, test_state, alloc, vqs, id, true); } /// Write or Read mac address from device config. @@ -1148,14 +1115,7 @@ fn ctrl_vq_set_mac_table( ctrl_data.len() ); - send_ctrl_vq_request( - net.clone(), - test_state.clone(), - alloc.clone(), - vqs.clone(), - &ctrl_data, - ack, - ); + send_ctrl_vq_request(net, test_state, alloc, vqs, &ctrl_data, ack); } fn ctrl_vq_set_mac_address( @@ -1178,14 +1138,14 @@ fn ctrl_vq_set_mac_address( }; send_ctrl_vq_request( net.clone(), - test_state.clone(), - alloc.clone(), - vqs.clone(), + test_state, + alloc, + vqs, ctrl_mac_addr.as_bytes(), VIRTIO_NET_OK, ); // Check mac address result. - let config_mac = net_config_mac_rw(net.clone(), None); + let config_mac = net_config_mac_rw(net, None); assert_eq!(config_mac, ARP_SOURCE_MAC); } @@ -1309,14 +1269,7 @@ fn virtio_net_ctrl_vlan_test() { false, ); - tear_down( - net.clone(), - test_state.clone(), - alloc.clone(), - vqs, - id, - false, - ); + tear_down(net, test_state, alloc, vqs, id, false); } /// Test the control mac command. @@ -1692,14 +1645,7 @@ fn virtio_net_ctrl_abnormal_test() { check_device_status(net.clone(), VIRTIO_CONFIG_S_NEEDS_RESET); } - tear_down( - net.clone(), - test_state.clone(), - alloc.clone(), - vqs, - id, - false, - ); + tear_down(net, test_state, alloc, vqs, id, false); } /// Test the abnormal rx/tx request. @@ -1769,14 +1715,7 @@ fn virtio_net_abnormal_rx_tx_test() { assert!(time::Instant::now() - start_time < timeout_us); } - tear_down( - net.clone(), - test_state.clone(), - alloc.clone(), - vqs, - id, - false, - ); + tear_down(net, test_state, alloc, vqs, id, false); } /// Test the abnormal rx/tx request 2. @@ -1895,14 +1834,7 @@ fn virtio_net_set_abnormal_feature() { true, ); - tear_down( - net.clone(), - test_state.clone(), - alloc.clone(), - vqs, - id, - false, - ); + tear_down(net, test_state, alloc, vqs, id, false); } /// Send abnormal packet. @@ -1978,14 +1910,7 @@ fn virtio_net_send_abnormal_packet() { .qmp("{\"execute\": \"qmp_capabilities\"}"); assert_eq!(*ret.get("return").unwrap(), json!({})); - tear_down( - net.clone(), - test_state.clone(), - alloc.clone(), - vqs, - id, - false, - ); + tear_down(net, test_state, alloc, vqs, id, false); } /// Send and receive packet test with mq. @@ -2020,14 +1945,7 @@ fn virtio_net_rx_tx_mq_test() { ); } - tear_down( - net.clone(), - test_state.clone(), - alloc.clone(), - vqs, - id, - true, - ); + tear_down(net, test_state, alloc, vqs, id, true); } /// Test the abnormal rx/tx request 3. @@ -2096,12 +2014,5 @@ fn virtio_net_abnormal_rx_tx_test_3() { .readw(vqs[1].borrow().used + offset_of!(VringUsed, idx) as u64); assert_eq!(used_idx, 0); - tear_down( - net.clone(), - test_state.clone(), - alloc.clone(), - vqs, - id, - false, - ); + tear_down(net, test_state, alloc, vqs, id, false); } diff --git a/tests/mod_test/tests/pci_test.rs b/tests/mod_test/tests/pci_test.rs index 831d6288..dcad2ea4 100644 --- a/tests/mod_test/tests/pci_test.rs +++ b/tests/mod_test/tests/pci_test.rs @@ -82,7 +82,7 @@ fn init_demo_dev(cfg: DemoDev, dev_num: u8) -> (Rc>, Rc Self { - let mut root_port = TestPciDev::new(machine.clone().borrow().pci_bus.clone()); + let mut root_port = TestPciDev::new(machine.borrow().pci_bus.clone()); root_port.set_bus_num(bus_num); root_port.devfn = devfn; assert_eq!(root_port.config_readw(PCI_SUB_CLASS_DEVICE), 0x0604); root_port.enable(); root_port.enable_msix(None); - let root_port_msix = MsixVector::new(0, alloc.clone()); + let root_port_msix = MsixVector::new(0, alloc); root_port.set_msix_vector( root_port_msix.msix_entry, root_port_msix.msix_addr, @@ -319,7 +319,7 @@ fn create_blk( pci_fn: u8, ) -> Rc> { let virtio_blk = Rc::new(RefCell::new(TestVirtioPciDev::new( - machine.clone().borrow().pci_bus.clone(), + machine.borrow().pci_bus.clone(), ))); virtio_blk.borrow_mut().pci_dev.set_bus_num(bus_num); virtio_blk.borrow_mut().init(pci_slot, pci_fn); @@ -405,10 +405,9 @@ fn tear_down( blk.clone().unwrap().borrow_mut().pci_dev.disable_msix(); } if vqs.is_some() { - blk.clone() - .unwrap() + blk.unwrap() .borrow_mut() - .destroy_device(alloc.clone(), vqs.unwrap()); + .destroy_device(alloc, vqs.unwrap()); } test_state.borrow_mut().stop(); @@ -564,12 +563,7 @@ fn validate_blk_io_success( .borrow_mut() .init_device(test_state.clone(), alloc.clone(), features, 1); - validate_std_blk_io( - blk.clone(), - test_state.clone(), - virtqueues.clone(), - alloc.clone(), - ); + validate_std_blk_io(blk.clone(), test_state, virtqueues.clone(), alloc.clone()); blk.borrow_mut().pci_dev.disable_msix(); blk.borrow() @@ -583,14 +577,14 @@ fn simple_blk_io_req( alloc: Rc>, ) -> u32 { let (free_head, _req_addr) = add_blk_request( - test_state.clone(), - alloc.clone(), + test_state, + alloc, virtqueue.clone(), VIRTIO_BLK_T_OUT, 0, false, ); - blk.borrow().virtqueue_notify(virtqueue.clone()); + blk.borrow().virtqueue_notify(virtqueue); free_head } @@ -629,14 +623,7 @@ fn validate_std_blk_io( false, ); - virtio_blk_read( - blk.clone(), - test_state.clone(), - alloc.clone(), - virtqueues[0].clone(), - 0, - false, - ); + virtio_blk_read(blk, test_state, alloc, virtqueues[0].clone(), 0, false); } fn wait_root_port_msix(root_port: Rc>) -> bool { @@ -766,7 +753,7 @@ fn hotplug_blk( // Hotplug a block device whose bdf is 2:0:0. let (add_blk_command, add_device_command) = - build_hotplug_blk_cmd(hotplug_blk_id, hotplug_image_path.clone(), bus, slot, func); + build_hotplug_blk_cmd(hotplug_blk_id, hotplug_image_path, bus, slot, func); let ret = test_state.borrow().qmp(&add_blk_command); assert_eq!(*ret.get("return").unwrap(), json!({})); @@ -790,7 +777,7 @@ fn hotplug_blk( validate_hotplug(root_port.clone()); handle_isr(root_port.clone()); - power_on_device(root_port.clone()); + power_on_device(root_port); } fn hotunplug_blk( @@ -823,7 +810,7 @@ fn hotunplug_blk( "Wait for interrupt of root port timeout" ); validate_cmd_complete(root_port.clone()); - handle_isr(root_port.clone()); + handle_isr(root_port); // Verify the vendor id for the virtio block device. validate_config_value_2byte( blk.borrow().pci_dev.pci_bus.clone(), @@ -899,7 +886,7 @@ fn test_pci_device_discovery_001() { let (test_state, machine, alloc, image_paths) = set_up(blk_nums, root_port_nums, true, false); // Create a block device whose bdf is 1:0:0. - let blk = create_blk(machine.clone(), 1, 0, 0); + let blk = create_blk(machine, 1, 0, 0); // Verify the vendor id for non-existent devices. validate_config_value_2byte( @@ -972,12 +959,12 @@ fn test_pci_device_discovery_002() { ); // Hotplug a block device whose id is 0. - hotunplug_blk(test_state.clone(), blk.clone(), root_port_1.clone(), 0); + hotunplug_blk(test_state.clone(), blk, root_port_1, 0); // Hotplug a block device whose id is 1 and bdf is 2:0:0. hotplug_blk( test_state.clone(), - root_port_2.clone(), + root_port_2, &mut image_paths, 1, 2, @@ -986,7 +973,7 @@ fn test_pci_device_discovery_002() { ); // Create a block device whose bdf is 2:0:0. - let blk = create_blk(machine.clone(), 2, 0, 0); + let blk = create_blk(machine, 2, 0, 0); // Verify the vendor id for the virtio block device hotplugged. validate_config_value_2byte( blk.borrow().pci_dev.pci_bus.clone(), @@ -1010,7 +997,7 @@ fn test_pci_device_discovery_003() { // Create a root port whose bdf is 0:1:0. let root_port = Rc::new(RefCell::new(RootPort::new( - machine.clone(), + machine, alloc.clone(), 0, 1 << 3, @@ -1032,7 +1019,7 @@ fn test_pci_device_discovery_003() { // Hotplug a block device whose bdf is 1:0:0. let (add_blk_command, add_device_command) = - build_hotplug_blk_cmd(blk_id, hotplug_image_path.clone(), 1, 0, 0); + build_hotplug_blk_cmd(blk_id, hotplug_image_path, 1, 0, 0); let ret = test_state.borrow().qmp(&add_blk_command); assert_eq!(*ret.get("return").unwrap(), json!({})); let ret = test_state.borrow().qmp(&add_device_command); @@ -1069,7 +1056,7 @@ fn test_pci_device_discovery_004() { let blk_id = 0; let hotplug_image_path = create_img(TEST_IMAGE_SIZE, 1, &ImageType::Raw); - image_paths.push(hotplug_image_path.clone()); + image_paths.push(hotplug_image_path); // Hotplug a block device whose id is 0 and bdf is 1:0:0. hotplug_blk( @@ -1083,10 +1070,10 @@ fn test_pci_device_discovery_004() { ); // Create a block device whose bdf is 1:0:0. - let blk = create_blk(machine.clone(), 1, 0, 0); + let blk = create_blk(machine, 1, 0, 0); // Hotunplug the virtio block device whose id is 0. - hotunplug_blk(test_state.clone(), blk.clone(), root_port.clone(), blk_id); + hotunplug_blk(test_state.clone(), blk, root_port, blk_id); tear_down(None, test_state, alloc, None, Some(image_paths)); } @@ -1099,7 +1086,7 @@ fn test_pci_type0_config() { let (test_state, machine, alloc, image_paths) = set_up(root_port_nums, blk_nums, true, false); // Create a block device whose bdf is 1:0:0. - let blk = create_blk(machine.clone(), 1, 0, 0); + let blk = create_blk(machine, 1, 0, 0); // Verify that the vendor id of type0 device is read-only. validate_config_perm_2byte( @@ -1244,7 +1231,7 @@ fn test_pci_type1_config() { let (test_state, machine, alloc, image_paths) = set_up(root_port_nums, blk_nums, true, false); // Create a root port whose bdf is 0:1:0. - let root_port = RootPort::new(machine.clone(), alloc.clone(), 0, 1 << 3); + let root_port = RootPort::new(machine, alloc.clone(), 0, 1 << 3); assert_eq!(root_port.rp_dev.config_readb(PCI_PRIMARY_BUS), 0); assert_ne!(root_port.rp_dev.config_readb(PCI_SECONDARY_BUS), 0); @@ -1260,7 +1247,7 @@ fn test_pci_type1_reset() { let (test_state, machine, alloc, image_paths) = set_up(root_port_nums, blk_nums, true, false); // Create a root port whose bdf is 0:1:0. - let root_port = RootPort::new(machine.clone(), alloc.clone(), 0, 1 << 3); + let root_port = RootPort::new(machine, alloc.clone(), 0, 1 << 3); let command = root_port.rp_dev.config_readw(PCI_COMMAND); let cmd_memory = command & u16::from(PCI_COMMAND_MEMORY); @@ -1320,7 +1307,7 @@ fn test_out_size_config_access() { let (test_state, machine, alloc, image_paths) = set_up(root_port_nums, blk_nums, true, false); // Create a root port whose bdf is 0:1:0. - let root_port = RootPort::new(machine.clone(), alloc.clone(), 0, 1 << 3); + let root_port = RootPort::new(machine, alloc.clone(), 0, 1 << 3); let vendor_device_id = root_port.rp_dev.config_readl(PCI_VENDOR_ID); let command_status = root_port.rp_dev.config_readl(PCI_COMMAND); @@ -1341,7 +1328,7 @@ fn test_out_boundary_msix_access() { let (test_state, machine, alloc, image_paths) = set_up(root_port_nums, blk_nums, true, false); // Create a root port whose bdf is 0:1:0. - let root_port = RootPort::new(machine.clone(), alloc.clone(), 0, 1 << 3); + let root_port = RootPort::new(machine, alloc.clone(), 0, 1 << 3); // Out-of-bounds access to the msix table. let write_value = u32::max_value(); @@ -1371,7 +1358,7 @@ fn test_repeat_io_map_bar() { let (test_state, machine, alloc, image_paths) = set_up(root_port_nums, blk_nums, true, false); // Create a block device whose bdf is 1:0:0. - let blk = create_blk(machine.clone(), 1, 0, 0); + let blk = create_blk(machine, 1, 0, 0); let vqs = blk.borrow_mut().init_device( test_state.clone(), @@ -1406,7 +1393,7 @@ fn test_pci_type0_msix_config() { let root_port_nums = 0; let (test_state, machine, alloc, image_paths) = set_up(root_port_nums, blk_nums, false, false); // Create a block device whose bdf is 1:0:0. - let blk = create_blk(machine.clone(), 0, 1, 0); + let blk = create_blk(machine, 0, 1, 0); // Verify that there is only one msix capability addr of the type0 pci device. let blk_cap_msix_addrs = lookup_all_cap_addr(PCI_CAP_ID_MSIX, blk.borrow().pci_dev.clone()); @@ -1472,7 +1459,7 @@ fn test_pci_msix_global_ctl() { let (test_state, machine, alloc, image_paths) = set_up(root_port_nums, blk_nums, true, false); // Create a block device whose bdf is 1:0:0. - let blk = create_blk(machine.clone(), 1, 0, 0); + let blk = create_blk(machine, 1, 0, 0); let vqs = blk.borrow_mut().init_device( test_state.clone(), alloc.clone(), @@ -1546,7 +1533,7 @@ fn test_pci_msix_local_ctl() { let (test_state, machine, alloc, image_paths) = set_up(root_port_nums, blk_nums, true, false); // Create a block device whose bdf is 1:0:0. - let blk = create_blk(machine.clone(), 1, 0, 0); + let blk = create_blk(machine, 1, 0, 0); let vqs = blk.borrow_mut().init_device( test_state.clone(), alloc.clone(), @@ -1586,7 +1573,7 @@ fn test_alloc_abnormal_vector() { let (test_state, machine, alloc, image_paths) = set_up(root_port_nums, blk_nums, true, false); // Create a block device whose bdf is 1:0:0. - let blk = create_blk(machine.clone(), 1, 0, 0); + let blk = create_blk(machine, 1, 0, 0); // 1. Init device. blk.borrow_mut().reset(); @@ -1627,7 +1614,7 @@ fn test_intx_basic() { let root_port_nums = 1; let (test_state, machine, alloc, image_paths) = set_up(root_port_nums, blk_nums, true, false); - let blk = create_blk(machine.clone(), 1, 0, 0); + let blk = create_blk(machine, 1, 0, 0); // 1. Init device. blk.borrow_mut().reset(); @@ -1686,7 +1673,7 @@ fn test_intx_disable() { let root_port_nums = 1; let (test_state, machine, alloc, image_paths) = set_up(root_port_nums, blk_nums, true, false); - let blk = create_blk(machine.clone(), 1, 0, 0); + let blk = create_blk(machine, 1, 0, 0); // 1. Init device. blk.borrow_mut().reset(); @@ -1782,18 +1769,10 @@ fn test_pci_hotplug_001() { ))); // Hotplug a block device whose id is 1 and bdf is 1:0:0. - hotplug_blk( - test_state.clone(), - root_port.clone(), - &mut image_paths, - 0, - 1, - 0, - 0, - ); + hotplug_blk(test_state.clone(), root_port, &mut image_paths, 0, 1, 0, 0); // Create a block device whose bdf is 1:0:0. - let blk = create_blk(machine.clone(), 1, 0, 0); + let blk = create_blk(machine, 1, 0, 0); let vqs = blk.borrow_mut().init_device( test_state.clone(), alloc.clone(), @@ -1833,7 +1812,7 @@ fn test_pci_hotplug_002() { // Hotplug a block device whose id is 1 and bdf is 1:0:0. hotplug_blk( test_state.clone(), - root_port_1.clone(), + root_port_1, &mut image_paths, 1, 1, @@ -1845,17 +1824,17 @@ fn test_pci_hotplug_002() { // Hotplug a block device whose id is 2 and bdf is 2:0:0. hotplug_blk( test_state.clone(), - root_port_2.clone(), + root_port_2, &mut image_paths, 2, 2, 0, 0, ); - let blk_2 = create_blk(machine.clone(), 2, 0, 0); + let blk_2 = create_blk(machine, 2, 0, 0); - validate_blk_io_success(blk_1.clone(), test_state.clone(), alloc.clone()); - validate_blk_io_success(blk_2.clone(), test_state.clone(), alloc.clone()); + validate_blk_io_success(blk_1, test_state.clone(), alloc.clone()); + validate_blk_io_success(blk_2, test_state.clone(), alloc.clone()); tear_down(None, test_state, alloc, None, Some(image_paths)); } @@ -1873,7 +1852,7 @@ fn test_pci_hotplug_003() { // Hotplug a block device whose id is 0, bdf is 1:1:0. let (add_blk_command, add_device_command) = - build_hotplug_blk_cmd(0, hotplug_image_path.clone(), 1, 1, 0); + build_hotplug_blk_cmd(0, hotplug_image_path, 1, 1, 0); let ret = test_state.borrow().qmp(&add_blk_command); assert_eq!(*ret.get("return").unwrap(), json!({})); // Verify that hotpluging the device in non-zero slot will fail. @@ -1896,7 +1875,7 @@ fn test_pci_hotplug_004() { let hotplug_blk_id = 1; let (add_blk_command, add_device_command) = - build_hotplug_blk_cmd(hotplug_blk_id, hotplug_image_path.clone(), 0, 1, 0); + build_hotplug_blk_cmd(hotplug_blk_id, hotplug_image_path, 0, 1, 0); let ret = test_state.borrow().qmp(&add_blk_command); assert_eq!(*ret.get("return").unwrap(), json!({})); let ret = test_state.borrow().qmp(&add_device_command); @@ -1914,7 +1893,7 @@ fn test_pci_hotplug_005() { set_up(root_port_nums, blk_nums, true, false); let hotplug_image_path = create_img(TEST_IMAGE_SIZE, 1, &ImageType::Raw); - image_paths.push(hotplug_image_path.clone()); + image_paths.push(hotplug_image_path); let hotplug_blk_id = 0; let (add_blk_command, add_device_command) = @@ -1981,7 +1960,7 @@ fn test_pci_hotplug_007() { // Hotplug a block device whose bdf is 1:0:0. let (add_blk_command, add_device_command) = - build_hotplug_blk_cmd(hotplug_blk_id, hotplug_image_path.clone(), bus, slot, 0); + build_hotplug_blk_cmd(hotplug_blk_id, hotplug_image_path, bus, slot, 0); let ret = test_state.borrow().qmp(&add_blk_command); assert_eq!(*ret.get("return").unwrap(), json!({})); @@ -2005,10 +1984,10 @@ fn test_pci_hotplug_007() { validate_hotplug(root_port.clone()); handle_isr(root_port.clone()); - power_on_device(root_port.clone()); + power_on_device(root_port); // Create a block device whose bdf is 1:0:0. - let blk = create_blk(machine.clone(), 1, 0, 0); + let blk = create_blk(machine, 1, 0, 0); let vqs = blk.borrow_mut().init_device( test_state.clone(), alloc.clone(), @@ -2037,10 +2016,10 @@ fn test_pci_hotunplug_001() { ))); // Create a block device whose bdf is 1:0:0. - let blk = create_blk(machine.clone(), 1, 0, 0); + let blk = create_blk(machine, 1, 0, 0); // Hotunplug the block device whose bdf is 1:0:0. - hotunplug_blk(test_state.clone(), blk.clone(), root_port.clone(), 0); + hotunplug_blk(test_state.clone(), blk, root_port, 0); tear_down(None, test_state, alloc, None, Some(image_paths)); } @@ -2078,7 +2057,7 @@ fn test_pci_hotunplug_003() { ))); // Create a block device whose bdf is 1:0:0. - let blk = create_blk(machine.clone(), 1, 0, 0); + let blk = create_blk(machine, 1, 0, 0); let unplug_blk_id = 0; // Hotunplug the block device attaching the root port. @@ -2129,7 +2108,7 @@ fn test_pci_hotunplug_003() { assert!(!(*ret.get("error").unwrap()).is_null()); // The block device will be unplugged when indicator of power and slot is power off. - power_off_device(root_port.clone()); + power_off_device(root_port); test_state.borrow().wait_qmp_event(); // Verify the vendor id for the virtio block device. @@ -2172,7 +2151,7 @@ fn test_pci_hotunplug_004() { let blk_1 = create_blk(machine.clone(), 1, 0, 0); // Create a block device whose bdf is 2:0:0. - let blk_2 = create_blk(machine.clone(), 2, 0, 0); + let blk_2 = create_blk(machine, 2, 0, 0); let unplug_blk_id = 0; let (delete_device_command, delete_blk_command_1) = build_hotunplug_blk_cmd(unplug_blk_id); @@ -2194,10 +2173,10 @@ fn test_pci_hotunplug_004() { "Wait for interrupt of root port timeout" ); - power_off_device(root_port_1.clone()); + power_off_device(root_port_1); test_state.borrow().wait_qmp_event(); - power_off_device(root_port_2.clone()); + power_off_device(root_port_2); test_state.borrow().wait_qmp_event(); // The block device will be unplugged when indicator of power and slot is power off. @@ -2245,10 +2224,10 @@ fn test_pci_hotunplug_005() { 1 << 3, ))); - let blk = create_blk(machine.clone(), 1, 0, 0); + let blk = create_blk(machine, 1, 0, 0); // Hotplug the block device whose id is 0 and bdf is 1:0:0. - hotunplug_blk(test_state.clone(), blk.clone(), root_port.clone(), 0); + hotunplug_blk(test_state.clone(), blk, root_port, 0); let (delete_device_command, _delete_blk_command) = build_hotunplug_blk_cmd(0); let ret = test_state.borrow().qmp(&delete_device_command); @@ -2289,7 +2268,7 @@ fn test_pci_hotunplug_007() { ))); // Create a block device whose bdf is 1:0:0. - let blk = create_blk(machine.clone(), 1, 0, 0); + let blk = create_blk(machine, 1, 0, 0); let unplug_blk_id = 0; // Hotunplug the block device attaching the root port. @@ -2303,7 +2282,7 @@ fn test_pci_hotunplug_007() { // The block device will be unplugged when indicator of power and slot is power off. power_off_device(root_port.clone()); // Trigger a 2nd write to PIC/PCC, which will be ignored by the device, and causes no harm. - power_off_device(root_port.clone()); + power_off_device(root_port); test_state.borrow().wait_qmp_event(); @@ -2339,7 +2318,7 @@ fn test_pci_hotunplug_008() { root_port.borrow_mut().rp_dev.set_intx_irq_num(1_u8); // Create a block device whose bdf is 1:0:0. - let blk = create_blk(machine.clone(), 1, 0, 0); + let blk = create_blk(machine, 1, 0, 0); // Hotunplug the block device whose bdf is 1:0:0. let hotunplug_blk_id = 0; @@ -2366,7 +2345,7 @@ fn test_pci_hotunplug_008() { "Wait for interrupt of root port timeout" ); validate_cmd_complete(root_port.clone()); - handle_isr(root_port.clone()); + handle_isr(root_port); // Verify the vendor id for the virtio block device. validate_config_value_2byte( blk.borrow().pci_dev.pci_bus.clone(), @@ -2402,7 +2381,7 @@ fn test_pci_hotplug_combine_001() { // Hotplug a block device whose bdf is 1:0:0. let (add_blk_command, add_device_command) = - build_hotplug_blk_cmd(hotplug_blk_id, hotplug_image_path.clone(), 1, 0, 0); + build_hotplug_blk_cmd(hotplug_blk_id, hotplug_image_path, 1, 0, 0); let ret = test_state.borrow().qmp(&add_blk_command); assert_eq!(*ret.get("return").unwrap(), json!({})); let ret = test_state.borrow().qmp(&add_device_command); @@ -2425,7 +2404,7 @@ fn test_pci_hotplug_combine_001() { 1, ); // Verify that the function of the block device is normal. - validate_std_blk_io(blk.clone(), test_state.clone(), vqs.clone(), alloc.clone()); + validate_std_blk_io(blk.clone(), test_state.clone(), vqs, alloc.clone()); let (delete_device_command, delete_blk_command) = build_hotunplug_blk_cmd(hotplug_blk_id); let ret = test_state.borrow().qmp(&delete_device_command); @@ -2458,7 +2437,7 @@ fn test_pci_hotplug_combine_001() { // Hotplug a block device whose bdf is 1:0:0. let (add_blk_command, add_device_command) = - build_hotplug_blk_cmd(hotplug_blk_id, hotplug_image_path.clone(), 1, 0, 0); + build_hotplug_blk_cmd(hotplug_blk_id, hotplug_image_path, 1, 0, 0); let ret = test_state.borrow().qmp(&add_blk_command); assert_eq!(*ret.get("return").unwrap(), json!({})); let ret = test_state.borrow().qmp(&add_device_command); @@ -2482,7 +2461,7 @@ fn test_pci_hotplug_combine_001() { 0xFFFF, ); - let blk = create_blk(machine.clone(), 1, 0, 0); + let blk = create_blk(machine, 1, 0, 0); let vqs = blk.borrow_mut().init_device( test_state.clone(), alloc.clone(), @@ -2490,7 +2469,7 @@ fn test_pci_hotplug_combine_001() { 1, ); // Verify that the function of the block device is normal. - validate_std_blk_io(blk.clone(), test_state.clone(), vqs.clone(), alloc.clone()); + validate_std_blk_io(blk.clone(), test_state.clone(), vqs, alloc.clone()); let (delete_device_command, delete_blk_command) = build_hotunplug_blk_cmd(hotplug_blk_id); let ret = test_state.borrow().qmp(&delete_device_command); @@ -2500,7 +2479,7 @@ fn test_pci_hotplug_combine_001() { ); handle_isr(root_port.clone()); - power_off_device(root_port.clone()); + power_off_device(root_port); assert_eq!(*ret.get("return").unwrap(), json!({})); test_state.borrow().wait_qmp_event(); @@ -2551,7 +2530,7 @@ fn test_pci_hotplug_combine_002() { power_indicator_off(root_port.clone()); // Create a block device whose bdf is 1:0:0. - let blk = create_blk(machine.clone(), 1, 0, 0); + let blk = create_blk(machine, 1, 0, 0); validate_blk_io_success(blk.clone(), test_state.clone(), alloc.clone()); @@ -2591,7 +2570,7 @@ fn test_pci_hotplug_combine_002() { ); handle_isr(root_port.clone()); - power_off_device(root_port.clone()); + power_off_device(root_port); test_state.borrow().wait_qmp_event(); let ret = test_state.borrow().qmp(&delete_blk_command); @@ -2643,25 +2622,25 @@ fn test_pci_hotplug_combine_003() { // Hotplug a block device whose bdf is 1:0:0. let (add_blk_command, add_device_command) = - build_hotplug_blk_cmd(hotunplug_blk_id, hotplug_image_path.clone(), 1, 0, 0); + build_hotplug_blk_cmd(hotunplug_blk_id, hotplug_image_path, 1, 0, 0); let ret = test_state.borrow().qmp(&add_blk_command); assert_eq!(*ret.get("return").unwrap(), json!({})); let ret = test_state.borrow().qmp(&add_device_command); assert!(!(*ret.get("error").unwrap()).is_null()); - power_off_device(root_port.clone()); + power_off_device(root_port); test_state.borrow().wait_qmp_event(); let hotplug_image_path = create_img(TEST_IMAGE_SIZE, 1, &ImageType::Raw); image_paths.push(hotplug_image_path.clone()); // Hotplug a block device whose bdf is 1:0:0. let (add_blk_command, add_device_command) = - build_hotplug_blk_cmd(hotunplug_blk_id, hotplug_image_path.clone(), 1, 0, 0); + build_hotplug_blk_cmd(hotunplug_blk_id, hotplug_image_path, 1, 0, 0); let ret = test_state.borrow().qmp(&add_blk_command); assert!(!(*ret.get("error").unwrap()).is_null()); let ret = test_state.borrow().qmp(&add_device_command); assert_eq!(*ret.get("return").unwrap(), json!({})); - let blk = create_blk(machine.clone(), 1, 0, 0); + let blk = create_blk(machine, 1, 0, 0); let vqs = blk.borrow_mut().init_device( test_state.clone(), alloc.clone(), @@ -2773,7 +2752,7 @@ fn test_pci_root_port_exp_cap() { 0, ); // Create a block device whose bdf is 1:0:0. - let blk = create_blk(machine.clone(), 1, 0, 0); + let blk = create_blk(machine, 1, 0, 0); let nlw_mask = PCI_EXP_LNKSTA_NLW; let negotiated_link_width = (root_port.borrow().rp_dev.pci_bus.borrow().config_readw( @@ -2843,12 +2822,7 @@ fn test_pci_root_port_exp_cap() { ); // Hotplug the block device whose id is 0 and bdf is 1:0:0. - hotunplug_blk( - test_state.clone(), - blk.clone(), - root_port.clone(), - hotplug_blk_id, - ); + hotunplug_blk(test_state.clone(), blk, root_port.clone(), hotplug_blk_id); let dllla_mask = PCI_EXP_LNKSTA_DLLLA; validate_config_value_2byte( @@ -3001,7 +2975,7 @@ fn test_pci_combine_002() { wait_root_port_msix(root_port.clone()), "Wait for interrupt of root port timeout" ); - power_off_device(root_port.clone()); + power_off_device(root_port); // r/w mmio during hotunplug test_state.borrow().writeb(bar_addr, 5); diff --git a/tests/mod_test/tests/pvpanic_test.rs b/tests/mod_test/tests/pvpanic_test.rs index 01583a83..fd084959 100644 --- a/tests/mod_test/tests/pvpanic_test.rs +++ b/tests/mod_test/tests/pvpanic_test.rs @@ -66,7 +66,7 @@ impl PvPanicDevCfg { let test_state = Rc::new(RefCell::new(test_init(test_machine_args))); let machine = Rc::new(RefCell::new(TestStdMachine::new(test_state.clone()))); - let mut pvpanic_pci_dev = TestPciDev::new(machine.clone().borrow().pci_bus.clone()); + let mut pvpanic_pci_dev = TestPciDev::new(machine.borrow().pci_bus.clone()); let devfn = self.addr << 3; pvpanic_pci_dev.devfn = devfn; diff --git a/tests/mod_test/tests/rng_test.rs b/tests/mod_test/tests/rng_test.rs index 3a120b57..9296ebb0 100644 --- a/tests/mod_test/tests/rng_test.rs +++ b/tests/mod_test/tests/rng_test.rs @@ -82,7 +82,7 @@ fn virtio_rng_read_batch( .kick_virtqueue(test_state.clone(), virtqueue.clone()); rng.borrow().poll_used_elem( test_state.clone(), - virtqueue.clone(), + virtqueue, free_head, TIMEOUT_US, &mut len, @@ -123,7 +123,7 @@ fn virtio_rng_read_chained( .kick_virtqueue(test_state.clone(), virtqueue.clone()); rng.borrow().poll_used_elem( test_state.clone(), - virtqueue.clone(), + virtqueue, free_head, TIMEOUT_US, &mut len, @@ -142,7 +142,7 @@ fn tear_down( alloc: Rc>, vqs: Vec>>, ) { - rng.borrow_mut().destroy_device(alloc.clone(), vqs); + rng.borrow_mut().destroy_device(alloc, vqs); test_state.borrow_mut().stop(); } @@ -186,7 +186,7 @@ fn rng_read() { ); assert!(random_num_check(data)); - tear_down(rng.clone(), test_state.clone(), alloc.clone(), virtqueues); + tear_down(rng, test_state, alloc, virtqueues); } /// Rng device batch read random numbers function test. @@ -229,7 +229,7 @@ fn rng_read_batch() { ); assert!(random_num_check(data)); - tear_down(rng.clone(), test_state.clone(), alloc.clone(), virtqueues); + tear_down(rng, test_state, alloc, virtqueues); } /// Rng device rate limit random numbers reading test. @@ -300,7 +300,7 @@ fn rng_limited_rate() { RNG_DATA_BYTES ))); - tear_down(rng.clone(), test_state.clone(), alloc.clone(), virtqueues); + tear_down(rng, test_state, alloc, virtqueues); } /// Rng device read a large number of random numbers test. @@ -344,7 +344,7 @@ fn rng_read_with_max() { ); assert!(random_num_check(data)); - tear_down(rng.clone(), test_state.clone(), alloc.clone(), virtqueues); + tear_down(rng, test_state, alloc, virtqueues); } /// Rng device read/write config space. @@ -376,5 +376,5 @@ fn rng_rw_config() { let config = rng.borrow().config_readq(0); assert_ne!(config, 0xff); - tear_down(rng.clone(), test_state.clone(), alloc.clone(), virtqueues); + tear_down(rng, test_state, alloc, virtqueues); } diff --git a/tests/mod_test/tests/scsi_test.rs b/tests/mod_test/tests/scsi_test.rs index 443ce74f..acbdf17a 100644 --- a/tests/mod_test/tests/scsi_test.rs +++ b/tests/mod_test/tests/scsi_test.rs @@ -138,7 +138,7 @@ impl VirtioScsiTest { let scsi_devices: Vec = vec![ScsiDeviceConfig { cntlr_id: 0, device_type: scsi_type, - image_path: image_path.clone(), + image_path, target, lun, read_only: readonly, @@ -621,7 +621,7 @@ fn scsi_test_init( let machine = TestStdMachine::new(test_state.clone()); let allocator = machine.allocator.clone(); - let virtio_scsi = Rc::new(RefCell::new(TestVirtioPciDev::new(machine.pci_bus.clone()))); + let virtio_scsi = Rc::new(RefCell::new(TestVirtioPciDev::new(machine.pci_bus))); virtio_scsi.borrow_mut().init(pci_slot, pci_fn); (virtio_scsi, test_state, allocator) @@ -1874,7 +1874,7 @@ fn aio_model_test() { device_vec.push(ScsiDeviceConfig { cntlr_id: 0, device_type: ScsiDeviceType::ScsiHd, - image_path: image_path.clone(), + image_path, target, lun, read_only: false, @@ -1889,7 +1889,7 @@ fn aio_model_test() { device_vec.push(ScsiDeviceConfig { cntlr_id: 0, device_type: ScsiDeviceType::ScsiHd, - image_path: image_path.clone(), + image_path, target, lun, read_only: false, @@ -1908,7 +1908,7 @@ fn aio_model_test() { device_vec.push(ScsiDeviceConfig { cntlr_id: 0, device_type: ScsiDeviceType::ScsiHd, - image_path: image_path.clone(), + image_path, target, lun, read_only: false, @@ -1927,7 +1927,7 @@ fn aio_model_test() { device_vec.push(ScsiDeviceConfig { cntlr_id: 0, device_type: ScsiDeviceType::ScsiHd, - image_path: image_path.clone(), + image_path, target, lun, read_only: false, diff --git a/tests/mod_test/tests/serial_test.rs b/tests/mod_test/tests/serial_test.rs index 0efbc529..8009f8f2 100644 --- a/tests/mod_test/tests/serial_test.rs +++ b/tests/mod_test/tests/serial_test.rs @@ -155,7 +155,7 @@ impl SerialTest { self.serial .borrow() - .kick_virtqueue(self.state.clone(), queue.clone()); + .kick_virtqueue(self.state.clone(), queue); (addr, free_head) } @@ -599,7 +599,7 @@ fn virtserialport_socket_basic() { nowait: true, }; let port = PortConfig { - chardev_type: socket.clone(), + chardev_type: socket, nr: 1, is_console: false, }; @@ -657,7 +657,7 @@ fn virtconsole_pty_err_out_control_msg() { }; let pci_slot = 0x04; let pci_fn = 0x0; - let mut st = create_serial(vec![port.clone()], pci_slot, pci_fn); + let mut st = create_serial(vec![port], pci_slot, pci_fn); st.serial_init(); @@ -707,7 +707,7 @@ fn virtconsole_pty_invalid_in_control_buffer() { }; let pci_slot = 0x04; let pci_fn = 0x0; - let mut st = create_serial(vec![port.clone()], pci_slot, pci_fn); + let mut st = create_serial(vec![port], pci_slot, pci_fn); // Init virtqueues. st.virtqueue_setup(DEFAULT_SERIAL_VIRTQUEUES); @@ -776,7 +776,7 @@ fn virtserialport_socket_not_connect() { nowait: true, }; let port = PortConfig { - chardev_type: socket.clone(), + chardev_type: socket, nr, is_console: false, }; diff --git a/tests/mod_test/tests/usb_camera_test.rs b/tests/mod_test/tests/usb_camera_test.rs index 13ce8c2b..98ac301a 100644 --- a/tests/mod_test/tests/usb_camera_test.rs +++ b/tests/mod_test/tests/usb_camera_test.rs @@ -565,7 +565,7 @@ fn test_xhci_camera_hotplug_invalid() { #[cfg(target_env = "ohos")] assert_eq!(desc, "OH Camera: failed to init cameras"); // Invalid device id. - let value = qmp_unplug_camera(&test_state.clone(), "usbcam0"); + let value = qmp_unplug_camera(&test_state, "usbcam0"); let desc = value["error"]["desc"].as_str().unwrap().to_string(); assert_eq!(desc, "Failed to detach device: id usbcam0 not found"); // Invalid cameradev id. diff --git a/tests/mod_test/tests/virtio_test.rs b/tests/mod_test/tests/virtio_test.rs index 0c4a12f4..c306f359 100644 --- a/tests/mod_test/tests/virtio_test.rs +++ b/tests/mod_test/tests/virtio_test.rs @@ -78,17 +78,12 @@ fn send_one_request( alloc: Rc>, vq: Rc>, ) { - let (free_head, req_addr) = add_request( - test_state.clone(), - alloc.clone(), - vq.clone(), - VIRTIO_BLK_T_OUT, - 0, - ); + let (free_head, req_addr) = + add_request(test_state.clone(), alloc, vq.clone(), VIRTIO_BLK_T_OUT, 0); blk.borrow().virtqueue_notify(vq.clone()); blk.borrow().poll_used_elem( test_state.clone(), - vq.clone(), + vq, free_head, TIMEOUT_US, &mut None, @@ -170,9 +165,7 @@ fn check_req_result( addr: u64, timeout_us: u64, ) { - let status = blk - .borrow() - .req_result(test_state.clone(), addr, timeout_us); + let status = blk.borrow().req_result(test_state, addr, timeout_us); assert!(!blk.borrow().queue_was_notified(vq)); assert_eq!(status, VIRTIO_BLK_S_OK); } @@ -288,13 +281,7 @@ fn do_event_idx_with_flag(flag: u16) { DEFAULT_IO_REQS * 2 - 1, ); - tear_down( - blk.clone(), - test_state.clone(), - alloc.clone(), - vqs, - image_path.clone(), - ); + tear_down(blk, test_state, alloc, vqs, image_path); } /// Feature Test. @@ -332,13 +319,7 @@ fn virtio_feature_none() { check_stratovirt_status(test_state.clone()); - tear_down( - blk.clone(), - test_state.clone(), - alloc.clone(), - vqs, - image_path.clone(), - ); + tear_down(blk, test_state, alloc, vqs, image_path); } /// Feature Test. @@ -414,13 +395,7 @@ fn virtio_feature_vertion_1() { DEFAULT_IO_REQS, ); - tear_down( - blk.clone(), - test_state.clone(), - alloc.clone(), - vqs, - image_path.clone(), - ); + tear_down(blk, test_state, alloc, vqs, image_path); } /// Driver just enable VIRTIO_F_VERSION_1|VIRTIO_RING_F_INDIRECT_DESC feature, @@ -526,13 +501,7 @@ fn virtio_feature_indirect() { "TEST" ); - tear_down( - blk.clone(), - test_state.clone(), - alloc.clone(), - vqs, - image_path.clone(), - ); + tear_down(blk, test_state, alloc, vqs, image_path); } /// Driver just enable VIRTIO_F_VERSION_1|VIRTIO_RING_F_EVENT_IDX feature, @@ -674,13 +643,7 @@ fn virtio_feature_indirect_and_event_idx() { DEFAULT_IO_REQS * 2 - 1, ); - tear_down( - blk.clone(), - test_state.clone(), - alloc.clone(), - vqs, - image_path.clone(), - ); + tear_down(blk, test_state, alloc, vqs, image_path); } /// Setting abnormal status in device initialization. @@ -759,13 +722,7 @@ fn virtio_init_device_abnormal_status() { check_stratovirt_status(test_state.clone()); // 4. Destroy device. - tear_down( - blk.clone(), - test_state.clone(), - alloc.clone(), - vqs, - image_path.clone(), - ); + tear_down(blk, test_state, alloc, vqs, image_path); } /// Setting abnormal feature in device initialization. @@ -1133,13 +1090,7 @@ fn virtio_init_device_out_of_order_1() { 0, ); - tear_down( - blk.clone(), - test_state.clone(), - alloc.clone(), - vqs, - image_path.clone(), - ); + tear_down(blk, test_state, alloc, vqs, image_path); } /// Init device out of order test 2. @@ -1192,13 +1143,7 @@ fn virtio_init_device_out_of_order_2() { 0, ); - tear_down( - blk.clone(), - test_state.clone(), - alloc.clone(), - vqs, - image_path.clone(), - ); + tear_down(blk, test_state, alloc, vqs, image_path); } /// Init device out of order test 3. @@ -1253,13 +1198,7 @@ fn virtio_init_device_out_of_order_3() { 0, ); - tear_down( - blk.clone(), - test_state.clone(), - alloc.clone(), - vqs, - image_path.clone(), - ); + tear_down(blk, test_state, alloc, vqs, image_path); } /// Repeat the initialization operation. @@ -1323,13 +1262,7 @@ fn virtio_init_device_repeat() { 0, ); - tear_down( - blk.clone(), - test_state.clone(), - alloc.clone(), - vqs, - image_path.clone(), - ); + tear_down(blk, test_state, alloc, vqs, image_path); } /// Setting abnormal desc addr in IO request. @@ -1622,13 +1555,7 @@ fn virtio_io_abnormal_desc_flags_2() { assert!(blk.borrow().get_status() & VIRTIO_CONFIG_S_NEEDS_RESET > 0); check_stratovirt_status(test_state.clone()); - tear_down( - blk.clone(), - test_state.clone(), - alloc.clone(), - vqs, - image_path.clone(), - ); + tear_down(blk, test_state, alloc, vqs, image_path); } /// Setting abnormal desc flag in IO request, testcase 3. @@ -1829,13 +1756,7 @@ fn virtio_io_abnormal_desc_elem_place() { check_stratovirt_status(test_state.clone()); - tear_down( - blk.clone(), - test_state.clone(), - alloc.clone(), - vqs, - image_path.clone(), - ); + tear_down(blk, test_state, alloc, vqs, image_path); } /// Setting (queue_size + 1) indirect desc elems in IO request. @@ -1904,13 +1825,7 @@ fn virtio_io_abnormal_indirect_desc_elem_num() { check_stratovirt_status(test_state.clone()); - tear_down( - blk.clone(), - test_state.clone(), - alloc.clone(), - vqs, - image_path.clone(), - ); + tear_down(blk, test_state, alloc, vqs, image_path); } /// Setting invalid flags to avail->flag in IO request. @@ -2180,13 +2095,7 @@ fn virtio_io_abnormal_used_idx() { true, ); - tear_down( - blk.clone(), - test_state.clone(), - alloc.clone(), - vqs, - image_path.clone(), - ); + tear_down(blk, test_state, alloc, vqs, image_path); } /// Virtio test step out of order, testcase 1. @@ -2250,13 +2159,7 @@ fn virtio_test_out_of_order_1() { check_stratovirt_status(test_state.clone()); - tear_down( - blk.clone(), - test_state.clone(), - alloc.clone(), - vqs, - image_path.clone(), - ); + tear_down(blk, test_state, alloc, vqs, image_path); } /// Virtio test step out of order, testcase 2. @@ -2278,13 +2181,7 @@ fn virtio_test_out_of_order_2() { 1, ); - tear_down( - blk.clone(), - test_state.clone(), - alloc.clone(), - vqs, - image_path.clone(), - ); + tear_down(blk, test_state, alloc, vqs, image_path); let (blk, test_state, alloc, image_path) = set_up(&ImageType::Raw); let vqs = blk.borrow_mut().init_device( @@ -2309,13 +2206,7 @@ fn virtio_test_out_of_order_2() { 0, ); - tear_down( - blk.clone(), - test_state.clone(), - alloc.clone(), - vqs, - image_path.clone(), - ); + tear_down(blk, test_state, alloc, vqs, image_path); } /// Virtio test step repeat. @@ -2380,11 +2271,5 @@ fn virtio_test_repeat() { blk.borrow_mut().destroy_device(alloc.clone(), vqs.clone()); blk.borrow_mut().destroy_device(alloc.clone(), vqs.clone()); - tear_down( - blk.clone(), - test_state.clone(), - alloc.clone(), - vqs.clone(), - image_path.clone(), - ); + tear_down(blk, test_state, alloc, vqs, image_path); } diff --git a/tests/mod_test/tests/virtiofs_test.rs b/tests/mod_test/tests/virtiofs_test.rs index 99105aab..6598a9c7 100644 --- a/tests/mod_test/tests/virtiofs_test.rs +++ b/tests/mod_test/tests/virtiofs_test.rs @@ -75,7 +75,7 @@ fn env_prepare(temp: bool) -> (String, String, String) { .unwrap(); Command::new("mknod") - .arg(virtiofs_test_character_device.clone()) + .arg(virtiofs_test_character_device) .arg("c") .arg("1") .arg("1") @@ -132,7 +132,7 @@ impl VirtioFsTest { let machine = TestStdMachine::new_bymem(test_state.clone(), memsize * 1024 * 1024, page_size); let allocator = machine.allocator.clone(); - let dev = Rc::new(RefCell::new(TestVirtioPciDev::new(machine.pci_bus.clone()))); + let dev = Rc::new(RefCell::new(TestVirtioPciDev::new(machine.pci_bus))); dev.borrow_mut().init(pci_slot, pci_fn); let features = virtio_fs_default_feature(dev.clone()); let queues = @@ -288,7 +288,7 @@ impl VirtioFsTest { } fn testcase_end(&self, test_dir: String) { - self.testcase_check_and_end(None, test_dir.clone()); + self.testcase_check_and_end(None, test_dir); } fn testcase_check_and_end(&self, absolute_virtiofs_sock: Option, test_dir: String) { @@ -297,7 +297,7 @@ impl VirtioFsTest { .destroy_device(self.allocator.clone(), self.queues.clone()); if let Some(path) = absolute_virtiofs_sock { - let path_clone = path.clone(); + let path_clone = path; let sock_path = Path::new(&path_clone); assert!(sock_path.exists()); self.state.borrow_mut().stop(); @@ -1118,7 +1118,7 @@ fn symlink_test() { assert!(link_path.is_symlink()); // Read link - let node_id = fuse_lookup(&fs, linkname.clone()); + let node_id = fuse_lookup(&fs, linkname); let len = size_of::() as u32; let fuse_in_head = FuseInHeader::new(len, FUSE_READLINK, 8, node_id, 0, 0, 0, 0); let fuse_out_head = FuseOutHeader::default(); @@ -1492,7 +1492,7 @@ fn openfile_test() { // start vm. let fs = VirtioFsTest::new(TEST_MEM_SIZE, TEST_PAGE_SIZE, virtiofs_sock); fuse_init(&fs); - let nodeid = fuse_lookup(&fs, file.clone()); + let nodeid = fuse_lookup(&fs, file); // open/write/flush/close/open/read/close let fh = fuse_open(&fs, nodeid); @@ -1802,7 +1802,7 @@ fn regularfile_xattr_test() { // The first attr is "security.selinux" let (_attr1, next1) = read_cstring(attr_list.clone(), 0); // The next attrs are what we set by FUSE_SETXATTR. Check it. - let (attr2, _next2) = read_cstring(attr_list.clone(), next1); + let (attr2, _next2) = read_cstring(attr_list, next1); assert_eq!(attr2.unwrap(), testattr_name); // REMOVEXATTR diff --git a/tests/mod_test/tests/vnc_test.rs b/tests/mod_test/tests/vnc_test.rs index d8423030..61868f9e 100644 --- a/tests/mod_test/tests/vnc_test.rs +++ b/tests/mod_test/tests/vnc_test.rs @@ -785,7 +785,7 @@ fn test_set_encoding_abnormal(test_state: Rc>, port: u16) -> assert!(vnc_client.connect(TestAuthType::VncAuthNone).is_ok()); assert!(vnc_client.test_setup_encodings(Some(100), None).is_ok()); // Send a qmp to query vnc client state. - let value = qmp_query_vnc(test_state.clone()); + let value = qmp_query_vnc(test_state); let client_num = value["return"]["clients"].as_array().unwrap().len(); assert_eq!(client_num, 1); assert!(vnc_client.disconnect().is_ok()); @@ -805,7 +805,7 @@ fn test_client_cut_event(test_state: Rc>, port: u16) -> Resul }; assert!(vnc_client.test_send_client_cut(client_cut).is_ok()); // Send a qmp to query vnc client state. - let value = qmp_query_vnc(test_state.clone()); + let value = qmp_query_vnc(test_state); let client_num = value["return"]["clients"].as_array().unwrap().len(); assert_eq!(client_num, 1); assert!(vnc_client.disconnect().is_ok()); diff --git a/ui/src/console.rs b/ui/src/console.rs index 40c02c3f..f4461c8c 100644 --- a/ui/src/console.rs +++ b/ui/src/console.rs @@ -860,7 +860,7 @@ mod tests { assert!(console_close(&con_0).is_ok()); assert_eq!(CONSOLES.lock().unwrap().activate_id, Some(1)); let dev_name3 = "test_device3".to_string(); - let con_3 = console_init(dev_name3, ConsoleType::Graphic, con_opts.clone()); + let con_3 = console_init(dev_name3, ConsoleType::Graphic, con_opts); assert_eq!(con_3.unwrap().upgrade().unwrap().lock().unwrap().con_id, 3); assert!(console_select(Some(0)).is_ok()); assert_eq!(CONSOLES.lock().unwrap().activate_id, Some(0)); @@ -891,10 +891,7 @@ mod tests { None, dcl_opts.clone(), ))); - let dcl_3 = Arc::new(Mutex::new(DisplayChangeListener::new( - None, - dcl_opts.clone(), - ))); + let dcl_3 = Arc::new(Mutex::new(DisplayChangeListener::new(None, dcl_opts))); assert!(register_display(&dcl_0).is_ok()); assert_eq!(dcl_0.lock().unwrap().dcl_id, Some(0)); diff --git a/virtio/src/device/balloon.rs b/virtio/src/device/balloon.rs index aa19e88a..dbfa06b7 100644 --- a/virtio/src/device/balloon.rs +++ b/virtio/src/device/balloon.rs @@ -1456,7 +1456,7 @@ mod tests { driver_features: bln.base.driver_features, mem_space: mem_space.clone(), inf_queue: queue1, - inf_evt: event_inf.clone(), + inf_evt: event_inf, def_queue: queue2, def_evt: event_def, report_queue: None, diff --git a/virtio/src/queue/split.rs b/virtio/src/queue/split.rs index 7c9d512e..58f8250a 100644 --- a/virtio/src/queue/split.rs +++ b/virtio/src/queue/split.rs @@ -1956,12 +1956,9 @@ mod tests { // it is false when the index is more than the size of queue if let Err(err) = vring.add_used(&sys_space, QUEUE_SIZE, 100) { if let Some(e) = err.downcast_ref::() { - match e { - VirtioError::QueueIndex(offset, size) => { - assert_eq!(*offset, 256); - assert_eq!(*size, 256); - } - _ => (), + if let VirtioError::QueueIndex(offset, size) = e { + assert_eq!(*offset, 256); + assert_eq!(*size, 256); } } } diff --git a/virtio/src/transport/virtio_pci.rs b/virtio/src/transport/virtio_pci.rs index d656d283..1bfaa2c2 100644 --- a/virtio/src/transport/virtio_pci.rs +++ b/virtio/src/transport/virtio_pci.rs @@ -1526,21 +1526,21 @@ mod tests { .set_queue_select(VIRTIO_DEVICE_QUEUE_NUM as u16 - 1); let queue_select = virtio_dev.lock().unwrap().queue_select(); virtio_dev.lock().unwrap().virtio_base_mut().queues_config[queue_select as usize] - .desc_table = GuestAddress(0xAABBCCDD_FFEEDDAA); + .desc_table = GuestAddress(0xAABB_CCDD_FFEE_DDAA); com_cfg_read_test!(virtio_pci, COMMON_Q_DESCLO_REG, 0xFFEEDDAA_u32); com_cfg_read_test!(virtio_pci, COMMON_Q_DESCHI_REG, 0xAABBCCDD_u32); // Read Queue's Available Ring address virtio_dev.lock().unwrap().set_queue_select(0); virtio_dev.lock().unwrap().virtio_base_mut().queues_config[0].avail_ring = - GuestAddress(0x11223344_55667788); + GuestAddress(0x1122_3344_5566_7788); com_cfg_read_test!(virtio_pci, COMMON_Q_AVAILLO_REG, 0x55667788_u32); com_cfg_read_test!(virtio_pci, COMMON_Q_AVAILHI_REG, 0x11223344_u32); // Read Queue's Used Ring address virtio_dev.lock().unwrap().set_queue_select(0); virtio_dev.lock().unwrap().virtio_base_mut().queues_config[0].used_ring = - GuestAddress(0x55667788_99AABBCC); + GuestAddress(0x5566_7788_99AA_BBCC); com_cfg_read_test!(virtio_pci, COMMON_Q_USEDLO_REG, 0x99AABBCC_u32); com_cfg_read_test!(virtio_pci, COMMON_Q_USEDHI_REG, 0x55667788_u32); } -- Gitee From caadcd23b90f68d150721b1fbcb2a090d9041d5c Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Sat, 17 Aug 2024 18:44:12 +0800 Subject: [PATCH 267/489] machine: Specify type of numeric literal Signed-off-by: Keqian Zhu --- machine/src/aarch64/standard.rs | 4 ++-- machine/src/micro_common/mod.rs | 2 +- machine/src/standard_common/mod.rs | 20 ++++++++++---------- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index 69363507..a996a4a4 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -835,7 +835,7 @@ impl AcpiBuilder for StdMachine { dbg2.set_field(40, 1_u32); // Table 2. Debug Device Information structure format - let offset = 44; + let offset = 44_usize; // Revision dbg2.set_field(offset, 0_u8); // Length @@ -1147,7 +1147,7 @@ impl AcpiBuilder for StdMachine { loader: &mut TableLoader, ) -> Result { let mut pptt = AcpiTable::new(*b"PPTT", 2, *b"STRATO", *b"VIRTPPTT", 1); - let mut uid = 0; + let mut uid = 0_u32; self.build_pptt_sockets(&mut pptt, &mut uid); let pptt_begin = StdMachine::add_table_to_loader(acpi_data, loader, &pptt) .with_context(|| "Fail to add PPTT table to loader")?; diff --git a/machine/src/micro_common/mod.rs b/machine/src/micro_common/mod.rs index 34c12318..9684259b 100644 --- a/machine/src/micro_common/mod.rs +++ b/machine/src/micro_common/mod.rs @@ -764,7 +764,7 @@ impl DeviceInterface for LightMachine { fn device_add(&mut self, args: Box) -> Response { // get slot of bus by addr or lun - let mut slot = 0; + let mut slot = 0_usize; if let Some(addr) = args.addr.clone() { if let Ok(num) = str_to_num::(&addr) { slot = num; diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index f32bf7a1..357ed1aa 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -547,7 +547,7 @@ pub(crate) trait AcpiBuilder { { let mut mcfg = AcpiTable::new(*b"MCFG", 1, *b"STRATO", *b"VIRTMCFG", 1); // Bits 20~28 (totally 9 bits) in PCIE ECAM represents bus number. - let bus_number_mask = (1 << 9) - 1; + let bus_number_mask = (1u64 << 9) - 1; let ecam_addr: u64; let max_nr_bus: u64; #[cfg(target_arch = "x86_64")] @@ -610,31 +610,31 @@ pub(crate) trait AcpiBuilder { fadt.set_table_len(208_usize); // PM1A_EVENT bit, offset is 56. #[cfg(target_arch = "x86_64")] - fadt.set_field(56, 0x600); + fadt.set_field(56, 0x600_u32); // PM1A_CONTROL bit, offset is 64. #[cfg(target_arch = "x86_64")] - fadt.set_field(64, 0x604); + fadt.set_field(64, 0x604_u32); // PM_TMR_BLK bit, offset is 76. #[cfg(target_arch = "x86_64")] - fadt.set_field(76, 0x608); + fadt.set_field(76, 0x608_u32); // PM1_EVT_LEN, offset is 88. #[cfg(target_arch = "x86_64")] - fadt.set_field(88, 4); + fadt.set_field(88, 4_u8); // PM1_CNT_LEN, offset is 89. #[cfg(target_arch = "x86_64")] - fadt.set_field(89, 2); + fadt.set_field(89, 2_u8); // PM_TMR_LEN, offset is 91. #[cfg(target_arch = "x86_64")] - fadt.set_field(91, 4); + fadt.set_field(91, 4_u8); #[cfg(target_arch = "aarch64")] { // FADT flag: enable HW_REDUCED_ACPI bit on aarch64 plantform. - fadt.set_field(112, 1 << 20 | 1 << 10 | 1 << 8); + fadt.set_field(112, 1_u32 << 20 | 1_u32 << 10 | 1_u32 << 8); // ARM Boot Architecture Flags fadt.set_field(129, 0x3_u16); } // FADT minor revision - fadt.set_field(131, 3); + fadt.set_field(131, 3_u8); // X_PM_TMR_BLK bit, offset is 208. #[cfg(target_arch = "x86_64")] fadt.append_child(&AcpiGenericAddress::new_io_address(0x608_u32).aml_bytes()); @@ -644,7 +644,7 @@ pub(crate) trait AcpiBuilder { #[cfg(target_arch = "x86_64")] { // FADT flag: disable HW_REDUCED_ACPI bit on x86 plantform. - fadt.set_field(112, 1 << 10 | 1 << 8); + fadt.set_field(112, 1_u32 << 10 | 1_u32 << 8); // Reset Register bit, offset is 116. fadt.set_field(116, 0x01_u8); fadt.set_field(117, 0x08_u8); -- Gitee From 7620188352f8560a2e539585314cd35f779aed47 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Mon, 19 Aug 2024 13:09:33 +0800 Subject: [PATCH 268/489] machine: Verify arithmetic side effects Signed-off-by: Keqian Zhu --- cpu/src/lib.rs | 16 +++--- cpu/src/x86_64/mod.rs | 36 ++++++++------ machine/src/aarch64/micro.rs | 6 ++- machine/src/aarch64/standard.rs | 6 ++- machine/src/lib.rs | 6 ++- machine/src/micro_common/mod.rs | 12 ++--- machine/src/standard_common/mod.rs | 15 +++++- machine/src/x86_64/micro.rs | 2 + machine/src/x86_64/standard.rs | 15 +++++- machine_manager/src/config/machine_config.rs | 51 ++++++++++++-------- 10 files changed, 107 insertions(+), 58 deletions(-) diff --git a/cpu/src/lib.rs b/cpu/src/lib.rs index b141334e..5b70ef75 100644 --- a/cpu/src/lib.rs +++ b/cpu/src/lib.rs @@ -601,16 +601,18 @@ impl CpuTopology { /// # Arguments /// /// * `vcpu_id` - ID of vcpu. - fn get_topo_item(&self, vcpu_id: usize) -> (u8, u8, u8, u8, u8) { - let socketid: u8 = vcpu_id as u8 / (self.dies * self.clusters * self.cores * self.threads); - let dieid: u8 = (vcpu_id as u8 / (self.clusters * self.cores * self.threads)) % self.dies; - let clusterid: u8 = (vcpu_id as u8 / (self.cores * self.threads)) % self.clusters; - let coreid: u8 = (vcpu_id as u8 / self.threads) % self.cores; - let threadid: u8 = vcpu_id as u8 % self.threads; + fn get_topo_item(&self, vcpu_id: u8) -> (u8, u8, u8, u8, u8) { + // nr_cpus is no more than u8::MAX, multiply will not overflow. + // nr_xxx is no less than 1, div and mod operations will not panic. + let socketid: u8 = vcpu_id / (self.dies * self.clusters * self.cores * self.threads); + let dieid: u8 = (vcpu_id / (self.clusters * self.cores * self.threads)) % self.dies; + let clusterid: u8 = (vcpu_id / (self.cores * self.threads)) % self.clusters; + let coreid: u8 = (vcpu_id / self.threads) % self.cores; + let threadid: u8 = vcpu_id % self.threads; (socketid, dieid, clusterid, coreid, threadid) } - pub fn get_topo_instance_for_qmp(&self, cpu_index: usize) -> qmp_schema::CpuInstanceProperties { + pub fn get_topo_instance_for_qmp(&self, cpu_index: u8) -> qmp_schema::CpuInstanceProperties { let (socketid, _dieid, _clusterid, coreid, threadid) = self.get_topo_item(cpu_index); qmp_schema::CpuInstanceProperties { node_id: None, diff --git a/cpu/src/x86_64/mod.rs b/cpu/src/x86_64/mod.rs index 9bf91313..7b077378 100644 --- a/cpu/src/x86_64/mod.rs +++ b/cpu/src/x86_64/mod.rs @@ -123,11 +123,11 @@ impl X86CPUTopology { #[derive(Desc, ByteCode)] #[desc_version(compat_version = "0.1.0")] pub struct X86CPUState { - max_vcpus: u32, - nr_threads: u32, - nr_cores: u32, - nr_dies: u32, - nr_sockets: u32, + max_vcpus: u8, + nr_threads: u8, + nr_cores: u8, + nr_dies: u8, + nr_sockets: u8, pub apic_id: u32, pub regs: Regs, pub sregs: Sregs, @@ -177,7 +177,7 @@ impl X86CPUState { /// /// * `vcpu_id` - ID of this `CPU`. /// * `max_vcpus` - Number of vcpus. - pub fn new(vcpu_id: u32, max_vcpus: u32) -> Self { + pub fn new(vcpu_id: u32, max_vcpus: u8) -> Self { let mp_state = MpState { mp_state: if vcpu_id == 0 { MP_STATE_RUNNABLE @@ -221,9 +221,9 @@ impl X86CPUState { /// /// * `topology` - X86 CPU Topology pub fn set_cpu_topology(&mut self, topology: &X86CPUTopology) -> Result<()> { - self.nr_threads = u32::from(topology.threads); - self.nr_cores = u32::from(topology.cores); - self.nr_dies = u32::from(topology.dies); + self.nr_threads = topology.threads; + self.nr_cores = topology.cores; + self.nr_dies = topology.dies; Ok(()) } @@ -359,6 +359,7 @@ impl X86CPUState { data, ..Default::default() }; + // usize is enough for storing msr len. self.msr_len += 1; } } @@ -392,6 +393,7 @@ impl X86CPUState { } pub fn setup_cpuid(&self, cpuid: &mut CpuId) -> Result<()> { + // nr_xx is no less than 1. let core_offset = 32u32 - (self.nr_threads - 1).leading_zeros(); let die_offset = (32u32 - (self.nr_cores - 1).leading_zeros()) + core_offset; let pkg_offset = (32u32 - (self.nr_dies - 1).leading_zeros()) + die_offset; @@ -430,7 +432,8 @@ impl X86CPUState { ); entry.eax &= !0xfc00_0000; if entry.eax & 0x0001_ffff != 0 && self.max_vcpus > 1 { - entry.eax |= (self.max_vcpus - 1) << 26; + // max_vcpus is no less than 1. + entry.eax |= (u32::from(self.max_vcpus) - 1) << 26; } } 6 => { @@ -452,12 +455,13 @@ impl X86CPUState { match entry.index { 0 => { entry.eax = core_offset; - entry.ebx = self.nr_threads; + entry.ebx = u32::from(self.nr_threads); entry.ecx |= ECX_THREAD; } 1 => { entry.eax = pkg_offset; - entry.ebx = self.nr_threads * self.nr_cores; + // nr_cpus is no more than u8::MAX, multiply will not overflow. + entry.ebx = u32::from(self.nr_threads * self.nr_cores); entry.ecx |= ECX_CORE; } _ => { @@ -483,17 +487,19 @@ impl X86CPUState { match entry.index { 0 => { entry.eax = core_offset; - entry.ebx = self.nr_threads; + entry.ebx = u32::from(self.nr_threads); entry.ecx |= ECX_THREAD; } 1 => { entry.eax = die_offset; - entry.ebx = self.nr_cores * self.nr_threads; + // nr_cpus is no more than u8::MAX, multiply will not overflow. + entry.ebx = u32::from(self.nr_cores * self.nr_threads); entry.ecx |= ECX_CORE; } 2 => { entry.eax = pkg_offset; - entry.ebx = self.nr_dies * self.nr_cores * self.nr_threads; + // nr_cpus is no more than u8::MAX, multiply will not overflow. + entry.ebx = u32::from(self.nr_dies * self.nr_cores * self.nr_threads); entry.ecx |= ECX_DIE; } _ => { diff --git a/machine/src/aarch64/micro.rs b/machine/src/aarch64/micro.rs index 6afc15e2..6fd87d76 100644 --- a/machine/src/aarch64/micro.rs +++ b/machine/src/aarch64/micro.rs @@ -279,7 +279,11 @@ impl CompileFDTHelper for LightMachine { match &boot_source.initrd { Some(initrd) => { fdt.set_property_u64("linux,initrd-start", initrd.initrd_addr)?; - fdt.set_property_u64("linux,initrd-end", initrd.initrd_addr + initrd.initrd_size)?; + let initrd_end = initrd + .initrd_addr + .checked_add(initrd.initrd_size) + .with_context(|| "initrd end overflow")?; + fdt.set_property_u64("linux,initrd-end", initrd_end)?; } None => {} } diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index a996a4a4..9feab83a 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -1290,7 +1290,11 @@ impl CompileFDTHelper for StdMachine { match &boot_source.initrd { Some(initrd) => { fdt.set_property_u64("linux,initrd-start", initrd.initrd_addr)?; - fdt.set_property_u64("linux,initrd-end", initrd.initrd_addr + initrd.initrd_size)?; + let initrd_end = initrd + .initrd_addr + .checked_add(initrd.initrd_size) + .with_context(|| "initrd end overflow")?; + fdt.set_property_u64("linux,initrd-end", initrd_end)?; } None => {} } diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 73ada4da..39fb7ef2 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -411,7 +411,9 @@ pub trait MachineOps: MachineLifecycle { if zone.id.eq(&node.1.mem_dev) { let ram = create_backend_mem(zone, thread_num)?; root.add_subregion_not_update(ram, offset)?; - offset += zone.size; + offset = offset + .checked_add(zone.size) + .with_context(|| "total zone size overflow")?; break; } } @@ -477,7 +479,7 @@ pub trait MachineOps: MachineLifecycle { #[cfg(target_arch = "aarch64")] let arch_cpu = ArchCPU::new(u32::from(vcpu_id)); #[cfg(target_arch = "x86_64")] - let arch_cpu = ArchCPU::new(u32::from(vcpu_id), u32::from(max_cpus)); + let arch_cpu = ArchCPU::new(u32::from(vcpu_id), max_cpus); let cpu = Arc::new(CPU::new( hypervisor_cpu, diff --git a/machine/src/micro_common/mod.rs b/machine/src/micro_common/mod.rs index 9684259b..3ed04c09 100644 --- a/machine/src/micro_common/mod.rs +++ b/machine/src/micro_common/mod.rs @@ -642,7 +642,7 @@ impl DeviceInterface for LightMachine { for cpu_index in 0..cpu_topo.max_cpus { if cpu_topo.get_mask(cpu_index as usize) == 1 { let thread_id = cpus[cpu_index as usize].tid(); - let cpu_instance = cpu_topo.get_topo_instance_for_qmp(cpu_index as usize); + let cpu_instance = cpu_topo.get_topo_instance_for_qmp(cpu_index); let cpu_common = qmp_schema::CpuInfoCommon { current: true, qom_path: String::from("/machine/unattached/device[") @@ -683,10 +683,7 @@ impl DeviceInterface for LightMachine { for cpu_index in 0..self.base.cpu_topo.max_cpus { if self.base.cpu_topo.get_mask(cpu_index as usize) == 0 { - let cpu_instance = self - .base - .cpu_topo - .get_topo_instance_for_qmp(cpu_index as usize); + let cpu_instance = self.base.cpu_topo.get_topo_instance_for_qmp(cpu_index); let hotpluggable_cpu = qmp_schema::HotpluggableCPU { type_: cpu_type.clone(), vcpus_count: 1, @@ -695,10 +692,7 @@ impl DeviceInterface for LightMachine { }; hotplug_vec.push(serde_json::to_value(hotpluggable_cpu).unwrap()); } else { - let cpu_instance = self - .base - .cpu_topo - .get_topo_instance_for_qmp(cpu_index as usize); + let cpu_instance = self.base.cpu_topo.get_topo_instance_for_qmp(cpu_index); let hotpluggable_cpu = qmp_schema::HotpluggableCPU { type_: cpu_type.clone(), vcpus_count: 1, diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index 357ed1aa..0bfd6466 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -409,6 +409,7 @@ pub(crate) trait AcpiBuilder { loader.add_cksum_entry( ACPI_TABLE_FILE, + // table_begin is much less than u32::MAX, will not overflow. table_begin + TABLE_CHECKSUM_OFFSET, table_begin, table_end - table_begin, @@ -568,7 +569,7 @@ pub(crate) trait AcpiBuilder { mcfg.append_child(ecam_addr.as_bytes()); // PCI Segment Group Number mcfg.append_child(0_u16.as_bytes()); - // Start Bus Number and End Bus Number + // Start Bus Number and End Bus Number. max_nr_bus is no less than 1. mcfg.append_child(&[0_u8, (max_nr_bus - 1) as u8]); // Reserved mcfg.append_child(&[0_u8; 4]); @@ -581,6 +582,7 @@ pub(crate) trait AcpiBuilder { loader.add_cksum_entry( ACPI_TABLE_FILE, + // mcfg_begin is much less than u32::MAX, will not overflow. mcfg_begin + TABLE_CHECKSUM_OFFSET, mcfg_begin, mcfg_end - mcfg_begin, @@ -680,6 +682,7 @@ pub(crate) trait AcpiBuilder { let facs_size = 4_u8; loader.add_pointer_entry( ACPI_TABLE_FILE, + // fadt_begin is much less than u32::MAX, will not overflow. fadt_begin + facs_offset, facs_size, ACPI_TABLE_FILE, @@ -692,6 +695,7 @@ pub(crate) trait AcpiBuilder { let xdsdt_size = 8_u8; loader.add_pointer_entry( ACPI_TABLE_FILE, + // fadt_begin is much less than u32::MAX, will not overflow. fadt_begin + xdsdt_offset, xdsdt_size, ACPI_TABLE_FILE, @@ -700,6 +704,7 @@ pub(crate) trait AcpiBuilder { loader.add_cksum_entry( ACPI_TABLE_FILE, + // fadt_begin is much less than u32::MAX, will not overflow. fadt_begin + TABLE_CHECKSUM_OFFSET, fadt_begin, fadt_end - fadt_begin, @@ -833,6 +838,7 @@ pub(crate) trait AcpiBuilder { { let mut xsdt = AcpiTable::new(*b"XSDT", 1, *b"STRATO", *b"VIRTXSDT", 1); + // usize is enough for storing table len. xsdt.set_table_len(xsdt.table_len() + size_of::() * xsdt_entries.len()); let mut locked_acpi_data = acpi_data.lock().unwrap(); @@ -848,16 +854,19 @@ pub(crate) trait AcpiBuilder { for entry in xsdt_entries { loader.add_pointer_entry( ACPI_TABLE_FILE, + // xsdt_begin is much less than u32::MAX, will not overflow. xsdt_begin + entry_offset, entry_size, ACPI_TABLE_FILE, entry as u32, )?; + // u32 is enough for storing offset. entry_offset += u32::from(entry_size); } loader.add_cksum_entry( ACPI_TABLE_FILE, + // xsdt_begin is much less than u32::MAX, will not overflow. xsdt_begin + TABLE_CHECKSUM_OFFSET, xsdt_begin, xsdt_end - xsdt_begin, @@ -931,6 +940,7 @@ impl StdMachine { bail!("Cpu-id {} already exist.", cpu_id) } if cpu_id >= max_cpus { + // max_cpus is no less than 1. bail!("Max cpu-id is {}", max_cpus - 1) } @@ -1100,7 +1110,7 @@ impl DeviceInterface for StdMachine { for cpu_index in 0..cpu_topo.max_cpus { if cpu_topo.get_mask(cpu_index as usize) == 1 { let thread_id = cpus[cpu_index as usize].tid(); - let cpu_instance = cpu_topo.get_topo_instance_for_qmp(cpu_index as usize); + let cpu_instance = cpu_topo.get_topo_instance_for_qmp(cpu_index); let cpu_common = qmp_schema::CpuInfoCommon { current: true, qom_path: String::from("/machine/unattached/device[") @@ -1616,6 +1626,7 @@ impl DeviceInterface for StdMachine { } for (i, data) in data.iter_mut().enumerate().take(std::mem::size_of::()) { + // i is less than 8, multiply will not overflow. *data = (self.head >> (8 * i)) as u8; } true diff --git a/machine/src/x86_64/micro.rs b/machine/src/x86_64/micro.rs index 5747076a..80c3c1b9 100644 --- a/machine/src/x86_64/micro.rs +++ b/machine/src/x86_64/micro.rs @@ -95,6 +95,7 @@ impl MachineOps for LightMachine { let boot_source = self.base.boot_source.lock().unwrap(); let initrd = boot_source.initrd.as_ref().map(|b| b.initrd_file.clone()); + // MEM_LAYOUT is defined statically, will not overflow. let gap_start = MEM_LAYOUT[LayoutEntryType::MemBelow4g as usize].0 + MEM_LAYOUT[LayoutEntryType::MemBelow4g as usize].1; let gap_end = MEM_LAYOUT[LayoutEntryType::MemAbove4g as usize].0; @@ -103,6 +104,7 @@ impl MachineOps for LightMachine { initrd, kernel_cmdline: boot_source.kernel_cmdline.to_string(), cpu_count: self.base.cpu_topo.nrcpus, + // gap_end is bigger than gap_start, as MEM_LAYOUT is defined statically. gap_range: (gap_start, gap_end - gap_start), ioapic_addr: MEM_LAYOUT[LayoutEntryType::IoApic as usize].0 as u32, lapic_addr: MEM_LAYOUT[LayoutEntryType::LocalApic as usize].0 as u32, diff --git a/machine/src/x86_64/standard.rs b/machine/src/x86_64/standard.rs index da509da7..61007855 100644 --- a/machine/src/x86_64/standard.rs +++ b/machine/src/x86_64/standard.rs @@ -411,6 +411,7 @@ impl MachineOps for StdMachine { let boot_source = self.base.boot_source.lock().unwrap(); let initrd = boot_source.initrd.as_ref().map(|b| b.initrd_file.clone()); + // MEM_LAYOUT is defined statically, will not overflow. let gap_start = MEM_LAYOUT[LayoutEntryType::MemBelow4g as usize].0 + MEM_LAYOUT[LayoutEntryType::MemBelow4g as usize].1; let gap_end = MEM_LAYOUT[LayoutEntryType::MemAbove4g as usize].0; @@ -419,6 +420,7 @@ impl MachineOps for StdMachine { initrd, kernel_cmdline: boot_source.kernel_cmdline.to_string(), cpu_count: self.base.cpu_topo.nrcpus, + // gap_end is bigger than gap_start, as MEM_LAYOUT is defined statically. gap_range: (gap_start, gap_end - gap_start), ioapic_addr: MEM_LAYOUT[LayoutEntryType::IoApic as usize].0 as u32, lapic_addr: MEM_LAYOUT[LayoutEntryType::LocalApic as usize].0 as u32, @@ -441,6 +443,7 @@ impl MachineOps for StdMachine { let mut rtc = RTC::new(&self.base.sysbus).with_context(|| "Failed to create RTC device")?; rtc.set_memory( mem_size, + // MEM_LAYOUT is defined statically, will not overflow. MEM_LAYOUT[LayoutEntryType::MemBelow4g as usize].0 + MEM_LAYOUT[LayoutEntryType::MemBelow4g as usize].1, ); @@ -590,7 +593,10 @@ impl MachineOps for StdMachine { // KiB is for BIOS code which is stored in the first PFlash. let rom_base = 0xe0000; let rom_size = 0x20000; - file.as_ref().seek(SeekFrom::Start(pfl_size - rom_size))?; + let seek_start = pfl_size + .checked_sub(rom_size) + .with_context(|| "pflash file size less than rom size")?; + file.as_ref().seek(SeekFrom::Start(seek_start))?; let ram1 = Arc::new(HostMemMapping::new( GuestAddress(rom_base), @@ -614,6 +620,9 @@ impl MachineOps for StdMachine { let sector_len: u32 = 1024 * 4; let backend = Some(file); + let region_base = flash_end + .checked_sub(pfl_size) + .with_context(|| "flash end is less than flash size")?; let pflash = PFlash::new( pfl_size, backend, @@ -622,12 +631,13 @@ impl MachineOps for StdMachine { 1_u32, config.readonly, &self.base.sysbus, - flash_end - pfl_size, + region_base, ) .with_context(|| MachineError::InitPflashErr)?; pflash .realize() .with_context(|| MachineError::RlzPflashErr)?; + // sub has been checked above. flash_end -= pfl_size; } @@ -822,6 +832,7 @@ impl AcpiBuilder for StdMachine { node: &NumaNode, srat: &mut AcpiTable, ) -> u64 { + // MEM_LAYOUT is defined statically, will not overflow. let mem_below_4g = MEM_LAYOUT[LayoutEntryType::MemBelow4g as usize].0 + MEM_LAYOUT[LayoutEntryType::MemBelow4g as usize].1; let mem_above_4g = MEM_LAYOUT[LayoutEntryType::MemAbove4g as usize].0; diff --git a/machine_manager/src/config/machine_config.rs b/machine_manager/src/config/machine_config.rs index 6163f111..96ce5a11 100644 --- a/machine_manager/src/config/machine_config.rs +++ b/machine_manager/src/config/machine_config.rs @@ -31,8 +31,8 @@ const DEFAULT_CLUSTERS: u8 = 1; const DEFAULT_SOCKETS: u8 = 1; const DEFAULT_MAX_CPUS: u8 = 1; const DEFAULT_MEMSIZE: u64 = 256; -const MAX_NR_CPUS: u64 = 254; -const MIN_NR_CPUS: u64 = 1; +const MAX_NR_CPUS: u8 = 254; +const MIN_NR_CPUS: u8 = 1; const MAX_MEMSIZE: u64 = 549_755_813_888; const MIN_MEMSIZE: u64 = 134_217_728; pub const K: u64 = 1024; @@ -291,20 +291,20 @@ struct MachineCmdConfig { #[derive(Parser)] #[command(no_binary_name(true))] struct SmpConfig { - #[arg(long, alias = "classtype", value_parser = clap::value_parser!(u64).range(MIN_NR_CPUS..=MAX_NR_CPUS))] - cpus: u64, + #[arg(long, alias = "classtype", value_parser = clap::value_parser!(u8).range(i64::from(MIN_NR_CPUS)..=i64::from(MAX_NR_CPUS)))] + cpus: u8, #[arg(long, default_value = "0")] - maxcpus: u64, - #[arg(long, default_value = "0", value_parser = clap::value_parser!(u64).range(..u8::MAX as u64))] - sockets: u64, - #[arg(long, default_value = "1", value_parser = clap::value_parser!(u64).range(1..u8::MAX as u64))] - dies: u64, - #[arg(long, default_value = "1", value_parser = clap::value_parser!(u64).range(1..u8::MAX as u64))] - clusters: u64, - #[arg(long, default_value = "0", value_parser = clap::value_parser!(u64).range(..u8::MAX as u64))] - cores: u64, - #[arg(long, default_value = "0", value_parser = clap::value_parser!(u64).range(..u8::MAX as u64))] - threads: u64, + maxcpus: u8, + #[arg(long, default_value = "0", value_parser = clap::value_parser!(u8).range(..i64::from(u8::MAX)))] + sockets: u8, + #[arg(long, default_value = "1", value_parser = clap::value_parser!(u8).range(1..i64::from(u8::MAX)))] + dies: u8, + #[arg(long, default_value = "1", value_parser = clap::value_parser!(u8).range(1..i64::from(u8::MAX)))] + clusters: u8, + #[arg(long, default_value = "0", value_parser = clap::value_parser!(u8).range(..i64::from(u8::MAX)))] + cores: u8, + #[arg(long, default_value = "0", value_parser = clap::value_parser!(u8).range(..i64::from(u8::MAX)))] + threads: u8, } impl SmpConfig { @@ -315,8 +315,21 @@ impl SmpConfig { let mut threads = self.threads; if max_cpus == 0 { - if sockets * self.dies * self.clusters * cores * threads > 0 { - max_cpus = sockets * self.dies * self.clusters * cores * threads; + let mut tmp_max = sockets + .checked_mul(self.dies) + .with_context(|| "Illegal smp config")?; + tmp_max = tmp_max + .checked_mul(self.clusters) + .with_context(|| "Illegal smp config")?; + tmp_max = tmp_max + .checked_mul(cores) + .with_context(|| "Illegal smp config")?; + tmp_max = tmp_max + .checked_mul(threads) + .with_context(|| "Illegal smp config")?; + + if tmp_max > 0 { + max_cpus = tmp_max; } else { max_cpus = self.cpus; } @@ -346,9 +359,9 @@ impl SmpConfig { if !(min_max_cpus..=MAX_NR_CPUS).contains(&max_cpus) { return Err(anyhow!(ConfigError::IllegalValue( "MAX CPU number".to_string(), - min_max_cpus, + u64::from(min_max_cpus), true, - MAX_NR_CPUS, + u64::from(MAX_NR_CPUS), true, ))); } -- Gitee From 2840179045d09b4b43805024ca36a17d9eec6a8c Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Mon, 19 Aug 2024 16:06:15 +0800 Subject: [PATCH 269/489] cpu: Fix cast_ptr_alignment warning Cast *u8 to *u32 may causing unaligned memory access. Signed-off-by: Keqian Zhu --- cpu/src/lib.rs | 1 + cpu/src/x86_64/mod.rs | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cpu/src/lib.rs b/cpu/src/lib.rs index 5b70ef75..704ef604 100644 --- a/cpu/src/lib.rs +++ b/cpu/src/lib.rs @@ -285,6 +285,7 @@ impl CPU { /// Set thread id for `CPU`. pub fn set_tid(&self, tid: Option) { if tid.is_none() { + // Cast is safe as tid is not negative. *self.tid.lock().unwrap() = Some(gettid().as_raw() as u64); } else { *self.tid.lock().unwrap() = tid; diff --git a/cpu/src/x86_64/mod.rs b/cpu/src/x86_64/mod.rs index 7b077378..c64ab8e8 100644 --- a/cpu/src/x86_64/mod.rs +++ b/cpu/src/x86_64/mod.rs @@ -239,19 +239,19 @@ impl X86CPUState { self.lapic = lapic; // SAFETY: The member regs in struct LapicState is a u8 array with 1024 entries, - // so it's saft to cast u8 pointer to u32 at position APIC_LVT0 and APIC_LVT1. + // so it's safe to cast u8 pointer to u32 at position APIC_LVT0 and APIC_LVT1. // Safe because all value in this unsafe block is certain. unsafe { let apic_lvt_lint0 = &mut self.lapic.regs[APIC_LVT0..] as *mut [i8] as *mut u32; - *apic_lvt_lint0 &= !0x700; - *apic_lvt_lint0 |= APIC_MODE_EXTINT << 8; + let modified = (apic_lvt_lint0.read_unaligned() & !0x700) | (APIC_MODE_EXTINT << 8); + apic_lvt_lint0.write_unaligned(modified); let apic_lvt_lint1 = &mut self.lapic.regs[APIC_LVT1..] as *mut [i8] as *mut u32; - *apic_lvt_lint1 &= !0x700; - *apic_lvt_lint1 |= APIC_MODE_NMI << 8; + let modified = (apic_lvt_lint1.read_unaligned() & !0x700) | (APIC_MODE_NMI << 8); + apic_lvt_lint1.write_unaligned(modified); let apic_id = &mut self.lapic.regs[APIC_ID..] as *mut [i8] as *mut u32; - *apic_id = self.apic_id << 24; + apic_id.write_unaligned(self.apic_id << 24); } Ok(()) -- Gitee From 049b337e45b88e6c4109629b285e6b88be3d3642 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Mon, 19 Aug 2024 17:15:56 +0800 Subject: [PATCH 270/489] machine: Fix cast_possible_truncation warnings Signed-off-by: Keqian Zhu --- machine/src/lib.rs | 2 +- machine/src/standard_common/mod.rs | 16 +++++++++++----- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 39fb7ef2..e71300dd 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -1564,7 +1564,7 @@ pub trait MachineOps: MachineLifecycle { } drop(locked_bus); // It's safe to call devfn.unwrap(), because the bus exists. - match locked_pci_host.find_device(0, devfn.unwrap() as u8) { + match locked_pci_host.find_device(0, u8::try_from(devfn.unwrap())?) { Some(dev) => dev .lock() .unwrap() diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index 0bfd6466..4f95bb37 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -570,7 +570,7 @@ pub(crate) trait AcpiBuilder { // PCI Segment Group Number mcfg.append_child(0_u16.as_bytes()); // Start Bus Number and End Bus Number. max_nr_bus is no less than 1. - mcfg.append_child(&[0_u8, (max_nr_bus - 1) as u8]); + mcfg.append_child(&[0_u8, u8::try_from(max_nr_bus - 1)?]); // Reserved mcfg.append_child(&[0_u8; 4]); @@ -686,7 +686,7 @@ pub(crate) trait AcpiBuilder { fadt_begin + facs_offset, facs_size, ACPI_TABLE_FILE, - facs_addr as u32, + u32::try_from(facs_addr)?, )?; // xDSDT address field's offset in FADT. @@ -699,7 +699,7 @@ pub(crate) trait AcpiBuilder { fadt_begin + xdsdt_offset, xdsdt_size, ACPI_TABLE_FILE, - dsdt_addr as u32, + u32::try_from(dsdt_addr)?, )?; loader.add_cksum_entry( @@ -858,7 +858,7 @@ pub(crate) trait AcpiBuilder { xsdt_begin + entry_offset, entry_size, ACPI_TABLE_FILE, - entry as u32, + u32::try_from(entry)?, )?; // u32 is enough for storing offset. entry_offset += u32::from(entry_size); @@ -898,7 +898,7 @@ pub(crate) trait AcpiBuilder { xsdt_offset, xsdt_size, ACPI_TABLE_FILE, - xsdt_addr as u32, + u32::try_from(xsdt_addr)?, )?; let cksum_offset = 8_u32; @@ -1745,6 +1745,12 @@ impl DeviceInterface for StdMachine { } }; + if i32::try_from(args.priority).is_err() { + return Response::create_error_response( + qmp_schema::QmpErrorClass::GenericError("priority illegal".to_string()), + None, + ); + } region.set_priority(args.priority as i32); if let Some(read_only) = args.romd { if region.set_rom_device_romd(read_only).is_err() { -- Gitee From b70304a3ee29da8aad4ee5dc8cfaa545973ad451 Mon Sep 17 00:00:00 2001 From: Jinhao Gao Date: Mon, 19 Aug 2024 15:09:42 +0800 Subject: [PATCH 271/489] Hypervisor: Add numeric literal type Add numeric literal type. Signed-off-by: Jinhao Gao --- hypervisor/src/kvm/aarch64/gicv3.rs | 2 +- hypervisor/src/kvm/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/hypervisor/src/kvm/aarch64/gicv3.rs b/hypervisor/src/kvm/aarch64/gicv3.rs index 5f8c9ede..0ced57c6 100644 --- a/hypervisor/src/kvm/aarch64/gicv3.rs +++ b/hypervisor/src/kvm/aarch64/gicv3.rs @@ -118,7 +118,7 @@ impl GICv3Access for KvmGICv3 { } fn vcpu_gicr_attr(&self, cpu: usize) -> u64 { - let clustersz = 16; + let clustersz = 16usize; let aff1 = (cpu / clustersz) as u64; let aff0 = (cpu % clustersz) as u64; diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs index 209442ba..3cec118e 100644 --- a/hypervisor/src/kvm/mod.rs +++ b/hypervisor/src/kvm/mod.rs @@ -665,7 +665,7 @@ impl CPUHypervisorOps for KvmCpu { } // It shall wait for the vCPU pause state from hypervisor exits. - let mut sleep_times = 0; + let mut sleep_times = 0u32; while !pause_signal.load(Ordering::SeqCst) { if sleep_times >= 5 { bail!(CpuError::StopVcpu("timeout".to_string())); -- Gitee From 71b12a39937eae2729e4613f6bc9fb6b4fe27e17 Mon Sep 17 00:00:00 2001 From: Jinhao Gao Date: Tue, 20 Aug 2024 11:31:59 +0800 Subject: [PATCH 272/489] Hypervisor: Fix cast_possible_truncation warnings Signed-off-by: Jinhao Gao --- hypervisor/src/kvm/aarch64/gicv3.rs | 1 + hypervisor/src/kvm/aarch64/mod.rs | 48 +++++++++++++++-------------- hypervisor/src/kvm/interrupt.rs | 7 +++-- hypervisor/src/kvm/listener.rs | 10 +++--- hypervisor/src/kvm/mod.rs | 3 +- 5 files changed, 37 insertions(+), 32 deletions(-) diff --git a/hypervisor/src/kvm/aarch64/gicv3.rs b/hypervisor/src/kvm/aarch64/gicv3.rs index 0ced57c6..23d86c0d 100644 --- a/hypervisor/src/kvm/aarch64/gicv3.rs +++ b/hypervisor/src/kvm/aarch64/gicv3.rs @@ -128,6 +128,7 @@ impl GICv3Access for KvmGICv3 { let last = u64::from((self.vcpu_count - 1) == cpu as u64); + // Allow conversion of variables from i64 to u64. ((cpu_affid << 32) | (1 << 24) | (1 << 8) | (last << 4)) & kvm_bindings::KVM_DEV_ARM_VGIC_V3_MPIDR_MASK as u64 } diff --git a/hypervisor/src/kvm/aarch64/mod.rs b/hypervisor/src/kvm/aarch64/mod.rs index 3e6c8461..7e42f61a 100644 --- a/hypervisor/src/kvm/aarch64/mod.rs +++ b/hypervisor/src/kvm/aarch64/mod.rs @@ -175,12 +175,13 @@ impl KvmCpu { if vcpu_config.sve { self.fd - .vcpu_finalize(&(kvm_bindings::KVM_ARM_VCPU_SVE as i32))?; + .vcpu_finalize(&(i32::try_from(kvm_bindings::KVM_ARM_VCPU_SVE)?))?; } - arch_cpu.lock().unwrap().mpidr = + arch_cpu.lock().unwrap().mpidr = u64::try_from( self.get_one_reg(KVM_REG_ARM_MPIDR_EL1) - .with_context(|| "Failed to get mpidr")? as u64; + .with_context(|| "Failed to get mpidr")?, + )?; arch_cpu.lock().unwrap().features = *vcpu_config; @@ -255,10 +256,10 @@ impl KvmCpu { ); } RegsIndex::VtimerCount => { - locked_arch_cpu.vtimer_cnt = self - .get_one_reg(KVM_REG_ARM_TIMER_CNT) - .with_context(|| "Failed to get virtual timer count")? - as u64; + locked_arch_cpu.vtimer_cnt = u64::try_from( + self.get_one_reg(KVM_REG_ARM_TIMER_CNT) + .with_context(|| "Failed to get virtual timer count")?, + )?; locked_arch_cpu.vtimer_cnt_valid = true; } } @@ -325,33 +326,34 @@ impl KvmCpu { fn get_core_regs(&self) -> Result { let mut core_regs = kvm_regs::default(); - core_regs.regs.sp = self.get_one_reg(Arm64CoreRegs::UserPTRegSp.into())? as u64; - core_regs.sp_el1 = self.get_one_reg(Arm64CoreRegs::KvmSpEl1.into())? as u64; - core_regs.regs.pstate = self.get_one_reg(Arm64CoreRegs::UserPTRegPState.into())? as u64; - core_regs.regs.pc = self.get_one_reg(Arm64CoreRegs::UserPTRegPc.into())? as u64; - core_regs.elr_el1 = self.get_one_reg(Arm64CoreRegs::KvmElrEl1.into())? as u64; + core_regs.regs.sp = u64::try_from(self.get_one_reg(Arm64CoreRegs::UserPTRegSp.into())?)?; + core_regs.sp_el1 = u64::try_from(self.get_one_reg(Arm64CoreRegs::KvmSpEl1.into())?)?; + core_regs.regs.pstate = + u64::try_from(self.get_one_reg(Arm64CoreRegs::UserPTRegPState.into())?)?; + core_regs.regs.pc = u64::try_from(self.get_one_reg(Arm64CoreRegs::UserPTRegPc.into())?)?; + core_regs.elr_el1 = u64::try_from(self.get_one_reg(Arm64CoreRegs::KvmElrEl1.into())?)?; - for i in 0..KVM_NR_REGS as usize { + for i in 0..usize::try_from(KVM_NR_REGS)? { core_regs.regs.regs[i] = - self.get_one_reg(Arm64CoreRegs::UserPTRegRegs(i).into())? as u64; + u64::try_from(self.get_one_reg(Arm64CoreRegs::UserPTRegRegs(i).into())?)?; } - for i in 0..KVM_NR_SPSR as usize { - core_regs.spsr[i] = self.get_one_reg(Arm64CoreRegs::KvmSpsr(i).into())? as u64; + for i in 0..usize::try_from(KVM_NR_SPSR)? { + core_regs.spsr[i] = u64::try_from(self.get_one_reg(Arm64CoreRegs::KvmSpsr(i).into())?)?; } // State save and restore is not supported for SVE for now, so we just skip it. if self.kvi.lock().unwrap().features[0] & (1 << kvm_bindings::KVM_ARM_VCPU_SVE) == 0 { - for i in 0..KVM_NR_FP_REGS as usize { + for i in 0..usize::try_from(KVM_NR_FP_REGS)? { core_regs.fp_regs.vregs[i] = self.get_one_reg(Arm64CoreRegs::UserFPSIMDStateVregs(i).into())?; } } core_regs.fp_regs.fpsr = - self.get_one_reg(Arm64CoreRegs::UserFPSIMDStateFpsr.into())? as u32; + u32::try_from(self.get_one_reg(Arm64CoreRegs::UserFPSIMDStateFpsr.into())?)?; core_regs.fp_regs.fpcr = - self.get_one_reg(Arm64CoreRegs::UserFPSIMDStateFpcr.into())? as u32; + u32::try_from(self.get_one_reg(Arm64CoreRegs::UserFPSIMDStateFpcr.into())?)?; Ok(core_regs) } @@ -383,14 +385,14 @@ impl KvmCpu { u128::from(core_regs.elr_el1), )?; - for i in 0..KVM_NR_REGS as usize { + for i in 0..usize::try_from(KVM_NR_REGS)? { self.set_one_reg( Arm64CoreRegs::UserPTRegRegs(i).into(), u128::from(core_regs.regs.regs[i]), )?; } - for i in 0..KVM_NR_SPSR as usize { + for i in 0..usize::try_from(KVM_NR_SPSR)? { self.set_one_reg( Arm64CoreRegs::KvmSpsr(i).into(), u128::from(core_regs.spsr[i]), @@ -399,7 +401,7 @@ impl KvmCpu { // State save and restore is not supported for SVE for now, so we just skip it. if self.kvi.lock().unwrap().features[0] & (1 << kvm_bindings::KVM_ARM_VCPU_SVE) == 0 { - for i in 0..KVM_NR_FP_REGS as usize { + for i in 0..usize::try_from(KVM_NR_FP_REGS)? { self.set_one_reg( Arm64CoreRegs::UserFPSIMDStateVregs(i).into(), core_regs.fp_regs.vregs[i], @@ -420,7 +422,7 @@ impl KvmCpu { } fn reg_sync_by_cpreg_list(reg_id: u64) -> Result { - let coproc = reg_id as u32 & KVM_REG_ARM_COPROC_MASK; + let coproc = u32::try_from(reg_id)? & KVM_REG_ARM_COPROC_MASK; if coproc == KVM_REG_ARM_CORE { return Ok(false); } diff --git a/hypervisor/src/kvm/interrupt.rs b/hypervisor/src/kvm/interrupt.rs index 4df7feb9..b067b17c 100644 --- a/hypervisor/src/kvm/interrupt.rs +++ b/hypervisor/src/kvm/interrupt.rs @@ -46,7 +46,7 @@ fn get_maximum_gsi_cnt(kvmfd: &Kvm) -> u32 { gsi_count = 0; } - gsi_count as u32 + u32::try_from(gsi_count).unwrap_or_default() } /// Return `IrqRouteEntry` according to gsi, irqchip kind and pin. @@ -180,7 +180,7 @@ impl IrqRouteTable { .find_next_zero(0) .with_context(|| "Failed to get new free gsi")?; self.gsi_bitmap.set(free_gsi)?; - Ok(free_gsi as u32) + Ok(u32::try_from(free_gsi)?) } /// Release gsi number to free. @@ -208,11 +208,12 @@ impl IrqRouteTable { trace::kvm_commit_irq_routing(); // SAFETY: data in `routes` is reliable. unsafe { + // layout is aligned, so casting of ptr is allowed. let irq_routing = std::alloc::alloc(layout) as *mut IrqRoute; if irq_routing.is_null() { bail!("Failed to alloc irq routing"); } - (*irq_routing).nr = routes.len() as u32; + (*irq_routing).nr = u32::try_from(routes.len())?; (*irq_routing).flags = 0; let entries: &mut [IrqRouteEntry] = (*irq_routing).entries.as_mut_slice(routes.len()); entries.copy_from_slice(&routes); diff --git a/hypervisor/src/kvm/listener.rs b/hypervisor/src/kvm/listener.rs index b05175c2..2e1c603f 100644 --- a/hypervisor/src/kvm/listener.rs +++ b/hypervisor/src/kvm/listener.rs @@ -93,7 +93,7 @@ impl KvmMemoryListener { for (index, slot) in slots.iter_mut().enumerate() { if slot.size == 0 { - slot.index = index as u32; + slot.index = u32::try_from(index)?; slot.guest_addr = guest_addr; slot.size = size; slot.host_addr = host_addr; @@ -316,8 +316,8 @@ impl KvmMemoryListener { let ioctl_ret = if ioevtfd.data_match { let length = ioevtfd.addr_range.size; match length { - 2 => vm_fd.register_ioevent(&ioevtfd.fd, &io_addr, ioevtfd.data as u16), - 4 => vm_fd.register_ioevent(&ioevtfd.fd, &io_addr, ioevtfd.data as u32), + 2 => vm_fd.register_ioevent(&ioevtfd.fd, &io_addr, u16::try_from(ioevtfd.data)?), + 4 => vm_fd.register_ioevent(&ioevtfd.fd, &io_addr, u32::try_from(ioevtfd.data)?), 8 => vm_fd.register_ioevent(&ioevtfd.fd, &io_addr, ioevtfd.data), _ => bail!("Unexpected ioeventfd data length {}", length), } @@ -357,8 +357,8 @@ impl KvmMemoryListener { let ioctl_ret = if ioevtfd.data_match { let length = ioevtfd.addr_range.size; match length { - 2 => vm_fd.unregister_ioevent(&ioevtfd.fd, &io_addr, ioevtfd.data as u16), - 4 => vm_fd.unregister_ioevent(&ioevtfd.fd, &io_addr, ioevtfd.data as u32), + 2 => vm_fd.unregister_ioevent(&ioevtfd.fd, &io_addr, u16::try_from(ioevtfd.data)?), + 4 => vm_fd.unregister_ioevent(&ioevtfd.fd, &io_addr, u32::try_from(ioevtfd.data)?), 8 => vm_fd.unregister_ioevent(&ioevtfd.fd, &io_addr, ioevtfd.data), _ => bail!("Unexpected ioeventfd data length {}", length), } diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs index 3cec118e..6d00cd38 100644 --- a/hypervisor/src/kvm/mod.rs +++ b/hypervisor/src/kvm/mod.rs @@ -135,6 +135,7 @@ impl KvmHypervisor { } fn create_memory_listener(&self) -> Arc> { + // Memslot will not exceed u32::MAX, so use as translate data type. Arc::new(Mutex::new(KvmMemoryListener::new( self.fd.as_ref().unwrap().get_nr_memslots() as u32, self.vm_fd.clone(), @@ -298,7 +299,7 @@ impl MigrateOps for KvmHypervisor { self.vm_fd .as_ref() .unwrap() - .get_dirty_log(slot, mem_size as usize) + .get_dirty_log(slot, usize::try_from(mem_size)?) .with_context(|| { format!( "Failed to get dirty log, error is {}", -- Gitee From aa32a2e925646a5dca5acab4af914568cbdca5c1 Mon Sep 17 00:00:00 2001 From: zhanghan64 Date: Tue, 20 Aug 2024 11:44:21 +0800 Subject: [PATCH 273/489] ohui/ohaudio/ohcam: fix type of literal value Explicitly declare the value of literal Signed-off-by: zhanghan64 --- devices/src/camera_backend/ohcam.rs | 4 ++-- devices/src/misc/scream/alsa.rs | 4 ++-- devices/src/misc/scream/mod.rs | 2 +- devices/src/misc/scream/ohaudio.rs | 4 ++-- devices/src/usb/camera.rs | 4 ++-- ui/src/ohui_srv/channel.rs | 2 +- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/devices/src/camera_backend/ohcam.rs b/devices/src/camera_backend/ohcam.rs index 04ba1b4f..9d8c2841 100755 --- a/devices/src/camera_backend/ohcam.rs +++ b/devices/src/camera_backend/ohcam.rs @@ -340,7 +340,7 @@ impl CameraBackend for OhCameraBackend { .with_context(|| "Invalid camid in callback table")? .get_buffer(); - if src_len == 0 { + if src_len == 0_u64 { bail!("Invalid frame src_len {}", src_len); } @@ -350,7 +350,7 @@ impl CameraBackend for OhCameraBackend { trace::trace_scope_start!(ohcam_get_frame, args = (frame_offset, len)); - let mut copied = 0; + let mut copied = 0_usize; for iov in iovecs { if len == copied { break; diff --git a/devices/src/misc/scream/alsa.rs b/devices/src/misc/scream/alsa.rs index 7daaee0f..c97084b7 100644 --- a/devices/src/misc/scream/alsa.rs +++ b/devices/src/misc/scream/alsa.rs @@ -168,7 +168,7 @@ impl AudioInterface for AlsaStreamData { return; } - let mut frames = 0; + let mut frames = 0_u32; let mut io = self.pcm.as_ref().unwrap().io_bytes(); // Make sure audio read does not bypass chunk_idx read. @@ -215,7 +215,7 @@ impl AudioInterface for AlsaStreamData { return 0; } - let mut frames = 0; + let mut frames = 0_u32; let mut io = self.pcm.as_ref().unwrap().io_bytes(); // Make sure audio read does not bypass chunk_idx read. diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index 54ac9341..5db2c93c 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -330,7 +330,7 @@ impl StreamData { &unsafe { std::slice::from_raw_parts(hva as *const ShmemHeader, 1) }[0]; self.init(stream_header); - let mut last_end = 0; + let mut last_end = 0_u64; // The recording buffer is behind the playback buffer. Thereforce, the end position of // the playback buffer must be calculted to determine whether the two buffers overlap. if dir == ScreamDirection::Record && header.play.is_started != 0 { diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index 5b03c188..cd504140 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -80,7 +80,7 @@ struct StreamQueue { impl Read for StreamQueue { fn read(&mut self, buf: &mut [u8]) -> std::io::Result { let len = buf.len(); - let mut ret = 0; + let mut ret = 0_usize; while ret < len { if self.queue.is_empty() { break; @@ -191,7 +191,7 @@ impl OhAudioRender { fn flush(&mut self) { self.set_flushing(true); - let mut cnt = 0; + let mut cnt = 0_u64; while cnt < FLUSH_DELAY_CNT { thread::sleep(Duration::from_millis(FLUSH_DELAY_MS)); cnt += 1; diff --git a/devices/src/usb/camera.rs b/devices/src/usb/camera.rs index b4ef0861..b7f0f130 100644 --- a/devices/src/usb/camera.rs +++ b/devices/src/usb/camera.rs @@ -1109,8 +1109,8 @@ fn gen_intface_header_desc(fmt_num: u8) -> VsDescInputHeader { fn gen_fmt_header(fmt: &CameraFormatList) -> Result> { let bits_per_pixel = match fmt.format { - FmtType::Yuy2 | FmtType::Rgb565 => 0x10, - FmtType::Nv12 => 0xc, + FmtType::Yuy2 | FmtType::Rgb565 => 0x10_u8, + FmtType::Nv12 => 0xc_u8, _ => 0, }; let header = match fmt.format { diff --git a/ui/src/ohui_srv/channel.rs b/ui/src/ohui_srv/channel.rs index 64d6e0ac..e55279c9 100755 --- a/ui/src/ohui_srv/channel.rs +++ b/ui/src/ohui_srv/channel.rs @@ -65,7 +65,7 @@ impl OhUiChannel { pub fn recv_slice(stream: &mut dyn Read, data: &mut [u8]) -> Result { let len = data.len(); - let mut ret = 0; + let mut ret = 0_usize; while ret < len { match stream.read(&mut data[ret..len]) { -- Gitee From 1b0065e556513a6097dfbbb2ec1ff0ee66baa6ad Mon Sep 17 00:00:00 2001 From: zhanghan64 Date: Tue, 20 Aug 2024 11:31:42 +0800 Subject: [PATCH 274/489] ohui:fix oh keycode keycode of "menu" on oh is 0x813 Signed-off-by: zhanghan64 --- ui/src/keycode.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/keycode.rs b/ui/src/keycode.rs index 18bbaa7c..16db2dbd 100644 --- a/ui/src/keycode.rs +++ b/ui/src/keycode.rs @@ -458,7 +458,7 @@ const KEY_CODE_OH: [(KeyCode, u16); 105] = [ (KeyCode::Home, 0x0821), (KeyCode::SysReq, 0x081F), (KeyCode::Right, 0x07DF), - (KeyCode::Menu, 0x09A2), + (KeyCode::Menu, 0x0813), (KeyCode::Prior, 0x0814), (KeyCode::Insert, 0x0823), (KeyCode::NumLock, 0x0836), -- Gitee From c9d05dea6ff357b991133dbb7378db2b3642cdbd Mon Sep 17 00:00:00 2001 From: sujerry1991 Date: Tue, 20 Aug 2024 14:46:38 +0800 Subject: [PATCH 275/489] virtio-net: fix possible out of bound of array Checking length of array before using it. Signed-off-by: Yan Wang --- virtio/src/device/net.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index 1ec3dc36..b3108415 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -1684,7 +1684,7 @@ impl VirtioDevice for Net { // configs[0]: NetDevcfg. configs[1]: NetworkInterfaceConfig. fn update_config(&mut self, dev_config: Vec>) -> Result<()> { - if !dev_config.is_empty() { + if dev_config.len() == 2 { self.netdev_cfg = dev_config[0] .as_any() .downcast_ref::() -- Gitee From 684351528e5e0412bf4ad0154e237b6408962c05 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Tue, 20 Aug 2024 09:42:51 +0800 Subject: [PATCH 276/489] machine: Verify unsafe code blocks Reduce unsafe range of host_cpuid(), and propagate unsafe to function user. Signed-off-by: Keqian Zhu --- cpu/src/x86_64/cpuid.rs | 24 ++++++++--------- cpu/src/x86_64/mod.rs | 57 ++++++++++++++++++++++++----------------- 2 files changed, 43 insertions(+), 38 deletions(-) diff --git a/cpu/src/x86_64/cpuid.rs b/cpu/src/x86_64/cpuid.rs index 58ecfbd8..f7b8d752 100644 --- a/cpu/src/x86_64/cpuid.rs +++ b/cpu/src/x86_64/cpuid.rs @@ -12,21 +12,17 @@ use core::arch::x86_64::__cpuid_count; -pub fn host_cpuid( +pub unsafe fn host_cpuid( leaf: u32, subleaf: u32, - eax: *mut u32, - ebx: *mut u32, - ecx: *mut u32, - edx: *mut u32, + eax: &mut u32, + ebx: &mut u32, + ecx: &mut u32, + edx: &mut u32, ) { - // SAFETY: cpuid is created in get_supported_cpuid(). - unsafe { - let cpuid = __cpuid_count(leaf, subleaf); - - *eax = cpuid.eax; - *ebx = cpuid.ebx; - *ecx = cpuid.ecx; - *edx = cpuid.edx; - } + let cpuid = __cpuid_count(leaf, subleaf); + *eax = cpuid.eax; + *ebx = cpuid.ebx; + *ecx = cpuid.ecx; + *edx = cpuid.edx; } diff --git a/cpu/src/x86_64/mod.rs b/cpu/src/x86_64/mod.rs index c64ab8e8..09fdf5db 100644 --- a/cpu/src/x86_64/mod.rs +++ b/cpu/src/x86_64/mod.rs @@ -410,26 +410,32 @@ impl X86CPUState { } } 2 => { - host_cpuid( - 2, - 0, - &mut entry.eax, - &mut entry.ebx, - &mut entry.ecx, - &mut entry.edx, - ); + // SAFETY: entry is from KVM_GET_SUPPORTED_CPUID. + unsafe { + host_cpuid( + 2, + 0, + &mut entry.eax, + &mut entry.ebx, + &mut entry.ecx, + &mut entry.edx, + ); + } } 4 => { // cache info: needed for Pentium Pro compatibility // Passthrough host cache info directly to guest - host_cpuid( - 4, - entry.index, - &mut entry.eax, - &mut entry.ebx, - &mut entry.ecx, - &mut entry.edx, - ); + // SAFETY: entry is from KVM_GET_SUPPORTED_CPUID. + unsafe { + host_cpuid( + 4, + entry.index, + &mut entry.eax, + &mut entry.ebx, + &mut entry.ecx, + &mut entry.edx, + ); + } entry.eax &= !0xfc00_0000; if entry.eax & 0x0001_ffff != 0 && self.max_vcpus > 1 { // max_vcpus is no less than 1. @@ -511,14 +517,17 @@ impl X86CPUState { } 0x8000_0002..=0x8000_0004 => { // Passthrough host cpu model name directly to guest - host_cpuid( - entry.function, - entry.index, - &mut entry.eax, - &mut entry.ebx, - &mut entry.ecx, - &mut entry.edx, - ); + // SAFETY: entry is from KVM_GET_SUPPORTED_CPUID. + unsafe { + host_cpuid( + entry.function, + entry.index, + &mut entry.eax, + &mut entry.ebx, + &mut entry.ecx, + &mut entry.edx, + ); + } } _ => (), } -- Gitee From 32b1cd2c02648d4c2e3abfd68e20300ea0d6b213 Mon Sep 17 00:00:00 2001 From: Li Huachao Date: Tue, 20 Aug 2024 15:01:48 +0800 Subject: [PATCH 277/489] Balloon: pass the memory_advise usafe upwards --- virtio/src/device/balloon.rs | 83 ++++++++++++++++++++++-------------- 1 file changed, 50 insertions(+), 33 deletions(-) diff --git a/virtio/src/device/balloon.rs b/virtio/src/device/balloon.rs index dbfa06b7..d4e611cd 100644 --- a/virtio/src/device/balloon.rs +++ b/virtio/src/device/balloon.rs @@ -170,9 +170,8 @@ fn iov_to_buf( } } -fn memory_advise(addr: *mut libc::c_void, len: libc::size_t, advice: libc::c_int) { - // SAFETY: The memory to be freed is allocated by guest. - if unsafe { libc::madvise(addr, len, advice) } != 0 { +unsafe fn memory_advise(addr: *mut libc::c_void, len: libc::size_t, advice: libc::c_int) { + if libc::madvise(addr, len, advice) != 0 { let evt_type = match advice { libc::MADV_DONTNEED => "DONTNEED".to_string(), libc::MADV_REMOVE => "REMOVE".to_string(), @@ -238,11 +237,14 @@ impl Request { } else if hva == last_addr + BALLOON_PAGE_SIZE { free_len += 1; } else { - memory_advise( - start_addr as *const libc::c_void as *mut _, - (free_len * BALLOON_PAGE_SIZE) as usize, - libc::MADV_WILLNEED, - ); + // SAFETY: The memory to be freed is allocated by guest. + unsafe { + memory_advise( + start_addr as *const libc::c_void as *mut _, + (free_len * BALLOON_PAGE_SIZE) as usize, + libc::MADV_WILLNEED, + ) + }; free_len = 1; start_addr = hva; } @@ -251,11 +253,14 @@ impl Request { } if free_len != 0 { - memory_advise( - start_addr as *const libc::c_void as *mut _, - (free_len * BALLOON_PAGE_SIZE) as usize, - libc::MADV_WILLNEED, - ); + // SAFETY: The memory to be freed is allocated by guest. + unsafe { + memory_advise( + start_addr as *const libc::c_void as *mut _, + (free_len * BALLOON_PAGE_SIZE) as usize, + libc::MADV_WILLNEED, + ) + }; } } /// Mark balloon page with `MADV_DONTNEED` or `MADV_WILLNEED`. @@ -319,11 +324,14 @@ impl Request { } else if hva == last_addr + BALLOON_PAGE_SIZE && last_share == share { free_len += 1; } else { - memory_advise( - start_addr as *const libc::c_void as *mut _, - (free_len * BALLOON_PAGE_SIZE) as usize, - advice, - ); + // SAFETY: The memory to be freed is allocated by guest. + unsafe { + memory_advise( + start_addr as *const libc::c_void as *mut _, + (free_len * BALLOON_PAGE_SIZE) as usize, + advice, + ) + }; free_len = 1; start_addr = hva; last_share = share; @@ -337,11 +345,14 @@ impl Request { last_addr = hva; } if free_len != 0 { - memory_advise( - start_addr as *const libc::c_void as *mut _, - (free_len * BALLOON_PAGE_SIZE) as usize, - advice, - ); + // SAFETY: The memory to be freed is allocated by guest. + unsafe { + memory_advise( + start_addr as *const libc::c_void as *mut _, + (free_len * BALLOON_PAGE_SIZE) as usize, + advice, + ) + }; } } else { let mut host_page_bitmap = BalloonedPageBitmap::new(host_page_size / BALLOON_PAGE_SIZE); @@ -375,11 +386,14 @@ impl Request { } else { advice = libc::MADV_DONTNEED; } - memory_advise( - host_page_bitmap.base_address as *const libc::c_void as *mut _, - host_page_size as usize, - advice, - ); + // SAFETY: The memory to be freed is allocated by guest. + unsafe { + memory_advise( + host_page_bitmap.base_address as *const libc::c_void as *mut _, + host_page_size as usize, + advice, + ) + }; host_page_bitmap = BalloonedPageBitmap::new(host_page_size / BALLOON_PAGE_SIZE); } } @@ -401,11 +415,14 @@ impl Request { } else { libc::MADV_DONTNEED }; - memory_advise( - hva as *const libc::c_void as *mut _, - iov.iov_len as usize, - advice, - ); + // SAFETY: The memory to be freed is allocated by guest. + unsafe { + memory_advise( + hva as *const libc::c_void as *mut _, + iov.iov_len as usize, + advice, + ) + }; } } } -- Gitee From 2fbf9bb29c481bceff38f566c42bb52c76452bcc Mon Sep 17 00:00:00 2001 From: Li Huachao Date: Tue, 20 Aug 2024 15:24:54 +0800 Subject: [PATCH 278/489] Memory: Numeric literals need to ne explicitly typed. --- address_space/src/address_space.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/address_space/src/address_space.rs b/address_space/src/address_space.rs index 0689aaea..4e8e35fc 100644 --- a/address_space/src/address_space.rs +++ b/address_space/src/address_space.rs @@ -230,7 +230,7 @@ impl AddressSpace { } locked_listener.enable(); - let mut idx = 0; + let mut idx = 0_usize; let mut mls = self.listeners.lock().unwrap(); for ml in mls.iter() { if ml.lock().unwrap().priority() >= locked_listener.priority() { @@ -381,8 +381,8 @@ impl AddressSpace { /// * `new_evtfds` - New `RegionIoEventFd` array. fn update_ioeventfds_pass(&self, new_evtfds: &[RegionIoEventFd]) -> Result<()> { let old_evtfds = self.ioeventfds.lock().unwrap(); - let mut old_idx = 0; - let mut new_idx = 0; + let mut old_idx = 0_usize; + let mut new_idx = 0_usize; while old_idx < old_evtfds.len() || new_idx < new_evtfds.len() { let old_fd = old_evtfds.get(old_idx); -- Gitee From d6e88c9c64aed544d7b50e178ebd76ce7339a62c Mon Sep 17 00:00:00 2001 From: Li Huachao Date: Tue, 20 Aug 2024 15:38:44 +0800 Subject: [PATCH 279/489] Balloon: Numeric literals need to ne explicitly typed. --- virtio/src/device/balloon.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/virtio/src/device/balloon.rs b/virtio/src/device/balloon.rs index d4e611cd..34f241ab 100644 --- a/virtio/src/device/balloon.rs +++ b/virtio/src/device/balloon.rs @@ -282,7 +282,7 @@ impl Request { let mut hvaset = Vec::new(); for iov in self.iovec.iter() { - let mut offset = 0; + let mut offset = 0_u64; while let Some(pfn) = iov_to_buf::(address_space, iov, offset) { offset += std::mem::size_of::() as u64; @@ -305,7 +305,7 @@ impl Request { } let host_page_size = host_page_size(); - let mut advice = 0; + let mut advice = 0_i32; // If host_page_size equals BALLOON_PAGE_SIZE and have the same share properties, // we can directly call the madvise function without any problem. And if the advice is // MADV_WILLNEED, we just hint the whole host page it lives on, since we can't do -- Gitee From 3edd0c0aa7e025653086b4063ad871886820ec68 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sun, 18 Aug 2024 05:44:09 +0800 Subject: [PATCH 280/489] ohui_srv: fix wrong type Fix wrong type in ohui_srv. Signed-off-by: liuxiangdong --- ui/src/ohui_srv/msg_handle.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ui/src/ohui_srv/msg_handle.rs b/ui/src/ohui_srv/msg_handle.rs index 84b78857..b87d5916 100755 --- a/ui/src/ohui_srv/msg_handle.rs +++ b/ui/src/ohui_srv/msg_handle.rs @@ -148,7 +148,7 @@ impl OhUiMsgHandler { let hdr = &reader.header; let event_type = hdr.event_type; - let body_size = hdr.size as size; + let body_size = hdr.size as usize; trace::trace_scope_start!(handle_msg, args = (&event_type)); let body_bytes = reader.body.as_ref().unwrap(); -- Gitee From f591fa1cd612f3da74fcaf12505c973cb459e347 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sun, 18 Aug 2024 05:33:09 +0800 Subject: [PATCH 281/489] clippy: fix some cast_lossless warnings Fix some clippy warnings that were not fixed last commit (f3f0a3c432). Use command line: cargo clippy --fix --workspace --all-features --all-targets -- -Aclippy::all -Wclippy::cast_lossless Use command line in HM: cargo clippy --target aarch64-linux-ohos --features "boot_time ramfb virtio_gpu scream_ohaudio ohui_srv vnc usb_camera_oh pvpanic" -- -Aclippy::all -Wclippy::cast_lossless Note: Some header files have different type definitions in HM and Linux, and such warnings will not be fixed this time. See: machine_manager/src/socket.rs util/src/unix.rs Fix: f3f0a3c432(clippy: fix some cast_lossless warnings) Signed-off-by: liuxiangdong --- devices/src/camera_backend/demo.rs | 14 +++--- devices/src/camera_backend/mod.rs | 4 +- devices/src/camera_backend/ohcam.rs | 2 +- devices/src/camera_backend/v4l2.rs | 8 +-- devices/src/legacy/ramfb.rs | 4 +- devices/src/misc/scream/alsa.rs | 25 ++++++---- devices/src/misc/scream/ohaudio.rs | 12 +++-- devices/src/misc/scream/pulseaudio.rs | 11 ++-- devices/src/pci/demo_device/dpy_device.rs | 4 +- .../src/pci/demo_device/kbd_pointer_device.rs | 2 +- devices/src/pci/demo_device/mod.rs | 6 +-- devices/src/usb/camera.rs | 6 +-- devices/src/usb/usbhost/host_usblib.rs | 4 +- devices/src/usb/usbhost/mod.rs | 8 +-- hypervisor/src/kvm/mod.rs | 2 +- ui/src/gtk/draw.rs | 8 +-- ui/src/gtk/mod.rs | 32 ++++++------ ui/src/input.rs | 2 +- ui/src/ohui_srv/msg_handle.rs | 2 +- ui/src/vnc/client_io.rs | 50 +++++++++---------- ui/src/vnc/encoding/enc_hextile.rs | 3 +- ui/src/vnc/mod.rs | 22 ++++---- ui/src/vnc/server_io.rs | 8 +-- util/src/v4l2.rs | 2 +- 24 files changed, 125 insertions(+), 116 deletions(-) diff --git a/devices/src/camera_backend/demo.rs b/devices/src/camera_backend/demo.rs index 19b1d4da..60732d63 100644 --- a/devices/src/camera_backend/demo.rs +++ b/devices/src/camera_backend/demo.rs @@ -204,7 +204,7 @@ impl DemoCameraBackend { notify(); } let interval = if locked_fmt.fps != 0 { - 1000 / locked_fmt.fps as u64 + 1000 / u64::from(locked_fmt.fps) } else { 20 }; @@ -544,9 +544,9 @@ fn convert_to_nv12(source: &[u8], width: u32, height: u32) -> Vec { for i in 0..len { let idx = (i * pixel) as usize; let (b, g, r) = ( - source[idx] as f32, - source[idx + 1] as f32, - source[idx + 2] as f32, + f32::from(source[idx]), + f32::from(source[idx + 1]), + f32::from(source[idx + 2]), ); let y = (0.299 * r + 0.587 * g + 0.114 * b) as u8; img_nv12.push(y); @@ -554,9 +554,9 @@ fn convert_to_nv12(source: &[u8], width: u32, height: u32) -> Vec { for i in 0..(width * height / 2) { let idx = (i * 2 * pixel) as usize; let (b, g, r) = ( - source[idx] as f32, - source[idx + 1] as f32, - source[idx + 2] as f32, + f32::from(source[idx]), + f32::from(source[idx + 1]), + f32::from(source[idx + 2]), ); let u = (-0.147 * r - 0.289 * g + 0.436 * b + 128_f32) as u8; let v = (0.615 * r - 0.515 * g - 0.100 * b + 128_f32) as u8; diff --git a/devices/src/camera_backend/mod.rs b/devices/src/camera_backend/mod.rs index 6e67d762..86b1c4ec 100644 --- a/devices/src/camera_backend/mod.rs +++ b/devices/src/camera_backend/mod.rs @@ -123,9 +123,9 @@ pub fn get_video_frame_size(width: u32, height: u32, fmt: FmtType) -> Result Result { let fm_size = get_video_frame_size(width, height, fmt)?; - let size_in_bit = fm_size as u64 * INTERVALS_PER_SEC as u64 * 8; + let size_in_bit = u64::from(fm_size) * u64::from(INTERVALS_PER_SEC) * 8; let rate = size_in_bit - .checked_div(interval as u64) + .checked_div(u64::from(interval)) .with_context(|| format!("Invalid size {} or interval {}", size_in_bit, interval))?; Ok(rate as u32) } diff --git a/devices/src/camera_backend/ohcam.rs b/devices/src/camera_backend/ohcam.rs index 9d8c2841..a67b7898 100755 --- a/devices/src/camera_backend/ohcam.rs +++ b/devices/src/camera_backend/ohcam.rs @@ -236,7 +236,7 @@ impl CameraBackend for OhCameraBackend { let mut fmt_list: Vec = Vec::new(); for idx in 0..self.profile_cnt { - match self.ctx.get_profile(idx as i32) { + match self.ctx.get_profile(i32::from(idx)) { Ok((fmt, width, height, fps)) => { if !FRAME_FORMAT_WHITELIST.iter().any(|&x| x == fmt) || !RESOLUTION_WHITELIST.iter().any(|&x| x == (width, height)) diff --git a/devices/src/camera_backend/v4l2.rs b/devices/src/camera_backend/v4l2.rs index 0885d1da..f86b13ea 100644 --- a/devices/src/camera_backend/v4l2.rs +++ b/devices/src/camera_backend/v4l2.rs @@ -225,8 +225,8 @@ impl V4l2CameraBackend { ); continue; } - let interval = - (numerator as u64 * INTERVALS_PER_SEC as u64 / denominator as u64) as u32; + let interval = (u64::from(numerator) * u64::from(INTERVALS_PER_SEC) + / u64::from(denominator)) as u32; list.push(interval); } Ok(list) @@ -498,7 +498,7 @@ impl V4l2IoHandler { let iov = locked_buf .get(buf.index as usize) .with_context(|| "Buffer index overflow")?; - if buf.bytesused as u64 > iov.iov_len { + if u64::from(buf.bytesused) > iov.iov_len { bail!( "Buffer overflow, bytesused {} iov len {}", buf.bytesused, @@ -506,7 +506,7 @@ impl V4l2IoHandler { ); } locked_sample.addr = iov.iov_base; - locked_sample.used_len = buf.bytesused as u64; + locked_sample.used_len = u64::from(buf.bytesused); locked_sample.buf_index = buf.index; drop(locked_sample); // Notify the camera to deal with request. diff --git a/devices/src/legacy/ramfb.rs b/devices/src/legacy/ramfb.rs index 40eda77e..8363213a 100644 --- a/devices/src/legacy/ramfb.rs +++ b/devices/src/legacy/ramfb.rs @@ -121,13 +121,13 @@ impl RamfbState { } if stride == 0 { - let linesize = width * pixman_format_bpp(format as u32) as u32 / BYTES_PER_PIXELS; + let linesize = width * u32::from(pixman_format_bpp(format as u32)) / BYTES_PER_PIXELS; stride = linesize; } let fb_addr = match self.sys_mem.addr_cache_init(GuestAddress(addr)) { Some((hva, len)) => { - if len < stride as u64 { + if len < u64::from(stride) { error!("Insufficient contiguous memory length"); return; } diff --git a/devices/src/misc/scream/alsa.rs b/devices/src/misc/scream/alsa.rs index c97084b7..f6a8689e 100644 --- a/devices/src/misc/scream/alsa.rs +++ b/devices/src/misc/scream/alsa.rs @@ -81,7 +81,7 @@ impl AlsaStreamData { hwp.set_rate_resample(true)?; hwp.set_access(Access::RWInterleaved)?; hwp.set_format(self.format)?; - hwp.set_channels(channels as u32)?; + hwp.set_channels(u32::from(channels))?; hwp.set_rate(self.rate, ValueOr::Nearest)?; // Set the latency in microseconds. hwp.set_buffer_time_near(self.latency * 1000, ValueOr::Nearest)?; @@ -184,12 +184,14 @@ impl AudioInterface for AlsaStreamData { }; let samples = - recv_data.audio_size / (self.bytes_per_sample * recv_data.fmt.channels as u32); + recv_data.audio_size / (self.bytes_per_sample * u32::from(recv_data.fmt.channels)); while frames < samples { let send_frame_num = min(samples - frames, MAX_FRAME_NUM); - let offset = (frames * self.bytes_per_sample * recv_data.fmt.channels as u32) as usize; + let offset = + (frames * self.bytes_per_sample * u32::from(recv_data.fmt.channels)) as usize; let end = offset - + (send_frame_num * self.bytes_per_sample * recv_data.fmt.channels as u32) as usize; + + (send_frame_num * self.bytes_per_sample * u32::from(recv_data.fmt.channels)) + as usize; match io.write(&data[offset..end]) { Err(e) => { debug!("Failed to write data to ALSA buffer: {:?}", e); @@ -203,7 +205,8 @@ impl AudioInterface for AlsaStreamData { } Ok(n) => { trace::scream_alsa_send_frames(frames, offset, end); - frames += n as u32 / (self.bytes_per_sample * recv_data.fmt.channels as u32); + frames += + n as u32 / (self.bytes_per_sample * u32::from(recv_data.fmt.channels)); } } } @@ -231,11 +234,12 @@ impl AudioInterface for AlsaStreamData { }; let samples = - recv_data.audio_size / (self.bytes_per_sample * recv_data.fmt.channels as u32); + recv_data.audio_size / (self.bytes_per_sample * u32::from(recv_data.fmt.channels)); while frames < samples { - let offset = (frames * self.bytes_per_sample * recv_data.fmt.channels as u32) as usize; + let offset = + (frames * self.bytes_per_sample * u32::from(recv_data.fmt.channels)) as usize; let end = offset - + ((samples - frames) * self.bytes_per_sample * recv_data.fmt.channels as u32) + + ((samples - frames) * self.bytes_per_sample * u32::from(recv_data.fmt.channels)) as usize; match io.read(&mut data[offset..end]) { Err(e) => { @@ -250,7 +254,8 @@ impl AudioInterface for AlsaStreamData { } Ok(n) => { trace::scream_alsa_receive_frames(frames, offset, end); - frames += n as u32 / (self.bytes_per_sample * recv_data.fmt.channels as u32); + frames += + n as u32 / (self.bytes_per_sample * u32::from(recv_data.fmt.channels)); // During the host headset switchover, io.read is blocked for a long time. // As a result, the VM recording delay exceeds 1s. Thereforce, check whether @@ -259,7 +264,7 @@ impl AudioInterface for AlsaStreamData { warn!("Scream alsa can't get frames delay: {e:?}"); 0 }); - if delay > self.rate as i64 >> 1 { + if delay > i64::from(self.rate) >> 1 { warn!("Scream alsa read audio blocked too long, delay {delay} frames, init again!"); self.init = false; } diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index cd504140..d6badff8 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -356,8 +356,9 @@ impl OhAudioProcess for OhAudioCapture { self.align = sh_header.chunk_size; self.new_chunks.store(0, Ordering::Release); self.shm_addr = start_addr; - self.shm_len = sh_header.max_chunks as u64 * sh_header.chunk_size as u64; - self.cur_pos = start_addr + sh_header.chunk_idx as u64 * sh_header.chunk_size as u64; + self.shm_len = u64::from(sh_header.max_chunks) * u64::from(sh_header.chunk_size); + self.cur_pos = + start_addr + u64::from(sh_header.chunk_idx) * u64::from(sh_header.chunk_size); } fn process(&mut self, recv_data: &StreamData) -> i32 { @@ -442,7 +443,8 @@ extern "C" fn on_read_data_cb( break; } } - let old_pos = capture.cur_pos - ((capture.cur_pos - capture.shm_addr) % capture.align as u64); + let old_pos = + capture.cur_pos - ((capture.cur_pos - capture.shm_addr) % u64::from(capture.align)); let buf_end = capture.shm_addr + capture.shm_len; let mut src_addr = buffer as u64; let mut left = length as u64; @@ -466,8 +468,8 @@ extern "C" fn on_read_data_cb( } let new_chunks = match capture.cur_pos <= old_pos { - true => (capture.shm_len - (old_pos - capture.cur_pos)) / capture.align as u64, - false => (capture.cur_pos - old_pos) / capture.align as u64, + true => (capture.shm_len - (old_pos - capture.cur_pos)) / u64::from(capture.align), + false => (capture.cur_pos - old_pos) / u64::from(capture.align), }; capture .new_chunks diff --git a/devices/src/misc/scream/pulseaudio.rs b/devices/src/misc/scream/pulseaudio.rs index 2e90bfbb..22105585 100644 --- a/devices/src/misc/scream/pulseaudio.rs +++ b/devices/src/misc/scream/pulseaudio.rs @@ -84,8 +84,8 @@ impl PulseStreamData { // Set buffer size for requested latency. let buffer_attr = BufferAttr { - maxlength: ss.usec_to_bytes(MicroSeconds(MAX_LATENCY_MS as u64 * 1000)) as u32, - tlength: ss.usec_to_bytes(MicroSeconds(TARGET_LATENCY_MS as u64 * 1000)) as u32, + maxlength: ss.usec_to_bytes(MicroSeconds(u64::from(MAX_LATENCY_MS) * 1000)) as u32, + tlength: ss.usec_to_bytes(MicroSeconds(u64::from(TARGET_LATENCY_MS) * 1000)) as u32, prebuf: std::u32::MAX, minreq: std::u32::MAX, fragsize: std::u32::MAX, @@ -198,9 +198,10 @@ impl PulseStreamData { if self.ss.rate > 0 { // Sample spec has changed, so the playback buffer size for the requested latency must // be recalculated as well. - self.buffer_attr.tlength = - self.ss - .usec_to_bytes(MicroSeconds(self.latency as u64 * 1000)) as u32; + self.buffer_attr.tlength = self + .ss + .usec_to_bytes(MicroSeconds(u64::from(self.latency) * 1000)) + as u32; self.simple = Simple::new( None, diff --git a/devices/src/pci/demo_device/dpy_device.rs b/devices/src/pci/demo_device/dpy_device.rs index bde922f6..e0157461 100644 --- a/devices/src/pci/demo_device/dpy_device.rs +++ b/devices/src/pci/demo_device/dpy_device.rs @@ -128,8 +128,8 @@ impl DisplayChangeListenerOperations for DpyInterface { } let mut i = 0; - let mut offset = y * stride + x * bpp as i32 / 8; - let count = w * bpp as i32 / 8; + let mut offset = y * stride + x * i32::from(bpp) / 8; + let count = w * i32::from(bpp) / 8; while i < h { error!( "update from {} to {}, before is {}", diff --git a/devices/src/pci/demo_device/kbd_pointer_device.rs b/devices/src/pci/demo_device/kbd_pointer_device.rs index ce554987..78033f8e 100644 --- a/devices/src/pci/demo_device/kbd_pointer_device.rs +++ b/devices/src/pci/demo_device/kbd_pointer_device.rs @@ -94,7 +94,7 @@ impl KeyboardOpts for TestPciKbd { let msg = PointerMessage { event_type: InputEvent::KbdEvent, keycode, - down: down as u8, + down: u8::from(down), ..Default::default() }; MEM_ADDR.lock().unwrap().send_kbdmouse_message(&msg) diff --git a/devices/src/pci/demo_device/mod.rs b/devices/src/pci/demo_device/mod.rs index b4163f7a..e8264b0d 100644 --- a/devices/src/pci/demo_device/mod.rs +++ b/devices/src/pci/demo_device/mod.rs @@ -107,7 +107,7 @@ impl DemoDev { devfn, }, cmd_cfg: cfg, - mem_region: Region::init_container_region(u32::MAX as u64, "DemoDev"), + mem_region: Region::init_container_region(u64::from(u32::MAX), "DemoDev"), dev_id: Arc::new(AtomicU16::new(0)), device, } @@ -160,7 +160,7 @@ impl DemoDev { self.mem_region.clone(), RegionType::Mem64Bit, false, - (self.cmd_cfg.bar_size * self.cmd_cfg.bar_num as u64).next_power_of_two(), + (self.cmd_cfg.bar_size * u64::from(self.cmd_cfg.bar_num)).next_power_of_two(), )?; Ok(()) @@ -190,7 +190,7 @@ impl Device for DemoDev { self.register_data_handling_bar()?; self.device.lock().unwrap().realize()?; - let devfn = self.base.devfn as u64; + let devfn = u64::from(self.base.devfn); let parent_bus = self.parent_bus().unwrap().upgrade().unwrap(); let mut locked_bus = parent_bus.lock().unwrap(); let demo_pci_dev = Arc::new(Mutex::new(self)); diff --git a/devices/src/usb/camera.rs b/devices/src/usb/camera.rs index b7f0f130..7dce7834 100644 --- a/devices/src/usb/camera.rs +++ b/devices/src/usb/camera.rs @@ -905,7 +905,7 @@ impl UvcPayload { MAX_PAYLOAD ); } - frame_data_size = MAX_PAYLOAD as u64 - self.payload_offset as u64; + frame_data_size = u64::from(MAX_PAYLOAD) - self.payload_offset as u64; } // payload start, reserve the header. if self.payload_offset == 0 && frame_data_size + header_len as u64 > iov_size { @@ -998,7 +998,7 @@ impl CameraIoHandler { // Payload start, add header. pkt.transfer_packet(&mut locked_payload.header, header_len); locked_payload.payload_offset += header_len; - iovecs = iov_discard_front_direct(&mut pkt.iovecs, pkt.actual_length as u64) + iovecs = iov_discard_front_direct(&mut pkt.iovecs, u64::from(pkt.actual_length)) .with_context(|| format!("Invalid iov size {}", pkt_size))?; } let copied = locked_camera.get_frame( @@ -1078,7 +1078,7 @@ fn gen_fmt_desc(fmt_list: Vec) -> Result body.push(Arc::new(UsbDescOther { data })); } - header_struct.wTotalLength = header_struct.bLength as u16 + header_struct.wTotalLength = u16::from(header_struct.bLength) + body.clone().iter().fold(0, |len, x| len + x.data.len()) as u16; let mut vec = header_struct.as_bytes().to_vec(); diff --git a/devices/src/usb/usbhost/host_usblib.rs b/devices/src/usb/usbhost/host_usblib.rs index e558f814..91376074 100644 --- a/devices/src/usb/usbhost/host_usblib.rs +++ b/devices/src/usb/usbhost/host_usblib.rs @@ -133,7 +133,7 @@ pub fn set_pollfd_notifiers( if (*poll.offset(i)).is_null() { break; }; - if (*(*poll.offset(i))).events as c_int == EPOLLIN { + if i32::from((*(*poll.offset(i))).events) == EPOLLIN { notifiers.push(EventNotifier::new( NotifierOperation::AddShared, (*(*poll.offset(i))).fd, @@ -141,7 +141,7 @@ pub fn set_pollfd_notifiers( EventSet::IN, vec![handler.clone()], )); - } else if (*(*poll.offset(i))).events as c_int == EPOLLOUT { + } else if i32::from((*(*poll.offset(i))).events) == EPOLLOUT { notifiers.push(EventNotifier::new( NotifierOperation::AddShared, (*(*poll.offset(i))).fd, diff --git a/devices/src/usb/usbhost/mod.rs b/devices/src/usb/usbhost/mod.rs index 5859e19f..62a2382e 100644 --- a/devices/src/usb/usbhost/mod.rs +++ b/devices/src/usb/usbhost/mod.rs @@ -243,7 +243,7 @@ impl IsoTransfer { pub fn copy_data(&mut self, packet: Arc>, ep_max_packet_size: u32) -> bool { let mut lockecd_packet = packet.lock().unwrap(); let mut size: usize; - if lockecd_packet.pid == USB_TOKEN_OUT as u32 { + if lockecd_packet.pid == u32::from(USB_TOKEN_OUT) { size = lockecd_packet.get_iovecs_size() as usize; if size > ep_max_packet_size as usize { size = ep_max_packet_size as usize; @@ -783,7 +783,7 @@ impl UsbHost { .set_alternate_setting(iface as u8, alt as u8) { Ok(_) => { - self.base.altsetting[iface as usize] = alt as u32; + self.base.altsetting[iface as usize] = u32::from(alt); self.ep_update(); } Err(e) => { @@ -871,7 +871,7 @@ impl UsbHost { pub fn handle_iso_data_in(&mut self, packet: Arc>) { let cloned_packet = packet.clone(); let locked_packet = packet.lock().unwrap(); - let in_direction = locked_packet.pid == USB_TOKEN_IN as u32; + let in_direction = locked_packet.pid == u32::from(USB_TOKEN_IN); let iso_queue = if self.find_iso_queue(locked_packet.ep_number).is_some() { self.find_iso_queue(locked_packet.ep_number).unwrap() } else { @@ -905,7 +905,7 @@ impl UsbHost { let mut locked_iso_queue = iso_queue.lock().unwrap(); - let in_direction = locked_packet.pid == USB_TOKEN_IN as u32; + let in_direction = locked_packet.pid == u32::from(USB_TOKEN_IN); let ep = self .base .get_endpoint(in_direction, locked_packet.ep_number); diff --git a/hypervisor/src/kvm/mod.rs b/hypervisor/src/kvm/mod.rs index 6d00cd38..16e7a479 100644 --- a/hypervisor/src/kvm/mod.rs +++ b/hypervisor/src/kvm/mod.rs @@ -426,7 +426,7 @@ impl KvmCpu { #[cfg(target_arch = "x86_64")] VcpuExit::IoOut(addr, data) => { #[cfg(feature = "boot_time")] - cpu::capture_boot_signal(addr as u64, data); + cpu::capture_boot_signal(u64::from(addr), data); vm.lock().unwrap().pio_out(u64::from(addr), data); } diff --git a/ui/src/gtk/draw.rs b/ui/src/gtk/draw.rs index 9d9dde3c..b9cbfc6e 100644 --- a/ui/src/gtk/draw.rs +++ b/ui/src/gtk/draw.rs @@ -218,7 +218,7 @@ fn da_event_callback(gs: &Rc>, event: &gdk::Event) -> fn gd_cursor_move_event(gs: &Rc>, event: &gdk::Event) -> Result<()> { let mut borrowed_gs = gs.borrow_mut(); let (width, height) = match &borrowed_gs.cairo_image { - Some(image) => (image.width() as f64, image.height() as f64), + Some(image) => (f64::from(image.width()), f64::from(image.height())), None => return Ok(()), }; @@ -231,8 +231,8 @@ fn gd_cursor_move_event(gs: &Rc>, event: &gdk::Event) let standard_x = ((real_x * (ABS_MAX as f64)) / width) as u16; let standard_y = ((real_y * (ABS_MAX as f64)) / height) as u16; - input_move_abs(Axis::X, standard_x as u32)?; - input_move_abs(Axis::Y, standard_y as u32)?; + input_move_abs(Axis::X, u32::from(standard_x))?; + input_move_abs(Axis::Y, u32::from(standard_y))?; input_point_sync() } @@ -304,7 +304,7 @@ fn da_draw_callback(gs: &Rc>, cr: &cairo::Context) -> let mut borrowed_gs = gs.borrow_mut(); let scale_mode = borrowed_gs.scale_mode.clone(); let (mut surface_width, mut surface_height) = match &borrowed_gs.cairo_image { - Some(image) => (image.width() as f64, image.height() as f64), + Some(image) => (f64::from(image.width()), f64::from(image.height())), None => return Ok(()), }; diff --git a/ui/src/gtk/mod.rs b/ui/src/gtk/mod.rs index 84b59e5d..2b055adc 100644 --- a/ui/src/gtk/mod.rs +++ b/ui/src/gtk/mod.rs @@ -429,8 +429,8 @@ impl GtkDisplayScreen { fn get_window_size(&self) -> Option<(f64, f64)> { if let Some(win) = self.draw_area.window() { - let w_width = win.width() as f64; - let w_height = win.height() as f64; + let w_width = f64::from(win.width()); + let w_height = f64::from(win.height()); if w_width.ne(&0.0) && w_height.ne(&0.0) { return Some((w_width, w_height)); @@ -452,8 +452,8 @@ impl GtkDisplayScreen { None => bail!("No display image."), }; let (scale_width, scale_height) = ( - (surface_width as f64) * self.scale_x, - (surface_height as f64) * self.scale_y, + f64::from(surface_width) * self.scale_x, + f64::from(surface_height) * self.scale_y, ); let (mut window_width, mut window_height) = (0.0, 0.0); @@ -461,7 +461,7 @@ impl GtkDisplayScreen { (window_width, window_height) = (w, h); }; let scale_factor = match self.draw_area.window() { - Some(window) => window.scale_factor() as f64, + Some(window) => f64::from(window.scale_factor()), None => bail!("No display window."), }; @@ -816,13 +816,13 @@ fn do_update_event(gs: &Rc>, event: DisplayChangeEvent drop(locked_con); // Image scalling. - let x1 = ((x as f64) * borrowed_gs.scale_x).floor(); - let y1 = ((y as f64) * borrowed_gs.scale_y).floor(); - let x2 = ((x as f64) * borrowed_gs.scale_x + (w as f64) * borrowed_gs.scale_x).ceil(); - let y2 = ((y as f64) * borrowed_gs.scale_y + (h as f64) * borrowed_gs.scale_y).ceil(); + let x1 = (f64::from(x) * borrowed_gs.scale_x).floor(); + let y1 = (f64::from(y) * borrowed_gs.scale_y).floor(); + let x2 = (f64::from(x) * borrowed_gs.scale_x + f64::from(w) * borrowed_gs.scale_x).ceil(); + let y2 = (f64::from(y) * borrowed_gs.scale_y + f64::from(h) * borrowed_gs.scale_y).ceil(); - let scale_width = (surface_width as f64) * borrowed_gs.scale_x; - let scale_height = (surface_height as f64) * borrowed_gs.scale_y; + let scale_width = f64::from(surface_width) * borrowed_gs.scale_x; + let scale_height = f64::from(surface_height) * borrowed_gs.scale_y; let (window_width, window_height); match borrowed_gs.get_window_size() { Some((w, h)) => (window_width, window_height) = (w, h), @@ -964,8 +964,8 @@ fn do_switch_event(gs: &Rc>) -> Result<()> { None => return Ok(()), }; if scale_mode.borrow().is_full_screen() || scale_mode.borrow().is_free_scale() { - borrowed_gs.scale_x = window_width / surface_width as f64; - borrowed_gs.scale_y = window_height / surface_height as f64; + borrowed_gs.scale_x = window_width / f64::from(surface_width); + borrowed_gs.scale_y = window_height / f64::from(surface_height); } // Vm desktop manage its own cursor, gtk cursor need to be trsp firstly. @@ -1001,7 +1001,7 @@ pub(crate) fn update_window_size(gs: &Rc>) -> Result<( let borrowed_gs = gs.borrow(); let scale_mode = borrowed_gs.scale_mode.borrow().clone(); let (width, height) = match &borrowed_gs.cairo_image { - Some(image) => (image.width() as f64, image.height() as f64), + Some(image) => (f64::from(image.width()), f64::from(image.height())), None => (0.0, 0.0), }; let (mut scale_width, mut scale_height) = if scale_mode.is_free_scale() { @@ -1009,8 +1009,8 @@ pub(crate) fn update_window_size(gs: &Rc>) -> Result<( } else { (width * borrowed_gs.scale_x, height * borrowed_gs.scale_y) }; - scale_width = scale_width.max(DEFAULT_SURFACE_WIDTH as f64); - scale_height = scale_height.max(DEFAULT_SURFACE_HEIGHT as f64); + scale_width = scale_width.max(f64::from(DEFAULT_SURFACE_WIDTH)); + scale_height = scale_height.max(f64::from(DEFAULT_SURFACE_HEIGHT)); let geo: Geometry = Geometry::new( scale_width as i32, diff --git a/ui/src/input.rs b/ui/src/input.rs index a04f65b5..f72119cf 100644 --- a/ui/src/input.rs +++ b/ui/src/input.rs @@ -647,7 +647,7 @@ mod tests { for idx in 0..keysym_lists.len() { let keysym = keycode_lists[idx]; let keycode = keycode_lists[idx]; - assert!(do_key_event(true, keysym as i32, keycode).is_ok()); + assert!(do_key_event(true, i32::from(keysym), keycode).is_ok()); assert_eq!(test_kdb.lock().unwrap().keycode, keycode); assert!(test_kdb.lock().unwrap().down); } diff --git a/ui/src/ohui_srv/msg_handle.rs b/ui/src/ohui_srv/msg_handle.rs index b87d5916..21a11637 100755 --- a/ui/src/ohui_srv/msg_handle.rs +++ b/ui/src/ohui_srv/msg_handle.rs @@ -89,7 +89,7 @@ impl WindowState { } fn move_pointer(&mut self, x: f64, y: f64) -> Result<()> { - let (pos_x, pos_y) = trans_mouse_pos(x, y, self.width as f64, self.height as f64); + let (pos_x, pos_y) = trans_mouse_pos(x, y, f64::from(self.width), f64::from(self.height)); input_move_abs(Axis::X, pos_x)?; input_move_abs(Axis::Y, pos_y)?; input_point_sync() diff --git a/ui/src/vnc/client_io.rs b/ui/src/vnc/client_io.rs index b4fa9055..7ffa8996 100644 --- a/ui/src/vnc/client_io.rs +++ b/ui/src/vnc/client_io.rs @@ -400,7 +400,7 @@ impl ClientState { conn_state: Arc::new(Mutex::new(ConnState::default())), dirty_bitmap: Arc::new(Mutex::new(Bitmap::::new( MAX_WINDOW_HEIGHT as usize - * round_up_div(DIRTY_WIDTH_BITS as u64, u64::BITS as u64) as usize, + * round_up_div(u64::from(DIRTY_WIDTH_BITS), u64::from(u64::BITS)) as usize, ))), } } @@ -728,9 +728,9 @@ impl ClientIoHandler { let pf = self.client.client_dpm.lock().unwrap().pf.clone(); for i in 0..NUM_OF_COLORMAP { - let r = ((i >> pf.red.shift) & pf.red.max as u16) << (16 - pf.red.bits); - let g = ((i >> pf.green.shift) & pf.green.max as u16) << (16 - pf.green.bits); - let b = ((i >> pf.blue.shift) & pf.blue.max as u16) << (16 - pf.blue.bits); + let r = ((i >> pf.red.shift) & u16::from(pf.red.max)) << (16 - pf.red.bits); + let g = ((i >> pf.green.shift) & u16::from(pf.green.max)) << (16 - pf.green.bits); + let b = ((i >> pf.blue.shift) & u16::from(pf.blue.max)) << (16 - pf.blue.bits); buf.append(&mut r.to_be_bytes().to_vec()); buf.append(&mut g.to_be_bytes().to_vec()); buf.append(&mut b.to_be_bytes().to_vec()); @@ -922,10 +922,10 @@ impl ClientIoHandler { } } else { locked_state.update_state = UpdateState::Force; - let x = u16::from_be_bytes([buf[2], buf[3]]) as i32; - let y = u16::from_be_bytes([buf[4], buf[5]]) as i32; - let w = u16::from_be_bytes([buf[6], buf[7]]) as i32; - let h = u16::from_be_bytes([buf[8], buf[9]]) as i32; + let x = i32::from(u16::from_be_bytes([buf[2], buf[3]])); + let y = i32::from(u16::from_be_bytes([buf[4], buf[5]])); + let w = i32::from(u16::from_be_bytes([buf[6], buf[7]])); + let h = i32::from(u16::from_be_bytes([buf[8], buf[9]])); set_area_dirty( &mut client.dirty_bitmap.lock().unwrap(), x, @@ -992,8 +992,8 @@ impl ClientIoHandler { } let buf = self.read_incoming_msg(); - let mut x = ((buf[2] as u16) << 8) + buf[3] as u16; - let mut y = ((buf[4] as u16) << 8) + buf[5] as u16; + let mut x = (u16::from(buf[2]) << 8) + u16::from(buf[3]); + let mut y = (u16::from(buf[4]) << 8) + u16::from(buf[5]); trace::vnc_client_point_event(&buf[1], &x, &y); // Window size alignment. @@ -1001,8 +1001,8 @@ impl ClientIoHandler { let width = get_image_width(locked_surface.server_image); let height = get_image_height(locked_surface.server_image); drop(locked_surface); - x = ((x as u64 * ABS_MAX) / width as u64) as u16; - y = ((y as u64 * ABS_MAX) / height as u64) as u16; + x = ((u64::from(x) * ABS_MAX) / width as u64) as u16; + y = ((u64::from(y) * ABS_MAX) / height as u64) as u16; // ASCII -> HidCode. let new_button = buf[1]; @@ -1023,15 +1023,15 @@ impl ClientIoHandler { VNC_INPUT_BUTTON_WHEEL_RIGHT => INPUT_BUTTON_WHEEL_RIGHT, VNC_INPUT_BUTTON_WHEEL_LEFT => INPUT_BUTTON_WHEEL_LEFT, VNC_INPUT_BUTTON_BACK => INPUT_POINT_BACK, - _ => button_mask as u32, + _ => u32::from(button_mask), }; input_button(button, new_button & button_mask != 0)?; } self.client.client_dpm.lock().unwrap().last_button = new_button; } - input_move_abs(Axis::X, x as u32)?; - input_move_abs(Axis::Y, y as u32)?; + input_move_abs(Axis::X, u32::from(x))?; + input_move_abs(Axis::Y, u32::from(y))?; input_point_sync()?; self.update_event_handler(1, ClientIoHandler::handle_protocol_msg); @@ -1061,7 +1061,7 @@ impl ClientIoHandler { fn auth_failed(&mut self, msg: &str) { let auth_rej: u8 = 1; let mut buf: Vec = vec![1u8]; - buf.append(&mut (auth_rej as u32).to_be_bytes().to_vec()); + buf.append(&mut u32::from(auth_rej).to_be_bytes().to_vec()); // If the RFB protocol version is above 3.8, an error reason will be returned. if self.client.conn_state.lock().unwrap().version.minor >= 8 { let err_msg = msg; @@ -1250,17 +1250,17 @@ pub fn get_rects(client: &Arc, server: &Arc, dirty_num: } h = i - y; - x2 = cmp::min(x2, width / DIRTY_PIXELS_NUM as u64); + x2 = cmp::min(x2, width / u64::from(DIRTY_PIXELS_NUM)); if x2 > x { rects.push(Rectangle::new( - (x * DIRTY_PIXELS_NUM as u64) as i32, + (x * u64::from(DIRTY_PIXELS_NUM)) as i32, y as i32, - ((x2 - x) * DIRTY_PIXELS_NUM as u64) as i32, + ((x2 - x) * u64::from(DIRTY_PIXELS_NUM)) as i32, h as i32, )); } - if x == 0 && x2 == width / DIRTY_PIXELS_NUM as u64 { + if x == 0 && x2 == width / u64::from(DIRTY_PIXELS_NUM) { y += h; if y == height { break; @@ -1289,9 +1289,9 @@ fn pixel_format_message(client: &Arc, buf: &mut Vec) { buf.append(&mut locked_dpm.pf.depth.to_be_bytes().to_vec()); // Depth. buf.append(&mut big_endian.to_be_bytes().to_vec()); // Big-endian flag. buf.append(&mut (1_u8).to_be_bytes().to_vec()); // True-color flag. - buf.append(&mut (locked_dpm.pf.red.max as u16).to_be_bytes().to_vec()); // Red max. - buf.append(&mut (locked_dpm.pf.green.max as u16).to_be_bytes().to_vec()); // Green max. - buf.append(&mut (locked_dpm.pf.blue.max as u16).to_be_bytes().to_vec()); // Blue max. + buf.append(&mut u16::from(locked_dpm.pf.red.max).to_be_bytes().to_vec()); // Red max. + buf.append(&mut u16::from(locked_dpm.pf.green.max).to_be_bytes().to_vec()); // Green max. + buf.append(&mut u16::from(locked_dpm.pf.blue.max).to_be_bytes().to_vec()); // Blue max. buf.append(&mut locked_dpm.pf.red.shift.to_be_bytes().to_vec()); // Red shift. buf.append(&mut locked_dpm.pf.green.shift.to_be_bytes().to_vec()); // Green shift. buf.append(&mut locked_dpm.pf.blue.shift.to_be_bytes().to_vec()); // Blue shift. @@ -1416,7 +1416,7 @@ pub fn display_cursor_define( buf, ); let dpm = client.client_dpm.lock().unwrap().clone(); - let data_size = cursor.width * cursor.height * dpm.pf.pixel_bytes as u32; + let data_size = cursor.width * cursor.height * u32::from(dpm.pf.pixel_bytes); let data_ptr = cursor.data.as_ptr() as *mut u8; write_pixel(data_ptr, data_size as usize, &dpm, buf); buf.append(&mut mask); @@ -1442,7 +1442,7 @@ pub fn vnc_update_output_throttle(client: &Arc) { let width = locked_dpm.client_width; let height = locked_dpm.client_height; let bytes_per_pixel = locked_dpm.pf.pixel_bytes; - let mut offset = width * height * (bytes_per_pixel as i32) * OUTPUT_THROTTLE_SCALE; + let mut offset = width * height * i32::from(bytes_per_pixel) * OUTPUT_THROTTLE_SCALE; drop(locked_dpm); offset = cmp::max(offset, MIN_OUTPUT_LIMIT); diff --git a/ui/src/vnc/encoding/enc_hextile.rs b/ui/src/vnc/encoding/enc_hextile.rs index d6b31f69..f41a4d8c 100644 --- a/ui/src/vnc/encoding/enc_hextile.rs +++ b/ui/src/vnc/encoding/enc_hextile.rs @@ -127,7 +127,8 @@ fn compress_each_tile<'a>( &mut tmp_buf, ); // If the length becomes longer after compression, give up compression. - if tmp_buf.len() > (sub_rect.h * sub_rect.w * client_dpm.pf.pixel_bytes as i32) as usize + if tmp_buf.len() + > (sub_rect.h * sub_rect.w * i32::from(client_dpm.pf.pixel_bytes)) as usize { flag = RAW; *last_bg = None; diff --git a/ui/src/vnc/mod.rs b/ui/src/vnc/mod.rs index ff2e48c9..a760ae3b 100644 --- a/ui/src/vnc/mod.rs +++ b/ui/src/vnc/mod.rs @@ -234,10 +234,10 @@ impl DisplayChangeListenerOperations for VncInterface { return Ok(()); } let server = VNC_SERVERS.lock().unwrap()[0].clone(); - let width = cursor.width as u64; - let height = cursor.height as u64; + let width = u64::from(cursor.width); + let height = u64::from(cursor.height); trace::vnc_dpy_cursor_update(&width, &height); - let bpl = round_up_div(width, BIT_PER_BYTE as u64); + let bpl = round_up_div(width, u64::from(BIT_PER_BYTE)); // Set the bit for mask. let bit_mask: u8 = 0x80; @@ -254,7 +254,7 @@ impl DisplayChangeListenerOperations for VncInterface { let idx = ((i + j * width) as usize) * bytes_per_pixel() + first_bit; if let Some(n) = cursor.data.get(idx) { if *n == 0xff { - mask[(j * bpl + i / BIT_PER_BYTE as u64) as usize] |= bit; + mask[(j * bpl + i / u64::from(BIT_PER_BYTE)) as usize] |= bit; } } bit >>= 1; @@ -426,16 +426,16 @@ pub fn set_area_dirty( let width: i32 = vnc_width(g_w); let height: i32 = vnc_height(g_h); - w += x % DIRTY_PIXELS_NUM as i32; - x -= x % DIRTY_PIXELS_NUM as i32; + w += x % i32::from(DIRTY_PIXELS_NUM); + x -= x % i32::from(DIRTY_PIXELS_NUM); x = cmp::min(x, width); y = cmp::min(y, height); w = cmp::min(x + w, width) - x; h = cmp::min(y + h, height); while y < h { - let pos = (y * VNC_BITMAP_WIDTH as i32 + x / DIRTY_PIXELS_NUM as i32) as usize; - let len = round_up_div(w as u64, DIRTY_PIXELS_NUM as u64) as usize; + let pos = (y * VNC_BITMAP_WIDTH as i32 + x / i32::from(DIRTY_PIXELS_NUM)) as usize; + let len = round_up_div(w as u64, u64::from(DIRTY_PIXELS_NUM)) as usize; dirty.set_range(pos, len)?; y += 1; } @@ -445,14 +445,14 @@ pub fn set_area_dirty( /// Get the width of image. fn vnc_width(width: i32) -> i32 { cmp::min( - MAX_WINDOW_WIDTH as i32, - round_up(width as u64, DIRTY_PIXELS_NUM as u64) as i32, + i32::from(MAX_WINDOW_WIDTH), + round_up(width as u64, u64::from(DIRTY_PIXELS_NUM)) as i32, ) } /// Get the height of image. fn vnc_height(height: i32) -> i32 { - cmp::min(MAX_WINDOW_HEIGHT as i32, height) + cmp::min(i32::from(MAX_WINDOW_HEIGHT), height) } /// Update server image diff --git a/ui/src/vnc/server_io.rs b/ui/src/vnc/server_io.rs index ac577df1..2b290355 100644 --- a/ui/src/vnc/server_io.rs +++ b/ui/src/vnc/server_io.rs @@ -173,7 +173,7 @@ struct ImageInfo { impl ImageInfo { fn new(image: *mut pixman_image_t) -> Self { let bpp = pixman_format_bpp(get_image_format(image) as u32); - let length = get_image_width(image) * round_up_div(bpp as u64, 8) as i32; + let length = get_image_width(image) * round_up_div(u64::from(bpp), 8) as i32; ImageInfo { data: get_image_data(image) as *mut u8, stride: get_image_stride(image), @@ -310,8 +310,8 @@ impl VncSurface { guest_dirty_bitmap: Bitmap::::new( MAX_WINDOW_HEIGHT as usize * round_up_div( - (MAX_WINDOW_WIDTH / DIRTY_PIXELS_NUM) as u64, - u64::BITS as u64, + u64::from(MAX_WINDOW_WIDTH / DIRTY_PIXELS_NUM), + u64::from(u64::BITS), ) as usize, ), server_image: ptr::null_mut(), @@ -424,7 +424,7 @@ impl VncSurface { let width = self.get_min_width(); let line_bytes = cmp::min(s_info.stride, g_info.length); - while x < round_up_div(width as u64, DIRTY_PIXELS_NUM as u64) as usize { + while x < round_up_div(width as u64, u64::from(DIRTY_PIXELS_NUM)) as usize { if !self .guest_dirty_bitmap .contain(x + y * VNC_BITMAP_WIDTH as usize) diff --git a/util/src/v4l2.rs b/util/src/v4l2.rs index 1e289050..9abcfd22 100644 --- a/util/src/v4l2.rs +++ b/util/src/v4l2.rs @@ -152,7 +152,7 @@ impl V4l2Backend { ); } locked_buf[i as usize].iov_base = ret as u64; - locked_buf[i as usize].iov_len = buf.length as u64; + locked_buf[i as usize].iov_len = u64::from(buf.length); // Queue buffer to get data. self.queue_buffer(&buf)?; } -- Gitee From 8f4adb85166efd442d42535313e2f13f7eb4138d Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sun, 18 Aug 2024 07:43:46 +0800 Subject: [PATCH 282/489] block: print device id in error log Log device ID when block device IO error occurs. This is mainly used for locating unexpected error IO for micro VMs. Signed-off-by: liuxiangdong --- virtio/src/device/block.rs | 52 ++++++++++++++++++++++++++++---------- 1 file changed, 38 insertions(+), 14 deletions(-) diff --git a/virtio/src/device/block.rs b/virtio/src/device/block.rs index d07fc2bc..6e17764f 100644 --- a/virtio/src/device/block.rs +++ b/virtio/src/device/block.rs @@ -276,10 +276,12 @@ impl Request { cache: &Option, elem: &mut Element, status: &mut u8, + devid: &str, ) -> Result { if elem.out_iovec.is_empty() || elem.in_iovec.is_empty() { bail!( - "Missed header for block request: out {} in {} desc num {}", + "Missed header for block {} request: out {} in {} desc num {}", + devid, elem.out_iovec.len(), elem.in_iovec.len(), elem.desc_num @@ -332,7 +334,7 @@ impl Request { // Otherwise discard the last "status" byte. _ => iov_discard_back(&mut elem.in_iovec, 1), } - .with_context(|| "Empty data for block request")?; + .with_context(|| format!("Empty data for block {} request", devid))?; let (data_len, iovec) = gpa_hva_iovec_map(data_iovec, &handler.mem_space, cache)?; request.data_len = data_len; @@ -345,7 +347,7 @@ impl Request { } } - if !request.io_range_valid(handler.disk_sectors) { + if !request.io_range_valid(handler.disk_sectors, devid) { *status = VIRTIO_BLK_S_IOERR; } @@ -389,24 +391,40 @@ impl Request { VIRTIO_BLK_T_IN => { locked_backend .read_vectored(iovecs, offset, aiocompletecb) - .with_context(|| "Failed to process block request for reading")?; + .with_context(|| { + format!( + "Failed to process block {} request for reading", + iohandler.devid + ) + })?; } VIRTIO_BLK_T_OUT => { locked_backend .write_vectored(iovecs, offset, aiocompletecb) - .with_context(|| "Failed to process block request for writing")?; + .with_context(|| { + format!( + "Failed to process block {} request for writing", + iohandler.devid + ) + })?; } VIRTIO_BLK_T_FLUSH => { - locked_backend - .datasync(aiocompletecb) - .with_context(|| "Failed to process block request for flushing")?; + locked_backend.datasync(aiocompletecb).with_context(|| { + format!( + "Failed to process block {} request for flushing", + iohandler.devid + ) + })?; } VIRTIO_BLK_T_GET_ID => { let serial = serial_num.clone().unwrap_or_else(|| String::from("")); let serial_vec = get_serial_num_config(&serial); let status = iov_from_buf_direct(&self.iovec, &serial_vec).map_or_else( |e| { - error!("Failed to process block request for getting id, {:?}", e); + error!( + "Failed to process block {} request for getting id, {:?}", + iohandler.devid, e + ); VIRTIO_BLK_S_IOERR }, |_| VIRTIO_BLK_S_OK, @@ -504,7 +522,7 @@ impl Request { Ok(()) } - fn io_range_valid(&self, disk_sectors: u64) -> bool { + fn io_range_valid(&self, disk_sectors: u64, devid: &str) -> bool { match self.out_header.request_type { VIRTIO_BLK_T_IN | VIRTIO_BLK_T_OUT => { if self.data_len % SECTOR_SIZE != 0 { @@ -518,8 +536,8 @@ impl Request { .is_none() { error!( - "offset {} invalid, disk sector {}", - self.out_header.sector, disk_sectors + "devid {} offset {} invalid, disk sector {}", + devid, self.out_header.sector, disk_sectors ); return false; } @@ -536,6 +554,8 @@ impl Request { /// Control block of Block IO. struct BlockIoHandler { + /// Device id of this block device. + devid: String, /// The virtqueue. queue: Arc>, /// Eventfd of the virtqueue for IO event. @@ -648,7 +668,7 @@ impl BlockIoHandler { // Init and put valid request into request queue. let mut status = VIRTIO_BLK_S_OK; let cache = queue.vring.get_cache(); - let req = Request::new(self, cache, &mut elem, &mut status)?; + let req = Request::new(self, cache, &mut elem, &mut status, &self.devid)?; if status != VIRTIO_BLK_S_OK { let aiocompletecb = AioCompleteCb::new( self.queue.clone(), @@ -687,7 +707,10 @@ impl BlockIoHandler { if let Some(block_backend) = self.block_backend.as_ref() { req_rc.execute(self, block_backend.clone(), aiocompletecb)?; } else { - warn!("Failed to execute block request, block_backend not specified"); + warn!( + "Failed to execute block {} request, block_backend not specified", + &self.devid + ); aiocompletecb.complete_request(VIRTIO_BLK_S_IOERR)?; } } @@ -1235,6 +1258,7 @@ impl VirtioDevice for Block { let update_evt = Arc::new(create_new_eventfd()?); let driver_features = self.base.driver_features; let handler = BlockIoHandler { + devid: self.blk_cfg.id.clone(), queue: queue.clone(), queue_evt: queue_evts[index].clone(), mem_space: mem_space.clone(), -- Gitee From 48d94e42bb1dc0eac862dda5a196dec0d309393b Mon Sep 17 00:00:00 2001 From: Liu Wenyuan Date: Tue, 20 Aug 2024 16:17:29 +0800 Subject: [PATCH 283/489] balloon: Fix the unsafe shared reference to BALLOON_DEV The shared reference to mutable static will be hard error in the future Rust version, so Fix it. Signed-off-by: Liu Wenyuan --- virtio/src/device/balloon.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/virtio/src/device/balloon.rs b/virtio/src/device/balloon.rs index 34f241ab..b0190268 100644 --- a/virtio/src/device/balloon.rs +++ b/virtio/src/device/balloon.rs @@ -719,7 +719,7 @@ impl BalloonIoHandler { .with_context(|| "Fail to parse available descriptor chain")?; // SAFETY: There is no confliction when writing global variable BALLOON_DEV, in other // words, this function will not be called simultaneously. - if let Some(dev) = unsafe { &BALLOON_DEV } { + if let Some(dev) = unsafe { BALLOON_DEV.as_ref() } { let mut balloon_dev = dev.lock().unwrap(); for iov in req.iovec.iter() { if let Some(stat) = iov_to_buf::(&self.mem_space, iov, 0) { @@ -1218,7 +1218,7 @@ impl VirtioDevice for Balloon { pub fn qmp_balloon(target: u64) -> bool { // SAFETY: there is no confliction when writing global variable BALLOON_DEV, in other // words, this function will not be called simultaneously. - if let Some(dev) = unsafe { &BALLOON_DEV } { + if let Some(dev) = unsafe { BALLOON_DEV.as_ref() } { match dev.lock().unwrap().set_guest_memory_size(target) { Ok(()) => { return true; @@ -1236,7 +1236,7 @@ pub fn qmp_balloon(target: u64) -> bool { pub fn qmp_query_balloon() -> Option { // SAFETY: There is no confliction when writing global variable BALLOON_DEV, in other // words, this function will not be called simultaneously. - if let Some(dev) = unsafe { &BALLOON_DEV } { + if let Some(dev) = unsafe { BALLOON_DEV.as_ref() } { let unlocked_dev = dev.lock().unwrap(); return Some(unlocked_dev.get_guest_memory_size()); } -- Gitee From ab94ed10c8ac80ed9d258885ae806e77a9b82051 Mon Sep 17 00:00:00 2001 From: Liu Wenyuan Date: Tue, 20 Aug 2024 16:23:13 +0800 Subject: [PATCH 284/489] memory: Fix the memory dump madvise unsafe chain The unsafe madvise input params should be checked by the caller. Signed-off-by: Liu Wenyuan --- util/src/unix.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/util/src/unix.rs b/util/src/unix.rs index 2640d948..bf103ee3 100644 --- a/util/src/unix.rs +++ b/util/src/unix.rs @@ -125,15 +125,15 @@ pub fn do_mmap( return Err(std::io::Error::last_os_error()).with_context(|| "Mmap failed."); } if !dump_guest_core { - set_memory_undumpable(hva, len); + // SAFETY: The hva and len are mmap-ed above and are verified. + unsafe { set_memory_undumpable(hva, len) }; } Ok(hva as u64) } -fn set_memory_undumpable(host_addr: *mut libc::c_void, size: u64) { - // SAFETY: host_addr and size are valid and return value is checked. - let ret = unsafe { libc::madvise(host_addr, size as libc::size_t, libc::MADV_DONTDUMP) }; +unsafe fn set_memory_undumpable(host_addr: *mut libc::c_void, size: u64) { + let ret = libc::madvise(host_addr, size as libc::size_t, libc::MADV_DONTDUMP); if ret < 0 { error!( "Syscall madvise(with MADV_DONTDUMP) failed, OS error is {:?}", -- Gitee From 5273b470a562e1d07628495dee00c9e01899adf6 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sun, 18 Aug 2024 09:55:19 +0800 Subject: [PATCH 285/489] qcow2: fix refcount updating error when deleting snapshot When deleting snapshot, snapshot information in memory will be deleted firstly. Therefore, the size of the snapshot table in the updated memory (assuming size1) is not the size of the old snapshot table (assuming size0). If this `size1` is used to release the old snapshot table refcount, it may cause problems. For example, if there is only one snapshot and the updated size is 0, using `0` to release the old snapshot table will result in no clusters being released, causing problems with the refcount block count. Fix this problem. Signed-off-by: liuxiangdong --- block_backend/src/qcow2/mod.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/block_backend/src/qcow2/mod.rs b/block_backend/src/qcow2/mod.rs index 7c14cb98..f45cfce0 100644 --- a/block_backend/src/qcow2/mod.rs +++ b/block_backend/src/qcow2/mod.rs @@ -913,16 +913,20 @@ impl Qcow2Driver { bail!("Snapshot with name {} does not exist", name); } + // Record the old snapshot table size which will be used to free these old snapshot table clusters. + let cluster_size = self.header.cluster_size(); + let old_snapshot_table_clusters = + bytes_to_clusters(self.snapshot.snapshot_size, cluster_size).unwrap(); + // Delete snapshot information in memory. let snap = self.snapshot.del_snapshot(snapshot_idx as usize); // Alloc new cluster to save snapshots(except the deleted one) to disk. - let cluster_size = self.header.cluster_size(); let mut new_snapshots_offset = 0_u64; - let snapshot_table_clusters = + let new_snapshot_table_clusters = bytes_to_clusters(self.snapshot.snapshot_size, cluster_size).unwrap(); if self.snapshot.snapshots_number() > 0 { - new_snapshots_offset = self.alloc_cluster(snapshot_table_clusters, true)?; + new_snapshots_offset = self.alloc_cluster(new_snapshot_table_clusters, true)?; self.snapshot .save_snapshot_table(new_snapshots_offset, &snap, false)?; } @@ -952,7 +956,7 @@ impl Qcow2Driver { // Free the cluster of the old snapshot table. self.refcount.update_refcount( self.header.snapshots_offset, - snapshot_table_clusters, + old_snapshot_table_clusters, -1, false, &Qcow2DiscardType::Snapshot, -- Gitee From f2cef1820a950cd97371004fb38fa5d53c561e66 Mon Sep 17 00:00:00 2001 From: sujerry1991 Date: Thu, 22 Aug 2024 11:21:54 +0800 Subject: [PATCH 286/489] virtio: add explicit type identification for numeric literals Add explicit type identification for numeric literals in case of overflow. Signed-off-by: Yan Wang --- virtio/src/device/block.rs | 8 ++++---- virtio/src/device/net.rs | 6 +++--- virtio/src/device/serial.rs | 2 +- virtio/src/lib.rs | 2 +- virtio/src/transport/virtio_pci.rs | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/virtio/src/device/block.rs b/virtio/src/device/block.rs index 6e17764f..05541164 100644 --- a/virtio/src/device/block.rs +++ b/virtio/src/device/block.rs @@ -600,9 +600,9 @@ impl BlockIoHandler { let mut merge_req_queue = Vec::::new(); let mut last_req: Option<&mut Request> = None; - let mut merged_reqs = 0; - let mut merged_iovs = 0; - let mut merged_bytes = 0; + let mut merged_reqs: u16 = 0; + let mut merged_iovs: usize = 0; + let mut merged_bytes: u64 = 0; for req in req_queue { let req_iovs = req.iovec.len(); @@ -743,7 +743,7 @@ impl BlockIoHandler { trace::virtio_blk_process_queue_suppress_notify(len); let mut done = false; - let mut iteration = 0; + let mut iteration: u16 = 0; while self .queue diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index b3108415..16e17da1 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -223,7 +223,7 @@ impl CtrlInfo { data_iovec: &mut Vec, ) -> Result { let ack = VIRTIO_NET_OK; - let mut mac_table_len = 0; + let mut mac_table_len: usize = 0; // Default for unicast. let mut overflow = &mut self.mac_info.uni_mac_of; let mut mac_table = &mut self.mac_info.uni_mac_table; @@ -705,7 +705,7 @@ impl NetIoQueue { } let mut queue = self.rx.queue.lock().unwrap(); - let mut rx_packets = 0; + let mut rx_packets: u16 = 0; loop { let elem = queue .vring @@ -804,7 +804,7 @@ impl NetIoQueue { trace::virtio_receive_request("Net".to_string(), "to tx".to_string()); let mut queue = self.tx.queue.lock().unwrap(); - let mut tx_packets = 0; + let mut tx_packets: u16 = 0; loop { let elem = queue .vring diff --git a/virtio/src/device/serial.rs b/virtio/src/device/serial.rs index ae76f87a..37256dc7 100644 --- a/virtio/src/device/serial.rs +++ b/virtio/src/device/serial.rs @@ -193,7 +193,7 @@ impl Serial { } pub fn get_max_nr(ports: &Arc>>>>) -> u32 { - let mut max = 0; + let mut max: u32 = 0; for port in ports.lock().unwrap().iter() { let nr = port.lock().unwrap().nr; if nr > max { diff --git a/virtio/src/lib.rs b/virtio/src/lib.rs index 3245477d..40155498 100644 --- a/virtio/src/lib.rs +++ b/virtio/src/lib.rs @@ -867,7 +867,7 @@ fn gpa_hva_iovec_map( mem_space: &AddressSpace, cache: &Option, ) -> Result<(u64, Vec)> { - let mut iov_size = 0; + let mut iov_size: u64 = 0; let mut hva_iovec = Vec::with_capacity(gpa_elemiovec.len()); for elem in gpa_elemiovec.iter() { diff --git a/virtio/src/transport/virtio_pci.rs b/virtio/src/transport/virtio_pci.rs index 1bfaa2c2..00db23ee 100644 --- a/virtio/src/transport/virtio_pci.rs +++ b/virtio/src/transport/virtio_pci.rs @@ -772,7 +772,7 @@ impl VirtioPciDevice { }; let common_write = move |data: &[u8], _addr: GuestAddress, offset: u64| -> bool { - let mut value = 0; + let mut value: u32 = 0; if !read_data_u32(data, &mut value) { return false; } -- Gitee From 8d70b704b4ae45d7e0decaca3594fe3b7dccbdf7 Mon Sep 17 00:00:00 2001 From: sujerry1991 Date: Thu, 22 Aug 2024 11:27:10 +0800 Subject: [PATCH 287/489] block_backend: add explicit type identification for numeric literals Add explicit type identification for numeric literals in case of overflow. Signed-off-by: Yan Wang --- block_backend/src/qcow2/cache.rs | 2 +- block_backend/src/qcow2/check.rs | 4 ++-- block_backend/src/qcow2/mod.rs | 8 ++++---- block_backend/src/qcow2/refcount.rs | 10 +++++----- block_backend/src/qcow2/snapshot.rs | 4 ++-- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/block_backend/src/qcow2/cache.rs b/block_backend/src/qcow2/cache.rs index 245bbe67..e54739f8 100644 --- a/block_backend/src/qcow2/cache.rs +++ b/block_backend/src/qcow2/cache.rs @@ -190,7 +190,7 @@ impl Qcow2Cache { ) -> Option>> { let mut replaced_entry: Option>> = None; let mut lru_count = u64::MAX; - let mut target_idx = 0; + let mut target_idx: u64 = 0; self.check_refcount(); entry.borrow_mut().lru_count = self.lru_count; self.lru_count += 1; diff --git a/block_backend/src/qcow2/check.rs b/block_backend/src/qcow2/check.rs index 35e4f350..4313111a 100644 --- a/block_backend/src/qcow2/check.rs +++ b/block_backend/src/qcow2/check.rs @@ -321,7 +321,7 @@ impl Qcow2Driver { if check.res.need_rebuild && check.fix & FIX_ERRORS != 0 { let old_res = check.res; - let mut fresh_leak = 0; + let mut fresh_leak: i32 = 0; output_msg!(check.quite, "Rebuilding refcount structure"); self.rebuild_refcount_structure(check)?; @@ -874,7 +874,7 @@ impl Qcow2Driver { } } - let mut num_repaired = 0; + let mut num_repaired: i32 = 0; let l2_buf = self.load_cluster(l2_offset)?; let l2_table = Rc::new(RefCell::new(CacheTable::new( l2_offset, diff --git a/block_backend/src/qcow2/mod.rs b/block_backend/src/qcow2/mod.rs index f45cfce0..308a7778 100644 --- a/block_backend/src/qcow2/mod.rs +++ b/block_backend/src/qcow2/mod.rs @@ -390,9 +390,9 @@ impl Qcow2Driver { expect_len ); } - let mut host_start = 0; + let mut host_start: u64 = 0; let mut first_cluster_type = Qcow2ClusterType::Unallocated; - let mut cnt = 0; + let mut cnt: u64 = 0; while cnt < clusters { let offset = cnt * self.header.cluster_size(); let l2_entry = self.get_l2_entry(begin + offset)?; @@ -1694,7 +1694,7 @@ impl BlockDriverOps for Qcow2Driver { let mut left = iovec; let mut req_list: Vec = Vec::new(); - let mut copied = 0; + let mut copied: u64 = 0; while copied < nbytes { let pos = offset as u64 + copied; match self.host_offset_for_read(pos, nbytes - copied) { @@ -1731,7 +1731,7 @@ impl BlockDriverOps for Qcow2Driver { trace::block_write_vectored(&self.driver.block_prop.id, offset, nbytes); let mut req_list: Vec = Vec::new(); - let mut copied = 0; + let mut copied: u64 = 0; while copied < nbytes { let pos = offset as u64 + copied; let count = self.cluster_aligned_bytes(pos, nbytes - copied); diff --git a/block_backend/src/qcow2/refcount.rs b/block_backend/src/qcow2/refcount.rs index 7c60ce31..6e403da5 100644 --- a/block_backend/src/qcow2/refcount.rs +++ b/block_backend/src/qcow2/refcount.rs @@ -151,7 +151,7 @@ impl RefCount { } let nb_clusters = bytes_to_clusters(size, self.cluster_size).unwrap(); - let mut free_clusters = 0; + let mut free_clusters: u64 = 0; while free_clusters < nb_clusters { let offset = self.free_cluster_index << self.cluster_bits; self.free_cluster_index += 1; @@ -327,7 +327,7 @@ impl RefCount { } let first_cluster = bytes_to_clusters(offset, self.cluster_size).unwrap(); let mut rc_vec: Vec<(u64, u64, usize)> = Vec::with_capacity(clusters as usize); - let mut i = 0; + let mut i: u64 = 0; while i < clusters { let rt_idx = (first_cluster + i) >> self.refcount_blk_bits; if rt_idx >= self.refcount_table_size { @@ -669,11 +669,11 @@ pub fn refcount_metadata_size( ) -> Result<(u64, u64)> { let reftable_entries = cluster_size / ENTRY_SIZE; let refblock_entries = cluster_size * 8 / (1 << refcount_order); - let mut table = 0; - let mut blocks = 0; + let mut table: u64 = 0; + let mut blocks: u64 = 0; let mut clusters = nb_clusters; let mut last_clusters; - let mut total_clusters = 0; + let mut total_clusters: u64 = 0; loop { last_clusters = total_clusters; diff --git a/block_backend/src/qcow2/snapshot.rs b/block_backend/src/qcow2/snapshot.rs index 7a858e59..9e8345d5 100644 --- a/block_backend/src/qcow2/snapshot.rs +++ b/block_backend/src/qcow2/snapshot.rs @@ -85,7 +85,7 @@ impl InternalSnapshot { } pub fn find_new_snapshot_id(&self) -> u64 { - let mut id_max = 0; + let mut id_max: u64 = 0; for snap in &self.snapshots { if id_max < snap.id { id_max = snap.id; @@ -139,7 +139,7 @@ impl InternalSnapshot { for i in 0..nb_snapshots { let offset = addr + self.snapshot_size; - let mut pos = 0; + let mut pos: usize = 0; let header_size = size_of::(); let mut header_buf = vec![0_u8; header_size]; self.sync_aio -- Gitee From c3affa0ee29452f0fa7be4b11e406b682728e4f7 Mon Sep 17 00:00:00 2001 From: sujerry1991 Date: Thu, 22 Aug 2024 11:34:14 +0800 Subject: [PATCH 288/489] util: add explicit type identification for numeric literals Add explicit type identification for numeric literals in case of overflow. Signed-off-by: Yan Wang --- util/src/aio/mod.rs | 2 +- util/src/aio/raw.rs | 2 +- util/src/arg_parser.rs | 4 ++-- util/src/bitmap.rs | 2 +- util/src/file.rs | 4 ++-- util/src/loop_context.rs | 4 ++-- util/src/num_ops.rs | 2 +- util/src/tap.rs | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/util/src/aio/mod.rs b/util/src/aio/mod.rs index cc666f23..56a142c8 100644 --- a/util/src/aio/mod.rs +++ b/util/src/aio/mod.rs @@ -133,7 +133,7 @@ impl Iovec { } pub fn get_iov_size(iovecs: &[Iovec]) -> u64 { - let mut sum = 0; + let mut sum: u64 = 0; for iov in iovecs { sum += iov.iov_len; } diff --git a/util/src/aio/raw.rs b/util/src/aio/raw.rs index 4654a7c0..c376e5e0 100644 --- a/util/src/aio/raw.rs +++ b/util/src/aio/raw.rs @@ -171,7 +171,7 @@ fn do_fallocate( offset: u64, size: u64, ) -> i32 { - let mut ret = 0; + let mut ret: i32 = 0; loop { let mode = match &fallocate_mode { FallocateMode::PunchHole => FallocateMode::PunchHole, diff --git a/util/src/arg_parser.rs b/util/src/arg_parser.rs index 9ab97169..e92f052a 100644 --- a/util/src/arg_parser.rs +++ b/util/src/arg_parser.rs @@ -626,8 +626,8 @@ fn parse_cmdline( let mut arg_map: BTreeMap> = BTreeMap::new(); let mut multi_vec: Vec = Vec::new(); - let mut i = (0, ""); - let mut j = 1; + let mut i: (usize, &str) = (0, ""); + let mut j: usize = 1; for cmd_arg in &cmd_args[1..] { if !allow_list.contains(cmd_arg) && cmd_arg.starts_with(PREFIX_CHARS_SHORT) diff --git a/util/src/bitmap.rs b/util/src/bitmap.rs index ae6afeb2..128a286c 100644 --- a/util/src/bitmap.rs +++ b/util/src/bitmap.rs @@ -255,7 +255,7 @@ impl Bitmap { self.size() as u64 ))); } - let mut num = 0; + let mut num: usize = 0; for i in 0..self.bit_index(offset) + 1 { if i == self.bit_index(offset) { for j in i * T::len()..offset { diff --git a/util/src/file.rs b/util/src/file.rs index fd06c78e..bacce3db 100644 --- a/util/src/file.rs +++ b/util/src/file.rs @@ -67,8 +67,8 @@ pub fn get_file_alignment(file: &File, direct: bool) -> (u32, u32) { return (1, 1); } - let mut req_align = 0; - let mut buf_align = 0; + let mut req_align: u32 = 0; + let mut buf_align: u32 = 0; // SAFETY: we allocate aligned memory and free it later. let aligned_buffer = unsafe { libc::memalign( diff --git a/util/src/loop_context.rs b/util/src/loop_context.rs index ced2af40..42c94c5f 100644 --- a/util/src/loop_context.rs +++ b/util/src/loop_context.rs @@ -296,7 +296,7 @@ impl EventLoopContext { fn clear_gc(&mut self) { let max_cnt = self.gc.write().unwrap().len(); - let mut pop_cnt = 0; + let mut pop_cnt: usize = 0; loop { // Loop to avoid hold lock for long time. @@ -640,7 +640,7 @@ impl EventLoopContext { /// Call function of the timers which have already expired. pub fn run_timers(&mut self) { let now = get_current_time(); - let mut expired_nr = 0; + let mut expired_nr: usize = 0; let mut timers = self.timers.lock().unwrap(); for timer in timers.iter() { diff --git a/util/src/num_ops.rs b/util/src/num_ops.rs index 558f57bf..da9a6e99 100644 --- a/util/src/num_ops.rs +++ b/util/src/num_ops.rs @@ -451,7 +451,7 @@ int_trait_impl!(Num for u8 u16 usize); /// assert!(value == 17); /// ``` pub fn str_to_num(s: &str) -> Result { - let mut base = 10; + let mut base: u32 = 10; if s.starts_with("0x") || s.starts_with("0X") { base = 16; } diff --git a/util/src/tap.rs b/util/src/tap.rs index a523873e..55c98a93 100644 --- a/util/src/tap.rs +++ b/util/src/tap.rs @@ -115,7 +115,7 @@ impl Tap { )); } - let mut features = 0; + let mut features: u16 = 0; // SAFETY: The parameter of file can be guaranteed to be legal, and other parameters are constant. let ret = unsafe { ioctl_with_mut_ref(&file, TUNGETFEATURES(), &mut features) }; if ret < 0 { -- Gitee From 446edca4fcc27ba71b0b49dd7de99133212fb96a Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Thu, 22 Aug 2024 19:17:23 +0800 Subject: [PATCH 289/489] machine_manager: Remove unnecessary cast Signed-off-by: Keqian Zhu --- machine_manager/src/config/machine_config.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/machine_manager/src/config/machine_config.rs b/machine_manager/src/config/machine_config.rs index 96ce5a11..3d277ba1 100644 --- a/machine_manager/src/config/machine_config.rs +++ b/machine_manager/src/config/machine_config.rs @@ -436,13 +436,13 @@ impl VmConfig { SmpConfig::try_parse_from(str_slip_to_clap(cpu_config, !has_cpus_label, false))?; smp_cfg.auto_adjust_topology()?; - self.machine_config.nr_cpus = smp_cfg.cpus as u8; - self.machine_config.nr_threads = smp_cfg.threads as u8; - self.machine_config.nr_cores = smp_cfg.cores as u8; - self.machine_config.nr_dies = smp_cfg.dies as u8; - self.machine_config.nr_clusters = smp_cfg.clusters as u8; - self.machine_config.nr_sockets = smp_cfg.sockets as u8; - self.machine_config.max_cpus = smp_cfg.maxcpus as u8; + self.machine_config.nr_cpus = smp_cfg.cpus; + self.machine_config.nr_threads = smp_cfg.threads; + self.machine_config.nr_cores = smp_cfg.cores; + self.machine_config.nr_dies = smp_cfg.dies; + self.machine_config.nr_clusters = smp_cfg.clusters; + self.machine_config.nr_sockets = smp_cfg.sockets; + self.machine_config.max_cpus = smp_cfg.maxcpus; Ok(()) } -- Gitee From 5710b8ef89b5a7c90cd181434469cefbdd1540fa Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sun, 18 Aug 2024 18:59:45 +0800 Subject: [PATCH 290/489] xhci: fix altsetting/interfaces array overflows problem Converting nif/alt to u8 causes truncation, which only compares the lower eight bits, resulting in misjudgment. If nif is returned in this way, assuming that the higher bits of nif is non-zero, it will cause array descriptor.altsetting/descriptor.interfaces overflow in function `set_interface_descriptor`. Fix it. Signed-off-by: liuxiangdong --- devices/src/usb/descriptor.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/devices/src/usb/descriptor.rs b/devices/src/usb/descriptor.rs index 0f56753b..956dc3e9 100644 --- a/devices/src/usb/descriptor.rs +++ b/devices/src/usb/descriptor.rs @@ -407,8 +407,8 @@ impl UsbDescriptor { for i in 0..conf.iad_desc.len() { let ifaces = &conf.iad_desc[i].as_ref().itfs; for iface in ifaces { - if iface.interface_desc.bInterfaceNumber == nif as u8 - && iface.interface_desc.bAlternateSetting == alt as u8 + if u32::from(iface.interface_desc.bInterfaceNumber) == nif + && u32::from(iface.interface_desc.bAlternateSetting) == alt { return Some(iface.clone()); } @@ -416,8 +416,8 @@ impl UsbDescriptor { } for i in 0..conf.interfaces.len() { let iface = conf.interfaces[i].as_ref(); - if iface.interface_desc.bInterfaceNumber == nif as u8 - && iface.interface_desc.bAlternateSetting == alt as u8 + if u32::from(iface.interface_desc.bInterfaceNumber) == nif + && u32::from(iface.interface_desc.bAlternateSetting) == alt { return Some(conf.interfaces[i].clone()); } -- Gitee From 24505170dbb549d4b1cbc5f0df2ca2f696fba7c8 Mon Sep 17 00:00:00 2001 From: sujerry1991 Date: Fri, 23 Aug 2024 15:04:00 +0800 Subject: [PATCH 291/489] virtio: add note for unchecked arithmetic operations Add note for unchecked arithmetic operations to indicate that it is safe. Signed-off-by: Yan Wang --- virtio/src/lib.rs | 4 ++++ virtio/src/queue/mod.rs | 2 ++ virtio/src/queue/split.rs | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/virtio/src/lib.rs b/virtio/src/lib.rs index 40155498..6d4e8805 100644 --- a/virtio/src/lib.rs +++ b/virtio/src/lib.rs @@ -819,6 +819,8 @@ pub fn iov_to_buf( let mut start: usize = 0; let mut end: usize = 0; + // Note: iovec is part of elem.in_iovec/out_iovec which has been checked + // in pop_avail(). The sum of iov_len is not greater than u32::MAX. for iov in iovec { let mut addr_map = Vec::new(); mem_space.get_address_map(cache, iov.addr, u64::from(iov.len), &mut addr_map)?; @@ -870,6 +872,8 @@ fn gpa_hva_iovec_map( let mut iov_size: u64 = 0; let mut hva_iovec = Vec::with_capacity(gpa_elemiovec.len()); + // Note: gpa_elemiovec is part of elem.in_iovec/out_iovec which has been checked + // in pop_avail(). The sum of iov_len is not greater than u32::MAX. for elem in gpa_elemiovec.iter() { mem_space.get_address_map(cache, elem.addr, u64::from(elem.len), &mut hva_iovec)?; iov_size += u64::from(elem.len); diff --git a/virtio/src/queue/mod.rs b/virtio/src/queue/mod.rs index 93d95044..d226cd70 100644 --- a/virtio/src/queue/mod.rs +++ b/virtio/src/queue/mod.rs @@ -91,6 +91,8 @@ impl Element { pub fn iovec_size(iovec: &[ElemIovec]) -> u64 { let mut size: u64 = 0; for elem in iovec.iter() { + // Note: iovec is part of elem.in_iovec/out_iovec which has been checked + // in pop_avail(). The sum of iov_len is not greater than u32::MAX. size += u64::from(elem.len); } size diff --git a/virtio/src/queue/split.rs b/virtio/src/queue/split.rs index 58f8250a..092df0e1 100644 --- a/virtio/src/queue/split.rs +++ b/virtio/src/queue/split.rs @@ -437,6 +437,10 @@ impl SplitVringDesc { elem.out_iovec.push(iovec); } elem.desc_num += 1; + // Note: iovec.addr + iovec.len is located in RAM, and iovec.len is not greater than the + // VM RAM size. The number of iovec is not greater than 'queue_size * 2 - 1' which with + // a indirect table. Currently, the max value of queue_size is 1024. So, desc_total_len + // must not overflow. desc_total_len += u64::from(iovec.len); if desc.has_next() { -- Gitee From f8cce6838412ebce8073d75434b87f25e16e8432 Mon Sep 17 00:00:00 2001 From: zhanghan64 Date: Tue, 20 Aug 2024 10:14:43 +0800 Subject: [PATCH 292/489] OHUI/OHAUDIO/OHCAM: do safety check before unsafe block Do safety check before unsafe block. Signed-off-by: zhanghan64 --- devices/src/camera_backend/ohcam.rs | 4 +++ devices/src/misc/scream/ohaudio.rs | 10 ++++++ ui/src/ohui_srv/mod.rs | 56 +++++++++++++++++++---------- 3 files changed, 51 insertions(+), 19 deletions(-) diff --git a/devices/src/camera_backend/ohcam.rs b/devices/src/camera_backend/ohcam.rs index a67b7898..bf5d8ee9 100755 --- a/devices/src/camera_backend/ohcam.rs +++ b/devices/src/camera_backend/ohcam.rs @@ -340,6 +340,10 @@ impl CameraBackend for OhCameraBackend { .with_context(|| "Invalid camid in callback table")? .get_buffer(); + if src.is_none() || src.unwrap() == 0 { + bail!("Invalid frame src") + } + if src_len == 0_u64 { bail!("Invalid frame src_len {}", src_len); } diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index d6badff8..d746eecf 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -396,6 +396,11 @@ extern "C" fn on_write_data_cb( buffer: *mut ::std::os::raw::c_void, length: i32, ) -> i32 { + if buffer.is_null() || user_data.is_null() { + error!("on_write_data_cb: Invalid input"); + return 0; + } + // SAFETY: we make sure that it is OhAudioRender when register callback. let render = unsafe { (user_data as *mut OhAudioRender) @@ -426,6 +431,11 @@ extern "C" fn on_read_data_cb( buffer: *mut ::std::os::raw::c_void, length: i32, ) -> i32 { + if buffer.is_null() || user_data.is_null() { + error!("on_read_data_cb: Invalid input"); + return 0; + } + // SAFETY: we make sure that it is OhAudioCapture when register callback. let capture = unsafe { (user_data as *mut OhAudioCapture) diff --git a/ui/src/ohui_srv/mod.rs b/ui/src/ohui_srv/mod.rs index 6f13d6b0..8370c5b5 100755 --- a/ui/src/ohui_srv/mod.rs +++ b/ui/src/ohui_srv/mod.rs @@ -24,7 +24,7 @@ use std::sync::{ Arc, Mutex, RwLock, }; -use anyhow::{anyhow, Result}; +use anyhow::{anyhow, bail, Result}; use log::{error, info}; use once_cell::sync::OnceCell; use vmm_sys_util::epoll::EventSet; @@ -213,7 +213,8 @@ impl OhUiServer { self.msg_handler.handle_msg(self.token_id.clone()) } - fn raw_update_dirty_area( + // check dirty area data before call it. + unsafe fn raw_update_dirty_area( &self, surface_data: *mut u32, stride: i32, @@ -224,7 +225,10 @@ impl OhUiServer { let (x, y) = pos; let (w, h) = size; - if self.framebuffer == 0 || (!force_copy && *self.passthru.get_or_init(|| false)) { + if self.framebuffer == 0 + || surface_data.is_null() + || (!force_copy && *self.passthru.get_or_init(|| false)) + { return; } @@ -293,13 +297,16 @@ impl DisplayChangeListenerOperations for OhUiServer { locked_surface.height = surface.height(); drop(locked_surface); let locked_surface = self.surface.read().unwrap(); - self.raw_update_dirty_area( - get_image_data(locked_surface.guest_image), - locked_surface.stride, - (0, 0), - (locked_surface.width, locked_surface.height), - true, - ); + // SAFETY: Dirty area does not exceed surface buffer. + unsafe { + self.raw_update_dirty_area( + get_image_data(locked_surface.guest_image), + locked_surface.stride, + (0, 0), + (locked_surface.width, locked_surface.height), + true, + ) + }; if !self.connected() { return Ok(()); @@ -325,13 +332,24 @@ impl DisplayChangeListenerOperations for OhUiServer { return Ok(()); } - self.raw_update_dirty_area( - get_image_data(locked_surface.guest_image), - locked_surface.stride, - (x, y), - (w, h), - false, - ); + if locked_surface.width < x + || locked_surface.height < y + || locked_surface.width < x.saturating_add(w) + || locked_surface.height < y.saturating_add(h) + { + bail!("dpy_image_update: invalid dirty area"); + } + + // SAFETY: We checked dirty area data before. + unsafe { + self.raw_update_dirty_area( + get_image_data(locked_surface.guest_image), + locked_surface.stride, + (x, y), + (w, h), + false, + ) + }; self.msg_handler .handle_dirty_area(x as u32, y as u32, w as u32, h as u32); @@ -346,13 +364,13 @@ impl DisplayChangeListenerOperations for OhUiServer { } let len = cursor.width * cursor.height * size_of::() as u32; - if len > CURSOR_SIZE as u32 { + if len > CURSOR_SIZE as u32 || len > cursor.data.len().try_into()? { error!("Too large cursor length {}.", len); // No need to return Err for this situation is not fatal return Ok(()); } - // SAFETY: len is checked before copying,it's safe to do this. + // SAFETY: len is checked before copying, it's safe to do this. unsafe { ptr::copy_nonoverlapping( cursor.data.as_ptr(), -- Gitee From 34355d15881e4626211902acca1eb9651fae26a1 Mon Sep 17 00:00:00 2001 From: Li Huachao Date: Wed, 21 Aug 2024 11:40:12 +0800 Subject: [PATCH 293/489] Memory: Numeric literals need to ne explicitly typed part2 --- address_space/src/region.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/address_space/src/region.rs b/address_space/src/region.rs index 52e5f43f..5d908db0 100644 --- a/address_space/src/region.rs +++ b/address_space/src/region.rs @@ -201,7 +201,7 @@ macro_rules! rw_multi_ops { let offset = $args.offset; let cnt = $args.count; let access_size = $args.access_size; - let mut pos = 0; + let mut pos = 0_u64; for _ in 0..(cnt / access_size) { if !$ops( &mut $slice[pos as usize..(pos + access_size) as usize], -- Gitee From c9a283c284f0ea1f31c2fb8f119251b9ea034c3e Mon Sep 17 00:00:00 2001 From: Li Huachao Date: Wed, 21 Aug 2024 12:40:00 +0800 Subject: [PATCH 294/489] Memory: arithmetic conversion enhance. --- address_space/src/address.rs | 1 + address_space/src/host_mmap.rs | 5 +++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/address_space/src/address.rs b/address_space/src/address.rs index 6fd1a8dc..94a79162 100644 --- a/address_space/src/address.rs +++ b/address_space/src/address.rs @@ -175,6 +175,7 @@ impl AddressRange { return None; } let start = std::cmp::max(self.base, other.base); + // SAFETY: The range of a region will not exceed 64 bits. let size_inter = (std::cmp::min(end, other_end) - u128::from(start.0)) as u64; Some(AddressRange { diff --git a/address_space/src/host_mmap.rs b/address_space/src/host_mmap.rs index c4b8ce17..fa807a80 100644 --- a/address_space/src/host_mmap.rs +++ b/address_space/src/host_mmap.rs @@ -30,7 +30,7 @@ use util::{ unix::{do_mmap, host_page_size}, }; -const MAX_PREALLOC_THREAD: u8 = 16; +const MAX_PREALLOC_THREAD: i64 = 16; /// Verify existing pages in the mapping. const MPOL_MF_STRICT: u32 = 1; /// Move pages owned by this process to conform to mapping. @@ -171,7 +171,8 @@ fn max_nr_threads(nr_vcpus: u8) -> u8 { return 1; } - min(min(nr_host_cpu as u8, MAX_PREALLOC_THREAD), nr_vcpus) + // MAX_PREALLOC_THREAD's value(16) is less than 255. + min(min(nr_host_cpu, MAX_PREALLOC_THREAD) as u8, nr_vcpus) } /// Touch pages to pre-alloc memory for VM. -- Gitee From 1909c39a42609f72b5413fd22de0a498ab5d6111 Mon Sep 17 00:00:00 2001 From: Li Huachao Date: Thu, 22 Aug 2024 09:37:35 +0800 Subject: [PATCH 295/489] Use iterators instead of subscript traversals --- virtio/src/device/balloon.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/virtio/src/device/balloon.rs b/virtio/src/device/balloon.rs index b0190268..22462a79 100644 --- a/virtio/src/device/balloon.rs +++ b/virtio/src/device/balloon.rs @@ -458,17 +458,17 @@ impl BlnMemInfo { fn get_host_address(&self, addr: GuestAddress) -> Option<(u64, bool)> { let all_regions = self.regions.lock().unwrap(); - for i in 0..all_regions.len() { - if addr.raw_value() < all_regions[i].guest_phys_addr + all_regions[i].memory_size - && addr.raw_value() >= all_regions[i].guest_phys_addr + for region in all_regions.iter() { + if addr.raw_value() < region.guest_phys_addr + region.memory_size + && addr.raw_value() >= region.guest_phys_addr { return Some(( - all_regions[i].userspace_addr + addr.raw_value() - - all_regions[i].guest_phys_addr, - all_regions[i].mem_share, + region.userspace_addr + addr.raw_value() - region.guest_phys_addr, + region.mem_share, )); } } + None } -- Gitee From 4af34addc0856232279bc7f1503c3dba8e960e19 Mon Sep 17 00:00:00 2001 From: Li Huachao Date: Thu, 22 Aug 2024 13:09:08 +0800 Subject: [PATCH 296/489] PFlash: Dada type specification rectification --- devices/src/legacy/pflash.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devices/src/legacy/pflash.rs b/devices/src/legacy/pflash.rs index 67d8aacb..a5c16ccd 100644 --- a/devices/src/legacy/pflash.rs +++ b/devices/src/legacy/pflash.rs @@ -861,7 +861,7 @@ impl SysBusDevOps for PFlash { } fn write(&mut self, data: &[u8], _base: GuestAddress, offset: u64) -> bool { - let mut value = 0; + let mut value = 0_u32; if !read_data_u32(data, &mut value) { return false; } -- Gitee From dbff1f527505a5064df829080e6f89c7633b328b Mon Sep 17 00:00:00 2001 From: Fan Xuan Zhe Date: Fri, 23 Aug 2024 16:02:24 +0800 Subject: [PATCH 297/489] usb_host: Free a list of libusb_pollfd structures to avoid memory leak All pollfd lists allocated with libusb_get_pollfds() should be freed by calling libusb_free_pollfds() to avoid memory leak. Signed-off-by: Fan Xuan Zhe fanxuanzhe@huawei.com --- Cargo.lock | 4 ++-- devices/Cargo.toml | 2 +- devices/src/usb/usbhost/host_usblib.rs | 8 +++++++- devices/src/usb/usbhost/mod.rs | 3 +++ 4 files changed, 13 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 9453a417..36c8f841 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -936,9 +936,9 @@ dependencies = [ [[package]] name = "libusb1-sys" -version = "0.6.4" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d0e2afce4245f2c9a418511e5af8718bcaf2fa408aefb259504d1a9cb25f27" +checksum = "17f6bace2f39082e9787c851afce469e7b2fe0f1cc64bbc68ca96653b63d8f17" dependencies = [ "cc", "libc", diff --git a/devices/Cargo.toml b/devices/Cargo.toml index d411cc5c..932a0cdd 100644 --- a/devices/Cargo.toml +++ b/devices/Cargo.toml @@ -35,7 +35,7 @@ pulse = { version = "2.27", package = "libpulse-binding", optional = true } psimple = { version = "2.27", package = "libpulse-simple-binding", optional = true } alsa = { version = "0.7.0", optional = true } rusb = { version = "0.9", optional = true } -libusb1-sys = { version = "0.6.4", optional = true } +libusb1-sys = { version = "0.6.5", optional = true } trace = { path = "../trace" } clap = { version = "=4.1.4", default-features = false, features = ["std", "derive"] } hisysevent = { path = "../hisysevent" } diff --git a/devices/src/usb/usbhost/host_usblib.rs b/devices/src/usb/usbhost/host_usblib.rs index 91376074..8807909b 100644 --- a/devices/src/usb/usbhost/host_usblib.rs +++ b/devices/src/usb/usbhost/host_usblib.rs @@ -27,7 +27,8 @@ use libusb1_sys::{ LIBUSB_TRANSFER_COMPLETED, LIBUSB_TRANSFER_ERROR, LIBUSB_TRANSFER_NO_DEVICE, LIBUSB_TRANSFER_STALL, LIBUSB_TRANSFER_TIMED_OUT, LIBUSB_TRANSFER_TYPE_ISOCHRONOUS, }, - libusb_get_pollfds, libusb_iso_packet_descriptor, libusb_pollfd, libusb_transfer, + libusb_free_pollfds, libusb_get_pollfds, libusb_iso_packet_descriptor, libusb_pollfd, + libusb_transfer, }; use log::error; use rusb::{Context, DeviceHandle, Error, Result, TransferType, UsbContext}; @@ -121,6 +122,11 @@ pub fn get_libusb_pollfds(usbhost: Arc>) -> *const *mut libusb_po unsafe { libusb_get_pollfds(usbhost.lock().unwrap().context.as_raw()) } } +pub unsafe fn free_libusb_pollfds(pollfds: *const *mut libusb_pollfd) { + // Pollfds should be guaranteed to be valid. + libusb_free_pollfds(pollfds) +} + pub fn set_pollfd_notifiers( poll: *const *mut libusb_pollfd, notifiers: &mut Vec, diff --git a/devices/src/usb/usbhost/mod.rs b/devices/src/usb/usbhost/mod.rs index 62a2382e..4bf1325e 100644 --- a/devices/src/usb/usbhost/mod.rs +++ b/devices/src/usb/usbhost/mod.rs @@ -1044,6 +1044,9 @@ impl EventNotifierHelper for UsbHost { set_pollfd_notifiers(poll, &mut notifiers, handler); + // SAFETY: pointer of pollfds acquired from libusb_get_pollfds is guaranteed to be valid. + unsafe { free_libusb_pollfds(poll) }; + notifiers } } -- Gitee From 1709fe21e60e50eac7b47ebb37474e2e98380ff5 Mon Sep 17 00:00:00 2001 From: Fan Xuan Zhe Date: Fri, 23 Aug 2024 17:01:56 +0800 Subject: [PATCH 298/489] usb_host: Close the related fd when unrealize usb_host device After unrealizing the USB pass-through device, add processing logic to close the corresponding file descriptor. Signed-off-by: Fan Xuan Zhe fanxuanzhe@huawei.com --- devices/src/usb/usbhost/mod.rs | 2 +- devices/src/usb/usbhost/ohusb.rs | 58 +++++++++++++++----------------- 2 files changed, 28 insertions(+), 32 deletions(-) diff --git a/devices/src/usb/usbhost/mod.rs b/devices/src/usb/usbhost/mod.rs index 4bf1325e..b58c8d1b 100644 --- a/devices/src/usb/usbhost/mod.rs +++ b/devices/src/usb/usbhost/mod.rs @@ -422,7 +422,7 @@ unsafe impl Send for UsbHost {} impl UsbHost { pub fn new(config: UsbHostConfig) -> Result { #[cfg(all(target_arch = "aarch64", target_env = "ohos"))] - let oh_dev = OhUsbDev::new()?; + let oh_dev = OhUsbDev::new(config.hostbus, config.hostaddr)?; let mut context = Context::new()?; context.set_log_level(rusb::LogLevel::None); diff --git a/devices/src/usb/usbhost/ohusb.rs b/devices/src/usb/usbhost/ohusb.rs index 469a17a0..0e56acef 100644 --- a/devices/src/usb/usbhost/ohusb.rs +++ b/devices/src/usb/usbhost/ohusb.rs @@ -10,12 +10,13 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use std::os::fd::AsRawFd; +use std::fs::File; +use std::os::unix::io::{AsRawFd, FromRawFd}; use std::ptr; use anyhow::{bail, Context as anyhowContext, Result}; use libusb1_sys::constants::LIBUSB_OPTION_NO_DEVICE_DISCOVERY; -use log::{error, info}; +use log::info; use rusb::{Context, DeviceHandle, UsbContext}; use super::host_usblib::set_option; @@ -23,53 +24,48 @@ use super::{check_device_valid, UsbHostConfig}; use util::ohos_binding::usb::*; pub struct OhUsbDev { - dev: OhusbDevice, + #[allow(dead_code)] lib: OhUsb, -} - -impl Drop for OhUsbDev { - fn drop(&mut self) { - if let Err(e) = self.lib.close_device(ptr::addr_of_mut!(self.dev)) { - error!("Failed to close usb device with error {:?}", e) - } - } + dev_file: File, } impl OhUsbDev { - pub fn new() -> Result { + pub fn new(bus_num: u8, dev_addr: u8) -> Result { // In combination with libusb_wrap_sys_device(), in order to access a device directly without prior device scanning on ohos. set_option(LIBUSB_OPTION_NO_DEVICE_DISCOVERY)?; - Ok(Self { - dev: OhusbDevice { - busNum: u8::MAX, - devAddr: u8::MAX, - fd: -1, - }, - lib: OhUsb::new()?, - }) - } - - pub fn open(&mut self, cfg: UsbHostConfig, ctx: Context) -> Result> { - self.dev.busNum = cfg.hostbus; - self.dev.devAddr = cfg.hostaddr; + let mut ohusb_dev = OhusbDevice { + busNum: bus_num, + devAddr: dev_addr, + fd: -1, + }; - match self.lib.open_device(ptr::addr_of_mut!(self.dev))? { + let lib = OhUsb::new()?; + match lib.open_device(ptr::addr_of_mut!(ohusb_dev))? { 0 => { - if self.dev.fd < 0 { + if ohusb_dev.fd < 0 { bail!( "Failed to open usb device due to invalid fd {}", - self.dev.fd + ohusb_dev.fd ); } } _ => bail!("Failed to open usb device"), } - info!("OH USB: open_device: returned fd is {}", self.dev.fd); + info!("OH USB: open_device: returned fd is {}", ohusb_dev.fd); - // SAFETY: fd is valid. + Ok(Self { + lib, + // SAFETY: fd is passed from OH USB framework and we have checked the function return value. + // Now let's save it to rust File struct. + dev_file: unsafe { File::from_raw_fd(ohusb_dev.fd) }, + }) + } + + pub fn open(&mut self, cfg: UsbHostConfig, ctx: Context) -> Result> { + // SAFETY: The validation of fd is guaranteed by new function. let handle = unsafe { - ctx.open_device_with_fd(self.dev.fd.as_raw_fd()) + ctx.open_device_with_fd(self.dev_file.as_raw_fd()) .with_context(|| format!("os last error: {:?}", std::io::Error::last_os_error()))? }; -- Gitee From e1371620b7b4943a7eb68d659a1ffa7d771ec51a Mon Sep 17 00:00:00 2001 From: Fan Xuan Zhe Date: Fri, 23 Aug 2024 17:13:09 +0800 Subject: [PATCH 299/489] usb_host: Marked the numerical literals in usb_host with specific types Solve the problem that numerical literals in usb_host are not marked with specific types to prevent problems caused by inconsistent inference results on different platforms. Signed-off-by: Fan Xuan Zhe fanxuanzhe@huawei.com --- devices/src/usb/usbhost/host_usblib.rs | 2 +- devices/src/usb/usbhost/mod.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/devices/src/usb/usbhost/host_usblib.rs b/devices/src/usb/usbhost/host_usblib.rs index 8807909b..2f6bc88f 100644 --- a/devices/src/usb/usbhost/host_usblib.rs +++ b/devices/src/usb/usbhost/host_usblib.rs @@ -132,7 +132,7 @@ pub fn set_pollfd_notifiers( notifiers: &mut Vec, handler: Rc, ) { - let mut i = 0; + let mut i: isize = 0; // SAFETY: have checked whether the pointer is null before dereference it. unsafe { loop { diff --git a/devices/src/usb/usbhost/mod.rs b/devices/src/usb/usbhost/mod.rs index b58c8d1b..196baa2c 100644 --- a/devices/src/usb/usbhost/mod.rs +++ b/devices/src/usb/usbhost/mod.rs @@ -844,7 +844,7 @@ impl UsbHost { drop(locked_requests); // Max counts of uncompleted request to be handled. - let mut limit = 100; + let mut limit: i32 = 100; loop { if self.requests.lock().unwrap().len == 0 { return Ok(()); -- Gitee From f7cbe6296e82c6b1347b0fac9d1cea84b5561b4e Mon Sep 17 00:00:00 2001 From: Fan Xuan Zhe Date: Fri, 23 Aug 2024 17:20:42 +0800 Subject: [PATCH 300/489] usb_host: Handle possible overflow when getting device speed When the return value(i.g. speed) of libusb_get_device_speed is zero which means unknown speed, the following speed -1 operation would cause overflow. Signed-off-by: Fan Xuan Zhe fanxuanzhe@huawei.com --- devices/src/usb/usbhost/mod.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/devices/src/usb/usbhost/mod.rs b/devices/src/usb/usbhost/mod.rs index 196baa2c..267d60dd 100644 --- a/devices/src/usb/usbhost/mod.rs +++ b/devices/src/usb/usbhost/mod.rs @@ -671,7 +671,15 @@ impl UsbHost { self.ep_update(); - self.base.speed = self.libdev.as_ref().unwrap().speed() as u32 - 1; + match self.libdev.as_ref().unwrap().speed() as u32 { + 0 => { + return Err(anyhow!( + "Failed to realize usb host device due to unknown device speed." + )) + } + speed => self.base.speed = speed - 1, + }; + trace::usb_host_open_success(self.config.hostbus, self.config.hostaddr); Ok(()) -- Gitee From 1e53b4ec8bf8aeda54f500310ed9715e0ac8d9ed Mon Sep 17 00:00:00 2001 From: Fan Xuan Zhe Date: Fri, 23 Aug 2024 17:28:39 +0800 Subject: [PATCH 301/489] usb_host: Fix unsafe propagation chain breaking The function of get_libusb_pollfds which aims to obtain pollfd breaks the unsafe propagation chain, this patch fixed it. Signed-off-by: Fan Xuan Zhe fanxuanzhe@huawei.com --- devices/src/usb/usbhost/host_usblib.rs | 142 ++++++++++++++++++------- devices/src/usb/usbhost/mod.rs | 10 +- 2 files changed, 109 insertions(+), 43 deletions(-) diff --git a/devices/src/usb/usbhost/host_usblib.rs b/devices/src/usb/usbhost/host_usblib.rs index 2f6bc88f..8c5542af 100644 --- a/devices/src/usb/usbhost/host_usblib.rs +++ b/devices/src/usb/usbhost/host_usblib.rs @@ -11,11 +11,14 @@ // See the Mulan PSL v2 for more details. use std::{ + iter::Iterator, + os::unix::io::{AsRawFd, RawFd}, rc::Rc, + slice, sync::{Arc, Mutex}, }; -use libc::{c_int, c_uint, c_void, EPOLLIN, EPOLLOUT}; +use libc::{c_int, c_short, c_uint, c_void, EPOLLIN, EPOLLOUT}; #[cfg(all(target_arch = "aarch64", target_env = "ohos"))] use libusb1_sys::{constants::LIBUSB_SUCCESS, libusb_context, libusb_set_option}; use libusb1_sys::{ @@ -117,46 +120,28 @@ pub fn map_packet_status(status: i32) -> UsbPacketStatus { } } -pub fn get_libusb_pollfds(usbhost: Arc>) -> *const *mut libusb_pollfd { - // SAFETY: call C library of libusb to get pointer of poll fd. - unsafe { libusb_get_pollfds(usbhost.lock().unwrap().context.as_raw()) } -} - -pub unsafe fn free_libusb_pollfds(pollfds: *const *mut libusb_pollfd) { - // Pollfds should be guaranteed to be valid. - libusb_free_pollfds(pollfds) -} - pub fn set_pollfd_notifiers( - poll: *const *mut libusb_pollfd, + pollfds: PollFds, notifiers: &mut Vec, handler: Rc, ) { - let mut i: isize = 0; - // SAFETY: have checked whether the pointer is null before dereference it. - unsafe { - loop { - if (*poll.offset(i)).is_null() { - break; - }; - if i32::from((*(*poll.offset(i))).events) == EPOLLIN { - notifiers.push(EventNotifier::new( - NotifierOperation::AddShared, - (*(*poll.offset(i))).fd, - None, - EventSet::IN, - vec![handler.clone()], - )); - } else if i32::from((*(*poll.offset(i))).events) == EPOLLOUT { - notifiers.push(EventNotifier::new( - NotifierOperation::AddShared, - (*(*poll.offset(i))).fd, - None, - EventSet::OUT, - vec![handler.clone()], - )); - } - i += 1; + for pollfd in pollfds.iter() { + if i32::from(pollfd.events()) == EPOLLIN { + notifiers.push(EventNotifier::new( + NotifierOperation::AddShared, + pollfd.as_raw_fd(), + None, + EventSet::IN, + vec![handler.clone()], + )); + } else if i32::from(pollfd.events()) == EPOLLOUT { + notifiers.push(EventNotifier::new( + NotifierOperation::AddShared, + pollfd.as_raw_fd(), + None, + EventSet::OUT, + vec![handler.clone()], + )); } } } @@ -405,3 +390,86 @@ pub fn set_option(opt: u32) -> Result<()> { Ok(()) } + +#[derive(Debug)] +pub struct PollFd { + fd: c_int, + events: c_short, +} + +impl PollFd { + unsafe fn from_raw(raw: *mut libusb_pollfd) -> Self { + Self { + fd: (*raw).fd, + events: (*raw).events, + } + } + + pub fn events(&self) -> c_short { + self.events + } +} + +impl AsRawFd for PollFd { + fn as_raw_fd(&self) -> RawFd { + self.fd + } +} + +pub struct PollFds { + poll_fds: *const *mut libusb_pollfd, +} + +impl PollFds { + pub unsafe fn new(usbhost: Arc>) -> Result { + let poll_fds = libusb_get_pollfds(usbhost.lock().unwrap().context.as_raw()); + if poll_fds.is_null() { + Err(Error::NotFound) + } else { + Ok(Self { poll_fds }) + } + } + + pub fn iter(&self) -> PollFdIter { + let mut len: usize = 0; + // SAFETY: self.poll_fds is acquired from libusb_get_pollfds which is guaranteed to be valid. + unsafe { + while !(*self.poll_fds.add(len)).is_null() { + len += 1; + } + PollFdIter { + fds: slice::from_raw_parts(self.poll_fds, len), + index: 0, + } + } + } +} + +impl Drop for PollFds { + fn drop(&mut self) { + // SAFETY: self.poll_fds is acquired from libusb_get_pollfds which is guaranteed to be valid. + unsafe { + libusb_free_pollfds(self.poll_fds); + } + } +} + +pub struct PollFdIter<'a> { + fds: &'a [*mut libusb_pollfd], + index: usize, +} + +impl<'a> Iterator for PollFdIter<'a> { + type Item = PollFd; + + fn next(&mut self) -> Option { + if self.index < self.fds.len() { + // SAFETY: self.fds is guaranteed to be valid. + let poll_fd = unsafe { PollFd::from_raw(self.fds[self.index]) }; + self.index += 1; + Some(poll_fd) + } else { + None + } + } +} diff --git a/devices/src/usb/usbhost/mod.rs b/devices/src/usb/usbhost/mod.rs index 267d60dd..bc79fd38 100644 --- a/devices/src/usb/usbhost/mod.rs +++ b/devices/src/usb/usbhost/mod.rs @@ -1038,7 +1038,6 @@ impl EventNotifierHelper for UsbHost { let cloned_usbhost = usbhost.clone(); let mut notifiers = Vec::new(); - let poll = get_libusb_pollfds(usbhost); let timeout = Some(Duration::new(0, 0)); let handler: Rc = Rc::new(move |_, _fd: RawFd| { cloned_usbhost @@ -1049,11 +1048,10 @@ impl EventNotifierHelper for UsbHost { .unwrap_or_else(|e| error!("Failed to handle event: {:?}", e)); None }); - - set_pollfd_notifiers(poll, &mut notifiers, handler); - - // SAFETY: pointer of pollfds acquired from libusb_get_pollfds is guaranteed to be valid. - unsafe { free_libusb_pollfds(poll) }; + // SAFETY: The usbhost is guaranteed to be valid. + if let Ok(pollfds) = unsafe { PollFds::new(usbhost) } { + set_pollfd_notifiers(pollfds, &mut notifiers, handler); + } notifiers } -- Gitee From 01a8ea96a4f539842d3e1684e91c99e85f484e7a Mon Sep 17 00:00:00 2001 From: zhanghan64 Date: Fri, 23 Aug 2024 11:31:38 +0800 Subject: [PATCH 302/489] UI: clear hardware cursor buffer when dpy switch When switch dpy surface, clear cursor buffer. Signed-off-by: zhanghan64 --- ui/src/ohui_srv/mod.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/ui/src/ohui_srv/mod.rs b/ui/src/ohui_srv/mod.rs index 8370c5b5..45a51a8e 100755 --- a/ui/src/ohui_srv/mod.rs +++ b/ui/src/ohui_srv/mod.rs @@ -85,6 +85,8 @@ impl GuestSurface { } const CURSOR_SIZE: u64 = 16 * 1024; +const DEFAULT_CURSOR_WIDTH: u32 = 128; +const DEFAULT_CURSOR_HEIGHT: u32 = 128; pub struct OhUiServer { // framebuffer passthru to the guest @@ -282,6 +284,17 @@ impl OhUiServer { error!("Failed to initialize iothread of OHUI Server."); } } + + fn clear_cursor_buffer(&self) { + if self.cursorbuffer == 0 { + error!("Cursor buffer is invalid."); + return; + } + //SAFETY: we make sure that buffer info is valid. + unsafe { + ptr::write_bytes(self.cursorbuffer as *mut u8, 0, CURSOR_SIZE as usize); + } + } } impl DisplayChangeListenerOperations for OhUiServer { @@ -307,12 +320,20 @@ impl DisplayChangeListenerOperations for OhUiServer { true, ) }; + self.clear_cursor_buffer(); if !self.connected() { return Ok(()); } self.msg_handler .send_windowinfo(locked_surface.width as u32, locked_surface.height as u32); + self.msg_handler.handle_cursor_define( + DEFAULT_CURSOR_WIDTH, + DEFAULT_CURSOR_HEIGHT, + 0, + 0, + bytes_per_pixel().try_into()?, + ); Ok(()) } -- Gitee From 4e8e6e9ffd6660e17a1afa6759a8be5423cfa906 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Fri, 30 Aug 2024 15:18:21 +0800 Subject: [PATCH 303/489] scream: use secure remain function to caculate chunk idx The driver might clear scream capture header, e.g. if BSOD occurred while voice capture is ongoing, the driver will clear the header after VM restarted, then scream backend will div 0 and crash would occur. So let's use secure remain function. Signed-off-by: Zhao Yi Min --- devices/src/misc/scream/mod.rs | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index 5db2c93c..c0b4d0d1 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -449,7 +449,15 @@ impl StreamData { match recv_chunks_cnt.cmp(&0) { std::cmp::Ordering::Less => thread::sleep(time::Duration::from_millis(100)), std::cmp::Ordering::Greater => { - self.chunk_idx = (self.chunk_idx + recv_chunks_cnt as u16) % capt.max_chunks; + self.chunk_idx = match (self.chunk_idx + recv_chunks_cnt as u16) + .checked_rem(capt.max_chunks) + { + Some(idx) => idx, + None => { + warn!("Scream: capture header might be cleared by driver"); + return; + } + }; // Make sure chunk_idx write does not bypass audio chunk write. fence(Ordering::SeqCst); capt.chunk_idx = self.chunk_idx; -- Gitee From 57dd6d39c37ab7df68ea4c111f2fb16e06d9772d Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Fri, 30 Aug 2024 15:23:51 +0800 Subject: [PATCH 304/489] scream: support streams stop while VM is restarting This patch adds reset function for ivshmem device and introduces a callback for scream to register reset callback. Scream would stop streams while VM is restarting. Signed-off-by: Zhao Yi Min --- devices/src/misc/ivshmem.rs | 13 +++++++++++++ devices/src/misc/scream/mod.rs | 13 +++++++++++++ 2 files changed, 26 insertions(+) diff --git a/devices/src/misc/ivshmem.rs b/devices/src/misc/ivshmem.rs index 16ba7b22..a98a4a11 100644 --- a/devices/src/misc/ivshmem.rs +++ b/devices/src/misc/ivshmem.rs @@ -57,6 +57,7 @@ pub struct Ivshmem { ram_mem_region: Region, vector_nr: u32, bar0_ops: Arc>, + reset_cb: Option>, } impl Ivshmem { @@ -77,6 +78,7 @@ impl Ivshmem { ram_mem_region, vector_nr, bar0_ops: Arc::new(RwLock::new(Bar0Ops::default())), + reset_cb: None, } } @@ -168,6 +170,10 @@ impl Ivshmem { self.bar0_ops.write().unwrap().write = Some(bar0_ops.0); self.bar0_ops.write().unwrap().read = Some(bar0_ops.1); } + + pub fn register_reset_callback(&mut self, cb: Box) { + self.reset_cb = Some(cb); + } } impl Device for Ivshmem { @@ -205,6 +211,13 @@ impl Device for Ivshmem { locked_bus.attach_child(u64::from(dev.lock().unwrap().base.devfn), dev.clone())?; Ok(dev) } + + fn reset(&mut self, _reset_child_device: bool) -> Result<()> { + if let Some(cb) = &self.reset_cb { + cb(); + } + Ok(()) + } } impl PciDevOps for Ivshmem { diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index c0b4d0d1..38fd38b3 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -435,6 +435,10 @@ impl StreamData { while capt.is_started != 0 { cond.wait_if_paused(interface.clone()); + if capt.fmt.fmt_generation != self.fmt.fmt_generation { + return; + } + if !self.update_buffer_by_chunk_idx(hva, shmem_size, capt) { return; } @@ -704,6 +708,15 @@ impl Scream { play_cond: Arc, capt_cond: Arc, ) { + let cloned_play_cond = play_cond.clone(); + let cloned_capt_cond = capt_cond.clone(); + let cb = Box::new(move || { + info!("Scream: device is reset."); + cloned_play_cond.set_stream_pause(true); + cloned_capt_cond.set_stream_pause(true); + }); + ivshmem.lock().unwrap().register_reset_callback(cb); + let interface = self.create_audio_extension(ivshmem.clone()); let interface2 = interface.clone(); let bar0_write = Arc::new(move |data: &[u8], offset: u64| { -- Gitee From b8449a20d27e94a85c6ffe3e7c0a8c237fa71515 Mon Sep 17 00:00:00 2001 From: Xu Yandong Date: Mon, 26 Aug 2024 07:53:05 +0000 Subject: [PATCH 305/489] address_space: add attribute for GuestAddress access To make guset memory access more secure, controlling guest physical address through address attribute. Signed-off-by: Yandong Xu Author: Yandong Xu Date: Mon Aug 26 07:53:05 2024 +0000 --- address_space/src/address.rs | 9 ++ address_space/src/address_space.rs | 107 ++++++++++++++---- address_space/src/lib.rs | 6 +- address_space/src/state.rs | 6 +- boot_loader/src/aarch64/mod.rs | 16 ++- boot_loader/src/x86_64/direct_boot/gdt.rs | 6 +- boot_loader/src/x86_64/direct_boot/mod.rs | 41 +++++-- boot_loader/src/x86_64/direct_boot/mptable.rs | 6 +- boot_loader/src/x86_64/standard_boot/elf.rs | 9 +- devices/src/legacy/fwcfg.rs | 30 ++--- devices/src/pci/demo_device/dpy_device.rs | 3 +- devices/src/pci/demo_device/gpu_device.rs | 10 +- .../src/pci/demo_device/kbd_pointer_device.rs | 38 +++++-- devices/src/usb/xhci/xhci_controller.rs | 30 ++--- hypervisor/src/kvm/listener.rs | 12 +- machine/src/aarch64/micro.rs | 3 +- machine/src/aarch64/standard.rs | 4 +- machine/src/lib.rs | 12 +- machine/src/micro_common/mod.rs | 3 +- machine/src/standard_common/mod.rs | 5 +- virtio/src/device/balloon.rs | 8 +- virtio/src/device/block.rs | 7 +- virtio/src/device/net.rs | 5 +- virtio/src/device/rng.rs | 52 +++++++-- virtio/src/device/scsi_cntlr.rs | 6 +- virtio/src/device/serial.rs | 9 +- virtio/src/transport/virtio_pci.rs | 6 +- virtio/src/vhost/kernel/vsock.rs | 3 +- 28 files changed, 329 insertions(+), 123 deletions(-) diff --git a/address_space/src/address.rs b/address_space/src/address.rs index 94a79162..5d1d02b6 100644 --- a/address_space/src/address.rs +++ b/address_space/src/address.rs @@ -15,6 +15,15 @@ use std::ops::{BitAnd, BitOr}; use util::num_ops::{round_down, round_up}; +#[derive(PartialEq, Eq)] +pub enum AddressAttr { + Ram, + MMIO, + RamDevice, + RomDevice, + RomDeviceForce, +} + /// Represent the address in given address space. #[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Ord, PartialOrd)] pub struct GuestAddress(pub u64); diff --git a/address_space/src/address_space.rs b/address_space/src/address_space.rs index 4e8e35fc..58e304ab 100644 --- a/address_space/src/address_space.rs +++ b/address_space/src/address_space.rs @@ -15,14 +15,14 @@ use std::fmt::Debug; use std::io::Write; use std::sync::{Arc, Mutex}; -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, bail, Context, Result}; use arc_swap::ArcSwap; use log::error; use once_cell::sync::OnceCell; use crate::{ - AddressRange, AddressSpaceError, FlatRange, GuestAddress, Listener, ListenerReqType, Region, - RegionIoEventFd, RegionType, + AddressAttr, AddressRange, AddressSpaceError, FlatRange, GuestAddress, Listener, + ListenerReqType, Region, RegionIoEventFd, RegionType, }; use migration::{migration::Migratable, MigrationManager}; use util::aio::Iovec; @@ -41,10 +41,23 @@ impl FlatView { } } - fn read(&self, dst: &mut dyn std::io::Write, addr: GuestAddress, count: u64) -> Result<()> { + fn read( + &self, + dst: &mut dyn std::io::Write, + addr: GuestAddress, + count: u64, + attr: AddressAttr, + ) -> Result<()> { let mut len = count; let mut l = count; let mut start = addr; + let region_type = match attr { + AddressAttr::Ram => RegionType::Ram, + AddressAttr::MMIO => RegionType::IO, + AddressAttr::RamDevice => RegionType::RamDevice, + AddressAttr::RomDevice => RegionType::RomDevice, + AddressAttr::RomDeviceForce => RegionType::RomDevice, + }; loop { if let Some(fr) = self.find_flatrange(start) { @@ -53,9 +66,20 @@ impl FlatView { let region_base = fr.addr_range.base.unchecked_sub(fr.offset_in_region); let fr_remain = fr.addr_range.size - fr_offset; - if fr.owner.region_type() == RegionType::Ram - || fr.owner.region_type() == RegionType::RamDevice - { + if fr.owner.region_type() != region_type { + // Read op RomDevice in I/O access mode as MMIO + if region_type == RegionType::IO + && fr.owner.region_type() == RegionType::RomDevice + { + if fr.owner.get_rom_device_romd().unwrap() { + bail!("mismatch region type") + } + } else { + bail!("mismatch region type") + } + } + + if region_type == RegionType::Ram || region_type == RegionType::RamDevice { l = std::cmp::min(l, fr_remain); } fr.owner.read(dst, region_base, region_offset, l)?; @@ -74,20 +98,42 @@ impl FlatView { } } - fn write(&self, src: &mut dyn std::io::Read, addr: GuestAddress, count: u64) -> Result<()> { + fn write( + &self, + src: &mut dyn std::io::Read, + addr: GuestAddress, + count: u64, + attr: AddressAttr, + ) -> Result<()> { let mut l = count; let mut len = count; let mut start = addr; + let region_type = match attr { + AddressAttr::Ram => RegionType::Ram, + AddressAttr::MMIO => RegionType::IO, + AddressAttr::RamDevice => RegionType::RamDevice, + AddressAttr::RomDeviceForce => RegionType::RomDevice, + _ => { + bail!("Error write attr") + } + }; loop { if let Some(fr) = self.find_flatrange(start) { let fr_offset = start.offset_from(fr.addr_range.base); let region_offset = fr.offset_in_region + fr_offset; let region_base = fr.addr_range.base.unchecked_sub(fr.offset_in_region); let fr_remain = fr.addr_range.size - fr_offset; - if fr.owner.region_type() == RegionType::Ram - || fr.owner.region_type() == RegionType::RamDevice + + // Read/Write ops to RomDevice is MMIO. + if fr.owner.region_type() != region_type + && !(region_type == RegionType::IO + && fr.owner.region_type() == RegionType::RomDevice) { + bail!("mismatch region type") + } + + if region_type == RegionType::Ram || region_type == RegionType::RamDevice { l = std::cmp::min(l, fr_remain); } fr.owner.write(src, region_base, region_offset, l)?; @@ -610,11 +656,17 @@ impl AddressSpace { /// # Errors /// /// Return Error if the `addr` is not mapped. - pub fn read(&self, dst: &mut dyn std::io::Write, addr: GuestAddress, count: u64) -> Result<()> { + pub fn read( + &self, + dst: &mut dyn std::io::Write, + addr: GuestAddress, + count: u64, + attr: AddressAttr, + ) -> Result<()> { trace::address_space_read(&addr, count); let view = self.flat_view.load(); - view.read(dst, addr, count)?; + view.read(dst, addr, count, attr)?; Ok(()) } @@ -629,7 +681,13 @@ impl AddressSpace { /// # Errors /// /// Return Error if the `addr` is not mapped. - pub fn write(&self, src: &mut dyn std::io::Read, addr: GuestAddress, count: u64) -> Result<()> { + pub fn write( + &self, + src: &mut dyn std::io::Read, + addr: GuestAddress, + count: u64, + attr: AddressAttr, + ) -> Result<()> { trace::address_space_write(&addr, count); let view = self.flat_view.load(); @@ -664,13 +722,13 @@ impl AddressSpace { continue; } } - view.write(&mut buf_temp.as_slice(), addr, count)?; + view.write(&mut buf_temp.as_slice(), addr, count, attr)?; return Ok(()); } } } - view.write(&mut buf.as_slice(), addr, count)?; + view.write(&mut buf.as_slice(), addr, count, attr)?; Ok(()) } @@ -683,9 +741,19 @@ impl AddressSpace { /// /// # Note /// To use this method, it is necessary to implement `ByteCode` trait for your object. - pub fn write_object(&self, data: &T, addr: GuestAddress) -> Result<()> { - self.write(&mut data.as_bytes(), addr, std::mem::size_of::() as u64) - .with_context(|| "Failed to write object") + pub fn write_object( + &self, + data: &T, + addr: GuestAddress, + attr: AddressAttr, + ) -> Result<()> { + self.write( + &mut data.as_bytes(), + addr, + std::mem::size_of::() as u64, + attr, + ) + .with_context(|| "Failed to write object") } /// Write an object to memory via host address. @@ -718,12 +786,13 @@ impl AddressSpace { /// /// # Note /// To use this method, it is necessary to implement `ByteCode` trait for your object. - pub fn read_object(&self, addr: GuestAddress) -> Result { + pub fn read_object(&self, addr: GuestAddress, attr: AddressAttr) -> Result { let mut obj = T::default(); self.read( &mut obj.as_mut_bytes(), addr, std::mem::size_of::() as u64, + attr, ) .with_context(|| "Failed to read object")?; Ok(obj) diff --git a/address_space/src/lib.rs b/address_space/src/lib.rs index f9feddf3..ae8760a4 100644 --- a/address_space/src/lib.rs +++ b/address_space/src/lib.rs @@ -19,7 +19,7 @@ //! use std::sync::{Arc, Mutex}; //! extern crate address_space; //! use address_space::{ -//! AddressSpace, FileBackend, GuestAddress, HostMemMapping, Region, RegionOps, +//! AddressAttr, AddressSpace, FileBackend, GuestAddress, HostMemMapping, Region, RegionOps, //! }; //! //! struct DummyDevice; @@ -76,7 +76,7 @@ //! space.root().add_subregion(io_region, 0x2000); //! //! // 5. access address_space -//! space.write_object(&0x11u64, GuestAddress(0)); +//! space.write_object(&0x11u64, GuestAddress(0), AddressAttr::Ram); //! } //! ``` @@ -90,7 +90,7 @@ mod region; mod state; pub use crate::address_space::{AddressSpace, RegionCache}; -pub use address::{AddressRange, GuestAddress}; +pub use address::{AddressAttr, AddressRange, GuestAddress}; pub use error::AddressSpaceError; pub use host_mmap::{create_backend_mem, create_default_mem, FileBackend, HostMemMapping}; pub use listener::{Listener, ListenerReqType, MemSlot}; diff --git a/address_space/src/state.rs b/address_space/src/state.rs index 6a6d81ff..2f282325 100644 --- a/address_space/src/state.rs +++ b/address_space/src/state.rs @@ -17,7 +17,7 @@ use std::sync::Arc; use anyhow::{bail, Context, Result}; -use crate::{AddressSpace, FileBackend, GuestAddress, HostMemMapping, Region}; +use crate::{AddressAttr, AddressSpace, FileBackend, GuestAddress, HostMemMapping, Region}; use migration::{ error::MigrationError, DeviceStateDesc, FieldDesc, MemBlock, MigrationHook, StateTransfer, }; @@ -168,14 +168,14 @@ impl MigrationHook for AddressSpace { } fn send_memory(&self, fd: &mut dyn Write, range: MemBlock) -> Result<()> { - self.read(fd, GuestAddress(range.gpa), range.len) + self.read(fd, GuestAddress(range.gpa), range.len, AddressAttr::Ram) .map_err(|e| MigrationError::SendVmMemoryErr(e.to_string()))?; Ok(()) } fn recv_memory(&self, fd: &mut dyn Read, range: MemBlock) -> Result<()> { - self.write(fd, GuestAddress(range.gpa), range.len) + self.write(fd, GuestAddress(range.gpa), range.len, AddressAttr::Ram) .map_err(|e| MigrationError::RecvVmMemoryErr(e.to_string()))?; Ok(()) diff --git a/boot_loader/src/aarch64/mod.rs b/boot_loader/src/aarch64/mod.rs index 20d564c7..d06a95af 100644 --- a/boot_loader/src/aarch64/mod.rs +++ b/boot_loader/src/aarch64/mod.rs @@ -19,7 +19,7 @@ use anyhow::{anyhow, Context, Result}; use log::info; use crate::error::BootLoaderError; -use address_space::{AddressSpace, GuestAddress}; +use address_space::{AddressAttr, AddressSpace, GuestAddress}; use devices::legacy::{error::LegacyError as FwcfgErrorKind, FwCfgEntryType, FwCfgOps}; use util::byte_code::ByteCode; @@ -85,7 +85,12 @@ fn load_kernel( ))); } sys_mem - .write(&mut kernel_image, GuestAddress(kernel_start), kernel_size) + .write( + &mut kernel_image, + GuestAddress(kernel_start), + kernel_size, + AddressAttr::Ram, + ) .with_context(|| "Fail to write kernel to guest memory")?; } Ok(kernel_end) @@ -129,7 +134,12 @@ fn load_initrd( .with_context(|| FwcfgErrorKind::AddEntryErr("InitrdData".to_string()))?; } else { sys_mem - .write(&mut initrd_image, GuestAddress(initrd_start), initrd_size) + .write( + &mut initrd_image, + GuestAddress(initrd_start), + initrd_size, + AddressAttr::Ram, + ) .with_context(|| "Fail to write initrd to guest memory")?; } diff --git a/boot_loader/src/x86_64/direct_boot/gdt.rs b/boot_loader/src/x86_64/direct_boot/gdt.rs index f5d95af3..07995a06 100644 --- a/boot_loader/src/x86_64/direct_boot/gdt.rs +++ b/boot_loader/src/x86_64/direct_boot/gdt.rs @@ -19,7 +19,7 @@ use super::super::BootGdtSegment; use super::super::{ BOOT_GDT_MAX, BOOT_GDT_OFFSET, BOOT_IDT_OFFSET, GDT_ENTRY_BOOT_CS, GDT_ENTRY_BOOT_DS, }; -use address_space::{AddressSpace, GuestAddress}; +use address_space::{AddressAttr, AddressSpace, GuestAddress}; // /* // * Constructor for a conventional segment GDT (or LDT) entry. @@ -94,7 +94,7 @@ fn write_gdt_table(table: &[u64], guest_mem: &Arc) -> Result<()> { let mut boot_gdt_addr = BOOT_GDT_OFFSET; for (_, entry) in table.iter().enumerate() { guest_mem - .write_object(entry, GuestAddress(boot_gdt_addr)) + .write_object(entry, GuestAddress(boot_gdt_addr), AddressAttr::Ram) .with_context(|| format!("Failed to load gdt to 0x{:x}", boot_gdt_addr))?; boot_gdt_addr += 8; } @@ -104,7 +104,7 @@ fn write_gdt_table(table: &[u64], guest_mem: &Arc) -> Result<()> { fn write_idt_value(val: u64, guest_mem: &Arc) -> Result<()> { let boot_idt_addr = BOOT_IDT_OFFSET; guest_mem - .write_object(&val, GuestAddress(boot_idt_addr)) + .write_object(&val, GuestAddress(boot_idt_addr), AddressAttr::Ram) .with_context(|| format!("Failed to load gdt to 0x{:x}", boot_idt_addr))?; Ok(()) diff --git a/boot_loader/src/x86_64/direct_boot/mod.rs b/boot_loader/src/x86_64/direct_boot/mod.rs index 8aed3118..c910d822 100644 --- a/boot_loader/src/x86_64/direct_boot/mod.rs +++ b/boot_loader/src/x86_64/direct_boot/mod.rs @@ -29,7 +29,7 @@ use super::{ INITRD_ADDR_MAX, PDE_START, PDPTE_START, PML4_START, VMLINUX_STARTUP, ZERO_PAGE_START, }; use crate::error::BootLoaderError; -use address_space::{AddressSpace, GuestAddress}; +use address_space::{AddressAttr, AddressSpace, GuestAddress}; use util::byte_code::ByteCode; /// Load bzImage linux kernel to Guest Memory. @@ -91,7 +91,12 @@ fn load_image(image: &mut File, start_addr: u64, sys_mem: &Arc) -> let len = image.seek(SeekFrom::End(0))?; image.seek(SeekFrom::Start(curr_loc))?; - sys_mem.write(image, GuestAddress(start_addr), len - curr_loc)?; + sys_mem.write( + image, + GuestAddress(start_addr), + len - curr_loc, + AddressAttr::Ram, + )?; Ok(()) } @@ -163,13 +168,13 @@ fn setup_page_table(sys_mem: &Arc) -> Result { // Entry covering VA [0..512GB) let pdpte = boot_pdpte_addr | 0x03; sys_mem - .write_object(&pdpte, GuestAddress(boot_pml4_addr)) + .write_object(&pdpte, GuestAddress(boot_pml4_addr), AddressAttr::Ram) .with_context(|| format!("Failed to load PD PTE to 0x{:x}", boot_pml4_addr))?; // Entry covering VA [0..1GB) let pde = boot_pde_addr | 0x03; sys_mem - .write_object(&pde, GuestAddress(boot_pdpte_addr)) + .write_object(&pde, GuestAddress(boot_pdpte_addr), AddressAttr::Ram) .with_context(|| format!("Failed to load PDE to 0x{:x}", boot_pdpte_addr))?; // 512 2MB entries together covering VA [0..1GB). Note we are assuming @@ -177,7 +182,7 @@ fn setup_page_table(sys_mem: &Arc) -> Result { for i in 0..512u64 { let pde = (i << 21) + 0x83u64; sys_mem - .write_object(&pde, GuestAddress(boot_pde_addr + i * 8)) + .write_object(&pde, GuestAddress(boot_pde_addr + i * 8), AddressAttr::Ram) .with_context(|| format!("Failed to load PDE to 0x{:x}", boot_pde_addr + i * 8))?; } @@ -192,7 +197,11 @@ fn setup_boot_params( let mut boot_params = BootParams::new(*boot_hdr); boot_params.setup_e820_entries(config, sys_mem); sys_mem - .write_object(&boot_params, GuestAddress(ZERO_PAGE_START)) + .write_object( + &boot_params, + GuestAddress(ZERO_PAGE_START), + AddressAttr::Ram, + ) .with_context(|| format!("Failed to load zero page to 0x{:x}", ZERO_PAGE_START))?; Ok(()) @@ -210,6 +219,7 @@ fn setup_kernel_cmdline( &mut config.kernel_cmdline.as_bytes(), GuestAddress(CMDLINE_START), u64::from(cmdline_len), + AddressAttr::Ram, )?; Ok(()) @@ -305,18 +315,24 @@ mod test { .unwrap(); assert_eq!(setup_page_table(&space).unwrap(), 0x0000_9000); assert_eq!( - space.read_object::(GuestAddress(0x0000_9000)).unwrap(), + space + .read_object::(GuestAddress(0x0000_9000), AddressAttr::Ram) + .unwrap(), 0x0000_a003 ); assert_eq!( - space.read_object::(GuestAddress(0x0000_a000)).unwrap(), + space + .read_object::(GuestAddress(0x0000_a000), AddressAttr::Ram) + .unwrap(), 0x0000_b003 ); let mut page_addr: u64 = 0x0000_b000; let mut tmp_value: u64 = 0x83; for _ in 0..512u64 { assert_eq!( - space.read_object::(GuestAddress(page_addr)).unwrap(), + space + .read_object::(GuestAddress(page_addr), AddressAttr::Ram) + .unwrap(), tmp_value ); page_addr += 8; @@ -378,7 +394,11 @@ mod test { let mut arr: Vec = Vec::new(); let mut boot_addr: u64 = 0x500; for _ in 0..BOOT_GDT_MAX { - arr.push(space.read_object(GuestAddress(boot_addr)).unwrap()); + arr.push( + space + .read_object(GuestAddress(boot_addr), AddressAttr::Ram) + .unwrap(), + ); boot_addr += 8; } assert_eq!(arr[0], 0); @@ -395,6 +415,7 @@ mod test { &mut read_buffer.as_mut(), GuestAddress(0x0002_0000), cmd_len, + AddressAttr::Ram, ) .unwrap(); let s = String::from_utf8(read_buffer.to_vec()).unwrap(); diff --git a/boot_loader/src/x86_64/direct_boot/mptable.rs b/boot_loader/src/x86_64/direct_boot/mptable.rs index 8eee6d1c..8ea1ce2d 100644 --- a/boot_loader/src/x86_64/direct_boot/mptable.rs +++ b/boot_loader/src/x86_64/direct_boot/mptable.rs @@ -15,7 +15,7 @@ use std::sync::Arc; use anyhow::{anyhow, Result}; use crate::error::BootLoaderError; -use address_space::{AddressSpace, GuestAddress}; +use address_space::{AddressAttr, AddressSpace, GuestAddress}; use util::byte_code::ByteCode; use util::checksum::obj_checksum; @@ -267,7 +267,7 @@ impl LocalInterruptEntry { macro_rules! write_entry { ( $d:expr, $t:ty, $m:expr, $o:expr, $s:expr ) => { let entry = $d; - $m.write_object(&entry, GuestAddress($o))?; + $m.write_object(&entry, GuestAddress($o), AddressAttr::Ram)?; $o += std::mem::size_of::<$t>() as u64; $s = $s.wrapping_add(obj_checksum(&entry)); }; @@ -294,6 +294,7 @@ pub fn setup_isa_mptable( sys_mem.write_object( &FloatingPointer::new(header as u32), GuestAddress(start_addr), + AddressAttr::Ram, )?; let mut offset = header + std::mem::size_of::() as u64; @@ -345,6 +346,7 @@ pub fn setup_isa_mptable( sys_mem.write_object( &ConfigTableHeader::new((offset - header) as u16, sum, lapic_addr), GuestAddress(header), + AddressAttr::Ram, )?; Ok(()) diff --git a/boot_loader/src/x86_64/standard_boot/elf.rs b/boot_loader/src/x86_64/standard_boot/elf.rs index 3f852578..9158d4c1 100644 --- a/boot_loader/src/x86_64/standard_boot/elf.rs +++ b/boot_loader/src/x86_64/standard_boot/elf.rs @@ -16,7 +16,7 @@ use std::sync::Arc; use anyhow::{bail, Context, Result}; -use address_space::{AddressSpace, GuestAddress}; +use address_space::{AddressAttr, AddressSpace, GuestAddress}; use devices::legacy::{FwCfgEntryType, FwCfgOps}; use util::byte_code::ByteCode; use util::num_ops::round_up; @@ -163,7 +163,12 @@ pub fn load_elf_kernel( if ph.p_type == PT_LOAD { kernel_image.seek(SeekFrom::Start(ph.p_offset))?; - sys_mem.write(kernel_image, GuestAddress(ph.p_paddr), ph.p_filesz)?; + sys_mem.write( + kernel_image, + GuestAddress(ph.p_paddr), + ph.p_filesz, + AddressAttr::Ram, + )?; addr_low = std::cmp::min(addr_low, ph.p_paddr); addr_max = std::cmp::max(addr_max, ph.p_paddr); diff --git a/devices/src/legacy/fwcfg.rs b/devices/src/legacy/fwcfg.rs index d7a3d701..ce36d655 100644 --- a/devices/src/legacy/fwcfg.rs +++ b/devices/src/legacy/fwcfg.rs @@ -28,7 +28,7 @@ use acpi::{ use acpi::{AmlIoDecode, AmlIoResource}; #[cfg(target_arch = "aarch64")] use acpi::{AmlMemory32Fixed, AmlReadAndWrite}; -use address_space::{AddressSpace, GuestAddress}; +use address_space::{AddressAttr, AddressSpace, GuestAddress}; use util::byte_code::ByteCode; use util::num_ops::extract_u64; use util::{gen_base_func, offset_of}; @@ -243,12 +243,14 @@ fn write_dma_memory( mut buf: &[u8], len: u64, ) -> Result<()> { - addr_space.write(&mut buf, addr, len).with_context(|| { - format!( - "Failed to write dma memory of fwcfg at gpa=0x{:x} len=0x{:x}", - addr.0, len - ) - })?; + addr_space + .write(&mut buf, addr, len, AddressAttr::Ram) + .with_context(|| { + format!( + "Failed to write dma memory of fwcfg at gpa=0x{:x} len=0x{:x}", + addr.0, len + ) + })?; Ok(()) } @@ -260,12 +262,14 @@ fn read_dma_memory( mut buf: &mut [u8], len: u64, ) -> Result<()> { - addr_space.read(&mut buf, addr, len).with_context(|| { - format!( - "Failed to read dma memory of fwcfg at gpa=0x{:x} len=0x{:x}", - addr.0, len - ) - })?; + addr_space + .read(&mut buf, addr, len, AddressAttr::Ram) + .with_context(|| { + format!( + "Failed to read dma memory of fwcfg at gpa=0x{:x} len=0x{:x}", + addr.0, len + ) + })?; Ok(()) } diff --git a/devices/src/pci/demo_device/dpy_device.rs b/devices/src/pci/demo_device/dpy_device.rs index e0157461..8248b9dd 100644 --- a/devices/src/pci/demo_device/dpy_device.rs +++ b/devices/src/pci/demo_device/dpy_device.rs @@ -28,7 +28,7 @@ use log::error; use once_cell::sync::Lazy; use super::DeviceTypeOperation; -use address_space::{AddressSpace, GuestAddress}; +use address_space::{AddressAttr, AddressSpace, GuestAddress}; use ui::{ console::{ register_display, DisplayChangeListener, DisplayChangeListenerOperations, DisplayMouse, @@ -227,6 +227,7 @@ impl DeviceTypeOperation for DemoDisplay { &mut buf.as_slice(), address_space::GuestAddress(mem_addr), buf.len() as u64, + AddressAttr::Ram, ); } diff --git a/devices/src/pci/demo_device/gpu_device.rs b/devices/src/pci/demo_device/gpu_device.rs index 7abef712..8b7c1775 100644 --- a/devices/src/pci/demo_device/gpu_device.rs +++ b/devices/src/pci/demo_device/gpu_device.rs @@ -29,7 +29,7 @@ use byteorder::{ByteOrder, LittleEndian}; use log::info; use super::DeviceTypeOperation; -use address_space::{AddressSpace, GuestAddress}; +use address_space::{AddressAttr, AddressSpace, GuestAddress}; use ui::{ console::{ console_close, console_init, display_cursor_define, display_graphic_update, @@ -196,8 +196,12 @@ impl DeviceTypeOperation for DemoGpu { let mem_addr = LittleEndian::read_u64(data); // Event Type. let mut buf: Vec = vec![]; - self.sys_mem - .read(&mut buf, address_space::GuestAddress(mem_addr), 21)?; + self.sys_mem.read( + &mut buf, + address_space::GuestAddress(mem_addr), + 21, + AddressAttr::Ram, + )?; let event_type = GpuEvent::from(buf[0]); let x = LittleEndian::read_u32(&buf[1..5]); let y = LittleEndian::read_u32(&buf[5..9]); diff --git a/devices/src/pci/demo_device/kbd_pointer_device.rs b/devices/src/pci/demo_device/kbd_pointer_device.rs index 78033f8e..c4c036ba 100644 --- a/devices/src/pci/demo_device/kbd_pointer_device.rs +++ b/devices/src/pci/demo_device/kbd_pointer_device.rs @@ -22,7 +22,7 @@ use byteorder::{ByteOrder, LittleEndian}; use once_cell::sync::Lazy; use super::DeviceTypeOperation; -use address_space::{AddressSpace, GuestAddress}; +use address_space::{AddressAttr, AddressSpace, GuestAddress}; use ui::input::{register_keyboard, register_pointer, Axis, InputType, KeyboardOpts, PointerOpts}; static MEM_ADDR: Lazy>> = Lazy::new(|| { @@ -51,12 +51,36 @@ impl MemSpace { bail!("No memory allocated!") } }; - sys_mem.write_object(&(msg.event_type as u8), address_space::GuestAddress(addr))?; - sys_mem.write_object(&msg.keycode, address_space::GuestAddress(addr + 1))?; - sys_mem.write_object(&msg.down, address_space::GuestAddress(addr + 3))?; - sys_mem.write_object(&msg.button, address_space::GuestAddress(addr + 4))?; - sys_mem.write_object(&msg.x, address_space::GuestAddress(addr + 8))?; - sys_mem.write_object(&msg.y, address_space::GuestAddress(addr + 12))?; + sys_mem.write_object( + &(msg.event_type as u8), + address_space::GuestAddress(addr), + AddressAttr::Ram, + )?; + sys_mem.write_object( + &msg.keycode, + address_space::GuestAddress(addr + 1), + AddressAttr::Ram, + )?; + sys_mem.write_object( + &msg.down, + address_space::GuestAddress(addr + 3), + AddressAttr::Ram, + )?; + sys_mem.write_object( + &msg.button, + address_space::GuestAddress(addr + 4), + AddressAttr::Ram, + )?; + sys_mem.write_object( + &msg.x, + address_space::GuestAddress(addr + 8), + AddressAttr::Ram, + )?; + sys_mem.write_object( + &msg.y, + address_space::GuestAddress(addr + 12), + AddressAttr::Ram, + )?; Ok(()) } diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index 4dc652a9..fc2a4493 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -31,7 +31,7 @@ use super::xhci_trb::{ }; use crate::usb::{config::*, TransferOps}; use crate::usb::{UsbDevice, UsbDeviceRequest, UsbError, UsbPacket, UsbPacketStatus}; -use address_space::{AddressSpace, GuestAddress}; +use address_space::{AddressAttr, AddressSpace, GuestAddress}; use machine_manager::event_loop::EventLoop; const INVALID_SLOT_ID: u32 = 0; @@ -2452,12 +2452,14 @@ pub fn dma_read_bytes( mut buf: &mut [u8], ) -> Result<()> { let len = buf.len() as u64; - addr_space.read(&mut buf, addr, len).with_context(|| { - format!( - "Failed to read dma memory at gpa=0x{:x} len=0x{:x}", - addr.0, len - ) - })?; + addr_space + .read(&mut buf, addr, len, AddressAttr::Ram) + .with_context(|| { + format!( + "Failed to read dma memory at gpa=0x{:x} len=0x{:x}", + addr.0, len + ) + })?; Ok(()) } @@ -2467,12 +2469,14 @@ pub fn dma_write_bytes( mut buf: &[u8], ) -> Result<()> { let len = buf.len() as u64; - addr_space.write(&mut buf, addr, len).with_context(|| { - format!( - "Failed to write dma memory at gpa=0x{:x} len=0x{:x}", - addr.0, len - ) - })?; + addr_space + .write(&mut buf, addr, len, AddressAttr::Ram) + .with_context(|| { + format!( + "Failed to write dma memory at gpa=0x{:x} len=0x{:x}", + addr.0, len + ) + })?; Ok(()) } diff --git a/hypervisor/src/kvm/listener.rs b/hypervisor/src/kvm/listener.rs index 2e1c603f..327df1d8 100644 --- a/hypervisor/src/kvm/listener.rs +++ b/hypervisor/src/kvm/listener.rs @@ -179,12 +179,12 @@ impl KvmMemoryListener { return Ok(()); } - if flat_range.owner.region_type() != RegionType::Ram - && flat_range.owner.region_type() != RegionType::RomDevice - && flat_range.owner.region_type() != RegionType::RamDevice - { - return Ok(()); - } + let attr = match flat_range.owner.region_type() { + address_space::RegionType::Ram => AddressAttr::Ram, + address_space::RegionType::RamDevice => AddressAttr::RamDevice, + address_space::RegionType::RomDevice => AddressAttr::RomDevice, + _ => return Ok(()), + }; let (aligned_addr, aligned_size) = Self::align_mem_slot(flat_range.addr_range, host_page_size()) diff --git a/machine/src/aarch64/micro.rs b/machine/src/aarch64/micro.rs index 6fd87d76..8cd32b5d 100644 --- a/machine/src/aarch64/micro.rs +++ b/machine/src/aarch64/micro.rs @@ -16,7 +16,7 @@ use anyhow::{bail, Context, Result}; use crate::{micro_common::syscall::syscall_whitelist, MachineBase, MachineError}; use crate::{register_shutdown_event, LightMachine, MachineOps}; -use address_space::{AddressSpace, GuestAddress, Region}; +use address_space::{AddressAttr, AddressSpace, GuestAddress, Region}; use cpu::CPUTopology; use devices::legacy::{PL011, PL031}; use devices::{Device, ICGICConfig, ICGICv2Config, ICGICv3Config, GIC_IRQ_MAX}; @@ -191,6 +191,7 @@ impl MachineOps for LightMachine { &mut fdt_vec.as_slice(), GuestAddress(boot_config.fdt_addr), fdt_vec.len() as u64, + AddressAttr::Ram, ) .with_context(|| MachineError::WrtFdtErr(boot_config.fdt_addr, fdt_vec.len()))?; register_shutdown_event(locked_vm.shutdown_req.clone(), vm.clone()) diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index 9feab83a..fd1aa349 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -39,7 +39,7 @@ use acpi::{ }; #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] use address_space::FileBackend; -use address_space::{AddressSpace, GuestAddress, Region}; +use address_space::{AddressAttr, AddressSpace, GuestAddress, Region}; use cpu::{CPUInterface, CPUTopology, CpuLifecycleState, PMU_INTR, PPI_BASE}; use devices::acpi::ged::{acpi_dsdt_add_power_button, Ged, GedEvent}; use devices::acpi::power::PowerDev; @@ -201,6 +201,7 @@ impl StdMachine { &mut locked_vm.dtb_vec.as_slice(), GuestAddress(fdt_addr), locked_vm.dtb_vec.len() as u64, + AddressAttr::Ram, ) .with_context(|| "Fail to write dtb into sysmem")?; @@ -594,6 +595,7 @@ impl MachineOps for StdMachine { &mut fdt_vec.as_slice(), GuestAddress(boot_config.fdt_addr), fdt_vec.len() as u64, + AddressAttr::Ram, ) .with_context(|| MachineError::WrtFdtErr(boot_config.fdt_addr, fdt_vec.len()))?; diff --git a/machine/src/lib.rs b/machine/src/lib.rs index e71300dd..f69f40dd 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -45,7 +45,9 @@ use vmm_sys_util::eventfd::EventFd; #[cfg(all(target_env = "ohos", feature = "ohui_srv"))] use address_space::FileBackend; -use address_space::{create_backend_mem, create_default_mem, AddressSpace, GuestAddress, Region}; +use address_space::{ + create_backend_mem, create_default_mem, AddressAttr, AddressSpace, GuestAddress, Region, +}; #[cfg(target_arch = "aarch64")] use cpu::CPUFeatures; use cpu::{ArchCPU, CPUBootConfig, CPUHypervisorOps, CPUInterface, CPUTopology, CpuTopology, CPU}; @@ -262,7 +264,7 @@ impl MachineBase { let length = data.len() as u64; self.sys_io - .read(&mut data, GuestAddress(addr), length) + .read(&mut data, GuestAddress(addr), length, AddressAttr::MMIO) .is_ok() } @@ -277,21 +279,21 @@ impl MachineBase { } } self.sys_io - .write(&mut data, GuestAddress(addr), count) + .write(&mut data, GuestAddress(addr), count, AddressAttr::MMIO) .is_ok() } fn mmio_read(&self, addr: u64, mut data: &mut [u8]) -> bool { let length = data.len() as u64; self.sys_mem - .read(&mut data, GuestAddress(addr), length) + .read(&mut data, GuestAddress(addr), length, AddressAttr::MMIO) .is_ok() } fn mmio_write(&self, addr: u64, mut data: &[u8]) -> bool { let count = data.len() as u64; self.sys_mem - .write(&mut data, GuestAddress(addr), count) + .write(&mut data, GuestAddress(addr), count, AddressAttr::MMIO) .is_ok() } } diff --git a/machine/src/micro_common/mod.rs b/machine/src/micro_common/mod.rs index 3ed04c09..200028d5 100644 --- a/machine/src/micro_common/mod.rs +++ b/machine/src/micro_common/mod.rs @@ -597,12 +597,13 @@ impl MachineAddressInterface for LightMachine { #[cfg(target_arch = "x86_64")] fn pio_out(&self, addr: u64, mut data: &[u8]) -> bool { + use address_space::AddressAttr; use address_space::GuestAddress; let count = data.len() as u64; self.base .sys_io - .write(&mut data, GuestAddress(addr), count) + .write(&mut data, GuestAddress(addr), count, AddressAttr::MMIO) .is_ok() } diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index 4f95bb37..b493c6f4 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -46,7 +46,8 @@ use acpi::{ ACPI_TABLE_LOADER_FILE, TABLE_CHECKSUM_OFFSET, }; use address_space::{ - AddressRange, FileBackend, GuestAddress, HostMemMapping, Region, RegionIoEventFd, RegionOps, + AddressAttr, AddressRange, FileBackend, GuestAddress, HostMemMapping, Region, RegionIoEventFd, + RegionOps, }; use block_backend::{qcow2::QCOW2_LIST, BlockStatus}; #[cfg(target_arch = "x86_64")] @@ -2040,7 +2041,7 @@ impl DeviceInterface for StdMachine { match self .machine_base() .sys_mem - .read_object::(GuestAddress(gpa)) + .read_object::(GuestAddress(gpa), AddressAttr::Ram) { Ok(val) => { Response::create_response(serde_json::to_value(format!("{:X}", val)).unwrap(), None) diff --git a/virtio/src/device/balloon.rs b/virtio/src/device/balloon.rs index 22462a79..421cbb8a 100644 --- a/virtio/src/device/balloon.rs +++ b/virtio/src/device/balloon.rs @@ -31,7 +31,8 @@ use crate::{ VIRTIO_TYPE_BALLOON, }; use address_space::{ - AddressSpace, FlatRange, GuestAddress, Listener, ListenerReqType, RegionIoEventFd, RegionType, + AddressAttr, AddressSpace, FlatRange, GuestAddress, Listener, ListenerReqType, RegionIoEventFd, + RegionType, }; use machine_manager::{ config::{get_pci_df, parse_bool, DEFAULT_VIRTQUEUE_SIZE}, @@ -161,7 +162,10 @@ fn iov_to_buf( } // GPAChecked: the iov has been checked in pop_avail(). - match address_space.read_object::(GuestAddress(iov.iov_base.raw_value() + offset)) { + match address_space.read_object::( + GuestAddress(iov.iov_base.raw_value() + offset), + AddressAttr::Ram, + ) { Ok(dat) => Some(dat), Err(ref e) => { error!("Read virtioqueue failed: {:?}", e); diff --git a/virtio/src/device/block.rs b/virtio/src/device/block.rs index 05541164..efb6492e 100644 --- a/virtio/src/device/block.rs +++ b/virtio/src/device/block.rs @@ -36,7 +36,7 @@ use crate::{ VIRTIO_BLK_WRITE_ZEROES_FLAG_UNMAP, VIRTIO_F_RING_EVENT_IDX, VIRTIO_F_RING_INDIRECT_DESC, VIRTIO_F_VERSION_1, VIRTIO_TYPE_BLOCK, }; -use address_space::{AddressSpace, GuestAddress, RegionCache}; +use address_space::{AddressAttr, AddressSpace, GuestAddress, RegionCache}; use block_backend::{ create_block_backend, remove_block_backend, BlockDriverOps, BlockIoErrorCallback, BlockProperty, BlockStatus, @@ -228,7 +228,10 @@ impl AioCompleteCb { } fn complete_one_request(&self, req: &Request, status: u8) -> Result<()> { - if let Err(ref e) = self.mem_space.write_object(&status, req.in_header) { + if let Err(ref e) = self + .mem_space + .write_object(&status, req.in_header, AddressAttr::Ram) + { bail!("Failed to write the status (blk io completion) {:?}", e); } diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index 16e17da1..09f43aeb 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -43,7 +43,7 @@ use crate::{ VIRTIO_NET_F_HOST_TSO4, VIRTIO_NET_F_HOST_TSO6, VIRTIO_NET_F_HOST_UFO, VIRTIO_NET_F_MAC, VIRTIO_NET_F_MQ, VIRTIO_NET_OK, VIRTIO_TYPE_NET, }; -use address_space::AddressSpace; +use address_space::{AddressAttr, AddressSpace}; use machine_manager::config::{ConfigCheck, NetDevcfg, NetworkInterfaceConfig}; use machine_manager::event_loop::{register_event_helper, unregister_event_helper, EventLoop}; use machine_manager::state_query::{ @@ -616,7 +616,8 @@ impl NetCtrlHandler { .in_iovec .first() .with_context(|| "Failed to get device writable iovec")?; - self.mem_space.write_object::(&ack, status.addr)?; + self.mem_space + .write_object::(&ack, status.addr, AddressAttr::Ram)?; locked_queue .vring diff --git a/virtio/src/device/rng.rs b/virtio/src/device/rng.rs index aaad7cb9..39a5d57c 100644 --- a/virtio/src/device/rng.rs +++ b/virtio/src/device/rng.rs @@ -29,7 +29,7 @@ use crate::{ ElemIovec, Queue, VirtioBase, VirtioDevice, VirtioInterrupt, VirtioInterruptType, VIRTIO_F_VERSION_1, VIRTIO_TYPE_RNG, }; -use address_space::AddressSpace; +use address_space::{AddressAttr, AddressSpace}; use machine_manager::{ config::{get_pci_df, valid_id, ConfigError, RngObjConfig, DEFAULT_VIRTQUEUE_SIZE}, event_loop::EventLoop, @@ -140,6 +140,7 @@ impl RngHandler { &mut buffer[offset..].as_ref(), iov.addr, u64::from(min(size - offset as u32, iov.len)), + AddressAttr::Ram, ) .with_context(|| "Failed to write request data for virtio rng")?; @@ -416,6 +417,7 @@ mod tests { use super::*; use crate::tests::address_space_init; use crate::*; + use address_space::AddressAttr; use address_space::GuestAddress; use machine_manager::config::{str_slip_to_clap, VmConfig, DEFAULT_VIRTQUEUE_SIZE}; @@ -620,15 +622,23 @@ mod tests { }; // write table descriptor for queue mem_space - .write_object(&desc, queue_config.desc_table) + .write_object(&desc, queue_config.desc_table, AddressAttr::Ram) .unwrap(); // write avail_ring idx mem_space - .write_object::(&0, GuestAddress(queue_config.avail_ring.0 + 4_u64)) + .write_object::( + &0, + GuestAddress(queue_config.avail_ring.0 + 4_u64), + AddressAttr::Ram, + ) .unwrap(); // write avail_ring idx mem_space - .write_object::(&1, GuestAddress(queue_config.avail_ring.0 + 2_u64)) + .write_object::( + &1, + GuestAddress(queue_config.avail_ring.0 + 2_u64), + AddressAttr::Ram, + ) .unwrap(); let buffer = vec![1_u8; data_len as usize]; @@ -639,13 +649,17 @@ mod tests { .read( &mut read_buffer.as_mut_slice(), GuestAddress(0x40000), - u64::from(data_len) + u64::from(data_len), + AddressAttr::Ram ) .is_ok()); assert_eq!(read_buffer, buffer); let idx = mem_space - .read_object::(GuestAddress(queue_config.used_ring.0 + 2_u64)) + .read_object::( + GuestAddress(queue_config.used_ring.0 + 2_u64), + AddressAttr::Ram, + ) .unwrap(); assert_eq!(idx, 1); assert_eq!(cloned_interrupt_evt.read().unwrap(), 1); @@ -703,7 +717,7 @@ mod tests { }; // write table descriptor for queue mem_space - .write_object(&desc, queue_config.desc_table) + .write_object(&desc, queue_config.desc_table, AddressAttr::Ram) .unwrap(); let desc = SplitVringDesc { @@ -717,16 +731,25 @@ mod tests { .write_object( &desc, GuestAddress(queue_config.desc_table.0 + size_of::() as u64), + AddressAttr::Ram, ) .unwrap(); // write avail_ring idx mem_space - .write_object::(&0, GuestAddress(queue_config.avail_ring.0 + 4_u64)) + .write_object::( + &0, + GuestAddress(queue_config.avail_ring.0 + 4_u64), + AddressAttr::Ram, + ) .unwrap(); // write avail_ring idx mem_space - .write_object::(&1, GuestAddress(queue_config.avail_ring.0 + 2_u64)) + .write_object::( + &1, + GuestAddress(queue_config.avail_ring.0 + 2_u64), + AddressAttr::Ram, + ) .unwrap(); let mut buffer1 = vec![1_u8; data_len as usize]; @@ -742,7 +765,8 @@ mod tests { .read( &mut read_buffer.as_mut_slice(), GuestAddress(0x40000), - u64::from(data_len) + u64::from(data_len), + AddressAttr::Ram ) .is_ok()); assert_eq!(read_buffer, buffer1_check); @@ -750,13 +774,17 @@ mod tests { .read( &mut read_buffer.as_mut_slice(), GuestAddress(0x50000), - u64::from(data_len) + u64::from(data_len), + AddressAttr::Ram ) .is_ok()); assert_eq!(read_buffer, buffer2_check); let idx = mem_space - .read_object::(GuestAddress(queue_config.used_ring.0 + 2_u64)) + .read_object::( + GuestAddress(queue_config.used_ring.0 + 2_u64), + AddressAttr::Ram, + ) .unwrap(); assert_eq!(idx, 1); assert_eq!(cloned_interrupt_evt.read().unwrap(), 1); diff --git a/virtio/src/device/scsi_cntlr.rs b/virtio/src/device/scsi_cntlr.rs index 9f6fc01d..6f4143fb 100644 --- a/virtio/src/device/scsi_cntlr.rs +++ b/virtio/src/device/scsi_cntlr.rs @@ -27,7 +27,7 @@ use crate::{ VirtioError, VirtioInterrupt, VirtioInterruptType, VIRTIO_F_RING_EVENT_IDX, VIRTIO_F_RING_INDIRECT_DESC, VIRTIO_F_VERSION_1, VIRTIO_TYPE_SCSI, }; -use address_space::{AddressSpace, GuestAddress}; +use address_space::{AddressAttr, AddressSpace, GuestAddress}; use block_backend::BlockIoErrorCallback; use devices::ScsiBus::{ ScsiBus, ScsiRequest, ScsiRequestOps, ScsiSense, ScsiXferMode, CHECK_CONDITION, @@ -535,7 +535,7 @@ impl VirtioScsiReq fn complete(&self) -> Result<()> { self.mem_space - .write_object(&self.resp, self.resp_addr) + .write_object(&self.resp, self.resp_addr, AddressAttr::Ram) .with_context(|| "Failed to write the scsi response")?; let mut queue_lock = self.queue.lock().unwrap(); @@ -621,7 +621,7 @@ impl ScsiCtrlQueueHandler { .with_context(|| "Error request in ctrl queue. Empty dataout buf!")?; let ctrl_type = self .mem_space - .read_object::(ctrl_desc.addr) + .read_object::(ctrl_desc.addr, AddressAttr::Ram) .with_context(|| "Failed to get control queue descriptor")?; match ctrl_type { diff --git a/virtio/src/device/serial.rs b/virtio/src/device/serial.rs index 37256dc7..ac093df8 100644 --- a/virtio/src/device/serial.rs +++ b/virtio/src/device/serial.rs @@ -29,7 +29,7 @@ use crate::{ Element, Queue, VirtioBase, VirtioDevice, VirtioError, VirtioInterrupt, VirtioInterruptType, VIRTIO_CONSOLE_F_MULTIPORT, VIRTIO_CONSOLE_F_SIZE, VIRTIO_F_VERSION_1, VIRTIO_TYPE_CONSOLE, }; -use address_space::AddressSpace; +use address_space::{AddressAttr, AddressSpace}; use chardev_backend::chardev::{Chardev, ChardevNotifyDevice, ChardevStatus, InputReceiver}; use machine_manager::{ config::{ChardevType, VirtioSerialInfo, VirtioSerialPortCfg, DEFAULT_VIRTQUEUE_SIZE}, @@ -591,7 +591,12 @@ impl SerialPortHandler { // GPAChecked: the elem_iov has been checked in pop_avail(). self.mem_space - .write(&mut source_slice, elem_iov.addr, len as u64) + .write( + &mut source_slice, + elem_iov.addr, + len as u64, + AddressAttr::Ram, + ) .with_context(|| { format!( "Failed to write slice for virtio serial port input: addr {:X} len {}", diff --git a/virtio/src/transport/virtio_pci.rs b/virtio/src/transport/virtio_pci.rs index 00db23ee..0c4bfc88 100644 --- a/virtio/src/transport/virtio_pci.rs +++ b/virtio/src/transport/virtio_pci.rs @@ -35,7 +35,9 @@ use crate::{ }; #[cfg(feature = "virtio_gpu")] use address_space::HostMemMapping; -use address_space::{AddressRange, AddressSpace, GuestAddress, Region, RegionIoEventFd, RegionOps}; +use address_space::{ + AddressAttr, AddressRange, AddressSpace, GuestAddress, Region, RegionIoEventFd, RegionOps, +}; use devices::pci::config::{ RegionType, BAR_SPACE_UNMAPPED, DEVICE_ID, MINIMUM_BAR_SIZE_FOR_MMIO, PCIE_CONFIG_SPACE_SIZE, PCI_SUBDEVICE_ID_QEMU, PCI_VENDOR_ID_REDHAT_QUMRANET, REG_SIZE, REVISION_ID, STATUS, @@ -939,6 +941,7 @@ impl VirtioPciDevice { &mut data, GuestAddress(bar_base + u64::from(off)), u64::from(len), + AddressAttr::MMIO, ) } else { let mut data = self.base.config.config[pci_cfg_data_offset..].as_mut(); @@ -946,6 +949,7 @@ impl VirtioPciDevice { &mut data, GuestAddress(bar_base + u64::from(off)), u64::from(len), + AddressAttr::MMIO, ) }; if let Err(e) = result { diff --git a/virtio/src/vhost/kernel/vsock.rs b/virtio/src/vhost/kernel/vsock.rs index 8774fbeb..53a38745 100644 --- a/virtio/src/vhost/kernel/vsock.rs +++ b/virtio/src/vhost/kernel/vsock.rs @@ -26,7 +26,7 @@ use crate::{ Queue, VirtioBase, VirtioDevice, VirtioError, VirtioInterrupt, VirtioInterruptType, VIRTIO_F_ACCESS_PLATFORM, VIRTIO_TYPE_VSOCK, }; -use address_space::AddressSpace; +use address_space::{AddressAttr, AddressSpace}; use machine_manager::config::{get_pci_df, parse_bool, valid_id, DEFAULT_VIRTQUEUE_SIZE}; use machine_manager::event_loop::{register_event_helper, unregister_event_helper}; use migration::{DeviceStateDesc, FieldDesc, MigrationHook, MigrationManager, StateTransfer}; @@ -168,6 +168,7 @@ impl Vsock { .write_object( &VIRTIO_VSOCK_EVENT_TRANSPORT_RESET, element.in_iovec[0].addr, + AddressAttr::Ram, ) .with_context(|| "Failed to write buf for virtio vsock event")?; event_queue_locked -- Gitee From 9d494d1d2fc33a4804c62607f6b6534e75a559bd Mon Sep 17 00:00:00 2001 From: Xu Yandong Date: Mon, 26 Aug 2024 08:24:50 +0000 Subject: [PATCH 306/489] tests: add address attr Signed-off-by: Yandong Xu Author: Yandong Xu Date: Mon Aug 26 08:24:50 2024 +0000 --- address_space/src/address_space.rs | 14 +++++--- devices/src/legacy/fwcfg.rs | 44 ++++++++++++++++++++++---- virtio/src/device/balloon.rs | 42 ++++++++++++++++++------ virtio/src/device/block.rs | 33 +++++++++++++++---- virtio/src/queue/split.rs | 51 +++++++++++++++++++++--------- 5 files changed, 143 insertions(+), 41 deletions(-) diff --git a/address_space/src/address_space.rs b/address_space/src/address_space.rs index 58e304ab..e138fee3 100644 --- a/address_space/src/address_space.rs +++ b/address_space/src/address_space.rs @@ -854,7 +854,7 @@ mod test { use vmm_sys_util::eventfd::EventFd; use super::*; - use crate::{HostMemMapping, RegionOps}; + use crate::{AddressAttr, HostMemMapping, RegionOps}; #[derive(Default, Clone)] struct TestListener { @@ -1324,9 +1324,15 @@ mod test { .unwrap(); let data: u64 = 10000; - assert!(space.write_object(&data, GuestAddress(992)).is_ok()); - let data1: u64 = space.read_object(GuestAddress(992)).unwrap(); + assert!(space + .write_object(&data, GuestAddress(992), AddressAttr::Ram) + .is_ok()); + let data1: u64 = space + .read_object(GuestAddress(992), AddressAttr::Ram) + .unwrap(); assert_eq!(data1, 10000); - assert!(space.write_object(&data, GuestAddress(993)).is_err()); + assert!(space + .write_object(&data, GuestAddress(993), AddressAttr::Ram) + .is_err()); } } diff --git a/devices/src/legacy/fwcfg.rs b/devices/src/legacy/fwcfg.rs index ce36d655..b6a57a27 100644 --- a/devices/src/legacy/fwcfg.rs +++ b/devices/src/legacy/fwcfg.rs @@ -1436,7 +1436,12 @@ mod test { let addr = GuestAddress(0x0000); fwcfg_common .mem_space - .write(&mut dma_request.as_ref(), addr, dma_request.len() as u64) + .write( + &mut dma_request.as_ref(), + addr, + dma_request.len() as u64, + AddressAttr::Ram, + ) .unwrap(); // [2]set dma addr. @@ -1446,7 +1451,13 @@ mod test { assert_eq!(fwcfg_common.handle_dma_request().is_ok(), true); // [4]check dma response. - assert_eq!(fwcfg_common.mem_space.read_object::(addr).unwrap(), 0); + assert_eq!( + fwcfg_common + .mem_space + .read_object::(addr, AddressAttr::Ram) + .unwrap(), + 0 + ); // [5]check dma write result. let mut read_dma_buf = Vec::new(); @@ -1454,7 +1465,12 @@ mod test { let len = sig_entry_data.len(); fwcfg_common .mem_space - .read(&mut read_dma_buf, GuestAddress(0xffff), len as u64) + .read( + &mut read_dma_buf, + GuestAddress(0xffff), + len as u64, + AddressAttr::Ram, + ) .unwrap(); assert_eq!(read_dma_buf, sig_entry_data); @@ -1467,7 +1483,12 @@ mod test { let addr = GuestAddress(0x0000); fwcfg_common .mem_space - .write(&mut dma_request.as_ref(), addr, dma_request.len() as u64) + .write( + &mut dma_request.as_ref(), + addr, + dma_request.len() as u64, + AddressAttr::Ram, + ) .unwrap(); fwcfg_common.dma_addr = addr; @@ -1475,14 +1496,25 @@ mod test { assert_eq!(fwcfg_common.handle_dma_request().is_ok(), true); // Result should be all zero. - assert_eq!(fwcfg_common.mem_space.read_object::(addr).unwrap(), 0); + assert_eq!( + fwcfg_common + .mem_space + .read_object::(addr, AddressAttr::Ram) + .unwrap(), + 0 + ); let mut read_dma_buf = Vec::new(); let all_zero = vec![0x0_u8; 4]; let len = all_zero.len(); fwcfg_common .mem_space - .read(&mut read_dma_buf, GuestAddress(0xffff), len as u64) + .read( + &mut read_dma_buf, + GuestAddress(0xffff), + len as u64, + AddressAttr::Ram, + ) .unwrap(); assert_eq!(read_dma_buf, all_zero); } diff --git a/virtio/src/device/balloon.rs b/virtio/src/device/balloon.rs index 421cbb8a..094d04f6 100644 --- a/virtio/src/device/balloon.rs +++ b/virtio/src/device/balloon.rs @@ -1261,7 +1261,7 @@ mod tests { use super::*; use crate::tests::{address_space_init, MEMORY_SIZE}; use crate::*; - use address_space::{AddressRange, HostMemMapping, Region}; + use address_space::{AddressAttr, AddressRange, HostMemMapping, Region}; use machine_manager::event_loop::EventLoop; const QUEUE_SIZE: u16 = 256; @@ -1507,7 +1507,11 @@ mod tests { // Set desc table. mem_space - .write_object::(&desc, GuestAddress(queue_config_inf.desc_table.0)) + .write_object::( + &desc, + GuestAddress(queue_config_inf.desc_table.0), + AddressAttr::Ram, + ) .unwrap(); let ele = GuestIovec { @@ -1515,13 +1519,21 @@ mod tests { iov_len: std::mem::size_of::() as u64, }; mem_space - .write_object::(&ele, GuestAddress(0x2000)) + .write_object::(&ele, GuestAddress(0x2000), AddressAttr::Ram) .unwrap(); mem_space - .write_object::(&0, GuestAddress(queue_config_inf.avail_ring.0 + 4_u64)) + .write_object::( + &0, + GuestAddress(queue_config_inf.avail_ring.0 + 4_u64), + AddressAttr::Ram, + ) .unwrap(); mem_space - .write_object::(&1, GuestAddress(queue_config_inf.avail_ring.0 + 2_u64)) + .write_object::( + &1, + GuestAddress(queue_config_inf.avail_ring.0 + 2_u64), + AddressAttr::Ram, + ) .unwrap(); assert!(handler.process_balloon_queue(BALLOON_INFLATE_EVENT).is_ok()); @@ -1537,17 +1549,29 @@ mod tests { }; mem_space - .write_object::(&desc, GuestAddress(queue_config_def.desc_table.0)) + .write_object::( + &desc, + GuestAddress(queue_config_def.desc_table.0), + AddressAttr::Ram, + ) .unwrap(); mem_space - .write_object::(&ele, GuestAddress(0x3000)) + .write_object::(&ele, GuestAddress(0x3000), AddressAttr::Ram) .unwrap(); mem_space - .write_object::(&0, GuestAddress(queue_config_def.avail_ring.0 + 4_u64)) + .write_object::( + &0, + GuestAddress(queue_config_def.avail_ring.0 + 4_u64), + AddressAttr::Ram, + ) .unwrap(); mem_space - .write_object::(&1, GuestAddress(queue_config_def.avail_ring.0 + 2_u64)) + .write_object::( + &1, + GuestAddress(queue_config_def.avail_ring.0 + 2_u64), + AddressAttr::Ram, + ) .unwrap(); assert!(handler.process_balloon_queue(BALLOON_DEFLATE_EVENT).is_ok()); diff --git a/virtio/src/device/block.rs b/virtio/src/device/block.rs index efb6492e..1d1749be 100644 --- a/virtio/src/device/block.rs +++ b/virtio/src/device/block.rs @@ -1457,7 +1457,7 @@ mod tests { use super::*; use crate::tests::address_space_init; use crate::*; - use address_space::GuestAddress; + use address_space::{AddressAttr, GuestAddress}; use machine_manager::config::{ str_slip_to_clap, IothreadConfig, VmConfig, DEFAULT_VIRTQUEUE_SIZE, }; @@ -1715,7 +1715,11 @@ mod tests { next: 1, }; mem_space - .write_object::(&desc, GuestAddress(queue_config.desc_table.0)) + .write_object::( + &desc, + GuestAddress(queue_config.desc_table.0), + AddressAttr::Ram, + ) .unwrap(); // write RequestOutHeader to first desc @@ -1725,7 +1729,7 @@ mod tests { sector: 0, }; mem_space - .write_object::(&req_head, GuestAddress(0x100)) + .write_object::(&req_head, GuestAddress(0x100), AddressAttr::Ram) .unwrap(); // making the second descriptor entry to receive data from device @@ -1736,17 +1740,29 @@ mod tests { next: 2, }; mem_space - .write_object::(&desc, GuestAddress(queue_config.desc_table.0 + 16_u64)) + .write_object::( + &desc, + GuestAddress(queue_config.desc_table.0 + 16_u64), + AddressAttr::Ram, + ) .unwrap(); // write avail_ring idx mem_space - .write_object::(&0, GuestAddress(queue_config.avail_ring.0 + 4_u64)) + .write_object::( + &0, + GuestAddress(queue_config.avail_ring.0 + 4_u64), + AddressAttr::Ram, + ) .unwrap(); // write avail_ring id mem_space - .write_object::(&1, GuestAddress(queue_config.avail_ring.0 + 2_u64)) + .write_object::( + &1, + GuestAddress(queue_config.avail_ring.0 + 2_u64), + AddressAttr::Ram, + ) .unwrap(); // imitating guest OS to send notification. @@ -1764,7 +1780,10 @@ mod tests { // get used_ring data let idx = mem_space - .read_object::(GuestAddress(queue_config.used_ring.0 + 2_u64)) + .read_object::( + GuestAddress(queue_config.used_ring.0 + 2_u64), + AddressAttr::Ram, + ) .unwrap(); if idx == 1 { break; diff --git a/virtio/src/queue/split.rs b/virtio/src/queue/split.rs index 092df0e1..6ebbbc4e 100644 --- a/virtio/src/queue/split.rs +++ b/virtio/src/queue/split.rs @@ -990,7 +990,7 @@ mod tests { use super::*; use crate::tests::address_space_init; use crate::{Queue, QUEUE_TYPE_PACKED_VRING, QUEUE_TYPE_SPLIT_VRING}; - use address_space::{AddressSpace, GuestAddress}; + use address_space::{AddressAttr, AddressSpace, GuestAddress}; trait VringOpsTest { fn set_desc( @@ -1049,6 +1049,7 @@ mod tests { sys_mem.write_object::( &desc, GuestAddress(self.desc_table.0 + desc_addr_offset), + AddressAttr::Ram, )?; Ok(()) @@ -1056,15 +1057,21 @@ mod tests { fn set_avail_ring_idx(&self, sys_mem: &Arc, idx: u16) -> Result<()> { let avail_idx_offset = 2_u64; - sys_mem - .write_object::(&idx, GuestAddress(self.avail_ring.0 + avail_idx_offset))?; + sys_mem.write_object::( + &idx, + GuestAddress(self.avail_ring.0 + avail_idx_offset), + AddressAttr::Ram, + )?; Ok(()) } fn set_avail_ring_flags(&self, sys_mem: &Arc, flags: u16) -> Result<()> { let avail_idx_offset = 0_u64; - sys_mem - .write_object::(&flags, GuestAddress(self.avail_ring.0 + avail_idx_offset))?; + sys_mem.write_object::( + &flags, + GuestAddress(self.avail_ring.0 + avail_idx_offset), + AddressAttr::Ram, + )?; Ok(()) } @@ -1078,6 +1085,7 @@ mod tests { sys_mem.write_object::( &desc_index, GuestAddress(self.avail_ring.0 + avail_idx_offset), + AddressAttr::Ram, )?; Ok(()) } @@ -1085,36 +1093,49 @@ mod tests { fn get_avail_event(&self, sys_mem: &Arc) -> Result { let avail_event_idx_offset = VRING_FLAGS_AND_IDX_LEN + USEDELEM_LEN * u64::from(self.actual_size()); - let event_idx = sys_mem - .read_object::(GuestAddress(self.used_ring.0 + avail_event_idx_offset))?; + let event_idx = sys_mem.read_object::( + GuestAddress(self.used_ring.0 + avail_event_idx_offset), + AddressAttr::Ram, + )?; Ok(event_idx) } fn get_used_elem(&self, sys_mem: &Arc, index: u16) -> Result { let used_elem_offset = VRING_FLAGS_AND_IDX_LEN + USEDELEM_LEN * u64::from(index); - let used_elem = sys_mem - .read_object::(GuestAddress(self.used_ring.0 + used_elem_offset))?; + let used_elem = sys_mem.read_object::( + GuestAddress(self.used_ring.0 + used_elem_offset), + AddressAttr::Ram, + )?; Ok(used_elem) } fn get_used_ring_idx(&self, sys_mem: &Arc) -> Result { let used_idx_offset = VRING_IDX_POSITION; - let idx = - sys_mem.read_object::(GuestAddress(self.used_ring.0 + used_idx_offset))?; + let idx = sys_mem.read_object::( + GuestAddress(self.used_ring.0 + used_idx_offset), + AddressAttr::Ram, + )?; Ok(idx) } fn set_used_ring_idx(&self, sys_mem: &Arc, idx: u16) -> Result<()> { let used_idx_offset = VRING_IDX_POSITION; - sys_mem.write_object::(&idx, GuestAddress(self.used_ring.0 + used_idx_offset))?; + sys_mem.write_object::( + &idx, + GuestAddress(self.used_ring.0 + used_idx_offset), + AddressAttr::Ram, + )?; Ok(()) } fn set_used_event_idx(&self, sys_mem: &Arc, idx: u16) -> Result<()> { let event_idx_offset = VRING_FLAGS_AND_IDX_LEN + AVAILELEM_LEN * u64::from(self.actual_size()); - sys_mem - .write_object::(&idx, GuestAddress(self.avail_ring.0 + event_idx_offset))?; + sys_mem.write_object::( + &idx, + GuestAddress(self.avail_ring.0 + event_idx_offset), + AddressAttr::Ram, + )?; Ok(()) } } @@ -1133,7 +1154,7 @@ mod tests { flags, next, }; - sys_mem.write_object::(&desc, desc_addr)?; + sys_mem.write_object::(&desc, desc_addr, AddressAttr::Ram)?; Ok(()) } -- Gitee From ae8b745d8435c46fc5fad489b0ea3a3d8dc9fa84 Mon Sep 17 00:00:00 2001 From: Li Huachao Date: Mon, 26 Aug 2024 13:55:17 +0800 Subject: [PATCH 307/489] Memory: Add an unsafe flag to the get host address function. It is dangerous to read and write directly to hva. So we add unsafe to mark this function is not safe! Signed-off-by: Li Huachao Signed-off-by: Yandong Xu --- address_space/src/address_space.rs | 59 ++++++--- address_space/src/region.rs | 28 +++-- devices/src/legacy/pflash.rs | 32 ++++- devices/src/legacy/ramfb.rs | 7 +- hypervisor/src/kvm/listener.rs | 5 +- vfio/src/vfio_dev.rs | 7 +- virtio/src/device/balloon.rs | 54 +++++--- virtio/src/device/block.rs | 21 +++- virtio/src/device/rng.rs | 42 +++++-- virtio/src/queue/split.rs | 193 +++++++++++++++++++---------- virtio/src/vhost/kernel/mod.rs | 11 +- virtio/src/vhost/user/client.rs | 9 +- 12 files changed, 315 insertions(+), 153 deletions(-) diff --git a/address_space/src/address_space.rs b/address_space/src/address_space.rs index e138fee3..7e9fa729 100644 --- a/address_space/src/address_space.rs +++ b/address_space/src/address_space.rs @@ -496,19 +496,27 @@ impl AddressSpace { Ok(()) } - /// Return the host address according to the given `GuestAddress`. + /// Return the host address according to the given `GuestAddress`. It is dangerous to + /// read and write directly to hva. We strongly recommend that you use the read and + /// write interface provided by AddressSpace unless you know exactly what you need and + /// are sure it is safe. /// /// # Arguments /// /// * `addr` - Guest address. - pub fn get_host_address(&self, addr: GuestAddress) -> Option { + /// + /// # Safety + /// + /// Using this function, the caller needs to make it clear that hva is always in the ram + /// range of the virtual machine. And if you want to operate [hva,hva+size], the range + /// from hva to hva+size needs to be in the ram range. + pub unsafe fn get_host_address(&self, addr: GuestAddress, attr: AddressAttr) -> Option { let view = self.flat_view.load(); - view.find_flatrange(addr).and_then(|range| { let offset = addr.offset_from(range.addr_range.base); range .owner - .get_host_address() + .get_host_address(attr) .map(|host| host + range.offset_in_region + offset) }) } @@ -520,7 +528,7 @@ impl AddressSpace { /// * `addr` - Guest address. /// Return Error if the `addr` is not mapped. /// or return the HVA address and available mem length - pub fn addr_cache_init(&self, addr: GuestAddress) -> Option<(u64, u64)> { + pub fn addr_cache_init(&self, addr: GuestAddress, attr: AddressAttr) -> Option<(u64, u64)> { let view = self.flat_view.load(); if let Some(flat_range) = view.find_flatrange(addr) { @@ -530,12 +538,15 @@ impl AddressSpace { let region_remain = flat_range.owner.size() - region_offset; let fr_remain = flat_range.addr_range.size - fr_offset; - return flat_range.owner.get_host_address().map(|host| { - ( - host + region_offset, - std::cmp::min(fr_remain, region_remain), - ) - }); + // SAFETY: addr and size is in ram region. + return unsafe { + flat_range.owner.get_host_address(attr).map(|host| { + ( + host + region_offset, + std::cmp::min(fr_remain, region_remain), + ) + }) + }; } None @@ -589,7 +600,7 @@ impl AddressSpace { cache: &Option, ) -> Option<(u64, u64)> { if cache.is_none() { - return self.addr_cache_init(addr); + return self.addr_cache_init(addr, AddressAttr::Ram); } let region_cache = cache.unwrap(); if addr.0 >= region_cache.start && addr.0 < region_cache.end { @@ -598,7 +609,7 @@ impl AddressSpace { region_cache.end - addr.0, )) } else { - self.addr_cache_init(addr) + self.addr_cache_init(addr, AddressAttr::Ram) } } @@ -616,13 +627,17 @@ impl AddressSpace { }) } - pub fn get_region_cache(&self, addr: GuestAddress) -> Option { + pub fn get_region_cache(&self, addr: GuestAddress, attr: AddressAttr) -> Option { let view = &self.flat_view.load(); if let Some(range) = view.find_flatrange(addr) { let reg_type = range.owner.region_type(); let start = range.addr_range.base.0; let end = range.addr_range.end_addr().0; - let host_base = self.get_host_address(GuestAddress(start)).unwrap_or(0); + // SAFETY: the size is in region range, and the type will be checked in get_host_address. + let host_base = unsafe { + self.get_host_address(GuestAddress(start), attr) + .unwrap_or(0) + }; let cache = RegionCache { reg_type, host_base, @@ -1271,11 +1286,11 @@ mod test { assert!(space.address_in_memory(GuestAddress(2900), 0)); assert_eq!( - space.get_host_address(GuestAddress(500)), + unsafe { space.get_host_address(GuestAddress(500), AddressAttr::Ram) }, Some(ram1.host_address() + 500) ); assert_eq!( - space.get_host_address(GuestAddress(2500)), + unsafe { space.get_host_address(GuestAddress(2500), AddressAttr::Ram) }, Some(ram2.host_address() + 500) ); @@ -1302,12 +1317,16 @@ mod test { assert!(space.address_in_memory(GuestAddress(2900), 0)); assert_eq!( - space.get_host_address(GuestAddress(500)), + unsafe { space.get_host_address(GuestAddress(500), AddressAttr::Ram) }, Some(ram1.host_address() + 500) ); - assert!(space.get_host_address(GuestAddress(2400)).is_none()); + assert!(unsafe { + space + .get_host_address(GuestAddress(2400), AddressAttr::Ram) + .is_none() + }); assert_eq!( - space.get_host_address(GuestAddress(2500)), + unsafe { space.get_host_address(GuestAddress(2500), AddressAttr::Ram) }, Some(ram2.host_address() + 500) ); } diff --git a/address_space/src/region.rs b/address_space/src/region.rs index 5d908db0..48c70302 100644 --- a/address_space/src/region.rs +++ b/address_space/src/region.rs @@ -21,8 +21,8 @@ use log::{debug, warn}; use crate::address_space::FlatView; use crate::{ - AddressRange, AddressSpace, AddressSpaceError, FileBackend, GuestAddress, HostMemMapping, - RegionOps, + AddressAttr, AddressRange, AddressSpace, AddressSpaceError, FileBackend, GuestAddress, + HostMemMapping, RegionOps, }; use migration::{migration::Migratable, MigrationManager}; @@ -467,11 +467,21 @@ impl Region { /// Get the host address if this region is backed by host-memory, /// Return `None` if it is not a Ram-type region. - pub fn get_host_address(&self) -> Option { - if self.region_type != RegionType::Ram - && self.region_type != RegionType::RamDevice - && self.region_type != RegionType::RomDevice - { + /// + /// # Safety + /// + /// Need to make it clear that hva is always in the ram range of the virtual machine. + /// And if you want to operate [hva,hva+size], the range from hva to hva+size needs + /// to be in the ram range. + pub unsafe fn get_host_address(&self, attr: AddressAttr) -> Option { + let region_type = match attr { + AddressAttr::Ram => RegionType::Ram, + AddressAttr::MMIO => return None, + AddressAttr::RamDevice => RegionType::RamDevice, + AddressAttr::RomDevice | AddressAttr::RomDeviceForce => RegionType::RomDevice, + }; + + if self.region_type != region_type { return None; } self.mem_mapping.as_ref().map(|r| r.host_address()) @@ -1155,7 +1165,7 @@ mod test { assert_eq!(&data, &mut res_data); assert_eq!( - ram_region.get_host_address().unwrap(), + unsafe { ram_region.get_host_address(AddressAttr::Ram).unwrap() }, mem_mapping.host_address() ); @@ -1235,7 +1245,7 @@ mod test { .is_ok()); assert_eq!(data.to_vec(), data_res.to_vec()); - assert!(io_region.get_host_address().is_none()); + assert!(unsafe { io_region.get_host_address(AddressAttr::Ram).is_none() }); } #[test] diff --git a/devices/src/legacy/pflash.rs b/devices/src/legacy/pflash.rs index a5c16ccd..6c3138e0 100644 --- a/devices/src/legacy/pflash.rs +++ b/devices/src/legacy/pflash.rs @@ -21,7 +21,7 @@ use super::error::LegacyError; use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; use crate::{convert_bus_mut, Device, DeviceBase, MUT_SYS_BUS}; use acpi::AmlBuilder; -use address_space::{FileBackend, GuestAddress, HostMemMapping, Region}; +use address_space::{AddressAttr, FileBackend, GuestAddress, HostMemMapping, Region}; use util::gen_base_func; use util::num_ops::{deposit_u32, extract_u32, read_data_u32, round_up, write_data_u32}; use util::unix::host_page_size; @@ -337,9 +337,17 @@ impl PFlash { ))); } - let addr: u64 = mr - .get_host_address() - .with_context(|| "Failed to get host address.")?; + let attr = match mr.region_type() { + address_space::RegionType::Ram => AddressAttr::Ram, + address_space::RegionType::RomDevice => AddressAttr::RomDevice, + _ => bail!("Unexpected region type."), + }; + + // SAFETY: size has been checked. + let addr: u64 = unsafe { + mr.get_host_address(attr) + .with_context(|| "Failed to get host address.") + }?; let ret = // SAFETY: addr and size are valid. unsafe { @@ -366,7 +374,13 @@ impl PFlash { data.len() as u64 ))); } - let host_addr = mr.get_host_address().unwrap(); + let attr = match mr.region_type() { + address_space::RegionType::Ram => AddressAttr::Ram, + address_space::RegionType::RomDevice => AddressAttr::RomDevice, + _ => bail!("Unexpected region type."), + }; + // SAFETY: size has been checked. + let host_addr = unsafe { mr.get_host_address(attr).unwrap() }; let src = // SAFETY: host_addr of the region is local allocated and sanity has been checked. unsafe { std::slice::from_raw_parts_mut((host_addr + offset) as *mut u8, data.len()) }; @@ -394,7 +408,13 @@ impl PFlash { data.len() as u64 ))); } - let host_addr = mr.get_host_address().unwrap(); + let attr = match mr.region_type() { + address_space::RegionType::Ram => AddressAttr::Ram, + address_space::RegionType::RomDevice => AddressAttr::RomDevice, + _ => bail!("Unexpected region type."), + }; + // SAFETY: size has been checked. + let host_addr = unsafe { mr.get_host_address(attr).unwrap() }; let mut dst = // SAFETY: host_addr of the region is local allocated and sanity has been checked. unsafe { std::slice::from_raw_parts_mut((host_addr + offset) as *mut u8, data.len()) }; diff --git a/devices/src/legacy/ramfb.rs b/devices/src/legacy/ramfb.rs index 8363213a..569a5936 100644 --- a/devices/src/legacy/ramfb.rs +++ b/devices/src/legacy/ramfb.rs @@ -24,7 +24,7 @@ use super::fwcfg::{FwCfgOps, FwCfgWriteCallback}; use crate::sysbus::{SysBus, SysBusDevBase, SysBusDevOps, SysBusDevType}; use crate::{convert_bus_mut, Device, DeviceBase, MUT_SYS_BUS}; use acpi::AmlBuilder; -use address_space::{AddressSpace, GuestAddress}; +use address_space::{AddressAttr, AddressSpace, GuestAddress}; use machine_manager::config::valid_id; use machine_manager::event_loop::EventLoop; use ui::console::{ @@ -125,7 +125,10 @@ impl RamfbState { stride = linesize; } - let fb_addr = match self.sys_mem.addr_cache_init(GuestAddress(addr)) { + let fb_addr = match self + .sys_mem + .addr_cache_init(GuestAddress(addr), AddressAttr::Ram) + { Some((hva, len)) => { if len < u64::from(stride) { error!("Insufficient contiguous memory length"); diff --git a/hypervisor/src/kvm/listener.rs b/hypervisor/src/kvm/listener.rs index 327df1d8..1a6943ff 100644 --- a/hypervisor/src/kvm/listener.rs +++ b/hypervisor/src/kvm/listener.rs @@ -22,7 +22,7 @@ use log::{debug, warn}; use crate::HypervisorError; use address_space::{ - AddressRange, AddressSpaceError, FlatRange, Listener, ListenerReqType, MemSlot, + AddressAttr, AddressRange, AddressSpaceError, FlatRange, Listener, ListenerReqType, MemSlot, RegionIoEventFd, RegionType, }; use util::{num_ops::round_down, unix::host_page_size}; @@ -193,7 +193,8 @@ impl KvmMemoryListener { let align_adjust = aligned_addr.raw_value() - flat_range.addr_range.base.raw_value(); // `unwrap()` won't fail because Ram-type Region definitely has hva - let aligned_hva = flat_range.owner.get_host_address().unwrap() + // SAFETY: size has been checked. + let aligned_hva = unsafe { flat_range.owner.get_host_address(attr).unwrap() } + flat_range.offset_in_region + align_adjust; diff --git a/vfio/src/vfio_dev.rs b/vfio/src/vfio_dev.rs index cdba51c7..5a6fa444 100644 --- a/vfio/src/vfio_dev.rs +++ b/vfio/src/vfio_dev.rs @@ -32,7 +32,9 @@ use vmm_sys_util::{ioctl_io_nr, ioctl_ioc_nr}; use super::{CONTAINERS, GROUPS, KVM_DEVICE_FD}; use crate::VfioError; -use address_space::{AddressSpace, FlatRange, Listener, ListenerReqType, RegionIoEventFd}; +use address_space::{ + AddressAttr, AddressSpace, FlatRange, Listener, ListenerReqType, RegionIoEventFd, +}; /// Refer to VFIO in https://github.com/torvalds/linux/blob/master/include/uapi/linux/vfio.h const IOMMU_GROUP: &str = "iommu_group"; @@ -227,7 +229,8 @@ impl VfioContainer { let guest_phys_addr = fr.addr_range.base.raw_value(); let memory_size = fr.addr_range.size; - let hva = match fr.owner.get_host_address() { + // SAFETY: memory_size is range's size, so we make sure [hva, hva+size] is in ram range. + let hva = match unsafe { fr.owner.get_host_address(AddressAttr::Ram) } { Some(addr) => addr, None => bail!("Failed to get host address"), }; diff --git a/virtio/src/device/balloon.rs b/virtio/src/device/balloon.rs index 094d04f6..894a84a5 100644 --- a/virtio/src/device/balloon.rs +++ b/virtio/src/device/balloon.rs @@ -491,7 +491,8 @@ impl BlnMemInfo { fn add_mem_range(&self, fr: &FlatRange) { let guest_phys_addr = fr.addr_range.base.raw_value(); let memory_size = fr.addr_range.size; - if let Some(host_addr) = fr.owner.get_host_address() { + // SAFETY: memory_size is range's size, so we make sure [hva, hva+size] is in ram range. + if let Some(host_addr) = unsafe { fr.owner.get_host_address(AddressAttr::Ram) } { let userspace_addr = host_addr + fr.offset_in_region; let reg_page_size = fr.owner.get_region_page_size(); self.regions.lock().unwrap().push(BlnMemoryRegion { @@ -509,7 +510,8 @@ impl BlnMemInfo { fn delete_mem_range(&self, fr: &FlatRange) { let mut mem_regions = self.regions.lock().unwrap(); - if let Some(host_addr) = fr.owner.get_host_address() { + // SAFETY: memory_size is range's size, so we make sure [hva, hva+size] is in ram range. + if let Some(host_addr) = unsafe { fr.owner.get_host_address(AddressAttr::Ram) } { let reg_page_size = fr.owner.get_region_page_size(); let target = BlnMemoryRegion { guest_phys_addr: fr.addr_range.base.raw_value(), @@ -1437,33 +1439,45 @@ mod tests { let mut queue_config_inf = QueueConfig::new(QUEUE_SIZE); queue_config_inf.desc_table = GuestAddress(0x100); - queue_config_inf.addr_cache.desc_table_host = mem_space - .get_host_address(queue_config_inf.desc_table) - .unwrap(); + queue_config_inf.addr_cache.desc_table_host = unsafe { + mem_space + .get_host_address(queue_config_inf.desc_table, AddressAttr::Ram) + .unwrap() + }; queue_config_inf.avail_ring = GuestAddress(0x300); - queue_config_inf.addr_cache.avail_ring_host = mem_space - .get_host_address(queue_config_inf.avail_ring) - .unwrap(); + queue_config_inf.addr_cache.avail_ring_host = unsafe { + mem_space + .get_host_address(queue_config_inf.avail_ring, AddressAttr::Ram) + .unwrap() + }; queue_config_inf.used_ring = GuestAddress(0x600); - queue_config_inf.addr_cache.used_ring_host = mem_space - .get_host_address(queue_config_inf.used_ring) - .unwrap(); + queue_config_inf.addr_cache.used_ring_host = unsafe { + mem_space + .get_host_address(queue_config_inf.used_ring, AddressAttr::Ram) + .unwrap() + }; queue_config_inf.ready = true; queue_config_inf.size = QUEUE_SIZE; let mut queue_config_def = QueueConfig::new(QUEUE_SIZE); queue_config_def.desc_table = GuestAddress(0x1100); - queue_config_def.addr_cache.desc_table_host = mem_space - .get_host_address(queue_config_def.desc_table) - .unwrap(); + queue_config_def.addr_cache.desc_table_host = unsafe { + mem_space + .get_host_address(queue_config_def.desc_table, AddressAttr::Ram) + .unwrap() + }; queue_config_def.avail_ring = GuestAddress(0x1300); - queue_config_def.addr_cache.avail_ring_host = mem_space - .get_host_address(queue_config_def.avail_ring) - .unwrap(); + queue_config_def.addr_cache.avail_ring_host = unsafe { + mem_space + .get_host_address(queue_config_def.avail_ring, AddressAttr::Ram) + .unwrap() + }; queue_config_def.used_ring = GuestAddress(0x1600); - queue_config_def.addr_cache.used_ring_host = mem_space - .get_host_address(queue_config_def.used_ring) - .unwrap(); + queue_config_def.addr_cache.used_ring_host = unsafe { + mem_space + .get_host_address(queue_config_def.used_ring, AddressAttr::Ram) + .unwrap() + }; queue_config_def.ready = true; queue_config_def.size = QUEUE_SIZE; diff --git a/virtio/src/device/block.rs b/virtio/src/device/block.rs index 1d1749be..3cd02f56 100644 --- a/virtio/src/device/block.rs +++ b/virtio/src/device/block.rs @@ -1688,14 +1688,23 @@ mod tests { let mut queue_config = QueueConfig::new(DEFAULT_VIRTQUEUE_SIZE); queue_config.desc_table = GuestAddress(0); - queue_config.addr_cache.desc_table_host = - mem_space.get_host_address(queue_config.desc_table).unwrap(); + queue_config.addr_cache.desc_table_host = unsafe { + mem_space + .get_host_address(queue_config.desc_table, AddressAttr::Ram) + .unwrap() + }; queue_config.avail_ring = GuestAddress(16 * u64::from(DEFAULT_VIRTQUEUE_SIZE)); - queue_config.addr_cache.avail_ring_host = - mem_space.get_host_address(queue_config.avail_ring).unwrap(); + queue_config.addr_cache.avail_ring_host = unsafe { + mem_space + .get_host_address(queue_config.avail_ring, AddressAttr::Ram) + .unwrap() + }; queue_config.used_ring = GuestAddress(32 * u64::from(DEFAULT_VIRTQUEUE_SIZE)); - queue_config.addr_cache.used_ring_host = - mem_space.get_host_address(queue_config.used_ring).unwrap(); + queue_config.addr_cache.used_ring_host = unsafe { + mem_space + .get_host_address(queue_config.used_ring, AddressAttr::Ram) + .unwrap() + }; queue_config.size = DEFAULT_VIRTQUEUE_SIZE; queue_config.ready = true; diff --git a/virtio/src/device/rng.rs b/virtio/src/device/rng.rs index 39a5d57c..5cc277b1 100644 --- a/virtio/src/device/rng.rs +++ b/virtio/src/device/rng.rs @@ -591,14 +591,23 @@ mod tests { let mut queue_config = QueueConfig::new(DEFAULT_VIRTQUEUE_SIZE); queue_config.desc_table = GuestAddress(0); - queue_config.addr_cache.desc_table_host = - mem_space.get_host_address(queue_config.desc_table).unwrap(); + queue_config.addr_cache.desc_table_host = unsafe { + mem_space + .get_host_address(queue_config.desc_table, AddressAttr::Ram) + .unwrap() + }; queue_config.avail_ring = GuestAddress(16 * u64::from(DEFAULT_VIRTQUEUE_SIZE)); - queue_config.addr_cache.avail_ring_host = - mem_space.get_host_address(queue_config.avail_ring).unwrap(); + queue_config.addr_cache.avail_ring_host = unsafe { + mem_space + .get_host_address(queue_config.avail_ring, AddressAttr::Ram) + .unwrap() + }; queue_config.used_ring = GuestAddress(32 * u64::from(DEFAULT_VIRTQUEUE_SIZE)); - queue_config.addr_cache.used_ring_host = - mem_space.get_host_address(queue_config.used_ring).unwrap(); + queue_config.addr_cache.used_ring_host = unsafe { + mem_space + .get_host_address(queue_config.used_ring, AddressAttr::Ram) + .unwrap() + }; queue_config.size = DEFAULT_VIRTQUEUE_SIZE; queue_config.ready = true; @@ -686,14 +695,23 @@ mod tests { let mut queue_config = QueueConfig::new(DEFAULT_VIRTQUEUE_SIZE); queue_config.desc_table = GuestAddress(0); - queue_config.addr_cache.desc_table_host = - mem_space.get_host_address(queue_config.desc_table).unwrap(); + queue_config.addr_cache.desc_table_host = unsafe { + mem_space + .get_host_address(queue_config.desc_table, AddressAttr::Ram) + .unwrap() + }; queue_config.avail_ring = GuestAddress(16 * u64::from(DEFAULT_VIRTQUEUE_SIZE)); - queue_config.addr_cache.avail_ring_host = - mem_space.get_host_address(queue_config.avail_ring).unwrap(); + queue_config.addr_cache.avail_ring_host = unsafe { + mem_space + .get_host_address(queue_config.avail_ring, AddressAttr::Ram) + .unwrap() + }; queue_config.used_ring = GuestAddress(32 * u64::from(DEFAULT_VIRTQUEUE_SIZE)); - queue_config.addr_cache.used_ring_host = - mem_space.get_host_address(queue_config.used_ring).unwrap(); + queue_config.addr_cache.used_ring_host = unsafe { + mem_space + .get_host_address(queue_config.used_ring, AddressAttr::Ram) + .unwrap() + }; queue_config.size = DEFAULT_VIRTQUEUE_SIZE; queue_config.ready = true; diff --git a/virtio/src/queue/split.rs b/virtio/src/queue/split.rs index 6ebbbc4e..2fda39a4 100644 --- a/virtio/src/queue/split.rs +++ b/virtio/src/queue/split.rs @@ -27,7 +27,7 @@ use super::{ use crate::{ report_virtio_error, virtio_has_feature, VirtioError, VirtioInterrupt, VIRTIO_F_RING_EVENT_IDX, }; -use address_space::{AddressSpace, GuestAddress, RegionCache, RegionType}; +use address_space::{AddressAttr, AddressSpace, GuestAddress, RegionCache, RegionType}; use util::byte_code::ByteCode; /// When host consumes a buffer, don't interrupt the guest. @@ -151,41 +151,44 @@ impl QueueConfig { features: u64, broken: &Arc, ) { - self.addr_cache.desc_table_host = - if let Some((addr, size)) = mem_space.addr_cache_init(self.desc_table) { - if size < self.get_desc_size() { - report_virtio_error(interrupt_cb.clone(), features, broken); - 0_u64 - } else { - addr - } - } else { + self.addr_cache.desc_table_host = if let Some((addr, size)) = + mem_space.addr_cache_init(self.desc_table, AddressAttr::Ram) + { + if size < self.get_desc_size() { + report_virtio_error(interrupt_cb.clone(), features, broken); 0_u64 - }; - - self.addr_cache.avail_ring_host = - if let Some((addr, size)) = mem_space.addr_cache_init(self.avail_ring) { - if size < self.get_avail_size(features) { - report_virtio_error(interrupt_cb.clone(), features, broken); - 0_u64 - } else { - addr - } } else { - 0_u64 - }; + addr + } + } else { + 0_u64 + }; - self.addr_cache.used_ring_host = - if let Some((addr, size)) = mem_space.addr_cache_init(self.used_ring) { - if size < self.get_used_size(features) { - report_virtio_error(interrupt_cb.clone(), features, broken); - 0_u64 - } else { - addr - } + self.addr_cache.avail_ring_host = if let Some((addr, size)) = + mem_space.addr_cache_init(self.avail_ring, AddressAttr::Ram) + { + if size < self.get_avail_size(features) { + report_virtio_error(interrupt_cb.clone(), features, broken); + 0_u64 } else { + addr + } + } else { + 0_u64 + }; + + self.addr_cache.used_ring_host = if let Some((addr, size)) = + mem_space.addr_cache_init(self.used_ring, AddressAttr::Ram) + { + if size < self.get_used_size(features) { + report_virtio_error(interrupt_cb.clone(), features, broken); 0_u64 - }; + } else { + addr + } + } else { + 0_u64 + }; } } @@ -303,7 +306,7 @@ impl SplitVringDesc { miss_cached = false; } } else { - let gotten_cache = sys_mem.get_region_cache(self.addr); + let gotten_cache = sys_mem.get_region_cache(self.addr, AddressAttr::Ram); if let Some(obtained_cache) = gotten_cache { if obtained_cache.reg_type == RegionType::Ram { *cache = gotten_cache; @@ -1411,19 +1414,28 @@ mod tests { let mut queue_config = QueueConfig::new(QUEUE_SIZE); queue_config.desc_table = GuestAddress(0); - queue_config.addr_cache.desc_table_host = - sys_space.get_host_address(queue_config.desc_table).unwrap(); + queue_config.addr_cache.desc_table_host = unsafe { + sys_space + .get_host_address(queue_config.desc_table, AddressAttr::Ram) + .unwrap() + }; queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); - queue_config.addr_cache.avail_ring_host = - sys_space.get_host_address(queue_config.avail_ring).unwrap(); + queue_config.addr_cache.avail_ring_host = unsafe { + sys_space + .get_host_address(queue_config.avail_ring, AddressAttr::Ram) + .unwrap() + }; queue_config.used_ring = GuestAddress(align( u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + VRING_AVAIL_LEN_EXCEPT_AVAILELEM + AVAILELEM_LEN * u64::from(QUEUE_SIZE), 4096, )); - queue_config.addr_cache.used_ring_host = - sys_space.get_host_address(queue_config.used_ring).unwrap(); + queue_config.addr_cache.used_ring_host = unsafe { + sys_space + .get_host_address(queue_config.used_ring, AddressAttr::Ram) + .unwrap() + }; queue_config.ready = true; queue_config.size = QUEUE_SIZE; let mut vring = SplitVring::new(queue_config); @@ -1501,19 +1513,28 @@ mod tests { let mut queue_config = QueueConfig::new(QUEUE_SIZE); queue_config.desc_table = GuestAddress(0); - queue_config.addr_cache.desc_table_host = - sys_space.get_host_address(queue_config.desc_table).unwrap(); + queue_config.addr_cache.desc_table_host = unsafe { + sys_space + .get_host_address(queue_config.desc_table, AddressAttr::Ram) + .unwrap() + }; queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); - queue_config.addr_cache.avail_ring_host = - sys_space.get_host_address(queue_config.avail_ring).unwrap(); + queue_config.addr_cache.avail_ring_host = unsafe { + sys_space + .get_host_address(queue_config.avail_ring, AddressAttr::Ram) + .unwrap() + }; queue_config.used_ring = GuestAddress(align( u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + VRING_AVAIL_LEN_EXCEPT_AVAILELEM + AVAILELEM_LEN * u64::from(QUEUE_SIZE), 4096, )); - queue_config.addr_cache.used_ring_host = - sys_space.get_host_address(queue_config.used_ring).unwrap(); + queue_config.addr_cache.used_ring_host = unsafe { + sys_space + .get_host_address(queue_config.used_ring, AddressAttr::Ram) + .unwrap() + }; queue_config.ready = true; queue_config.size = QUEUE_SIZE; let mut vring = SplitVring::new(queue_config); @@ -1601,19 +1622,28 @@ mod tests { let mut queue_config = QueueConfig::new(QUEUE_SIZE); queue_config.desc_table = GuestAddress(0); - queue_config.addr_cache.desc_table_host = - sys_space.get_host_address(queue_config.desc_table).unwrap(); + queue_config.addr_cache.desc_table_host = unsafe { + sys_space + .get_host_address(queue_config.desc_table, AddressAttr::Ram) + .unwrap() + }; queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); - queue_config.addr_cache.avail_ring_host = - sys_space.get_host_address(queue_config.avail_ring).unwrap(); + queue_config.addr_cache.avail_ring_host = unsafe { + sys_space + .get_host_address(queue_config.avail_ring, AddressAttr::Ram) + .unwrap() + }; queue_config.used_ring = GuestAddress(align( u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + VRING_AVAIL_LEN_EXCEPT_AVAILELEM + AVAILELEM_LEN * u64::from(QUEUE_SIZE), 4096, )); - queue_config.addr_cache.used_ring_host = - sys_space.get_host_address(queue_config.used_ring).unwrap(); + queue_config.addr_cache.used_ring_host = unsafe { + sys_space + .get_host_address(queue_config.used_ring, AddressAttr::Ram) + .unwrap() + }; queue_config.ready = true; queue_config.size = QUEUE_SIZE; let mut vring = SplitVring::new(queue_config); @@ -1796,19 +1826,28 @@ mod tests { let mut queue_config = QueueConfig::new(QUEUE_SIZE); queue_config.desc_table = GuestAddress(0); - queue_config.addr_cache.desc_table_host = - sys_space.get_host_address(queue_config.desc_table).unwrap(); + queue_config.addr_cache.desc_table_host = unsafe { + sys_space + .get_host_address(queue_config.desc_table, AddressAttr::Ram) + .unwrap() + }; queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); - queue_config.addr_cache.avail_ring_host = - sys_space.get_host_address(queue_config.avail_ring).unwrap(); + queue_config.addr_cache.avail_ring_host = unsafe { + sys_space + .get_host_address(queue_config.avail_ring, AddressAttr::Ram) + .unwrap() + }; queue_config.used_ring = GuestAddress(align( u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + VRING_AVAIL_LEN_EXCEPT_AVAILELEM + AVAILELEM_LEN * u64::from(QUEUE_SIZE), 4096, )); - queue_config.addr_cache.used_ring_host = - sys_space.get_host_address(queue_config.used_ring).unwrap(); + queue_config.addr_cache.used_ring_host = unsafe { + sys_space + .get_host_address(queue_config.used_ring, AddressAttr::Ram) + .unwrap() + }; queue_config.ready = true; queue_config.size = QUEUE_SIZE; let mut vring = SplitVring::new(queue_config); @@ -1960,19 +1999,28 @@ mod tests { let mut queue_config = QueueConfig::new(QUEUE_SIZE); queue_config.desc_table = GuestAddress(0); - queue_config.addr_cache.desc_table_host = - sys_space.get_host_address(queue_config.desc_table).unwrap(); + queue_config.addr_cache.desc_table_host = unsafe { + sys_space + .get_host_address(queue_config.desc_table, AddressAttr::Ram) + .unwrap() + }; queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); - queue_config.addr_cache.avail_ring_host = - sys_space.get_host_address(queue_config.avail_ring).unwrap(); + queue_config.addr_cache.avail_ring_host = unsafe { + sys_space + .get_host_address(queue_config.avail_ring, AddressAttr::Ram) + .unwrap() + }; queue_config.used_ring = GuestAddress(align( u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + VRING_AVAIL_LEN_EXCEPT_AVAILELEM + AVAILELEM_LEN * u64::from(QUEUE_SIZE), 4096, )); - queue_config.addr_cache.used_ring_host = - sys_space.get_host_address(queue_config.used_ring).unwrap(); + queue_config.addr_cache.used_ring_host = unsafe { + sys_space + .get_host_address(queue_config.used_ring, AddressAttr::Ram) + .unwrap() + }; queue_config.ready = true; queue_config.size = QUEUE_SIZE; let mut vring = SplitVring::new(queue_config); @@ -2001,19 +2049,28 @@ mod tests { let mut queue_config = QueueConfig::new(QUEUE_SIZE); queue_config.desc_table = GuestAddress(0); - queue_config.addr_cache.desc_table_host = - sys_space.get_host_address(queue_config.desc_table).unwrap(); + queue_config.addr_cache.desc_table_host = unsafe { + sys_space + .get_host_address(queue_config.desc_table, AddressAttr::Ram) + .unwrap() + }; queue_config.avail_ring = GuestAddress(u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN); - queue_config.addr_cache.avail_ring_host = - sys_space.get_host_address(queue_config.avail_ring).unwrap(); + queue_config.addr_cache.avail_ring_host = unsafe { + sys_space + .get_host_address(queue_config.avail_ring, AddressAttr::Ram) + .unwrap() + }; queue_config.used_ring = GuestAddress(align( u64::from(QUEUE_SIZE) * DESCRIPTOR_LEN + VRING_AVAIL_LEN_EXCEPT_AVAILELEM + AVAILELEM_LEN * u64::from(QUEUE_SIZE), 4096, )); - queue_config.addr_cache.used_ring_host = - sys_space.get_host_address(queue_config.used_ring).unwrap(); + queue_config.addr_cache.used_ring_host = unsafe { + sys_space + .get_host_address(queue_config.used_ring, AddressAttr::Ram) + .unwrap() + }; queue_config.ready = true; queue_config.size = QUEUE_SIZE; let mut vring = SplitVring::new(queue_config); diff --git a/virtio/src/vhost/kernel/mod.rs b/virtio/src/vhost/kernel/mod.rs index cca3cedc..e04b1589 100644 --- a/virtio/src/vhost/kernel/mod.rs +++ b/virtio/src/vhost/kernel/mod.rs @@ -34,7 +34,8 @@ use super::super::QueueConfig; use super::VhostOps; use crate::VirtioError; use address_space::{ - AddressSpace, FlatRange, GuestAddress, Listener, ListenerReqType, RegionIoEventFd, RegionType, + AddressAttr, AddressSpace, FlatRange, GuestAddress, Listener, ListenerReqType, RegionIoEventFd, + RegionType, }; use util::byte_code::ByteCode; @@ -158,7 +159,9 @@ impl VhostMemInfo { fn add_mem_range(&self, fr: &FlatRange) { let guest_phys_addr = fr.addr_range.base.raw_value(); let memory_size = fr.addr_range.size; - let userspace_addr = fr.owner.get_host_address().unwrap() + fr.offset_in_region; + let userspace_addr = + // SAFETY: memory_size is range's size, so we make sure [hva, hva+size] is in ram range. + unsafe { fr.owner.get_host_address(AddressAttr::Ram).unwrap() } + fr.offset_in_region; self.regions.lock().unwrap().push(VhostMemoryRegion { guest_phys_addr, @@ -173,7 +176,9 @@ impl VhostMemInfo { let target = VhostMemoryRegion { guest_phys_addr: fr.addr_range.base.raw_value(), memory_size: fr.addr_range.size, - userspace_addr: fr.owner.get_host_address().unwrap() + fr.offset_in_region, + // SAFETY: memory_size is range's size, so we make sure [hva, hva+size] is in ram range. + userspace_addr: unsafe { fr.owner.get_host_address(AddressAttr::Ram).unwrap() } + + fr.offset_in_region, flags_padding: 0_u64, }; for (index, mr) in mem_regions.iter().enumerate() { diff --git a/virtio/src/vhost/user/client.rs b/virtio/src/vhost/user/client.rs index 469871f1..4a51c929 100644 --- a/virtio/src/vhost/user/client.rs +++ b/virtio/src/vhost/user/client.rs @@ -33,7 +33,8 @@ use crate::device::block::VirtioBlkConfig; use crate::VhostUser::message::VhostUserConfig; use crate::{virtio_has_feature, Queue, QueueConfig}; use address_space::{ - AddressSpace, FileBackend, FlatRange, GuestAddress, Listener, ListenerReqType, RegionIoEventFd, + AddressAttr, AddressSpace, FileBackend, FlatRange, GuestAddress, Listener, ListenerReqType, + RegionIoEventFd, }; use machine_manager::event_loop::{register_event_helper, unregister_event_helper, EventLoop}; use util::loop_context::{ @@ -234,7 +235,8 @@ impl VhostUserMemInfo { let guest_phys_addr = fr.addr_range.base.raw_value(); let memory_size = fr.addr_range.size; - let host_address = match fr.owner.get_host_address() { + // SAFETY: memory_size is range's size, so we make sure [hva, hva+size] is in ram range. + let host_address = match unsafe { fr.owner.get_host_address(AddressAttr::Ram) } { Some(addr) => addr, None => bail!("Failed to get host address to add mem range for vhost user device"), }; @@ -287,7 +289,8 @@ impl VhostUserMemInfo { Some(fb) => fb, }; let mut mem_regions = self.regions.lock().unwrap(); - let host_address = match fr.owner.get_host_address() { + // SAFETY: memory_size is range's size, so we make sure [hva, hva+size] is in ram range. + let host_address = match unsafe { fr.owner.get_host_address(AddressAttr::Ram) } { Some(addr) => addr, None => bail!("Failed to get host address to del mem range for vhost user device"), }; -- Gitee From 28ee1835374f95e1e2f3a461e9b73f5e96330ef2 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Tue, 20 Aug 2024 06:50:09 +0800 Subject: [PATCH 308/489] scsi: adjust xfer type Adjust the xfer type to avoid overflow. Signed-off-by: liuxiangdong --- devices/src/scsi/bus.rs | 32 +++++++++++++++++--------------- devices/src/usb/storage.rs | 3 ++- devices/src/usb/uas.rs | 2 +- trace/trace_info/usb.toml | 2 +- virtio/src/device/scsi_cntlr.rs | 2 +- 5 files changed, 22 insertions(+), 19 deletions(-) diff --git a/devices/src/scsi/bus.rs b/devices/src/scsi/bus.rs index 277b09ab..ceaa1e5b 100644 --- a/devices/src/scsi/bus.rs +++ b/devices/src/scsi/bus.rs @@ -260,13 +260,13 @@ pub const MODE_PAGE_TO_PROTECT: u8 = 0x1d; pub const MODE_PAGE_CAPABILITIES: u8 = 0x2a; pub const MODE_PAGE_ALLS: u8 = 0x3f; -pub const SCSI_MAX_INQUIRY_LEN: u32 = 256; +pub const SCSI_MAX_INQUIRY_LEN: u64 = 256; pub const SCSI_INQUIRY_PRODUCT_MAX_LEN: usize = 16; pub const SCSI_INQUIRY_VENDOR_MAX_LEN: usize = 8; pub const SCSI_INQUIRY_VERSION_MAX_LEN: usize = 4; pub const SCSI_INQUIRY_VPD_SERIAL_NUMBER_MAX_LEN: usize = 32; -const SCSI_TARGET_INQUIRY_LEN: u32 = 36; +const SCSI_TARGET_INQUIRY_LEN: u64 = 36; /// | bit7 - bit 5 | bit 4 - bit 0 | /// | Peripheral Qualifier | Peripheral Device Type | @@ -446,15 +446,15 @@ fn scsi_bus_parse_req_cdb( // When CDB's Group Code is vendor specific or reserved, len/xfer/lba will be negative. // So, don't need to check again after checking in cdb length. - let xfer = scsi_cdb_xfer(&cdb, dev); - let lba = scsi_cdb_lba(&cdb); + let xfer = scsi_cdb_xfer(&cdb, dev) as u64; + let lba = scsi_cdb_lba(&cdb) as u64; Some(ScsiCommand { buf: cdb, op, len: len as u32, - xfer: xfer as u32, - lba: lba as u64, + xfer, + lba, mode: scsi_cdb_xfer_mode(&cdb), }) } @@ -468,7 +468,7 @@ pub struct ScsiCommand { /// Length of CDB. pub len: u32, /// Transfer length. - pub xfer: u32, + pub xfer: u64, /// Logical Block Address. pub lba: u64, /// Transfer direction. @@ -790,22 +790,22 @@ fn scsi_cdb_length(cdb: &[u8; SCSI_CMD_BUF_SIZE]) -> i32 { } } -pub fn scsi_cdb_xfer(cdb: &[u8; SCSI_CMD_BUF_SIZE], dev: Arc>) -> i32 { +pub fn scsi_cdb_xfer(cdb: &[u8; SCSI_CMD_BUF_SIZE], dev: Arc>) -> i64 { SCSI_DEVICE!(dev, locked_dev, scsi_dev); - let block_size = scsi_dev.block_size as i32; + let block_size = scsi_dev.block_size as i64; drop(locked_dev); - let mut xfer = match cdb[0] >> 5 { + let mut xfer: i64 = match cdb[0] >> 5 { // Group Code | Transfer length. | // 000b | Byte[4]. | // 001b | Bytes[7-8]. | // 010b | Bytes[7-8]. | // 100b | Bytes[10-13]. | // 101b | Bytes[6-9]. | - 0 => i32::from(cdb[4]), - 1 | 2 => i32::from(BigEndian::read_u16(&cdb[7..])), - 4 => BigEndian::read_u32(&cdb[10..]) as i32, - 5 => BigEndian::read_u32(&cdb[6..]) as i32, + 0 => i64::from(cdb[4]), + 1 | 2 => i64::from(BigEndian::read_u16(&cdb[7..])), + 4 => i64::from(BigEndian::read_u32(&cdb[10..])), + 5 => i64::from(BigEndian::read_u32(&cdb[6..])), _ => -1, }; @@ -819,14 +819,16 @@ pub fn scsi_cdb_xfer(cdb: &[u8; SCSI_CMD_BUF_SIZE], dev: Arc>) WRITE_6 | READ_6 => { // length 0 means 256 blocks. if xfer == 0 { + // Safety: block_size is 2048 or 512. xfer = 256 * block_size; } } WRITE_10 | WRITE_12 | WRITE_16 | READ_10 | READ_12 | READ_16 => { + // Safety: xfer is less than u32::max now. xfer *= block_size; } INQUIRY => { - xfer = i32::from(cdb[4]) | i32::from(cdb[3]) << 8; + xfer = i64::from(cdb[4]) | i64::from(cdb[3]) << 8; } _ => {} } diff --git a/devices/src/usb/storage.rs b/devices/src/usb/storage.rs index 986e6741..bec30977 100644 --- a/devices/src/usb/storage.rs +++ b/devices/src/usb/storage.rs @@ -468,6 +468,7 @@ impl UsbStorage { self.state.check_cdb_exist(true)?; self.state.check_iovec_empty(true)?; + // Safety: iovecs are set in `setup_usb_packet` and iovec_len is no more than TRB_TR_LEN_MASK. let iovec_len = packet.get_iovecs_size() as u32; if iovec_len < self.state.cbw.data_len { bail!( @@ -504,7 +505,7 @@ impl UsbStorage { ) .with_context(|| "Error in creating scsirequest.")?; - if sreq.cmd.xfer > sreq.datalen && sreq.cmd.mode != ScsiXferMode::ScsiXferNone { + if sreq.cmd.xfer > u64::from(sreq.datalen) && sreq.cmd.mode != ScsiXferMode::ScsiXferNone { // Wrong USB packet which doesn't provide enough datain/dataout buffer. bail!( "command {:x} requested data's length({}), provided buffer length({})", diff --git a/devices/src/usb/uas.rs b/devices/src/usb/uas.rs index 79780033..04ce8745 100644 --- a/devices/src/usb/uas.rs +++ b/devices/src/usb/uas.rs @@ -540,7 +540,7 @@ impl UsbUas { ) .with_context(|| "failed to create SCSI request")?; - if scsi_request.cmd.xfer > scsi_request.datalen + if scsi_request.cmd.xfer > u64::from(scsi_request.datalen) && scsi_request.cmd.mode != ScsiXferMode::ScsiXferNone { bail!( diff --git a/trace/trace_info/usb.toml b/trace/trace_info/usb.toml index cabcf6ca..9defe6d2 100644 --- a/trace/trace_info/usb.toml +++ b/trace/trace_info/usb.toml @@ -528,7 +528,7 @@ enabled = true [[events]] name = "usb_uas_try_start_next_transfer" -args = "device_id: &str, xfer_len: i32" +args = "device_id: &str, xfer_len: i64" message = "UAS {} device is trying to start next transfer of length {}." enabled = true diff --git a/virtio/src/device/scsi_cntlr.rs b/virtio/src/device/scsi_cntlr.rs index 6f4143fb..dc58be3a 100644 --- a/virtio/src/device/scsi_cntlr.rs +++ b/virtio/src/device/scsi_cntlr.rs @@ -933,7 +933,7 @@ impl ScsiCmdQueueHandler { } let sreq = scsi_req.unwrap(); - if sreq.cmd.xfer > sreq.datalen && sreq.cmd.mode != ScsiXferMode::ScsiXferNone { + if sreq.cmd.xfer > u64::from(sreq.datalen) && sreq.cmd.mode != ScsiXferMode::ScsiXferNone { // Wrong virtio scsi request which doesn't provide enough datain/dataout buffer. qrequest.resp.response = VIRTIO_SCSI_S_OVERRUN; qrequest.complete()?; -- Gitee From 1fa1696a2a04c5c98091d8ccdc35b097c00a8bfd Mon Sep 17 00:00:00 2001 From: sujerry1991 Date: Wed, 4 Sep 2024 17:04:56 +0800 Subject: [PATCH 309/489] util: add more useful information to error log Add 'opcode' and 'nbytes' to error log. Signed-off-by: Yan Wang --- util/src/aio/mod.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/util/src/aio/mod.rs b/util/src/aio/mod.rs index 56a142c8..a401879b 100644 --- a/util/src/aio/mod.rs +++ b/util/src/aio/mod.rs @@ -613,8 +613,11 @@ impl Aio { evt.res } else { error!( - "Async IO request failed, status {} res {}", - evt.status, evt.res + "Async IO request failed, opcode {:?} status {} res {} expect {}", + (*node).value.opcode, + evt.status, + evt.res, + (*node).value.nbytes ); -1 }; -- Gitee From 2693bdb299fdee0b9909699b6b390a16b9d13afa Mon Sep 17 00:00:00 2001 From: Li Huachao Date: Mon, 26 Aug 2024 10:35:08 +0800 Subject: [PATCH 310/489] Memory: Fix potential unsafe chain breaks --- address_space/src/address_space.rs | 24 +++--- virtio/src/queue/split.rs | 127 ++++++++++++++++++----------- 2 files changed, 91 insertions(+), 60 deletions(-) diff --git a/address_space/src/address_space.rs b/address_space/src/address_space.rs index 7e9fa729..88dd6d92 100644 --- a/address_space/src/address_space.rs +++ b/address_space/src/address_space.rs @@ -778,17 +778,18 @@ impl AddressSpace { /// * `data` - The object that will be written to the memory. /// * `host_addr` - The start host address where the object will be written to. /// + /// # Safety + /// + /// Make true that host_addr and std::mem::size_of::() are in the range of ram. + /// /// # Note /// To use this method, it is necessary to implement `ByteCode` trait for your object. - pub fn write_object_direct(&self, data: &T, host_addr: u64) -> Result<()> { + pub unsafe fn write_object_direct(&self, data: &T, host_addr: u64) -> Result<()> { trace::address_space_write_direct(host_addr, std::mem::size_of::()); // Mark vmm dirty page manually if live migration is active. MigrationManager::mark_dirty_log(host_addr, data.as_bytes().len() as u64); - - // SAFETY: The host addr is managed by memory space, it has been verified. - let mut dst = unsafe { - std::slice::from_raw_parts_mut(host_addr as *mut u8, std::mem::size_of::()) - }; + let mut dst = + std::slice::from_raw_parts_mut(host_addr as *mut u8, std::mem::size_of::()); dst.write_all(data.as_bytes()) .with_context(|| "Failed to write object via host address") } @@ -819,16 +820,17 @@ impl AddressSpace { /// /// * `hoat_addr` - The start host address where the data will be read from. /// + /// # Safety + /// + /// Make true that host_addr and std::mem::size_of::() are in the range of ram. + /// /// # Note /// To use this method, it is necessary to implement `ByteCode` trait for your object. - pub fn read_object_direct(&self, host_addr: u64) -> Result { + pub unsafe fn read_object_direct(&self, host_addr: u64) -> Result { trace::address_space_read_direct(host_addr, std::mem::size_of::()); let mut obj = T::default(); let mut dst = obj.as_mut_bytes(); - // SAFETY: host_addr is managed by address_space, it has been verified for legality. - let src = unsafe { - std::slice::from_raw_parts_mut(host_addr as *mut u8, std::mem::size_of::()) - }; + let src = std::slice::from_raw_parts_mut(host_addr as *mut u8, std::mem::size_of::()); dst.write_all(src) .with_context(|| "Failed to read object via host address")?; diff --git a/virtio/src/queue/split.rs b/virtio/src/queue/split.rs index 2fda39a4..de35b043 100644 --- a/virtio/src/queue/split.rs +++ b/virtio/src/queue/split.rs @@ -268,9 +268,12 @@ impl SplitVringDesc { u64::from(index) * DESCRIPTOR_LEN, ) })?; - let desc = sys_mem - .read_object_direct::(desc_addr) - .with_context(|| VirtioError::ReadObjectErr("a descriptor", desc_addr))?; + // SAFETY: dest_addr has been checked in SplitVringDesc::is_valid() and is guaranteed to be within the ram range. + let desc = unsafe { + sys_mem + .read_object_direct::(desc_addr) + .with_context(|| VirtioError::ReadObjectErr("a descriptor", desc_addr)) + }?; if desc.is_valid(sys_mem, queue_size, cache) { Ok(desc) @@ -505,11 +508,14 @@ impl SplitVring { /// Get the flags and idx of the available ring from guest memory. fn get_avail_flags_idx(&self, sys_mem: &Arc) -> Result { - sys_mem - .read_object_direct::(self.addr_cache.avail_ring_host) - .with_context(|| { - VirtioError::ReadObjectErr("avail flags idx", self.avail_ring.raw_value()) - }) + // SAFETY: avail_ring_host is checked when addr_cache inited. + unsafe { + sys_mem + .read_object_direct::(self.addr_cache.avail_ring_host) + .with_context(|| { + VirtioError::ReadObjectErr("avail flags idx", self.avail_ring.raw_value()) + }) + } } /// Get the idx of the available ring from guest memory. @@ -528,11 +534,14 @@ impl SplitVring { fn get_used_flags_idx(&self, sys_mem: &Arc) -> Result { // Make sure the idx read from sys_mem is new. fence(Ordering::SeqCst); - sys_mem - .read_object_direct::(self.addr_cache.used_ring_host) - .with_context(|| { - VirtioError::ReadObjectErr("used flags idx", self.used_ring.raw_value()) - }) + // SAFETY: used_ring_host has been checked in set_addr_cache() and is guaranteed to be within the ram range. + unsafe { + sys_mem + .read_object_direct::(self.addr_cache.used_ring_host) + .with_context(|| { + VirtioError::ReadObjectErr("used flags idx", self.used_ring.raw_value()) + }) + } } /// Get the index of the used ring from guest memory. @@ -550,14 +559,20 @@ impl SplitVring { } else { flags_idx.flags &= !VRING_USED_F_NO_NOTIFY; } - sys_mem - .write_object_direct::(&flags_idx, self.addr_cache.used_ring_host) - .with_context(|| { - format!( - "Failed to set used flags, used_ring: 0x{:X}", - self.used_ring.raw_value() + // SAFETY: used_ring_host has been checked when addr_cache inited. + unsafe { + sys_mem + .write_object_direct::( + &flags_idx, + self.addr_cache.used_ring_host, ) - })?; + .with_context(|| { + format!( + "Failed to set used flags, used_ring: 0x{:X}", + self.used_ring.raw_value() + ) + }) + }?; // Make sure the data has been set. fence(Ordering::SeqCst); Ok(()) @@ -568,19 +583,21 @@ impl SplitVring { trace::virtqueue_set_avail_event(self as *const _ as u64, event_idx); let avail_event_offset = VRING_FLAGS_AND_IDX_LEN + USEDELEM_LEN * u64::from(self.actual_size()); - - sys_mem - .write_object_direct( - &event_idx, - self.addr_cache.used_ring_host + avail_event_offset, - ) - .with_context(|| { - format!( - "Failed to set avail event idx, used_ring: 0x{:X}, offset: {}", - self.used_ring.raw_value(), - avail_event_offset, + // SAFETY: used_ring_host has been checked in set_addr_cache(). + unsafe { + sys_mem + .write_object_direct( + &event_idx, + self.addr_cache.used_ring_host + avail_event_offset, ) - })?; + .with_context(|| { + format!( + "Failed to set avail event idx, used_ring: 0x{:X}, offset: {}", + self.used_ring.raw_value(), + avail_event_offset, + ) + }) + }?; // Make sure the data has been set. fence(Ordering::SeqCst); Ok(()) @@ -595,9 +612,12 @@ impl SplitVring { // The GPA of avail_ring_host with avail table length has been checked in // is_invalid_memory which must not be overflowed. let used_event_addr = self.addr_cache.avail_ring_host + used_event_offset; - let used_event = sys_mem - .read_object_direct::(used_event_addr) - .with_context(|| VirtioError::ReadObjectErr("used event id", used_event_addr))?; + // SAFETY: used_event_addr is protected by virtio calculations and is guaranteed to be within the ram range. + let used_event = unsafe { + sys_mem + .read_object_direct::(used_event_addr) + .with_context(|| VirtioError::ReadObjectErr("used event id", used_event_addr)) + }?; Ok(used_event) } @@ -757,11 +777,14 @@ impl SplitVring { // The GPA of avail_ring_host with avail table length has been checked in // is_invalid_memory which must not be overflowed. let desc_index_addr = self.addr_cache.avail_ring_host + index_offset; - let desc_index = sys_mem - .read_object_direct::(desc_index_addr) - .with_context(|| { - VirtioError::ReadObjectErr("the index of descriptor", desc_index_addr) - })?; + // SAFETY: dest_index_addr is protected by virtio calculations and is guaranteed to be within the ram range. + let desc_index = unsafe { + sys_mem + .read_object_direct::(desc_index_addr) + .with_context(|| { + VirtioError::ReadObjectErr("the index of descriptor", desc_index_addr) + }) + }?; let desc = SplitVringDesc::new( sys_mem, @@ -867,19 +890,25 @@ impl VringOps for SplitVring { id: u32::from(index), len, }; - sys_mem - .write_object_direct::(&used_elem, used_elem_addr) - .with_context(|| "Failed to write object for used element")?; + // SAFETY: used_elem_addr is guaranteed to be within ram range. + unsafe { + sys_mem + .write_object_direct::(&used_elem, used_elem_addr) + .with_context(|| "Failed to write object for used element") + }?; // Make sure used element is filled before updating used idx. fence(Ordering::Release); self.next_used += Wrapping(1); - sys_mem - .write_object_direct( - &(self.next_used.0), - self.addr_cache.used_ring_host + VRING_IDX_POSITION, - ) - .with_context(|| "Failed to write next used idx")?; + // SAFETY: used_ring_host has been checked when addr_cache inited. + unsafe { + sys_mem + .write_object_direct( + &(self.next_used.0), + self.addr_cache.used_ring_host + VRING_IDX_POSITION, + ) + .with_context(|| "Failed to write next used idx") + }?; // Make sure used index is exposed before notifying guest. fence(Ordering::SeqCst); -- Gitee From a995cdd09728942928c812ee0f121f8f7c2e3fd2 Mon Sep 17 00:00:00 2001 From: Li Huachao Date: Thu, 29 Aug 2024 12:00:52 +0800 Subject: [PATCH 311/489] Balloon: Fix potential risks of data type conversion --- virtio/src/device/balloon.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/virtio/src/device/balloon.rs b/virtio/src/device/balloon.rs index 894a84a5..850f77cb 100644 --- a/virtio/src/device/balloon.rs +++ b/virtio/src/device/balloon.rs @@ -729,10 +729,9 @@ impl BalloonIoHandler { let mut balloon_dev = dev.lock().unwrap(); for iov in req.iovec.iter() { if let Some(stat) = iov_to_buf::(&self.mem_space, iov, 0) { - let ram_size = (balloon_dev.mem_info.lock().unwrap().get_ram_size() - >> VIRTIO_BALLOON_PFN_SHIFT) - as u32; - balloon_dev.set_num_pages(cmp::min(stat._val as u32, ram_size)); + let ram_size = balloon_dev.mem_info.lock().unwrap().get_ram_size() + >> VIRTIO_BALLOON_PFN_SHIFT; + balloon_dev.set_num_pages(cmp::min(stat._val, ram_size) as u32); } } balloon_dev @@ -1043,11 +1042,11 @@ impl Balloon { if host_page_size > BALLOON_PAGE_SIZE && !self.mem_info.lock().unwrap().has_huge_page() { warn!("Balloon used with backing page size > 4kiB, this may not be reliable"); } - let target = (size >> VIRTIO_BALLOON_PFN_SHIFT) as u32; + let target = size >> VIRTIO_BALLOON_PFN_SHIFT; let address_space_ram_size = - (self.mem_info.lock().unwrap().get_ram_size() >> VIRTIO_BALLOON_PFN_SHIFT) as u32; + self.mem_info.lock().unwrap().get_ram_size() >> VIRTIO_BALLOON_PFN_SHIFT; let vm_target = cmp::min(target, address_space_ram_size); - self.num_pages = address_space_ram_size - vm_target; + self.num_pages = (address_space_ram_size - vm_target) as u32; self.signal_config_change().with_context(|| { "Failed to notify about configuration change after setting balloon memory" })?; -- Gitee From 144bf54636307fde9915ecfc0197a2f077f7276d Mon Sep 17 00:00:00 2001 From: zhanghan64 Date: Mon, 2 Sep 2024 11:44:38 +0800 Subject: [PATCH 312/489] ohcamera:set first caller tokenID for camera thread MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On OHOS, there is a mode named "超级隐私模式",on which camera cannot be accessed, and OHOS will pop up a window for telling users that camera is unaccessable. Now no windows appears, when camera is accessed in VM on "超级隐私模式",just because we don't pass a HAP's tokenID to related SA when we open OHOS camera. So we need to set first caller tokenID, a HAP tokenID. Signed-off-by: zhanghan64 --- devices/src/camera_backend/mod.rs | 2 ++ devices/src/camera_backend/ohcam.rs | 8 +++++++- devices/src/misc/scream/mod.rs | 12 +----------- devices/src/usb/camera.rs | 4 ++-- machine/src/lib.rs | 6 +++++- util/src/ohos_binding/misc.rs | 13 +++++++++++-- 6 files changed, 28 insertions(+), 17 deletions(-) diff --git a/devices/src/camera_backend/mod.rs b/devices/src/camera_backend/mod.rs index 86b1c4ec..d9fd95f9 100644 --- a/devices/src/camera_backend/mod.rs +++ b/devices/src/camera_backend/mod.rs @@ -193,6 +193,7 @@ pub trait CameraBackend: Send + Sync { pub fn create_cam_backend( config: UsbCameraConfig, cameradev: CameraDevConfig, + _tokenid: u64, ) -> Result>> { let cam: Arc> = match cameradev.backend { #[cfg(feature = "usb_camera_v4l2")] @@ -205,6 +206,7 @@ pub fn create_cam_backend( CamBackendType::OhCamera => Arc::new(Mutex::new(OhCameraBackend::new( cameradev.id, cameradev.path, + _tokenid, )?)), CamBackendType::Demo => Arc::new(Mutex::new(DemoCameraBackend::new( config.id, diff --git a/devices/src/camera_backend/ohcam.rs b/devices/src/camera_backend/ohcam.rs index bf5d8ee9..3527048c 100755 --- a/devices/src/camera_backend/ohcam.rs +++ b/devices/src/camera_backend/ohcam.rs @@ -30,6 +30,7 @@ use crate::camera_backend::{ use trace::trace_scope::Scope; use util::aio::Iovec; use util::ohos_binding::camera::*; +use util::ohos_binding::misc::bound_tokenid; type OhCamCB = RwLock>; static OHCAM_CALLBACKS: Lazy = Lazy::new(|| RwLock::new(HashMap::new())); @@ -132,6 +133,7 @@ pub struct OhCameraBackend { all(target_env = "ohos", feature = "trace_to_hitrace") ))] async_scope: Box, + tokenid: u64, } // SAFETY: Send and Sync is not auto-implemented for raw pointer type. @@ -159,7 +161,7 @@ impl Drop for OhCameraBackend { } impl OhCameraBackend { - pub fn new(id: String, cam_name: String) -> Result { + pub fn new(id: String, cam_name: String, tokenid: u64) -> Result { let (ctx, profile_cnt) = OhCamera::new(cam_name.clone())?; Ok(OhCameraBackend { @@ -177,6 +179,7 @@ impl OhCameraBackend { all(target_env = "ohos", feature = "trace_to_hitrace") ))] async_scope: Box::new(OhCameraAsyncScope::default()), + tokenid, }) } } @@ -212,6 +215,9 @@ impl CameraBackend for OhCameraBackend { } fn video_stream_on(&mut self) -> Result<()> { + if self.tokenid != 0 { + bound_tokenid(self.tokenid)?; + } self.ctx.start_stream(on_buffer_available, on_broken)?; self.stream_on = true; Ok(()) diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index 38fd38b3..a6c8ca8b 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -44,7 +44,7 @@ use ohaudio::{OhAudio, OhAudioVolume}; #[cfg(feature = "scream_pulseaudio")] use pulseaudio::PulseStreamData; #[cfg(all(target_env = "ohos", feature = "scream_ohaudio"))] -use util::ohos_binding::misc::{get_firstcaller_tokenid, set_firstcaller_tokenid}; +use util::ohos_binding::misc::bound_tokenid; pub const AUDIO_SAMPLE_RATE_44KHZ: u32 = 44100; pub const AUDIO_SAMPLE_RATE_48KHZ: u32 = 48000; @@ -472,16 +472,6 @@ impl StreamData { } } -#[cfg(all(target_env = "ohos", feature = "scream_ohaudio"))] -fn bound_tokenid(token_id: u64) -> Result<()> { - if token_id == 0 { - bail!("UI token ID not passed."); - } else if token_id != get_firstcaller_tokenid()? { - set_firstcaller_tokenid(token_id)?; - } - Ok(()) -} - #[derive(Clone, Debug)] enum ScreamInterface { #[cfg(feature = "scream_alsa")] diff --git a/devices/src/usb/camera.rs b/devices/src/usb/camera.rs index 7dce7834..159a33ca 100644 --- a/devices/src/usb/camera.rs +++ b/devices/src/usb/camera.rs @@ -502,8 +502,8 @@ impl VideoStreamingControl { } impl UsbCamera { - pub fn new(config: UsbCameraConfig, cameradev: CameraDevConfig) -> Result { - let camera = create_cam_backend(config.clone(), cameradev)?; + pub fn new(config: UsbCameraConfig, cameradev: CameraDevConfig, tokenid: u64) -> Result { + let camera = create_cam_backend(config.clone(), cameradev, tokenid)?; Ok(Self { base: UsbDeviceBase::new(config.id, USB_CAMERA_BUFFER_LEN), vs_control: VideoStreamingControl::default(), diff --git a/machine/src/lib.rs b/machine/src/lib.rs index f69f40dd..484aaf25 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -1833,6 +1833,10 @@ pub trait MachineOps: MachineLifecycle { } #[cfg(feature = "usb_camera")] "usb-camera" => { + let token_id = match self.get_token_id() { + Some(id) => *id.read().unwrap(), + None => 0, + }; let config = UsbCameraConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; let cameradev = get_cameradev_by_id(vm_config, config.cameradev.clone()) @@ -1843,7 +1847,7 @@ pub trait MachineOps: MachineLifecycle { ) })?; - let camera = UsbCamera::new(config, cameradev)?; + let camera = UsbCamera::new(config, cameradev, token_id)?; camera .realize() .with_context(|| "Failed to realize usb camera device")? diff --git a/util/src/ohos_binding/misc.rs b/util/src/ohos_binding/misc.rs index 1d9e31a5..27b56455 100644 --- a/util/src/ohos_binding/misc.rs +++ b/util/src/ohos_binding/misc.rs @@ -34,7 +34,7 @@ ioctl_ior_nr!( ::std::os::raw::c_ulonglong ); -pub fn set_firstcaller_tokenid(id: u64) -> Result<()> { +fn set_firstcaller_tokenid(id: u64) -> Result<()> { let fd = OpenOptions::new() .read(true) .write(true) @@ -56,7 +56,7 @@ pub fn set_firstcaller_tokenid(id: u64) -> Result<()> { Ok(()) } -pub fn get_firstcaller_tokenid() -> Result { +fn get_firstcaller_tokenid() -> Result { let fd = OpenOptions::new() .read(true) .write(true) @@ -78,3 +78,12 @@ pub fn get_firstcaller_tokenid() -> Result { } Ok(id) } + +pub fn bound_tokenid(token_id: u64) -> Result<()> { + if token_id == 0 { + bail!("UI token ID not passed."); + } else if token_id != get_firstcaller_tokenid()? { + set_firstcaller_tokenid(token_id)?; + } + Ok(()) +} -- Gitee From ef639a205503da202d90e6516d36bd4620875bee Mon Sep 17 00:00:00 2001 From: Jinhao Gao Date: Thu, 15 Aug 2024 16:32:21 +0800 Subject: [PATCH 313/489] USB: Modify type of dequeue of cmd ring and transfer ring Modify type of dequeue of cmd ring and transfer ring. And check if the dequeue addr locates in guest ram. Signed-off-by: Jinhao Gao --- devices/src/usb/xhci/xhci_controller.rs | 2 +- devices/src/usb/xhci/xhci_ring.rs | 57 +++++++++++++------------ 2 files changed, 31 insertions(+), 28 deletions(-) diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index fc2a4493..ad92caa8 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -1883,7 +1883,7 @@ impl XhciDevice { let mut evt = XhciEvent::new(TRBType::ErTransfer, ccode); evt.slot_id = slot_id as u8; evt.ep_id = ep_id as u8; - evt.ptr = ring.get_dequeue_ptr(); + evt.ptr = ring.get_dequeue_ptr().raw_value(); if let Err(e) = self.intrs[0].lock().unwrap().send_event(&evt) { error!("Failed to send event: {:?}", e); } diff --git a/devices/src/usb/xhci/xhci_ring.rs b/devices/src/usb/xhci/xhci_ring.rs index 061fd48f..0bfcee49 100644 --- a/devices/src/usb/xhci/xhci_ring.rs +++ b/devices/src/usb/xhci/xhci_ring.rs @@ -10,10 +10,10 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use std::sync::atomic::{fence, AtomicBool, AtomicU64, Ordering}; -use std::sync::Arc; +use std::sync::atomic::{fence, AtomicBool, Ordering}; +use std::sync::{Arc, Mutex}; -use anyhow::{bail, Context, Result}; +use anyhow::{bail, Result}; use byteorder::{ByteOrder, LittleEndian}; use log::debug; @@ -54,7 +54,7 @@ impl XhciTRB { #[derive(Clone)] pub struct XhciCommandRing { mem: Arc, - pub dequeue: u64, + pub dequeue: GuestAddress, /// Consumer Cycle State pub ccs: bool, } @@ -63,13 +63,13 @@ impl XhciCommandRing { pub fn new(mem: &Arc) -> Self { Self { mem: mem.clone(), - dequeue: 0, + dequeue: GuestAddress(0), ccs: true, } } pub fn init(&mut self, addr: u64) { - self.dequeue = addr; + self.dequeue = GuestAddress(addr); self.ccs = true; } @@ -87,7 +87,7 @@ impl XhciCommandRing { } fence(Ordering::Acquire); let mut trb = read_trb(&self.mem, self.dequeue)?; - trb.addr = self.dequeue; + trb.addr = self.dequeue.raw_value(); trb.ccs = self.ccs; let trb_type = trb.get_type(); debug!("Fetch TRB: type {:?} trb {:?}", trb_type, trb); @@ -96,7 +96,7 @@ impl XhciCommandRing { if link_cnt > TRB_LINK_LIMIT { bail!("TRB reach link limit"); } - self.dequeue = trb.parameter; + self.dequeue = GuestAddress(trb.parameter); if trb.control & TRB_LK_TC == TRB_LK_TC { self.ccs = !self.ccs; } @@ -105,7 +105,10 @@ impl XhciCommandRing { .dequeue .checked_add(u64::from(TRB_SIZE)) .ok_or_else(|| { - UsbError::MemoryAccessOverflow(self.dequeue, u64::from(TRB_SIZE)) + UsbError::MemoryAccessOverflow( + self.dequeue.raw_value(), + u64::from(TRB_SIZE), + ) })?; return Ok(Some(trb)); } @@ -116,7 +119,7 @@ impl XhciCommandRing { /// XHCI Transfer Ring pub struct XhciTransferRing { pub mem: Arc, - pub dequeue: AtomicU64, + pub dequeue: Mutex, /// Consumer Cycle State pub ccs: AtomicBool, } @@ -125,22 +128,22 @@ impl XhciTransferRing { pub fn new(mem: &Arc) -> Self { Self { mem: mem.clone(), - dequeue: AtomicU64::new(0), + dequeue: Mutex::new(GuestAddress(0)), ccs: AtomicBool::new(true), } } pub fn init(&self, addr: u64) { - self.set_dequeue_ptr(addr); + self.set_dequeue_ptr(GuestAddress(addr)); self.set_cycle_bit(true); } - pub fn get_dequeue_ptr(&self) -> u64 { - self.dequeue.load(Ordering::Acquire) + pub fn get_dequeue_ptr(&self) -> GuestAddress { + *self.dequeue.lock().unwrap() } - pub fn set_dequeue_ptr(&self, addr: u64) { - self.dequeue.store(addr, Ordering::SeqCst); + pub fn set_dequeue_ptr(&self, addr: GuestAddress) { + *self.dequeue.lock().unwrap() = addr } pub fn get_cycle_bit(&self) -> bool { @@ -168,7 +171,7 @@ impl XhciTransferRing { } fence(Ordering::Acquire); let mut trb = read_trb(&self.mem, dequeue)?; - trb.addr = dequeue; + trb.addr = dequeue.raw_value(); trb.ccs = ccs; trace::usb_xhci_fetch_trb(&dequeue, &trb.parameter, &trb.status, &trb.control); let trb_type = trb.get_type(); @@ -177,15 +180,15 @@ impl XhciTransferRing { if link_cnt > TRB_LINK_LIMIT { bail!("TRB link over limit"); } - dequeue = trb.parameter; + dequeue = GuestAddress(trb.parameter); if trb.control & TRB_LK_TC == TRB_LK_TC { ccs = !ccs; } } else { td.push(trb); - dequeue = dequeue - .checked_add(u64::from(TRB_SIZE)) - .ok_or_else(|| UsbError::MemoryAccessOverflow(dequeue, u64::from(TRB_SIZE)))?; + dequeue = dequeue.checked_add(u64::from(TRB_SIZE)).ok_or_else(|| { + UsbError::MemoryAccessOverflow(dequeue.raw_value(), u64::from(TRB_SIZE)) + })?; if trb_type == TRBType::TrSetup { ctrl_td = true; } else if trb_type == TRBType::TrStatus { @@ -216,15 +219,15 @@ impl XhciTransferRing { } pub fn update_dequeue_to_ctx(&self, ctx: &mut [u32]) { - let dequeue = self.get_dequeue_ptr(); + let dequeue = self.get_dequeue_ptr().raw_value(); ctx[0] = dequeue as u32 | u32::from(self.get_cycle_bit()); ctx[1] = (dequeue >> 32) as u32; } } -fn read_trb(mem: &Arc, addr: u64) -> Result { +fn read_trb(mem: &Arc, addr: GuestAddress) -> Result { let mut buf = [0; TRB_SIZE as usize]; - dma_read_bytes(mem, GuestAddress(addr), &mut buf)?; + dma_read_bytes(mem, addr, &mut buf)?; let trb = XhciTRB { parameter: LittleEndian::read_u64(&buf), status: LittleEndian::read_u32(&buf[8..]), @@ -235,12 +238,12 @@ fn read_trb(mem: &Arc, addr: u64) -> Result { Ok(trb) } -fn read_cycle_bit(mem: &Arc, addr: u64) -> Result { +fn read_cycle_bit(mem: &Arc, addr: GuestAddress) -> Result { let addr = addr .checked_add(12) - .with_context(|| format!("Ring address overflow, {:x}", addr))?; + .ok_or_else(|| UsbError::MemoryAccessOverflow(addr.raw_value(), 12))?; let mut buf = [0]; - dma_read_u32(mem, GuestAddress(addr), &mut buf)?; + dma_read_u32(mem, addr, &mut buf)?; Ok(buf[0] & TRB_C == TRB_C) } -- Gitee From 5254996059f25b3cd5f72a9dd2c31fd14ed54470 Mon Sep 17 00:00:00 2001 From: Jinhao Gao Date: Thu, 15 Aug 2024 19:20:54 +0800 Subject: [PATCH 314/489] USB: Check whether some addresses related to the event ring are valid The event ring dequeue pointer and the event ring segment table base address must locate in guest ram. Signed-off-by: Jinhao Gao --- devices/src/usb/xhci/xhci_controller.rs | 2 +- devices/src/usb/xhci/xhci_regs.rs | 56 ++++++++++++++----------- devices/src/usb/xhci/xhci_ring.rs | 4 +- 3 files changed, 34 insertions(+), 28 deletions(-) diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index ad92caa8..7ad659c5 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -2361,7 +2361,7 @@ impl XhciDevice { pub(crate) fn reset_event_ring(&mut self, idx: u32) -> Result<()> { let mut locked_intr = self.intrs[idx as usize].lock().unwrap(); - if locked_intr.erstsz == 0 || locked_intr.erstba == 0 { + if locked_intr.erstsz == 0 || locked_intr.erstba.raw_value() == 0 { locked_intr.er_start = GuestAddress(0); locked_intr.er_size = 0; return Ok(()); diff --git a/devices/src/usb/xhci/xhci_regs.rs b/devices/src/usb/xhci/xhci_regs.rs index 7062d52c..02c92ce2 100644 --- a/devices/src/usb/xhci/xhci_regs.rs +++ b/devices/src/usb/xhci/xhci_regs.rs @@ -183,9 +183,9 @@ pub struct XhciInterrupter { /// Event Ring Segment Table Size pub erstsz: u32, /// Event Ring Segment Table Base Address - pub erstba: u64, + pub erstba: GuestAddress, /// Event Ring Dequeue Pointer - pub erdp: u64, + pub erdp: GuestAddress, /// Event Ring Producer Cycle State pub er_pcs: bool, pub er_start: GuestAddress, @@ -209,8 +209,8 @@ impl XhciInterrupter { iman: 0, imod: 0, erstsz: 0, - erstba: 0, - erdp: 0, + erstba: GuestAddress(0), + erdp: GuestAddress(0), er_pcs: true, er_start: GuestAddress(0), er_size: 0, @@ -235,8 +235,8 @@ impl XhciInterrupter { self.iman = 0; self.imod = 0; self.erstsz = 0; - self.erstba = 0; - self.erdp = 0; + self.erstba = GuestAddress(0); + self.erdp = GuestAddress(0); self.er_pcs = true; self.er_start = GuestAddress(0); self.er_size = 0; @@ -254,15 +254,15 @@ impl XhciInterrupter { u64::from(TRB_SIZE * self.er_size), ) })?; - if self.erdp < self.er_start.raw_value() || self.erdp >= er_end.raw_value() { + if self.erdp < self.er_start || self.erdp >= er_end { bail!( - "DMA out of range, erdp {} er_start {:x} er_size {}", - self.erdp, + "DMA out of range, erdp {:x} er_start {:x} er_size {}", + self.erdp.raw_value(), self.er_start.raw_value(), self.er_size ); } - let dp_idx = (self.erdp - self.er_start.raw_value()) / u64::from(TRB_SIZE); + let dp_idx = (self.erdp.raw_value() - self.er_start.raw_value()) / u64::from(TRB_SIZE); if u64::from((self.er_ep_idx + 2) % self.er_size) == dp_idx { debug!("Event ring full error, idx {}", dp_idx); let event = XhciEvent::new(TRBType::ErHostController, TRBCCode::EventRingFullError); @@ -277,10 +277,11 @@ impl XhciInterrupter { } fn send_intr(&mut self) { - let pending = read_u32(self.erdp, 0) & ERDP_EHB == ERDP_EHB; - let mut erdp_low = read_u32(self.erdp, 0); + let erdp = self.erdp.raw_value(); + let pending = read_u32(erdp, 0) & ERDP_EHB == ERDP_EHB; + let mut erdp_low = read_u32(erdp, 0); erdp_low |= ERDP_EHB; - self.erdp = write_u64_low(self.erdp, erdp_low); + self.erdp = GuestAddress(write_u64_low(erdp, erdp_low)); self.iman |= IMAN_IP; self.enable_intr(); if pending { @@ -581,10 +582,10 @@ pub fn build_runtime_ops(xhci_dev: &Arc>) -> RegionOps { XHCI_INTR_REG_IMAN => locked_intr.iman, XHCI_INTR_REG_IMOD => locked_intr.imod, XHCI_INTR_REG_ERSTSZ => locked_intr.erstsz, - XHCI_INTR_REG_ERSTBA_LO => read_u32(locked_intr.erstba, 0), - XHCI_INTR_REG_ERSTBA_HI => read_u32(locked_intr.erstba, 1), - XHCI_INTR_REG_ERDP_LO => read_u32(locked_intr.erdp, 0), - XHCI_INTR_REG_ERDP_HI => read_u32(locked_intr.erdp, 1), + XHCI_INTR_REG_ERSTBA_LO => read_u32(locked_intr.erstba.raw_value(), 0), + XHCI_INTR_REG_ERSTBA_HI => read_u32(locked_intr.erstba.raw_value(), 1), + XHCI_INTR_REG_ERDP_LO => read_u32(locked_intr.erdp.raw_value(), 0), + XHCI_INTR_REG_ERDP_HI => read_u32(locked_intr.erdp.raw_value(), 1), _ => { error!( "Invalid offset {:x} for reading interrupter registers.", @@ -627,10 +628,12 @@ pub fn build_runtime_ops(xhci_dev: &Arc>) -> RegionOps { XHCI_INTR_REG_IMOD => locked_intr.imod = value, XHCI_INTR_REG_ERSTSZ => locked_intr.erstsz = value & 0xffff, XHCI_INTR_REG_ERSTBA_LO => { - locked_intr.erstba = write_u64_low(locked_intr.erstba, value & 0xffffffc0); + let erstba = write_u64_low(locked_intr.erstba.raw_value(), value & 0xffffffc0); + locked_intr.erstba = GuestAddress(erstba); } XHCI_INTR_REG_ERSTBA_HI => { - locked_intr.erstba = write_u64_high(locked_intr.erstba, value); + let erstba = GuestAddress(write_u64_high(locked_intr.erstba.raw_value(), value)); + locked_intr.erstba = erstba; drop(locked_intr); if let Err(e) = xhci.reset_event_ring(idx) { error!("Failed to reset event ring: {:?}", e); @@ -640,10 +643,11 @@ pub fn build_runtime_ops(xhci_dev: &Arc>) -> RegionOps { // ERDP_EHB is write 1 clear. let mut erdp_lo = value & !ERDP_EHB; if value & ERDP_EHB != ERDP_EHB { - let erdp_old = read_u32(locked_intr.erdp, 0); + let erdp_old = read_u32(locked_intr.erdp.raw_value(), 0); erdp_lo |= erdp_old & ERDP_EHB; } - locked_intr.erdp = write_u64_low(locked_intr.erdp, erdp_lo); + let erdp = write_u64_low(locked_intr.erdp.raw_value(), erdp_lo); + locked_intr.erdp = GuestAddress(erdp); if value & ERDP_EHB == ERDP_EHB { let erdp = locked_intr.erdp; let er_end = if let Some(addr) = locked_intr @@ -659,9 +663,10 @@ pub fn build_runtime_ops(xhci_dev: &Arc>) -> RegionOps { ); return false; }; - if erdp >= locked_intr.er_start.raw_value() - && erdp < er_end.raw_value() - && (erdp - locked_intr.er_start.raw_value()) / u64::from(TRB_SIZE) + if erdp >= locked_intr.er_start + && erdp < er_end + && (erdp.raw_value() - locked_intr.er_start.raw_value()) + / u64::from(TRB_SIZE) != u64::from(locked_intr.er_ep_idx) { drop(locked_intr); @@ -670,7 +675,8 @@ pub fn build_runtime_ops(xhci_dev: &Arc>) -> RegionOps { } } XHCI_INTR_REG_ERDP_HI => { - locked_intr.erdp = write_u64_high(locked_intr.erdp, value); + let erdp = write_u64_high(locked_intr.erdp.raw_value(), value); + locked_intr.erdp = GuestAddress(erdp); } _ => { error!( diff --git a/devices/src/usb/xhci/xhci_ring.rs b/devices/src/usb/xhci/xhci_ring.rs index 0bfcee49..b7a5df43 100644 --- a/devices/src/usb/xhci/xhci_ring.rs +++ b/devices/src/usb/xhci/xhci_ring.rs @@ -268,9 +268,9 @@ impl XhciEventRingSeg { } /// Fetch the event ring segment. - pub fn fetch_event_ring_seg(&mut self, addr: u64) -> Result<()> { + pub fn fetch_event_ring_seg(&mut self, addr: GuestAddress) -> Result<()> { let mut buf = [0_u8; TRB_SIZE as usize]; - dma_read_bytes(&self.mem, GuestAddress(addr), &mut buf)?; + dma_read_bytes(&self.mem, addr, &mut buf)?; self.addr_lo = LittleEndian::read_u32(&buf); self.addr_hi = LittleEndian::read_u32(&buf[4..]); self.size = LittleEndian::read_u32(&buf[8..]); -- Gitee From 9a62c202d20a7a3eddf1188efae89a6fd67409a9 Mon Sep 17 00:00:00 2001 From: Jinhao Gao Date: Mon, 19 Aug 2024 21:41:37 +0800 Subject: [PATCH 315/489] USB: Check if dcbaap address is valid Check if dcbaap address is valid. Signed-off-by: Jinhao Gao --- devices/src/usb/xhci/xhci_controller.rs | 5 +++-- devices/src/usb/xhci/xhci_regs.rs | 14 ++++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index 7ad659c5..8eca4640 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -1459,9 +1459,10 @@ impl XhciDevice { fn get_device_context_addr(&self, slot_id: u32) -> Result { self.oper .dcbaap + .raw_value() .checked_add(u64::from(8 * slot_id)) .with_context(|| { - UsbError::MemoryAccessOverflow(self.oper.dcbaap, u64::from(8 * slot_id)) + UsbError::MemoryAccessOverflow(self.oper.dcbaap.raw_value(), u64::from(8 * slot_id)) }) } @@ -1700,7 +1701,7 @@ impl XhciDevice { } self.cancel_all_ep_transfers(slot_id, ep_id, TRBCCode::Invalid)?; let epctx = &mut self.slots[(slot_id - 1) as usize].endpoints[(ep_id - 1) as usize]; - if self.oper.dcbaap != 0 { + if self.oper.dcbaap.raw_value() != 0 { epctx.set_state(EP_DISABLED, None)?; } epctx.enabled = false; diff --git a/devices/src/usb/xhci/xhci_regs.rs b/devices/src/usb/xhci/xhci_regs.rs index 02c92ce2..abf3128d 100644 --- a/devices/src/usb/xhci/xhci_regs.rs +++ b/devices/src/usb/xhci/xhci_regs.rs @@ -124,7 +124,7 @@ pub struct XhciOperReg { /// Command Ring Control pub cmd_ring_ctrl: u64, /// Device Context Base Address Array Pointer - pub dcbaap: u64, + pub dcbaap: GuestAddress, /// Configure pub config: u32, } @@ -135,7 +135,7 @@ impl XhciOperReg { self.set_usb_status(USB_STS_HCH); self.dev_notify_ctrl = 0; self.cmd_ring_ctrl = 0; - self.dcbaap = 0; + self.dcbaap = GuestAddress(0); self.config = 0; } @@ -453,8 +453,8 @@ pub fn build_oper_ops(xhci_dev: &Arc>) -> RegionOps { // Table 5-24 shows read CRP always returns 0. 0 } - XHCI_OPER_REG_DCBAAP_LO => read_u32(locked_xhci.oper.dcbaap, 0), - XHCI_OPER_REG_DCBAAP_HI => read_u32(locked_xhci.oper.dcbaap, 1), + XHCI_OPER_REG_DCBAAP_LO => read_u32(locked_xhci.oper.dcbaap.raw_value(), 0), + XHCI_OPER_REG_DCBAAP_HI => read_u32(locked_xhci.oper.dcbaap.raw_value(), 1), XHCI_OPER_REG_CONFIG => locked_xhci.oper.config, _ => { error!( @@ -535,10 +535,12 @@ pub fn build_oper_ops(xhci_dev: &Arc>) -> RegionOps { locked_xhci.oper.cmd_ring_ctrl = write_u64_low(crc_hi, crc_lo); } XHCI_OPER_REG_DCBAAP_LO => { - locked_xhci.oper.dcbaap = write_u64_low(locked_xhci.oper.dcbaap, value & 0xffffffc0) + let dcbaap = write_u64_low(locked_xhci.oper.dcbaap.raw_value(), value & 0xffffffc0); + locked_xhci.oper.dcbaap = GuestAddress(dcbaap); } XHCI_OPER_REG_DCBAAP_HI => { - locked_xhci.oper.dcbaap = write_u64_high(locked_xhci.oper.dcbaap, value) + let dcbaap = write_u64_high(locked_xhci.oper.dcbaap.raw_value(), value); + locked_xhci.oper.dcbaap = GuestAddress(dcbaap); } XHCI_OPER_REG_CONFIG => locked_xhci.oper.config = value & 0xff, _ => { -- Gitee From 1833e5f02018893b1cf2e9f71ec1e6d8100833e4 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Thu, 22 Aug 2024 20:23:52 +0800 Subject: [PATCH 316/489] chardev_backend: Set type for numeric literal Signed-off-by: Keqian Zhu --- chardev_backend/src/chardev.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chardev_backend/src/chardev.rs b/chardev_backend/src/chardev.rs index d13d306e..3f9e58b0 100644 --- a/chardev_backend/src/chardev.rs +++ b/chardev_backend/src/chardev.rs @@ -317,7 +317,7 @@ impl Chardev { fn write_buffer_sync(writer: Arc>, buf: Vec) -> Result<()> { let len = buf.len(); - let mut written = 0; + let mut written = 0_usize; let mut locked_writer = writer.lock().unwrap(); while written < len { @@ -339,7 +339,7 @@ fn write_buffer_async( ) -> Result { let len = buf.len(); let mut locked_writer = writer.lock().unwrap(); - let mut written = 0; + let mut written = 0_usize; while written < len { match locked_writer.write(&buf[written..len]) { -- Gitee From 26c76db26a5030dcc027954af3116d0b358b77da Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Thu, 22 Aug 2024 22:59:34 +0800 Subject: [PATCH 317/489] util: Fix possible truncation warnings Signed-off-by: Keqian Zhu --- util/src/logger.rs | 2 +- util/src/loop_context.rs | 4 ++-- util/src/pixman.rs | 5 +++++ util/src/seccomp.rs | 7 ++++--- util/src/tap.rs | 4 ++-- util/src/unix.rs | 10 +++++----- virtio/src/device/net.rs | 4 ++-- 7 files changed, 21 insertions(+), 15 deletions(-) diff --git a/util/src/logger.rs b/util/src/logger.rs index c5f6aec7..0f8634bb 100644 --- a/util/src/logger.rs +++ b/util/src/logger.rs @@ -159,7 +159,7 @@ fn init_vm_logger( current_size = Wrapping(metadata.len() as usize); let mod_time = metadata.modified()?; let sec = mod_time.duration_since(UNIX_EPOCH)?.as_secs(); - create_day = get_format_time(sec as i64)[2]; + create_day = get_format_time(i64::try_from(sec)?)[2]; }; let rotate = Mutex::new(FileRotate { handler: logfile, diff --git a/util/src/loop_context.rs b/util/src/loop_context.rs index 42c94c5f..0f00ed07 100644 --- a/util/src/loop_context.rs +++ b/util/src/loop_context.rs @@ -11,7 +11,6 @@ // See the Mulan PSL v2 for more details. use std::collections::BTreeMap; -use std::fmt; use std::fmt::Debug; use std::io::Error; use std::os::unix::io::{AsRawFd, RawFd}; @@ -19,6 +18,7 @@ use std::rc::Rc; use std::sync::atomic::{AtomicBool, AtomicU64, Ordering}; use std::sync::{Arc, Barrier, Mutex, RwLock}; use std::time::{Duration, Instant}; +use std::{fmt, i32}; use anyhow::{anyhow, Context, Result}; use libc::{c_void, read, EFD_CLOEXEC, EFD_NONBLOCK}; @@ -681,7 +681,7 @@ impl EventLoopContext { } let time_out_ms = match time_out { - Some(t) => t.as_millis() as i32, + Some(t) => i32::try_from(t.as_millis()).unwrap_or(i32::MAX), None => -1, }; let ev_count = match self.epoll.wait(time_out_ms, &mut self.ready_events[..]) { diff --git a/util/src/pixman.rs b/util/src/pixman.rs index 50fc5d28..5df34e03 100644 --- a/util/src/pixman.rs +++ b/util/src/pixman.rs @@ -199,6 +199,7 @@ pub extern "C" fn virtio_gpu_unref_resource_callback( fn pixman_format_reshift(val: u32, ofs: u32, num: u32) -> u32 { ((val >> (ofs)) & ((1 << (num)) - 1)) << ((val >> 22) & 3) } + pub fn pixman_format_bpp(val: u32) -> u8 { pixman_format_reshift(val, 24, 8) as u8 } @@ -206,15 +207,19 @@ pub fn pixman_format_bpp(val: u32) -> u8 { pub fn pixman_format_a(val: u32) -> u8 { pixman_format_reshift(val, 12, 4) as u8 } + pub fn pixman_format_r(val: u32) -> u8 { pixman_format_reshift(val, 8, 4) as u8 } + pub fn pixman_format_g(val: u32) -> u8 { pixman_format_reshift(val, 4, 4) as u8 } + pub fn pixman_format_b(val: u32) -> u8 { pixman_format_reshift(val, 0, 4) as u8 } + pub fn pixman_format_depth(val: u32) -> u8 { pixman_format_a(val) + pixman_format_r(val) + pixman_format_g(val) + pixman_format_b(val) } diff --git a/util/src/seccomp.rs b/util/src/seccomp.rs index 41206a3b..13827e92 100644 --- a/util/src/seccomp.rs +++ b/util/src/seccomp.rs @@ -348,7 +348,7 @@ impl BpfRule { inner_append.push(constraint_filter); inner_append.push(bpf_stmt(BPF_RET + BPF_K, SECCOMP_RET_ALLOW)); - if !self.append(&mut inner_append) { + if !self.append_to_inner(&mut inner_append) { self.start_new_session(); self.add_constraint(cmp, args_idx, args_value) } else { @@ -379,7 +379,8 @@ impl BpfRule { } /// Add bpf_filters to `inner_rules`. - fn append(&mut self, bpf_filters: &mut Vec) -> bool { + fn append_to_inner(&mut self, bpf_filters: &mut Vec) -> bool { + // bpf_filters len is less than u8::MAX. let offset = bpf_filters.len() as u8; if let Some(jf_added) = self.header_rule.jf.checked_add(offset) { @@ -446,7 +447,7 @@ impl SyscallFilter { } let prog = SockFProg { - len: sock_bpf_vec.len() as u16, + len: u16::try_from(sock_bpf_vec.len())?, sock_filter: sock_bpf_vec.as_ptr(), }; let bpf_prog_ptr = &prog as *const SockFProg; diff --git a/util/src/tap.rs b/util/src/tap.rs index 55c98a93..4752cd67 100644 --- a/util/src/tap.rs +++ b/util/src/tap.rs @@ -194,7 +194,7 @@ impl Tap { ret } - pub fn receive_packets(&self, iovecs: &[Iovec]) -> i32 { + pub fn receive_packets(&self, iovecs: &[Iovec]) -> isize { // SAFETY: the arguments of readv has been checked and is correct. let size = unsafe { libc::readv( @@ -202,7 +202,7 @@ impl Tap { iovecs.as_ptr() as *const libc::iovec, iovecs.len() as libc::c_int, ) - } as i32; + }; if size < 0 { let e = std::io::Error::last_os_error(); if e.kind() == std::io::ErrorKind::WouldBlock { diff --git a/util/src/unix.rs b/util/src/unix.rs index bf103ee3..af4de597 100644 --- a/util/src/unix.rs +++ b/util/src/unix.rs @@ -301,9 +301,9 @@ impl UnixSock { // SAFETY: We checked the iovecs lens before. let iovecs_len = iovecs.len(); // SAFETY: We checked the out_fds lens before. - let cmsg_len = unsafe { CMSG_LEN((std::mem::size_of_val(out_fds)) as u32) }; + let cmsg_len = unsafe { CMSG_LEN(u32::try_from(std::mem::size_of_val(out_fds))?) }; // SAFETY: We checked the out_fds lens before. - let cmsg_capacity = unsafe { CMSG_SPACE((std::mem::size_of_val(out_fds)) as u32) }; + let cmsg_capacity = unsafe { CMSG_SPACE(u32::try_from(std::mem::size_of_val(out_fds))?) }; let mut cmsg_buffer = vec![0_u64; cmsg_capacity as usize]; // In `musl` toolchain, msghdr has private member `__pad0` and `__pad1`, it can't be @@ -348,7 +348,7 @@ impl UnixSock { // SAFETY: msg parameters are valid. let write_count = unsafe { sendmsg(sock.as_raw_fd(), &msg, MSG_NOSIGNAL) }; - if write_count == -1 { + if write_count < 0 { Err(anyhow!( "Failed to send msg, err: {}", std::io::Error::last_os_error() @@ -372,7 +372,7 @@ impl UnixSock { // SAFETY: We check the iovecs lens before. let iovecs_len = iovecs.len(); // SAFETY: We check the in_fds lens before. - let cmsg_capacity = unsafe { CMSG_SPACE((std::mem::size_of_val(in_fds)) as u32) }; + let cmsg_capacity = unsafe { CMSG_SPACE(u32::try_from(std::mem::size_of_val(in_fds))?) }; let mut cmsg_buffer = vec![0_u64; cmsg_capacity as usize]; // In `musl` toolchain, msghdr has private member `__pad0` and `__pad1`, it can't be @@ -399,7 +399,7 @@ impl UnixSock { // SAFETY: msg parameters are valid. let total_read = unsafe { recvmsg(sock.as_raw_fd(), &mut msg, MSG_WAITALL) }; - if total_read == -1 { + if total_read < 0 { bail!( "Failed to recv msg, err: {}", std::io::Error::last_os_error() diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index 09f43aeb..fe7632dc 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -741,7 +741,7 @@ impl NetIoQueue { -1 }; drop(locked_tap); - if size < (NET_HDR_LENGTH + ETHERNET_HDR_LENGTH + VLAN_TAG_LENGTH) as i32 { + if size < (NET_HDR_LENGTH + ETHERNET_HDR_LENGTH + VLAN_TAG_LENGTH) as isize { queue.vring.push_back(); break; } @@ -769,7 +769,7 @@ impl NetIoQueue { queue .vring - .add_used(&self.mem_space, elem.index, size as u32) + .add_used(&self.mem_space, elem.index, u32::try_from(size)?) .with_context(|| { format!( "Failed to add used ring for net rx, index: {}, len: {}", -- Gitee From 5add34a0aebd561e8b032689c20caafb5c6960ff Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Fri, 23 Aug 2024 10:23:37 +0800 Subject: [PATCH 318/489] util: Set type for numeric literal Signed-off-by: Keqian Zhu --- util/src/bitmap.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/util/src/bitmap.rs b/util/src/bitmap.rs index 128a286c..2147ef77 100644 --- a/util/src/bitmap.rs +++ b/util/src/bitmap.rs @@ -515,7 +515,7 @@ mod tests { assert!(bitmap.clear(64).is_ok()); assert!(bitmap.clear(128).is_ok()); - let mut offset = 0; + let mut offset = 0_usize; offset = bitmap.find_next_zero(offset).unwrap(); assert_eq!(offset, 0); offset = bitmap.find_next_zero(offset + 1).unwrap(); @@ -537,7 +537,7 @@ mod tests { assert!(bitmap.set(64).is_ok()); assert!(bitmap.set(128).is_ok()); - let mut offset = 0; + let mut offset = 0_usize; offset = bitmap.find_next_bit(offset).unwrap(); assert_eq!(offset, 0); offset = bitmap.find_next_bit(offset + 1).unwrap(); -- Gitee From a1632550aa2a0e1b0d6cbb57f3832f6c4e860045 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Fri, 23 Aug 2024 15:52:15 +0800 Subject: [PATCH 319/489] util: Fix arithmetic side effetcts warnings Signed-off-by: Keqian Zhu --- devices/src/legacy/rtc.rs | 8 +++++++- machine_manager/src/qmp/qmp_socket.rs | 2 +- util/src/arg_parser.rs | 3 +++ util/src/leak_bucket.rs | 27 +++++++++++++++------------ util/src/num_ops.rs | 22 ++++++++++------------ util/src/pixman.rs | 5 ++++- util/src/seccomp.rs | 8 ++++---- util/src/time.rs | 4 ++-- util/src/unix.rs | 7 +++++-- virtio/src/device/block.rs | 4 ++-- virtio/src/device/rng.rs | 2 +- 11 files changed, 54 insertions(+), 38 deletions(-) diff --git a/devices/src/legacy/rtc.rs b/devices/src/legacy/rtc.rs index 9fd4a089..4c324bf5 100644 --- a/devices/src/legacy/rtc.rs +++ b/devices/src/legacy/rtc.rs @@ -321,7 +321,13 @@ impl RTC { + bcd_to_bin(self.cmos_data[RTC_CENTURY_BCD as usize]) * 100; // Check rtc time is valid to prevent tick_offset overflow. - if year < 1970 || !(1..=12).contains(&mon) || !(1..=31).contains(&day) { + if year < 1970 + || !(1..=12).contains(&mon) + || !(1..=31).contains(&day) + || !(0..=24).contains(&hour) + || !(0..=60).contains(&min) + || !(0..=60).contains(&sec) + { warn!( "RTC: the updated rtc time {}-{}-{} may be invalid.", year, mon, day diff --git a/machine_manager/src/qmp/qmp_socket.rs b/machine_manager/src/qmp/qmp_socket.rs index d2ed4992..f0b4ace2 100644 --- a/machine_manager/src/qmp/qmp_socket.rs +++ b/machine_manager/src/qmp/qmp_socket.rs @@ -375,7 +375,7 @@ fn handle_qmp( // If flow over `LEAK_BUCKET_LIMIT` per seconds, discard the request and return // a `OperationThrottled` error. - if leak_bucket.throttled(EventLoop::get_ctx(None).unwrap(), 1_u64) { + if leak_bucket.throttled(EventLoop::get_ctx(None).unwrap(), 1_u32) { qmp_service.discard()?; let err_resp = qmp_schema::QmpErrorClass::OperationThrottled(LEAK_BUCKET_LIMIT); qmp_service diff --git a/util/src/arg_parser.rs b/util/src/arg_parser.rs index e92f052a..1d6ddf91 100644 --- a/util/src/arg_parser.rs +++ b/util/src/arg_parser.rs @@ -608,6 +608,9 @@ impl<'a> ArgMatches<'a> { fn split_arg(args: &[String]) -> (&[String], &[String]) { if let Some(index) = args.iter().position(|arg| arg == ARG_SEPARATOR) { + if index == args.len() - 1 { + return (&args[..index], &[]); + } return (&args[..index], &args[index + 1..]); } (args, &[]) diff --git a/util/src/leak_bucket.rs b/util/src/leak_bucket.rs index 9390e17b..23a1d910 100644 --- a/util/src/leak_bucket.rs +++ b/util/src/leak_bucket.rs @@ -15,7 +15,7 @@ use std::os::unix::io::{AsRawFd, RawFd}; use std::sync::Arc; use std::time::{Duration, Instant}; -use anyhow::Result; +use anyhow::{Context, Result}; use log::error; use vmm_sys_util::eventfd::EventFd; @@ -49,7 +49,9 @@ impl LeakBucket { /// * `units_ps` - units per second. pub fn new(units_ps: u64) -> Result { Ok(LeakBucket { - capacity: units_ps * ACCURACY_SCALE, + capacity: units_ps + .checked_mul(ACCURACY_SCALE) + .with_context(|| "capacity overflow")?, level: 0, prev_time: get_current_time(), timer_started: false, @@ -63,7 +65,7 @@ impl LeakBucket { /// # Arguments /// /// * `loop_context` - used for delay function call. - pub fn throttled(&mut self, loop_context: &mut EventLoopContext, need_units: u64) -> bool { + pub fn throttled(&mut self, loop_context: &mut EventLoopContext, need_units: u32) -> bool { // capacity value is zero, indicating that there is no need to limit if self.capacity == 0 { return false; @@ -75,10 +77,13 @@ impl LeakBucket { // update the water level let now = get_current_time(); let nanos = (now - self.prev_time).as_nanos(); - if nanos > u128::from(self.level * NANOSECONDS_PER_SECOND / self.capacity) { + let throttle_timeout = + u128::from(self.level) * u128::from(NANOSECONDS_PER_SECOND) / u128::from(self.capacity); + if nanos > throttle_timeout { self.level = 0; } else { - self.level -= nanos as u64 * self.capacity / NANOSECONDS_PER_SECOND; + self.level -= + (nanos * u128::from(self.capacity) / u128::from(NANOSECONDS_PER_SECOND)) as u64; } self.prev_time = now; @@ -92,19 +97,17 @@ impl LeakBucket { .unwrap_or_else(|e| error!("LeakBucket send event to device failed {:?}", e)); }); - loop_context.timer_add( - func, - Duration::from_nanos( - (self.level - self.capacity) * NANOSECONDS_PER_SECOND / self.capacity, - ), - ); + let timeout = + (self.level - self.capacity).saturating_mul(NANOSECONDS_PER_SECOND) / self.capacity; + loop_context.timer_add(func, Duration::from_nanos(timeout)); self.timer_started = true; return true; } - self.level += need_units * ACCURACY_SCALE; + let scaled_need = u64::from(need_units) * ACCURACY_SCALE; + self.level = self.level.saturating_add(scaled_need); false } diff --git a/util/src/num_ops.rs b/util/src/num_ops.rs index da9a6e99..f5ea59be 100644 --- a/util/src/num_ops.rs +++ b/util/src/num_ops.rs @@ -35,7 +35,7 @@ use log::error; /// assert!(value == Some(1004)); /// ``` pub fn round_up(origin: u64, align: u64) -> Option { - match origin % align { + match origin.checked_rem(align)? { 0 => Some(origin), diff => origin.checked_add(align - diff), } @@ -58,7 +58,7 @@ pub fn round_up(origin: u64, align: u64) -> Option { /// assert!(value == Some(1000)); /// ``` pub fn round_down(origin: u64, align: u64) -> Option { - match origin % align { + match origin.checked_rem(align)? { 0 => Some(origin), diff => origin.checked_sub(diff), } @@ -81,14 +81,12 @@ pub fn round_down(origin: u64, align: u64) -> Option { /// assert!(value == Some(3)); /// ``` pub fn div_round_up(dividend: u64, divisor: u64) -> Option { - if let Some(res) = dividend.checked_div(divisor) { - if dividend % divisor == 0 { - return Some(res); - } else { - return Some(res + 1); - } + let res = dividend.checked_div(divisor)?; + if dividend.checked_rem(divisor)? == 0 { + Some(res) + } else { + Some(res + 1) } - None } /// Get the first half or second half of u64. @@ -203,7 +201,7 @@ pub fn write_u64_high(origin: u64, value: u32) -> u64 { /// assert!(value == 0xfa); /// ``` pub fn extract_u32(value: u32, start: u32, length: u32) -> Option { - if length > 32 - start { + if length > 32_u32.checked_sub(start)? { error!( "extract_u32: ( start {} length {} ) is out of range", start, length @@ -235,7 +233,7 @@ pub fn extract_u32(value: u32, start: u32, length: u32) -> Option { /// assert!(value == 0xffff); /// ``` pub fn extract_u64(value: u64, start: u32, length: u32) -> Option { - if length > 64 - start { + if length > 64_u32.checked_sub(start)? { error!( "extract_u64: ( start {} length {} ) is out of range", start, length @@ -271,7 +269,7 @@ pub fn extract_u64(value: u64, start: u32, length: u32) -> Option { /// assert!(value == 0xffba); /// ``` pub fn deposit_u32(value: u32, start: u32, length: u32, fieldval: u32) -> Option { - if length > 32 - start { + if length > 32_u32.checked_sub(start)? { error!( "deposit_u32: ( start {} length {} ) is out of range", start, length diff --git a/util/src/pixman.rs b/util/src/pixman.rs index 5df34e03..4ec4d074 100644 --- a/util/src/pixman.rs +++ b/util/src/pixman.rs @@ -221,7 +221,10 @@ pub fn pixman_format_b(val: u32) -> u8 { } pub fn pixman_format_depth(val: u32) -> u8 { - pixman_format_a(val) + pixman_format_r(val) + pixman_format_g(val) + pixman_format_b(val) + pixman_format_a(val) + .wrapping_add(pixman_format_r(val)) + .wrapping_add(pixman_format_g(val)) + .wrapping_add(pixman_format_b(val)) } extern "C" { diff --git a/util/src/seccomp.rs b/util/src/seccomp.rs index 13827e92..cce0facd 100644 --- a/util/src/seccomp.rs +++ b/util/src/seccomp.rs @@ -213,10 +213,10 @@ impl SeccompData { offset_of!(SeccompData, arch) as u32 } - fn args(num: u32) -> u32 { + fn args(num: u8) -> u32 { let offset_of_u64 = offset_of!(SeccompData, args) - offset_of!(SeccompData, instruction_pointer); - offset_of!(SeccompData, args) as u32 + num * offset_of_u64 as u32 + offset_of!(SeccompData, args) as u32 + u32::from(num) * offset_of_u64 as u32 } } @@ -292,7 +292,7 @@ pub struct BpfRule { /// The first bpf_filter to compare syscall number. header_rule: SockFilter, /// The last args index. - args_idx_last: Option, + args_idx_last: Option, /// The inner rules to limit the arguments of syscall. inner_rules: Vec, /// The last bpf_filter to allow syscall. @@ -321,7 +321,7 @@ impl BpfRule { /// * `args_idx` - The index number of system call's arguments. /// * `args_value` - The value of args_num you want to limit. This value used with `cmp` /// together. - pub fn add_constraint(mut self, cmp: SeccompCmpOpt, args_idx: u32, args_value: u32) -> BpfRule { + pub fn add_constraint(mut self, cmp: SeccompCmpOpt, args_idx: u8, args_value: u32) -> BpfRule { if self.inner_rules.is_empty() { self.tail_rule = bpf_stmt(BPF_LD + BPF_W + BPF_ABS, SeccompData::nr()); } diff --git a/util/src/time.rs b/util/src/time.rs index e8fd8a56..44950661 100644 --- a/util/src/time.rs +++ b/util/src/time.rs @@ -50,8 +50,8 @@ pub fn get_format_time(sec: i64) -> [i32; 6] { } [ - ti.tm_year + 1900, - ti.tm_mon + 1, + ti.tm_year.saturating_add(1900), + ti.tm_mon.saturating_add(1), ti.tm_mday, ti.tm_hour, ti.tm_min, diff --git a/util/src/unix.rs b/util/src/unix.rs index af4de597..d1d3813b 100644 --- a/util/src/unix.rs +++ b/util/src/unix.rs @@ -424,17 +424,20 @@ impl UnixSock { // SAFETY: Input parameter is constant. let fd_count = (cmsg.cmsg_len as u64 - u64::from(unsafe { CMSG_LEN(0) })) as usize / size_of::(); + let new_in_fds_count = in_fds_count + .checked_add(fd_count) + .with_context(|| "fds count overflow")?; // SAFETY: // 1. the pointer of cmsg_ptr was created in this function and can be guaranteed not be null. // 2. the parameter of in_fds has been checked before. unsafe { copy_nonoverlapping( self.cmsg_data(cmsg_ptr), - in_fds[in_fds_count..(in_fds_count + fd_count)].as_mut_ptr(), + in_fds[in_fds_count..new_in_fds_count].as_mut_ptr(), fd_count, ); } - in_fds_count += fd_count; + in_fds_count = new_in_fds_count; } cmsg_ptr = self.get_next_cmsg(&msg, &cmsg, cmsg_ptr); diff --git a/virtio/src/device/block.rs b/virtio/src/device/block.rs index 3cd02f56..ddc28fc9 100644 --- a/virtio/src/device/block.rs +++ b/virtio/src/device/block.rs @@ -661,7 +661,7 @@ impl BlockIoHandler { // limit io operations if iops is configured if let Some(lb) = self.leak_bucket.as_mut() { if let Some(ctx) = EventLoop::get_ctx(self.iothread.as_ref()) { - if lb.throttled(ctx, 1_u64) { + if lb.throttled(ctx, 1_u32) { queue.vring.push_back(); break; } @@ -781,7 +781,7 @@ impl BlockIoHandler { // See whether we have been throttled. if let Some(lb) = self.leak_bucket.as_mut() { if let Some(ctx) = EventLoop::get_ctx(self.iothread.as_ref()) { - if lb.throttled(ctx, 0) { + if lb.throttled(ctx, 0_u32) { break; } } diff --git a/virtio/src/device/rng.rs b/virtio/src/device/rng.rs index 5cc277b1..e7db31b2 100644 --- a/virtio/src/device/rng.rs +++ b/virtio/src/device/rng.rs @@ -167,7 +167,7 @@ impl RngHandler { get_req_data_size(&elem.in_iovec).with_context(|| "Failed to get request size")?; if let Some(leak_bucket) = self.leak_bucket.as_mut() { - if leak_bucket.throttled(EventLoop::get_ctx(None).unwrap(), u64::from(size)) { + if leak_bucket.throttled(EventLoop::get_ctx(None).unwrap(), size) { queue_lock.vring.push_back(); break; } -- Gitee From 73d6493d35df6745db94eb761cdb85d5aca889f8 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Fri, 23 Aug 2024 17:55:27 +0800 Subject: [PATCH 320/489] util: Fix possible out of bound array indexing Signed-off-by: Keqian Zhu --- util/src/bitmap.rs | 2 +- util/src/device_tree.rs | 5 ++++- util/src/loop_context.rs | 3 +-- util/src/unix.rs | 3 +++ 4 files changed, 9 insertions(+), 4 deletions(-) diff --git a/util/src/bitmap.rs b/util/src/bitmap.rs index 2147ef77..3d8111c6 100644 --- a/util/src/bitmap.rs +++ b/util/src/bitmap.rs @@ -230,7 +230,7 @@ impl Bitmap { /// /// * `num` - the input number. pub fn contain(&self, num: usize) -> Result { - if num > self.vol() { + if num >= self.vol() { return Err(anyhow!(UtilError::OutOfBound( num as u64, self.size() as u64 * T::len() as u64, diff --git a/util/src/device_tree.rs b/util/src/device_tree.rs index ebb50d0e..db590271 100644 --- a/util/src/device_tree.rs +++ b/util/src/device_tree.rs @@ -10,7 +10,7 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, bail, Context, Result}; use byteorder::{BigEndian, ByteOrder}; use crate::UtilError; @@ -142,6 +142,9 @@ impl FdtBuilder { let off_dt_strings = FDT_HEADER_SIZE + self.mem_reserve.len() + self.structure_blk.len(); let off_mem_rsvmap = FDT_HEADER_SIZE; + if self.fdt_header.len() < FDT_HEADER_SIZE { + bail!("fdt header size too small"); + } BigEndian::write_u32(&mut self.fdt_header[0..4], FDT_MAGIC); BigEndian::write_u32(&mut self.fdt_header[4..8], total_size as u32); BigEndian::write_u32(&mut self.fdt_header[8..12], off_dt_struct as u32); diff --git a/util/src/loop_context.rs b/util/src/loop_context.rs index 0f00ed07..5bf07652 100644 --- a/util/src/loop_context.rs +++ b/util/src/loop_context.rs @@ -702,8 +702,7 @@ impl EventLoopContext { let mut notifiers = Vec::new(); let status_locked = event.status.lock().unwrap(); if *status_locked == EventStatus::Alive { - for j in 0..event.handlers.len() { - let handler = &event.handlers[j]; + for handler in event.handlers.iter() { match handler(self.ready_events[i].event_set(), event.raw_fd) { None => {} Some(mut notifier) => { diff --git a/util/src/unix.rs b/util/src/unix.rs index d1d3813b..54a27462 100644 --- a/util/src/unix.rs +++ b/util/src/unix.rs @@ -427,6 +427,9 @@ impl UnixSock { let new_in_fds_count = in_fds_count .checked_add(fd_count) .with_context(|| "fds count overflow")?; + if new_in_fds_count > in_fds.len() { + bail!("in_fds is too small"); + } // SAFETY: // 1. the pointer of cmsg_ptr was created in this function and can be guaranteed not be null. // 2. the parameter of in_fds has been checked before. -- Gitee From 307babb5c03916980a4d2dee4014e7f22e9a4a79 Mon Sep 17 00:00:00 2001 From: Keqian Zhu Date: Sat, 24 Aug 2024 19:34:37 +0800 Subject: [PATCH 321/489] util: Verify unsafe code blocks Signed-off-by: Keqian Zhu --- address_space/src/host_mmap.rs | 28 +++--- block_backend/src/qcow2/mod.rs | 15 ++- block_backend/src/raw.rs | 15 +-- devices/src/camera_backend/demo.rs | 3 +- devices/src/usb/mod.rs | 6 +- util/src/aio/mod.rs | 150 ++++++++++++++++++----------- util/src/aio/raw.rs | 81 ++++++++-------- util/src/file.rs | 4 + util/src/lib.rs | 1 - util/src/loop_context.rs | 14 +-- util/src/offsetof.rs | 2 + util/src/pixman.rs | 14 +-- util/src/syscall.rs | 57 ----------- util/src/unix.rs | 45 ++++++++- virtio/src/device/block.rs | 6 +- virtio/src/device/gpu.rs | 18 ++-- virtio/src/device/net.rs | 5 +- virtio/src/device/rng.rs | 15 +-- virtio/src/device/serial.rs | 3 +- virtio/src/lib.rs | 5 +- 20 files changed, 269 insertions(+), 218 deletions(-) delete mode 100644 util/src/syscall.rs diff --git a/address_space/src/host_mmap.rs b/address_space/src/host_mmap.rs index fa807a80..d31d4fd3 100644 --- a/address_space/src/host_mmap.rs +++ b/address_space/src/host_mmap.rs @@ -25,10 +25,7 @@ use nix::unistd::{mkstemp, sysconf, unlink, SysconfVar}; use crate::{AddressRange, GuestAddress, Region}; use machine_manager::config::{HostMemPolicy, MachineMemConfig, MemZoneConfig}; -use util::{ - syscall::mbind, - unix::{do_mmap, host_page_size}, -}; +use util::unix::{do_mmap, host_page_size, mbind}; const MAX_PREALLOC_THREAD: i64 = 16; /// Verify existing pages in the mapping. @@ -370,15 +367,20 @@ fn set_host_memory_policy(mem_mappings: &Arc, zone: &MemZoneConf nmask = vec![0_u64; max_node]; } - mbind( - host_addr_start, - zone.size, - policy as u32, - nmask, - max_node as u64, - MPOL_MF_STRICT | MPOL_MF_MOVE, - ) - .with_context(|| "Failed to call mbind")?; + // SAFETY: + // 1. addr is managed by memory mapping, it can be guaranteed legal. + // 2. node_mask was created in this function. + // 3. Upper limit of max_node is MAX_NODES. + unsafe { + mbind( + host_addr_start, + zone.size, + policy as u32, + nmask, + max_node as u64, + MPOL_MF_STRICT | MPOL_MF_MOVE, + )?; + } Ok(()) } diff --git a/block_backend/src/qcow2/mod.rs b/block_backend/src/qcow2/mod.rs index 308a7778..151b9255 100644 --- a/block_backend/src/qcow2/mod.rs +++ b/block_backend/src/qcow2/mod.rs @@ -1711,7 +1711,8 @@ impl BlockDriverOps for Qcow2Driver { Ok(HostRange::DataNotInit(cnt)) => { let (begin, end) = iovecs_split(left, cnt); left = end; - iovec_write_zero(&begin); + // SAFETY: iovecs is generated by address_space. + unsafe { iovec_write_zero(&begin) }; copied += cnt; } Err(e) => { @@ -2317,8 +2318,10 @@ mod test { let mut wbuf = vec![0; case.sz as usize]; let mut rbuf = vec![0; case.sz as usize]; - let wsz = iov_to_buf_direct(&case.wiovec, 0, &mut wbuf).unwrap(); - let rsz = iov_to_buf_direct(&case.riovec, 0, &mut rbuf).unwrap(); + // SAFETY: wiovec is valid. + let wsz = unsafe { iov_to_buf_direct(&case.wiovec, 0, &mut wbuf).unwrap() }; + // SAFETY: riovec is valid. + let rsz = unsafe { iov_to_buf_direct(&case.riovec, 0, &mut rbuf).unwrap() }; assert_eq!(wsz, case.sz as usize); assert_eq!(rsz, case.sz as usize); assert_eq!(wbuf, rbuf); @@ -2392,8 +2395,10 @@ mod test { let mut wbuf = vec![0; case.sz as usize]; let mut rbuf = vec![0; case.sz as usize]; - let wsz = iov_to_buf_direct(&case.wiovec, 0, &mut wbuf).unwrap(); - let rsz = iov_to_buf_direct(&case.riovec, 0, &mut rbuf).unwrap(); + // SAFETY: wiovec is valid. + let wsz = unsafe { iov_to_buf_direct(&case.wiovec, 0, &mut wbuf).unwrap() }; + // SAFETY: riovec is valid. + let rsz = unsafe { iov_to_buf_direct(&case.riovec, 0, &mut rbuf).unwrap() }; assert_eq!(wsz, case.sz as usize); assert_eq!(rsz, case.sz as usize); assert_eq!(wbuf, rbuf); diff --git a/block_backend/src/raw.rs b/block_backend/src/raw.rs index 0edbc75d..d4957864 100644 --- a/block_backend/src/raw.rs +++ b/block_backend/src/raw.rs @@ -68,12 +68,15 @@ impl RawDriver { bail!("Failed to alloc memory for write."); } - let ret = raw_write( - self.driver.file.as_raw_fd(), - align_buf as u64, - write_size as usize, - 0, - ); + // SAFETY: align_buf is valid and large enough. + let ret = unsafe { + raw_write( + self.driver.file.as_raw_fd(), + align_buf as u64, + write_size as usize, + 0, + ) + }; // SAFETY: the memory is allocated in this function. unsafe { libc::free(align_buf) }; diff --git a/devices/src/camera_backend/demo.rs b/devices/src/camera_backend/demo.rs index 60732d63..725d3de8 100644 --- a/devices/src/camera_backend/demo.rs +++ b/devices/src/camera_backend/demo.rs @@ -467,7 +467,8 @@ impl CameraBackend for DemoCameraBackend { let start = frame_offset + copied; let end = start + cnt; let tmp = &locked_frame.image[start..end]; - mem_from_buf(tmp, iov.iov_base) + // SAFETY: iovecs is generated by address_space and len is not less than tmp's. + unsafe { mem_from_buf(tmp, iov.iov_base) } .with_context(|| format!("Failed to write data to {:x}", iov.iov_base))?; copied += cnt; } diff --git a/devices/src/usb/mod.rs b/devices/src/usb/mod.rs index 5670f16f..ff4927f9 100644 --- a/devices/src/usb/mod.rs +++ b/devices/src/usb/mod.rs @@ -565,7 +565,8 @@ impl UsbPacket { } let cnt = min(iov.iov_len as usize, len - copied); let tmp = &vec[copied..(copied + cnt)]; - if let Err(e) = mem_from_buf(tmp, iov.iov_base) { + // SAFETY: iovecs is generated by address_space and len is not less than tmp's. + if let Err(e) = unsafe { mem_from_buf(tmp, iov.iov_base) } { error!("Failed to write mem: {:?}", e); } copied += cnt; @@ -580,7 +581,8 @@ impl UsbPacket { } let cnt = min(iov.iov_len as usize, len - copied); let tmp = &mut vec[copied..(copied + cnt)]; - if let Err(e) = mem_to_buf(tmp, iov.iov_base) { + // SAFETY: iovecs is generation by address_space and len is not less than tmp's. + if let Err(e) = unsafe { mem_to_buf(tmp, iov.iov_base) } { error!("Failed to read mem {:?}", e); } copied += cnt; diff --git a/util/src/aio/mod.rs b/util/src/aio/mod.rs index a401879b..ac10fa16 100644 --- a/util/src/aio/mod.rs +++ b/util/src/aio/mod.rs @@ -213,8 +213,10 @@ impl AioCb { pub fn rw_sync(&self) -> i32 { let mut ret = match self.opcode { - OpCode::Preadv => raw_readv(self.file_fd, &self.iovec, self.offset), - OpCode::Pwritev => raw_writev(self.file_fd, &self.iovec, self.offset), + // SAFETY: iovec of aiocb is valid. + OpCode::Preadv => unsafe { raw_readv(self.file_fd, &self.iovec, self.offset) }, + // SAFETY: iovec of aiocb is valid. + OpCode::Pwritev => unsafe { raw_writev(self.file_fd, &self.iovec, self.offset) }, _ => -1, }; if ret < 0 { @@ -266,9 +268,10 @@ impl AioCb { // If the buffer is full with zero and the operation is Pwritev, // It's equal to write zero operation. fn try_convert_to_write_zero(&mut self) { - if self.opcode == OpCode::Pwritev - && self.write_zeroes != WriteZeroesState::Off - && iovec_is_zero(&self.iovec) + if self.opcode == OpCode::Pwritev && + self.write_zeroes != WriteZeroesState::Off && + // SAFETY: iovec is generated by address_space. + unsafe { iovec_is_zero(&self.iovec) } { self.opcode = OpCode::WriteZeroes; if self.write_zeroes == WriteZeroesState::Unmap && self.discard { @@ -341,12 +344,15 @@ impl AioCb { loop { // Step1: Read file to bounce buffer. let nbytes = cmp::min(high_align - offset, buffer_len); - let len = raw_read( - self.file_fd, - bounce_buffer as u64, - nbytes as usize, - offset as usize, - ); + // SAFETY: bounce_buffer is valid and large enough. + let len = unsafe { + raw_read( + self.file_fd, + bounce_buffer as u64, + nbytes as usize, + offset as usize, + ) + }; if len < 0 { bail!("Failed to do raw read for misaligned read."); } @@ -370,7 +376,8 @@ impl AioCb { }; // Step2: Copy bounce buffer to iovec. - iov_from_buf_direct(iovecs, src).and_then(|v| { + // SAFETY: iovecs is generated by address_space. + unsafe { iov_from_buf_direct(iovecs, src) }.and_then(|v| { if v == real_nbytes as usize { Ok(()) } else { @@ -392,12 +399,15 @@ impl AioCb { // Load the head from file before fill iovec to buffer. let mut head_loaded = false; if self.offset as u64 > offset_align { - let len = raw_read( - self.file_fd, - bounce_buffer as u64, - self.req_align as usize, - offset_align as usize, - ); + // SAFETY: bounce_buffer is valid and large enough. + let len = unsafe { + raw_read( + self.file_fd, + bounce_buffer as u64, + self.req_align as usize, + offset_align as usize, + ) + }; if len < 0 || len as u32 != self.req_align { bail!("Failed to load head for misaligned write."); } @@ -418,12 +428,15 @@ impl AioCb { let real_nbytes = real_high - real_offset; if real_high == high && need_tail { - let len = raw_read( - self.file_fd, - bounce_buffer as u64 + nbytes - u64::from(self.req_align), - self.req_align as usize, - (offset + nbytes) as usize - self.req_align as usize, - ); + // SAFETY: bounce_buffer is valid and large enough. + let len = unsafe { + raw_read( + self.file_fd, + bounce_buffer as u64 + nbytes - u64::from(self.req_align), + self.req_align as usize, + (offset + nbytes) as usize - self.req_align as usize, + ) + }; if len < 0 || len as u32 != self.req_align { bail!("Failed to load tail for misaligned write."); } @@ -436,7 +449,8 @@ impl AioCb { real_nbytes as usize, ) }; - iov_to_buf_direct(iovecs, 0, dst).and_then(|v| { + // SAFETY: iovecs is generated by address_space. + unsafe { iov_to_buf_direct(iovecs, 0, dst) }.and_then(|v| { if v == real_nbytes as usize { Ok(()) } else { @@ -445,12 +459,15 @@ impl AioCb { })?; // Step2: Write bounce buffer to file. - let len = raw_write( - self.file_fd, - bounce_buffer as u64, - nbytes as usize, - offset as usize, - ); + // SAFETY: bounce_buffer is valid and large enough. + let len = unsafe { + raw_write( + self.file_fd, + bounce_buffer as u64, + nbytes as usize, + offset as usize, + ) + }; if len < 0 || len as u64 != nbytes { bail!("Failed to do raw write for misaligned write."); } @@ -713,22 +730,28 @@ impl Aio { } } -pub fn mem_from_buf(buf: &[u8], hva: u64) -> Result<()> { - // SAFETY: all callers have valid hva address. - let mut slice = unsafe { std::slice::from_raw_parts_mut(hva as *mut u8, buf.len()) }; - (&mut slice) - .write(buf) +/// # Safety +/// +/// Caller should has valid hva address. +pub unsafe fn mem_from_buf(buf: &[u8], hva: u64) -> Result<()> { + let mut slice = std::slice::from_raw_parts_mut(hva as *mut u8, buf.len()); + slice + .write_all(buf) .with_context(|| format!("Failed to write buf to hva:{})", hva))?; Ok(()) } /// Write buf to iovec and return the written number of bytes. -pub fn iov_from_buf_direct(iovec: &[Iovec], buf: &[u8]) -> Result { +/// # Safety +/// +/// Caller should has valid iovec. +pub unsafe fn iov_from_buf_direct(iovec: &[Iovec], buf: &[u8]) -> Result { let mut start: usize = 0; let mut end: usize = 0; for iov in iovec.iter() { end = cmp::min(start + iov.iov_len as usize, buf.len()); + // iov len is not less than buf's. mem_from_buf(&buf[start..end], iov.iov_base)?; if end >= buf.len() { break; @@ -738,16 +761,21 @@ pub fn iov_from_buf_direct(iovec: &[Iovec], buf: &[u8]) -> Result { Ok(end) } -pub fn mem_to_buf(mut buf: &mut [u8], hva: u64) -> Result<()> { - // SAFETY: all callers have valid hva address. - let slice = unsafe { std::slice::from_raw_parts(hva as *const u8, buf.len()) }; - buf.write(slice) +/// # Safety +/// +/// Caller should has valid hva address. +pub unsafe fn mem_to_buf(mut buf: &mut [u8], hva: u64) -> Result<()> { + let slice = std::slice::from_raw_parts(hva as *const u8, buf.len()); + buf.write_all(slice) .with_context(|| format!("Failed to read buf from hva:{})", hva))?; Ok(()) } /// Read iovec to buf and return the read number of bytes. -pub fn iov_to_buf_direct(iovec: &[Iovec], offset: u64, buf: &mut [u8]) -> Result { +/// # Safety +/// +/// Caller should has valid iovec. +pub unsafe fn iov_to_buf_direct(iovec: &[Iovec], offset: u64, buf: &mut [u8]) -> Result { let mut iovec2: Option<&[Iovec]> = None; let mut start: usize = 0; let mut end: usize = 0; @@ -759,6 +787,7 @@ pub fn iov_to_buf_direct(iovec: &[Iovec], offset: u64, buf: &mut [u8]) -> Result for (index, iov) in iovec.iter().enumerate() { if iov.iov_len > offset { end = cmp::min((iov.iov_len - offset) as usize, buf.len()); + // iov len is not less than buf's. mem_to_buf(&mut buf[..end], iov.iov_base + offset)?; if end >= buf.len() || index >= (iovec.len() - 1) { return Ok(end); @@ -776,6 +805,7 @@ pub fn iov_to_buf_direct(iovec: &[Iovec], offset: u64, buf: &mut [u8]) -> Result for iov in iovec2.unwrap() { end = cmp::min(start + iov.iov_len as usize, buf.len()); + // iov len is not less than buf's. mem_to_buf(&mut buf[start..end], iov.iov_base)?; if end >= buf.len() { break; @@ -798,16 +828,16 @@ pub fn iov_discard_front_direct(iovec: &mut [Iovec], mut size: u64) -> Option<&m None } -fn iovec_is_zero(iovecs: &[Iovec]) -> bool { +// Caller should have valid hva iovec. +unsafe fn iovec_is_zero(iovecs: &[Iovec]) -> bool { let size = std::mem::size_of::() as u64; for iov in iovecs { if iov.iov_len % size != 0 { return false; } // SAFETY: iov_base and iov_len has been checked in pop_avail(). - let slice = unsafe { - std::slice::from_raw_parts(iov.iov_base as *const u64, (iov.iov_len / size) as usize) - }; + let slice = + std::slice::from_raw_parts(iov.iov_base as *const u64, (iov.iov_len / size) as usize); for val in slice.iter() { if *val != 0 { return false; @@ -838,12 +868,12 @@ pub fn iovecs_split(iovecs: Vec, mut size: u64) -> (Vec, Vec i64 { +/// # Safety +/// +/// Caller should has valid buf. +pub unsafe fn raw_read(fd: RawFd, buf: u64, size: usize, offset: usize) -> i64 { let mut ret; loop { - // SAFETY: fd and buf is valid. - ret = unsafe { - pread( - fd as c_int, - buf as *mut c_void, - size as size_t, - offset as off_t, - ) as i64 - }; + ret = pread( + fd as c_int, + buf as *mut c_void, + size as size_t, + offset as off_t, + ) as i64; if !(ret < 0 && (nix::errno::errno() == libc::EINTR || nix::errno::errno() == libc::EAGAIN)) { break; @@ -48,18 +48,18 @@ pub fn raw_read(fd: RawFd, buf: u64, size: usize, offset: usize) -> i64 { ret } -pub fn raw_readv(fd: RawFd, iovec: &[Iovec], offset: usize) -> i64 { +/// # Safety +/// +/// Caller should has valid iovec. +pub unsafe fn raw_readv(fd: RawFd, iovec: &[Iovec], offset: usize) -> i64 { let mut ret; loop { - // SAFETY: fd and buf is valid. - ret = unsafe { - preadv( - fd as c_int, - iovec.as_ptr() as *const iovec, - iovec.len() as c_int, - offset as off_t, - ) as i64 - }; + ret = preadv( + fd as c_int, + iovec.as_ptr() as *const iovec, + iovec.len() as c_int, + offset as off_t, + ) as i64; if !(ret < 0 && (nix::errno::errno() == libc::EINTR || nix::errno::errno() == libc::EAGAIN)) { break; @@ -76,18 +76,18 @@ pub fn raw_readv(fd: RawFd, iovec: &[Iovec], offset: usize) -> i64 { ret } -pub fn raw_write(fd: RawFd, buf: u64, size: usize, offset: usize) -> i64 { +/// # Safety +/// +/// Caller should has valid buf. +pub unsafe fn raw_write(fd: RawFd, buf: u64, size: usize, offset: usize) -> i64 { let mut ret; loop { - // SAFETY: fd and buf is valid. - ret = unsafe { - pwrite( - fd as c_int, - buf as *mut c_void, - size as size_t, - offset as off_t, - ) as i64 - }; + ret = pwrite( + fd as c_int, + buf as *mut c_void, + size as size_t, + offset as off_t, + ) as i64; if !(ret < 0 && (nix::errno::errno() == libc::EINTR || nix::errno::errno() == libc::EAGAIN)) { break; @@ -106,18 +106,19 @@ pub fn raw_write(fd: RawFd, buf: u64, size: usize, offset: usize) -> i64 { ret } -pub fn raw_writev(fd: RawFd, iovec: &[Iovec], offset: usize) -> i64 { +/// # Safety +/// +/// Caller should has valid iovec. +pub unsafe fn raw_writev(fd: RawFd, iovec: &[Iovec], offset: usize) -> i64 { let mut ret; loop { - // SAFETY: fd and buf is valid. - ret = unsafe { - pwritev( - fd as c_int, - iovec.as_ptr() as *const iovec, - iovec.len() as c_int, - offset as off_t, - ) as i64 - }; + // Caller should has valid iovec. + ret = pwritev( + fd as c_int, + iovec.as_ptr() as *const iovec, + iovec.len() as c_int, + offset as off_t, + ) as i64; if !(ret < 0 && (nix::errno::errno() == libc::EINTR || nix::errno::errno() == libc::EAGAIN)) { break; diff --git a/util/src/file.rs b/util/src/file.rs index bacce3db..c1efa02b 100644 --- a/util/src/file.rs +++ b/util/src/file.rs @@ -76,6 +76,10 @@ pub fn get_file_alignment(file: &File, direct: bool) -> (u32, u32) { (MAX_FILE_ALIGN * 2) as libc::size_t, ) }; + if aligned_buffer.is_null() { + log::warn!("OOM occurs when get file alignment, assume max alignment"); + return (MAX_FILE_ALIGN, MAX_FILE_ALIGN); + } // Guess alignment requirement of request. let mut align = MIN_FILE_ALIGN; diff --git a/util/src/lib.rs b/util/src/lib.rs index a33cab3c..60fa43d2 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -34,7 +34,6 @@ pub mod ohos_binding; pub mod pixman; pub mod seccomp; pub mod socket; -pub mod syscall; pub mod tap; pub mod test_helper; pub mod thread_pool; diff --git a/util/src/loop_context.rs b/util/src/loop_context.rs index 5bf07652..8e956982 100644 --- a/util/src/loop_context.rs +++ b/util/src/loop_context.rs @@ -726,17 +726,11 @@ impl EventLoopContext { pub fn read_fd(fd: RawFd) -> u64 { let mut value: u64 = 0; - // SAFETY: this is called by notifier handler and notifier handler - // is executed with fd is is valid. The value is defined above thus - // valid too. - let ret = unsafe { - read( - fd, - &mut value as *mut u64 as *mut c_void, - std::mem::size_of::(), - ) - }; + let buf = &mut value as *mut u64 as *mut c_void; + let count = std::mem::size_of::(); + // SAFETY: The buf refers to local value and count equals to value size. + let ret = unsafe { read(fd, buf, count) }; if ret == -1 { warn!("Failed to read fd"); } diff --git a/util/src/offsetof.rs b/util/src/offsetof.rs index 2cc01699..055b24e2 100644 --- a/util/src/offsetof.rs +++ b/util/src/offsetof.rs @@ -10,6 +10,8 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. +// Note: This can be replaced with std::mem::offset_of! within higher rust version. + /// Macro: Calculate offset of specified field in a type. #[macro_export] macro_rules! __offset_of { diff --git a/util/src/pixman.rs b/util/src/pixman.rs index 4ec4d074..2cd2e27b 100644 --- a/util/src/pixman.rs +++ b/util/src/pixman.rs @@ -184,16 +184,18 @@ pub enum pixman_op_t { PIXMAN_OP_HSL_LUMINOSITY = 62, } -pub type pixman_image_destroy_func_t = ::std::option::Option< - unsafe extern "C" fn(image: *mut pixman_image_t, data: *mut libc::c_void), ->; +pub type pixman_image_destroy_func_t = + Option; -pub extern "C" fn virtio_gpu_unref_resource_callback( +/// # Safety +/// +/// Caller should has valid image and data. +pub unsafe extern "C" fn virtio_gpu_unref_resource_callback( _image: *mut pixman_image_t, data: *mut libc::c_void, ) { - // SAFETY: The safety of this function is guaranteed by caller. - unsafe { pixman_image_unref(data.cast()) }; + // The safety of this function is guaranteed by caller. + pixman_image_unref(data.cast()); } fn pixman_format_reshift(val: u32, ofs: u32, num: u32) -> u32 { diff --git a/util/src/syscall.rs b/util/src/syscall.rs deleted file mode 100644 index f6088a72..00000000 --- a/util/src/syscall.rs +++ /dev/null @@ -1,57 +0,0 @@ -// Copyright (c) 2022 Huawei Technologies Co.,Ltd. All rights reserved. -// -// StratoVirt is licensed under Mulan PSL v2. -// You can use this software according to the terms and conditions of the Mulan -// PSL v2. -// You may obtain a copy of Mulan PSL v2 at: -// http://license.coscl.org.cn/MulanPSL2 -// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY -// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO -// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. -// See the Mulan PSL v2 for more details. - -use anyhow::{bail, Result}; -use libc::{c_void, syscall, SYS_mbind}; - -/// This function set memory policy for host NUMA node memory range. -/// -/// * Arguments -/// -/// * `addr` - The memory range starting with addr. -/// * `len` - Length of the memory range. -/// * `mode` - Memory policy mode. -/// * `node_mask` - node_mask specifies physical node ID. -/// * `max_node` - The max node. -/// * `flags` - Mode flags. -pub fn mbind( - addr: u64, - len: u64, - mode: u32, - node_mask: Vec, - max_node: u64, - flags: u32, -) -> Result<()> { - // SAFETY: - // 1. addr is managed by memory mapping, it can be guaranteed legal. - // 2. node_mask was created in function of set_host_memory_policy. - // 3. Upper limit of max_node is MAX_NODES. - let res = unsafe { - syscall( - SYS_mbind, - addr as *mut c_void, - len, - mode, - node_mask.as_ptr(), - max_node + 1, - flags, - ) - }; - if res < 0 { - bail!( - "Failed to apply host numa node policy, error is {}", - std::io::Error::last_os_error() - ); - } - - Ok(()) -} diff --git a/util/src/unix.rs b/util/src/unix.rs index 54a27462..2fcebce4 100644 --- a/util/src/unix.rs +++ b/util/src/unix.rs @@ -19,8 +19,8 @@ use std::ptr::{copy_nonoverlapping, null_mut, write_unaligned}; use anyhow::{anyhow, bail, Context, Result}; use libc::{ - c_void, cmsghdr, iovec, msghdr, recvmsg, sendmsg, CMSG_LEN, CMSG_SPACE, MSG_NOSIGNAL, - MSG_WAITALL, SCM_RIGHTS, SOL_SOCKET, + c_void, cmsghdr, iovec, msghdr, recvmsg, sendmsg, syscall, SYS_mbind, CMSG_LEN, CMSG_SPACE, + MSG_NOSIGNAL, MSG_WAITALL, SCM_RIGHTS, SOL_SOCKET, }; use log::error; use nix::unistd::{sysconf, SysconfVar}; @@ -142,6 +142,47 @@ unsafe fn set_memory_undumpable(host_addr: *mut libc::c_void, size: u64) { } } +/// This function set memory policy for host NUMA node memory range. +/// +/// * Arguments +/// +/// * `addr` - The memory range starting with addr. +/// * `len` - Length of the memory range. +/// * `mode` - Memory policy mode. +/// * `node_mask` - node_mask specifies physical node ID. +/// * `max_node` - The max node. +/// * `flags` - Mode flags. +/// +/// # Safety +/// +/// Caller should has valid params. +pub unsafe fn mbind( + addr: u64, + len: u64, + mode: u32, + node_mask: Vec, + max_node: u64, + flags: u32, +) -> Result<()> { + let res = syscall( + SYS_mbind, + addr as *mut c_void, + len, + mode, + node_mask.as_ptr(), + max_node + 1, + flags, + ); + if res < 0 { + bail!( + "Failed to apply host numa node policy, error is {}", + std::io::Error::last_os_error() + ); + } + + Ok(()) +} + /// Unix socket is a data communication endpoint for exchanging data /// between processes executing on the same host OS. pub struct UnixSock { diff --git a/virtio/src/device/block.rs b/virtio/src/device/block.rs index ddc28fc9..e6efd9de 100644 --- a/virtio/src/device/block.rs +++ b/virtio/src/device/block.rs @@ -422,7 +422,8 @@ impl Request { VIRTIO_BLK_T_GET_ID => { let serial = serial_num.clone().unwrap_or_else(|| String::from("")); let serial_vec = get_serial_num_config(&serial); - let status = iov_from_buf_direct(&self.iovec, &serial_vec).map_or_else( + // SAFETY: iovec is generated by address_space. + let status = unsafe { iov_from_buf_direct(&self.iovec, &serial_vec) }.map_or_else( |e| { error!( "Failed to process block {} request for getting id, {:?}", @@ -475,7 +476,8 @@ impl Request { // Get and check the discard segment. let mut segment = DiscardWriteZeroesSeg::default(); - iov_to_buf_direct(&self.iovec, 0, segment.as_mut_bytes()).and_then(|v| { + // SAFETY: iovec is generated by address_space. + unsafe { iov_to_buf_direct(&self.iovec, 0, segment.as_mut_bytes()) }.and_then(|v| { if v as u64 == size { Ok(()) } else { diff --git a/virtio/src/device/gpu.rs b/virtio/src/device/gpu.rs index 1f8fa7a3..717a05e5 100644 --- a/virtio/src/device/gpu.rs +++ b/virtio/src/device/gpu.rs @@ -714,7 +714,8 @@ impl GpuIoHandler { } fn get_request(&mut self, header: &VirtioGpuRequest, req: &mut T) -> Result<()> { - iov_to_buf_direct(&header.out_iovec, 0, req.as_mut_bytes()).and_then(|size| { + // SAFETY: out_iovec is generated by address_space. + unsafe { iov_to_buf_direct(&header.out_iovec, 0, req.as_mut_bytes()) }.and_then(|size| { if size == size_of::() { Ok(()) } else { @@ -760,7 +761,8 @@ impl GpuIoHandler { header.ctx_id = req.header.ctx_id; } - let len = iov_from_buf_direct(&req.in_iovec, resp.as_bytes())?; + // SAFETY: in_iovec is generated by address_space. + let len = unsafe { iov_from_buf_direct(&req.in_iovec, resp.as_bytes())? }; if len != size_of::() { error!( "GuestError: An incomplete response will be used instead of the expected: expected \ @@ -1364,7 +1366,8 @@ impl GpuIoHandler { let data = get_image_data(res.pixman_image).cast() as *mut u8; if res.format == VIRTIO_GPU_FORMAT_MONOCHROME { - let v = iov_to_buf_direct(&res.iov, 0, &mut res.monochrome_cursor)?; + // SAFETY: iov is generated by address_space. + let v = unsafe { iov_to_buf_direct(&res.iov, 0, &mut res.monochrome_cursor)? }; if v != res.monochrome_cursor.len() { error!("No enough data is copied for transfer_to_host_2d with monochrome"); } @@ -1377,7 +1380,8 @@ impl GpuIoHandler { let trans_size = (trans_info.rect.height * stride) as usize; // SAFETY: offset_dst and trans_size do not exceeds data size. let dst = unsafe { from_raw_parts_mut(data.add(offset_dst), trans_size) }; - iov_to_buf_direct(&res.iov, trans_info.offset, dst).map(|v| { + // SAFETY: iov is generated by address_space. + unsafe { iov_to_buf_direct(&res.iov, trans_info.offset, dst) }.map(|v| { if v < trans_size { warn!("No enough data is copied for transfer_to_host_2d"); } @@ -1394,7 +1398,8 @@ impl GpuIoHandler { for _ in 0..trans_info.rect.height { // SAFETY: offset_dst and line_size do not exceeds data size. let dst = unsafe { from_raw_parts_mut(data.add(offset_dst), line_size) }; - iov_to_buf_direct(&res.iov, offset_src as u64, dst).map(|v| { + // SAFETY: iov is generated by address_space. + unsafe { iov_to_buf_direct(&res.iov, offset_src as u64, dst) }.map(|v| { if v < line_size { warn!("No enough data is copied for transfer_to_host_2d"); } @@ -1469,7 +1474,8 @@ impl GpuIoHandler { let ents_buf = // SAFETY: ents is guaranteed not be null and the range of ents_size has been limited. unsafe { from_raw_parts_mut(ents.as_mut_ptr() as *mut u8, ents_size as usize) }; - let v = iov_to_buf_direct(&req.out_iovec, head_size, ents_buf)?; + // SAFETY: out_iovec is generated by address_space. + let v = unsafe { iov_to_buf_direct(&req.out_iovec, head_size, ents_buf)? }; if v as u64 != ents_size { error!( "Virtio-GPU: Load no enough ents buf when attach backing, {} vs {}", diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index fe7632dc..e2833d93 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -947,7 +947,10 @@ fn get_net_header(iovec: &[Iovec], buf: &mut [u8]) -> Result { .checked_add(elem.iov_len as usize) .with_context(|| "Overflow when getting the net header")?; end = cmp::min(end, buf.len()); - mem_to_buf(&mut buf[start..end], elem.iov_base)?; + // SAFETY: iovec is generated by address_space and len is not less than buf's. + unsafe { + mem_to_buf(&mut buf[start..end], elem.iov_base)?; + } if end >= buf.len() { break; } diff --git a/virtio/src/device/rng.rs b/virtio/src/device/rng.rs index e7db31b2..2040e856 100644 --- a/virtio/src/device/rng.rs +++ b/virtio/src/device/rng.rs @@ -174,12 +174,15 @@ impl RngHandler { } let mut buffer = vec![0_u8; size as usize]; - let ret = raw_read( - self.random_file.as_raw_fd(), - buffer.as_mut_ptr() as u64, - size as usize, - 0, - ); + // SAFETY: buffer is valid and large enough. + let ret = unsafe { + raw_read( + self.random_file.as_raw_fd(), + buffer.as_mut_ptr() as u64, + size as usize, + 0, + ) + }; if ret < 0 { bail!("Failed to read random file, size: {}", size); } diff --git a/virtio/src/device/serial.rs b/virtio/src/device/serial.rs index ac093df8..4047bcb3 100644 --- a/virtio/src/device/serial.rs +++ b/virtio/src/device/serial.rs @@ -908,7 +908,8 @@ impl SerialControlHandler { msg_data.extend(extra); } - iov_from_buf_direct(&ctrl_vec, &msg_data).and_then(|size| { + // SAFETY: ctrl_vec is generated by address_space. + unsafe { iov_from_buf_direct(&ctrl_vec, &msg_data) }.and_then(|size| { if size != len { bail!( "Expected send msg length is {}, actual send length {}.", diff --git a/virtio/src/lib.rs b/virtio/src/lib.rs index 6d4e8805..0c8e7673 100644 --- a/virtio/src/lib.rs +++ b/virtio/src/lib.rs @@ -826,7 +826,10 @@ pub fn iov_to_buf( mem_space.get_address_map(cache, iov.addr, u64::from(iov.len), &mut addr_map)?; for addr in addr_map.into_iter() { end = cmp::min(start + addr.iov_len as usize, buf.len()); - mem_to_buf(&mut buf[start..end], addr.iov_base)?; + // SAFETY: addr_map is generated by address_space and len is not less than buf's. + unsafe { + mem_to_buf(&mut buf[start..end], addr.iov_base)?; + } if end >= buf.len() { return Ok(end); } -- Gitee From acae50d49c8eb17556f91afd362e219aafaf2c12 Mon Sep 17 00:00:00 2001 From: zhanghan Date: Thu, 5 Sep 2024 11:57:00 +0800 Subject: [PATCH 322/489] ohaudio: support query host max&min volume value We used a middle-value for conversion between host and VM's volume. This way may introduce errors on conversions. Now we accquire host's volume value range, so we can do conversions directly. Fewer errors are introduced. --- devices/src/misc/scream/ohaudio.rs | 34 ++++++++++++++++++--- util/src/ohos_binding/audio/mod.rs | 18 +++++++++++ util/src/ohos_binding/hwf_adapter/volume.rs | 6 ++++ 3 files changed, 53 insertions(+), 5 deletions(-) diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index d746eecf..752e4d29 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -30,6 +30,7 @@ use util::ohos_binding::audio::*; const STREAM_DATA_VEC_CAPACITY: usize = 15; const FLUSH_DELAY_MS: u64 = 5; const FLUSH_DELAY_CNT: u64 = 200; +const SCREAM_MAX_VOLUME: u32 = 110; trait OhAudioProcess { fn init(&mut self, stream: &StreamData) -> bool; @@ -532,16 +533,18 @@ impl AudioInterface for OhAudio { pub struct OhAudioVolume { shm_dev: Arc>, ohos_vol: RwLock, + ohos_vol_max: u32, + ohos_vol_min: u32, } -// SAFETY: all fields are protected by lock +// SAFETY: all unsafe fields are protected by lock unsafe impl Send for OhAudioVolume {} -// SAFETY: all fields are protected by lock +// SAFETY: all unsafe fields are protected by lock unsafe impl Sync for OhAudioVolume {} impl GuestVolumeNotifier for OhAudioVolume { fn notify(&self, vol: u32) { - *self.ohos_vol.write().unwrap() = vol; + *self.ohos_vol.write().unwrap() = self.to_guest_vol(vol); self.shm_dev .lock() .unwrap() @@ -555,7 +558,7 @@ impl AudioExtension for OhAudioVolume { } fn set_host_volume(&self, vol: u32) { - set_ohos_volume(vol); + set_ohos_volume(self.to_host_vol(vol)); } } @@ -563,11 +566,32 @@ impl OhAudioVolume { pub fn new(shm_dev: Arc>) -> Arc { let vol = Arc::new(Self { shm_dev, - ohos_vol: RwLock::new(get_ohos_volume()), + ohos_vol: RwLock::new(0), + ohos_vol_max: get_ohos_volume_max(), + ohos_vol_min: get_ohos_volume_min(), }); + *vol.ohos_vol.write().unwrap() = vol.to_guest_vol(get_ohos_volume()); register_guest_volume_notifier(vol.clone()); vol } + + fn to_guest_vol(&self, h_vol: u32) -> u32 { + if self.ohos_vol_max > self.ohos_vol_min { + return SCREAM_MAX_VOLUME * h_vol / (self.ohos_vol_max - self.ohos_vol_min); + } + 0 + } + + fn to_host_vol(&self, v_vol: u32) -> u32 { + if v_vol == 0 || self.ohos_vol_max <= self.ohos_vol_min { + return 0; + } + let res = (self.ohos_vol_max - self.ohos_vol_min) * v_vol / SCREAM_MAX_VOLUME + 1; + if res > self.ohos_vol_max { + return self.ohos_vol_max; + } + res + } } #[cfg(test)] diff --git a/util/src/ohos_binding/audio/mod.rs b/util/src/ohos_binding/audio/mod.rs index 1a1b600a..61364719 100755 --- a/util/src/ohos_binding/audio/mod.rs +++ b/util/src/ohos_binding/audio/mod.rs @@ -397,6 +397,16 @@ impl OhVolume { unsafe { (self.capi.get_volume)() as u32 } } + fn get_max_volume(&self) -> u32 { + // SAFETY: We call related API sequentially for specified ctx. + unsafe { (self.capi.get_max_volume)() as u32 } + } + + fn get_min_volume(&self) -> u32 { + // SAFETY: We call related API sequentially for specified ctx. + unsafe { (self.capi.get_min_volume)() as u32 } + } + fn set_ohos_volume(&self, volume: i32) { // SAFETY: We call related API sequentially for specified ctx. unsafe { (self.capi.set_volume)(volume) }; @@ -428,6 +438,14 @@ pub fn register_guest_volume_notifier(notifier: Arc) { .register_guest_notifier(notifier); } +pub fn get_ohos_volume_max() -> u32 { + OH_VOLUME_ADAPTER.read().unwrap().get_max_volume() +} + +pub fn get_ohos_volume_min() -> u32 { + OH_VOLUME_ADAPTER.read().unwrap().get_min_volume() +} + pub fn get_ohos_volume() -> u32 { OH_VOLUME_ADAPTER.read().unwrap().get_ohos_volume() } diff --git a/util/src/ohos_binding/hwf_adapter/volume.rs b/util/src/ohos_binding/hwf_adapter/volume.rs index 3de5e34b..b730e143 100644 --- a/util/src/ohos_binding/hwf_adapter/volume.rs +++ b/util/src/ohos_binding/hwf_adapter/volume.rs @@ -21,11 +21,15 @@ use crate::get_libfn; pub type VolumeChangedCallBack = unsafe extern "C" fn(c_int); type OhSysAudioGetVolumeFn = unsafe extern "C" fn() -> c_int; +type OhSysAudioGetMaxVolumeFn = unsafe extern "C" fn() -> c_int; +type OhSysAudioGetMinVolumeFn = unsafe extern "C" fn() -> c_int; type OhSysAudioSetVolumeFn = unsafe extern "C" fn(c_int); type OhSysAudioRegisterVolumeChangeFn = unsafe extern "C" fn(VolumeChangedCallBack) -> c_int; pub struct VolumeFuncTable { pub get_volume: RawSymbol, + pub get_max_volume: RawSymbol, + pub get_min_volume: RawSymbol, pub set_volume: RawSymbol, pub register_volume_change: RawSymbol, } @@ -34,6 +38,8 @@ impl VolumeFuncTable { pub unsafe fn new(library: &Library) -> Result { Ok(Self { get_volume: get_libfn!(library, OhSysAudioGetVolumeFn, OhSysAudioGetVolume), + get_max_volume: get_libfn!(library, OhSysAudioGetMaxVolumeFn, OhSysAudioGetMaxVolume), + get_min_volume: get_libfn!(library, OhSysAudioGetMinVolumeFn, OhSysAudioGetMinVolume), set_volume: get_libfn!(library, OhSysAudioSetVolumeFn, OhSysAudioSetVolume), register_volume_change: get_libfn!( library, -- Gitee From 49a89282745761a3b70f54b26b9cb7092e4b0915 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 12 Sep 2024 18:28:10 +0800 Subject: [PATCH 323/489] address_space: don't return cache if AddressAttr is not the desired type Don't return cache if AddressAttr is not the required type. Otherwise, this wrong cache starting at 0 will cause subsequent address mapping errors. Fix: d46f7e5db43f1(address_space: add attribute for GuestAddress access) Signed-off-by: liuxiangdong --- address_space/src/address_space.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/address_space/src/address_space.rs b/address_space/src/address_space.rs index 88dd6d92..36106e95 100644 --- a/address_space/src/address_space.rs +++ b/address_space/src/address_space.rs @@ -634,10 +634,7 @@ impl AddressSpace { let start = range.addr_range.base.0; let end = range.addr_range.end_addr().0; // SAFETY: the size is in region range, and the type will be checked in get_host_address. - let host_base = unsafe { - self.get_host_address(GuestAddress(start), attr) - .unwrap_or(0) - }; + let host_base = unsafe { self.get_host_address(GuestAddress(start), attr) }?; let cache = RegionCache { reg_type, host_base, -- Gitee From 3dc2ea6bd1e619c27799bebc8cae9bf563a0a392 Mon Sep 17 00:00:00 2001 From: zhanghan64 Date: Mon, 9 Sep 2024 15:24:43 +0800 Subject: [PATCH 324/489] scream: fix mst usecase fix mst usecase introduced by front-end pause bit Signed-off-by: zhanghan64 --- devices/src/misc/scream/mod.rs | 6 +++--- tests/mod_test/src/libdriver/ivshmem.rs | 27 +++++++++++++++---------- tests/mod_test/tests/scream_test.rs | 11 +++++++++- 3 files changed, 29 insertions(+), 15 deletions(-) diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index a6c8ca8b..c3d25a1b 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -58,10 +58,10 @@ const IVSHMEM_VOLUME_SYNC_VECTOR: u16 = 0; const IVSHMEM_STATUS_CHANGE_VECTOR: u16 = 1; const IVSHMEM_VECTORS_NR: u32 = 2; const IVSHMEM_BAR0_VOLUME: u64 = 240; -const IVSHMEM_BAR0_STATUS: u64 = 244; +pub const IVSHMEM_BAR0_STATUS: u64 = 244; -const STATUS_PLAY_BIT: u32 = 0x1; -const STATUS_START_BIT: u32 = 0x2; +pub const STATUS_PLAY_BIT: u32 = 0x1; +pub const STATUS_START_BIT: u32 = 0x2; const STATUS_MIC_AVAIL_BIT: u32 = 0x4; // A frame of back-end audio data is 50ms, and the next frame of audio data needs diff --git a/tests/mod_test/src/libdriver/ivshmem.rs b/tests/mod_test/src/libdriver/ivshmem.rs index 03d76629..aa456e0b 100644 --- a/tests/mod_test/src/libdriver/ivshmem.rs +++ b/tests/mod_test/src/libdriver/ivshmem.rs @@ -19,16 +19,16 @@ use super::{ pub struct TestIvshmemDev { pub pci_dev: TestPciDev, - pub bar_addr: PCIBarAddr, - bar_idx: u8, + bar0_addr: PCIBarAddr, + pub bar2_addr: PCIBarAddr, } impl TestIvshmemDev { pub fn new(pci_bus: Rc>) -> Self { Self { pci_dev: TestPciDev::new(pci_bus), - bar_addr: 0, - bar_idx: 2, + bar0_addr: 0, + bar2_addr: 0, } } @@ -37,30 +37,35 @@ impl TestIvshmemDev { assert!(self.pci_dev.find_pci_device(devfn)); self.pci_dev.enable(); - self.bar_addr = self.pci_dev.io_map(self.bar_idx); + self.bar0_addr = self.pci_dev.io_map(0); + self.bar2_addr = self.pci_dev.io_map(2); } pub fn writeb(&mut self, offset: u64, value: u8) { - self.pci_dev.io_writeb(self.bar_addr, offset, value); + self.pci_dev.io_writeb(self.bar2_addr, offset, value); } pub fn writew(&mut self, offset: u64, value: u16) { - self.pci_dev.io_writew(self.bar_addr, offset, value); + self.pci_dev.io_writew(self.bar2_addr, offset, value); } pub fn writel(&mut self, offset: u64, value: u32) { - self.pci_dev.io_writel(self.bar_addr, offset, value); + self.pci_dev.io_writel(self.bar2_addr, offset, value); } pub fn writeq(&mut self, offset: u64, value: u64) { - self.pci_dev.io_writeq(self.bar_addr, offset, value); + self.pci_dev.io_writeq(self.bar2_addr, offset, value); } pub fn readw(&self, offset: u64) -> u16 { - self.pci_dev.io_readw(self.bar_addr, offset) + self.pci_dev.io_readw(self.bar2_addr, offset) } pub fn readl(&self, offset: u64) -> u32 { - self.pci_dev.io_readl(self.bar_addr, offset) + self.pci_dev.io_readl(self.bar2_addr, offset) + } + + pub fn writel_reg(&self, offset: u64, value: u32) { + self.pci_dev.io_writel(self.bar0_addr, offset, value); } } diff --git a/tests/mod_test/tests/scream_test.rs b/tests/mod_test/tests/scream_test.rs index ad2c9e68..59cd2838 100644 --- a/tests/mod_test/tests/scream_test.rs +++ b/tests/mod_test/tests/scream_test.rs @@ -22,7 +22,10 @@ use std::{ use core::time; -use devices::misc::scream::{ShmemHeader, ShmemStreamFmt, ShmemStreamHeader, SCREAM_MAGIC}; +use devices::misc::scream::{ + ShmemHeader, ShmemStreamFmt, ShmemStreamHeader, IVSHMEM_BAR0_STATUS, SCREAM_MAGIC, + STATUS_PLAY_BIT, STATUS_START_BIT, +}; use mod_test::{ libdriver::{ivshmem::TestIvshmemDev, machine::TestStdMachine}, libtest::{test_init, TestState, MACHINE_TYPE_ARG}, @@ -235,6 +238,9 @@ fn scream_playback_basic_test() { thread::sleep(time::Duration::from_millis(1000)); play_header_init(&mut ivshmem.borrow_mut()); + ivshmem + .borrow_mut + .writel_reg(IVSHMEM_BAR0_STATUS, STATUS_PLAY_BIT | STATUS_START_BIT); thread::sleep(time::Duration::from_millis(POLL_DELAY_MS)); @@ -342,6 +348,9 @@ fn scream_record_basic_test() { ivshmem.borrow_mut().init(pci_slot); record_header_init(&mut ivshmem.borrow_mut()); + ivshmem + .borrow_mut + .writel_reg(IVSHMEM_BAR0_STATUS, STATUS_START_BIT); let mut cnt = 0; let mut chunk_idx = 0; -- Gitee From 814017694fb975ed7e49b52eaff13e71a018a659 Mon Sep 17 00:00:00 2001 From: zhanghan64 Date: Mon, 9 Sep 2024 17:46:58 +0800 Subject: [PATCH 325/489] scream: add volume sync mst use case Signed-off-by: zhanghan64 --- devices/src/misc/scream/audio_demo.rs | 46 ++++++++++++++++++++++++- devices/src/misc/scream/mod.rs | 8 +++-- tests/mod_test/src/libdriver/ivshmem.rs | 7 ++++ tests/mod_test/tests/scream_test.rs | 40 ++++++++++++++++++--- 4 files changed, 93 insertions(+), 8 deletions(-) diff --git a/devices/src/misc/scream/audio_demo.rs b/devices/src/misc/scream/audio_demo.rs index 3576c43f..c709c216 100644 --- a/devices/src/misc/scream/audio_demo.rs +++ b/devices/src/misc/scream/audio_demo.rs @@ -10,6 +10,7 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. +use std::sync::{Arc, Mutex, RwLock}; use std::{ fs::{File, OpenOptions}, io::{Read, Write}, @@ -19,7 +20,50 @@ use std::{ use core::time; use log::error; -use super::{AudioInterface, AudioStatus, ScreamDirection, StreamData}; +use super::{AudioExtension, AudioInterface, AudioStatus, ScreamDirection, StreamData}; +use crate::misc::ivshmem::Ivshmem; + +pub const INITIAL_VOLUME_VAL: u32 = 0xaa; +const IVSHMEM_VOLUME_SYNC_VECTOR: u16 = 0; + +pub struct DemoAudioVolume { + shm_dev: Arc>, + vol: RwLock, +} + +// SAFETY: all fields are protected by lock +unsafe impl Send for DemoAudioVolume {} +// SAFETY: all fields are protected by lock +unsafe impl Sync for DemoAudioVolume {} + +impl AudioExtension for DemoAudioVolume { + fn get_host_volume(&self) -> u32 { + *self.vol.read().unwrap() + } + + fn set_host_volume(&self, vol: u32) { + *self.vol.write().unwrap() = vol; + } +} + +impl DemoAudioVolume { + pub fn new(shm_dev: Arc>) -> Arc { + let vol = Arc::new(Self { + shm_dev, + vol: RwLock::new(0), + }); + vol.notify(INITIAL_VOLUME_VAL); + vol + } + + fn notify(&self, vol: u32) { + *self.vol.write().unwrap() = vol; + self.shm_dev + .lock() + .unwrap() + .trigger_msix(IVSHMEM_VOLUME_SYNC_VECTOR); + } +} pub struct AudioDemo { file: File, diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index c3d25a1b..806f00bf 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -12,7 +12,7 @@ #[cfg(feature = "scream_alsa")] mod alsa; -mod audio_demo; +pub mod audio_demo; #[cfg(all(target_env = "ohos", feature = "scream_ohaudio"))] mod ohaudio; #[cfg(feature = "scream_pulseaudio")] @@ -31,7 +31,7 @@ use once_cell::sync::Lazy; #[cfg(feature = "scream_alsa")] use self::alsa::AlsaStreamData; -use self::audio_demo::AudioDemo; +use self::audio_demo::{AudioDemo, DemoAudioVolume}; use super::ivshmem::Ivshmem; use crate::pci::{le_read_u32, le_write_u32}; use crate::{Bus, Device}; @@ -57,7 +57,7 @@ pub const TARGET_LATENCY_MS: u32 = 50; const IVSHMEM_VOLUME_SYNC_VECTOR: u16 = 0; const IVSHMEM_STATUS_CHANGE_VECTOR: u16 = 1; const IVSHMEM_VECTORS_NR: u32 = 2; -const IVSHMEM_BAR0_VOLUME: u64 = 240; +pub const IVSHMEM_BAR0_VOLUME: u64 = 240; pub const IVSHMEM_BAR0_STATUS: u64 = 244; pub const STATUS_PLAY_BIT: u32 = 0x1; @@ -752,6 +752,8 @@ impl Scream { match self.config.interface { #[cfg(all(target_env = "ohos", feature = "scream_ohaudio"))] ScreamInterface::OhAudio => OhAudioVolume::new(_ivshmem), + ScreamInterface::Demo => DemoAudioVolume::new(_ivshmem), + #[allow(unreachable_patterns)] _ => Arc::new(AudioExtensionDummy {}), } } diff --git a/tests/mod_test/src/libdriver/ivshmem.rs b/tests/mod_test/src/libdriver/ivshmem.rs index aa456e0b..edb5ef62 100644 --- a/tests/mod_test/src/libdriver/ivshmem.rs +++ b/tests/mod_test/src/libdriver/ivshmem.rs @@ -20,6 +20,7 @@ use super::{ pub struct TestIvshmemDev { pub pci_dev: TestPciDev, bar0_addr: PCIBarAddr, + bar1_addr: PCIBarAddr, pub bar2_addr: PCIBarAddr, } @@ -28,6 +29,7 @@ impl TestIvshmemDev { Self { pci_dev: TestPciDev::new(pci_bus), bar0_addr: 0, + bar1_addr: 0, bar2_addr: 0, } } @@ -38,6 +40,7 @@ impl TestIvshmemDev { self.pci_dev.enable(); self.bar0_addr = self.pci_dev.io_map(0); + self.bar1_addr = self.pci_dev.io_map(1); self.bar2_addr = self.pci_dev.io_map(2); } @@ -68,4 +71,8 @@ impl TestIvshmemDev { pub fn writel_reg(&self, offset: u64, value: u32) { self.pci_dev.io_writel(self.bar0_addr, offset, value); } + + pub fn readl_reg(&self, offset: u64) -> u32 { + self.pci_dev.io_readl(self.bar0_addr, offset) + } } diff --git a/tests/mod_test/tests/scream_test.rs b/tests/mod_test/tests/scream_test.rs index 59cd2838..d7669fe0 100644 --- a/tests/mod_test/tests/scream_test.rs +++ b/tests/mod_test/tests/scream_test.rs @@ -23,8 +23,8 @@ use std::{ use core::time; use devices::misc::scream::{ - ShmemHeader, ShmemStreamFmt, ShmemStreamHeader, IVSHMEM_BAR0_STATUS, SCREAM_MAGIC, - STATUS_PLAY_BIT, STATUS_START_BIT, + audio_demo::INITIAL_VOLUME_VAL, ShmemHeader, ShmemStreamFmt, ShmemStreamHeader, + IVSHMEM_BAR0_STATUS, IVSHMEM_BAR0_VOLUME, SCREAM_MAGIC, STATUS_PLAY_BIT, STATUS_START_BIT, }; use mod_test::{ libdriver::{ivshmem::TestIvshmemDev, machine::TestStdMachine}, @@ -239,7 +239,7 @@ fn scream_playback_basic_test() { play_header_init(&mut ivshmem.borrow_mut()); ivshmem - .borrow_mut + .borrow_mut() .writel_reg(IVSHMEM_BAR0_STATUS, STATUS_PLAY_BIT | STATUS_START_BIT); thread::sleep(time::Duration::from_millis(POLL_DELAY_MS)); @@ -326,6 +326,38 @@ fn scream_playback_basic_test() { scream_tmp_clear(playback_path, record_path); } +/// scream device volume synchronization. +/// TestStep: +/// 1. Init scream device. +/// 2. Check volume's initial value. +/// 3. Set volume and read back to check. +/// 4. Stop VM. +/// Expect: +/// 1/2/3/4: success. +#[test] +fn scream_volume_sync_test() { + let pci_slot = 0x1; + let (playback_path, record_path) = get_audio_file_name(); + audio_data_init(playback_path.clone(), record_path.clone()); + let (ivshmem, test_state) = set_up( + IVSHMEM_DEFAULT_SIZE, + pci_slot, + playback_path.clone(), + record_path.clone(), + ); + ivshmem.borrow_mut().init(pci_slot); + + let init_val = ivshmem.borrow_mut().readl_reg(IVSHMEM_BAR0_VOLUME); + assert_eq!(init_val, INITIAL_VOLUME_VAL); + + ivshmem.borrow_mut().writel_reg(IVSHMEM_BAR0_VOLUME, 0xff); + let second_val = ivshmem.borrow_mut().readl_reg(IVSHMEM_BAR0_VOLUME); + assert_eq!(second_val, 0xff); + + test_state.borrow_mut().stop(); + scream_tmp_clear(playback_path, record_path); +} + /// scream device record audio. /// TestStep: /// 1. Init scream device and start recording. @@ -349,7 +381,7 @@ fn scream_record_basic_test() { record_header_init(&mut ivshmem.borrow_mut()); ivshmem - .borrow_mut + .borrow_mut() .writel_reg(IVSHMEM_BAR0_STATUS, STATUS_START_BIT); let mut cnt = 0; -- Gitee From 41e1d486d6f31951c200d3f93a6c45a8005f8c05 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Fri, 13 Sep 2024 07:00:38 +0800 Subject: [PATCH 326/489] pflash: delete useless region type check Region type of `rom` in `pflash` is set in `realize` function as `RegionType::RomDevice`. It will not be modified later. Remove these useless check. Fix: 44795e4c6ac5(Memory: Add an unsafe flag to the get host address function.) Signed-off-by: liuxiangdong --- devices/src/legacy/pflash.rs | 22 +++------------------- 1 file changed, 3 insertions(+), 19 deletions(-) diff --git a/devices/src/legacy/pflash.rs b/devices/src/legacy/pflash.rs index 6c3138e0..209c9ecd 100644 --- a/devices/src/legacy/pflash.rs +++ b/devices/src/legacy/pflash.rs @@ -337,15 +337,9 @@ impl PFlash { ))); } - let attr = match mr.region_type() { - address_space::RegionType::Ram => AddressAttr::Ram, - address_space::RegionType::RomDevice => AddressAttr::RomDevice, - _ => bail!("Unexpected region type."), - }; - // SAFETY: size has been checked. let addr: u64 = unsafe { - mr.get_host_address(attr) + mr.get_host_address(AddressAttr::RomDevice) .with_context(|| "Failed to get host address.") }?; let ret = @@ -374,13 +368,8 @@ impl PFlash { data.len() as u64 ))); } - let attr = match mr.region_type() { - address_space::RegionType::Ram => AddressAttr::Ram, - address_space::RegionType::RomDevice => AddressAttr::RomDevice, - _ => bail!("Unexpected region type."), - }; // SAFETY: size has been checked. - let host_addr = unsafe { mr.get_host_address(attr).unwrap() }; + let host_addr = unsafe { mr.get_host_address(AddressAttr::RomDevice).unwrap() }; let src = // SAFETY: host_addr of the region is local allocated and sanity has been checked. unsafe { std::slice::from_raw_parts_mut((host_addr + offset) as *mut u8, data.len()) }; @@ -408,13 +397,8 @@ impl PFlash { data.len() as u64 ))); } - let attr = match mr.region_type() { - address_space::RegionType::Ram => AddressAttr::Ram, - address_space::RegionType::RomDevice => AddressAttr::RomDevice, - _ => bail!("Unexpected region type."), - }; // SAFETY: size has been checked. - let host_addr = unsafe { mr.get_host_address(attr).unwrap() }; + let host_addr = unsafe { mr.get_host_address(AddressAttr::RomDevice).unwrap() }; let mut dst = // SAFETY: host_addr of the region is local allocated and sanity has been checked. unsafe { std::slice::from_raw_parts_mut((host_addr + offset) as *mut u8, data.len()) }; -- Gitee From 8977393abc65bc1d184fd6bab9b885509867b21c Mon Sep 17 00:00:00 2001 From: Li Huachao Date: Sat, 14 Sep 2024 16:03:16 +0800 Subject: [PATCH 327/489] AddressSpace: fix mst Mst use mmio_read/write to read/write the ram region. --- address_space/src/address_space.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/address_space/src/address_space.rs b/address_space/src/address_space.rs index 36106e95..263aa314 100644 --- a/address_space/src/address_space.rs +++ b/address_space/src/address_space.rs @@ -66,7 +66,7 @@ impl FlatView { let region_base = fr.addr_range.base.unchecked_sub(fr.offset_in_region); let fr_remain = fr.addr_range.size - fr_offset; - if fr.owner.region_type() != region_type { + if !util::test_helper::is_test_enabled() && fr.owner.region_type() != region_type { // Read op RomDevice in I/O access mode as MMIO if region_type == RegionType::IO && fr.owner.region_type() == RegionType::RomDevice @@ -79,7 +79,9 @@ impl FlatView { } } - if region_type == RegionType::Ram || region_type == RegionType::RamDevice { + if fr.owner.region_type() == RegionType::Ram + || fr.owner.region_type() == RegionType::RamDevice + { l = std::cmp::min(l, fr_remain); } fr.owner.read(dst, region_base, region_offset, l)?; @@ -126,14 +128,17 @@ impl FlatView { let fr_remain = fr.addr_range.size - fr_offset; // Read/Write ops to RomDevice is MMIO. - if fr.owner.region_type() != region_type + if !util::test_helper::is_test_enabled() + && fr.owner.region_type() != region_type && !(region_type == RegionType::IO && fr.owner.region_type() == RegionType::RomDevice) { bail!("mismatch region type") } - if region_type == RegionType::Ram || region_type == RegionType::RamDevice { + if fr.owner.region_type() == RegionType::Ram + || fr.owner.region_type() == RegionType::RamDevice + { l = std::cmp::min(l, fr_remain); } fr.owner.write(src, region_base, region_offset, l)?; -- Gitee From 22740a34e729bfba8b9a71a18f24659012771822 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Mon, 9 Sep 2024 10:01:27 +0800 Subject: [PATCH 328/489] vhost: use debug log level To avoid too much log output, let's use debug log level instead of info level. Signed-off-by: Zhao Yi Min --- virtio/src/vhost/user/client.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/virtio/src/vhost/user/client.rs b/virtio/src/vhost/user/client.rs index 4a51c929..9a06e8e1 100644 --- a/virtio/src/vhost/user/client.rs +++ b/virtio/src/vhost/user/client.rs @@ -20,7 +20,7 @@ use std::sync::{Arc, Mutex}; use std::time::Duration; use anyhow::{bail, Context, Result}; -use log::{error, info, warn}; +use log::{debug, error, info, warn}; use vmm_sys_util::{epoll::EventSet, eventfd::EventFd}; use super::super::VhostOps; @@ -243,7 +243,7 @@ impl VhostUserMemInfo { let file_back = match fr.owner.get_file_backend() { Some(file_back_) => file_back_, _ => { - info!("It is not share memory for vhost user device"); + debug!("It is not share memory for vhost user device"); return Ok(()); } }; @@ -283,7 +283,7 @@ impl VhostUserMemInfo { let file_back = match fr.owner.get_file_backend() { None => { - info!("fr {:?} backend is not file, ignored", fr); + debug!("fr {:?} backend is not file, ignored", fr); return Ok(()); } Some(fb) => fb, -- Gitee From 86548caaf9ed681edcf094ea04255d66e2ca6f32 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 12 Sep 2024 20:33:21 +0800 Subject: [PATCH 329/489] virtio: move read/write_object_direct from address_space to virtio lib `read/write_object_direct` functions are only used in virtio lib. And they are unsafe. To avoid being mistakenly used by other modules, they will be moved to the virtio/split. Signed-off-by: liuxiangdong --- address_space/src/address_space.rs | 48 ------- trace/trace_info/memory.toml | 12 -- trace/trace_info/virtio.toml | 12 ++ virtio/src/device/balloon.rs | 6 +- virtio/src/device/block.rs | 43 ++---- virtio/src/device/gpu.rs | 36 ++--- virtio/src/device/net.rs | 34 ++--- virtio/src/device/rng.rs | 2 +- virtio/src/device/scsi_cntlr.rs | 11 +- virtio/src/device/serial.rs | 61 +++------ virtio/src/queue/mod.rs | 20 +-- virtio/src/queue/split.rs | 207 ++++++++++++++++------------- virtio/src/vhost/kernel/vsock.rs | 1 - virtio/src/vhost/user/client.rs | 4 +- 14 files changed, 201 insertions(+), 296 deletions(-) diff --git a/address_space/src/address_space.rs b/address_space/src/address_space.rs index 263aa314..95cad2ac 100644 --- a/address_space/src/address_space.rs +++ b/address_space/src/address_space.rs @@ -12,7 +12,6 @@ use std::fmt; use std::fmt::Debug; -use std::io::Write; use std::sync::{Arc, Mutex}; use anyhow::{anyhow, bail, Context, Result}; @@ -24,7 +23,6 @@ use crate::{ AddressAttr, AddressRange, AddressSpaceError, FlatRange, GuestAddress, Listener, ListenerReqType, Region, RegionIoEventFd, RegionType, }; -use migration::{migration::Migratable, MigrationManager}; use util::aio::Iovec; use util::byte_code::ByteCode; @@ -773,29 +771,6 @@ impl AddressSpace { .with_context(|| "Failed to write object") } - /// Write an object to memory via host address. - /// - /// # Arguments - /// - /// * `data` - The object that will be written to the memory. - /// * `host_addr` - The start host address where the object will be written to. - /// - /// # Safety - /// - /// Make true that host_addr and std::mem::size_of::() are in the range of ram. - /// - /// # Note - /// To use this method, it is necessary to implement `ByteCode` trait for your object. - pub unsafe fn write_object_direct(&self, data: &T, host_addr: u64) -> Result<()> { - trace::address_space_write_direct(host_addr, std::mem::size_of::()); - // Mark vmm dirty page manually if live migration is active. - MigrationManager::mark_dirty_log(host_addr, data.as_bytes().len() as u64); - let mut dst = - std::slice::from_raw_parts_mut(host_addr as *mut u8, std::mem::size_of::()); - dst.write_all(data.as_bytes()) - .with_context(|| "Failed to write object via host address") - } - /// Read some data from memory to form an object. /// /// # Arguments @@ -816,29 +791,6 @@ impl AddressSpace { Ok(obj) } - /// Read some data from memory to form an object via host address. - /// - /// # Arguments - /// - /// * `hoat_addr` - The start host address where the data will be read from. - /// - /// # Safety - /// - /// Make true that host_addr and std::mem::size_of::() are in the range of ram. - /// - /// # Note - /// To use this method, it is necessary to implement `ByteCode` trait for your object. - pub unsafe fn read_object_direct(&self, host_addr: u64) -> Result { - trace::address_space_read_direct(host_addr, std::mem::size_of::()); - let mut obj = T::default(); - let mut dst = obj.as_mut_bytes(); - let src = std::slice::from_raw_parts_mut(host_addr as *mut u8, std::mem::size_of::()); - dst.write_all(src) - .with_context(|| "Failed to read object via host address")?; - - Ok(obj) - } - /// Update the topology of memory. pub fn update_topology(&self) -> Result<()> { trace::trace_scope_start!(address_update_topology); diff --git a/trace/trace_info/memory.toml b/trace/trace_info/memory.toml index 1a832e58..c7d8171c 100644 --- a/trace/trace_info/memory.toml +++ b/trace/trace_info/memory.toml @@ -10,18 +10,6 @@ args = "addr: &dyn fmt::Debug, count: u64" message = "Memory: flatview_write addr {:?}, count {}" enabled = true -[[events]] -name = "address_space_read_direct" -args = "host_addr: u64, count: usize" -message = "Memory: address_space_read_direct host_addr {}, count {}" -enabled = true - -[[events]] -name = "address_space_write_direct" -args = "host_addr: u64, count: usize" -message = "Memory: address_space_write_direct host_addr {}, count {}" -enabled = true - [[scopes]] name = "address_update_topology" args = "" diff --git a/trace/trace_info/virtio.toml b/trace/trace_info/virtio.toml index d30ba1f7..5d3240b0 100644 --- a/trace/trace_info/virtio.toml +++ b/trace/trace_info/virtio.toml @@ -309,3 +309,15 @@ name = "reporting_evt_handler" args = "" message = "Balloon: handle fpr message" enabled = true + +[[events]] +name = "virtio_read_object_direct" +args = "host_addr: u64, count: usize" +message = "Memory: virtio_read_object_direct host_addr {}, count {}" +enabled = true + +[[events]] +name = "virtio_write_object_direct" +args = "host_addr: u64, count: usize" +message = "Memory: virtio_write_object_direct host_addr {}, count {}" +enabled = true diff --git a/virtio/src/device/balloon.rs b/virtio/src/device/balloon.rs index 850f77cb..e6ab32cd 100644 --- a/virtio/src/device/balloon.rs +++ b/virtio/src/device/balloon.rs @@ -658,7 +658,7 @@ impl BalloonIoHandler { } locked_queue .vring - .add_used(&self.mem_space, req.desc_index, req.elem_cnt) + .add_used(req.desc_index, req.elem_cnt) .with_context(|| "Failed to add balloon response into used queue")?; (self.interrupt_cb)(&VirtioInterruptType::Vring, Some(&locked_queue), false) .with_context(|| { @@ -693,7 +693,7 @@ impl BalloonIoHandler { } locked_queue .vring - .add_used(&self.mem_space, req.desc_index, req.elem_cnt) + .add_used(req.desc_index, req.elem_cnt) .with_context(|| "Failed to add balloon response into used queue")?; (self.interrupt_cb)(&VirtioInterruptType::Vring, Some(&locked_queue), false) .with_context(|| { @@ -741,7 +741,7 @@ impl BalloonIoHandler { locked_queue .vring - .add_used(&self.mem_space, req.desc_index, req.elem_cnt) + .add_used(req.desc_index, req.elem_cnt) .with_context(|| "Failed to add balloon response into used queue")?; (self.interrupt_cb)(&VirtioInterruptType::Vring, Some(&locked_queue), false) .with_context(|| { diff --git a/virtio/src/device/block.rs b/virtio/src/device/block.rs index e6efd9de..45b91944 100644 --- a/virtio/src/device/block.rs +++ b/virtio/src/device/block.rs @@ -238,7 +238,7 @@ impl AioCompleteCb { let mut queue_lock = self.queue.lock().unwrap(); queue_lock .vring - .add_used(&self.mem_space, req.desc_index, req.in_len) + .add_used(req.desc_index, req.in_len) .with_context(|| { format!( "Failed to add used ring(blk io completion), index {}, len {}", @@ -247,10 +247,7 @@ impl AioCompleteCb { })?; trace::virtio_blk_complete_one_request(req.desc_index, req.in_len); - if queue_lock - .vring - .should_notify(&self.mem_space, self.driver_features) - { + if queue_lock.vring.should_notify(self.driver_features) { (self.interrupt_cb)(&VirtioInterruptType::Vring, Some(&queue_lock), false) .with_context(|| { VirtioError::InterruptTrigger("blk io completion", VirtioInterruptType::Vring) @@ -732,12 +729,7 @@ impl BlockIoHandler { // Do not unlock or drop the locked_status in this function. let status; let mut locked_status; - let len = self - .queue - .lock() - .unwrap() - .vring - .avail_ring_len(&self.mem_space)?; + let len = self.queue.lock().unwrap().vring.avail_ring_len()?; if len > 0 { if let Some(block_backend) = self.block_backend.as_ref() { status = block_backend.lock().unwrap().get_status(); @@ -750,14 +742,7 @@ impl BlockIoHandler { let mut done = false; let mut iteration: u16 = 0; - while self - .queue - .lock() - .unwrap() - .vring - .avail_ring_len(&self.mem_space)? - != 0 - { + while self.queue.lock().unwrap().vring.avail_ring_len()? != 0 { // Do not stuck IO thread. iteration += 1; if iteration > MAX_ITERATION_PROCESS_QUEUE { @@ -766,19 +751,19 @@ impl BlockIoHandler { break; } - self.queue.lock().unwrap().vring.suppress_queue_notify( - &self.mem_space, - self.driver_features, - true, - )?; + self.queue + .lock() + .unwrap() + .vring + .suppress_queue_notify(self.driver_features, true)?; done = self.process_queue_internal()?; - self.queue.lock().unwrap().vring.suppress_queue_notify( - &self.mem_space, - self.driver_features, - false, - )?; + self.queue + .lock() + .unwrap() + .vring + .suppress_queue_notify(self.driver_features, false)?; // See whether we have been throttled. if let Some(lb) = self.leak_bucket.as_mut() { diff --git a/virtio/src/device/gpu.rs b/virtio/src/device/gpu.rs index 717a05e5..0725c09d 100644 --- a/virtio/src/device/gpu.rs +++ b/virtio/src/device/gpu.rs @@ -727,20 +727,14 @@ impl GpuIoHandler { fn complete_one_request(&mut self, index: u16, len: u32) -> Result<()> { let mut queue_lock = self.ctrl_queue.lock().unwrap(); - queue_lock - .vring - .add_used(&self.mem_space, index, len) - .with_context(|| { - format!( - "Failed to add used ring(gpu ctrl), index {}, len {}", - index, len, - ) - })?; - - if queue_lock - .vring - .should_notify(&self.mem_space, self.driver_features) - { + queue_lock.vring.add_used(index, len).with_context(|| { + format!( + "Failed to add used ring(gpu ctrl), index {}, len {}", + index, len, + ) + })?; + + if queue_lock.vring.should_notify(self.driver_features) { (self.interrupt_cb)(&VirtioInterruptType::Vring, Some(&queue_lock), false) .with_context(|| "Failed to trigger interrupt(gpu ctrl)")?; trace::virtqueue_send_interrupt("Gpu", &*queue_lock as *const _ as u64); @@ -1603,17 +1597,11 @@ impl GpuIoHandler { } }; - queue - .vring - .add_used(&self.mem_space, elem.index, 0) - .with_context(|| { - format!("Failed to add used ring(cursor), index {}", elem.index) - })?; + queue.vring.add_used(elem.index, 0).with_context(|| { + format!("Failed to add used ring(cursor), index {}", elem.index) + })?; - if queue - .vring - .should_notify(&self.mem_space, self.driver_features) - { + if queue.vring.should_notify(self.driver_features) { (self.interrupt_cb)(&VirtioInterruptType::Vring, Some(&queue), false) .with_context(|| { VirtioError::InterruptTrigger("gpu cursor", VirtioInterruptType::Vring) diff --git a/virtio/src/device/net.rs b/virtio/src/device/net.rs index e2833d93..4d745089 100644 --- a/virtio/src/device/net.rs +++ b/virtio/src/device/net.rs @@ -621,13 +621,10 @@ impl NetCtrlHandler { locked_queue .vring - .add_used(&self.mem_space, elem.index, mem::size_of_val(&ack) as u32) + .add_used(elem.index, mem::size_of_val(&ack) as u32) .with_context(|| format!("Failed to add used ring {}", elem.index))?; - if locked_queue - .vring - .should_notify(&self.mem_space, self.driver_features) - { + if locked_queue.vring.should_notify(self.driver_features) { (self.interrupt_cb)(&VirtioInterruptType::Vring, Some(&locked_queue), false) .with_context(|| { VirtioError::InterruptTrigger("ctrl", VirtioInterruptType::Vring) @@ -715,7 +712,7 @@ impl NetIoQueue { if elem.desc_num == 0 { queue .vring - .suppress_queue_notify(&self.mem_space, self.driver_features, false) + .suppress_queue_notify(self.driver_features, false) .with_context(|| "Failed to enable rx queue notify")?; self.listen_state.lock().unwrap().set_queue_avail(false); break; @@ -769,7 +766,7 @@ impl NetIoQueue { queue .vring - .add_used(&self.mem_space, elem.index, u32::try_from(size)?) + .add_used(elem.index, u32::try_from(size)?) .with_context(|| { format!( "Failed to add used ring for net rx, index: {}, len: {}", @@ -777,10 +774,7 @@ impl NetIoQueue { ) })?; - if queue - .vring - .should_notify(&self.mem_space, self.driver_features) - { + if queue.vring.should_notify(self.driver_features) { (self.interrupt_cb)(&VirtioInterruptType::Vring, Some(&queue), false) .with_context(|| { VirtioError::InterruptTrigger("net", VirtioInterruptType::Vring) @@ -824,7 +818,7 @@ impl NetIoQueue { queue.vring.push_back(); queue .vring - .suppress_queue_notify(&self.mem_space, self.driver_features, true) + .suppress_queue_notify(self.driver_features, true) .with_context(|| "Failed to suppress tx queue notify")?; self.listen_state.lock().unwrap().set_tap_full(true); break; @@ -833,13 +827,10 @@ impl NetIoQueue { queue .vring - .add_used(&self.mem_space, elem.index, 0) + .add_used(elem.index, 0) .with_context(|| format!("Net tx: Failed to add used ring {}", elem.index))?; - if queue - .vring - .should_notify(&self.mem_space, self.driver_features) - { + if queue.vring.should_notify(self.driver_features) { (self.interrupt_cb)(&VirtioInterruptType::Vring, Some(&queue), false) .with_context(|| { VirtioError::InterruptTrigger("net", VirtioInterruptType::Vring) @@ -1057,11 +1048,10 @@ impl NetIoHandler { net_queue.listen_state.lock().unwrap().set_queue_avail(true); let mut locked_queue = net_queue.rx.queue.lock().unwrap(); - if let Err(ref err) = locked_queue.vring.suppress_queue_notify( - &net_queue.mem_space, - net_queue.driver_features, - true, - ) { + if let Err(ref err) = locked_queue + .vring + .suppress_queue_notify(net_queue.driver_features, true) + { error!("Failed to suppress rx queue notify: {:?}", err); report_virtio_error( net_queue.interrupt_cb.clone(), diff --git a/virtio/src/device/rng.rs b/virtio/src/device/rng.rs index 2040e856..68f17d84 100644 --- a/virtio/src/device/rng.rs +++ b/virtio/src/device/rng.rs @@ -192,7 +192,7 @@ impl RngHandler { queue_lock .vring - .add_used(&self.mem_space, elem.index, size) + .add_used(elem.index, size) .with_context(|| { format!( "Failed to add used ring, index: {}, size: {}", diff --git a/virtio/src/device/scsi_cntlr.rs b/virtio/src/device/scsi_cntlr.rs index dc58be3a..1c03b471 100644 --- a/virtio/src/device/scsi_cntlr.rs +++ b/virtio/src/device/scsi_cntlr.rs @@ -544,11 +544,7 @@ impl VirtioScsiReq // DESC_CHAIN_MAX_TOTAL_LEN(1 << 32). So, it will not overflow here. queue_lock .vring - .add_used( - &self.mem_space, - self.desc_index, - self.data_len + (size_of::() as u32), - ) + .add_used(self.desc_index, self.data_len + (size_of::() as u32)) .with_context(|| { format!( "Failed to add used ring(scsi completion), index {}, len {}", @@ -556,10 +552,7 @@ impl VirtioScsiReq ) })?; - if queue_lock - .vring - .should_notify(&self.mem_space, self.driver_features) - { + if queue_lock.vring.should_notify(self.driver_features) { (self.interrupt_cb)(&VirtioInterruptType::Vring, Some(&queue_lock), false) .with_context(|| { VirtioError::InterruptTrigger( diff --git a/virtio/src/device/serial.rs b/virtio/src/device/serial.rs index 4047bcb3..3141672b 100644 --- a/virtio/src/device/serial.rs +++ b/virtio/src/device/serial.rs @@ -493,21 +493,15 @@ impl SerialPortHandler { trace::virtio_serial_output_data(iovec_size, size); } - queue_lock - .vring - .add_used(&self.mem_space, elem.index, 0) - .with_context(|| { - format!( - "Failed to add used ring for virtio serial port output, index: {} len: {}", - elem.index, 0, - ) - })?; + queue_lock.vring.add_used(elem.index, 0).with_context(|| { + format!( + "Failed to add used ring for virtio serial port output, index: {} len: {}", + elem.index, 0, + ) + })?; } - if queue_lock - .vring - .should_notify(&self.mem_space, self.driver_features) - { + if queue_lock.vring.should_notify(self.driver_features) { (self.interrupt_cb)(&VirtioInterruptType::Vring, Some(&queue_lock), false) .with_context(|| { VirtioError::InterruptTrigger( @@ -555,10 +549,9 @@ impl SerialPortHandler { } let mut queue_lock = self.input_queue.lock().unwrap(); - let _ = - queue_lock - .vring - .suppress_queue_notify(&self.mem_space, self.driver_features, !enable); + let _ = queue_lock + .vring + .suppress_queue_notify(self.driver_features, !enable); } fn input_handle_internal(&mut self, buffer: &[u8]) -> Result<()> { @@ -614,7 +607,7 @@ impl SerialPortHandler { queue_lock .vring - .add_used(&self.mem_space, elem.index, once_count as u32) + .add_used(elem.index, once_count as u32) .with_context(|| { format!( "Failed to add used ring for virtio serial port input: index {} len {}", @@ -622,10 +615,7 @@ impl SerialPortHandler { ) })?; - if queue_lock - .vring - .should_notify(&self.mem_space, self.driver_features) - { + if queue_lock.vring.should_notify(self.driver_features) { (self.interrupt_cb)(&VirtioInterruptType::Vring, Some(&queue_lock), false) .with_context(|| { VirtioError::InterruptTrigger( @@ -761,21 +751,15 @@ impl SerialControlHandler { ); self.handle_control_message(&mut req); - queue_lock - .vring - .add_used(&self.mem_space, elem.index, 0) - .with_context(|| { - format!( - "Failed to add used ring for control port, index: {} len: {}.", - elem.index, 0 - ) - })?; + queue_lock.vring.add_used(elem.index, 0).with_context(|| { + format!( + "Failed to add used ring for control port, index: {} len: {}.", + elem.index, 0 + ) + })?; } - if queue_lock - .vring - .should_notify(&self.mem_space, self.driver_features) - { + if queue_lock.vring.should_notify(self.driver_features) { (self.interrupt_cb)(&VirtioInterruptType::Vring, Some(&queue_lock), false) .with_context(|| { VirtioError::InterruptTrigger( @@ -922,7 +906,7 @@ impl SerialControlHandler { queue_lock .vring - .add_used(&self.mem_space, elem.index, len as u32) + .add_used(elem.index, len as u32) .with_context(|| { format!( "Failed to add used ring(serial input control queue), index {}, len {}", @@ -930,10 +914,7 @@ impl SerialControlHandler { ) })?; - if queue_lock - .vring - .should_notify(&self.mem_space, self.driver_features) - { + if queue_lock.vring.should_notify(self.driver_features) { (self.interrupt_cb)(&VirtioInterruptType::Vring, Some(&queue_lock), false) .with_context(|| { VirtioError::InterruptTrigger( diff --git a/virtio/src/queue/mod.rs b/virtio/src/queue/mod.rs index d226cd70..44f16473 100644 --- a/virtio/src/queue/mod.rs +++ b/virtio/src/queue/mod.rs @@ -126,32 +126,24 @@ pub trait VringOps { /// /// # Arguments /// - /// * `sys_mem` - Address space to which the vring belongs. /// * `index` - Index of descriptor in the virqueue descriptor table. /// * `len` - Total length of the descriptor chain which was used (written to). - fn add_used(&mut self, sys_mem: &Arc, index: u16, len: u32) -> Result<()>; + fn add_used(&mut self, index: u16, len: u32) -> Result<()>; /// Return true if guest needed to be notified. /// /// # Arguments /// - /// * `sys_mem` - Address space to which the vring belongs. /// * `features` - Bit mask of features negotiated by the backend and the frontend. - fn should_notify(&mut self, sys_mem: &Arc, features: u64) -> bool; + fn should_notify(&mut self, features: u64) -> bool; /// Give guest a hint to suppress virtqueue notification. /// /// # Arguments /// - /// * `sys_mem` - Address space to which the vring belongs. /// * `features` - Bit mask of features negotiated by the backend and the frontend. /// * `suppress` - Suppress virtqueue notification or not. - fn suppress_queue_notify( - &mut self, - sys_mem: &Arc, - features: u64, - suppress: bool, - ) -> Result<()>; + fn suppress_queue_notify(&mut self, features: u64, suppress: bool) -> Result<()>; /// Get the actual size of the vring. fn actual_size(&self) -> u16; @@ -160,13 +152,13 @@ pub trait VringOps { fn get_queue_config(&self) -> QueueConfig; /// The number of descriptor chains in the available ring. - fn avail_ring_len(&mut self, sys_mem: &Arc) -> Result; + fn avail_ring_len(&mut self) -> Result; /// Get the avail index of the vring. - fn get_avail_idx(&self, sys_mem: &Arc) -> Result; + fn get_avail_idx(&self) -> Result; /// Get the used index of the vring. - fn get_used_idx(&self, sys_mem: &Arc) -> Result; + fn get_used_idx(&self) -> Result; /// Get the region cache information of the SplitVring. fn get_cache(&self) -> &Option; diff --git a/virtio/src/queue/split.rs b/virtio/src/queue/split.rs index de35b043..30a906ff 100644 --- a/virtio/src/queue/split.rs +++ b/virtio/src/queue/split.rs @@ -11,6 +11,7 @@ // See the Mulan PSL v2 for more details. use std::cmp::min; +use std::io::Write; use std::mem::size_of; use std::num::Wrapping; use std::ops::{Deref, DerefMut}; @@ -28,6 +29,7 @@ use crate::{ report_virtio_error, virtio_has_feature, VirtioError, VirtioInterrupt, VIRTIO_F_RING_EVENT_IDX, }; use address_space::{AddressAttr, AddressSpace, GuestAddress, RegionCache, RegionType}; +use migration::{migration::Migratable, MigrationManager}; use util::byte_code::ByteCode; /// When host consumes a buffer, don't interrupt the guest. @@ -52,6 +54,51 @@ const VRING_IDX_POSITION: u64 = size_of::() as u64; /// The length of virtio descriptor. const DESCRIPTOR_LEN: u64 = size_of::() as u64; +/// Read some data from memory to form an object via host address. +/// +/// # Arguments +/// +/// * `hoat_addr` - The start host address where the data will be read from. +/// +/// # Safety +/// +/// Make true that host_addr and std::mem::size_of::() are in the range of ram. +/// +/// # Note +/// To use this method, it is necessary to implement `ByteCode` trait for your object. +unsafe fn read_object_direct(host_addr: u64) -> Result { + trace::virtio_read_object_direct(host_addr, std::mem::size_of::()); + let mut obj = T::default(); + let mut dst = obj.as_mut_bytes(); + let src = std::slice::from_raw_parts_mut(host_addr as *mut u8, std::mem::size_of::()); + dst.write_all(src) + .with_context(|| "Failed to read object via host address")?; + + Ok(obj) +} + +/// Write an object to memory via host address. +/// +/// # Arguments +/// +/// * `data` - The object that will be written to the memory. +/// * `host_addr` - The start host address where the object will be written to. +/// +/// # Safety +/// +/// Make true that host_addr and std::mem::size_of::() are in the range of ram. +/// +/// # Note +/// To use this method, it is necessary to implement `ByteCode` trait for your object. +unsafe fn write_object_direct(data: &T, host_addr: u64) -> Result<()> { + trace::virtio_write_object_direct(host_addr, std::mem::size_of::()); + // Mark vmm dirty page manually if live migration is active. + MigrationManager::mark_dirty_log(host_addr, data.as_bytes().len() as u64); + let mut dst = std::slice::from_raw_parts_mut(host_addr as *mut u8, std::mem::size_of::()); + dst.write_all(data.as_bytes()) + .with_context(|| "Failed to write object via host address") +} + #[derive(Default, Clone, Copy)] pub struct VirtioAddrCache { /// Host virtual address of the descriptor table. @@ -270,8 +317,7 @@ impl SplitVringDesc { })?; // SAFETY: dest_addr has been checked in SplitVringDesc::is_valid() and is guaranteed to be within the ram range. let desc = unsafe { - sys_mem - .read_object_direct::(desc_addr) + read_object_direct::(desc_addr) .with_context(|| VirtioError::ReadObjectErr("a descriptor", desc_addr)) }?; @@ -507,52 +553,48 @@ impl SplitVring { } /// Get the flags and idx of the available ring from guest memory. - fn get_avail_flags_idx(&self, sys_mem: &Arc) -> Result { + fn get_avail_flags_idx(&self) -> Result { // SAFETY: avail_ring_host is checked when addr_cache inited. unsafe { - sys_mem - .read_object_direct::(self.addr_cache.avail_ring_host) - .with_context(|| { - VirtioError::ReadObjectErr("avail flags idx", self.avail_ring.raw_value()) - }) + read_object_direct::(self.addr_cache.avail_ring_host).with_context( + || VirtioError::ReadObjectErr("avail flags idx", self.avail_ring.raw_value()), + ) } } /// Get the idx of the available ring from guest memory. - fn get_avail_idx(&self, sys_mem: &Arc) -> Result { - let flags_idx = self.get_avail_flags_idx(sys_mem)?; + fn get_avail_idx(&self) -> Result { + let flags_idx = self.get_avail_flags_idx()?; Ok(flags_idx.idx) } /// Get the flags of the available ring from guest memory. - fn get_avail_flags(&self, sys_mem: &Arc) -> Result { - let flags_idx = self.get_avail_flags_idx(sys_mem)?; + fn get_avail_flags(&self) -> Result { + let flags_idx = self.get_avail_flags_idx()?; Ok(flags_idx.flags) } /// Get the flags and idx of the used ring from guest memory. - fn get_used_flags_idx(&self, sys_mem: &Arc) -> Result { + fn get_used_flags_idx(&self) -> Result { // Make sure the idx read from sys_mem is new. fence(Ordering::SeqCst); // SAFETY: used_ring_host has been checked in set_addr_cache() and is guaranteed to be within the ram range. unsafe { - sys_mem - .read_object_direct::(self.addr_cache.used_ring_host) - .with_context(|| { - VirtioError::ReadObjectErr("used flags idx", self.used_ring.raw_value()) - }) + read_object_direct::(self.addr_cache.used_ring_host).with_context( + || VirtioError::ReadObjectErr("used flags idx", self.used_ring.raw_value()), + ) } } /// Get the index of the used ring from guest memory. - fn get_used_idx(&self, sys_mem: &Arc) -> Result { - let flag_idx = self.get_used_flags_idx(sys_mem)?; + fn get_used_idx(&self) -> Result { + let flag_idx = self.get_used_flags_idx()?; Ok(flag_idx.idx) } /// Set the used flags to suppress virtqueue notification or not - fn set_used_flags(&self, sys_mem: &Arc, suppress: bool) -> Result<()> { - let mut flags_idx = self.get_used_flags_idx(sys_mem)?; + fn set_used_flags(&self, suppress: bool) -> Result<()> { + let mut flags_idx = self.get_used_flags_idx()?; if suppress { flags_idx.flags |= VRING_USED_F_NO_NOTIFY; @@ -561,11 +603,7 @@ impl SplitVring { } // SAFETY: used_ring_host has been checked when addr_cache inited. unsafe { - sys_mem - .write_object_direct::( - &flags_idx, - self.addr_cache.used_ring_host, - ) + write_object_direct::(&flags_idx, self.addr_cache.used_ring_host) .with_context(|| { format!( "Failed to set used flags, used_ring: 0x{:X}", @@ -579,24 +617,23 @@ impl SplitVring { } /// Set the avail idx to the field of the event index for the available ring. - fn set_avail_event(&self, sys_mem: &Arc, event_idx: u16) -> Result<()> { + fn set_avail_event(&self, event_idx: u16) -> Result<()> { trace::virtqueue_set_avail_event(self as *const _ as u64, event_idx); let avail_event_offset = VRING_FLAGS_AND_IDX_LEN + USEDELEM_LEN * u64::from(self.actual_size()); // SAFETY: used_ring_host has been checked in set_addr_cache(). unsafe { - sys_mem - .write_object_direct( - &event_idx, - self.addr_cache.used_ring_host + avail_event_offset, + write_object_direct( + &event_idx, + self.addr_cache.used_ring_host + avail_event_offset, + ) + .with_context(|| { + format!( + "Failed to set avail event idx, used_ring: 0x{:X}, offset: {}", + self.used_ring.raw_value(), + avail_event_offset, ) - .with_context(|| { - format!( - "Failed to set avail event idx, used_ring: 0x{:X}, offset: {}", - self.used_ring.raw_value(), - avail_event_offset, - ) - }) + }) }?; // Make sure the data has been set. fence(Ordering::SeqCst); @@ -604,7 +641,7 @@ impl SplitVring { } /// Get the event index of the used ring from guest memory. - fn get_used_event(&self, sys_mem: &Arc) -> Result { + fn get_used_event(&self) -> Result { let used_event_offset = VRING_FLAGS_AND_IDX_LEN + AVAILELEM_LEN * u64::from(self.actual_size()); // Make sure the event idx read from sys_mem is new. @@ -614,8 +651,7 @@ impl SplitVring { let used_event_addr = self.addr_cache.avail_ring_host + used_event_offset; // SAFETY: used_event_addr is protected by virtio calculations and is guaranteed to be within the ram range. let used_event = unsafe { - sys_mem - .read_object_direct::(used_event_addr) + read_object_direct::(used_event_addr) .with_context(|| VirtioError::ReadObjectErr("used event id", used_event_addr)) }?; @@ -623,8 +659,8 @@ impl SplitVring { } /// Return true if VRING_AVAIL_F_NO_INTERRUPT is set. - fn is_avail_ring_no_interrupt(&self, sys_mem: &Arc) -> bool { - match self.get_avail_flags(sys_mem) { + fn is_avail_ring_no_interrupt(&self) -> bool { + match self.get_avail_flags() { Ok(avail_flags) => (avail_flags & VRING_AVAIL_F_NO_INTERRUPT) != 0, Err(ref e) => { warn!( @@ -637,9 +673,9 @@ impl SplitVring { } /// Return true if it's required to trigger interrupt for the used vring. - fn used_ring_need_event(&mut self, sys_mem: &Arc) -> bool { + fn used_ring_need_event(&mut self) -> bool { let old = self.last_signal_used; - let new = match self.get_used_idx(sys_mem) { + let new = match self.get_used_idx() { Ok(used_idx) => Wrapping(used_idx), Err(ref e) => { error!("Failed to get the status for notifying used vring: {:?}", e); @@ -647,7 +683,7 @@ impl SplitVring { } }; - let used_event_idx = match self.get_used_event(sys_mem) { + let used_event_idx = match self.get_used_event() { Ok(idx) => Wrapping(idx), Err(ref e) => { error!("Failed to get the status for notifying used vring: {:?}", e); @@ -779,11 +815,9 @@ impl SplitVring { let desc_index_addr = self.addr_cache.avail_ring_host + index_offset; // SAFETY: dest_index_addr is protected by virtio calculations and is guaranteed to be within the ram range. let desc_index = unsafe { - sys_mem - .read_object_direct::(desc_index_addr) - .with_context(|| { - VirtioError::ReadObjectErr("the index of descriptor", desc_index_addr) - }) + read_object_direct::(desc_index_addr).with_context(|| { + VirtioError::ReadObjectErr("the index of descriptor", desc_index_addr) + }) }?; let desc = SplitVringDesc::new( @@ -796,7 +830,7 @@ impl SplitVring { // Suppress queue notification related to current processing desc chain. if virtio_has_feature(features, VIRTIO_F_RING_EVENT_IDX) { - self.set_avail_event(sys_mem, (next_avail + Wrapping(1)).0) + self.set_avail_event((next_avail + Wrapping(1)).0) .with_context(|| "Failed to set avail event for popping avail ring")?; } @@ -854,7 +888,7 @@ impl VringOps for SplitVring { fn pop_avail(&mut self, sys_mem: &Arc, features: u64) -> Result { let mut element = Element::new(0); - if !self.is_enabled() || self.avail_ring_len(sys_mem)? == 0 { + if !self.is_enabled() || self.avail_ring_len()? == 0 { return Ok(element); } @@ -877,7 +911,7 @@ impl VringOps for SplitVring { self.next_avail -= Wrapping(1); } - fn add_used(&mut self, sys_mem: &Arc, index: u16, len: u32) -> Result<()> { + fn add_used(&mut self, index: u16, len: u32) -> Result<()> { if index >= self.size { return Err(anyhow!(VirtioError::QueueIndex(index, self.size))); } @@ -892,8 +926,7 @@ impl VringOps for SplitVring { }; // SAFETY: used_elem_addr is guaranteed to be within ram range. unsafe { - sys_mem - .write_object_direct::(&used_elem, used_elem_addr) + write_object_direct::(&used_elem, used_elem_addr) .with_context(|| "Failed to write object for used element") }?; // Make sure used element is filled before updating used idx. @@ -902,12 +935,11 @@ impl VringOps for SplitVring { self.next_used += Wrapping(1); // SAFETY: used_ring_host has been checked when addr_cache inited. unsafe { - sys_mem - .write_object_direct( - &(self.next_used.0), - self.addr_cache.used_ring_host + VRING_IDX_POSITION, - ) - .with_context(|| "Failed to write next used idx") + write_object_direct( + &(self.next_used.0), + self.addr_cache.used_ring_host + VRING_IDX_POSITION, + ) + .with_context(|| "Failed to write next used idx") }?; // Make sure used index is exposed before notifying guest. fence(Ordering::SeqCst); @@ -919,28 +951,23 @@ impl VringOps for SplitVring { Ok(()) } - fn should_notify(&mut self, sys_mem: &Arc, features: u64) -> bool { + fn should_notify(&mut self, features: u64) -> bool { if virtio_has_feature(features, VIRTIO_F_RING_EVENT_IDX) { - self.used_ring_need_event(sys_mem) + self.used_ring_need_event() } else { - !self.is_avail_ring_no_interrupt(sys_mem) + !self.is_avail_ring_no_interrupt() } } - fn suppress_queue_notify( - &mut self, - sys_mem: &Arc, - features: u64, - suppress: bool, - ) -> Result<()> { + fn suppress_queue_notify(&mut self, features: u64, suppress: bool) -> Result<()> { if !self.is_enabled() { bail!("queue is not ready"); } if virtio_has_feature(features, VIRTIO_F_RING_EVENT_IDX) { - self.set_avail_event(sys_mem, self.get_avail_idx(sys_mem)?)?; + self.set_avail_event(self.get_avail_idx()?)?; } else { - self.set_used_flags(sys_mem, suppress)?; + self.set_used_flags(suppress)?; } Ok(()) } @@ -956,18 +983,18 @@ impl VringOps for SplitVring { } /// The number of descriptor chains in the available ring. - fn avail_ring_len(&mut self, sys_mem: &Arc) -> Result { - let avail_idx = self.get_avail_idx(sys_mem).map(Wrapping)?; + fn avail_ring_len(&mut self) -> Result { + let avail_idx = self.get_avail_idx().map(Wrapping)?; Ok((avail_idx - self.next_avail).0) } - fn get_avail_idx(&self, sys_mem: &Arc) -> Result { - SplitVring::get_avail_idx(self, sys_mem) + fn get_avail_idx(&self) -> Result { + SplitVring::get_avail_idx(self) } - fn get_used_idx(&self, sys_mem: &Arc) -> Result { - SplitVring::get_used_idx(self, sys_mem) + fn get_used_idx(&self) -> Result { + SplitVring::get_used_idx(self) } fn get_cache(&self) -> &Option { @@ -987,7 +1014,7 @@ impl VringOps for SplitVring { let mut avail_bytes = 0_usize; let mut avail_idx = self.next_avail; - let end_idx = self.get_avail_idx(sys_mem).map(Wrapping)?; + let end_idx = self.get_avail_idx().map(Wrapping)?; while (end_idx - avail_idx).0 > 0 { let desc_info = self.get_desc_info(sys_mem, avail_idx, 0)?; @@ -1532,7 +1559,7 @@ mod tests { // the event idx of avail ring is equal to get_avail_event let event_idx = vring.get_avail_event(&sys_space).unwrap(); assert_eq!(event_idx, 1); - let avail_idx = vring.get_avail_idx(&sys_space).unwrap(); + let avail_idx = vring.get_avail_idx().unwrap(); assert_eq!(avail_idx, 1); } @@ -2018,7 +2045,7 @@ mod tests { // The event idx of avail ring is equal to get_avail_event. let event_idx = vring.get_avail_event(&sys_space).unwrap(); assert_eq!(event_idx, 1); - let avail_idx = vring.get_avail_idx(&sys_space).unwrap(); + let avail_idx = vring.get_avail_idx().unwrap(); assert_eq!(avail_idx, 1); } @@ -2056,7 +2083,7 @@ mod tests { assert!(vring.is_valid(&sys_space)); // it is false when the index is more than the size of queue - if let Err(err) = vring.add_used(&sys_space, QUEUE_SIZE, 100) { + if let Err(err) = vring.add_used(QUEUE_SIZE, 100) { if let Some(e) = err.downcast_ref::() { if let VirtioError::QueueIndex(offset, size) = e { assert_eq!(*offset, 256); @@ -2065,7 +2092,7 @@ mod tests { } } - assert!(vring.add_used(&sys_space, 10, 100).is_ok()); + assert!(vring.add_used(10, 100).is_ok()); let elem = vring.get_used_elem(&sys_space, 0).unwrap(); assert_eq!(elem.id, 10); assert_eq!(elem.len, 100); @@ -2108,7 +2135,7 @@ mod tests { // it's true when the feature of event idx and no interrupt for the avail ring is closed let features = 0_u64; assert!(vring.set_avail_ring_flags(&sys_space, 0).is_ok()); - assert!(vring.should_notify(&sys_space, features)); + assert!(vring.should_notify(features)); // it's false when the feature of event idx is closed and the feature of no interrupt for // the avail ring is open @@ -2116,7 +2143,7 @@ mod tests { assert!(vring .set_avail_ring_flags(&sys_space, VRING_AVAIL_F_NO_INTERRUPT) .is_ok()); - assert!(!vring.should_notify(&sys_space, features)); + assert!(!vring.should_notify(features)); // it's true when the feature of event idx is open and // (new - event_idx - Wrapping(1) < new -old) @@ -2124,20 +2151,20 @@ mod tests { vring.last_signal_used = Wrapping(5); // old assert!(vring.set_used_ring_idx(&sys_space, 10).is_ok()); // new assert!(vring.set_used_event_idx(&sys_space, 6).is_ok()); // event_idx - assert!(vring.should_notify(&sys_space, features)); + assert!(vring.should_notify(features)); // it's false when the feature of event idx is open and // (new - event_idx - Wrapping(1) > new - old) vring.last_signal_used = Wrapping(5); // old assert!(vring.set_used_ring_idx(&sys_space, 10).is_ok()); // new assert!(vring.set_used_event_idx(&sys_space, 1).is_ok()); // event_idx - assert!(!vring.should_notify(&sys_space, features)); + assert!(!vring.should_notify(features)); // it's false when the feature of event idx is open and // (new - event_idx - Wrapping(1) = new -old) vring.last_signal_used = Wrapping(5); // old assert!(vring.set_used_ring_idx(&sys_space, 10).is_ok()); // new assert!(vring.set_used_event_idx(&sys_space, 4).is_ok()); // event_idx - assert!(!vring.should_notify(&sys_space, features)); + assert!(!vring.should_notify(features)); } } diff --git a/virtio/src/vhost/kernel/vsock.rs b/virtio/src/vhost/kernel/vsock.rs index 53a38745..b67d21ae 100644 --- a/virtio/src/vhost/kernel/vsock.rs +++ b/virtio/src/vhost/kernel/vsock.rs @@ -174,7 +174,6 @@ impl Vsock { event_queue_locked .vring .add_used( - &self.mem_space, element.index, VIRTIO_VSOCK_EVENT_TRANSPORT_RESET.as_bytes().len() as u32, ) diff --git a/virtio/src/vhost/user/client.rs b/virtio/src/vhost/user/client.rs index 9a06e8e1..d4c86a78 100644 --- a/virtio/src/vhost/user/client.rs +++ b/virtio/src/vhost/user/client.rs @@ -405,7 +405,6 @@ pub struct VhostUserClient { client: Arc>, mem_info: VhostUserMemInfo, delete_evts: Vec, - mem_space: Arc, queues: Vec>>, queue_evts: Vec>, call_events: Vec>, @@ -441,7 +440,6 @@ impl VhostUserClient { client, mem_info, delete_evts: Vec::new(), - mem_space: mem_space.clone(), queues: Vec::new(), queue_evts: Vec::new(), call_events: Vec::new(), @@ -571,7 +569,7 @@ impl VhostUserClient { })?; // When spdk/ovs has been killed, stratovirt can not get the last avail // index in spdk/ovs, it can only use used index as last avail index. - let last_avail_idx = queue.vring.get_used_idx(&self.mem_space)?; + let last_avail_idx = queue.vring.get_used_idx()?; self.set_vring_base(queue_index, last_avail_idx) .with_context(|| { format!( -- Gitee From d0483b6ec6916ba492b92b99be407d41d88c4da5 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Thu, 15 Aug 2024 09:14:31 +0800 Subject: [PATCH 330/489] StratoVirt: Add a Rust implemented OCI runtime named ozonec Cli of ozonec: ozonec [GLOBAL OPTIONS] [OPTIONS] ... --- ozonec/Cargo.toml | 23 +++++++++++++++ ozonec/src/main.rs | 72 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 ozonec/Cargo.toml create mode 100644 ozonec/src/main.rs diff --git a/ozonec/Cargo.toml b/ozonec/Cargo.toml new file mode 100644 index 00000000..f80ccad0 --- /dev/null +++ b/ozonec/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "ozonec" +version = "0.1.0" +authors = ["Huawei StratoVirt Team"] +edition = "2021" +license = "Mulan PSL v2" +description = "An OCI runtime implemented by Rust" + +[dependencies] +anyhow = "= 1.0.71" +clap = { version = "= 4.1.4", default-features = false, features = ["derive", "cargo", "std", "help", "usage"] } + +[workspace] + +[profile.dev] +panic = "unwind" + +[profile.release] +lto = true +strip = true +opt-level = 'z' +codegen-units = 1 +panic = "abort" diff --git a/ozonec/src/main.rs b/ozonec/src/main.rs new file mode 100644 index 00000000..71b777bf --- /dev/null +++ b/ozonec/src/main.rs @@ -0,0 +1,72 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::{path::PathBuf, process::exit}; + +use anyhow::Result; +use clap::{crate_description, Args, Parser, Subcommand}; + +// Global options which are not binded to any specific command. +#[derive(Args, Debug)] +struct GlobalOpts { + /// Root directory to store container state. + #[arg(short, long)] + root: Option, + /// Path of log file. + #[arg(short, long)] + log: Option, + /// Enable debug log level. + #[arg(short, long)] + debug: bool, +} + +// Standard commands supported by [OCI runtime-spec] +// (https://github.com/opencontainers/runtime-spec/blob/master/runtime.md) +// and [OCI Command Line Interface] +// (https://github.com/opencontainers/runtime-tools/blob/master/docs/command-line-interface.md). +#[derive(Subcommand, Debug)] +enum StandardCmd {} + +// Extended commands not documented in [OCI Command Line Interface]. +#[derive(Subcommand, Debug)] +enum ExtendCmd {} + +#[derive(Subcommand, Debug)] +enum Command { + #[command(flatten)] + Standard(StandardCmd), + #[command(flatten)] + Extend(ExtendCmd), +} + +#[derive(Parser, Debug)] +#[command(version, author, about = crate_description!())] +#[command(propagate_version = true)] +struct Cli { + #[command(flatten)] + global: GlobalOpts, + #[command(subcommand)] + cmd: Command, +} + +fn real_main() -> Result<()> { + let cli = Cli::parse(); + Ok(()) +} + +fn main() { + if let Err(e) = real_main() { + eprintln!("ERROR: {:?}", e); + exit(1); + } + exit(0); +} -- Gitee From 2dcba80c047fda83603b0c346834d7662770db66 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Thu, 15 Aug 2024 18:17:34 +0800 Subject: [PATCH 331/489] ozonec/utils: Add logger.rs Write logs to the file specified by global command option --log, otherwise output logs to stderr. --- ozonec/Cargo.toml | 3 + ozonec/src/main.rs | 9 +- ozonec/src/utils/logger.rs | 238 +++++++++++++++++++++++++++++++++++++ ozonec/src/utils/mod.rs | 13 ++ 4 files changed, 262 insertions(+), 1 deletion(-) create mode 100644 ozonec/src/utils/logger.rs create mode 100644 ozonec/src/utils/mod.rs diff --git a/ozonec/Cargo.toml b/ozonec/Cargo.toml index f80ccad0..d853ab0a 100644 --- a/ozonec/Cargo.toml +++ b/ozonec/Cargo.toml @@ -9,6 +9,9 @@ description = "An OCI runtime implemented by Rust" [dependencies] anyhow = "= 1.0.71" clap = { version = "= 4.1.4", default-features = false, features = ["derive", "cargo", "std", "help", "usage"] } +libc = "= 0.2.146" +log = { version = "= 0.4.18", features = ["std"]} +nix = "= 0.26.2" [workspace] diff --git a/ozonec/src/main.rs b/ozonec/src/main.rs index 71b777bf..69752860 100644 --- a/ozonec/src/main.rs +++ b/ozonec/src/main.rs @@ -10,11 +10,15 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. +mod utils; + use std::{path::PathBuf, process::exit}; -use anyhow::Result; +use anyhow::{Context, Result}; use clap::{crate_description, Args, Parser, Subcommand}; +use crate::utils::logger; + // Global options which are not binded to any specific command. #[derive(Args, Debug)] struct GlobalOpts { @@ -60,6 +64,9 @@ struct Cli { fn real_main() -> Result<()> { let cli = Cli::parse(); + + logger::init(&cli.global.log, cli.global.debug).with_context(|| "Failed to init logger")?; + Ok(()) } diff --git a/ozonec/src/utils/logger.rs b/ozonec/src/utils/logger.rs new file mode 100644 index 00000000..17a35ff8 --- /dev/null +++ b/ozonec/src/utils/logger.rs @@ -0,0 +1,238 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::{ + fs::{remove_file, rename, File, OpenOptions}, + io::{stderr, Write}, + num::Wrapping, + os::unix::fs::OpenOptionsExt, + path::{Path, PathBuf}, + sync::Mutex, + time::UNIX_EPOCH, +}; + +use anyhow::{Context, Result}; +use log::{set_boxed_logger, set_max_level, Level, LevelFilter, Log, Metadata, Record}; +use nix::unistd::{getpid, gettid}; + +// Maximum size of log file is 100MB. +const LOG_ROTATE_SIZE_MAX: usize = 100 * 1024 * 1024; +// Logs are retained for seven days at most. +const LOG_ROTATE_CNT_MAX: u8 = 7; + +struct LogRotate { + handler: Box, + path: String, + size: Wrapping, + created_day: i32, +} + +impl LogRotate { + fn rotate(&mut self, inc_size: usize) -> Result<()> { + if self.path.is_empty() { + return Ok(()); + } + + self.size += Wrapping(inc_size); + let seconds = wall_time().0; + let today = formatted_time(seconds)[2]; + if self.size < Wrapping(LOG_ROTATE_SIZE_MAX) && self.created_day == today { + return Ok(()); + } + + // Delete oldest log file. + let mut rotate_cnt = LOG_ROTATE_CNT_MAX - 1; + let olddest = format!("{}{}", self.path, rotate_cnt); + if Path::new(&olddest).exists() { + remove_file(&olddest).with_context(|| "Failed to delete olddest log")?; + } + + // Rename remaining logs. + let mut new_log = olddest; + while rotate_cnt != 0 { + let mut old_log = self.path.clone(); + + rotate_cnt -= 1; + if rotate_cnt != 0 { + old_log += &rotate_cnt.to_string(); + } + + if Path::new(&old_log).exists() { + rename(&old_log, &new_log) + .with_context(|| format!("Failed to rename {} to {}", old_log, new_log))?; + } + new_log = old_log; + } + + self.handler = Box::new( + open_log_file(&PathBuf::from(self.path.clone())) + .with_context(|| format!("Failed to convert {}", self.path))?, + ); + self.size = Wrapping(0); + self.created_day = today; + Ok(()) + } +} + +fn open_log_file(path: &PathBuf) -> Result { + OpenOptions::new() + .read(false) + .write(true) + .append(true) + .create(true) + .mode(0o640) + .open(path) + .with_context(|| "Failed to open log file") +} + +fn formatted_time(seconds: i64) -> [i32; 6] { + // SAFETY: an all-zero value is valid for libc::tm. + let mut ti: libc::tm = unsafe { std::mem::zeroed() }; + unsafe { + // SAFETY: seconds and ti are both local variables and valid. + libc::localtime_r(&seconds, &mut ti); + } + [ + ti.tm_year + 1900, + ti.tm_mon + 1, + ti.tm_mday, + ti.tm_hour, + ti.tm_min, + ti.tm_sec, + ] +} + +fn wall_time() -> (i64, i64) { + let mut ts = libc::timespec { + tv_sec: 0, + tv_nsec: 0, + }; + unsafe { + // SAFETY: ts is a local variable and valid. + libc::clock_gettime(libc::CLOCK_REALTIME, &mut ts); + } + (ts.tv_sec, ts.tv_nsec) +} + +fn formatted_now() -> String { + let (sec, nsec) = wall_time(); + let formatted_time = formatted_time(sec); + + format!( + "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}:{:09}", + formatted_time[0], + formatted_time[1], + formatted_time[2], + formatted_time[3], + formatted_time[4], + formatted_time[5], + nsec + ) +} + +struct Logger { + rotate: Mutex, + level: Level, +} + +impl Logger { + fn new(path: &Option, level: Level) -> Result { + let (log_file, log_size, created_day) = match path { + Some(p) => { + let file = Box::new(open_log_file(&p)?); + let metadata = file.metadata().with_context(|| "Failed to get metadata")?; + let mod_time = metadata + .modified() + .with_context(|| "Failed to get modify time")?; + let seconds = mod_time + .duration_since(UNIX_EPOCH) + .with_context(|| "Failed to get duration time")? + .as_secs(); + let log_size = Wrapping(metadata.len() as usize); + let created_day = formatted_time(seconds as i64)[2]; + (file as Box, log_size, created_day) + } + None => (Box::new(stderr()) as Box, Wrapping(0), 0), + }; + + let rotate = Mutex::new(LogRotate { + handler: log_file, + path: path + .as_ref() + .unwrap_or(&PathBuf::new()) + .to_string_lossy() + .to_string(), + size: log_size, + created_day, + }); + Ok(Self { rotate, level }) + } +} + +impl Log for Logger { + fn enabled(&self, metadata: &Metadata) -> bool { + metadata.level() <= self.level + } + + fn log(&self, record: &Record) { + if !self.enabled(record.metadata()) { + return; + } + + let fmt_msg = format_args!( + "{:<5}: [{}][{}][{}: {}]:{}: {}\n", + formatted_now(), + getpid(), + gettid(), + record.file().unwrap_or(""), + record.line().unwrap_or(0), + record.level(), + record.args() + ) + .to_string(); + + let mut log_rotate = self.rotate.lock().unwrap(); + if let Err(e) = log_rotate.handler.write_all(fmt_msg.as_bytes()) { + eprintln!("Failed to log message: {:?}", e); + return; + } + if let Err(e) = log_rotate.rotate(fmt_msg.as_bytes().len()) { + eprintln!("Failed to rotate log files: {:?}", e); + } + } + + fn flush(&self) {} +} + +pub fn init(path: &Option, debug: bool) -> Result<()> { + let log_level = if debug { + Level::Debug + } else { + match std::env::var("OZONEC_LOG_LEVEL") { + Ok(level) => match level.to_lowercase().as_str() { + "error" => Level::Error, + "warn" => Level::Warn, + "info" => Level::Info, + "debug" => Level::Debug, + "trace" => Level::Trace, + _ => Level::Info, + }, + _ => Level::Info, + } + }; + + let logger = Box::new(Logger::new(path, log_level)?); + set_boxed_logger(logger) + .map(|_| set_max_level(LevelFilter::Trace)) + .with_context(|| "Logger has been already set")?; + Ok(()) +} diff --git a/ozonec/src/utils/mod.rs b/ozonec/src/utils/mod.rs new file mode 100644 index 00000000..3415cf8e --- /dev/null +++ b/ozonec/src/utils/mod.rs @@ -0,0 +1,13 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +pub mod logger; -- Gitee From 4e9cca19b9f038c2ed7c9740dab15b7aef0baabd Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Thu, 15 Aug 2024 19:00:17 +0800 Subject: [PATCH 332/489] ozonec: Add crate oci_spec to interact with OCI specification --- ozonec/Cargo.toml | 1 + ozonec/oci_spec/Cargo.toml | 19 +++++++++++++++++++ ozonec/oci_spec/src/lib.rs | 17 +++++++++++++++++ ozonec/oci_spec/src/linux.rs | 11 +++++++++++ ozonec/oci_spec/src/posix.rs | 11 +++++++++++ ozonec/oci_spec/src/runtime.rs | 11 +++++++++++ ozonec/oci_spec/src/state.rs | 11 +++++++++++ ozonec/oci_spec/src/vm.rs | 11 +++++++++++ 8 files changed, 92 insertions(+) create mode 100644 ozonec/oci_spec/Cargo.toml create mode 100644 ozonec/oci_spec/src/lib.rs create mode 100644 ozonec/oci_spec/src/linux.rs create mode 100644 ozonec/oci_spec/src/posix.rs create mode 100644 ozonec/oci_spec/src/runtime.rs create mode 100644 ozonec/oci_spec/src/state.rs create mode 100644 ozonec/oci_spec/src/vm.rs diff --git a/ozonec/Cargo.toml b/ozonec/Cargo.toml index d853ab0a..8cd9de1b 100644 --- a/ozonec/Cargo.toml +++ b/ozonec/Cargo.toml @@ -12,6 +12,7 @@ clap = { version = "= 4.1.4", default-features = false, features = ["derive", "c libc = "= 0.2.146" log = { version = "= 0.4.18", features = ["std"]} nix = "= 0.26.2" +oci_spec = { path = "oci_spec" } [workspace] diff --git a/ozonec/oci_spec/Cargo.toml b/ozonec/oci_spec/Cargo.toml new file mode 100644 index 00000000..c9d2cbe9 --- /dev/null +++ b/ozonec/oci_spec/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "oci_spec" +version = "0.1.0" +authors = ["Huawei StratoVirt Team"] +edition = "2021" +license = "Mulan PSL v2" +description = "Open Container Initiative (OCI) Specifications in Rust" + +[dependencies] + +[profile.dev] +panic = "unwind" + +[profile.release] +lto = true +strip = true +opt-level = 'z' +codegen-units = 1 +panic = "abort" \ No newline at end of file diff --git a/ozonec/oci_spec/src/lib.rs b/ozonec/oci_spec/src/lib.rs new file mode 100644 index 00000000..c7b44ff0 --- /dev/null +++ b/ozonec/oci_spec/src/lib.rs @@ -0,0 +1,17 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +pub mod linux; +pub mod posix; +pub mod runtime; +pub mod state; +pub mod vm; diff --git a/ozonec/oci_spec/src/linux.rs b/ozonec/oci_spec/src/linux.rs new file mode 100644 index 00000000..4524f4b2 --- /dev/null +++ b/ozonec/oci_spec/src/linux.rs @@ -0,0 +1,11 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. diff --git a/ozonec/oci_spec/src/posix.rs b/ozonec/oci_spec/src/posix.rs new file mode 100644 index 00000000..4524f4b2 --- /dev/null +++ b/ozonec/oci_spec/src/posix.rs @@ -0,0 +1,11 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. diff --git a/ozonec/oci_spec/src/runtime.rs b/ozonec/oci_spec/src/runtime.rs new file mode 100644 index 00000000..4524f4b2 --- /dev/null +++ b/ozonec/oci_spec/src/runtime.rs @@ -0,0 +1,11 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. diff --git a/ozonec/oci_spec/src/state.rs b/ozonec/oci_spec/src/state.rs new file mode 100644 index 00000000..4524f4b2 --- /dev/null +++ b/ozonec/oci_spec/src/state.rs @@ -0,0 +1,11 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. diff --git a/ozonec/oci_spec/src/vm.rs b/ozonec/oci_spec/src/vm.rs new file mode 100644 index 00000000..4524f4b2 --- /dev/null +++ b/ozonec/oci_spec/src/vm.rs @@ -0,0 +1,11 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. -- Gitee From 2e0d576a4f9800bdb64f7b59210eb22692859530 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Fri, 16 Aug 2024 09:57:00 +0800 Subject: [PATCH 333/489] oci_spec/linux: Add namespace support --- ozonec/oci_spec/Cargo.toml | 4 + ozonec/oci_spec/src/linux.rs | 195 +++++++++++++++++++++++++++++++++++ 2 files changed, 199 insertions(+) diff --git a/ozonec/oci_spec/Cargo.toml b/ozonec/oci_spec/Cargo.toml index c9d2cbe9..b18928f4 100644 --- a/ozonec/oci_spec/Cargo.toml +++ b/ozonec/oci_spec/Cargo.toml @@ -7,6 +7,10 @@ license = "Mulan PSL v2" description = "Open Container Initiative (OCI) Specifications in Rust" [dependencies] +anyhow = "= 1.0.71" +nix = "= 0.26.2" +serde = { version = "= 1.0.163", features = ["derive"] } +serde_json = "= 1.0.96" [profile.dev] panic = "unwind" diff --git a/ozonec/oci_spec/src/linux.rs b/ozonec/oci_spec/src/linux.rs index 4524f4b2..0cb696f7 100644 --- a/ozonec/oci_spec/src/linux.rs +++ b/ozonec/oci_spec/src/linux.rs @@ -9,3 +9,198 @@ // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. + +use std::path::PathBuf; + +use anyhow::{anyhow, Result}; +use nix::sched::CloneFlags; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, Hash)] +#[serde(rename_all = "snake_case")] +/// Available Linux namespaces. +pub enum NamespaceType { + Cgroup = 0x0200_0000, + Ipc = 0x0800_0000, + Network = 0x4000_0000, + Mount = 0x0002_0000, + Pid = 0x2000_0000, + Time = 0x0000_0080, + User = 0x1000_0000, + Uts = 0x0400_0000, +} + +impl TryInto for NamespaceType { + type Error = anyhow::Error; + + fn try_into(self) -> Result { + match self { + NamespaceType::Cgroup => Ok(CloneFlags::CLONE_NEWCGROUP), + NamespaceType::Ipc => Ok(CloneFlags::CLONE_NEWIPC), + NamespaceType::Network => Ok(CloneFlags::CLONE_NEWNET), + NamespaceType::Mount => Ok(CloneFlags::CLONE_NEWNS), + NamespaceType::Pid => Ok(CloneFlags::CLONE_NEWPID), + NamespaceType::Time => Err(anyhow!("Time namespace not supported with clone")), + NamespaceType::User => Ok(CloneFlags::CLONE_NEWUSER), + NamespaceType::Uts => Ok(CloneFlags::CLONE_NEWUTS), + } + } +} + +impl From for String { + fn from(ns_type: NamespaceType) -> Self { + match ns_type { + NamespaceType::Cgroup => String::from("cgroup"), + NamespaceType::Ipc => String::from("ipc"), + NamespaceType::Network => String::from("net"), + NamespaceType::Mount => String::from("mnt"), + NamespaceType::Pid => String::from("pid"), + NamespaceType::Time => String::from("time"), + NamespaceType::User => String::from("user"), + NamespaceType::Uts => String::from("uts"), + } + } +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +/// Namespaces. +pub struct Namespace { + /// Namespace type. + #[serde(rename = "type")] + pub ns_type: NamespaceType, + /// Namespace file. If path is not specified, a new namespace is created. + #[serde(skip_serializing_if = "Option::is_none")] + pub path: Option, +} + +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +/// User namespace mappings. +pub struct IdMapping { + /// Starting uid/gid in the container. + pub containerID: u32, + /// Starting uid/gid on the host to be mapped to containerID. + pub hostID: u32, + /// Number of ids to be mapped. + pub size: u32, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +/// Offset for Time Namespace. +pub struct TimeOffsets { + #[serde(skip_serializing_if = "Option::is_none")] + /// Offset of clock (in seconds) in the container. + pub secs: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// Offset of clock (in nanoseconds) in the container. + pub nanosecs: Option, +} + +#[cfg(test)] +mod tests { + use serde_json; + + use super::*; + + #[test] + fn test_namespaces() { + let json = r#"{ + "namespaces": [ + { + "type": "pid", + "path": "/proc/1234/ns/pid" + }, + { + "type": "network", + "path": "/var/run/netns/neta" + }, + { + "type": "mount" + }, + { + "type": "ipc" + }, + { + "type": "uts" + }, + { + "type": "user" + }, + { + "type": "cgroup" + }, + { + "type": "time" + } + ] + }"#; + + #[derive(Serialize, Deserialize)] + struct Section { + namespaces: Vec, + } + + let ns: Section = serde_json::from_str(json).unwrap(); + assert_eq!(ns.namespaces.len(), 8); + assert_eq!(ns.namespaces[0].ns_type, NamespaceType::Pid); + assert_eq!(ns.namespaces[1].ns_type, NamespaceType::Network); + assert_eq!(ns.namespaces[2].ns_type, NamespaceType::Mount); + assert_eq!(ns.namespaces[3].ns_type, NamespaceType::Ipc); + assert_eq!(ns.namespaces[4].ns_type, NamespaceType::Uts); + assert_eq!(ns.namespaces[5].ns_type, NamespaceType::User); + assert_eq!(ns.namespaces[6].ns_type, NamespaceType::Cgroup); + assert_eq!(ns.namespaces[7].ns_type, NamespaceType::Time); + } + + #[test] + fn test_ids_mapping() { + let json = r#"{ + "uidMappings": [ + { + "containerID": 0, + "hostID": 1000, + "size": 32000 + } + ], + "gidMappings": [ + { + "containerID": 0, + "hostID": 1000, + "size": 32000 + } + ] + }"#; + + #[allow(non_snake_case)] + #[derive(Serialize, Deserialize)] + struct Section { + uidMappings: Vec, + gidMappings: Vec, + } + + let ids_mapping: Section = serde_json::from_str(json).unwrap(); + assert_eq!(ids_mapping.uidMappings.len(), 1); + assert_eq!(ids_mapping.uidMappings[0].size, 32000 as u32); + assert_eq!(ids_mapping.gidMappings.len(), 1); + assert_eq!(ids_mapping.gidMappings[0].size, 32000 as u32); + } + + #[test] + fn test_time_offsets() { + let json = r#"{ + "timeOffsets": { + "secs": 100 + } + }"#; + + #[allow(non_snake_case)] + #[derive(Serialize, Deserialize)] + struct Section { + timeOffsets: TimeOffsets, + } + + let time_offsets: Section = serde_json::from_str(json).unwrap(); + assert_eq!(time_offsets.timeOffsets.secs, Some(100)); + assert_eq!(time_offsets.timeOffsets.nanosecs, None); + } +} -- Gitee From 59776e775a70dc11956808ce38e66fd01879c8df Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Fri, 16 Aug 2024 11:18:22 +0800 Subject: [PATCH 334/489] oci_spec/linux: Add devices support --- ozonec/oci_spec/src/linux.rs | 64 ++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) diff --git a/ozonec/oci_spec/src/linux.rs b/ozonec/oci_spec/src/linux.rs index 0cb696f7..1db46a93 100644 --- a/ozonec/oci_spec/src/linux.rs +++ b/ozonec/oci_spec/src/linux.rs @@ -96,6 +96,32 @@ pub struct TimeOffsets { pub nanosecs: Option, } +/// Devices available in the container. +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Device { + /// Type of device. + #[serde(rename = "type")] + pub dev_type: String, + /// Full path to device inside container. + pub path: String, + /// Major number for the device. + #[serde(skip_serializing_if = "Option::is_none")] + pub major: Option, + /// Minor number for the device. + #[serde(skip_serializing_if = "Option::is_none")] + pub minor: Option, + /// File mode for the device. + #[serde(skip_serializing_if = "Option::is_none")] + pub fileMode: Option, + /// Id of device owner. + #[serde(skip_serializing_if = "Option::is_none")] + pub uid: Option, + /// Id of device group. + #[serde(skip_serializing_if = "Option::is_none")] + pub gid: Option, +} + #[cfg(test)] mod tests { use serde_json; @@ -203,4 +229,42 @@ mod tests { assert_eq!(time_offsets.timeOffsets.secs, Some(100)); assert_eq!(time_offsets.timeOffsets.nanosecs, None); } + + #[test] + fn test_devices() { + let json = r#"{ + "devices": [ + { + "path": "/dev/fuse", + "type": "c", + "major": 10, + "minor": 229, + "fileMode": 438, + "uid": 0, + "gid": 0 + }, + { + "path": "/dev/sda", + "type": "b", + "major": 8, + "minor": 0 + } + ] + }"#; + + #[derive(Serialize, Deserialize)] + struct Section { + devices: Vec, + } + + let section: Section = serde_json::from_str(json).unwrap(); + assert_eq!(section.devices.len(), 2); + assert_eq!(section.devices[1].path, "/dev/sda"); + assert_eq!(section.devices[1].dev_type, "b"); + assert_eq!(section.devices[1].major, Some(8)); + assert_eq!(section.devices[1].minor, Some(0)); + assert_eq!(section.devices[1].fileMode, None); + assert_eq!(section.devices[1].uid, None); + assert_eq!(section.devices[1].gid, None); + } } -- Gitee From ee88bb8dcfe0fe595caa4b9b27034654d2470651 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Fri, 16 Aug 2024 15:24:22 +0800 Subject: [PATCH 335/489] oci_spec/linux: Add cgroup support --- ozonec/oci_spec/src/linux.rs | 250 +++++++++++++++++++++++++++++++++++ 1 file changed, 250 insertions(+) diff --git a/ozonec/oci_spec/src/linux.rs b/ozonec/oci_spec/src/linux.rs index 1db46a93..00f845f4 100644 --- a/ozonec/oci_spec/src/linux.rs +++ b/ozonec/oci_spec/src/linux.rs @@ -122,6 +122,256 @@ pub struct Device { pub gid: Option, } +fn default_device_type() -> String { + "a".to_string() +} + +/// Allowed device in Device Cgroup. +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct CgroupDevice { + /// Whether the entry is allowed or denied. + pub allow: bool, + /// Type of device. + #[serde(default = "default_device_type", rename = "type")] + pub dev_type: String, + /// Major number for the device. + #[serde(skip_serializing_if = "Option::is_none")] + pub major: Option, + /// Minor number for the device. + #[serde(skip_serializing_if = "Option::is_none")] + pub minor: Option, + /// Cgroup permissions for device. + #[serde(skip_serializing_if = "Option::is_none")] + pub access: Option, +} + +/// Cgroup subsystem to set limits on the container's memory usage. +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct MemoryCgroup { + /// Limit of memory usage. + #[serde(skip_serializing_if = "Option::is_none")] + pub limit: Option, + /// Soft limit of memory usage. + #[serde(skip_serializing_if = "Option::is_none")] + pub reservation: Option, + /// Limits of memory +Swap usage. + #[serde(skip_serializing_if = "Option::is_none")] + pub swap: Option, + /// Hard limit for kernel memory. + #[serde(skip_serializing_if = "Option::is_none")] + pub kernel: Option, + /// Hard limit for kernel TCP buffer memory. + #[serde(skip_serializing_if = "Option::is_none")] + pub kernelTCP: Option, + /// Swappiness parameter of vmscan. + #[serde(skip_serializing_if = "Option::is_none")] + pub swappiness: Option, + /// Enable or disable the OOM killer. + #[serde(skip_serializing_if = "Option::is_none")] + pub disableOOMKiller: Option, + /// Enable or disable hierarchical memory accounting. + #[serde(skip_serializing_if = "Option::is_none")] + pub useHierarchy: Option, + /// Enable container memory usage check before setting a new limit. + #[serde(skip_serializing_if = "Option::is_none")] + pub checkBeforeUpdate: Option, +} + +/// Cgroup subsystems cpu and cpusets. +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct CpuCgroup { + /// Relative share of CPU time available to the tasks in a cgroup. + #[serde(skip_serializing_if = "Option::is_none")] + pub shares: Option, + /// Total amount of time in microseconds for which all tasks in a + /// cgroup can run during one period. + #[serde(skip_serializing_if = "Option::is_none")] + pub quota: Option, + /// Maximum amount of accumulated time in microseconds for which + /// all tasks in a cgroup can run additionally for burst during + /// one period. + #[serde(skip_serializing_if = "Option::is_none")] + pub burst: Option, + /// Period of time in microseconds for how regularly a cgroup's access + /// to CPU resources should be reallocated (CFS scheduler only) + #[serde(skip_serializing_if = "Option::is_none")] + pub period: Option, + /// Period of time in microseconds for the longest continuous period + /// in which the tasks in a cgrouop have access to CPU resources. + #[serde(skip_serializing_if = "Option::is_none")] + pub realtimeRuntime: Option, + /// Same as period but applies to realtime scheduler only. + #[serde(skip_serializing_if = "Option::is_none")] + pub realtimePeriod: Option, + /// List of CPUs the container will run on. + #[serde(skip_serializing_if = "Option::is_none")] + pub cpus: Option, + /// List of memory nodes the container will run on. + #[serde(skip_serializing_if = "Option::is_none")] + pub mems: Option, + /// Cgroups are configured with minimum weight. + #[serde(skip_serializing_if = "Option::is_none")] + pub idle: Option, +} + +/// Per-device bandwidth weights. +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct WeightDevice { + /// Major number for device. + pub major: i64, + /// Minor number for device. + pub minor: i64, + /// Bandwidth weight for the device. + #[serde(skip_serializing_if = "Option::is_none")] + pub weight: Option, + /// Bandwidth weight for the device while competing with the cgroup's + /// child cgroups (CFS scheduler only) + #[serde(skip_serializing_if = "Option::is_none")] + pub leafWeight: Option, +} + +/// Per-device bandwidth rate limits. +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct ThrottleDevice { + /// Major number for device. + pub major: i64, + /// Minor number for device. + pub minor: i64, + /// Bandwidth rate limit in bytes per second or IO rate limit for + /// the device. + pub rate: u64, +} + +/// Cgroup subsystem blkio which implements the block IO controller. +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct BlockIoCgroup { + /// Per-cgroup weight. + #[serde(skip_serializing_if = "Option::is_none")] + pub weight: Option, + /// Equivalents of weight for the purpose of deciding how much + /// weight tasks in the given cgroup has while competing with + /// the cgroup's child cgroups. + #[serde(skip_serializing_if = "Option::is_none")] + pub leafWeight: Option, + /// Array of per-device bandwidth weights. + #[serde(skip_serializing_if = "Option::is_none")] + pub weightDevice: Option>, + /// Array of per-device read bandwidth rate limits. + #[serde(skip_serializing_if = "Option::is_none")] + pub throttleReadBpsDevice: Option>, + /// Array of per-device write bandwidth rate limits. + #[serde(skip_serializing_if = "Option::is_none")] + pub throttleWriteBpsDevice: Option>, + /// Array of per-device read IO rate limits. + #[serde(skip_serializing_if = "Option::is_none")] + pub throttleReadIOPSDevice: Option>, + /// Array of per-device write IO rate limits. + #[serde(skip_serializing_if = "Option::is_none")] + pub throttleWriteIOPSDevice: Option>, +} + +/// hugetlb controller which allows to limit the HugeTLB reservations +/// (if supported) or usage (page fault). +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct HugetlbCgroup { + /// Hugepage size + pub pageSize: String, + /// Limit in bytes of hugepagesize HugeTLB reservations + /// (if supported) or usage. + pub limit: u64, +} + +/// Priority assigned to traffic originating from processes in the +/// group and egressing the system on various interfaces. +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct NetPriority { + /// Interface name. + pub name: String, + /// Priority applied to the interface. + pub priority: u32, +} + +/// Cgroup subsystems net_cls and net_prio. +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct NetworkCgroup { + /// Network class identifier the cgroup's network packets will + /// be tagged with. + #[serde(skip_serializing_if = "Option::is_none")] + pub classID: Option, + /// List of objects of the priorities assigned to traffic + /// originating from processes in the group and egressing the + /// system on various interfaces. + #[serde(skip_serializing_if = "Option::is_none")] + pub priorities: Option>, +} + +/// Cgroup subsystem pids. +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct PidsCgroup { + /// Maximum number of tasks in the cgroup. + pub limit: i64, +} + +/// Per-device rdma limit. +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct RdmaLimit { + /// Maximum number of hca_handles in the cgroup. + pub hcaHandles: Option, + /// Maximum number of hca_objects in the cgroup. + pub hcaObjects: Option, +} + +/// Cgroup subsystem rdma. +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct RdmaCgroup { + /// Rdma limit for mlx5_1. + #[serde(skip_serializing_if = "Option::is_none")] + pub mlx5_1: Option, + /// Rdma limit for mlx4_0. + #[serde(skip_serializing_if = "Option::is_none")] + pub mlx4_0: Option, + /// Rdma limit for rxe3. + #[serde(skip_serializing_if = "Option::is_none")] + pub rxe3: Option, +} + +/// Cgroups to restrict resource usage for a container and +/// handle device access. +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Cgroups { + /// Device cgroup settings. + #[serde(skip_serializing_if = "Option::is_none")] + pub devices: Option>, + /// Memory cgroup settings. + #[serde(skip_serializing_if = "Option::is_none")] + pub memory: Option, + /// Cpu and Cpuset cgroup settings. + #[serde(skip_serializing_if = "Option::is_none")] + pub cpu: Option, + /// Blkio cgroup settings. + #[serde(skip_serializing_if = "Option::is_none")] + pub blockIO: Option, + /// Hugetlb cgroup settings. + #[serde(skip_serializing_if = "Option::is_none")] + pub hugepageLimits: Option>, + /// Network cgroup settings. + #[serde(skip_serializing_if = "Option::is_none")] + pub network: Option, + /// Pids cgroup settings. + #[serde(skip_serializing_if = "Option::is_none")] + pub pids: Option, +} + #[cfg(test)] mod tests { use serde_json; -- Gitee From dd763f952719756ea67793ee2fc87eaaa0aa769a Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Fri, 16 Aug 2024 16:41:17 +0800 Subject: [PATCH 336/489] ozonec/linux: Add unit testcases for cpu/memory/blkio/device cgroup --- ozonec/oci_spec/src/linux.rs | 215 ++++++++++++++++++++++++++++++++++- 1 file changed, 214 insertions(+), 1 deletion(-) diff --git a/ozonec/oci_spec/src/linux.rs b/ozonec/oci_spec/src/linux.rs index 00f845f4..bffd1e3a 100644 --- a/ozonec/oci_spec/src/linux.rs +++ b/ozonec/oci_spec/src/linux.rs @@ -235,7 +235,7 @@ pub struct WeightDevice { /// Per-device bandwidth rate limits. #[allow(non_snake_case)] -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] pub struct ThrottleDevice { /// Major number for device. pub major: i64, @@ -517,4 +517,217 @@ mod tests { assert_eq!(section.devices[1].uid, None); assert_eq!(section.devices[1].gid, None); } + + #[test] + fn test_cgroup_devices() { + let json = r#"{ + "devices": [ + { + "allow": false + }, + { + "allow": true, + "type": "c", + "major": 10, + "minor": 229, + "access": "rw" + } + ] + }"#; + + #[derive(Serialize, Deserialize)] + struct Section { + devices: Vec, + } + + let section: Section = serde_json::from_str(json).unwrap(); + assert_eq!(section.devices.len(), 2); + assert_eq!(section.devices[0].allow, false); + assert_eq!(section.devices[0].dev_type, "a"); + assert_eq!(section.devices[0].major, None); + assert_eq!(section.devices[0].minor, None); + assert_eq!(section.devices[0].access, None); + assert_eq!(section.devices[1].allow, true); + assert_eq!(section.devices[1].dev_type, "c"); + assert_eq!(section.devices[1].major, Some(10)); + assert_eq!(section.devices[1].minor, Some(229)); + assert_eq!(section.devices[1].access, Some("rw".to_string())); + } + + #[test] + fn test_cgroup_memory_01() { + let json = r#"{ + "memory": { + "limit": 536870912, + "reservation": 536870912, + "swap": 536870912, + "kernel": -1, + "kernelTCP": -1, + "swappiness": 0, + "disableOOMKiller": false + } + }"#; + + #[derive(Serialize, Deserialize)] + struct Section { + memory: MemoryCgroup, + } + + let section: Section = serde_json::from_str(json).unwrap(); + assert_eq!(section.memory.limit, Some(536870912)); + assert_eq!(section.memory.reservation, Some(536870912)); + assert_eq!(section.memory.swap, Some(536870912)); + assert_eq!(section.memory.kernel, Some(-1)); + assert_eq!(section.memory.kernelTCP, Some(-1)); + assert_eq!(section.memory.swappiness, Some(0)); + assert_eq!(section.memory.disableOOMKiller, Some(false)); + assert_eq!(section.memory.useHierarchy, None); + assert_eq!(section.memory.checkBeforeUpdate, None); + } + + #[test] + fn test_cgroup_memory_02() { + let json = r#"{ + "memory": { + "useHierarchy": true, + "checkBeforeUpdate": true + } + }"#; + + #[derive(Serialize, Deserialize)] + struct Section { + memory: MemoryCgroup, + } + + let section: Section = serde_json::from_str(json).unwrap(); + assert_eq!(section.memory.limit, None); + assert_eq!(section.memory.reservation, None); + assert_eq!(section.memory.swap, None); + assert_eq!(section.memory.kernel, None); + assert_eq!(section.memory.kernelTCP, None); + assert_eq!(section.memory.swappiness, None); + assert_eq!(section.memory.disableOOMKiller, None); + assert_eq!(section.memory.useHierarchy, Some(true)); + assert_eq!(section.memory.checkBeforeUpdate, Some(true)); + } + + #[test] + fn test_cgroup_cpu_01() { + let json = r#"{ + "cpu": { + "shares": 1024, + "quota": 1000000, + "burst": 1000000, + "period": 500000, + "realtimeRuntime": 950000, + "realtimePeriod": 1000000, + "cpus": "2-3", + "mems": "0-7", + "idle": 0 + } + }"#; + + #[derive(Serialize, Deserialize)] + struct Section { + cpu: CpuCgroup, + } + + let section: Section = serde_json::from_str(json).unwrap(); + assert_eq!(section.cpu.shares, Some(1024)); + assert_eq!(section.cpu.quota, Some(1000000)); + assert_eq!(section.cpu.burst, Some(1000000)); + assert_eq!(section.cpu.period, Some(500000)); + assert_eq!(section.cpu.realtimeRuntime, Some(950000)); + assert_eq!(section.cpu.realtimePeriod, Some(1000000)); + assert_eq!(section.cpu.cpus, Some("2-3".to_string())); + assert_eq!(section.cpu.mems, Some("0-7".to_string())); + assert_eq!(section.cpu.idle, Some(0)); + } + + #[test] + fn test_cgroup_cpu_02() { + let json = r#"{ + "cpu": {} + }"#; + + #[derive(Serialize, Deserialize)] + struct Section { + cpu: CpuCgroup, + } + + let section: Section = serde_json::from_str(json).unwrap(); + assert_eq!(section.cpu.shares, None); + assert_eq!(section.cpu.quota, None); + assert_eq!(section.cpu.burst, None); + assert_eq!(section.cpu.period, None); + assert_eq!(section.cpu.realtimeRuntime, None); + assert_eq!(section.cpu.realtimePeriod, None); + assert_eq!(section.cpu.cpus, None); + assert_eq!(section.cpu.mems, None); + assert_eq!(section.cpu.idle, None); + } + + #[test] + fn test_cgroup_blkio() { + let json = r#"{ + "blockIO": { + "weight": 10, + "leafWeight": 10, + "weightDevice": [ + { + "major": 8, + "minor": 0, + "weight": 500, + "leafWeight": 300 + }, + { + "major": 8, + "minor": 16 + } + ], + "throttleReadBpsDevice": [ + { + "major": 8, + "minor": 0, + "rate": 600 + }, + { + "major": 8, + "minor": 16, + "rate": 300 + } + ] + } + }"#; + + #[allow(non_snake_case)] + #[derive(Serialize, Deserialize)] + struct Section { + blockIO: BlockIoCgroup, + } + + let section: Section = serde_json::from_str(json).unwrap(); + assert_eq!(section.blockIO.weight, Some(10)); + assert_eq!(section.blockIO.leafWeight, Some(10)); + assert_eq!(section.blockIO.throttleReadIOPSDevice, None); + assert_eq!(section.blockIO.throttleWriteBpsDevice, None); + assert_eq!(section.blockIO.throttleWriteIOPSDevice, None); + + let weight_device = section.blockIO.weightDevice.as_ref().unwrap(); + assert_eq!(weight_device.len(), 2); + assert_eq!(weight_device[0].major, 8); + assert_eq!(weight_device[0].minor, 0); + assert_eq!(weight_device[0].weight, Some(500)); + assert_eq!(weight_device[0].leafWeight, Some(300)); + assert_eq!(weight_device[1].major, 8); + assert_eq!(weight_device[1].minor, 16); + assert_eq!(weight_device[1].weight, None); + assert_eq!(weight_device[1].leafWeight, None); + + let throttle = section.blockIO.throttleReadBpsDevice.as_ref().unwrap(); + assert_eq!(throttle.len(), 2); + assert_eq!(throttle[1].major, 8); + assert_eq!(throttle[1].minor, 16); + assert_eq!(throttle[1].rate, 300); + } } -- Gitee From f60900cf648d96a976767efc6d55eac1a59dcc74 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Fri, 16 Aug 2024 17:41:13 +0800 Subject: [PATCH 337/489] ozonec/linux: Add unit testcases for hugetlb/network/rdma/pid cgroups --- ozonec/oci_spec/src/linux.rs | 117 ++++++++++++++++++++++++++++++++++- 1 file changed, 116 insertions(+), 1 deletion(-) diff --git a/ozonec/oci_spec/src/linux.rs b/ozonec/oci_spec/src/linux.rs index bffd1e3a..236d0e84 100644 --- a/ozonec/oci_spec/src/linux.rs +++ b/ozonec/oci_spec/src/linux.rs @@ -289,7 +289,7 @@ pub struct HugetlbCgroup { /// Priority assigned to traffic originating from processes in the /// group and egressing the system on various interfaces. -#[derive(Serialize, Deserialize, Debug, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] pub struct NetPriority { /// Interface name. pub name: String, @@ -730,4 +730,119 @@ mod tests { assert_eq!(throttle[1].minor, 16); assert_eq!(throttle[1].rate, 300); } + + #[test] + fn test_cgroup_hugetlb() { + let json = r#"{ + "hugepageLimits": [ + { + "pageSize": "2MB", + "limit": 209715200 + } + ] + }"#; + + #[allow(non_snake_case)] + #[derive(Serialize, Deserialize)] + struct Section { + hugepageLimits: Vec, + } + + let section: Section = serde_json::from_str(json).unwrap(); + assert_eq!(section.hugepageLimits[0].pageSize, "2MB"); + assert_eq!(section.hugepageLimits[0].limit, 209715200); + } + + #[test] + fn test_cgroup_network_01() { + let json = r#"{ + "network": { + "classID": 1048577, + "priorities": [ + { + "name": "eth0", + "priority": 500 + } + ] + } + }"#; + + #[derive(Serialize, Deserialize)] + struct Section { + network: NetworkCgroup, + } + + let section: Section = serde_json::from_str(json).unwrap(); + assert_eq!(section.network.classID, Some(1048577)); + let priorities = section.network.priorities.as_ref().unwrap(); + assert_eq!(priorities[0].name, "eth0"); + assert_eq!(priorities[0].priority, 500); + } + + #[test] + fn test_cgroup_network_02() { + let json = r#"{ + "network": {} + }"#; + + #[derive(Serialize, Deserialize)] + struct Section { + network: NetworkCgroup, + } + + let section: Section = serde_json::from_str(json).unwrap(); + assert_eq!(section.network.classID, None); + assert_eq!(section.network.priorities, None); + } + + #[test] + fn test_cgroup_pid() { + let json = r#"{ + "pids": { + "limit": 32771 + } + }"#; + + #[derive(Serialize, Deserialize)] + struct Section { + pids: PidsCgroup, + } + + let section: Section = serde_json::from_str(json).unwrap(); + assert_eq!(section.pids.limit, 32771); + } + + #[test] + fn test_cgroup_rdma() { + let json = r#"{ + "rdma": { + "mlx5_1": { + "hcaHandles": 3, + "hcaObjects": 10000 + }, + "mlx4_0": { + "hcaObjects": 1000 + }, + "rxe3": { + "hcaHandles": 10000 + } + } + }"#; + + #[derive(Serialize, Deserialize)] + struct Section { + rdma: RdmaCgroup, + } + + let section: Section = serde_json::from_str(json).unwrap(); + let rdma_limit = section.rdma.mlx5_1.as_ref().unwrap(); + assert_eq!(rdma_limit.hcaHandles, Some(3)); + assert_eq!(rdma_limit.hcaObjects, Some(10000)); + let rdma_limit = section.rdma.mlx4_0.as_ref().unwrap(); + assert_eq!(rdma_limit.hcaHandles, None); + assert_eq!(rdma_limit.hcaObjects, Some(1000)); + let rdma_limit = section.rdma.rxe3.as_ref().unwrap(); + assert_eq!(rdma_limit.hcaHandles, Some(10000)); + assert_eq!(rdma_limit.hcaObjects, None); + } } -- Gitee From e7bf01b63f85d5f30d0792237864f22c5041ed2e Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Fri, 16 Aug 2024 17:56:03 +0800 Subject: [PATCH 338/489] ozonec/linux: Add IntelRdt support --- ozonec/oci_spec/src/linux.rs | 58 ++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/ozonec/oci_spec/src/linux.rs b/ozonec/oci_spec/src/linux.rs index 236d0e84..5d5c2458 100644 --- a/ozonec/oci_spec/src/linux.rs +++ b/ozonec/oci_spec/src/linux.rs @@ -372,6 +372,28 @@ pub struct Cgroups { pub pids: Option, } +#[cfg(target_arch = "x86_64")] +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +/// Intel Resource Director Technology +pub struct IntelRdt { + #[serde(skip_serializing_if = "Option::is_none")] + /// Identity for RDT Class of Service (CLOS). + pub closID: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// Schema for L3 cache id and capacity bitmask (CBM). + pub l3CacheSchema: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// Schema of memory bandwidth per L3 cache id. + pub memBwSchema: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// If Intel RDT CMT should be enabled. + pub enableCMT: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// If Intel RDT MBM should be enabled. + pub enableMBM: Option, +} + #[cfg(test)] mod tests { use serde_json; @@ -845,4 +867,40 @@ mod tests { assert_eq!(rdma_limit.hcaHandles, Some(10000)); assert_eq!(rdma_limit.hcaObjects, None); } + + #[cfg(target_arch = "x86_64")] + #[test] + fn test_intel_rdt() { + let json = r#"{ + "intelRdt": { + "closID": "guaranteed_group", + "l3CacheSchema": "L3:0=7f0;1=1f", + "memBwSchema": "MB:0=20;1=70", + "enableCMT": true, + "enableMBM": true + } + }"#; + + #[allow(non_snake_case)] + #[derive(Serialize, Deserialize)] + struct Section { + intelRdt: IntelRdt, + } + + let section: Section = serde_json::from_str(json).unwrap(); + assert_eq!( + section.intelRdt.closID, + Some("guaranteed_group".to_string()) + ); + assert_eq!( + section.intelRdt.l3CacheSchema, + Some("L3:0=7f0;1=1f".to_string()) + ); + assert_eq!( + section.intelRdt.memBwSchema, + Some("MB:0=20;1=70".to_string()) + ); + assert_eq!(section.intelRdt.enableCMT, Some(true)); + assert_eq!(section.intelRdt.enableMBM, Some(true)); + } } -- Gitee From 388306c86fa8fe6f36ebee14252c8d5305558296 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Sun, 18 Aug 2024 10:42:21 +0800 Subject: [PATCH 339/489] ozonec/linux: Add seccomp support --- ozonec/oci_spec/src/linux.rs | 131 +++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) diff --git a/ozonec/oci_spec/src/linux.rs b/ozonec/oci_spec/src/linux.rs index 5d5c2458..88078d1c 100644 --- a/ozonec/oci_spec/src/linux.rs +++ b/ozonec/oci_spec/src/linux.rs @@ -394,6 +394,98 @@ pub struct IntelRdt { pub enableMBM: Option, } +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +#[repr(u32)] +/// Action for seccomp rules. +pub enum SeccompAction { + ScmpActKill = 0x0000_0000, + ScmpActKillProcess = 0x8000_0000, + ScmpActTrap = 0x0003_0000, + ScmpActErrno = 0x0005_0001, + ScmpActNotify = 0x7fc0_0000, + ScmpActTrace = 0x7ff0_0001, + ScmpActLog = 0x7ffc_0000, + ScmpActAllow = 0x7fff_0000, +} + +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, Default)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +#[repr(u32)] +/// Operator for syscall arguments in seccomp. +pub enum SeccompOp { + ScmpCmpNe = 1, + ScmpCmpLt = 2, + ScmpCmpLe = 3, + #[default] + ScmpCmpEq = 4, + ScmpCmpGe = 5, + ScmpCmpGt = 6, + ScmpCmpMaskedEq = 7, +} + +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +/// The specific syscall in seccomp. +pub struct SeccompSyscallArg { + /// Index for syscall arguments. + pub index: usize, + /// Value for syscall arguments. + pub value: u64, + #[serde(skip_serializing_if = "Option::is_none")] + /// Value for syscall arguments. + pub valueTwo: Option, + /// Operator for syscall arguments. + pub op: SeccompOp, +} + +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +/// Match a syscall in seccomp. +pub struct SeccompSyscall { + /// Names of the syscalls. + pub names: Vec, + /// Action for seccomp rules. + pub action: SeccompAction, + #[serde(skip_serializing_if = "Option::is_none")] + /// Errno return code to use. + pub errnoRet: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// Specific syscall in seccomp. + pub args: Option>, +} + +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +/// Seccomp provides application sandboxing mechanism in the Linux kernel. +pub struct Seccomp { + /// Default action for seccomp. + pub defaultAction: SeccompAction, + #[serde(skip_serializing_if = "Option::is_none")] + /// Errno return code to use. + pub defaultErrnoRet: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// Architecture used for system calls. + pub architectures: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + /// List of flags to use with seccomp. + pub flags: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + /// Path of UNIX domain socket over which the runtime will send the + /// container process state data structure when the SCMP_ACT_NOTIFY + /// action is used. + pub listennerPath: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// Seccomp file descriptor returned by the seccomp syscall. + pub seccompFd: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// Opaque data to pass to the seccomp agent. + pub listenerMetadata: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// Match a syscall in seccomp. + pub syscalls: Option>, +} + #[cfg(test)] mod tests { use serde_json; @@ -903,4 +995,43 @@ mod tests { assert_eq!(section.intelRdt.enableCMT, Some(true)); assert_eq!(section.intelRdt.enableMBM, Some(true)); } + + #[test] + fn test_seccomp() { + let json = r#"{ + "seccomp": { + "defaultAction": "SCMP_ACT_ALLOW", + "architectures": [ + "SCMP_ARCH_X86", + "SCMP_ARCH_X32" + ], + "syscalls": [ + { + "names": [ + "getcwd", + "chmod" + ], + "action": "SCMP_ACT_ERRNO" + } + ] + } + }"#; + + #[derive(Serialize, Deserialize)] + struct Section { + seccomp: Seccomp, + } + + let section: Section = serde_json::from_str(json).unwrap(); + assert_eq!(section.seccomp.defaultAction, SeccompAction::ScmpActAllow); + let architectures = section.seccomp.architectures.as_ref().unwrap(); + assert_eq!(architectures.len(), 2); + assert_eq!(architectures[0], "SCMP_ARCH_X86"); + assert_eq!(architectures[1], "SCMP_ARCH_X32"); + let syscall_names = section.seccomp.syscalls.as_ref().unwrap(); + assert_eq!(syscall_names[0].names.len(), 2); + assert_eq!(syscall_names[0].names[0], "getcwd"); + assert_eq!(syscall_names[0].names[1], "chmod"); + assert_eq!(syscall_names[0].action, SeccompAction::ScmpActErrno); + } } -- Gitee From 2e82d7361abc0bc806ddbcb0a0f09f233420050e Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Sun, 18 Aug 2024 11:33:59 +0800 Subject: [PATCH 340/489] ozonec/linux: Add LinuxPlatform structure for Linux specific configuration --- ozonec/oci_spec/src/linux.rs | 90 +++++++++++++++++++++++++++++++++++- 1 file changed, 89 insertions(+), 1 deletion(-) diff --git a/ozonec/oci_spec/src/linux.rs b/ozonec/oci_spec/src/linux.rs index 88078d1c..5fa0af26 100644 --- a/ozonec/oci_spec/src/linux.rs +++ b/ozonec/oci_spec/src/linux.rs @@ -10,7 +10,7 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use std::path::PathBuf; +use std::{collections::HashMap, path::PathBuf}; use anyhow::{anyhow, Result}; use nix::sched::CloneFlags; @@ -486,6 +486,76 @@ pub struct Seccomp { pub syscalls: Option>, } +#[derive(Serialize, Deserialize, Debug, Clone)] +/// Linux execution personality. +pub struct Personality { + /// Execution domain. + pub domain: String, + /// Additional flags to apply. + pub flags: Option>, +} + +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +/// Linux-specific configuration. +pub struct LinuxPlatform { + /// A namespace wraps a global system resource in an abstraction. + pub namespaces: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + /// User namespace uid mappings from the host to the container. + pub uidMappings: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + /// User namespace gid mappings from the host to the container. + pub gidMappings: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + /// Offset for Time Namespace. + pub timeOffsets: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// Lists devices that MUST be available in the container. + pub devices: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + /// Path to the cgroups. + pub cgroupsPath: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// Rootfs's mount propagation. + pub rootfsPropagation: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// Mask over the provided paths inside the container so + /// that they cannot be read. + pub maskedPaths: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + /// Set the provided paths as readonly inside the container. + pub readonlyPaths: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + /// Selinux context for the mounts in the container. + pub mountLabel: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// Linux execution personality. + pub personality: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// Configure a container's cgroups. + pub resources: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// The cgroup subsystem rdma. + pub rdma: Option, + #[serde(skip_serializing_if = "Option::is_none")] + /// Allows cgroup v2 parameters to be to be set and modified + /// for the container. + pub unified: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + /// Kernel parameters to be modified at runtime for the + /// container. + pub sysctl: Option>, + #[serde(skip_serializing_if = "Option::is_none")] + /// Seccomp provides application sandboxing mechanism in + /// the Linux kernel. + pub seccomp: Option, + #[cfg(target_arch = "x86_64")] + #[serde(skip_serializing_if = "Option::is_none")] + /// Intel Resource Director Technology. + pub intelRdt: Option, +} + #[cfg(test)] mod tests { use serde_json; @@ -1034,4 +1104,22 @@ mod tests { assert_eq!(syscall_names[0].names[1], "chmod"); assert_eq!(syscall_names[0].action, SeccompAction::ScmpActErrno); } + + #[test] + fn test_personality() { + let json = r#"{ + "personality": { + "domain": "LINUX" + } + }"#; + + #[derive(Serialize, Deserialize)] + struct Section { + personality: Personality, + } + + let section: Section = serde_json::from_str(json).unwrap(); + assert_eq!(section.personality.domain, "LINUX"); + assert_eq!(section.personality.flags, None); + } } -- Gitee From 1a65ffb5f70d843317f11014880bced688d50eb9 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Sun, 18 Aug 2024 17:14:37 +0800 Subject: [PATCH 341/489] ozonec/oci_spec: Add process support --- ozonec/oci_spec/Cargo.toml | 1 + ozonec/oci_spec/src/lib.rs | 3 + ozonec/oci_spec/src/linux.rs | 104 ++++++++++++++++++++++++++++ ozonec/oci_spec/src/posix.rs | 43 ++++++++++++ ozonec/oci_spec/src/process.rs | 120 +++++++++++++++++++++++++++++++++ 5 files changed, 271 insertions(+) create mode 100644 ozonec/oci_spec/src/process.rs diff --git a/ozonec/oci_spec/Cargo.toml b/ozonec/oci_spec/Cargo.toml index b18928f4..e5923ad5 100644 --- a/ozonec/oci_spec/Cargo.toml +++ b/ozonec/oci_spec/Cargo.toml @@ -8,6 +8,7 @@ description = "Open Container Initiative (OCI) Specifications in Rust" [dependencies] anyhow = "= 1.0.71" +libc = "= 0.2.146" nix = "= 0.26.2" serde = { version = "= 1.0.163", features = ["derive"] } serde_json = "= 1.0.96" diff --git a/ozonec/oci_spec/src/lib.rs b/ozonec/oci_spec/src/lib.rs index c7b44ff0..3f79329b 100644 --- a/ozonec/oci_spec/src/lib.rs +++ b/ozonec/oci_spec/src/lib.rs @@ -10,8 +10,11 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. +#[cfg(target_os = "linux")] pub mod linux; +#[cfg(target_os = "linux")] pub mod posix; +pub mod process; pub mod runtime; pub mod state; pub mod vm; diff --git a/ozonec/oci_spec/src/linux.rs b/ozonec/oci_spec/src/linux.rs index 5fa0af26..234132ee 100644 --- a/ozonec/oci_spec/src/linux.rs +++ b/ozonec/oci_spec/src/linux.rs @@ -556,6 +556,110 @@ pub struct LinuxPlatform { pub intelRdt: Option, } +/// Arrays that specifies the sets of capabilities for the process. +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Capbilities { + /// Array of effective capabilities that are kept for the process. + #[serde(skip_serializing_if = "Option::is_none")] + pub effective: Option>, + /// Array of bounding capabilities that are kept for the process. + #[serde(skip_serializing_if = "Option::is_none")] + pub bounding: Option>, + /// Array of inheritable capabilities that are kept for the process. + #[serde(skip_serializing_if = "Option::is_none")] + pub inheritable: Option>, + /// Array of permitted capabilities that are kept for the process. + #[serde(skip_serializing_if = "Option::is_none")] + pub permitted: Option>, + /// Array of ambient capabilities that are kept for the process. + #[serde(skip_serializing_if = "Option::is_none")] + pub ambient: Option>, +} + +/// Scheduling policy. +#[derive(Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum SchedPolicy { + SchedOther, + SchedFifo, + SchedRr, + SchedBatch, + SchedIdle, +} + +impl From for libc::c_int { + fn from(value: SchedPolicy) -> Self { + match value { + SchedPolicy::SchedOther => libc::SCHED_OTHER, + SchedPolicy::SchedFifo => libc::SCHED_FIFO, + SchedPolicy::SchedRr => libc::SCHED_RR, + SchedPolicy::SchedBatch => libc::SCHED_BATCH, + SchedPolicy::SchedIdle => libc::SCHED_IDLE, + } + } +} + +/// Scheduler properties for the process. +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Scheduler { + /// Scheduling policy. + pub policy: SchedPolicy, + /// Nice value for the process, affecting its priority. + #[serde(skip_serializing_if = "Option::is_none")] + pub nice: Option, + /// Static priority of the process. + #[serde(skip_serializing_if = "Option::is_none")] + pub priority: Option, + /// Array of strings representing scheduling flags. + #[serde(skip_serializing_if = "Option::is_none")] + pub flags: Option>, + /// Amount of time in nanoseconds during which the process is + /// allowed to run in a given period, used by the deadline + /// scheduler. + #[serde(skip_serializing_if = "Option::is_none")] + pub runtime: Option, + /// Absolute deadline for the process to complete its execution, + /// used by the deadline scheduler. + #[serde(skip_serializing_if = "Option::is_none")] + pub deadline: Option, + /// Length of the period in nanoseconds used for determining the + /// process runtime, used by the deadline scheduler. + #[serde(skip_serializing_if = "Option::is_none")] + pub period: Option, +} + +/// I/O scheduling class. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] +#[serde(rename_all = "SCREAMING_SNAKE_CASE")] +pub enum IoPriClass { + IoprioClassRt, + IoprioClassBe, + IoprioClassIdle, +} + +/// I/O priority settings for the container's processes within the +/// process group. +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct IoPriority { + /// I/O scheduling class. + pub class: IoPriClass, + /// Priority level within the class. + pub priority: i64, +} + +/// CPU affinity used to execute the process. +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct ExecCpuAffinity { + /// List of CPUs a runtime parent process to be run on initially, + /// before the transition to container's cgroup. + #[serde(skip_serializing_if = "Option::is_none")] + pub initial: Option, + /// List of CPUs the process will be run on after the transition + /// to container's cgroup. + #[serde(skip_serializing_if = "Option::is_none", rename = "final")] + pub final_cpus: Option, +} + #[cfg(test)] mod tests { use serde_json; diff --git a/ozonec/oci_spec/src/posix.rs b/ozonec/oci_spec/src/posix.rs index 4524f4b2..03396e42 100644 --- a/ozonec/oci_spec/src/posix.rs +++ b/ozonec/oci_spec/src/posix.rs @@ -9,3 +9,46 @@ // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. + +use serde::{Deserialize, Serialize}; + +/// Container's root filesystem. +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +pub struct Root { + /// Path to the root filesystem for the container. + pub path: String, + #[serde(default)] + /// If true then the root filesystem MUST be read-only inside the container. + pub readonly: bool, +} + +/// Resource limits for the process. +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Rlimits { + /// The platform resource being limited. + #[serde(rename = "type")] + pub rlimit_type: String, + /// Value of the limit enforced for the corresponding resource. + pub soft: u64, + /// Ceiling for the soft limit that could be set by an + /// unprivileged process. + pub hard: u64, +} + +/// The user for the process that allows specific control over which user +/// the process runs as. +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct User { + /// User ID in the container namespace. + pub uid: u32, + /// Group ID in the container namespace. + pub gid: u32, + /// [umask][umask_2] of the user. + #[serde(skip_serializing_if = "Option::is_none")] + pub umask: Option, + /// Additional group IDs in the container namespace to be added + /// to the process. + #[serde(skip_serializing_if = "Option::is_none")] + pub additionalGids: Option>, +} diff --git a/ozonec/oci_spec/src/process.rs b/ozonec/oci_spec/src/process.rs new file mode 100644 index 00000000..fc325812 --- /dev/null +++ b/ozonec/oci_spec/src/process.rs @@ -0,0 +1,120 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use serde::{Deserialize, Serialize}; + +use crate::{ + linux::{Capbilities, ExecCpuAffinity, IdMapping, IoPriority, Scheduler}, + posix::{Rlimits, User}, +}; + +/// Additional mounts beyond root. +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Mount { + /// Destination of mount point: path inside container. + pub destination: String, + /// A device name, but can also be a file or directory name for bind mounts + /// or a dummy. + #[serde(skip_serializing_if = "Option::is_none")] + pub source: Option, + /// Mount options of the filesystem to be used. + #[serde(skip_serializing_if = "Option::is_none")] + pub options: Option>, + /// The type of the filesystem to be mounted. + #[serde(skip_serializing_if = "Option::is_none", rename = "type")] + pub fs_type: Option, + /// The mapping to convert UIDs from the source file system to the + /// destination mount point. + #[serde(skip_serializing_if = "Option::is_none")] + pub uidMappings: Option, + /// The mapping to convert GIDs from the source file system to the + /// destination mount point. + #[serde(skip_serializing_if = "Option::is_none")] + pub gidMappings: Option, +} + +/// Console size in characters of the terminal. +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct ConsoleSize { + /// Height size in characters. + #[serde(skip_serializing_if = "Option::is_none")] + pub height: Option, + /// Width size in characters. + #[serde(skip_serializing_if = "Option::is_none")] + pub width: Option, +} + +/// Container process. +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Process { + /// Working directory that will be set for the executable. + pub cwd: String, + /// Similar semantics to IEEE Std 1003.1-2008 execvp's argv. + #[serde(skip_serializing_if = "Option::is_none")] + pub args: Option>, + /// Same semantics as IEEE Std 1003.1-2008's environ. + #[serde(skip_serializing_if = "Option::is_none")] + pub env: Option>, + /// Whether a terminal is attached to the process. + #[serde(default)] + pub terminal: bool, + /// Console size in characters of the terminal. + #[serde(skip_serializing_if = "Option::is_none")] + pub consoleSize: Option, + /// Full command line to be executed on Windows. + #[cfg(target_os = "windows")] + pub commandLine: Option, + /// Resource limits for the process. + #[cfg(target_os = "linux")] + #[serde(skip_serializing_if = "Option::is_none")] + pub rlimits: Option>, + /// Name of the AppArmor profile for the process. + #[cfg(target_os = "linux")] + #[serde(skip_serializing_if = "Option::is_none")] + pub apparmorProfile: Option, + /// Arrays that specifies the sets of capabilities for the process. + #[cfg(target_os = "linux")] + #[serde(skip_serializing_if = "Option::is_none")] + pub capabilities: Option, + /// Setting noNewPrivileges to true prevents the process from + /// gaining additional privileges. + #[cfg(target_os = "linux")] + #[serde(skip_serializing_if = "Option::is_none")] + pub noNewPrivileges: Option, + /// Oom-killer score in [pid]/oom_score_adj for the process's + /// [pid] in a proc pseudo-filesystem. + #[cfg(target_os = "linux")] + #[serde(skip_serializing_if = "Option::is_none")] + pub oomScoreAdj: Option, + /// Scheduler properties for the process. + #[cfg(target_os = "linux")] + #[serde(skip_serializing_if = "Option::is_none")] + pub scheduler: Option, + /// SELinux label for the process. + #[cfg(target_os = "linux")] + #[serde(skip_serializing_if = "Option::is_none")] + pub selinuxLabel: Option, + /// I/O priority settings for the container's processes within + /// the process group. + #[cfg(target_os = "linux")] + #[serde(skip_serializing_if = "Option::is_none")] + pub ioPriority: Option, + /// CPU affinity used to execute the process. + #[cfg(target_os = "linux")] + #[serde(skip_serializing_if = "Option::is_none")] + pub execCPUAffinity: Option, + /// The user for the process that allows specific control over + /// which user the process runs as. + pub user: User, +} -- Gitee From cb036e410e9e691477a90983cfb9d474843dbaa0 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Mon, 19 Aug 2024 09:39:21 +0800 Subject: [PATCH 342/489] oci_spec/process: Add an unit testcase for process --- ozonec/oci_spec/src/process.rs | 147 +++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/ozonec/oci_spec/src/process.rs b/ozonec/oci_spec/src/process.rs index fc325812..a32db540 100644 --- a/ozonec/oci_spec/src/process.rs +++ b/ozonec/oci_spec/src/process.rs @@ -118,3 +118,150 @@ pub struct Process { /// which user the process runs as. pub user: User, } + +#[cfg(test)] +mod tests { + use crate::linux::IoPriClass; + + use super::*; + use serde_json; + + #[test] + fn test_process() { + let json = r#"{ + "process": { + "terminal": true, + "consoleSize": { + "height": 25, + "width": 80 + }, + "user": { + "uid": 1, + "gid": 1, + "umask": 63, + "additionalGids": [5, 6] + }, + "env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "TERM=xterm" + ], + "cwd": "/root", + "args": [ + "sh" + ], + "apparmorProfile": "acme_secure_profile", + "selinuxLabel": "system_u:system_r:svirt_lxc_net_t:s0:c124,c675", + "ioPriority": { + "class": "IOPRIO_CLASS_IDLE", + "priority": 4 + }, + "noNewPrivileges": true, + "capabilities": { + "bounding": [ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE" + ], + "permitted": [ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE" + ], + "inheritable": [ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE" + ], + "effective": [ + "CAP_AUDIT_WRITE", + "CAP_KILL" + ], + "ambient": [ + "CAP_NET_BIND_SERVICE" + ] + }, + "rlimits": [ + { + "type": "RLIMIT_NOFILE", + "hard": 1024, + "soft": 1024 + } + ], + "execCPUAffinity": { + "initial": "7", + "final": "0-3,7" + } + } + }"#; + + #[allow(non_snake_case)] + #[derive(Serialize, Deserialize)] + struct Section { + process: Process, + } + + let section: Section = serde_json::from_str(json).unwrap(); + assert_eq!(section.process.terminal, true); + let console_size = section.process.consoleSize.as_ref().unwrap(); + assert_eq!(console_size.height, Some(25)); + assert_eq!(console_size.width, Some(80)); + assert_eq!(section.process.user.uid, 1); + assert_eq!(section.process.user.gid, 1); + assert_eq!(section.process.user.umask, Some(63)); + assert_eq!(section.process.user.additionalGids, Some(vec![5, 6])); + let env = section.process.env.as_ref().unwrap(); + assert_eq!(env.len(), 2); + assert_eq!( + env[0], + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + ); + assert_eq!(env[1], "TERM=xterm"); + assert_eq!(section.process.cwd, "/root"); + let args = section.process.args.as_ref().unwrap(); + assert_eq!(args.len(), 1); + assert_eq!(args[0], "sh"); + assert_eq!( + section.process.apparmorProfile, + Some("acme_secure_profile".to_string()) + ); + assert_eq!( + section.process.selinuxLabel, + Some("system_u:system_r:svirt_lxc_net_t:s0:c124,c675".to_string()) + ); + let io_pri = section.process.ioPriority.as_ref().unwrap(); + assert_eq!(io_pri.class, IoPriClass::IoprioClassIdle); + assert_eq!(io_pri.priority, 4); + assert_eq!(section.process.noNewPrivileges, Some(true)); + let caps = section.process.capabilities.as_ref().unwrap(); + let bonding_caps = caps.bounding.as_ref().unwrap(); + assert_eq!(bonding_caps.len(), 3); + assert_eq!(bonding_caps[0], "CAP_AUDIT_WRITE"); + assert_eq!(bonding_caps[1], "CAP_KILL"); + assert_eq!(bonding_caps[2], "CAP_NET_BIND_SERVICE"); + let permitted_caps = caps.permitted.as_ref().unwrap(); + assert_eq!(permitted_caps.len(), 3); + assert_eq!(permitted_caps[0], "CAP_AUDIT_WRITE"); + assert_eq!(permitted_caps[1], "CAP_KILL"); + assert_eq!(permitted_caps[2], "CAP_NET_BIND_SERVICE"); + let inheritable_caps = caps.inheritable.as_ref().unwrap(); + assert_eq!(inheritable_caps.len(), 3); + assert_eq!(inheritable_caps[0], "CAP_AUDIT_WRITE"); + assert_eq!(inheritable_caps[1], "CAP_KILL"); + assert_eq!(inheritable_caps[2], "CAP_NET_BIND_SERVICE"); + let effective_caps = caps.effective.as_ref().unwrap(); + assert_eq!(effective_caps.len(), 2); + assert_eq!(effective_caps[0], "CAP_AUDIT_WRITE"); + assert_eq!(effective_caps[1], "CAP_KILL"); + let ambient_caps = caps.ambient.as_ref().unwrap(); + assert_eq!(ambient_caps.len(), 1); + assert_eq!(ambient_caps[0], "CAP_NET_BIND_SERVICE"); + let rlimits = section.process.rlimits.as_ref().unwrap(); + assert_eq!(rlimits.len(), 1); + assert_eq!(rlimits[0].rlimit_type, "RLIMIT_NOFILE"); + assert_eq!(rlimits[0].hard, 1024); + assert_eq!(rlimits[0].soft, 1024); + let exec_cpu_affinity = section.process.execCPUAffinity.as_ref().unwrap(); + assert_eq!(exec_cpu_affinity.initial, Some("7".to_string())); + assert_eq!(exec_cpu_affinity.final_cpus, Some("0-3,7".to_string())); + } +} -- Gitee From ec06b10212bdd83546b9f1e9c0a7d72c8c066be3 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Mon, 19 Aug 2024 10:55:22 +0800 Subject: [PATCH 343/489] oci_spec/vm: Add vm platform support --- ozonec/oci_spec/src/vm.rs | 125 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) diff --git a/ozonec/oci_spec/src/vm.rs b/ozonec/oci_spec/src/vm.rs index 4524f4b2..08d1a354 100644 --- a/ozonec/oci_spec/src/vm.rs +++ b/ozonec/oci_spec/src/vm.rs @@ -9,3 +9,128 @@ // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. + +use serde::{Deserialize, Serialize}; + +/// Hypervisor that manages the container virtual machine. +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Hypervisor { + /// Path to the hypervisor binary that manages the container + /// virtual machine. + pub path: String, + /// Array of parameters to pass to the hypervisor. + #[serde(skip_serializing_if = "Option::is_none")] + pub parameters: Option>, +} + +/// Kernel to boot the container virtual machine with. +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Kernel { + /// Path to the kernel used to boot the container virtual machine. + pub path: String, + #[serde(skip_serializing_if = "Option::is_none")] + /// Array of parameters to pass to the kernel. + pub parameters: Option>, + /// Path to an initial ramdisk to be used by the container + /// virtual machine. + #[serde(skip_serializing_if = "Option::is_none")] + pub initrd: Option, +} + +/// Image that contains the root filesystem for the container +/// virtual machine. +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Image { + /// Path to the container virtual machine root image. + pub path: String, + /// Format of the container virtual machine root image. + pub format: String, +} + +/// Configuration for the hypervisor, kernel, and image. +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct VmPlatform { + /// Hypervisor that manages the container virtual machine. + #[serde(skip_serializing_if = "Option::is_none")] + pub hypervisor: Option, + /// Kernel to boot the container virtual machine with. + pub kernel: Kernel, + /// Image that contains the root filesystem for the container + /// virtual machine. + #[serde(skip_serializing_if = "Option::is_none")] + pub image: Option, +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json; + + #[test] + fn test_hypervisor() { + let json = r#"{ + "hypervisor": { + "path": "/path/to/vmm", + "parameters": ["opts1=foo", "opts2=bar"] + } + }"#; + + #[derive(Serialize, Deserialize)] + struct Section { + hypervisor: Hypervisor, + } + + let section: Section = serde_json::from_str(json).unwrap(); + assert_eq!(section.hypervisor.path, "/path/to/vmm"); + let parameters = section.hypervisor.parameters.as_ref().unwrap(); + assert_eq!(parameters.len(), 2); + assert_eq!(parameters[0], "opts1=foo"); + assert_eq!(parameters[1], "opts2=bar"); + } + + #[test] + fn test_kernel() { + let json = r#"{ + "kernel": { + "path": "/path/to/vmlinuz", + "parameters": ["foo=bar", "hello world"], + "initrd": "/path/to/initrd.img" + } + }"#; + + #[derive(Serialize, Deserialize)] + struct Section { + kernel: Kernel, + } + + let section: Section = serde_json::from_str(json).unwrap(); + assert_eq!(section.kernel.path, "/path/to/vmlinuz"); + let parameters = section.kernel.parameters.as_ref().unwrap(); + assert_eq!(parameters.len(), 2); + assert_eq!(parameters[0], "foo=bar"); + assert_eq!(parameters[1], "hello world"); + assert_eq!( + section.kernel.initrd, + Some("/path/to/initrd.img".to_string()) + ); + } + + #[test] + fn test_image() { + let json = r#"{ + "image": { + "path": "/path/to/vm/rootfs.img", + "format": "raw" + } + }"#; + + #[derive(Serialize, Deserialize)] + struct Section { + image: Image, + } + + let section: Section = serde_json::from_str(json).unwrap(); + assert_eq!(section.image.path, "/path/to/vm/rootfs.img"); + assert_eq!(section.image.format, "raw"); + } +} -- Gitee From 7539a4494ab6ee76882ea26e49b29ff812b07d21 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Mon, 19 Aug 2024 12:46:19 +0800 Subject: [PATCH 344/489] oci_spec/runtime: Add struct RuntimeConfig --- ozonec/oci_spec/src/lib.rs | 2 +- ozonec/oci_spec/src/posix.rs | 193 +++++++++++++++++++++++++++++++++ ozonec/oci_spec/src/process.rs | 35 +----- ozonec/oci_spec/src/runtime.rs | 83 ++++++++++++++ 4 files changed, 281 insertions(+), 32 deletions(-) diff --git a/ozonec/oci_spec/src/lib.rs b/ozonec/oci_spec/src/lib.rs index 3f79329b..f0dd3fe5 100644 --- a/ozonec/oci_spec/src/lib.rs +++ b/ozonec/oci_spec/src/lib.rs @@ -12,7 +12,7 @@ #[cfg(target_os = "linux")] pub mod linux; -#[cfg(target_os = "linux")] +#[cfg(target_family = "unix")] pub mod posix; pub mod process; pub mod runtime; diff --git a/ozonec/oci_spec/src/posix.rs b/ozonec/oci_spec/src/posix.rs index 03396e42..b6ae8b37 100644 --- a/ozonec/oci_spec/src/posix.rs +++ b/ozonec/oci_spec/src/posix.rs @@ -52,3 +52,196 @@ pub struct User { #[serde(skip_serializing_if = "Option::is_none")] pub additionalGids: Option>, } + +/// Hook Entry. +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct HookEntry { + /// Similar semantics to IEEE Std 1003.1-2008 execv's path. + pub path: String, + /// Same semantics as IEEE Std 1003.1-2008 execv's argv. + #[serde(skip_serializing_if = "Option::is_none")] + pub args: Option>, + /// Same semantics as IEEE Std 1003.1-2008's environ. + #[serde(skip_serializing_if = "Option::is_none")] + pub env: Option>, + /// Number of seconds before aborting the hook. + #[serde(skip_serializing_if = "Option::is_none")] + pub timeout: Option, +} + +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Hooks { + /// Array of prestart hooks. + #[serde(skip_serializing_if = "Option::is_none")] + prestart: Option>, + /// Array of createRuntime hooks. + #[serde(skip_serializing_if = "Option::is_none")] + createRuntime: Option>, + /// Array of createContainer hooks. + #[serde(skip_serializing_if = "Option::is_none")] + createContainer: Option>, + /// Array of startContainer hooks. + #[serde(skip_serializing_if = "Option::is_none")] + startContainer: Option>, + /// Array of poststart hooks. + #[serde(skip_serializing_if = "Option::is_none")] + poststart: Option>, + /// Array of poststop hooks. + #[serde(skip_serializing_if = "Option::is_none")] + poststop: Option>, +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json; + + #[test] + fn test_root() { + let json = r#"{ + "root": { + "path": "rootfs", + "readonly": true + } + }"#; + + #[derive(Serialize, Deserialize)] + struct Section { + root: Root, + } + + let section: Section = serde_json::from_str(json).unwrap(); + assert_eq!(section.root.path, "rootfs"); + assert_eq!(section.root.readonly, true); + } + + #[test] + fn test_hooks() { + let json = r#"{ + "hooks": { + "prestart": [ + { + "path": "/usr/bin/fix-mounts", + "args": ["fix-mounts", "arg1", "arg2"], + "env": [ "key1=value1"] + }, + { + "path": "/usr/bin/setup-network" + } + ], + "createRuntime": [ + { + "path": "/usr/bin/fix-mounts", + "args": ["fix-mounts", "arg1", "arg2"], + "env": [ "key1=value1"] + }, + { + "path": "/usr/bin/setup-network" + } + ], + "createContainer": [ + { + "path": "/usr/bin/mount-hook", + "args": ["-mount", "arg1", "arg2"], + "env": [ "key1=value1"] + } + ], + "startContainer": [ + { + "path": "/usr/bin/refresh-ldcache" + } + ], + "poststart": [ + { + "path": "/usr/bin/notify-start", + "timeout": 5 + } + ], + "poststop": [ + { + "path": "/usr/sbin/cleanup.sh", + "args": ["cleanup.sh", "-f"] + } + ] + } + }"#; + + #[derive(Serialize, Deserialize)] + struct Section { + hooks: Hooks, + } + + let section: Section = serde_json::from_str(json).unwrap(); + let prestart = section.hooks.prestart.as_ref().unwrap(); + assert_eq!(prestart.len(), 2); + assert_eq!(prestart[0].path, "/usr/bin/fix-mounts"); + let args = prestart[0].args.as_ref().unwrap(); + assert_eq!(args.len(), 3); + assert_eq!(args[0], "fix-mounts"); + assert_eq!(args[1], "arg1"); + assert_eq!(args[2], "arg2"); + let env = prestart[0].env.as_ref().unwrap(); + assert_eq!(env.len(), 1); + assert_eq!(env[0], "key1=value1"); + assert_eq!(prestart[0].timeout, None); + assert_eq!(prestart[1].path, "/usr/bin/setup-network"); + assert_eq!(prestart[1].args, None); + assert_eq!(prestart[1].env, None); + assert_eq!(prestart[1].timeout, None); + + let create_runtime = section.hooks.createRuntime.as_ref().unwrap(); + assert_eq!(create_runtime.len(), 2); + assert_eq!(create_runtime[0].path, "/usr/bin/fix-mounts"); + let args = create_runtime[0].args.as_ref().unwrap(); + assert_eq!(args.len(), 3); + assert_eq!(args[0], "fix-mounts"); + assert_eq!(args[1], "arg1"); + assert_eq!(args[2], "arg2"); + let env = create_runtime[0].env.as_ref().unwrap(); + assert_eq!(env.len(), 1); + assert_eq!(env[0], "key1=value1"); + assert_eq!(create_runtime[0].timeout, None); + assert_eq!(create_runtime[1].path, "/usr/bin/setup-network"); + assert_eq!(create_runtime[1].args, None); + assert_eq!(create_runtime[1].env, None); + assert_eq!(create_runtime[1].timeout, None); + + let create_container = section.hooks.createContainer.as_ref().unwrap(); + assert_eq!(create_container.len(), 1); + assert_eq!(create_container[0].path, "/usr/bin/mount-hook"); + let args = create_container[0].args.as_ref().unwrap(); + assert_eq!(args.len(), 3); + assert_eq!(args[0], "-mount"); + assert_eq!(args[1], "arg1"); + assert_eq!(args[2], "arg2"); + let env = create_container[0].env.as_ref().unwrap(); + assert_eq!(env.len(), 1); + assert_eq!(env[0], "key1=value1"); + assert_eq!(create_container[0].timeout, None); + + let start_container = section.hooks.startContainer.as_ref().unwrap(); + assert_eq!(start_container.len(), 1); + assert_eq!(start_container[0].path, "/usr/bin/refresh-ldcache"); + assert_eq!(start_container[0].args, None); + assert_eq!(start_container[0].env, None); + assert_eq!(start_container[0].timeout, None); + + let poststart = section.hooks.poststart.as_ref().unwrap(); + assert_eq!(poststart.len(), 1); + assert_eq!(poststart[0].path, "/usr/bin/notify-start"); + assert_eq!(poststart[0].args, None); + assert_eq!(poststart[0].env, None); + assert_eq!(poststart[0].timeout, Some(5)); + + let poststop = section.hooks.poststop.as_ref().unwrap(); + assert_eq!(poststop.len(), 1); + assert_eq!(poststop[0].path, "/usr/sbin/cleanup.sh"); + let args = poststop[0].args.as_ref().unwrap(); + assert_eq!(args.len(), 2); + assert_eq!(args[0], "cleanup.sh"); + assert_eq!(args[1], "-f"); + assert_eq!(poststop[0].env, None); + assert_eq!(poststop[0].timeout, None); + } +} diff --git a/ozonec/oci_spec/src/process.rs b/ozonec/oci_spec/src/process.rs index a32db540..a558d78b 100644 --- a/ozonec/oci_spec/src/process.rs +++ b/ozonec/oci_spec/src/process.rs @@ -12,36 +12,10 @@ use serde::{Deserialize, Serialize}; -use crate::{ - linux::{Capbilities, ExecCpuAffinity, IdMapping, IoPriority, Scheduler}, - posix::{Rlimits, User}, -}; - -/// Additional mounts beyond root. -#[allow(non_snake_case)] -#[derive(Serialize, Deserialize, Debug, Clone)] -pub struct Mount { - /// Destination of mount point: path inside container. - pub destination: String, - /// A device name, but can also be a file or directory name for bind mounts - /// or a dummy. - #[serde(skip_serializing_if = "Option::is_none")] - pub source: Option, - /// Mount options of the filesystem to be used. - #[serde(skip_serializing_if = "Option::is_none")] - pub options: Option>, - /// The type of the filesystem to be mounted. - #[serde(skip_serializing_if = "Option::is_none", rename = "type")] - pub fs_type: Option, - /// The mapping to convert UIDs from the source file system to the - /// destination mount point. - #[serde(skip_serializing_if = "Option::is_none")] - pub uidMappings: Option, - /// The mapping to convert GIDs from the source file system to the - /// destination mount point. - #[serde(skip_serializing_if = "Option::is_none")] - pub gidMappings: Option, -} +#[cfg(target_os = "linux")] +use crate::linux::{Capbilities, ExecCpuAffinity, IoPriority, Scheduler}; +#[cfg(target_family = "unix")] +use crate::posix::{Rlimits, User}; /// Console size in characters of the terminal. #[derive(Serialize, Deserialize, Debug, Clone)] @@ -194,7 +168,6 @@ mod tests { } }"#; - #[allow(non_snake_case)] #[derive(Serialize, Deserialize)] struct Section { process: Process, diff --git a/ozonec/oci_spec/src/runtime.rs b/ozonec/oci_spec/src/runtime.rs index 4524f4b2..8b6b327b 100644 --- a/ozonec/oci_spec/src/runtime.rs +++ b/ozonec/oci_spec/src/runtime.rs @@ -9,3 +9,86 @@ // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. + +use std::{collections::HashMap, fs::File, io::BufReader, path::Path}; + +use anyhow::{Context, Result}; +use serde::{Deserialize, Serialize}; + +#[cfg(target_os = "linux")] +use crate::linux::IdMapping; +#[cfg(target_family = "unix")] +use crate::posix::Root; +use crate::{linux::LinuxPlatform, posix::Hooks, process::Process, vm::VmPlatform}; + +/// Additional mounts beyond root. +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct Mount { + /// Destination of mount point: path inside container. + pub destination: String, + /// A device name, but can also be a file or directory name for bind mounts + /// or a dummy. + #[serde(skip_serializing_if = "Option::is_none")] + pub source: Option, + /// Mount options of the filesystem to be used. + #[serde(skip_serializing_if = "Option::is_none")] + pub options: Option>, + /// The type of the filesystem to be mounted. + #[serde(skip_serializing_if = "Option::is_none", rename = "type")] + pub fs_type: Option, + /// The mapping to convert UIDs from the source file system to the + /// destination mount point. + #[serde(skip_serializing_if = "Option::is_none")] + pub uidMappings: Option, + /// The mapping to convert GIDs from the source file system to the + /// destination mount point. + #[serde(skip_serializing_if = "Option::is_none")] + pub gidMappings: Option, +} + +/// Metadata necessary to implement standard operations against the container. +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct RuntimeConfig { + /// Version of the Open Container Initiative Runtime Specification + /// with which the bundle complies. + pub ociVersion: String, + /// Container's root filesystem. + pub root: Root, + /// Additional mounts beyond root. + pub mounts: Vec, + /// Container process. + pub process: Process, + /// Container's hostname as seen by processes running inside the container. + #[serde(skip_serializing_if = "Option::is_none")] + pub hostname: Option, + /// Container's domainname as seen by processes running inside the + /// container. + #[serde(skip_serializing_if = "Option::is_none")] + pub domainname: Option, + /// Linux-specific section of the container configuration. + #[cfg(target_os = "linux")] + #[serde(skip_serializing_if = "Option::is_none")] + pub linux: Option, + /// Vm-specific section of the container configuration. + #[serde(skip_serializing_if = "Option::is_none")] + pub vm: Option, + /// Custom actions related to the lifecycle of the container. + #[cfg(target_family = "unix")] + #[serde(skip_serializing_if = "Option::is_none")] + pub hooks: Option, + /// Arbitrary metadata for the container. + #[serde(skip_serializing_if = "Option::is_none")] + pub annotations: Option>, +} + +impl RuntimeConfig { + pub fn from_file(path: &String) -> Result { + let file = File::open(Path::new(path)).with_context(|| "Failed to open config.json")?; + let reader = BufReader::new(file); + let config = + serde_json::from_reader(reader).with_context(|| "Failed to load config.json")?; + Ok(config) + } +} -- Gitee From e71f77772d08fbf4df0f76c1541c8ede0cb17582 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Mon, 19 Aug 2024 15:04:16 +0800 Subject: [PATCH 345/489] oci_spec/runtime: Add unit testcase for mounts --- ozonec/oci_spec/src/runtime.rs | 48 ++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/ozonec/oci_spec/src/runtime.rs b/ozonec/oci_spec/src/runtime.rs index 8b6b327b..f1286357 100644 --- a/ozonec/oci_spec/src/runtime.rs +++ b/ozonec/oci_spec/src/runtime.rs @@ -92,3 +92,51 @@ impl RuntimeConfig { Ok(config) } } + +#[cfg(test)] +mod tests { + use super::*; + use serde_json; + + #[test] + fn test_mounts() { + let json = r#"{ + "mounts": [ + { + "destination": "/proc", + "type": "proc", + "source": "proc" + }, + { + "destination": "/dev", + "type": "tmpfs", + "source": "tmpfs", + "options": [ + "nosuid", + "strictatime", + "mode=755", + "size=65536k" + ] + } + ] + }"#; + + #[allow(non_snake_case)] + #[derive(Serialize, Deserialize)] + struct Section { + mounts: Vec, + } + + let section: Section = serde_json::from_str(json).unwrap(); + assert_eq!(section.mounts.len(), 2); + assert_eq!(section.mounts[0].destination, "/proc"); + assert_eq!(section.mounts[0].fs_type, Some("proc".to_string())); + assert_eq!(section.mounts[0].source, Some("proc".to_string())); + let options = section.mounts[1].options.as_ref().unwrap(); + assert_eq!(options.len(), 4); + assert_eq!(options[0], "nosuid"); + assert_eq!(options[1], "strictatime"); + assert_eq!(options[2], "mode=755"); + assert_eq!(options[3], "size=65536k"); + } +} -- Gitee From ce4f8d929be06138a7f970c8ff896824c1b7c08f Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Mon, 19 Aug 2024 15:42:17 +0800 Subject: [PATCH 346/489] oci_spec/state: Add container state support --- ozonec/oci_spec/src/state.rs | 79 ++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) diff --git a/ozonec/oci_spec/src/state.rs b/ozonec/oci_spec/src/state.rs index 4524f4b2..fe818052 100644 --- a/ozonec/oci_spec/src/state.rs +++ b/ozonec/oci_spec/src/state.rs @@ -9,3 +9,82 @@ // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. + +use std::collections::HashMap; + +use serde::{Deserialize, Serialize}; + +/// Runtime state of the container. +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Copy, Default)] +#[serde(rename_all = "lowercase")] +pub enum ContainerStatus { + Creating, + Created, + Running, + #[default] + Stopped, +} + +impl ToString for ContainerStatus { + fn to_string(&self) -> String { + match *self { + ContainerStatus::Creating => String::from("creating"), + ContainerStatus::Created => String::from("created"), + ContainerStatus::Running => String::from("running"), + ContainerStatus::Stopped => String::from("stopped"), + } + } +} + +/// The state of a container. +#[allow(non_snake_case)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +pub struct State { + /// Version of the Open Container Initiative Runtime Specification + /// with which the state complies. + #[serde(default, skip_serializing_if = "String::is_empty")] + pub ociVersion: String, + /// Container's ID. + #[serde(default, skip_serializing_if = "String::is_empty")] + pub id: String, + /// Runtime state of the container. + pub status: ContainerStatus, + /// ID of the container process. + #[serde(default)] + pub pid: i32, + /// Absolute path to the container's bundle directory. + #[serde(default, skip_serializing_if = "String::is_empty")] + pub bundle: String, + /// List of annotations associated with the container. + #[serde(default, skip_serializing_if = "HashMap::is_empty")] + pub annotations: HashMap, +} + +#[cfg(test)] +mod tests { + use super::*; + use serde_json; + + #[test] + fn test_state() { + let json = r#"{ + "ociVersion": "0.2.0", + "id": "oci-container1", + "status": "running", + "pid": 4422, + "bundle": "/containers/redis", + "annotations": { + "myKey": "myValue" + } + }"#; + + let state: State = serde_json::from_str(json).unwrap(); + assert_eq!(state.ociVersion, "0.2.0"); + assert_eq!(state.id, "oci-container1"); + assert_eq!(state.status, ContainerStatus::Running); + assert_eq!(state.pid, 4422); + assert_eq!(state.bundle, "/containers/redis"); + assert!(state.annotations.contains_key("myKey")); + assert_eq!(state.annotations.get("myKey"), Some(&"myValue".to_string())); + } +} -- Gitee From 5a891da4b2573738c3b964bb26d9e27ad384df0d Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Mon, 19 Aug 2024 21:57:39 +0800 Subject: [PATCH 347/489] ozonec/container: Add struct Launcher to launch container process --- ozonec/Cargo.toml | 4 ++ ozonec/src/container/launcher.rs | 110 +++++++++++++++++++++++++++++++ ozonec/src/container/mod.rs | 44 +++++++++++++ ozonec/src/container/process.rs | 49 ++++++++++++++ ozonec/src/container/state.rs | 99 ++++++++++++++++++++++++++++ 5 files changed, 306 insertions(+) create mode 100644 ozonec/src/container/launcher.rs create mode 100644 ozonec/src/container/mod.rs create mode 100644 ozonec/src/container/process.rs create mode 100644 ozonec/src/container/state.rs diff --git a/ozonec/Cargo.toml b/ozonec/Cargo.toml index 8cd9de1b..b00a0b35 100644 --- a/ozonec/Cargo.toml +++ b/ozonec/Cargo.toml @@ -8,11 +8,15 @@ description = "An OCI runtime implemented by Rust" [dependencies] anyhow = "= 1.0.71" +chrono = { version = "0.4.31", default-features = false, features = ["clock", "serde"] } clap = { version = "= 4.1.4", default-features = false, features = ["derive", "cargo", "std", "help", "usage"] } libc = "= 0.2.146" log = { version = "= 0.4.18", features = ["std"]} nix = "= 0.26.2" oci_spec = { path = "oci_spec" } +procfs = "0.14.0" +serde = { version = "= 1.0.163", features = ["derive"] } +serde_json = "= 1.0.96" [workspace] diff --git a/ozonec/src/container/launcher.rs b/ozonec/src/container/launcher.rs new file mode 100644 index 00000000..9887d9eb --- /dev/null +++ b/ozonec/src/container/launcher.rs @@ -0,0 +1,110 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::path::{Path, PathBuf}; + +use anyhow::{Context, Result}; + +use super::{process::Process, state::State, Container}; + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum Action { + Create, + Start, + Exec, +} + +pub struct Launcher { + pub bundle: PathBuf, + pub state_root: PathBuf, + /// init is set to true when creating a container. + pub init: bool, + pub runner: Box, + pub pid_file: Option, +} + +impl Launcher { + pub fn new( + bundle: &Path, + state_root: &Path, + init: bool, + runner: Box, + pid_file: Option, + ) -> Self { + Self { + bundle: bundle.to_path_buf(), + state_root: state_root.to_path_buf(), + init, + runner, + pid_file, + } + } + + pub fn launch(&mut self, action: Action) -> Result<()> { + if self.init { + self.spawn_container()?; + } else { + self.spawn_process(action)?; + } + + if let Some(pid_file) = self.pid_file.as_ref() { + let pid = self.runner.get_pid(); + std::fs::write(pid_file, format!("{}", pid)).with_context(|| "Failed to write pid")?; + } + + Ok(()) + } + + fn spawn_container(&mut self) -> Result<()> { + self.spawn_process(Action::Create)?; + + let mut state = self + .get_state() + .with_context(|| "Failed to get container state")?; + state.update(); + state.save().with_context(|| "Failed to save state")?; + Ok(()) + } + + fn spawn_process(&mut self, action: Action) -> Result<()> { + let mut process = self.get_process(); + match action { + Action::Create => self.runner.create(&mut process), + Action::Start => self.runner.start(), + Action::Exec => self.runner.exec(&mut process), + } + } + + fn get_process(&self) -> Process { + let config = self.runner.get_config(); + Process::new(&config.process, self.init) + } + + fn get_state(&self) -> Result { + let state = self.runner.get_oci_state()?; + let pid = self.runner.get_pid(); + let proc = procfs::process::Process::new(pid)?; + let start_time = proc + .stat() + .with_context(|| format!("Failed to access /proc/{}/status", pid))? + .starttime; + + Ok(State::new( + &self.state_root, + &self.bundle, + state, + start_time, + *self.runner.created_time(), + self.runner.get_config(), + )) + } +} diff --git a/ozonec/src/container/mod.rs b/ozonec/src/container/mod.rs new file mode 100644 index 00000000..611af779 --- /dev/null +++ b/ozonec/src/container/mod.rs @@ -0,0 +1,44 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +mod launcher; +mod process; +mod state; + +pub use launcher::{Action, Launcher}; +pub use process::Process; + +use std::time::SystemTime; + +use anyhow::Result; +use libc::pid_t; +use nix::sys::signal::Signal; + +use oci_spec::{runtime::RuntimeConfig, state::State as OciState}; + +pub trait Container { + fn get_config(&self) -> &RuntimeConfig; + + fn get_oci_state(&self) -> Result; + + fn get_pid(&self) -> pid_t; + + fn created_time(&self) -> &SystemTime; + + fn create(&mut self, process: &mut Process) -> Result<()>; + + fn start(&mut self) -> Result<()>; + + fn exec(&mut self, process: &mut Process) -> Result<()>; + + fn kill(&mut self, sig: Signal) -> Result<()>; +} diff --git a/ozonec/src/container/process.rs b/ozonec/src/container/process.rs new file mode 100644 index 00000000..962599ab --- /dev/null +++ b/ozonec/src/container/process.rs @@ -0,0 +1,49 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::{ + io::{stderr, stdin, stdout}, + os::fd::{AsRawFd, RawFd}, +}; + +use oci_spec::process::Process as OciProcess; + +pub struct Process { + pub stdin: Option, + pub stdout: Option, + pub stderr: Option, + pub term_master: Option, + pub init: bool, + pub tty: bool, + pub oci: OciProcess, +} + +impl Process { + pub fn new(oci: &OciProcess, init: bool) -> Self { + let mut p = Process { + stdin: None, + stdout: None, + stderr: None, + tty: oci.terminal, + term_master: None, + init, + oci: oci.clone(), + }; + + if !p.tty { + p.stdin = Some(stdin().as_raw_fd()); + p.stdout = Some(stdout().as_raw_fd()); + p.stderr = Some(stderr().as_raw_fd()); + } + p + } +} diff --git a/ozonec/src/container/state.rs b/ozonec/src/container/state.rs new file mode 100644 index 00000000..424e2d81 --- /dev/null +++ b/ozonec/src/container/state.rs @@ -0,0 +1,99 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::{ + fs::{DirBuilder, OpenOptions}, + os::unix::fs::DirBuilderExt, + path::{Path, PathBuf}, + time::SystemTime, +}; + +use anyhow::{Context, Result}; +use chrono::{DateTime, Utc}; +use libc::pid_t; +use nix::sys::stat::Mode; +use serde::{Deserialize, Serialize}; + +use oci_spec::{runtime::RuntimeConfig, state::State as OciState}; + +#[derive(Serialize, Deserialize, Debug, Clone, Default)] +#[serde(rename_all = "camelCase")] +pub struct State { + pub oci_version: String, + pub id: String, + pub pid: pid_t, + pub root: PathBuf, + pub bundle: PathBuf, + pub rootfs: String, + pub start_time: u64, + pub created_time: DateTime, + pub config: Option, +} + +impl State { + pub fn new( + root: &Path, + bundle: &Path, + oci_state: OciState, + start_time: u64, + created_time: SystemTime, + config: &RuntimeConfig, + ) -> Self { + Self { + oci_version: oci_state.ociVersion, + id: oci_state.id, + pid: oci_state.pid, + root: root.to_path_buf(), + bundle: bundle.to_path_buf(), + rootfs: config.root.path.clone(), + start_time, + created_time: DateTime::from(created_time), + config: Some(config.clone()), + } + } + + fn file_path(root: &Path, id: &str) -> PathBuf { + root.join(id).join("state.json") + } + + pub fn save(&self) -> Result<()> { + if !&self.root.exists() { + DirBuilder::new() + .recursive(true) + .mode(Mode::S_IRWXU.bits()) + .create(&self.root) + .with_context(|| "Failed to create root directory")?; + } + + let path = Self::file_path(&self.root, &self.id); + let state_file = OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(path) + .with_context(|| "Failed to open state file")?; + serde_json::to_writer(&state_file, self)?; + Ok(()) + } + + pub fn update(&mut self) { + let linux = self.config.as_mut().unwrap().linux.as_mut(); + if let Some(config) = linux { + for ns in &mut config.namespaces { + if ns.path.is_none() { + let ns_name: String = ns.ns_type.into(); + ns.path = Some(PathBuf::from(format!("/proc/{}/ns/{}", self.pid, ns_name))) + } + } + } + } +} -- Gitee From ff458f3c5e1e99fab7dad0d3dedde60662bf57a4 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Tue, 20 Aug 2024 14:21:33 +0800 Subject: [PATCH 348/489] ozonec/linux: Add Linux container support --- ozonec/src/linux/container.rs | 179 ++++++++++++++++++++++++++++++ ozonec/src/linux/mod.rs | 16 +++ ozonec/src/linux/notify_socket.rs | 13 +++ 3 files changed, 208 insertions(+) create mode 100644 ozonec/src/linux/container.rs create mode 100644 ozonec/src/linux/mod.rs create mode 100644 ozonec/src/linux/notify_socket.rs diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs new file mode 100644 index 00000000..28c0de31 --- /dev/null +++ b/ozonec/src/linux/container.rs @@ -0,0 +1,179 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::{ + collections::HashMap, + fs::{canonicalize, create_dir_all}, + path::{Path, PathBuf}, + time::SystemTime, +}; + +use anyhow::{anyhow, bail, Context, Result}; +use libc::pid_t; +use log::error; +use nix::{ + sys::signal::Signal, + unistd::{chown, getegid, geteuid}, +}; +use procfs::process::ProcState; + +use super::notify_socket::NOTIFY_SOCKET; +use crate::container::{Container, Process}; +use oci_spec::{ + runtime::RuntimeConfig, + state::{ContainerStatus, State}, +}; + +pub struct LinuxContainer { + pub id: String, + pub root: String, + pub config: RuntimeConfig, + pub pid: pid_t, + pub start_time: u64, + pub created_time: SystemTime, + pub console_socket: Option, +} + +impl LinuxContainer { + pub fn new( + id: &String, + root: &String, + config: &RuntimeConfig, + console_socket: &Option, + exist: &mut bool, + ) -> Result { + let container_dir = format!("{}/{}", root, id); + + Self::validate_config(config)?; + + if Path::new(container_dir.as_str()).exists() { + *exist = true; + bail!("Container {} already exists", id); + } + create_dir_all(container_dir.as_str()).map_err(|e| { + error!("Failed to create container directory: {}", e); + anyhow!(e).context("Failed to create container directory") + })?; + chown(container_dir.as_str(), Some(geteuid()), Some(getegid())) + .with_context(|| "Failed to chown container directory")?; + + Ok(Self { + id: id.clone(), + root: container_dir, + config: config.clone(), + pid: -1, + start_time: 0, + created_time: SystemTime::now(), + console_socket: console_socket.clone(), + }) + } + + fn validate_config(config: &RuntimeConfig) -> Result<()> { + if config.linux.is_none() { + bail!("There is no linux specific configuration in config.json for Linux container"); + } + Ok(()) + } + + fn container_status(&self) -> Result { + if self.pid == -1 { + return Ok(ContainerStatus::Creating); + } + + let proc = procfs::process::Process::new(self.pid); + // If error occurs when accessing /proc/, the process most likely has stopped. + if proc.is_err() { + return Ok(ContainerStatus::Stopped); + } + let proc_stat = proc + .unwrap() + .stat() + .with_context(|| format!("Failed to read /proc/{}/stat", self.pid))?; + // If starttime is not the same, then pid is reused, and the original process has stopped. + if proc_stat.starttime != self.start_time { + return Ok(ContainerStatus::Stopped); + } + + match proc_stat.state()? { + ProcState::Zombie | ProcState::Dead => Ok(ContainerStatus::Stopped), + _ => { + let notify_socket = PathBuf::from(&self.root).join(NOTIFY_SOCKET); + if notify_socket.exists() { + return Ok(ContainerStatus::Created); + } + Ok(ContainerStatus::Running) + } + } + } +} + +impl Container for LinuxContainer { + fn get_config(&self) -> &RuntimeConfig { + &self.config + } + + fn get_pid(&self) -> pid_t { + self.pid + } + + fn created_time(&self) -> &SystemTime { + &self.created_time + } + + fn get_oci_state(&self) -> Result { + let status = self.container_status()?; + let pid = if status != ContainerStatus::Stopped { + self.pid + } else { + 0 + }; + + let rootfs = canonicalize(&self.config.root.path.clone()) + .with_context(|| "Failed to canonicalize root path")?; + let bundle = match rootfs.parent() { + Some(p) => p + .to_str() + .ok_or(anyhow!("root path is not valid unicode"))? + .to_string(), + None => bail!("Failed to get bundle directory"), + }; + let annotations = if let Some(a) = self.config.annotations.clone() { + a + } else { + HashMap::new() + }; + Ok(State { + ociVersion: self.config.ociVersion.clone(), + id: self.id.clone(), + status, + pid, + bundle, + annotations, + }) + } + + fn create(&mut self, process: &mut Process) -> Result<()> { + Ok(()) + } + + fn start(&mut self) -> Result<()> { + Ok(()) + } + + fn exec(&mut self, process: &mut Process) -> Result<()> { + Ok(()) + } + + fn kill(&mut self, sig: Signal) -> Result<()> { + Ok(()) + } +} diff --git a/ozonec/src/linux/mod.rs b/ozonec/src/linux/mod.rs new file mode 100644 index 00000000..05cf2fa5 --- /dev/null +++ b/ozonec/src/linux/mod.rs @@ -0,0 +1,16 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +mod container; +mod notify_socket; + +pub use container::LinuxContainer; diff --git a/ozonec/src/linux/notify_socket.rs b/ozonec/src/linux/notify_socket.rs new file mode 100644 index 00000000..2a7ed69e --- /dev/null +++ b/ozonec/src/linux/notify_socket.rs @@ -0,0 +1,13 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +pub const NOTIFY_SOCKET: &str = "notify.sock"; -- Gitee From bcceeed7746679e742471e37fae5f457651c874d Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Tue, 20 Aug 2024 14:45:18 +0800 Subject: [PATCH 349/489] ozonec/command: Add create.rs --- ozonec/src/commands/create.rs | 78 +++++++++++++++++++++++++++++++++++ ozonec/src/commands/mod.rs | 15 +++++++ ozonec/src/main.rs | 44 ++++++++++++++++++-- 3 files changed, 133 insertions(+), 4 deletions(-) create mode 100644 ozonec/src/commands/create.rs create mode 100644 ozonec/src/commands/mod.rs diff --git a/ozonec/src/commands/create.rs b/ozonec/src/commands/create.rs new file mode 100644 index 00000000..22c92469 --- /dev/null +++ b/ozonec/src/commands/create.rs @@ -0,0 +1,78 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::path::{Path, PathBuf}; + +use anyhow::{Context, Ok, Result}; +use clap::{builder::NonEmptyStringValueParser, Parser}; + +use crate::container::{Action, Container, Launcher}; +use crate::linux::LinuxContainer; +use oci_spec::runtime::RuntimeConfig; + +#[derive(Parser, Debug)] +pub struct Create { + /// File to write the container PID to + #[arg(short, long)] + pub pid_file: Option, + /// Path to the bundle directory, defaults to the current working directory. + #[arg(short, long, default_value = ".")] + pub bundle: PathBuf, + /// Path to an AF_UNIX socket which will receive the pseudoterminal master + /// at a file descriptor. + #[arg(short, long)] + pub console_socket: Option, + /// Container ID to create. + #[arg(value_parser = NonEmptyStringValueParser::new(), required = true)] + pub container_id: String, +} + +impl Create { + fn launcher(&self, root: &Path, exist: &mut bool) -> Result { + let bundle_path = self + .bundle + .canonicalize() + .with_context(|| "Failed to canonicalize bundle path")?; + let config_path = bundle_path + .join("config.json") + .to_string_lossy() + .to_string(); + let mut config = RuntimeConfig::from_file(&config_path)?; + let mut rootfs_path = PathBuf::from(config.root.path); + + if !rootfs_path.is_absolute() { + rootfs_path = bundle_path.join(rootfs_path); + } + config.root.path = rootfs_path.to_string_lossy().to_string(); + + let container: Box = Box::new(LinuxContainer::new( + &self.container_id, + &root.to_string_lossy().to_string(), + &config, + &self.console_socket, + exist, + )?); + Ok(Launcher::new( + &bundle_path, + root, + true, + container, + self.pid_file.clone(), + )) + } + + pub fn run(&self, root: &Path, exist: &mut bool) -> Result<()> { + let mut launcher = self.launcher(root, exist)?; + launcher.launch(Action::Create)?; + Ok(()) + } +} diff --git a/ozonec/src/commands/mod.rs b/ozonec/src/commands/mod.rs new file mode 100644 index 00000000..2472ae99 --- /dev/null +++ b/ozonec/src/commands/mod.rs @@ -0,0 +1,15 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +mod create; + +pub use create::Create; diff --git a/ozonec/src/main.rs b/ozonec/src/main.rs index 69752860..dd88161a 100644 --- a/ozonec/src/main.rs +++ b/ozonec/src/main.rs @@ -10,14 +10,23 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. +mod commands; +mod container; +mod linux; mod utils; -use std::{path::PathBuf, process::exit}; +use std::{ + fs::remove_dir_all, + path::{Path, PathBuf}, + process::exit, +}; use anyhow::{Context, Result}; use clap::{crate_description, Args, Parser, Subcommand}; +use log::info; +use nix::unistd::geteuid; -use crate::utils::logger; +use crate::{commands::Create, utils::logger}; // Global options which are not binded to any specific command. #[derive(Args, Debug)] @@ -38,7 +47,9 @@ struct GlobalOpts { // and [OCI Command Line Interface] // (https://github.com/opencontainers/runtime-tools/blob/master/docs/command-line-interface.md). #[derive(Subcommand, Debug)] -enum StandardCmd {} +enum StandardCmd { + Create(Create), +} // Extended commands not documented in [OCI Command Line Interface]. #[derive(Subcommand, Debug)] @@ -62,12 +73,37 @@ struct Cli { cmd: Command, } +fn cmd_run(command: Command, root: &Path) -> Result<()> { + match command { + Command::Standard(cmd) => match cmd { + StandardCmd::Create(create) => { + info!("Exec command: {:?}", create); + + let mut root_exist = false; + create.run(root, &mut root_exist).inspect_err(|_| { + if !root_exist { + let _ = remove_dir_all(root); + } + })? + } + }, + Command::Extend(cmd) => (), + } + Ok(()) +} + fn real_main() -> Result<()> { let cli = Cli::parse(); logger::init(&cli.global.log, cli.global.debug).with_context(|| "Failed to init logger")?; - Ok(()) + let root_path = if let Some(root) = cli.global.root { + root + } else { + let euid = geteuid(); + PathBuf::from(format!("/var/run/user/{}/ozonec", euid)) + }; + cmd_run(cli.cmd, &root_path) } fn main() { -- Gitee From 1cd31397919f7814c8321aa5fe48d2aa843e18f6 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Wed, 21 Aug 2024 16:47:59 +0800 Subject: [PATCH 350/489] ozonec/utils: Add channel.rs --- ozonec/src/utils/channel.rs | 191 ++++++++++++++++++++++++++++++++++++ ozonec/src/utils/mod.rs | 4 + 2 files changed, 195 insertions(+) create mode 100644 ozonec/src/utils/channel.rs diff --git a/ozonec/src/utils/channel.rs b/ozonec/src/utils/channel.rs new file mode 100644 index 00000000..4e303d10 --- /dev/null +++ b/ozonec/src/utils/channel.rs @@ -0,0 +1,191 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::{ + fmt::Debug, + io::{IoSlice, IoSliceMut}, + marker::PhantomData, + mem, + os::fd::RawFd, + slice, +}; + +use anyhow::{bail, Context, Result}; +use nix::{ + sys::{ + socket::{ + recvmsg, sendmsg, setsockopt, socketpair, sockopt, AddressFamily, MsgFlags, SockFlag, + SockType, UnixAddr, + }, + time::TimeVal, + }, + unistd::{self, Pid}, +}; +use serde::{de::DeserializeOwned, Deserialize, Serialize}; + +// Wrapper for messages to be sent between parent and child processes. +#[derive(Debug, Serialize, Deserialize)] +pub enum Message { + IdMappingStart, + IdMappingDone, + InitReady(i32), + ContainerCreated, + ExecFailed(String), +} + +pub struct Sender { + fd: RawFd, + phantom: PhantomData, +} + +impl Sender +where + T: Serialize, +{ + pub fn close(&self) -> Result<()> { + Ok(unistd::close(self.fd)?) + } + + pub fn send(&self, msg: T) -> Result<()> { + let msg_vec = serde_json::to_vec(&msg).with_context(|| "Failed to load message")?; + let msg_len = msg_vec.len() as u64; + let iov = [ + IoSlice::new(unsafe { + slice::from_raw_parts((&msg_len as *const u64) as *const u8, mem::size_of::()) + }), + IoSlice::new(&msg_vec), + ]; + + sendmsg::(self.fd, &iov, &[], MsgFlags::empty(), None)?; + Ok(()) + } +} + +pub struct Receiver { + fd: RawFd, + phantom: PhantomData, +} + +impl Receiver +where + T: DeserializeOwned, +{ + pub fn close(&self) -> Result<()> { + Ok(unistd::close(self.fd)?) + } + + pub fn set_timeout(&self, timeout: i64) -> Result<()> { + let timeval = TimeVal::new(0, timeout); + setsockopt(self.fd, sockopt::ReceiveTimeout, &timeval) + .with_context(|| "Failed to set receiver end timeout")?; + Ok(()) + } + + fn max_len_iovec(&self) -> Result { + let mut len: u64 = 0; + // SAFETY: len and type "u64" are both valid. + let mut iov = [IoSliceMut::new(unsafe { + slice::from_raw_parts_mut((&mut len as *mut u64) as *mut u8, mem::size_of::()) + })]; + + recvmsg::(self.fd, &mut iov, None, MsgFlags::MSG_PEEK)?; + match len { + 0 => bail!("Failed to get maximum length"), + _ => Ok(len), + } + } + + pub fn recv(&self) -> Result { + let msg_len = self.max_len_iovec()?; + let mut received_len: u64 = 0; + let mut buf = vec![0u8; msg_len as usize]; + let bytes = { + let mut iov = [ + IoSliceMut::new(unsafe { + slice::from_raw_parts_mut( + (&mut received_len as *mut u64) as *mut u8, + mem::size_of::(), + ) + }), + IoSliceMut::new(&mut buf), + ]; + let mut cmsg = nix::cmsg_space!(T); + let msg = recvmsg::( + self.fd, + &mut iov, + Some(&mut cmsg), + MsgFlags::MSG_CMSG_CLOEXEC, + )?; + msg.bytes + }; + + match bytes { + 0 => bail!("Received zero length message"), + _ => Ok(serde_json::from_slice(&buf[..]) + .with_context(|| "Failed to read received message")?), + } + } +} + +pub struct Channel { + pub sender: Sender, + pub receiver: Receiver, +} + +impl Channel { + pub fn new() -> Result> { + let (sender_fd, receiver_fd) = socketpair( + AddressFamily::Unix, + SockType::SeqPacket, + None, + SockFlag::SOCK_CLOEXEC, + )?; + let sender = Sender { + fd: sender_fd, + phantom: PhantomData, + }; + let receiver = Receiver { + fd: receiver_fd, + phantom: PhantomData, + }; + + Ok(Channel { sender, receiver }) + } + + pub fn recv_container_created(&self) -> Result<()> { + let msg = self.receiver.recv()?; + match msg { + Message::ContainerCreated => Ok(()), + _ => bail!("Expect receiving ContainerCreated, but got {:?}", msg), + } + } + + pub fn send_container_created(&self) -> Result<()> { + self.sender + .send(Message::ContainerCreated) + .with_context(|| "Failed to send created message to parent process") + } + + pub fn recv_init_pid(&self) -> Result { + let msg = self.receiver.recv()?; + match msg { + Message::InitReady(pid) => Ok(Pid::from_raw(pid)), + _ => bail!("Expect receiving InitReady, but got {:?}", msg), + } + } + + pub fn send_init_pid(&self, pid: Pid) -> Result<()> { + self.sender + .send(Message::InitReady(pid.as_raw())) + .with_context(|| "Failed to send container process pid") + } +} diff --git a/ozonec/src/utils/mod.rs b/ozonec/src/utils/mod.rs index 3415cf8e..461581f6 100644 --- a/ozonec/src/utils/mod.rs +++ b/ozonec/src/utils/mod.rs @@ -11,3 +11,7 @@ // See the Mulan PSL v2 for more details. pub mod logger; + +mod channel; + +pub use channel::{Channel, Message}; -- Gitee From 6d3c51e358993ae8a52d99e967c458b3956835e4 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Wed, 21 Aug 2024 16:50:46 +0800 Subject: [PATCH 351/489] ozonec/linux: Add notify_socket.rs --- ozonec/src/linux/mod.rs | 1 + ozonec/src/linux/notify_socket.rs | 47 +++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/ozonec/src/linux/mod.rs b/ozonec/src/linux/mod.rs index 05cf2fa5..9aed65f4 100644 --- a/ozonec/src/linux/mod.rs +++ b/ozonec/src/linux/mod.rs @@ -14,3 +14,4 @@ mod container; mod notify_socket; pub use container::LinuxContainer; +pub use notify_socket::NotifyListener; diff --git a/ozonec/src/linux/notify_socket.rs b/ozonec/src/linux/notify_socket.rs index 2a7ed69e..65ab4c9f 100644 --- a/ozonec/src/linux/notify_socket.rs +++ b/ozonec/src/linux/notify_socket.rs @@ -10,4 +10,51 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. +use std::{ + env, + io::Read, + os::{fd::AsRawFd, unix::net::UnixListener}, + path::{Path, PathBuf}, +}; + +use anyhow::{bail, Context, Result}; +use nix::unistd::{self, chdir}; + pub const NOTIFY_SOCKET: &str = "notify.sock"; + +pub struct NotifyListener { + socket: UnixListener, +} + +impl NotifyListener { + pub fn new(root: PathBuf) -> Result { + // The length of path of Unix domain socket has the limit 108, which is smaller then + // the maximum length of file on Linux (255). + let cwd = + env::current_dir().with_context(|| "Current working directory value is invalid")?; + chdir(&root).with_context(|| "Failed to chdir to root directory")?; + let listener = + UnixListener::bind(NOTIFY_SOCKET).with_context(|| "Failed to bind notify socket")?; + chdir(&cwd).with_context(|| "Failed to chdir to previous working directory")?; + Ok(Self { socket: listener }) + } + + pub fn wait_for_start_container(&self) -> Result<()> { + match self.socket.accept() { + Ok((mut socket, _)) => { + let mut response = String::new(); + socket + .read_to_string(&mut response) + .with_context(|| "Invalid response from notify socket")?; + } + Err(e) => { + bail!("Failed to accept on notify socket: {}", e); + } + } + Ok(()) + } + + pub fn close(&self) -> Result<()> { + Ok(unistd::close(self.socket.as_raw_fd())?) + } +} -- Gitee From d76f19ba05ef240aa1f48c1b1f2b258a9aec9143 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Wed, 21 Aug 2024 16:56:27 +0800 Subject: [PATCH 352/489] ozonec: Implement create command for Linux containers --- ozonec/Cargo.toml | 3 + ozonec/src/commands/create.rs | 1 + ozonec/src/container/launcher.rs | 17 +-- ozonec/src/container/mod.rs | 4 +- ozonec/src/linux/container.rs | 134 ++++++++++++++++++++- ozonec/src/linux/mod.rs | 2 + ozonec/src/{container => linux}/process.rs | 49 +++++++- ozonec/src/utils/error.rs | 21 ++++ ozonec/src/utils/mod.rs | 2 + 9 files changed, 217 insertions(+), 16 deletions(-) rename ozonec/src/{container => linux}/process.rs (45%) create mode 100644 ozonec/src/utils/error.rs diff --git a/ozonec/Cargo.toml b/ozonec/Cargo.toml index b00a0b35..8c7eb551 100644 --- a/ozonec/Cargo.toml +++ b/ozonec/Cargo.toml @@ -10,13 +10,16 @@ description = "An OCI runtime implemented by Rust" anyhow = "= 1.0.71" chrono = { version = "0.4.31", default-features = false, features = ["clock", "serde"] } clap = { version = "= 4.1.4", default-features = false, features = ["derive", "cargo", "std", "help", "usage"] } +clone3 = "0.2.3" libc = "= 0.2.146" log = { version = "= 0.4.18", features = ["std"]} nix = "= 0.26.2" oci_spec = { path = "oci_spec" } +prctl = "1.0.0" procfs = "0.14.0" serde = { version = "= 1.0.163", features = ["derive"] } serde_json = "= 1.0.96" +thiserror = "= 1.0.40" [workspace] diff --git a/ozonec/src/commands/create.rs b/ozonec/src/commands/create.rs index 22c92469..e4c802b0 100644 --- a/ozonec/src/commands/create.rs +++ b/ozonec/src/commands/create.rs @@ -19,6 +19,7 @@ use crate::container::{Action, Container, Launcher}; use crate::linux::LinuxContainer; use oci_spec::runtime::RuntimeConfig; +/// Create a container from a bundle directory #[derive(Parser, Debug)] pub struct Create { /// File to write the container PID to diff --git a/ozonec/src/container/launcher.rs b/ozonec/src/container/launcher.rs index 9887d9eb..0e0e7eb1 100644 --- a/ozonec/src/container/launcher.rs +++ b/ozonec/src/container/launcher.rs @@ -14,7 +14,9 @@ use std::path::{Path, PathBuf}; use anyhow::{Context, Result}; -use super::{process::Process, state::State, Container}; +use crate::{linux::Process, utils::OzonecErr}; + +use super::{state::State, Container}; #[derive(Debug, Clone, Copy, PartialEq)] pub enum Action { @@ -25,7 +27,7 @@ pub enum Action { pub struct Launcher { pub bundle: PathBuf, - pub state_root: PathBuf, + pub root: PathBuf, /// init is set to true when creating a container. pub init: bool, pub runner: Box, @@ -35,14 +37,14 @@ pub struct Launcher { impl Launcher { pub fn new( bundle: &Path, - state_root: &Path, + root: &Path, init: bool, runner: Box, pid_file: Option, ) -> Self { Self { bundle: bundle.to_path_buf(), - state_root: state_root.to_path_buf(), + root: root.to_path_buf(), init, runner, pid_file, @@ -92,14 +94,15 @@ impl Launcher { fn get_state(&self) -> Result { let state = self.runner.get_oci_state()?; let pid = self.runner.get_pid(); - let proc = procfs::process::Process::new(pid)?; + let proc = + procfs::process::Process::new(pid).with_context(|| OzonecErr::ReadProcPid(pid))?; let start_time = proc .stat() - .with_context(|| format!("Failed to access /proc/{}/status", pid))? + .with_context(|| OzonecErr::ReadProcStat(pid))? .starttime; Ok(State::new( - &self.state_root, + &self.root, &self.bundle, state, start_time, diff --git a/ozonec/src/container/mod.rs b/ozonec/src/container/mod.rs index 611af779..bc6905a6 100644 --- a/ozonec/src/container/mod.rs +++ b/ozonec/src/container/mod.rs @@ -11,11 +11,9 @@ // See the Mulan PSL v2 for more details. mod launcher; -mod process; mod state; pub use launcher::{Action, Launcher}; -pub use process::Process; use std::time::SystemTime; @@ -25,6 +23,8 @@ use nix::sys::signal::Signal; use oci_spec::{runtime::RuntimeConfig, state::State as OciState}; +use crate::linux::Process; + pub trait Container { fn get_config(&self) -> &RuntimeConfig; diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index 28c0de31..20a9fd77 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -19,15 +19,22 @@ use std::{ use anyhow::{anyhow, bail, Context, Result}; use libc::pid_t; -use log::error; +use log::{debug, error, info}; use nix::{ - sys::signal::Signal, + errno::Errno, + sys::{ + signal::Signal, + wait::{waitpid, WaitStatus}, + }, unistd::{chown, getegid, geteuid}, }; use procfs::process::ProcState; -use super::notify_socket::NOTIFY_SOCKET; -use crate::container::{Container, Process}; +use super::{notify_socket::NOTIFY_SOCKET, process::clone_process, NotifyListener, Process}; +use crate::{ + container::Container, + utils::{Channel, Message, OzonecErr}, +}; use oci_spec::{ runtime::RuntimeConfig, state::{ContainerStatus, State}, @@ -81,6 +88,64 @@ impl LinuxContainer { if config.linux.is_none() { bail!("There is no linux specific configuration in config.json for Linux container"); } + if config.process.args.is_none() { + bail!("args in process is not set in config.json."); + } + Ok(()) + } + + fn do_first_stage( + &mut self, + process: &mut Process, + parent_channel: &Channel, + fst_stage_channel: &Channel, + notify_listener: Option, + ) -> Result<()> { + debug!("First stage process start"); + + fst_stage_channel + .receiver + .close() + .with_context(|| "Failed to close receiver end of first stage channel")?; + + // Spawn a child process to perform the second stage to initialize container. + let init_pid = clone_process("ozonec:[2:INIT]", || { + self.do_second_stage(process, parent_channel, notify_listener) + .with_context(|| "Second stage process encounters errors")?; + Ok(0) + })?; + + // Send the final container pid to the parent process. + parent_channel.send_init_pid(init_pid)?; + + debug!("First stage process exit"); + Ok(()) + } + + fn do_second_stage( + &mut self, + process: &mut Process, + parent_channel: &Channel, + notify_listener: Option, + ) -> Result<()> { + debug!("Second stage process start"); + + // Tell the parent process that the init process has been cloned. + parent_channel.send_container_created()?; + parent_channel + .sender + .close() + .with_context(|| "Failed to close sender of parent channel")?; + + // Listening on the notify socket to start container. + if let Some(listener) = notify_listener { + listener.wait_for_start_container()?; + listener + .close() + .with_context(|| "Failed to close notify socket")?; + } + + debug!("Container process exit"); Ok(()) } @@ -97,7 +162,7 @@ impl LinuxContainer { let proc_stat = proc .unwrap() .stat() - .with_context(|| format!("Failed to read /proc/{}/stat", self.pid))?; + .with_context(|| OzonecErr::ReadProcStat(self.pid))?; // If starttime is not the same, then pid is reused, and the original process has stopped. if proc_stat.starttime != self.start_time { return Ok(ContainerStatus::Stopped); @@ -162,6 +227,65 @@ impl Container for LinuxContainer { } fn create(&mut self, process: &mut Process) -> Result<()> { + // Create notify socket to notify the container process to start. + let notify_listener = if process.init { + Some(NotifyListener::new(PathBuf::from(&self.root))?) + } else { + None + }; + + // Create channels to communicate with child processes. + let parent_channel = Channel::::new() + .with_context(|| "Failed to create message channel for parent process")?; + let fst_stage_channel = Channel::::new()?; + // Set receivers timeout: 50ms. + parent_channel.receiver.set_timeout(50000)?; + fst_stage_channel.receiver.set_timeout(50000)?; + + // Spawn a child process to perform Stage 1. + let fst_stage_pid = clone_process("ozonec:[1:CHILD]", || { + self.do_first_stage( + process, + &parent_channel, + &fst_stage_channel, + notify_listener, + ) + .with_context(|| "First stage process encounters errors")?; + Ok(0) + })?; + + let init_pid = parent_channel + .recv_init_pid() + .with_context(|| "Failed to receive init pid")?; + parent_channel.recv_container_created()?; + parent_channel + .receiver + .close() + .with_context(|| "Failed to close receiver end of parent channel")?; + + self.pid = init_pid.as_raw(); + self.start_time = procfs::process::Process::new(self.pid) + .with_context(|| OzonecErr::ReadProcPid(self.pid))? + .stat() + .with_context(|| OzonecErr::ReadProcStat(self.pid))? + .starttime; + + match waitpid(fst_stage_pid, None) { + Ok(WaitStatus::Exited(_, 0)) => (), + Ok(WaitStatus::Exited(_, s)) => { + info!("First stage process exits with status: {}", s); + } + Ok(WaitStatus::Signaled(_, sig, _)) => { + info!("First stage process killed by signal: {}", sig) + } + Ok(_) => (), + Err(Errno::ECHILD) => { + info!("First stage process has already been reaped"); + } + Err(e) => { + bail!("Failed to waitpid for first stage process: {e}"); + } + } Ok(()) } diff --git a/ozonec/src/linux/mod.rs b/ozonec/src/linux/mod.rs index 9aed65f4..ef049ae8 100644 --- a/ozonec/src/linux/mod.rs +++ b/ozonec/src/linux/mod.rs @@ -12,6 +12,8 @@ mod container; mod notify_socket; +mod process; pub use container::LinuxContainer; pub use notify_socket::NotifyListener; +pub use process::Process; diff --git a/ozonec/src/container/process.rs b/ozonec/src/linux/process.rs similarity index 45% rename from ozonec/src/container/process.rs rename to ozonec/src/linux/process.rs index 962599ab..59784249 100644 --- a/ozonec/src/container/process.rs +++ b/ozonec/src/linux/process.rs @@ -11,17 +11,22 @@ // See the Mulan PSL v2 for more details. use std::{ + ffi::CString, io::{stderr, stdin, stdout}, os::fd::{AsRawFd, RawFd}, }; +use anyhow::{anyhow, Context, Result}; +use clone3::Clone3; +use libc::SIGCHLD; +use nix::unistd::{self, Pid}; + use oci_spec::process::Process as OciProcess; pub struct Process { pub stdin: Option, pub stdout: Option, pub stderr: Option, - pub term_master: Option, pub init: bool, pub tty: bool, pub oci: OciProcess, @@ -34,7 +39,6 @@ impl Process { stdout: None, stderr: None, tty: oci.terminal, - term_master: None, init, oci: oci.clone(), }; @@ -46,4 +50,45 @@ impl Process { } p } + + pub fn exec_program(&self) -> ! { + // It has been make sure that args is not None in validate_config(). + let args = &self.oci.args.as_ref().unwrap(); + // args don't have 0 byte in the middle such as "hello\0world". + let exec_bin = CString::new(args[0].as_str().as_bytes()).unwrap(); + let args: Vec = args + .iter() + .map(|s| CString::new(s.as_bytes()).unwrap_or_default()) + .collect(); + + let _ = unistd::execvp(&exec_bin, &args).map_err(|e| match e { + nix::Error::UnknownErrno => std::process::exit(-2), + _ => std::process::exit(e as i32), + }); + + unreachable!() + } +} + +// Clone a new child process. +pub fn clone_process Result>(child_name: &str, cb: F) -> Result { + let mut clone3 = Clone3::default(); + clone3.exit_signal(SIGCHLD as u64); + + // SAFETY: FFI call with valid arguments. + match unsafe { clone3.call().with_context(|| "Clone3() error")? } { + 0 => { + prctl::set_name(child_name) + .map_err(|e| anyhow!("Failed to set process name: errno {}", e))?; + let ret = match cb() { + Err(e) => { + eprintln!("Child process exit with errors: {:?}", e); + -1 + } + Ok(exit_code) => exit_code, + }; + std::process::exit(ret); + } + pid => Ok(Pid::from_raw(pid)), + } } diff --git a/ozonec/src/utils/error.rs b/ozonec/src/utils/error.rs new file mode 100644 index 00000000..2df6bb52 --- /dev/null +++ b/ozonec/src/utils/error.rs @@ -0,0 +1,21 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum OzonecErr { + #[error("Failed to access /proc/{0}")] + ReadProcPid(i32), + #[error("Failed to access /proc/{0}/status")] + ReadProcStat(i32), +} diff --git a/ozonec/src/utils/mod.rs b/ozonec/src/utils/mod.rs index 461581f6..0f37aae8 100644 --- a/ozonec/src/utils/mod.rs +++ b/ozonec/src/utils/mod.rs @@ -13,5 +13,7 @@ pub mod logger; mod channel; +mod error; pub use channel::{Channel, Message}; +pub use error::OzonecErr; -- Gitee From cd796fc14642e656d952e5fca4b8102b7fd6cc89 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Thu, 22 Aug 2024 12:02:52 +0800 Subject: [PATCH 353/489] ozonec/linux: Add namespace.rs --- ozonec/src/linux/mod.rs | 1 + ozonec/src/linux/namespace.rs | 66 +++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 ozonec/src/linux/namespace.rs diff --git a/ozonec/src/linux/mod.rs b/ozonec/src/linux/mod.rs index ef049ae8..03c78b93 100644 --- a/ozonec/src/linux/mod.rs +++ b/ozonec/src/linux/mod.rs @@ -11,6 +11,7 @@ // See the Mulan PSL v2 for more details. mod container; +mod namespace; mod notify_socket; mod process; diff --git a/ozonec/src/linux/namespace.rs b/ozonec/src/linux/namespace.rs new file mode 100644 index 00000000..5928e3d0 --- /dev/null +++ b/ozonec/src/linux/namespace.rs @@ -0,0 +1,66 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::collections::HashMap; + +use anyhow::{Context, Result}; +use nix::{ + fcntl::{self, OFlag}, + sched::{setns, unshare, CloneFlags}, + sys::stat::Mode, + unistd, +}; +use oci_spec::linux::{Namespace, NamespaceType}; + +pub struct NsController { + pub namespaces: HashMap, +} + +impl TryFrom> for NsController { + type Error = anyhow::Error; + + fn try_from(namespaces: Vec) -> Result { + Ok(NsController { + namespaces: namespaces + .iter() + .map(|ns| match ns.ns_type.try_into() { + Ok(flag) => Ok((flag, ns.clone())), + Err(e) => Err(e), + }) + .collect::>>()? + .into_iter() + .collect(), + }) + } +} + +impl NsController { + pub fn set_namespace(&self, ns_type: NamespaceType) -> Result<()> { + if let Some(ns) = self.get(ns_type)? { + match ns.path.clone() { + Some(path) => { + let fd = fcntl::open(&path, OFlag::empty(), Mode::empty()) + .with_context(|| format!("fcntl error at opening {}", path.display()))?; + setns(fd, ns_type.try_into()?).with_context(|| "Failed to setns")?; + unistd::close(fd).with_context(|| "Close fcntl fd error")?; + } + None => unshare(ns_type.try_into()?).with_context(|| "Failed to unshare")?, + } + } + Ok(()) + } + + pub fn get(&self, ns_type: NamespaceType) -> Result> { + let clone_flags: CloneFlags = ns_type.try_into()?; + Ok(self.namespaces.get(&clone_flags)) + } +} -- Gitee From 801713d3880fcdb57e862695a4968fbfd857f9a1 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Thu, 22 Aug 2024 12:05:12 +0800 Subject: [PATCH 354/489] ozonec/utils: Add OzonecErr::OpenFile(String) --- ozonec/src/container/state.rs | 6 ++++-- ozonec/src/utils/error.rs | 2 ++ ozonec/src/utils/logger.rs | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/ozonec/src/container/state.rs b/ozonec/src/container/state.rs index 424e2d81..ab97cc36 100644 --- a/ozonec/src/container/state.rs +++ b/ozonec/src/container/state.rs @@ -25,6 +25,8 @@ use serde::{Deserialize, Serialize}; use oci_spec::{runtime::RuntimeConfig, state::State as OciState}; +use crate::utils::OzonecErr; + #[derive(Serialize, Deserialize, Debug, Clone, Default)] #[serde(rename_all = "camelCase")] pub struct State { @@ -79,8 +81,8 @@ impl State { .write(true) .create(true) .truncate(true) - .open(path) - .with_context(|| "Failed to open state file")?; + .open(&path) + .with_context(|| OzonecErr::OpenFile(path.to_string_lossy().to_string()))?; serde_json::to_writer(&state_file, self)?; Ok(()) } diff --git a/ozonec/src/utils/error.rs b/ozonec/src/utils/error.rs index 2df6bb52..46cb6f01 100644 --- a/ozonec/src/utils/error.rs +++ b/ozonec/src/utils/error.rs @@ -18,4 +18,6 @@ pub enum OzonecErr { ReadProcPid(i32), #[error("Failed to access /proc/{0}/status")] ReadProcStat(i32), + #[error("Failed to open {0}")] + OpenFile(String), } diff --git a/ozonec/src/utils/logger.rs b/ozonec/src/utils/logger.rs index 17a35ff8..47265023 100644 --- a/ozonec/src/utils/logger.rs +++ b/ozonec/src/utils/logger.rs @@ -24,6 +24,8 @@ use anyhow::{Context, Result}; use log::{set_boxed_logger, set_max_level, Level, LevelFilter, Log, Metadata, Record}; use nix::unistd::{getpid, gettid}; +use super::OzonecErr; + // Maximum size of log file is 100MB. const LOG_ROTATE_SIZE_MAX: usize = 100 * 1024 * 1024; // Logs are retained for seven days at most. @@ -91,7 +93,7 @@ fn open_log_file(path: &PathBuf) -> Result { .create(true) .mode(0o640) .open(path) - .with_context(|| "Failed to open log file") + .with_context(|| OzonecErr::OpenFile(path.to_string_lossy().to_string())) } fn formatted_time(seconds: i64) -> [i32; 6] { -- Gitee From 2bd150857a7de62e85552371a75988e9382028ec Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Thu, 22 Aug 2024 12:06:05 +0800 Subject: [PATCH 355/489] ozonec/linux: Add namespace support --- ozonec/oci_spec/src/linux.rs | 12 +- ozonec/src/linux/container.rs | 207 ++++++++++++++++++++++++++++++++-- ozonec/src/linux/process.rs | 28 ++++- ozonec/src/utils/channel.rs | 24 ++++ 4 files changed, 256 insertions(+), 15 deletions(-) diff --git a/ozonec/oci_spec/src/linux.rs b/ozonec/oci_spec/src/linux.rs index 234132ee..4de386f3 100644 --- a/ozonec/oci_spec/src/linux.rs +++ b/ozonec/oci_spec/src/linux.rs @@ -16,9 +16,9 @@ use anyhow::{anyhow, Result}; use nix::sched::CloneFlags; use serde::{Deserialize, Serialize}; +/// Available Linux namespaces. #[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, Hash)] #[serde(rename_all = "snake_case")] -/// Available Linux namespaces. pub enum NamespaceType { Cgroup = 0x0200_0000, Ipc = 0x0800_0000, @@ -62,8 +62,8 @@ impl From for String { } } -#[derive(Serialize, Deserialize, Debug, Clone)] /// Namespaces. +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct Namespace { /// Namespace type. #[serde(rename = "type")] @@ -73,9 +73,9 @@ pub struct Namespace { pub path: Option, } +/// UID/GID mapping. #[allow(non_snake_case)] #[derive(Serialize, Deserialize, Debug, Clone)] -/// User namespace mappings. pub struct IdMapping { /// Starting uid/gid in the container. pub containerID: u32, @@ -85,14 +85,14 @@ pub struct IdMapping { pub size: u32, } -#[derive(Serialize, Deserialize, Debug, Clone)] /// Offset for Time Namespace. +#[derive(Serialize, Deserialize, Debug, Clone)] pub struct TimeOffsets { - #[serde(skip_serializing_if = "Option::is_none")] /// Offset of clock (in seconds) in the container. - pub secs: Option, #[serde(skip_serializing_if = "Option::is_none")] + pub secs: Option, /// Offset of clock (in nanoseconds) in the container. + #[serde(skip_serializing_if = "Option::is_none")] pub nanosecs: Option, } diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index 20a9fd77..4be88d30 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -12,13 +12,14 @@ use std::{ collections::HashMap, - fs::{canonicalize, create_dir_all}, + fs::{canonicalize, create_dir_all, OpenOptions}, + io::Write, path::{Path, PathBuf}, time::SystemTime, }; use anyhow::{anyhow, bail, Context, Result}; -use libc::pid_t; +use libc::{c_char, pid_t, setdomainname}; use log::{debug, error, info}; use nix::{ errno::Errno, @@ -26,16 +27,21 @@ use nix::{ signal::Signal, wait::{waitpid, WaitStatus}, }, - unistd::{chown, getegid, geteuid}, + unistd::{chown, getegid, geteuid, sethostname, Gid, Pid, Uid}, }; +use prctl::set_dumpable; use procfs::process::ProcState; -use super::{notify_socket::NOTIFY_SOCKET, process::clone_process, NotifyListener, Process}; +use super::{ + namespace::NsController, notify_socket::NOTIFY_SOCKET, process::clone_process, NotifyListener, + Process, +}; use crate::{ container::Container, utils::{Channel, Message, OzonecErr}, }; use oci_spec::{ + linux::{IdMapping, NamespaceType}, runtime::RuntimeConfig, state::{ContainerStatus, State}, }; @@ -103,11 +109,16 @@ impl LinuxContainer { ) -> Result<()> { debug!("First stage process start"); + self.set_user_namespace(parent_channel, fst_stage_channel, process)?; + fst_stage_channel .receiver .close() .with_context(|| "Failed to close receiver end of first stage channel")?; + // New pid namespace goes intto effect in cloned child processes. + self.set_pid_namespace()?; + // Spawn a child process to perform the second stage to initialize container. let init_pid = clone_process("ozonec:[2:INIT]", || { self.do_second_stage(process, parent_channel, notify_listener) @@ -130,6 +141,10 @@ impl LinuxContainer { ) -> Result<()> { debug!("Second stage process start"); + self.set_rest_namespaces()?; + + process.set_additional_gids()?; + // Tell the parent process that the init process has been cloned. parent_channel.send_container_created()?; parent_channel @@ -144,9 +159,7 @@ impl LinuxContainer { .close() .with_context(|| "Failed to close notify socket")?; } - - debug!("Container process exit"); - Ok(()) + process.exec_program(); } fn container_status(&self) -> Result { @@ -179,6 +192,175 @@ impl LinuxContainer { } } } + + fn ns_controller(&self) -> Result { + Ok(self + .config + .linux + .as_ref() + .unwrap() + .namespaces + .clone() + .try_into()?) + } + + fn set_user_namespace( + &self, + parent_channel: &Channel, + fst_stage_channel: &Channel, + process: &Process, + ) -> Result<()> { + let ns_controller: NsController = self.ns_controller()?; + + if let Some(ns) = ns_controller.get(NamespaceType::User)? { + ns_controller + .set_namespace(NamespaceType::User) + .with_context(|| "Failed to set user namespace")?; + + if ns.path.is_none() { + // Child process needs to be dumpable, otherwise the parent process is not + // allowed to write the uid/gid mappings. + set_dumpable(true).map_err(|e| anyhow!("Failed to set process dumpable: {e}"))?; + parent_channel + .send_id_mappings() + .with_context(|| "Failed to send id mappings")?; + fst_stage_channel + .recv_id_mappings_done() + .with_context(|| "Failed to receive id mappings done")?; + set_dumpable(false) + .map_err(|e| anyhow!("Failed to set process undumpable: {e}"))?; + } + + // After UID/GID mappings are configured, ozonec wants to make sure continue as + // the root user inside the new user namespace. This is required because the + // process of configuring the container process will require root, even though + // the root in the user namespace is likely mapped to an non-privileged user. + process.set_id(Gid::from_raw(0), Uid::from_raw(0))?; + } + Ok(()) + } + + fn is_namespace_set(&self, ns_type: NamespaceType) -> Result { + let ns_controller: NsController = self.ns_controller()?; + Ok(ns_controller.get(ns_type)?.is_some()) + } + + fn set_pid_namespace(&self) -> Result<()> { + let ns_controller = self.ns_controller()?; + + if ns_controller.get(NamespaceType::Pid)?.is_some() { + ns_controller + .set_namespace(NamespaceType::Pid) + .with_context(|| "Failed to set pid namespace")?; + } + Ok(()) + } + + fn set_rest_namespaces(&self) -> Result<()> { + let ns_config = &self.config.linux.as_ref().unwrap().namespaces; + let ns_controller: NsController = ns_config.clone().try_into()?; + + for ns in ns_config { + match ns.ns_type { + // User namespace and pid namespace have been set in the first stage. + // Mount namespace is going to be set later to avoid failure with + // existed namespaces. + NamespaceType::User | NamespaceType::Pid | NamespaceType::Mount => (), + _ => ns_controller.set_namespace(ns.ns_type).with_context(|| { + format!( + "Failed to set {} namespace", + >::into(ns.ns_type) + ) + })?, + } + + if ns.ns_type == NamespaceType::Uts && ns.path.is_none() { + if let Some(hostname) = &self.config.hostname { + sethostname(hostname).with_context(|| "Failed to set hostname")?; + } + if let Some(domainname) = &self.config.domainname { + let errno; + + // SAFETY: FFI call with valid arguments. + match unsafe { + setdomainname( + domainname.as_bytes().as_ptr() as *const c_char, + domainname.len(), + ) + } { + 0 => return Ok(()), + -1 => errno = nix::Error::last(), + _ => errno = nix::Error::UnknownErrno, + } + bail!("Failed to set domainname: {}", errno); + } + } + } + + ns_controller + .set_namespace(NamespaceType::Mount) + .with_context(|| "Failed to set mount namespace")?; + Ok(()) + } + + fn set_id_mappings( + &self, + parent_channel: &Channel, + fst_stage_channel: &Channel, + fst_stage_pid: &Pid, + ) -> Result<()> { + parent_channel + .recv_id_mappings() + .with_context(|| "Failed to receive id mappings")?; + LinuxContainer::set_groups(fst_stage_pid, false) + .with_context(|| "Failed to disable setting groups")?; + + if let Some(linux) = self.config.linux.as_ref() { + if let Some(uid_mappings) = linux.uidMappings.as_ref() { + self.write_id_mapping(uid_mappings, fst_stage_pid, "uid_map")?; + } + if let Some(gid_mappings) = linux.gidMappings.as_ref() { + self.write_id_mapping(gid_mappings, fst_stage_pid, "gid_map")?; + } + } + + fst_stage_channel + .send_id_mappings_done() + .with_context(|| "Failed to send id mapping done")?; + fst_stage_channel + .sender + .close() + .with_context(|| "Failed to close fst_stage_channel sender")?; + Ok(()) + } + + fn write_id_mapping(&self, mappings: &Vec, pid: &Pid, file: &str) -> Result<()> { + let path = format!("/proc/{}/{}", pid.as_raw().to_string(), file); + let mut opened_file = OpenOptions::new() + .write(true) + .open(&path) + .with_context(|| OzonecErr::OpenFile(path))?; + let mut id_mappings = String::from(""); + + for m in mappings { + let mapping = format!("{} {} {}\n", m.containerID, m.hostID, m.size); + id_mappings = id_mappings + &mapping; + } + opened_file + .write_all(&id_mappings.as_bytes()) + .with_context(|| "Failed to write id mappings")?; + Ok(()) + } + + fn set_groups(pid: &Pid, allow: bool) -> Result<()> { + let path = format!("/proc/{}/setgroups", pid.as_raw().to_string()); + if allow == true { + std::fs::write(&path, "allow")? + } else { + std::fs::write(&path, "deny")? + } + Ok(()) + } } impl Container for LinuxContainer { @@ -234,6 +416,13 @@ impl Container for LinuxContainer { None }; + // Make the process undumpable to avoid various race conditions that could cause + // processes in namespaces to join to access host resources (or execute code). + if !self.config.linux.as_ref().unwrap().namespaces.is_empty() { + prctl::set_dumpable(false) + .map_err(|e| anyhow!("Failed to set process undumpable: {}", e))?; + } + // Create channels to communicate with child processes. let parent_channel = Channel::::new() .with_context(|| "Failed to create message channel for parent process")?; @@ -254,6 +443,10 @@ impl Container for LinuxContainer { Ok(0) })?; + if self.is_namespace_set(NamespaceType::User)? { + self.set_id_mappings(&parent_channel, &fst_stage_channel, &fst_stage_pid)?; + } + let init_pid = parent_channel .recv_init_pid() .with_context(|| "Failed to receive init pid")?; diff --git a/ozonec/src/linux/process.rs b/ozonec/src/linux/process.rs index 59784249..d6dc61ef 100644 --- a/ozonec/src/linux/process.rs +++ b/ozonec/src/linux/process.rs @@ -12,14 +12,15 @@ use std::{ ffi::CString, + fs::read_to_string, io::{stderr, stdin, stdout}, os::fd::{AsRawFd, RawFd}, }; -use anyhow::{anyhow, Context, Result}; +use anyhow::{anyhow, bail, Context, Result}; use clone3::Clone3; use libc::SIGCHLD; -use nix::unistd::{self, Pid}; +use nix::unistd::{self, setresgid, setresuid, Gid, Pid, Uid}; use oci_spec::process::Process as OciProcess; @@ -51,6 +52,29 @@ impl Process { p } + pub fn set_additional_gids(&self) -> Result<()> { + if let Some(additional_gids) = &self.oci.user.additionalGids { + let setgroups = read_to_string("proc/self/setgroups") + .with_context(|| "Failed to read setgroups")?; + if setgroups.trim() == "deny" { + bail!("Cannot set additional gids as setgroup is desabled"); + } + + let gids: Vec = additional_gids + .iter() + .map(|gid| Gid::from_raw(*gid)) + .collect(); + unistd::setgroups(&gids).with_context(|| "Failed to set additional gids")?; + } + Ok(()) + } + + pub fn set_id(&self, gid: Gid, uid: Uid) -> Result<()> { + setresgid(gid, gid, gid).with_context(|| "Failed to setresgid")?; + setresuid(uid, uid, uid).with_context(|| "Failed to setresuid")?; + Ok(()) + } + pub fn exec_program(&self) -> ! { // It has been make sure that args is not None in validate_config(). let args = &self.oci.args.as_ref().unwrap(); diff --git a/ozonec/src/utils/channel.rs b/ozonec/src/utils/channel.rs index 4e303d10..b74c3a78 100644 --- a/ozonec/src/utils/channel.rs +++ b/ozonec/src/utils/channel.rs @@ -175,6 +175,18 @@ impl Channel { .with_context(|| "Failed to send created message to parent process") } + pub fn recv_id_mappings(&self) -> Result<()> { + let msg = self.receiver.recv()?; + match msg { + Message::IdMappingStart => Ok(()), + _ => bail!("Expect receiving IdMappingStart, but got {:?}", msg), + } + } + + pub fn send_id_mappings(&self) -> Result<()> { + self.sender.send(Message::IdMappingStart) + } + pub fn recv_init_pid(&self) -> Result { let msg = self.receiver.recv()?; match msg { @@ -183,6 +195,18 @@ impl Channel { } } + pub fn recv_id_mappings_done(&self) -> Result<()> { + let msg = self.receiver.recv()?; + match msg { + Message::IdMappingDone => Ok(()), + _ => bail!("Expect receiving IdMappingDone, but got {:?}", msg), + } + } + + pub fn send_id_mappings_done(&self) -> Result<()> { + self.sender.send(Message::IdMappingDone) + } + pub fn send_init_pid(&self, pid: Pid) -> Result<()> { self.sender .send(Message::InitReady(pid.as_raw())) -- Gitee From b1a86eb594d710bc7caf089dbb1fba80e07c4c8e Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Thu, 22 Aug 2024 17:21:08 +0800 Subject: [PATCH 356/489] ozonec/linux: Add mount.rs --- ozonec/src/linux/container.rs | 6 +- ozonec/src/linux/mod.rs | 1 + ozonec/src/linux/mount.rs | 195 ++++++++++++++++++++++++++++++++++ ozonec/src/utils/error.rs | 2 + 4 files changed, 200 insertions(+), 4 deletions(-) create mode 100644 ozonec/src/linux/mount.rs diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index 4be88d30..36f819e3 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -72,10 +72,8 @@ impl LinuxContainer { *exist = true; bail!("Container {} already exists", id); } - create_dir_all(container_dir.as_str()).map_err(|e| { - error!("Failed to create container directory: {}", e); - anyhow!(e).context("Failed to create container directory") - })?; + create_dir_all(container_dir.as_str()) + .with_context(|| OzonecErr::CreateDir(container_dir.clone()))?; chown(container_dir.as_str(), Some(geteuid()), Some(getegid())) .with_context(|| "Failed to chown container directory")?; diff --git a/ozonec/src/linux/mod.rs b/ozonec/src/linux/mod.rs index 03c78b93..c4374b3a 100644 --- a/ozonec/src/linux/mod.rs +++ b/ozonec/src/linux/mod.rs @@ -11,6 +11,7 @@ // See the Mulan PSL v2 for more details. mod container; +mod mount; mod namespace; mod notify_socket; mod process; diff --git a/ozonec/src/linux/mount.rs b/ozonec/src/linux/mount.rs new file mode 100644 index 00000000..a06efffe --- /dev/null +++ b/ozonec/src/linux/mount.rs @@ -0,0 +1,195 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::{ + fs::{self, canonicalize, create_dir_all, read_to_string, File}, + path::{Path, PathBuf}, +}; + +use anyhow::{anyhow, Context, Result}; +use nix::mount::MsFlags; + +use oci_spec::runtime::Mount as OciMount; + +use crate::utils::OzonecErr; + +pub struct Mount { + rootfs: PathBuf, +} + +impl Mount { + pub fn new(rootfs: &PathBuf) -> Self { + Self { + rootfs: rootfs.clone(), + } + } + + fn get_mount_flag_data(&self, mount: &OciMount) -> (MsFlags, String) { + let mut ms_flags = MsFlags::empty(); + let mut data = Vec::new(); + + if let Some(options) = &mount.options { + for option in options { + if let Some((clear, flag)) = match option.as_str() { + "defaults" => Some((false, MsFlags::empty())), + "ro" => Some((false, MsFlags::MS_RDONLY)), + "rw" => Some((true, MsFlags::MS_RDONLY)), + "suid" => Some((true, MsFlags::MS_NOSUID)), + "nosuid" => Some((false, MsFlags::MS_NOSUID)), + "dev" => Some((true, MsFlags::MS_NODEV)), + "nodev" => Some((false, MsFlags::MS_NODEV)), + "exec" => Some((true, MsFlags::MS_NOEXEC)), + "noexec" => Some((false, MsFlags::MS_NOEXEC)), + "sync" => Some((false, MsFlags::MS_SYNCHRONOUS)), + "async" => Some((true, MsFlags::MS_SYNCHRONOUS)), + "dirsync" => Some((false, MsFlags::MS_DIRSYNC)), + "remount" => Some((false, MsFlags::MS_REMOUNT)), + "mand" => Some((false, MsFlags::MS_MANDLOCK)), + "nomand" => Some((true, MsFlags::MS_MANDLOCK)), + "atime" => Some((true, MsFlags::MS_NOATIME)), + "noatime" => Some((false, MsFlags::MS_NOATIME)), + "diratime" => Some((true, MsFlags::MS_NODIRATIME)), + "nodiratime" => Some((false, MsFlags::MS_NODIRATIME)), + "bind" => Some((false, MsFlags::MS_BIND)), + "rbind" => Some((false, MsFlags::MS_BIND | MsFlags::MS_REC)), + "unbindable" => Some((false, MsFlags::MS_UNBINDABLE)), + "runbindable" => Some((false, MsFlags::MS_UNBINDABLE | MsFlags::MS_REC)), + "private" => Some((false, MsFlags::MS_PRIVATE)), + "rprivate" => Some((false, MsFlags::MS_PRIVATE | MsFlags::MS_REC)), + "shared" => Some((false, MsFlags::MS_SHARED)), + "rshared" => Some((false, MsFlags::MS_SHARED | MsFlags::MS_REC)), + "slave" => Some((false, MsFlags::MS_SLAVE)), + "rslave" => Some((false, MsFlags::MS_SLAVE | MsFlags::MS_REC)), + "relatime" => Some((false, MsFlags::MS_RELATIME)), + "norelatime" => Some((true, MsFlags::MS_RELATIME)), + "strictatime" => Some((false, MsFlags::MS_STRICTATIME)), + "nostrictatime" => Some((true, MsFlags::MS_STRICTATIME)), + _ => None, + } { + if clear { + ms_flags &= !flag; + } else { + ms_flags |= flag; + } + continue; + } + data.push(option.as_str()); + } + } + (ms_flags, data.join(",")) + } + + fn do_one_mount(&self, mount: &OciMount, label: &Option) -> Result<()> { + let fs_type = mount.fs_type.as_deref(); + let (flag, mut data) = self.get_mount_flag_data(mount); + + if let Some(label) = label { + if fs_type != Some("proc") && fs_type != Some("sysfs") { + match data.is_empty() { + true => data = format!("context=\"{}\"", label), + false => data = format!("{},context=\"{}\"", data, label), + } + } + } + + // If destination begins with "/", then ignore the first "/". + let binding = self.rootfs.join(&mount.destination[1..]); + let dest_path = Path::new(&binding); + let binding = &mount + .source + .clone() + .ok_or(anyhow!("Mount source not set"))?; + let source = Path::new(&binding); + let canonicalized; + let src_path = match fs_type { + Some("bind") => { + canonicalized = canonicalize(source) + .with_context(|| format!("Failed to canonicalize {}", source.display()))?; + canonicalized.as_path() + } + _ => source, + }; + + match fs_type { + Some("bind") => { + let dir = if src_path.is_file() { + dest_path.parent().ok_or(anyhow!( + "Failed to get parent directory: {}", + dest_path.display() + ))? + } else { + dest_path + }; + + create_dir_all(dir) + .with_context(|| OzonecErr::CreateDir(dir.to_string_lossy().to_string()))?; + if src_path.is_file() && !dest_path.exists() { + File::create(dest_path) + .with_context(|| format!("Failed to create {}", dest_path.display()))?; + } + + nix::mount::mount( + Some(src_path), + dest_path, + None::<&str>, + MsFlags::MS_BIND | MsFlags::MS_REC, + Some(data.as_str()), + )?; + } + _ => { + create_dir_all(&dest_path).with_context(|| { + OzonecErr::CreateDir(dest_path.to_string_lossy().to_string()) + })?; + // Sysfs doesn't support duplicate mounting to one directory. + if self.is_mounted_sysfs_dir(&dest_path.to_string_lossy().to_string()) { + nix::mount::umount(dest_path) + .with_context(|| format!("Failed to umount {}", dest_path.display()))?; + } + nix::mount::mount( + Some(src_path), + dest_path, + fs_type, + flag, + Some(data.as_str()), + )?; + } + } + + Ok(()) + } + + fn is_mounted_sysfs_dir(&self, path: &str) -> bool { + if let Ok(metadata) = fs::metadata(path) { + if metadata.file_type().is_dir() { + if let Ok(mounts) = read_to_string("/proc/mounts") { + for line in mounts.lines() { + let parts: Vec<&str> = line.split_whitespace().collect(); + if parts.len() >= 3 && parts[1] == path && parts[2] == "sysfs" { + return true; + } + } + } + } + } + false + } + + pub fn do_mounts(&self, mounts: &Vec, label: &Option) -> Result<()> { + for mount in mounts { + match mount.fs_type.as_deref() { + Some("cgroup") => (), + _ => self.do_one_mount(mount, label)?, + } + } + Ok(()) + } +} diff --git a/ozonec/src/utils/error.rs b/ozonec/src/utils/error.rs index 46cb6f01..24c38ac6 100644 --- a/ozonec/src/utils/error.rs +++ b/ozonec/src/utils/error.rs @@ -20,4 +20,6 @@ pub enum OzonecErr { ReadProcStat(i32), #[error("Failed to open {0}")] OpenFile(String), + #[error("Failed to create directory {0}")] + CreateDir(String), } -- Gitee From e25e488307d68116e7e0b15db090c109ad3ce312 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Thu, 22 Aug 2024 18:31:56 +0800 Subject: [PATCH 357/489] ozonec/linux: Add support for mounting cgroups --- ozonec/src/linux/mount.rs | 112 ++++++++++++++++++++++++++++++++++++-- ozonec/src/utils/error.rs | 6 ++ 2 files changed, 112 insertions(+), 6 deletions(-) diff --git a/ozonec/src/linux/mount.rs b/ozonec/src/linux/mount.rs index a06efffe..972be73a 100644 --- a/ozonec/src/linux/mount.rs +++ b/ozonec/src/linux/mount.rs @@ -11,16 +11,25 @@ // See the Mulan PSL v2 for more details. use std::{ + collections::HashMap, fs::{self, canonicalize, create_dir_all, read_to_string, File}, path::{Path, PathBuf}, }; -use anyhow::{anyhow, Context, Result}; -use nix::mount::MsFlags; +use anyhow::{anyhow, bail, Context, Result}; +use nix::{ + mount::MsFlags, + sys::statfs::{statfs, CGROUP2_SUPER_MAGIC}, +}; +use crate::utils::OzonecErr; use oci_spec::runtime::Mount as OciMount; +use procfs::process::{MountInfo, Process}; -use crate::utils::OzonecErr; +enum CgroupType { + CgroupV1, + CgroupV2, +} pub struct Mount { rootfs: PathBuf, @@ -143,7 +152,8 @@ impl Mount { None::<&str>, MsFlags::MS_BIND | MsFlags::MS_REC, Some(data.as_str()), - )?; + ) + .with_context(|| OzonecErr::Mount(src_path.to_string_lossy().to_string()))?; } _ => { create_dir_all(&dest_path).with_context(|| { @@ -160,7 +170,8 @@ impl Mount { fs_type, flag, Some(data.as_str()), - )?; + ) + .with_context(|| OzonecErr::Mount(src_path.to_string_lossy().to_string()))?; } } @@ -186,10 +197,99 @@ impl Mount { pub fn do_mounts(&self, mounts: &Vec, label: &Option) -> Result<()> { for mount in mounts { match mount.fs_type.as_deref() { - Some("cgroup") => (), + Some("cgroup") => match self.cgroup_type()? { + CgroupType::CgroupV1 => self + .do_cgroup_mount(mount) + .with_context(|| "Failed to do cgroup mount")?, + CgroupType::CgroupV2 => bail!("Cgroup V2 is not supported now"), + }, _ => self.do_one_mount(mount, label)?, } } Ok(()) } + + fn do_cgroup_mount(&self, mount: &OciMount) -> Result<()> { + // If destination begins with "/", then ignore the first "/". + let binding = self.rootfs.join(&mount.destination[1..]); + let mut dest = Path::new(&binding); + nix::mount::mount( + Some("tmpfs"), + dest, + Some("tmpfs"), + MsFlags::MS_NOEXEC | MsFlags::MS_NOSUID | MsFlags::MS_NODEV, + None::<&str>, + ) + .with_context(|| OzonecErr::Mount(String::from("tmpfs")))?; + + let process = Process::myself().with_context(|| OzonecErr::AccessProcSelf)?; + let mnt_info: Vec = + process.mountinfo().with_context(|| OzonecErr::GetMntInfo)?; + + let proc_cgroups: HashMap = process + .cgroups() + .with_context(|| "Failed to get cgroups belong to")? + .into_iter() + .map(|cgroup| (cgroup.controllers.join(","), cgroup.pathname)) + .collect(); + // Get all of available cgroup mount points. + let host_cgroups: Vec = mnt_info + .into_iter() + .filter(|m| m.fs_type == "cgroup") + .map(|m| m.mount_point) + .collect(); + for cg_path in host_cgroups { + let binding = self.rootfs.join( + cg_path + .strip_prefix("/") + .with_context(|| format!("Strip {} error", cg_path.display()))?, + ); + dest = Path::new(&binding); + let cg = cg_path + .file_name() + .ok_or(anyhow!("Failed to get controller file"))? + .to_str() + .ok_or(anyhow!( + "Convert {:?} to string error", + cg_path.file_name().unwrap() + ))?; + let proc_cg_key = if cg == "systemd" { + String::from("systemd") + } else { + cg.to_string() + }; + + if let Some(src) = proc_cgroups.get(&proc_cg_key) { + let source = cg_path.join(&src[1..]); + if !dest.exists() { + create_dir_all(dest).with_context(|| { + OzonecErr::CreateDir(dest.to_string_lossy().to_string()) + })?; + } + nix::mount::mount( + Some(&source), + dest, + Some("bind"), + MsFlags::MS_BIND | MsFlags::MS_REC, + None::<&str>, + ) + .with_context(|| OzonecErr::Mount(source.to_string_lossy().to_string()))?; + } + } + + Ok(()) + } + + fn cgroup_type(&self) -> Result { + let cgroup_path = Path::new("/sys/fs/cgroup"); + if !cgroup_path.exists() { + bail!("/sys/fs/cgroup doesn't exist."); + } + + let st = statfs(cgroup_path).with_context(|| "statfs /sys/fs/cgroup error")?; + if st.filesystem_type() == CGROUP2_SUPER_MAGIC { + return Ok(CgroupType::CgroupV2); + } + Ok(CgroupType::CgroupV1) + } } diff --git a/ozonec/src/utils/error.rs b/ozonec/src/utils/error.rs index 24c38ac6..9c00bd13 100644 --- a/ozonec/src/utils/error.rs +++ b/ozonec/src/utils/error.rs @@ -22,4 +22,10 @@ pub enum OzonecErr { OpenFile(String), #[error("Failed to create directory {0}")] CreateDir(String), + #[error("Failed to mount {0}")] + Mount(String), + #[error("Failed to access /proc/self")] + AccessProcSelf, + #[error("Failed to get mountinfo")] + GetMntInfo, } -- Gitee From 6cfa2f0ed033d3fccdad3d81d989bddc674ffe33 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Fri, 23 Aug 2024 09:21:23 +0800 Subject: [PATCH 358/489] ozonec/linux: Add device.rs --- ozonec/src/linux/device.rs | 230 +++++++++++++++++++++++++++++++++++++ ozonec/src/linux/mod.rs | 1 + 2 files changed, 231 insertions(+) create mode 100644 ozonec/src/linux/device.rs diff --git a/ozonec/src/linux/device.rs b/ozonec/src/linux/device.rs new file mode 100644 index 00000000..baa67ab1 --- /dev/null +++ b/ozonec/src/linux/device.rs @@ -0,0 +1,230 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::{ + fs::{create_dir_all, remove_file, File}, + path::{Path, PathBuf}, +}; + +use anyhow::{anyhow, bail, Context, Result}; +use nix::{ + mount::MsFlags, + sys::stat::{makedev, mknod, Mode, SFlag}, + unistd::{chown, Gid, Uid}, +}; +use oci_spec::linux::Device as OciDevice; + +use crate::utils::OzonecErr; + +pub struct Device { + rootfs: PathBuf, +} + +impl Device { + pub fn new(rootfs: PathBuf) -> Self { + Self { rootfs } + } + + fn default_devices(&self) -> Vec { + vec![ + DeviceInfo { + path: self.rootfs.join("dev/null"), + dev_type: "c".to_string(), + major: 1, + minor: 3, + file_mode: Some(0o666u32), + uid: None, + gid: None, + }, + DeviceInfo { + path: self.rootfs.join("dev/zero"), + dev_type: "c".to_string(), + major: 1, + minor: 5, + file_mode: Some(0o666u32), + uid: None, + gid: None, + }, + DeviceInfo { + path: self.rootfs.join("dev/full"), + dev_type: "c".to_string(), + major: 1, + minor: 7, + file_mode: Some(0o666u32), + uid: None, + gid: None, + }, + DeviceInfo { + path: self.rootfs.join("dev/random"), + dev_type: "c".to_string(), + major: 1, + minor: 8, + file_mode: Some(0o666u32), + uid: None, + gid: None, + }, + DeviceInfo { + path: self.rootfs.join("dev/urandom"), + dev_type: "c".to_string(), + major: 1, + minor: 9, + file_mode: Some(0o666u32), + uid: None, + gid: None, + }, + DeviceInfo { + path: self.rootfs.join("dev/tty"), + dev_type: "c".to_string(), + major: 5, + minor: 0, + file_mode: Some(0o666u32), + uid: None, + gid: None, + }, + ] + } + + fn create_device_dir(&self, path: &PathBuf) -> Result<()> { + let dir = Path::new(path).parent().ok_or(anyhow!( + "Failed to get parent directory: {}", + path.display() + ))?; + if !dir.exists() { + create_dir_all(dir) + .with_context(|| OzonecErr::CreateDir(dir.to_string_lossy().to_string()))?; + } + Ok(()) + } + + fn get_sflag(&self, dev_type: &str) -> Result { + let sflag = match dev_type { + "c" => SFlag::S_IFCHR, + "b" => SFlag::S_IFBLK, + "u" => SFlag::S_IFCHR, + "p" => SFlag::S_IFIFO, + _ => bail!("Not supported device type: {}", dev_type), + }; + Ok(sflag) + } + + fn bind_device(&self, dev: &DeviceInfo) -> Result<()> { + self.create_device_dir(&dev.path)?; + + let binding = dev.path.to_string_lossy().to_string(); + let stripped_path = binding + .strip_prefix(&self.rootfs.to_string_lossy().to_string()) + .ok_or(anyhow!("Invalid device path"))?; + let src_path = PathBuf::from(stripped_path); + + if !dev.path.exists() { + File::create(&dev.path) + .with_context(|| format!("Failed to create {}", dev.path.display()))?; + } + nix::mount::mount( + Some(&src_path), + &dev.path, + Some("bind"), + MsFlags::MS_BIND, + None::<&str>, + ) + .with_context(|| OzonecErr::Mount(stripped_path.to_string()))?; + + Ok(()) + } + + fn mknod_device(&self, dev: &DeviceInfo) -> Result<()> { + self.create_device_dir(&dev.path)?; + + let sflag = self.get_sflag(&dev.dev_type)?; + let device = makedev(dev.major as u64, dev.minor as u64); + mknod( + &dev.path, + sflag, + Mode::from_bits_truncate(dev.file_mode.unwrap_or(0)), + device, + )?; + chown( + &dev.path, + dev.uid.map(Uid::from_raw), + dev.gid.map(Gid::from_raw), + ) + .with_context(|| "Failed to chown")?; + + Ok(()) + } + + pub fn create_default_devices(&self, mknod: bool) -> Result<()> { + let default_devs = self.default_devices(); + for dev in default_devs { + if mknod { + self.mknod_device(&dev) + .with_context(|| format!("Failed to mknod device: {}", dev.path.display()))?; + } else { + self.bind_device(&dev) + .with_context(|| format!("Failed to bind device: {}", dev.path.display()))?; + } + } + Ok(()) + } + + pub fn is_default_device(&self, dev: &OciDevice) -> bool { + for d in &self.default_devices() { + let path = self.rootfs.join(&dev.path.clone()[1..]); + if path == d.path { + return true; + } + } + return false; + } + + pub fn delete_device(&self, dev: &OciDevice) -> Result<()> { + let path = self.rootfs.join(&dev.path.clone()[1..]); + remove_file(&path).with_context(|| format!("Failed to delete {}", path.display()))?; + Ok(()) + } + + pub fn create_device(&self, dev: &OciDevice, mknod: bool) -> Result<()> { + let path = self.rootfs.join(&dev.path.clone()[1..]); + let major = dev + .major + .ok_or(anyhow!("major not set for device {}", dev.path))?; + let minor = dev + .minor + .ok_or(anyhow!("minor not set for device {}", dev.path))?; + let dev_info = DeviceInfo { + path, + dev_type: dev.dev_type.clone(), + major, + minor, + file_mode: dev.fileMode, + uid: dev.uid, + gid: dev.gid, + }; + + if mknod { + self.mknod_device(&dev_info)?; + } else { + self.bind_device(&dev_info)?; + } + Ok(()) + } +} + +struct DeviceInfo { + path: PathBuf, + dev_type: String, + major: i64, + minor: i64, + file_mode: Option, + uid: Option, + gid: Option, +} diff --git a/ozonec/src/linux/mod.rs b/ozonec/src/linux/mod.rs index c4374b3a..ea85d598 100644 --- a/ozonec/src/linux/mod.rs +++ b/ozonec/src/linux/mod.rs @@ -11,6 +11,7 @@ // See the Mulan PSL v2 for more details. mod container; +mod device; mod mount; mod namespace; mod notify_socket; -- Gitee From ef2adcba80b05f8673b975ea2da5625c013a0987 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Fri, 23 Aug 2024 11:57:28 +0800 Subject: [PATCH 359/489] ozonec/linux: Add rootfs.rs --- ozonec/src/linux/mod.rs | 1 + ozonec/src/linux/rootfs.rs | 231 +++++++++++++++++++++++++++++++++++++ 2 files changed, 232 insertions(+) create mode 100644 ozonec/src/linux/rootfs.rs diff --git a/ozonec/src/linux/mod.rs b/ozonec/src/linux/mod.rs index ea85d598..84fff70c 100644 --- a/ozonec/src/linux/mod.rs +++ b/ozonec/src/linux/mod.rs @@ -16,6 +16,7 @@ mod mount; mod namespace; mod notify_socket; mod process; +mod rootfs; pub use container::LinuxContainer; pub use notify_socket::NotifyListener; diff --git a/ozonec/src/linux/rootfs.rs b/ozonec/src/linux/rootfs.rs new file mode 100644 index 00000000..ac67d325 --- /dev/null +++ b/ozonec/src/linux/rootfs.rs @@ -0,0 +1,231 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::{ + fs::remove_file, + os::unix::fs::symlink, + path::{Path, PathBuf}, +}; + +use anyhow::{bail, Context, Result}; +use nix::{ + fcntl::{open, OFlag}, + mount::{umount2, MntFlags, MsFlags}, + sys::stat::{umask, Mode}, + unistd::{chroot, fchdir, pivot_root}, + NixPath, +}; +use procfs::process::Process; + +use super::{device::Device, mount::Mount}; +use crate::utils::OzonecErr; +use oci_spec::{ + linux::Device as OciDevice, + runtime::{Mount as OciMount, RuntimeConfig}, +}; + +pub struct Rootfs { + pub path: PathBuf, + propagation_flags: MsFlags, + mounts: Vec, + // Should we mknod the device or bind one. + mknod_device: bool, + devices: Vec, +} + +impl Rootfs { + pub fn new( + path: PathBuf, + propagation: Option, + mounts: Vec, + mknod_device: bool, + devices: Vec, + ) -> Result { + if !path.exists() { + bail!("Rootfs directory not exist"); + } + + let propagation_flags = Self::get_mount_flags(propagation)?; + Ok(Self { + path, + propagation_flags, + mounts, + mknod_device, + devices, + }) + } + + fn get_mount_flags(propagation: Option) -> Result { + let flags = match propagation.as_deref() { + Some("shared") => MsFlags::MS_SHARED, + Some("private") => MsFlags::MS_PRIVATE, + Some("slave") => MsFlags::MS_SLAVE, + Some("unbindable") => MsFlags::MS_UNBINDABLE, + Some(_) => bail!("Invalid rootfsPropagation"), + None => MsFlags::MS_REC | MsFlags::MS_SLAVE, + }; + Ok(flags) + } + + fn set_propagation(&self) -> Result<()> { + nix::mount::mount( + None::<&str>, + Path::new("/"), + None::<&str>, + self.propagation_flags, + None::<&str>, + ) + .with_context(|| "Failed to set rootfs mount propagation")?; + Ok(()) + } + + fn mount(&self) -> Result<()> { + nix::mount::mount( + Some(&self.path), + &self.path, + None::<&str>, + MsFlags::MS_BIND | MsFlags::MS_REC, + None::<&str>, + )?; + Ok(()) + } + + fn make_parent_mount_private(&self) -> Result<()> { + let process = Process::myself().with_context(|| OzonecErr::AccessProcSelf)?; + let mount_info = process.mountinfo().with_context(|| OzonecErr::GetMntInfo)?; + + match mount_info + .into_iter() + .filter(|m| self.path.starts_with(&m.mount_point) && m.mount_point != self.path) + .map(|m| m.mount_point) + .max_by_key(|m| m.len()) + .as_ref() + { + Some(m) => { + nix::mount::mount(Some(m), m, None::<&str>, MsFlags::MS_PRIVATE, None::<&str>)? + } + None => (), + } + Ok(()) + } + + // OCI spec requires runtime MUST create the following symlinks if the source file exists after + // processing mounts: + // dev/fd -> /proc/self/fd + // dev/stdin -> /proc/self/fd/0 + // dev/stdout -> /proc/self/fd/1 + // dev/stderr -> /proc/self/fd/2 + fn set_default_symlinks(&self) -> Result<()> { + let link_pairs = vec![ + ((&self.path).join("dev/fd"), "/proc/self/fd"), + ((&self.path).join("dev/stdin"), "/proc/self/fd/0"), + ((&self.path).join("dev/stdout"), "/proc/self/fd/1"), + ((&self.path).join("dev/stderr"), "/proc/self/fd/2"), + ]; + + for pair in link_pairs { + let cloned_pair = pair.clone(); + symlink(pair.1, pair.0).with_context(|| { + format!( + "Failed to create symlink {} -> {}", + cloned_pair.0.display(), + cloned_pair.1 + ) + })?; + } + Ok(()) + } + + fn do_mounts(&self, config: &RuntimeConfig) -> Result<()> { + let mount = Mount::new(&self.path); + mount + .do_mounts(&self.mounts, &config.linux.as_ref().unwrap().mountLabel) + .with_context(|| "Failed to do mounts")?; + Ok(()) + } + + fn link_ptmx(&self) -> Result<()> { + let ptmx = self.path.clone().join("dev/ptmx"); + if ptmx.exists() { + remove_file(&ptmx).with_context(|| "Failed to delete ptmx")?; + } + symlink("pts/ptmx", &ptmx) + .with_context(|| format!("Failed to create symlink {} -> pts/ptmx", ptmx.display()))?; + Ok(()) + } + + fn create_default_devices(&self, mknod: bool) -> Result<()> { + let dev = Device::new(self.path.clone()); + dev.create_default_devices(mknod)?; + Ok(()) + } + + fn create_devices(&self, devices: &Vec, mknod: bool) -> Result<()> { + let dev = Device::new(self.path.clone()); + for d in devices { + if dev.is_default_device(d) { + dev.delete_device(d)?; + } + dev.create_device(d, mknod) + .with_context(|| format!("Failed to create device {}", d.path))?; + } + Ok(()) + } + + pub fn prepare_rootfs(&self, config: &RuntimeConfig) -> Result<()> { + self.set_propagation()?; + self.mount().with_context(|| "Failed to mount rootfs")?; + self.make_parent_mount_private() + .with_context(|| "Failed to make parent mount private")?; + self.do_mounts(config)?; + self.set_default_symlinks()?; + + let old_mode = umask(Mode::from_bits_truncate(0o000)); + self.create_default_devices(self.mknod_device)?; + self.create_devices(&self.devices, self.mknod_device)?; + umask(old_mode); + + self.link_ptmx()?; + Ok(()) + } + + pub fn chroot(path: &Path) -> Result<()> { + let new_root = open(path, OFlag::O_DIRECTORY | OFlag::O_RDONLY, Mode::empty()) + .with_context(|| OzonecErr::OpenFile(path.to_string_lossy().to_string()))?; + chroot(path)?; + fchdir(new_root).with_context(|| "Failed to chdir to new root directory")?; + Ok(()) + } + + pub fn pivot_root(path: &Path) -> Result<()> { + let new_root = open(path, OFlag::O_DIRECTORY | OFlag::O_RDONLY, Mode::empty()) + .with_context(|| OzonecErr::OpenFile(path.to_string_lossy().to_string()))?; + let old_root = open("/", OFlag::O_DIRECTORY | OFlag::O_RDONLY, Mode::empty()) + .with_context(|| OzonecErr::OpenFile("/".to_string()))?; + + pivot_root(path, path)?; + nix::mount::mount( + None::<&str>, + "/", + None::<&str>, + MsFlags::MS_SLAVE | MsFlags::MS_REC, + None::<&str>, + ) + .with_context(|| OzonecErr::Mount("/".to_string()))?; + + fchdir(old_root).with_context(|| "Failed to chdir to old root directory")?; + umount2(".", MntFlags::MNT_DETACH) + .with_context(|| "Failed to umount old root directory")?; + fchdir(new_root).with_context(|| "Failed to chdir to new root directory")?; + Ok(()) + } +} -- Gitee From 1406fa0587e0232bf2fa53d4584afca37d2429a1 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Fri, 23 Aug 2024 12:06:03 +0800 Subject: [PATCH 360/489] ozonec/linux: Add support for setting oom_score_adj --- ozonec/src/linux/container.rs | 8 +++++++- ozonec/src/linux/process.rs | 9 ++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index 36f819e3..7c6faad2 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -20,7 +20,7 @@ use std::{ use anyhow::{anyhow, bail, Context, Result}; use libc::{c_char, pid_t, setdomainname}; -use log::{debug, error, info}; +use log::{debug, info}; use nix::{ errno::Errno, sys::{ @@ -414,6 +414,12 @@ impl Container for LinuxContainer { None }; + // As /proc/self/oom_score_adj is not allowed to write unless privileged, + // set oom_score_adj before setting process undumpable. + process + .set_oom_score_adj() + .with_context(|| "Failed to set oom_score_adj")?; + // Make the process undumpable to avoid various race conditions that could cause // processes in namespaces to join to access host resources (or execute code). if !self.config.linux.as_ref().unwrap().namespaces.is_empty() { diff --git a/ozonec/src/linux/process.rs b/ozonec/src/linux/process.rs index d6dc61ef..5d8793a2 100644 --- a/ozonec/src/linux/process.rs +++ b/ozonec/src/linux/process.rs @@ -12,7 +12,7 @@ use std::{ ffi::CString, - fs::read_to_string, + fs::{self, read_to_string}, io::{stderr, stdin, stdout}, os::fd::{AsRawFd, RawFd}, }; @@ -52,6 +52,13 @@ impl Process { p } + pub fn set_oom_score_adj(&self) -> Result<()> { + if let Some(score) = self.oci.oomScoreAdj { + fs::write("/proc/self/oom_score_adj", score.to_string().as_bytes())?; + } + Ok(()) + } + pub fn set_additional_gids(&self) -> Result<()> { if let Some(additional_gids) = &self.oci.user.additionalGids { let setgroups = read_to_string("proc/self/setgroups") -- Gitee From 5a051fbba21123ee8402da8b9af1cf7521f9cd7e Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Fri, 23 Aug 2024 12:16:48 +0800 Subject: [PATCH 361/489] ozonec/linux: Add support for setting rlimits --- ozonec/Cargo.toml | 1 + ozonec/src/linux/container.rs | 3 +++ ozonec/src/linux/process.rs | 16 ++++++++++++++++ 3 files changed, 20 insertions(+) diff --git a/ozonec/Cargo.toml b/ozonec/Cargo.toml index 8c7eb551..7dc5860b 100644 --- a/ozonec/Cargo.toml +++ b/ozonec/Cargo.toml @@ -17,6 +17,7 @@ nix = "= 0.26.2" oci_spec = { path = "oci_spec" } prctl = "1.0.0" procfs = "0.14.0" +rlimit = "0.5.3" serde = { version = "= 1.0.163", features = ["derive"] } serde_json = "= 1.0.96" thiserror = "= 1.0.40" diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index 7c6faad2..4a8c7642 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -114,6 +114,9 @@ impl LinuxContainer { .close() .with_context(|| "Failed to close receiver end of first stage channel")?; + process + .set_rlimits() + .with_context(|| "Failed to set rlimit")?; // New pid namespace goes intto effect in cloned child processes. self.set_pid_namespace()?; diff --git a/ozonec/src/linux/process.rs b/ozonec/src/linux/process.rs index 5d8793a2..08f68112 100644 --- a/ozonec/src/linux/process.rs +++ b/ozonec/src/linux/process.rs @@ -15,6 +15,7 @@ use std::{ fs::{self, read_to_string}, io::{stderr, stdin, stdout}, os::fd::{AsRawFd, RawFd}, + str::FromStr, }; use anyhow::{anyhow, bail, Context, Result}; @@ -23,6 +24,7 @@ use libc::SIGCHLD; use nix::unistd::{self, setresgid, setresuid, Gid, Pid, Uid}; use oci_spec::process::Process as OciProcess; +use rlimit::{setrlimit, Resource, Rlim}; pub struct Process { pub stdin: Option, @@ -59,6 +61,20 @@ impl Process { Ok(()) } + pub fn set_rlimits(&self) -> Result<()> { + if let Some(rlimits) = self.oci.rlimits.as_ref() { + for rlimit in rlimits { + setrlimit( + Resource::from_str(&rlimit.rlimit_type) + .with_context(|| "rlimit type is ill-formatted")?, + Rlim::from_raw(rlimit.soft), + Rlim::from_raw(rlimit.hard), + )?; + } + } + Ok(()) + } + pub fn set_additional_gids(&self) -> Result<()> { if let Some(additional_gids) = &self.oci.user.additionalGids { let setgroups = read_to_string("proc/self/setgroups") -- Gitee From e8d64b15adf469bbef93115815f66e86fb5ce7d8 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Fri, 23 Aug 2024 14:29:21 +0800 Subject: [PATCH 362/489] ozonec/linux: Implement do_second_stage() to initialize container enviroment --- ozonec/src/linux/container.rs | 178 +++++++++++++++++++++++++++++++++- ozonec/src/linux/process.rs | 115 +++++++++++++++++++++- 2 files changed, 286 insertions(+), 7 deletions(-) diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index 4a8c7642..e1756d33 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -12,7 +12,7 @@ use std::{ collections::HashMap, - fs::{canonicalize, create_dir_all, OpenOptions}, + fs::{self, canonicalize, create_dir_all, OpenOptions}, io::Write, path::{Path, PathBuf}, time::SystemTime, @@ -23,11 +23,13 @@ use libc::{c_char, pid_t, setdomainname}; use log::{debug, info}; use nix::{ errno::Errno, + mount::MsFlags, sys::{ signal::Signal, + statfs::statfs, wait::{waitpid, WaitStatus}, }, - unistd::{chown, getegid, geteuid, sethostname, Gid, Pid, Uid}, + unistd::{self, chown, getegid, geteuid, sethostname, Gid, Pid, Uid}, }; use prctl::set_dumpable; use procfs::process::ProcState; @@ -38,10 +40,11 @@ use super::{ }; use crate::{ container::Container, + linux::rootfs::Rootfs, utils::{Channel, Message, OzonecErr}, }; use oci_spec::{ - linux::{IdMapping, NamespaceType}, + linux::{Device as OciDevice, IdMapping, NamespaceType}, runtime::RuntimeConfig, state::{ContainerStatus, State}, }; @@ -142,9 +145,67 @@ impl LinuxContainer { ) -> Result<()> { debug!("Second stage process start"); + unistd::setsid().with_context(|| "Failed to setsid")?; + process + .set_io_priority() + .with_context(|| "Failed to set io priority")?; + process + .set_scheduler() + .with_context(|| "Failed to set scheduler")?; + self.set_rest_namespaces()?; + process.set_no_new_privileges()?; + + if process.init { + let propagation = self + .config + .linux + .as_ref() + .unwrap() + .rootfsPropagation + .clone(); + let mknod_device = !self.is_namespace_set(NamespaceType::User)?; + let mut devices: Vec = Vec::new(); + if let Some(devs) = self.config.linux.as_ref().unwrap().devices.as_ref() { + devices = devs.clone() + }; + let rootfs = Rootfs::new( + self.config.root.path.clone().into(), + propagation, + self.config.mounts.clone(), + mknod_device, + devices, + )?; + rootfs.prepare_rootfs(&self.config)?; + + // Entering into rootfs jail. If mount namespace is specified, use pivot_root. + // Otherwise use chroot. + if self.is_namespace_set(NamespaceType::Mount)? { + Rootfs::pivot_root(&rootfs.path).with_context(|| "Failed to pivot_root")?; + } else { + Rootfs::chroot(&rootfs.path).with_context(|| "Failed to chroot")?; + } + + self.set_sysctl_parameters()?; + } else if !self.is_namespace_set(NamespaceType::Mount)? { + Rootfs::chroot(&PathBuf::from(self.config.root.path.clone())) + .with_context(|| "Failed to chroot")?; + } + + if self.config.root.readonly { + LinuxContainer::mount_rootfs_readonly()?; + } + self.set_readonly_paths()?; + self.set_masked_paths()?; + let chdir_cwd_ret = process.chdir_cwd().is_err(); process.set_additional_gids()?; + process.set_process_id()?; + if chdir_cwd_ret { + process.chdir_cwd()?; + } + process.clean_envs(); + process.set_envs(); // Tell the parent process that the init process has been cloned. parent_channel.send_container_created()?; @@ -163,6 +224,25 @@ impl LinuxContainer { process.exec_program(); } + fn mount_rootfs_readonly() -> Result<()> { + let ms_flags = MsFlags::MS_RDONLY | MsFlags::MS_REMOUNT | MsFlags::MS_BIND; + let root_path = Path::new("/"); + let fs_flags = statfs(root_path) + .with_context(|| "Statfs root directory error")? + .flags() + .bits(); + + nix::mount::mount( + None::<&str>, + root_path, + None::<&str>, + ms_flags | MsFlags::from_bits_truncate(fs_flags), + None::<&str>, + ) + .with_context(|| "Failed to remount rootfs readonly")?; + Ok(()) + } + fn container_status(&self) -> Result { if self.pid == -1 { return Ok(ContainerStatus::Creating); @@ -257,6 +337,86 @@ impl LinuxContainer { Ok(()) } + fn set_readonly_paths(&self) -> Result<()> { + if let Some(readonly_paths) = self.config.linux.as_ref().unwrap().readonlyPaths.clone() { + for p in readonly_paths { + let path = Path::new(&p); + if let Err(e) = nix::mount::mount( + Some(path), + path, + None::<&str>, + MsFlags::MS_BIND | MsFlags::MS_REC, + None::<&str>, + ) { + if matches!(e, Errno::ENOENT) { + return Ok(()); + } + bail!("Failed to make {} as recursive bind mount", path.display()); + } + + nix::mount::mount( + Some(path), + path, + None::<&str>, + MsFlags::MS_NOSUID + | MsFlags::MS_NODEV + | MsFlags::MS_NOEXEC + | MsFlags::MS_BIND + | MsFlags::MS_REMOUNT + | MsFlags::MS_RDONLY, + None::<&str>, + ) + .with_context(|| format!("Failed to remount {} readonly", path.display()))?; + } + } + Ok(()) + } + + fn set_masked_paths(&self) -> Result<()> { + let linux = self.config.linux.as_ref().unwrap(); + if let Some(masked_paths) = linux.maskedPaths.clone() { + for p in masked_paths { + let path = Path::new(&p); + if let Err(e) = nix::mount::mount( + Some(Path::new("/dev/null")), + path, + None::<&str>, + MsFlags::MS_BIND, + None::<&str>, + ) { + match e { + // Ignore if path doesn't exists. + Errno::ENOENT => (), + Errno::ENOTDIR => { + let label = match linux.mountLabel.clone() { + Some(l) => format!("context=\"{}\"", l), + None => "".to_string(), + }; + nix::mount::mount( + Some(Path::new("tmpfs")), + path, + Some("tmpfs"), + MsFlags::MS_RDONLY, + Some(label.as_str()), + ) + .with_context(|| { + format!( + "Failed to make {} as masked mount by tmpfs", + path.display() + ) + })?; + } + _ => bail!( + "Failed to make {} as masked mount by /dev/null", + path.display() + ), + } + } + } + } + Ok(()) + } + fn set_rest_namespaces(&self) -> Result<()> { let ns_config = &self.config.linux.as_ref().unwrap().namespaces; let ns_controller: NsController = ns_config.clone().try_into()?; @@ -362,6 +522,18 @@ impl LinuxContainer { } Ok(()) } + + fn set_sysctl_parameters(&self) -> Result<()> { + if let Some(sysctl_params) = self.config.linux.as_ref().unwrap().sysctl.clone() { + let sys_path = PathBuf::from("/proc/sys"); + for (param, value) in sysctl_params { + let path = sys_path.join(param.replace('.', "/")); + fs::write(&path, value.as_bytes()) + .with_context(|| format!("Failed to set {} to {}", path.display(), value))?; + } + } + Ok(()) + } } impl Container for LinuxContainer { diff --git a/ozonec/src/linux/process.rs b/ozonec/src/linux/process.rs index 08f68112..a8e22ca0 100644 --- a/ozonec/src/linux/process.rs +++ b/ozonec/src/linux/process.rs @@ -11,19 +11,22 @@ // See the Mulan PSL v2 for more details. use std::{ + env, ffi::CString, fs::{self, read_to_string}, io::{stderr, stdin, stdout}, + mem, os::fd::{AsRawFd, RawFd}, + path::PathBuf, str::FromStr, }; use anyhow::{anyhow, bail, Context, Result}; use clone3::Clone3; -use libc::SIGCHLD; -use nix::unistd::{self, setresgid, setresuid, Gid, Pid, Uid}; +use nix::unistd::{self, chdir, setresgid, setresuid, Gid, Pid, Uid}; -use oci_spec::process::Process as OciProcess; +use oci_spec::{linux::IoPriClass, process::Process as OciProcess}; +use prctl::set_no_new_privileges; use rlimit::{setrlimit, Resource, Rlim}; pub struct Process { @@ -75,6 +78,67 @@ impl Process { Ok(()) } + pub fn set_io_priority(&self) -> Result<()> { + if let Some(io_prio) = &self.oci.ioPriority { + let class = match io_prio.class { + IoPriClass::IoprioClassRt => 1i64, + IoPriClass::IoprioClassBe => 2i64, + IoPriClass::IoprioClassIdle => 3i64, + }; + // Who is a process id or thread id identifying a single process or + // thread. If who is 0, then operate on the calling process or thread. + let io_prio_who_process: libc::c_int = 1; + let io_prio_who_pid = 0; + // SAFETY: FFI call with valid arguments. + match unsafe { + libc::syscall( + libc::SYS_ioprio_set, + io_prio_who_process, + io_prio_who_pid, + (class << 13) | io_prio.priority, + ) + } { + 0 => Ok(()), + -1 => Err(nix::Error::last()), + _ => Err(nix::Error::UnknownErrno), + }?; + } + Ok(()) + } + + pub fn set_scheduler(&self) -> Result<()> { + if let Some(scheduler) = &self.oci.scheduler { + // SAFETY: FFI call with valid arguments. + let mut param: libc::sched_param = unsafe { mem::zeroed() }; + param.sched_priority = scheduler.priority.unwrap_or_default(); + // SAFETY: FFI call with valid arguments. + match unsafe { libc::sched_setscheduler(0, scheduler.policy.into(), ¶m) } { + 0 => Ok(()), + -1 => Err(nix::Error::last()), + _ => Err(nix::Error::UnknownErrno), + }?; + } + Ok(()) + } + + pub fn set_no_new_privileges(&self) -> Result<()> { + if let Some(no_new_privileges) = self.oci.noNewPrivileges { + if no_new_privileges { + set_no_new_privileges(true) + .map_err(|e| anyhow!("Failed to set no new privileges: {}", e))?; + } + } + Ok(()) + } + + pub fn chdir_cwd(&self) -> Result<()> { + if !self.oci.cwd.is_empty() { + chdir(&PathBuf::from(&self.oci.cwd)) + .with_context(|| format!("Failed to chdir to {}", &self.oci.cwd))?; + } + Ok(()) + } + pub fn set_additional_gids(&self) -> Result<()> { if let Some(additional_gids) = &self.oci.user.additionalGids { let setgroups = read_to_string("proc/self/setgroups") @@ -92,12 +156,55 @@ impl Process { Ok(()) } + pub fn set_process_id(&self) -> Result<()> { + let gid = Gid::from(self.oci.user.gid); + let uid = Uid::from(self.oci.user.uid); + self.set_id(gid, uid)?; + Ok(()) + } + pub fn set_id(&self, gid: Gid, uid: Uid) -> Result<()> { setresgid(gid, gid, gid).with_context(|| "Failed to setresgid")?; setresuid(uid, uid, uid).with_context(|| "Failed to setresuid")?; Ok(()) } + // Check and reserve valid environment variables. + // Invalid env vars may cause panic, refer to https://doc.rust-lang.org/std/env/fn.set_var.html#panics + // Key should not : + // * contain NULL character '\0' + // * contain ASCII character '=' + // * be empty + // Value should not: + // * contain NULL character '\0' + fn is_env_valid(env: &str) -> Option<(&str, &str)> { + // Split the env var by '=' to ensure there is no '=' in key, and there is only one '=' + // in the whole env var. + if let Some((key, value)) = env.split_once('=') { + if !key.is_empty() + && !key.as_bytes().contains(&b'\0') + && !value.as_bytes().contains(&b'\0') + { + return Some((key.trim(), value.trim())); + } + } + None + } + + pub fn set_envs(&self) { + if let Some(envs) = &self.oci.env { + for env in envs { + if let Some((key, value)) = Self::is_env_valid(env) { + env::set_var(key, value); + } + } + } + } + + pub fn clean_envs(&self) { + env::vars().for_each(|(key, value)| env::remove_var(key)); + } + pub fn exec_program(&self) -> ! { // It has been make sure that args is not None in validate_config(). let args = &self.oci.args.as_ref().unwrap(); @@ -120,7 +227,7 @@ impl Process { // Clone a new child process. pub fn clone_process Result>(child_name: &str, cb: F) -> Result { let mut clone3 = Clone3::default(); - clone3.exit_signal(SIGCHLD as u64); + clone3.exit_signal(libc::SIGCHLD as u64); // SAFETY: FFI call with valid arguments. match unsafe { clone3.call().with_context(|| "Clone3() error")? } { -- Gitee From cd38675acbdb0dbcda0e07f86975206c3a27a393 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Fri, 23 Aug 2024 15:27:34 +0800 Subject: [PATCH 363/489] ozonec/linux: Add tty support --- ozonec/src/linux/container.rs | 9 +++++ ozonec/src/linux/mod.rs | 1 + ozonec/src/linux/process.rs | 17 +++++++++ ozonec/src/linux/terminal.rs | 69 +++++++++++++++++++++++++++++++++++ ozonec/src/utils/error.rs | 2 + 5 files changed, 98 insertions(+) create mode 100644 ozonec/src/linux/terminal.rs diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index e1756d33..2d50e017 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -14,6 +14,7 @@ use std::{ collections::HashMap, fs::{self, canonicalize, create_dir_all, OpenOptions}, io::Write, + os::{fd::AsRawFd, unix::net::UnixStream}, path::{Path, PathBuf}, time::SystemTime, }; @@ -153,6 +154,14 @@ impl LinuxContainer { .set_scheduler() .with_context(|| "Failed to set scheduler")?; + if let Some(console_socket) = &self.console_socket { + let stream = UnixStream::connect(console_socket) + .with_context(|| "Failed to connect console socket")?; + process + .set_tty(Some(stream.as_raw_fd())) + .with_context(|| "Failed to set tty")?; + } + self.set_rest_namespaces()?; process.set_no_new_privileges()?; diff --git a/ozonec/src/linux/mod.rs b/ozonec/src/linux/mod.rs index 84fff70c..b5dfc178 100644 --- a/ozonec/src/linux/mod.rs +++ b/ozonec/src/linux/mod.rs @@ -17,6 +17,7 @@ mod namespace; mod notify_socket; mod process; mod rootfs; +mod terminal; pub use container::LinuxContainer; pub use notify_socket::NotifyListener; diff --git a/ozonec/src/linux/process.rs b/ozonec/src/linux/process.rs index a8e22ca0..a15a137f 100644 --- a/ozonec/src/linux/process.rs +++ b/ozonec/src/linux/process.rs @@ -29,6 +29,8 @@ use oci_spec::{linux::IoPriClass, process::Process as OciProcess}; use prctl::set_no_new_privileges; use rlimit::{setrlimit, Resource, Rlim}; +use super::terminal::{connect_stdio, setup_console}; + pub struct Process { pub stdin: Option, pub stdout: Option, @@ -57,6 +59,21 @@ impl Process { p } + pub fn set_tty(&self, console_fd: Option) -> Result<()> { + if self.tty && console_fd.is_some() { + setup_console(&console_fd.unwrap()).with_context(|| "Failed to setup console")?; + } else { + connect_stdio( + self.stdin.as_ref().unwrap(), + self.stdout.as_ref().unwrap(), + self.stderr.as_ref().unwrap(), + )?; + // SAFETY: FFI call with valid arguments. + unsafe { libc::ioctl(0, libc::TIOCSCTTY) }; + } + Ok(()) + } + pub fn set_oom_score_adj(&self) -> Result<()> { if let Some(score) = self.oci.oomScoreAdj { fs::write("/proc/self/oom_score_adj", score.to_string().as_bytes())?; diff --git a/ozonec/src/linux/terminal.rs b/ozonec/src/linux/terminal.rs new file mode 100644 index 00000000..e7490d2b --- /dev/null +++ b/ozonec/src/linux/terminal.rs @@ -0,0 +1,69 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::{ + io::IoSlice, + mem::ManuallyDrop, + os::fd::{AsRawFd, RawFd}, +}; + +use anyhow::{Context, Result}; +use nix::{ + pty::openpty, + sys::socket::{sendmsg, ControlMessage, MsgFlags, UnixAddr}, + unistd::{close, dup2}, +}; + +use crate::utils::OzonecErr; + +pub enum Stdio { + Stdin = 0, + Stdout = 1, + Stderr = 2, +} + +pub fn setup_console(console_fd: &RawFd) -> Result<()> { + let ret = openpty(None, None).with_context(|| "openpty error")?; + let pty_name: &[u8] = b"/dev/ptmx"; + let iov = [IoSlice::new(pty_name)]; + + // Use ManuallyDrop to keep fds open. + let master = ManuallyDrop::new(ret.master); + let slave = ManuallyDrop::new(ret.slave); + let fds = [master.as_raw_fd()]; + let cmsg = ControlMessage::ScmRights(&fds); + sendmsg::( + console_fd.as_raw_fd(), + &iov, + &[cmsg], + MsgFlags::empty(), + None, + ) + .with_context(|| "sendmsg error")?; + + // SAFETY: FFI call with valid arguments. + let slave_fd = slave.as_raw_fd(); + unsafe { libc::ioctl(slave_fd, libc::TIOCSCTTY) }; + connect_stdio(&slave_fd, &slave_fd, &slave_fd)?; + close(console_fd.as_raw_fd()).with_context(|| "Failed to close console socket")?; + Ok(()) +} + +pub fn connect_stdio(stdin: &RawFd, stdout: &RawFd, stderr: &RawFd) -> Result<()> { + dup2(*stdin, (Stdio::Stdin as i32).as_raw_fd()) + .with_context(|| OzonecErr::Dup2("stdin".to_string()))?; + dup2(*stdout, (Stdio::Stdout as i32).as_raw_fd()) + .with_context(|| OzonecErr::Dup2("stdout".to_string()))?; + dup2(*stderr, (Stdio::Stderr as i32).as_raw_fd()) + .with_context(|| OzonecErr::Dup2("stderr".to_string()))?; + Ok(()) +} diff --git a/ozonec/src/utils/error.rs b/ozonec/src/utils/error.rs index 9c00bd13..8f5f052d 100644 --- a/ozonec/src/utils/error.rs +++ b/ozonec/src/utils/error.rs @@ -28,4 +28,6 @@ pub enum OzonecErr { AccessProcSelf, #[error("Failed to get mountinfo")] GetMntInfo, + #[error("Dup2 {0} error")] + Dup2(String), } -- Gitee From 2d7b7def80151415dcc535dadd6186b92fd3ff0e Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Sat, 24 Aug 2024 12:16:25 +0800 Subject: [PATCH 364/489] ozonec/linux: Add capabilities support --- ozonec/Cargo.toml | 1 + ozonec/src/linux/container.rs | 6 ++ ozonec/src/linux/process.rs | 117 ++++++++++++++++++++++++++++++++-- ozonec/src/utils/error.rs | 4 ++ 4 files changed, 124 insertions(+), 4 deletions(-) diff --git a/ozonec/Cargo.toml b/ozonec/Cargo.toml index 7dc5860b..290b13fe 100644 --- a/ozonec/Cargo.toml +++ b/ozonec/Cargo.toml @@ -8,6 +8,7 @@ description = "An OCI runtime implemented by Rust" [dependencies] anyhow = "= 1.0.71" +caps = "0.5.5" chrono = { version = "0.4.31", default-features = false, features = ["clock", "serde"] } clap = { version = "= 4.1.4", default-features = false, features = ["derive", "cargo", "std", "help", "usage"] } clone3 = "0.2.3" diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index 2d50e017..9242b2ba 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -210,6 +210,12 @@ impl LinuxContainer { let chdir_cwd_ret = process.chdir_cwd().is_err(); process.set_additional_gids()?; process.set_process_id()?; + process + .reset_capabilities() + .with_context(|| "Failed to reset capabilities")?; + process + .drop_capabilities() + .with_context(|| "Failed to drop capabilities")?; if chdir_cwd_ret { process.chdir_cwd()?; } diff --git a/ozonec/src/linux/process.rs b/ozonec/src/linux/process.rs index a15a137f..46bb990e 100644 --- a/ozonec/src/linux/process.rs +++ b/ozonec/src/linux/process.rs @@ -22,14 +22,15 @@ use std::{ }; use anyhow::{anyhow, bail, Context, Result}; +use caps::{self, CapSet, Capability, CapsHashSet}; use clone3::Clone3; use nix::unistd::{self, chdir, setresgid, setresuid, Gid, Pid, Uid}; - -use oci_spec::{linux::IoPriClass, process::Process as OciProcess}; -use prctl::set_no_new_privileges; +use prctl::{set_keep_capabilities, set_no_new_privileges}; use rlimit::{setrlimit, Resource, Rlim}; use super::terminal::{connect_stdio, setup_console}; +use crate::utils::OzonecErr; +use oci_spec::{linux::IoPriClass, process::Process as OciProcess}; pub struct Process { pub stdin: Option, @@ -156,6 +157,45 @@ impl Process { Ok(()) } + pub fn drop_capabilities(&self) -> Result<()> { + if let Some(caps) = self.oci.capabilities.as_ref() { + if let Some(bounding) = caps.bounding.as_ref() { + let all_caps = caps::read(None, CapSet::Bounding) + .with_context(|| OzonecErr::GetAllCaps("Bounding".to_string()))?; + let caps_hash_set = to_cap_set(bounding)?; + for cap in all_caps.difference(&caps_hash_set) { + caps::drop(None, CapSet::Bounding, *cap).with_context(|| { + format!("Failed to drop {} from bonding set", cap.to_string()) + })?; + } + } + if let Some(effective) = caps.effective.as_ref() { + caps::set(None, CapSet::Effective, &to_cap_set(effective)?) + .with_context(|| OzonecErr::SetCaps("Effective".to_string()))?; + } + if let Some(permitted) = caps.permitted.as_ref() { + caps::set(None, CapSet::Permitted, &to_cap_set(permitted)?) + .with_context(|| OzonecErr::SetCaps("Permitted".to_string()))?; + } + if let Some(inheritable) = caps.inheritable.as_ref() { + caps::set(None, CapSet::Inheritable, &to_cap_set(inheritable)?) + .with_context(|| OzonecErr::SetCaps("Inheritable".to_string()))?; + } + if let Some(ambient) = caps.ambient.as_ref() { + caps::set(None, CapSet::Ambient, &to_cap_set(ambient)?) + .with_context(|| OzonecErr::SetCaps("Ambient".to_string()))?; + } + } + Ok(()) + } + + pub fn reset_capabilities(&self) -> Result<()> { + let permitted = caps::read(None, CapSet::Permitted) + .with_context(|| OzonecErr::GetAllCaps("Permitted".to_string()))?; + caps::set(None, CapSet::Effective, &permitted)?; + Ok(()) + } + pub fn set_additional_gids(&self) -> Result<()> { if let Some(additional_gids) = &self.oci.user.additionalGids { let setgroups = read_to_string("proc/self/setgroups") @@ -181,8 +221,17 @@ impl Process { } pub fn set_id(&self, gid: Gid, uid: Uid) -> Result<()> { + set_keep_capabilities(true) + .map_err(|e| anyhow!("Failed to enable keeping capabilities: {}", e))?; setresgid(gid, gid, gid).with_context(|| "Failed to setresgid")?; setresuid(uid, uid, uid).with_context(|| "Failed to setresuid")?; + + let permitted = caps::read(None, CapSet::Permitted) + .with_context(|| OzonecErr::GetAllCaps("Permitted".to_string()))?; + caps::set(None, CapSet::Effective, &permitted) + .with_context(|| OzonecErr::SetCaps("Effective".to_string()))?; + set_keep_capabilities(false) + .map_err(|e| anyhow!("Failed to disable keeping capabilities: {}", e))?; Ok(()) } @@ -219,7 +268,7 @@ impl Process { } pub fn clean_envs(&self) { - env::vars().for_each(|(key, value)| env::remove_var(key)); + env::vars().for_each(|(key, _value)| env::remove_var(key)); } pub fn exec_program(&self) -> ! { @@ -263,3 +312,63 @@ pub fn clone_process Result>(child_name: &str, cb: F) -> Res pid => Ok(Pid::from_raw(pid)), } } + +fn to_cap_set(caps: &Vec) -> Result { + let mut caps_hash_set = CapsHashSet::new(); + + for c in caps { + let cap = to_cap(&c)?; + caps_hash_set.insert(cap); + } + Ok(caps_hash_set) +} + +fn to_cap(value: &str) -> Result { + let binding = value.to_uppercase(); + let stripped = binding.strip_prefix("CAP_").unwrap_or(&binding); + + match stripped { + "AUDIT_CONTROL" => Ok(Capability::CAP_AUDIT_CONTROL), + "AUDIT_READ" => Ok(Capability::CAP_AUDIT_READ), + "AUDIT_WRITE" => Ok(Capability::CAP_AUDIT_WRITE), + "BLOCK_SUSPEND" => Ok(Capability::CAP_BLOCK_SUSPEND), + "BPF" => Ok(Capability::CAP_BPF), + "CHECKPOINT_RESTORE" => Ok(Capability::CAP_CHECKPOINT_RESTORE), + "CHOWN" => Ok(Capability::CAP_CHOWN), + "DAC_OVERRIDE" => Ok(Capability::CAP_DAC_OVERRIDE), + "DAC_READ_SEARCH" => Ok(Capability::CAP_DAC_READ_SEARCH), + "FOWNER" => Ok(Capability::CAP_FOWNER), + "FSETID" => Ok(Capability::CAP_FSETID), + "IPC_LOCK" => Ok(Capability::CAP_IPC_LOCK), + "IPC_OWNER" => Ok(Capability::CAP_IPC_OWNER), + "KILL" => Ok(Capability::CAP_KILL), + "LEASE" => Ok(Capability::CAP_LEASE), + "LINUX_IMMUTABLE" => Ok(Capability::CAP_LINUX_IMMUTABLE), + "MAC_ADMIN" => Ok(Capability::CAP_MAC_ADMIN), + "MAC_OVERRIDE" => Ok(Capability::CAP_MAC_OVERRIDE), + "MKNOD" => Ok(Capability::CAP_MKNOD), + "NET_ADMIN" => Ok(Capability::CAP_NET_ADMIN), + "NET_BIND_SERVICE" => Ok(Capability::CAP_NET_BIND_SERVICE), + "NET_BROADCAST" => Ok(Capability::CAP_NET_BROADCAST), + "NET_RAW" => Ok(Capability::CAP_NET_RAW), + "PERFMON" => Ok(Capability::CAP_PERFMON), + "SETGID" => Ok(Capability::CAP_SETGID), + "SETFCAP" => Ok(Capability::CAP_SETFCAP), + "SETPCAP" => Ok(Capability::CAP_SETPCAP), + "SETUID" => Ok(Capability::CAP_SETUID), + "SYS_ADMIN" => Ok(Capability::CAP_SYS_ADMIN), + "SYS_BOOT" => Ok(Capability::CAP_SYS_BOOT), + "SYS_CHROOT" => Ok(Capability::CAP_SYS_CHROOT), + "SYS_MODULE" => Ok(Capability::CAP_SYS_MODULE), + "SYS_NICE" => Ok(Capability::CAP_SYS_NICE), + "SYS_PACCT" => Ok(Capability::CAP_SYS_PACCT), + "SYS_PTRACE" => Ok(Capability::CAP_SYS_PTRACE), + "SYS_RAWIO" => Ok(Capability::CAP_SYS_RAWIO), + "SYS_RESOURCE" => Ok(Capability::CAP_SYS_RESOURCE), + "SYS_TIME" => Ok(Capability::CAP_SYS_TIME), + "SYS_TTY_CONFIG" => Ok(Capability::CAP_SYS_TTY_CONFIG), + "SYSLOG" => Ok(Capability::CAP_SYSLOG), + "WAKE_ALARM" => Ok(Capability::CAP_WAKE_ALARM), + _ => bail!("Invalid capability: {}", value), + } +} diff --git a/ozonec/src/utils/error.rs b/ozonec/src/utils/error.rs index 8f5f052d..a078a961 100644 --- a/ozonec/src/utils/error.rs +++ b/ozonec/src/utils/error.rs @@ -30,4 +30,8 @@ pub enum OzonecErr { GetMntInfo, #[error("Dup2 {0} error")] Dup2(String), + #[error("Failed to get all capabilities of {0} set")] + GetAllCaps(String), + #[error("Failed to set the capability set {0}")] + SetCaps(String), } -- Gitee From 43c30ef1a645f4c7e7acf161b2fab7f224db5719 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Mon, 26 Aug 2024 07:20:40 +0800 Subject: [PATCH 365/489] ozonec/linux: Add seccomp support --- ozonec/Cargo.toml | 1 + ozonec/src/linux/container.rs | 14 +++- ozonec/src/linux/mod.rs | 1 + ozonec/src/linux/process.rs | 4 ++ ozonec/src/linux/seccomp.rs | 116 ++++++++++++++++++++++++++++++++++ ozonec/src/utils/error.rs | 2 + 6 files changed, 137 insertions(+), 1 deletion(-) create mode 100644 ozonec/src/linux/seccomp.rs diff --git a/ozonec/Cargo.toml b/ozonec/Cargo.toml index 290b13fe..c3e52cf5 100644 --- a/ozonec/Cargo.toml +++ b/ozonec/Cargo.toml @@ -13,6 +13,7 @@ chrono = { version = "0.4.31", default-features = false, features = ["clock", "s clap = { version = "= 4.1.4", default-features = false, features = ["derive", "cargo", "std", "help", "usage"] } clone3 = "0.2.3" libc = "= 0.2.146" +libseccomp = "0.3.0" log = { version = "= 0.4.18", features = ["std"]} nix = "= 0.26.2" oci_spec = { path = "oci_spec" } diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index 9242b2ba..5b0de9b0 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -41,7 +41,7 @@ use super::{ }; use crate::{ container::Container, - linux::rootfs::Rootfs, + linux::{rootfs::Rootfs, seccomp::set_seccomp}, utils::{Channel, Message, OzonecErr}, }; use oci_spec::{ @@ -210,6 +210,13 @@ impl LinuxContainer { let chdir_cwd_ret = process.chdir_cwd().is_err(); process.set_additional_gids()?; process.set_process_id()?; + + // Without setting no new privileges, setting seccomp is a privileged operation. + if !process.no_new_privileges() { + if let Some(seccomp) = &self.config.linux.as_ref().unwrap().seccomp { + set_seccomp(seccomp).with_context(|| "Failed to set seccomp")?; + } + } process .reset_capabilities() .with_context(|| "Failed to reset capabilities")?; @@ -221,6 +228,11 @@ impl LinuxContainer { } process.clean_envs(); process.set_envs(); + if process.no_new_privileges() { + if let Some(seccomp) = &self.config.linux.as_ref().unwrap().seccomp { + set_seccomp(seccomp).with_context(|| "Failed to set seccomp")?; + } + } // Tell the parent process that the init process has been cloned. parent_channel.send_container_created()?; diff --git a/ozonec/src/linux/mod.rs b/ozonec/src/linux/mod.rs index b5dfc178..4e09c1eb 100644 --- a/ozonec/src/linux/mod.rs +++ b/ozonec/src/linux/mod.rs @@ -17,6 +17,7 @@ mod namespace; mod notify_socket; mod process; mod rootfs; +mod seccomp; mod terminal; pub use container::LinuxContainer; diff --git a/ozonec/src/linux/process.rs b/ozonec/src/linux/process.rs index 46bb990e..0a590c67 100644 --- a/ozonec/src/linux/process.rs +++ b/ozonec/src/linux/process.rs @@ -139,6 +139,10 @@ impl Process { Ok(()) } + pub fn no_new_privileges(&self) -> bool { + self.oci.noNewPrivileges.is_some() + } + pub fn set_no_new_privileges(&self) -> Result<()> { if let Some(no_new_privileges) = self.oci.noNewPrivileges { if no_new_privileges { diff --git a/ozonec/src/linux/seccomp.rs b/ozonec/src/linux/seccomp.rs new file mode 100644 index 00000000..e9586610 --- /dev/null +++ b/ozonec/src/linux/seccomp.rs @@ -0,0 +1,116 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::vec; + +use anyhow::{bail, Context, Result}; + +use libseccomp::{ + ScmpAction, ScmpArch, ScmpArgCompare, ScmpCompareOp, ScmpFilterContext, ScmpSyscall, +}; +use oci_spec::linux::{Seccomp, SeccompAction as OciSeccompAction, SeccompOp}; + +use crate::utils::OzonecErr; + +fn parse_action(action: OciSeccompAction, errno: Option) -> ScmpAction { + let errno = errno.unwrap_or(libc::EPERM as u32); + match action { + OciSeccompAction::ScmpActKill => ScmpAction::KillThread, + OciSeccompAction::ScmpActKillProcess => ScmpAction::KillProcess, + OciSeccompAction::ScmpActTrap => ScmpAction::Trap, + OciSeccompAction::ScmpActErrno => ScmpAction::Errno(errno as i32), + OciSeccompAction::ScmpActTrace => ScmpAction::Trace(errno as u16), + OciSeccompAction::ScmpActLog => ScmpAction::Log, + OciSeccompAction::ScmpActAllow => ScmpAction::Allow, + _ => ScmpAction::KillThread, + } +} + +fn parse_cmp(op: SeccompOp) -> ScmpCompareOp { + match op { + SeccompOp::ScmpCmpNe => ScmpCompareOp::NotEqual, + SeccompOp::ScmpCmpLt => ScmpCompareOp::Less, + SeccompOp::ScmpCmpLe => ScmpCompareOp::LessOrEqual, + SeccompOp::ScmpCmpEq => ScmpCompareOp::Equal, + SeccompOp::ScmpCmpGe => ScmpCompareOp::GreaterEqual, + SeccompOp::ScmpCmpGt => ScmpCompareOp::Greater, + _ => ScmpCompareOp::Equal, + } +} + +fn check_seccomp(seccomp: &Seccomp) -> Result<()> { + // We don't support NOTIFY as the default action. When the seccomp filter + // is created with NOTIFY, the container process will have to communicate + // the returned fd to another process. Therefore, ozonec needs to call + // the WRITE syscall. And then READ and CLOSE syscalls are also needed to + // be enabled to use. + if seccomp.defaultAction == OciSeccompAction::ScmpActNotify { + bail!("SCMP_ACT_NOTIFY is not supported as the default action"); + } + if let Some(syscalls) = &seccomp.syscalls { + for syscall in syscalls { + if syscall.action == OciSeccompAction::ScmpActNotify { + for name in &syscall.names { + if name == "write" { + bail!("SCMP_ACT_NOTIFY is not supported to be used for write syscall"); + } + } + } + } + } + + Ok(()) +} + +pub fn set_seccomp(seccomp: &Seccomp) -> Result<()> { + check_seccomp(seccomp)?; + + let default_action = parse_action(seccomp.defaultAction, seccomp.defaultErrnoRet); + if let Some(syscalls) = &seccomp.syscalls { + let mut filter = ScmpFilterContext::new_filter(default_action)?; + #[cfg(target_arch = "x86_64")] + filter + .add_arch(ScmpArch::X8664) + .with_context(|| OzonecErr::AddScmpArch)?; + #[cfg(target_arch = "aarch64")] + filter + .add_arch(ScmpArch::Aarch64) + .with_context(|| OzonecErr::AddScmpArch)?; + + for syscall in syscalls { + let action = parse_action(syscall.action, syscall.errnoRet); + if action == default_action { + continue; + } + + for name in &syscall.names { + let sc = ScmpSyscall::from_name(name)?; + let mut comparators: Vec = vec![]; + if let Some(args) = &syscall.args { + for arg in args { + let op = parse_cmp(arg.op); + let cmp = ScmpArgCompare::new(arg.index as u32, op, arg.value); + comparators.push(cmp); + } + } + filter + .add_rule_conditional(action, sc, &comparators) + .with_context(|| "Failed to add conditional rule")?; + } + } + filter + .load() + .with_context(|| "Failed to load filter into the kernel")?; + } + + Ok(()) +} diff --git a/ozonec/src/utils/error.rs b/ozonec/src/utils/error.rs index a078a961..0631f47b 100644 --- a/ozonec/src/utils/error.rs +++ b/ozonec/src/utils/error.rs @@ -34,4 +34,6 @@ pub enum OzonecErr { GetAllCaps(String), #[error("Failed to set the capability set {0}")] SetCaps(String), + #[error("Failed to add architecture to seccomp filter")] + AddScmpArch, } -- Gitee From 13c43afc7f41ee641f2834d71329178adbdc33f6 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Mon, 26 Aug 2024 09:07:08 +0800 Subject: [PATCH 366/489] ozonec/commands: Add support for starting container --- ozonec/src/commands/mod.rs | 2 ++ ozonec/src/commands/start.rs | 58 +++++++++++++++++++++++++++++++ ozonec/src/container/mod.rs | 1 + ozonec/src/container/state.rs | 24 +++++++++---- ozonec/src/linux/container.rs | 43 +++++++++++++++++++---- ozonec/src/linux/notify_socket.rs | 42 ++++++++++++++++++---- ozonec/src/main.rs | 6 ++++ ozonec/src/utils/error.rs | 2 ++ 8 files changed, 159 insertions(+), 19 deletions(-) create mode 100644 ozonec/src/commands/start.rs diff --git a/ozonec/src/commands/mod.rs b/ozonec/src/commands/mod.rs index 2472ae99..0ed00ef1 100644 --- a/ozonec/src/commands/mod.rs +++ b/ozonec/src/commands/mod.rs @@ -11,5 +11,7 @@ // See the Mulan PSL v2 for more details. mod create; +mod start; pub use create::Create; +pub use start::Start; diff --git a/ozonec/src/commands/start.rs b/ozonec/src/commands/start.rs new file mode 100644 index 00000000..782701e4 --- /dev/null +++ b/ozonec/src/commands/start.rs @@ -0,0 +1,58 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::path::Path; + +use anyhow::{bail, Context, Result}; +use clap::Parser; +use oci_spec::state::ContainerStatus; + +use crate::{ + container::{Action, Container, Launcher, State}, + linux::LinuxContainer, +}; + +/// Start the user-specified code from process +#[derive(Parser, Debug)] +pub struct Start { + pub container_id: String, +} + +impl Start { + fn launcher(&self, root: &Path) -> Result { + let container_state = State::load(root, &self.container_id) + .with_context(|| "Failed to load container state")?; + let container = LinuxContainer::load_from_state(&container_state, &None)?; + let oci_status = container + .get_oci_state() + .with_context(|| "Failed to get oci state")? + .status; + + if oci_status != ContainerStatus::Created { + bail!("Can't start a container with {:?} status", oci_status); + } + + Ok(Launcher::new( + &container_state.bundle, + root, + false, + Box::new(container), + None, + )) + } + + pub fn run(&self, root: &Path) -> Result<()> { + let mut launcher = self.launcher(root)?; + launcher.launch(Action::Start)?; + Ok(()) + } +} diff --git a/ozonec/src/container/mod.rs b/ozonec/src/container/mod.rs index bc6905a6..ca576a38 100644 --- a/ozonec/src/container/mod.rs +++ b/ozonec/src/container/mod.rs @@ -14,6 +14,7 @@ mod launcher; mod state; pub use launcher::{Action, Launcher}; +pub use state::State; use std::time::SystemTime; diff --git a/ozonec/src/container/state.rs b/ozonec/src/container/state.rs index ab97cc36..41ec2ec9 100644 --- a/ozonec/src/container/state.rs +++ b/ozonec/src/container/state.rs @@ -11,13 +11,13 @@ // See the Mulan PSL v2 for more details. use std::{ - fs::{DirBuilder, OpenOptions}, + fs::{DirBuilder, File, OpenOptions}, os::unix::fs::DirBuilderExt, path::{Path, PathBuf}, time::SystemTime, }; -use anyhow::{Context, Result}; +use anyhow::{bail, Context, Result}; use chrono::{DateTime, Utc}; use libc::pid_t; use nix::sys::stat::Mode; @@ -63,10 +63,6 @@ impl State { } } - fn file_path(root: &Path, id: &str) -> PathBuf { - root.join(id).join("state.json") - } - pub fn save(&self) -> Result<()> { if !&self.root.exists() { DirBuilder::new() @@ -98,4 +94,20 @@ impl State { } } } + + pub fn load(root: &Path, id: &str) -> Result { + let path = Self::file_path(root, id); + if !path.exists() { + bail!("Container {} doesn't exist", id); + } + + let state_file = File::open(&path) + .with_context(|| OzonecErr::OpenFile(path.to_string_lossy().to_string()))?; + let state = serde_json::from_reader(&state_file)?; + Ok(state) + } + + fn file_path(root: &Path, id: &str) -> PathBuf { + root.join(id).join("state.json") + } } diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index 5b0de9b0..5e4166e3 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -30,24 +30,26 @@ use nix::{ statfs::statfs, wait::{waitpid, WaitStatus}, }, - unistd::{self, chown, getegid, geteuid, sethostname, Gid, Pid, Uid}, + unistd::{self, chown, getegid, geteuid, sethostname, unlink, Gid, Pid, Uid}, }; use prctl::set_dumpable; use procfs::process::ProcState; use super::{ - namespace::NsController, notify_socket::NOTIFY_SOCKET, process::clone_process, NotifyListener, - Process, + namespace::NsController, + notify_socket::{NotifySocket, NOTIFY_SOCKET}, + process::clone_process, + NotifyListener, Process, }; use crate::{ - container::Container, + container::{Container, State}, linux::{rootfs::Rootfs, seccomp::set_seccomp}, utils::{Channel, Message, OzonecErr}, }; use oci_spec::{ linux::{Device as OciDevice, IdMapping, NamespaceType}, runtime::RuntimeConfig, - state::{ContainerStatus, State}, + state::{ContainerStatus, State as OciState}, }; pub struct LinuxContainer { @@ -92,6 +94,24 @@ impl LinuxContainer { }) } + pub fn load_from_state(state: &State, console_socket: &Option) -> Result { + let root_path = format!("{}/{}", state.root.to_string_lossy().to_string(), &state.id); + let config = state + .config + .clone() + .ok_or(anyhow!("Can't find config in state"))?; + + Ok(Self { + id: state.id.clone(), + root: root_path, + config, + pid: state.pid, + start_time: state.start_time, + created_time: state.created_time.into(), + console_socket: console_socket.clone(), + }) + } + fn validate_config(config: &RuntimeConfig) -> Result<()> { if config.linux.is_none() { bail!("There is no linux specific configuration in config.json for Linux container"); @@ -576,7 +596,7 @@ impl Container for LinuxContainer { &self.created_time } - fn get_oci_state(&self) -> Result { + fn get_oci_state(&self) -> Result { let status = self.container_status()?; let pid = if status != ContainerStatus::Stopped { self.pid @@ -598,7 +618,7 @@ impl Container for LinuxContainer { } else { HashMap::new() }; - Ok(State { + Ok(OciState { ociVersion: self.config.ociVersion.clone(), id: self.id.clone(), status, @@ -689,6 +709,15 @@ impl Container for LinuxContainer { } fn start(&mut self) -> Result<()> { + let path = PathBuf::from(&self.root).join(NOTIFY_SOCKET); + let mut notify_socket = NotifySocket::new(&path); + + notify_socket.notify_container_start()?; + unlink(&path).with_context(|| "Failed to delete notify.sock")?; + self.start_time = SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .with_context(|| "Failed to get start time")? + .as_secs(); Ok(()) } diff --git a/ozonec/src/linux/notify_socket.rs b/ozonec/src/linux/notify_socket.rs index 65ab4c9f..a2ccc695 100644 --- a/ozonec/src/linux/notify_socket.rs +++ b/ozonec/src/linux/notify_socket.rs @@ -12,14 +12,19 @@ use std::{ env, - io::Read, - os::{fd::AsRawFd, unix::net::UnixListener}, - path::{Path, PathBuf}, + io::{Read, Write}, + os::{ + fd::AsRawFd, + unix::net::{UnixListener, UnixStream}, + }, + path::PathBuf, }; -use anyhow::{bail, Context, Result}; +use anyhow::{anyhow, bail, Context, Result}; use nix::unistd::{self, chdir}; +use crate::utils::OzonecErr; + pub const NOTIFY_SOCKET: &str = "notify.sock"; pub struct NotifyListener { @@ -30,8 +35,7 @@ impl NotifyListener { pub fn new(root: PathBuf) -> Result { // The length of path of Unix domain socket has the limit 108, which is smaller then // the maximum length of file on Linux (255). - let cwd = - env::current_dir().with_context(|| "Current working directory value is invalid")?; + let cwd = env::current_dir().with_context(|| OzonecErr::GetCurDir)?; chdir(&root).with_context(|| "Failed to chdir to root directory")?; let listener = UnixListener::bind(NOTIFY_SOCKET).with_context(|| "Failed to bind notify socket")?; @@ -58,3 +62,29 @@ impl NotifyListener { Ok(unistd::close(self.socket.as_raw_fd())?) } } + +pub struct NotifySocket { + path: PathBuf, +} + +impl NotifySocket { + pub fn new(path: &PathBuf) -> Self { + Self { path: path.into() } + } + + pub fn notify_container_start(&mut self) -> Result<()> { + let cwd = env::current_dir().with_context(|| OzonecErr::GetCurDir)?; + let root_path = self + .path + .parent() + .ok_or(anyhow!("Invalid notify socket path"))?; + chdir(root_path).with_context(|| "Failed to chdir to root directory")?; + + let mut stream = + UnixStream::connect(NOTIFY_SOCKET).with_context(|| "Failed to connect notify.sock")?; + stream.write_all(b"start container")?; + chdir(&cwd).with_context(|| "Failed to chdir to previous working directory")?; + + Ok(()) + } +} diff --git a/ozonec/src/main.rs b/ozonec/src/main.rs index dd88161a..1d6dc9b7 100644 --- a/ozonec/src/main.rs +++ b/ozonec/src/main.rs @@ -23,6 +23,7 @@ use std::{ use anyhow::{Context, Result}; use clap::{crate_description, Args, Parser, Subcommand}; +use commands::Start; use log::info; use nix::unistd::geteuid; @@ -49,6 +50,7 @@ struct GlobalOpts { #[derive(Subcommand, Debug)] enum StandardCmd { Create(Create), + Start(Start), } // Extended commands not documented in [OCI Command Line Interface]. @@ -86,6 +88,10 @@ fn cmd_run(command: Command, root: &Path) -> Result<()> { } })? } + StandardCmd::Start(start) => { + info!("Exec command: {:?}", start); + start.run(root)? + } }, Command::Extend(cmd) => (), } diff --git a/ozonec/src/utils/error.rs b/ozonec/src/utils/error.rs index 0631f47b..db1e2430 100644 --- a/ozonec/src/utils/error.rs +++ b/ozonec/src/utils/error.rs @@ -36,4 +36,6 @@ pub enum OzonecErr { SetCaps(String), #[error("Failed to add architecture to seccomp filter")] AddScmpArch, + #[error("Failed to get current directory")] + GetCurDir, } -- Gitee From 0bfe04a969066376ee7ad11977e04bcc4687dde1 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Mon, 26 Aug 2024 09:30:50 +0800 Subject: [PATCH 367/489] ozonec/linux: Add apparmor support --- ozonec/src/linux/apparmor.rs | 44 +++++++++++++++++++++++++++++++++++ ozonec/src/linux/container.rs | 2 ++ ozonec/src/linux/mod.rs | 1 + ozonec/src/linux/process.rs | 15 +++++++++++- 4 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 ozonec/src/linux/apparmor.rs diff --git a/ozonec/src/linux/apparmor.rs b/ozonec/src/linux/apparmor.rs new file mode 100644 index 00000000..1f91c59c --- /dev/null +++ b/ozonec/src/linux/apparmor.rs @@ -0,0 +1,44 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::{fs, path::Path}; + +use anyhow::{Context, Result}; + +const APPARMOR_ENABLED_PATH: &str = "/sys/module/apparmor/parameters/enabled"; +const APPARMOR_INTERFACE: &str = "/proc/self/attr/apparmor/exec"; +const APPARMOR_LEGACY_INTERFACE: &str = "/proc/self/attr/exec"; + +pub fn is_enabled() -> Result { + let enabled = fs::read_to_string(APPARMOR_ENABLED_PATH) + .with_context(|| format!("Failed to read {}", APPARMOR_ENABLED_PATH))?; + Ok(enabled.starts_with('Y')) +} + +pub fn apply_profile(profile: &str) -> Result<()> { + if profile.is_empty() { + return Ok(()); + } + + // Try the module specific subdirectory. This is recommended to configure LSMs + // since Linux kernel 5.1. AppArmor has such a directory since Linux kernel 5.8. + match activate_profile(Path::new(APPARMOR_INTERFACE), profile) { + Ok(_) => Ok(()), + Err(_) => activate_profile(Path::new(APPARMOR_LEGACY_INTERFACE), profile) + .with_context(|| "Failed to apply apparmor profile"), + } +} + +fn activate_profile(path: &Path, profile: &str) -> Result<()> { + fs::write(path, format!("exec {}", profile))?; + Ok(()) +} diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index 5e4166e3..b01991cc 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -221,6 +221,8 @@ impl LinuxContainer { .with_context(|| "Failed to chroot")?; } + process.set_apparmor()?; + if self.config.root.readonly { LinuxContainer::mount_rootfs_readonly()?; } diff --git a/ozonec/src/linux/mod.rs b/ozonec/src/linux/mod.rs index 4e09c1eb..bde83b87 100644 --- a/ozonec/src/linux/mod.rs +++ b/ozonec/src/linux/mod.rs @@ -10,6 +10,7 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. +mod apparmor; mod container; mod device; mod mount; diff --git a/ozonec/src/linux/process.rs b/ozonec/src/linux/process.rs index 0a590c67..2de80b2d 100644 --- a/ozonec/src/linux/process.rs +++ b/ozonec/src/linux/process.rs @@ -28,7 +28,10 @@ use nix::unistd::{self, chdir, setresgid, setresuid, Gid, Pid, Uid}; use prctl::{set_keep_capabilities, set_no_new_privileges}; use rlimit::{setrlimit, Resource, Rlim}; -use super::terminal::{connect_stdio, setup_console}; +use super::{ + apparmor, + terminal::{connect_stdio, setup_console}, +}; use crate::utils::OzonecErr; use oci_spec::{linux::IoPriClass, process::Process as OciProcess}; @@ -193,6 +196,16 @@ impl Process { Ok(()) } + pub fn set_apparmor(&self) -> Result<()> { + if let Some(profile) = &self.oci.apparmorProfile { + if !apparmor::is_enabled()? { + bail!("Apparmor is disabled."); + } + apparmor::apply_profile(profile)?; + } + Ok(()) + } + pub fn reset_capabilities(&self) -> Result<()> { let permitted = caps::read(None, CapSet::Permitted) .with_context(|| OzonecErr::GetAllCaps("Permitted".to_string()))?; -- Gitee From e4615d311f30995fed771ec79f69d9a1782781b8 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Mon, 26 Aug 2024 17:50:41 +0800 Subject: [PATCH 368/489] ozonec/commands: Add support to executing command in container --- ozonec/src/commands/exec.rs | 117 ++++++++++++++++++++++++++++++++++ ozonec/src/commands/mod.rs | 2 + ozonec/src/commands/start.rs | 7 +- ozonec/src/linux/container.rs | 2 + ozonec/src/main.rs | 17 +++-- ozonec/src/utils/error.rs | 4 ++ 6 files changed, 141 insertions(+), 8 deletions(-) create mode 100644 ozonec/src/commands/exec.rs diff --git a/ozonec/src/commands/exec.rs b/ozonec/src/commands/exec.rs new file mode 100644 index 00000000..0bc9b733 --- /dev/null +++ b/ozonec/src/commands/exec.rs @@ -0,0 +1,117 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use core::str; +use std::path::{Path, PathBuf}; + +use anyhow::{anyhow, bail, Context, Result}; +use clap::{builder::NonEmptyStringValueParser, Parser}; +use oci_spec::state::ContainerStatus; + +use crate::{ + container::{Action, Container, Launcher, State}, + linux::LinuxContainer, + utils::OzonecErr, +}; + +/// Execute a new process inside the container +#[derive(Debug, Parser)] +pub struct Exec { + /// Path to an AF_UNIX socket which will receive a file descriptor of the master end + /// of the console's pseudoterminal + #[arg(long)] + pub console_socket: Option, + /// Allocate a pseudio-TTY + #[arg(short, long)] + pub tty: bool, + /// Current working directory in the container + #[arg(long)] + pub cwd: Option, + /// Specify the file to write the process pid to + #[arg(long)] + pub pid_file: Option, + /// Specify environment variables + #[arg(short, long, value_parser = parse_key_val::, number_of_values = 1)] + pub env: Vec<(String, String)>, + /// Prevent the process from gaining additional privileges + #[arg(long)] + pub no_new_privs: bool, + /// Specify the container id + #[arg(value_parser = NonEmptyStringValueParser::new(), required = true)] + pub container_id: String, + /// Specify the command to execute in the container + #[arg(required = false)] + pub command: Vec, +} + +fn parse_key_val(s: &str) -> Result<(T, U)> +where + T: str::FromStr, + T::Err: std::error::Error + Send + Sync + 'static, + U: str::FromStr, + U::Err: std::error::Error + Send + Sync + 'static, +{ + let pos = s + .find('=') + .ok_or(anyhow!("Invalid KEY=value: no '=' found in '{}'", s))?; + Ok((s[..pos].parse()?, s[pos + 1..].parse()?)) +} + +impl Exec { + fn launcher(&self, root: &Path) -> Result { + let mut container_state = + State::load(root, &self.container_id).with_context(|| OzonecErr::LoadConState)?; + + if let Some(config) = container_state.config.as_mut() { + config.process.terminal = self.tty; + config.process.cwd = if let Some(cwd) = &self.cwd { + cwd.to_string_lossy().to_string() + } else { + String::from("/") + }; + + for (env_name, env_value) in &self.env { + config + .process + .env + .as_mut() + .unwrap() + .push(format!("{}={}", env_name, env_value)); + } + config.process.noNewPrivileges = Some(self.no_new_privs); + config.process.args = Some(self.command.clone()); + } + + let container = LinuxContainer::load_from_state(&container_state, &self.console_socket)?; + let oci_status = container + .get_oci_state() + .with_context(|| OzonecErr::GetOciState)? + .status; + if oci_status != ContainerStatus::Created && oci_status != ContainerStatus::Running { + bail!("Can't exec in container with {:?} state", oci_status); + } + + Ok(Launcher::new( + &container_state.bundle, + root, + false, + Box::new(container), + self.pid_file.clone(), + )) + } + + pub fn run(&self, root: &Path) -> Result<()> { + let mut launcher = self.launcher(root)?; + launcher.launch(Action::Exec)?; + Ok(()) + } +} diff --git a/ozonec/src/commands/mod.rs b/ozonec/src/commands/mod.rs index 0ed00ef1..a8bd4691 100644 --- a/ozonec/src/commands/mod.rs +++ b/ozonec/src/commands/mod.rs @@ -11,7 +11,9 @@ // See the Mulan PSL v2 for more details. mod create; +mod exec; mod start; pub use create::Create; +pub use exec::Exec; pub use start::Start; diff --git a/ozonec/src/commands/start.rs b/ozonec/src/commands/start.rs index 782701e4..c8a68802 100644 --- a/ozonec/src/commands/start.rs +++ b/ozonec/src/commands/start.rs @@ -19,6 +19,7 @@ use oci_spec::state::ContainerStatus; use crate::{ container::{Action, Container, Launcher, State}, linux::LinuxContainer, + utils::OzonecErr, }; /// Start the user-specified code from process @@ -29,12 +30,12 @@ pub struct Start { impl Start { fn launcher(&self, root: &Path) -> Result { - let container_state = State::load(root, &self.container_id) - .with_context(|| "Failed to load container state")?; + let container_state = + State::load(root, &self.container_id).with_context(|| OzonecErr::LoadConState)?; let container = LinuxContainer::load_from_state(&container_state, &None)?; let oci_status = container .get_oci_state() - .with_context(|| "Failed to get oci state")? + .with_context(|| OzonecErr::GetOciState)? .status; if oci_status != ContainerStatus::Created { diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index b01991cc..fc7f5648 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -724,6 +724,8 @@ impl Container for LinuxContainer { } fn exec(&mut self, process: &mut Process) -> Result<()> { + // process.init is false. + self.create(process)?; Ok(()) } diff --git a/ozonec/src/main.rs b/ozonec/src/main.rs index 1d6dc9b7..7c30dcee 100644 --- a/ozonec/src/main.rs +++ b/ozonec/src/main.rs @@ -23,7 +23,7 @@ use std::{ use anyhow::{Context, Result}; use clap::{crate_description, Args, Parser, Subcommand}; -use commands::Start; +use commands::{Exec, Start}; use log::info; use nix::unistd::geteuid; @@ -55,7 +55,9 @@ enum StandardCmd { // Extended commands not documented in [OCI Command Line Interface]. #[derive(Subcommand, Debug)] -enum ExtendCmd {} +enum ExtendCmd { + Exec(Exec), +} #[derive(Subcommand, Debug)] enum Command { @@ -79,7 +81,7 @@ fn cmd_run(command: Command, root: &Path) -> Result<()> { match command { Command::Standard(cmd) => match cmd { StandardCmd::Create(create) => { - info!("Exec command: {:?}", create); + info!("Run command: {:?}", create); let mut root_exist = false; create.run(root, &mut root_exist).inspect_err(|_| { @@ -89,11 +91,16 @@ fn cmd_run(command: Command, root: &Path) -> Result<()> { })? } StandardCmd::Start(start) => { - info!("Exec command: {:?}", start); + info!("Run command: {:?}", start); start.run(root)? } }, - Command::Extend(cmd) => (), + Command::Extend(cmd) => match cmd { + ExtendCmd::Exec(exec) => { + info!("Run command: {:?}", exec); + exec.run(root)? + } + }, } Ok(()) } diff --git a/ozonec/src/utils/error.rs b/ozonec/src/utils/error.rs index db1e2430..ffe13756 100644 --- a/ozonec/src/utils/error.rs +++ b/ozonec/src/utils/error.rs @@ -38,4 +38,8 @@ pub enum OzonecErr { AddScmpArch, #[error("Failed to get current directory")] GetCurDir, + #[error("Failed to load container state")] + LoadConState, + #[error("Failed to get oci state")] + GetOciState, } -- Gitee From 4cf826be051538c7786eae780d183466dbbd7075 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Mon, 26 Aug 2024 19:41:41 +0800 Subject: [PATCH 369/489] ozonec/commands: Add support for killing container --- ozonec/src/commands/kill.rs | 72 +++++++++++++++++++++++++++++++++++ ozonec/src/commands/mod.rs | 2 + ozonec/src/container/mod.rs | 2 +- ozonec/src/linux/container.rs | 13 ++++++- ozonec/src/main.rs | 7 +++- 5 files changed, 92 insertions(+), 4 deletions(-) create mode 100644 ozonec/src/commands/kill.rs diff --git a/ozonec/src/commands/kill.rs b/ozonec/src/commands/kill.rs new file mode 100644 index 00000000..070b7932 --- /dev/null +++ b/ozonec/src/commands/kill.rs @@ -0,0 +1,72 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::{path::Path, str::FromStr, thread::sleep, time::Duration}; + +use anyhow::{bail, Context, Result}; +use clap::{builder::NonEmptyStringValueParser, Parser}; +use nix::sys::signal::Signal; +use oci_spec::state::ContainerStatus; + +use crate::{ + container::{Container, State}, + linux::LinuxContainer, +}; + +/// Send a signal to the container process +#[derive(Parser, Debug)] +pub struct Kill { + /// Specify the container id + #[arg(value_parser = NonEmptyStringValueParser::new(), required = true)] + pub container_id: String, + /// The signal to send to the container process + pub signal: String, +} + +impl Kill { + pub fn run(&self, root: &Path) -> Result<()> { + let container_state = State::load(root, &self.container_id)?; + let signal = parse_signal(&self.signal).with_context(|| "Invalid signal")?; + let container = LinuxContainer::load_from_state(&container_state, &None)?; + let mut status = container.get_oci_state()?.status; + + if status == ContainerStatus::Stopped { + bail!("The container is alread stopped"); + } + + container.kill(signal)?; + + let mut _retry = 0; + status = container.get_oci_state()?.status; + while status != ContainerStatus::Stopped { + sleep(Duration::from_millis(1)); + if _retry > 3 { + bail!("The container is still not stopped."); + } + status = container.get_oci_state()?.status; + _retry += 1; + } + Ok(()) + } +} + +fn parse_signal(signal: &str) -> Result { + if let Ok(num) = signal.parse::() { + return Ok(Signal::try_from(num)?); + } + + let mut uppercase_sig = signal.to_uppercase(); + if !uppercase_sig.starts_with("SIG") { + uppercase_sig = format!("SIG{}", &uppercase_sig); + } + Ok(Signal::from_str(&uppercase_sig)?) +} diff --git a/ozonec/src/commands/mod.rs b/ozonec/src/commands/mod.rs index a8bd4691..68d05ee3 100644 --- a/ozonec/src/commands/mod.rs +++ b/ozonec/src/commands/mod.rs @@ -12,8 +12,10 @@ mod create; mod exec; +mod kill; mod start; pub use create::Create; pub use exec::Exec; +pub use kill::Kill; pub use start::Start; diff --git a/ozonec/src/container/mod.rs b/ozonec/src/container/mod.rs index ca576a38..3fbfa4c4 100644 --- a/ozonec/src/container/mod.rs +++ b/ozonec/src/container/mod.rs @@ -41,5 +41,5 @@ pub trait Container { fn exec(&mut self, process: &mut Process) -> Result<()>; - fn kill(&mut self, sig: Signal) -> Result<()>; + fn kill(&self, sig: Signal) -> Result<()>; } diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index fc7f5648..6d520cda 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -26,7 +26,7 @@ use nix::{ errno::Errno, mount::MsFlags, sys::{ - signal::Signal, + signal::{kill, Signal}, statfs::statfs, wait::{waitpid, WaitStatus}, }, @@ -729,7 +729,16 @@ impl Container for LinuxContainer { Ok(()) } - fn kill(&mut self, sig: Signal) -> Result<()> { + fn kill(&self, sig: Signal) -> Result<()> { + let pid = Pid::from_raw(self.pid); + match kill(pid, None) { + Err(errno) => { + if errno != Errno::ESRCH { + bail!("Failed to kill process {}: {:?}", pid, errno); + } + } + Ok(_) => kill(pid, sig)?, + } Ok(()) } } diff --git a/ozonec/src/main.rs b/ozonec/src/main.rs index 7c30dcee..ea1e5129 100644 --- a/ozonec/src/main.rs +++ b/ozonec/src/main.rs @@ -23,7 +23,7 @@ use std::{ use anyhow::{Context, Result}; use clap::{crate_description, Args, Parser, Subcommand}; -use commands::{Exec, Start}; +use commands::{Exec, Kill, Start}; use log::info; use nix::unistd::geteuid; @@ -51,6 +51,7 @@ struct GlobalOpts { enum StandardCmd { Create(Create), Start(Start), + Kill(Kill), } // Extended commands not documented in [OCI Command Line Interface]. @@ -94,6 +95,10 @@ fn cmd_run(command: Command, root: &Path) -> Result<()> { info!("Run command: {:?}", start); start.run(root)? } + StandardCmd::Kill(kill) => { + info!("Run command: {:?}", kill); + kill.run(root)? + } }, Command::Extend(cmd) => match cmd { ExtendCmd::Exec(exec) => { -- Gitee From 5c60cfb79c1e56a982adfd4ed2fba79577d79508 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Tue, 27 Aug 2024 07:32:24 +0800 Subject: [PATCH 370/489] ozonec/commands: Add support for deleting container --- ozonec/src/commands/delete.rs | 52 +++++++++++++++++++++++++++++++++++ ozonec/src/commands/exec.rs | 11 +++----- ozonec/src/commands/kill.rs | 21 ++------------ ozonec/src/commands/mod.rs | 2 ++ ozonec/src/commands/start.rs | 7 ++--- ozonec/src/container/mod.rs | 2 ++ ozonec/src/container/state.rs | 8 +++++- ozonec/src/linux/container.rs | 52 +++++++++++++++++++++++++++++++++-- ozonec/src/main.rs | 7 ++++- 9 files changed, 126 insertions(+), 36 deletions(-) create mode 100644 ozonec/src/commands/delete.rs diff --git a/ozonec/src/commands/delete.rs b/ozonec/src/commands/delete.rs new file mode 100644 index 00000000..67f712e4 --- /dev/null +++ b/ozonec/src/commands/delete.rs @@ -0,0 +1,52 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::{fs, path::Path}; + +use anyhow::{bail, Result}; +use clap::{builder::NonEmptyStringValueParser, Parser}; + +use crate::{ + container::{Container, State}, + linux::LinuxContainer, +}; + +/// Release container resources after the container process has exited +#[derive(Debug, Parser)] +pub struct Delete { + /// Specify the container id + #[arg(value_parser = NonEmptyStringValueParser::new(), required = true)] + pub container_id: String, + /// Force to delete the container (kill the container using SIGKILL) + #[arg(short, long)] + pub force: bool, +} + +impl Delete { + pub fn run(&self, root: &Path) -> Result<()> { + let state_dir = root.join(&self.container_id); + if !state_dir.exists() { + bail!("{} doesn't exist", state_dir.display()); + } + + let state = if let Ok(s) = State::load(root, &self.container_id) { + s + } else { + fs::remove_dir_all(state_dir)?; + return Ok(()); + }; + + let container = LinuxContainer::load_from_state(&state, &None)?; + container.delete(&state, self.force)?; + Ok(()) + } +} diff --git a/ozonec/src/commands/exec.rs b/ozonec/src/commands/exec.rs index 0bc9b733..51347ff7 100644 --- a/ozonec/src/commands/exec.rs +++ b/ozonec/src/commands/exec.rs @@ -18,7 +18,7 @@ use clap::{builder::NonEmptyStringValueParser, Parser}; use oci_spec::state::ContainerStatus; use crate::{ - container::{Action, Container, Launcher, State}, + container::{Action, Launcher, State}, linux::LinuxContainer, utils::OzonecErr, }; @@ -92,12 +92,9 @@ impl Exec { } let container = LinuxContainer::load_from_state(&container_state, &self.console_socket)?; - let oci_status = container - .get_oci_state() - .with_context(|| OzonecErr::GetOciState)? - .status; - if oci_status != ContainerStatus::Created && oci_status != ContainerStatus::Running { - bail!("Can't exec in container with {:?} state", oci_status); + let status = container.status()?; + if status != ContainerStatus::Created && status != ContainerStatus::Running { + bail!("Can't exec in container with {:?} state", status); } Ok(Launcher::new( diff --git a/ozonec/src/commands/kill.rs b/ozonec/src/commands/kill.rs index 070b7932..d67a0079 100644 --- a/ozonec/src/commands/kill.rs +++ b/ozonec/src/commands/kill.rs @@ -10,12 +10,11 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use std::{path::Path, str::FromStr, thread::sleep, time::Duration}; +use std::{path::Path, str::FromStr}; -use anyhow::{bail, Context, Result}; +use anyhow::{Context, Result}; use clap::{builder::NonEmptyStringValueParser, Parser}; use nix::sys::signal::Signal; -use oci_spec::state::ContainerStatus; use crate::{ container::{Container, State}, @@ -37,24 +36,8 @@ impl Kill { let container_state = State::load(root, &self.container_id)?; let signal = parse_signal(&self.signal).with_context(|| "Invalid signal")?; let container = LinuxContainer::load_from_state(&container_state, &None)?; - let mut status = container.get_oci_state()?.status; - - if status == ContainerStatus::Stopped { - bail!("The container is alread stopped"); - } container.kill(signal)?; - - let mut _retry = 0; - status = container.get_oci_state()?.status; - while status != ContainerStatus::Stopped { - sleep(Duration::from_millis(1)); - if _retry > 3 { - bail!("The container is still not stopped."); - } - status = container.get_oci_state()?.status; - _retry += 1; - } Ok(()) } } diff --git a/ozonec/src/commands/mod.rs b/ozonec/src/commands/mod.rs index 68d05ee3..a5751b55 100644 --- a/ozonec/src/commands/mod.rs +++ b/ozonec/src/commands/mod.rs @@ -11,11 +11,13 @@ // See the Mulan PSL v2 for more details. mod create; +mod delete; mod exec; mod kill; mod start; pub use create::Create; +pub use delete::Delete; pub use exec::Exec; pub use kill::Kill; pub use start::Start; diff --git a/ozonec/src/commands/start.rs b/ozonec/src/commands/start.rs index c8a68802..33ce7dd6 100644 --- a/ozonec/src/commands/start.rs +++ b/ozonec/src/commands/start.rs @@ -17,7 +17,7 @@ use clap::Parser; use oci_spec::state::ContainerStatus; use crate::{ - container::{Action, Container, Launcher, State}, + container::{Action, Launcher, State}, linux::LinuxContainer, utils::OzonecErr, }; @@ -33,10 +33,7 @@ impl Start { let container_state = State::load(root, &self.container_id).with_context(|| OzonecErr::LoadConState)?; let container = LinuxContainer::load_from_state(&container_state, &None)?; - let oci_status = container - .get_oci_state() - .with_context(|| OzonecErr::GetOciState)? - .status; + let oci_status = container.status()?; if oci_status != ContainerStatus::Created { bail!("Can't start a container with {:?} status", oci_status); diff --git a/ozonec/src/container/mod.rs b/ozonec/src/container/mod.rs index 3fbfa4c4..761e2517 100644 --- a/ozonec/src/container/mod.rs +++ b/ozonec/src/container/mod.rs @@ -42,4 +42,6 @@ pub trait Container { fn exec(&mut self, process: &mut Process) -> Result<()>; fn kill(&self, sig: Signal) -> Result<()>; + + fn delete(&self, state: &State, force: bool) -> Result<()>; } diff --git a/ozonec/src/container/state.rs b/ozonec/src/container/state.rs index 41ec2ec9..e689a1ee 100644 --- a/ozonec/src/container/state.rs +++ b/ozonec/src/container/state.rs @@ -11,7 +11,7 @@ // See the Mulan PSL v2 for more details. use std::{ - fs::{DirBuilder, File, OpenOptions}, + fs::{self, DirBuilder, File, OpenOptions}, os::unix::fs::DirBuilderExt, path::{Path, PathBuf}, time::SystemTime, @@ -107,6 +107,12 @@ impl State { Ok(state) } + pub fn remove_dir(&self) -> Result<()> { + let state_dir = &self.root.join(&self.id); + fs::remove_dir_all(state_dir).with_context(|| "Failed to remove state directory")?; + Ok(()) + } + fn file_path(root: &Path, id: &str) -> PathBuf { root.join(id).join("state.json") } diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index 6d520cda..26dbc6fb 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -16,7 +16,8 @@ use std::{ io::Write, os::{fd::AsRawFd, unix::net::UnixStream}, path::{Path, PathBuf}, - time::SystemTime, + thread::sleep, + time::{Duration, SystemTime}, }; use anyhow::{anyhow, bail, Context, Result}; @@ -292,7 +293,7 @@ impl LinuxContainer { Ok(()) } - fn container_status(&self) -> Result { + fn get_container_status(&self) -> Result { if self.pid == -1 { return Ok(ContainerStatus::Creating); } @@ -323,6 +324,13 @@ impl LinuxContainer { } } + pub fn status(&self) -> Result { + Ok(self + .get_oci_state() + .with_context(|| OzonecErr::GetOciState)? + .status) + } + fn ns_controller(&self) -> Result { Ok(self .config @@ -599,7 +607,7 @@ impl Container for LinuxContainer { } fn get_oci_state(&self) -> Result { - let status = self.container_status()?; + let status = self.get_container_status()?; let pid = if status != ContainerStatus::Stopped { self.pid } else { @@ -730,6 +738,14 @@ impl Container for LinuxContainer { } fn kill(&self, sig: Signal) -> Result<()> { + let mut status = self.status()?; + if status == ContainerStatus::Stopped { + bail!("The container is already stopped"); + } + if status == ContainerStatus::Creating { + bail!("The container has not been created"); + } + let pid = Pid::from_raw(self.pid); match kill(pid, None) { Err(errno) => { @@ -739,6 +755,36 @@ impl Container for LinuxContainer { } Ok(_) => kill(pid, sig)?, } + + let mut _retry = 0; + status = self.status()?; + while status != ContainerStatus::Stopped { + sleep(Duration::from_millis(1)); + if _retry > 3 { + bail!("The container is still not stopped."); + } + status = self.status()?; + _retry += 1; + } + Ok(()) + } + + fn delete(&self, state: &State, force: bool) -> Result<()> { + match self.status()? { + ContainerStatus::Stopped => state.remove_dir()?, + _ => { + if force { + self.kill(Signal::SIGKILL) + .with_context(|| "Failed to kill the container by force")?; + state.remove_dir()?; + } else { + bail!( + "Failed to delete container {} which is not stopped", + &state.id + ); + } + } + } Ok(()) } } diff --git a/ozonec/src/main.rs b/ozonec/src/main.rs index ea1e5129..6eceaeb3 100644 --- a/ozonec/src/main.rs +++ b/ozonec/src/main.rs @@ -23,7 +23,7 @@ use std::{ use anyhow::{Context, Result}; use clap::{crate_description, Args, Parser, Subcommand}; -use commands::{Exec, Kill, Start}; +use commands::{Delete, Exec, Kill, Start}; use log::info; use nix::unistd::geteuid; @@ -52,6 +52,7 @@ enum StandardCmd { Create(Create), Start(Start), Kill(Kill), + Delete(Delete), } // Extended commands not documented in [OCI Command Line Interface]. @@ -99,6 +100,10 @@ fn cmd_run(command: Command, root: &Path) -> Result<()> { info!("Run command: {:?}", kill); kill.run(root)? } + StandardCmd::Delete(delete) => { + info!("Run command: {:?}", delete); + delete.run(root)? + } }, Command::Extend(cmd) => match cmd { ExtendCmd::Exec(exec) => { -- Gitee From 1953e2c0f955e6e44be4a901cb01583bef8dd3ad Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Tue, 27 Aug 2024 07:51:32 +0800 Subject: [PATCH 371/489] ozonec/commands: Add support for quering container state --- ozonec/src/commands/mod.rs | 2 ++ ozonec/src/commands/state.rs | 55 ++++++++++++++++++++++++++++++++++++ ozonec/src/main.rs | 7 ++++- 3 files changed, 63 insertions(+), 1 deletion(-) create mode 100644 ozonec/src/commands/state.rs diff --git a/ozonec/src/commands/mod.rs b/ozonec/src/commands/mod.rs index a5751b55..f8096f3f 100644 --- a/ozonec/src/commands/mod.rs +++ b/ozonec/src/commands/mod.rs @@ -15,9 +15,11 @@ mod delete; mod exec; mod kill; mod start; +mod state; pub use create::Create; pub use delete::Delete; pub use exec::Exec; pub use kill::Kill; pub use start::Start; +pub use state::State; diff --git a/ozonec/src/commands/state.rs b/ozonec/src/commands/state.rs new file mode 100644 index 00000000..d667694f --- /dev/null +++ b/ozonec/src/commands/state.rs @@ -0,0 +1,55 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::path::{Path, PathBuf}; + +use anyhow::{Context, Result}; +use clap::{builder::NonEmptyStringValueParser, Parser}; +use serde::{Deserialize, Serialize}; + +use crate::{container::State as ContainerState, linux::LinuxContainer}; + +/// Request the container state +#[derive(Debug, Parser)] +pub struct State { + /// Specify the container id + #[arg(value_parser = NonEmptyStringValueParser::new(), required = true)] + pub container_id: String, +} + +#[derive(Serialize, Deserialize, Debug)] +pub struct RuntimeState { + pub oci_version: String, + pub id: String, + pub status: String, + pub pid: i32, + pub bundle: PathBuf, +} + +impl State { + pub fn run(&self, root: &Path) -> Result<()> { + let state = ContainerState::load(root, &self.container_id)?; + let container = LinuxContainer::load_from_state(&state, &None)?; + let runtime_state = RuntimeState { + oci_version: state.oci_version, + id: state.id, + pid: state.pid, + status: container.status()?.to_string(), + bundle: state.bundle, + }; + let json_data = &serde_json::to_string_pretty(&runtime_state) + .with_context(|| "Failed to get json data of container state")?; + + println!("{}", json_data); + Ok(()) + } +} diff --git a/ozonec/src/main.rs b/ozonec/src/main.rs index 6eceaeb3..06d67a65 100644 --- a/ozonec/src/main.rs +++ b/ozonec/src/main.rs @@ -23,7 +23,7 @@ use std::{ use anyhow::{Context, Result}; use clap::{crate_description, Args, Parser, Subcommand}; -use commands::{Delete, Exec, Kill, Start}; +use commands::{Delete, Exec, Kill, Start, State}; use log::info; use nix::unistd::geteuid; @@ -51,6 +51,7 @@ struct GlobalOpts { enum StandardCmd { Create(Create), Start(Start), + State(State), Kill(Kill), Delete(Delete), } @@ -104,6 +105,10 @@ fn cmd_run(command: Command, root: &Path) -> Result<()> { info!("Run command: {:?}", delete); delete.run(root)? } + StandardCmd::State(state) => { + info!("Run command: {:?}", state); + state.run(root)? + } }, Command::Extend(cmd) => match cmd { ExtendCmd::Exec(exec) => { -- Gitee From cfb0bef23a81c58aae798ce9ab304e983adfbef4 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Tue, 27 Aug 2024 07:52:39 +0800 Subject: [PATCH 372/489] ozonec: Add Cargo.lock --- ozonec/Cargo.lock | 910 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 910 insertions(+) create mode 100644 ozonec/Cargo.lock diff --git a/ozonec/Cargo.lock b/ozonec/Cargo.lock new file mode 100644 index 00000000..f2e9b747 --- /dev/null +++ b/ozonec/Cargo.lock @@ -0,0 +1,910 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "aho-corasick" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-tzdata" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" + +[[package]] +name = "autocfg" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bumpalo" +version = "3.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "caps" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190baaad529bcfbde9e1a19022c42781bdb6ff9de25721abdb8fd98c0807730b" +dependencies = [ + "libc", + "thiserror", +] + +[[package]] +name = "cc" +version = "1.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72db2f7947ecee9b03b510377e8bb9077afa27176fdbff55c51027e976fdcc48" +dependencies = [ + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "chrono" +version = "0.4.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" +dependencies = [ + "android-tzdata", + "iana-time-zone", + "num-traits", + "serde", + "windows-targets 0.52.6", +] + +[[package]] +name = "clap" +version = "4.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76" +dependencies = [ + "bitflags", + "clap_derive", + "clap_lex", + "once_cell", +] + +[[package]] +name = "clap_derive" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "clap_lex" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "033f6b7a4acb1f358c742aaca805c939ee73b4c6209ae4318ec7aca81c42e646" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "clone3" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ee4e061ea30800291ca09663878f3953840a69b08ce244b3e8b26e894d9f60f" +dependencies = [ + "bitflags", + "uapi", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "crc32fast" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "flate2" +version = "1.0.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f211bbe8e69bbd0cfdea405084f128ae8b4aaa6b0b522fc8f2b009084797920" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "hermit-abi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "iana-time-zone" +version = "0.1.60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "wasm-bindgen", + "windows-core", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" +dependencies = [ + "hermit-abi", + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "js-sys" +version = "0.3.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1868808506b929d7b0cfa8f75951347aa71bb21144b7791bae35d9bccfcfe37a" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.146" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f92be4933c13fd498862a9e02a3055f8a8d9c039ce33db97306fd5a6caa7f29b" + +[[package]] +name = "libseccomp" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21c57fd8981a80019807b7b68118618d29a87177c63d704fc96e6ecd003ae5b3" +dependencies = [ + "bitflags", + "libc", + "libseccomp-sys", + "pkg-config", +] + +[[package]] +name = "libseccomp-sys" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a7cbbd4ad467251987c6e5b47d53b11a5a05add08f2447a9e2d70aef1e0d138" + +[[package]] +name = "linux-raw-sys" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" + +[[package]] +name = "log" +version = "0.4.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + +[[package]] +name = "miniz_oxide" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8a240ddb74feaf34a79a7add65a741f3167852fba007066dcac1ca548d89c08" +dependencies = [ + "adler", +] + +[[package]] +name = "nix" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" +dependencies = [ + "bitflags", + "cfg-if", + "libc", + "memoffset", + "pin-utils", + "static_assertions", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "oci_spec" +version = "0.1.0" +dependencies = [ + "anyhow", + "libc", + "nix", + "serde", + "serde_json", +] + +[[package]] +name = "once_cell" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" + +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + +[[package]] +name = "ozonec" +version = "0.1.0" +dependencies = [ + "anyhow", + "caps", + "chrono", + "clap", + "clone3", + "libc", + "libseccomp", + "log", + "nix", + "oci_spec", + "prctl", + "procfs", + "rlimit", + "serde", + "serde_json", + "thiserror", +] + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkg-config" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" + +[[package]] +name = "prctl" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "059a34f111a9dee2ce1ac2826a68b24601c4298cfeb1a587c3cb493d5ab46f52" +dependencies = [ + "libc", + "nix", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "procfs" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1de8dacb0873f77e6aefc6d71e044761fcc68060290f5b1089fcdf84626bb69" +dependencies = [ + "bitflags", + "byteorder", + "chrono", + "flate2", + "hex", + "lazy_static", + "rustix", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "rlimit" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81a9ed03edbed449d6897c2092c71ab5f7b5fb80f6f0b1a3ed6d40a6f9fc0720" +dependencies = [ + "libc", +] + +[[package]] +name = "rustix" +version = "0.36.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "305efbd14fde4139eb501df5f136994bb520b033fa9fbdce287507dc23b8c7ed" +dependencies = [ + "bitflags", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.45.0", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "serde" +version = "1.0.163" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.163" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.74", +] + +[[package]] +name = "serde_json" +version = "1.0.96" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fceb41e3d546d0bd83421d3409b1460cc7444cd389341a4c880fe7a042cb3d7" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.74", +] + +[[package]] +name = "uapi" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3bf073840d1b16485bfe28b4e752eccee38d9ac53f152adf869708e3136561e6" +dependencies = [ + "cc", + "cfg-if", + "libc", + "uapi-proc", +] + +[[package]] +name = "uapi-proc" +version = "0.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54de46f980cea7b2ae8d8f7f9f1c35cf7062c68343e99345ef73758f8e60975a" +dependencies = [ + "lazy_static", + "libc", + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "wasm-bindgen" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a82edfc16a6c469f5f44dc7b571814045d60404b55a0ee849f9bcfa2e63dd9b5" +dependencies = [ + "cfg-if", + "once_cell", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de396da306523044d3302746f1208fa71d7532227f15e347e2d93e4145dd77b" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.74", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "585c4c91a46b072c92e908d99cb1dcdf95c5218eeb6f3bf1efa991ee7a68cccf" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afc340c74d9005395cf9dd098506f7f44e38f2b4a21c6aaacf9a105ea5e1e836" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.74", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c62a0a307cb4a311d3a07867860911ca130c3494e8c2719593806c08bc5d0484" + +[[package]] +name = "windows-core" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -- Gitee From 0bace50e33a87cd46ae629552430ea5102076bc8 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Tue, 27 Aug 2024 08:04:39 +0800 Subject: [PATCH 373/489] ozonec/laucher: Add comments about process relationship --- ozonec/src/container/launcher.rs | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/ozonec/src/container/launcher.rs b/ozonec/src/container/launcher.rs index 0e0e7eb1..ef68c392 100644 --- a/ozonec/src/container/launcher.rs +++ b/ozonec/src/container/launcher.rs @@ -10,13 +10,32 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. +// Linux container create flow: +// ozonec create | State 1 process | Stage 2 process | ozonec start +// | | | +// -> clone3 -> | | | +// <- mapping request <- | | | +// write uid/gid mappings | | | +// -> send mapping done -> | | | +// | set uid/gid | | +// | set pid namespace | | +// <- send stage 2 pid | | -> clone3 -> | +// | exit | set rest namespaces | +// | | pivot_root/chroot | +// | | set capabilities | +// | | set seccomp | +// < send ready <- | | +// | | wait for start signal | +// update pid file | | | ozonec start $id +// exit | | | <- send start signal +// | | execvp cmd | exit + use std::path::{Path, PathBuf}; use anyhow::{Context, Result}; -use crate::{linux::Process, utils::OzonecErr}; - use super::{state::State, Container}; +use crate::{linux::Process, utils::OzonecErr}; #[derive(Debug, Clone, Copy, PartialEq)] pub enum Action { -- Gitee From 7d9bf18910b2af630acca5272555f4282301dbc7 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Wed, 28 Aug 2024 20:32:01 +0800 Subject: [PATCH 374/489] ozonec/oci_spec: Print failed reason loading config.json --- ozonec/oci_spec/src/runtime.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/ozonec/oci_spec/src/runtime.rs b/ozonec/oci_spec/src/runtime.rs index f1286357..d68dea0b 100644 --- a/ozonec/oci_spec/src/runtime.rs +++ b/ozonec/oci_spec/src/runtime.rs @@ -12,7 +12,7 @@ use std::{collections::HashMap, fs::File, io::BufReader, path::Path}; -use anyhow::{Context, Result}; +use anyhow::{anyhow, Context, Result}; use serde::{Deserialize, Serialize}; #[cfg(target_os = "linux")] @@ -87,9 +87,7 @@ impl RuntimeConfig { pub fn from_file(path: &String) -> Result { let file = File::open(Path::new(path)).with_context(|| "Failed to open config.json")?; let reader = BufReader::new(file); - let config = - serde_json::from_reader(reader).with_context(|| "Failed to load config.json")?; - Ok(config) + serde_json::from_reader(reader).map_err(|e| anyhow!("Failed to load config.json: {:?}", e)) } } -- Gitee From 2ee081c66ed7780827e35131584a94b60b24b694 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Thu, 29 Aug 2024 12:43:54 +0800 Subject: [PATCH 375/489] ozonec/oci_spec: Set default values when not set in config.json Although in OCI spec process.user.uid/gid, resources.devices.allow and seccomp.syscalls.args.index/value are required, but some users still don't set these values in config.json. So let's set default values to these parameters in config.json as runc/crun does. --- ozonec/oci_spec/src/linux.rs | 3 +++ ozonec/oci_spec/src/posix.rs | 2 ++ 2 files changed, 5 insertions(+) diff --git a/ozonec/oci_spec/src/linux.rs b/ozonec/oci_spec/src/linux.rs index 4de386f3..6dafcd5a 100644 --- a/ozonec/oci_spec/src/linux.rs +++ b/ozonec/oci_spec/src/linux.rs @@ -130,6 +130,7 @@ fn default_device_type() -> String { #[derive(Serialize, Deserialize, Debug, Clone)] pub struct CgroupDevice { /// Whether the entry is allowed or denied. + #[serde(default)] pub allow: bool, /// Type of device. #[serde(default = "default_device_type", rename = "type")] @@ -429,8 +430,10 @@ pub enum SeccompOp { /// The specific syscall in seccomp. pub struct SeccompSyscallArg { /// Index for syscall arguments. + #[serde(default)] pub index: usize, /// Value for syscall arguments. + #[serde(default)] pub value: u64, #[serde(skip_serializing_if = "Option::is_none")] /// Value for syscall arguments. diff --git a/ozonec/oci_spec/src/posix.rs b/ozonec/oci_spec/src/posix.rs index b6ae8b37..b284d5d3 100644 --- a/ozonec/oci_spec/src/posix.rs +++ b/ozonec/oci_spec/src/posix.rs @@ -41,8 +41,10 @@ pub struct Rlimits { #[derive(Serialize, Deserialize, Debug, Clone)] pub struct User { /// User ID in the container namespace. + #[serde(default)] pub uid: u32, /// Group ID in the container namespace. + #[serde(default)] pub gid: u32, /// [umask][umask_2] of the user. #[serde(skip_serializing_if = "Option::is_none")] -- Gitee From aae92e04f1e497cd85da69547d63fa8e3b010876 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Fri, 30 Aug 2024 17:49:49 +0800 Subject: [PATCH 376/489] typos: Allow the spelling closID --- _typos.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/_typos.toml b/_typos.toml index 1d161a7f..9bbf0e69 100644 --- a/_typos.toml +++ b/_typos.toml @@ -18,6 +18,8 @@ RTC_MIS = "RTC_MIS" SECCOMP_FILETER_FLAG_TSYNC = "SECCOMP_FILETER_FLAG_TSYNC" test_ths = "test_ths" UART_LSR_THRE = "UART_LSR_THRE" +closID = "closID" +CLOS = "CLOS" [default.extend-words] ba = "ba" -- Gitee From 74409aa93ce0be8b27a1523a10d3d36bb754d471 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Fri, 30 Aug 2024 23:24:56 +0800 Subject: [PATCH 377/489] ozonec: Fix compile issues with rustc 1.64 --- ozonec/Cargo.lock | 93 +---------------------- ozonec/Cargo.toml | 3 +- ozonec/src/linux/container.rs | 12 +-- ozonec/src/linux/notify_socket.rs | 6 +- ozonec/src/linux/process.rs | 18 ++--- ozonec/src/linux/terminal.rs | 2 +- ozonec/src/main.rs | 5 +- ozonec/src/utils/channel.rs | 2 +- ozonec/src/utils/clone.rs | 121 ++++++++++++++++++++++++++++++ ozonec/src/utils/mod.rs | 3 + ozonec/src/utils/prctl.rs | 94 +++++++++++++++++++++++ 11 files changed, 243 insertions(+), 116 deletions(-) create mode 100644 ozonec/src/utils/clone.rs create mode 100644 ozonec/src/utils/prctl.rs diff --git a/ozonec/Cargo.lock b/ozonec/Cargo.lock index f2e9b747..6274f9c4 100644 --- a/ozonec/Cargo.lock +++ b/ozonec/Cargo.lock @@ -8,15 +8,6 @@ version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" -[[package]] -name = "aho-corasick" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" -dependencies = [ - "memchr", -] - [[package]] name = "android-tzdata" version = "0.1.1" @@ -134,16 +125,6 @@ dependencies = [ "os_str_bytes", ] -[[package]] -name = "clone3" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee4e061ea30800291ca09663878f3953840a69b08ce244b3e8b26e894d9f60f" -dependencies = [ - "bitflags", - "uapi", -] - [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -288,12 +269,6 @@ version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" -[[package]] -name = "memchr" -version = "2.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" - [[package]] name = "memoffset" version = "0.7.1" @@ -363,16 +338,15 @@ name = "ozonec" version = "0.1.0" dependencies = [ "anyhow", + "bitflags", "caps", "chrono", "clap", - "clone3", "libc", "libseccomp", "log", "nix", "oci_spec", - "prctl", "procfs", "rlimit", "serde", @@ -392,16 +366,6 @@ version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" -[[package]] -name = "prctl" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "059a34f111a9dee2ce1ac2826a68b24601c4298cfeb1a587c3cb493d5ab46f52" -dependencies = [ - "libc", - "nix", -] - [[package]] name = "proc-macro-error" version = "1.0.4" @@ -459,35 +423,6 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "regex" -version = "1.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" -dependencies = [ - "aho-corasick", - "memchr", - "regex-automata", - "regex-syntax", -] - -[[package]] -name = "regex-automata" -version = "0.4.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" -dependencies = [ - "aho-corasick", - "memchr", - "regex-syntax", -] - -[[package]] -name = "regex-syntax" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" - [[package]] name = "rlimit" version = "0.5.4" @@ -602,32 +537,6 @@ dependencies = [ "syn 2.0.74", ] -[[package]] -name = "uapi" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bf073840d1b16485bfe28b4e752eccee38d9ac53f152adf869708e3136561e6" -dependencies = [ - "cc", - "cfg-if", - "libc", - "uapi-proc", -] - -[[package]] -name = "uapi-proc" -version = "0.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54de46f980cea7b2ae8d8f7f9f1c35cf7062c68343e99345ef73758f8e60975a" -dependencies = [ - "lazy_static", - "libc", - "proc-macro2", - "quote", - "regex", - "syn 1.0.109", -] - [[package]] name = "unicode-ident" version = "1.0.12" diff --git a/ozonec/Cargo.toml b/ozonec/Cargo.toml index c3e52cf5..ac0977b3 100644 --- a/ozonec/Cargo.toml +++ b/ozonec/Cargo.toml @@ -8,16 +8,15 @@ description = "An OCI runtime implemented by Rust" [dependencies] anyhow = "= 1.0.71" +bitflags = "= 1.3.2" caps = "0.5.5" chrono = { version = "0.4.31", default-features = false, features = ["clock", "serde"] } clap = { version = "= 4.1.4", default-features = false, features = ["derive", "cargo", "std", "help", "usage"] } -clone3 = "0.2.3" libc = "= 0.2.146" libseccomp = "0.3.0" log = { version = "= 0.4.18", features = ["std"]} nix = "= 0.26.2" oci_spec = { path = "oci_spec" } -prctl = "1.0.0" procfs = "0.14.0" rlimit = "0.5.3" serde = { version = "= 1.0.163", features = ["derive"] } diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index 26dbc6fb..ff818920 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -14,7 +14,7 @@ use std::{ collections::HashMap, fs::{self, canonicalize, create_dir_all, OpenOptions}, io::Write, - os::{fd::AsRawFd, unix::net::UnixStream}, + os::unix::{io::AsRawFd, net::UnixStream}, path::{Path, PathBuf}, thread::sleep, time::{Duration, SystemTime}, @@ -33,7 +33,6 @@ use nix::{ }, unistd::{self, chown, getegid, geteuid, sethostname, unlink, Gid, Pid, Uid}, }; -use prctl::set_dumpable; use procfs::process::ProcState; use super::{ @@ -45,7 +44,7 @@ use super::{ use crate::{ container::{Container, State}, linux::{rootfs::Rootfs, seccomp::set_seccomp}, - utils::{Channel, Message, OzonecErr}, + utils::{prctl, Channel, Message, OzonecErr}, }; use oci_spec::{ linux::{Device as OciDevice, IdMapping, NamespaceType}, @@ -358,14 +357,15 @@ impl LinuxContainer { if ns.path.is_none() { // Child process needs to be dumpable, otherwise the parent process is not // allowed to write the uid/gid mappings. - set_dumpable(true).map_err(|e| anyhow!("Failed to set process dumpable: {e}"))?; + prctl::set_dumpable(true) + .map_err(|e| anyhow!("Failed to set process dumpable: {e}"))?; parent_channel .send_id_mappings() .with_context(|| "Failed to send id mappings")?; fst_stage_channel .recv_id_mappings_done() .with_context(|| "Failed to receive id mappings done")?; - set_dumpable(false) + prctl::set_dumpable(false) .map_err(|e| anyhow!("Failed to set process undumpable: {e}"))?; } @@ -656,7 +656,7 @@ impl Container for LinuxContainer { // processes in namespaces to join to access host resources (or execute code). if !self.config.linux.as_ref().unwrap().namespaces.is_empty() { prctl::set_dumpable(false) - .map_err(|e| anyhow!("Failed to set process undumpable: {}", e))?; + .map_err(|e| anyhow!("Failed to set process undumpable: errno {}", e))?; } // Create channels to communicate with child processes. diff --git a/ozonec/src/linux/notify_socket.rs b/ozonec/src/linux/notify_socket.rs index a2ccc695..956c415e 100644 --- a/ozonec/src/linux/notify_socket.rs +++ b/ozonec/src/linux/notify_socket.rs @@ -13,9 +13,9 @@ use std::{ env, io::{Read, Write}, - os::{ - fd::AsRawFd, - unix::net::{UnixListener, UnixStream}, + os::unix::{ + io::AsRawFd, + net::{UnixListener, UnixStream}, }, path::PathBuf, }; diff --git a/ozonec/src/linux/process.rs b/ozonec/src/linux/process.rs index 2de80b2d..7fac8cf7 100644 --- a/ozonec/src/linux/process.rs +++ b/ozonec/src/linux/process.rs @@ -16,23 +16,21 @@ use std::{ fs::{self, read_to_string}, io::{stderr, stdin, stdout}, mem, - os::fd::{AsRawFd, RawFd}, + os::unix::io::{AsRawFd, RawFd}, path::PathBuf, str::FromStr, }; use anyhow::{anyhow, bail, Context, Result}; use caps::{self, CapSet, Capability, CapsHashSet}; -use clone3::Clone3; use nix::unistd::{self, chdir, setresgid, setresuid, Gid, Pid, Uid}; -use prctl::{set_keep_capabilities, set_no_new_privileges}; use rlimit::{setrlimit, Resource, Rlim}; use super::{ apparmor, terminal::{connect_stdio, setup_console}, }; -use crate::utils::OzonecErr; +use crate::utils::{prctl, Clone3, OzonecErr}; use oci_spec::{linux::IoPriClass, process::Process as OciProcess}; pub struct Process { @@ -149,7 +147,7 @@ impl Process { pub fn set_no_new_privileges(&self) -> Result<()> { if let Some(no_new_privileges) = self.oci.noNewPrivileges { if no_new_privileges { - set_no_new_privileges(true) + prctl::set_no_new_privileges(true) .map_err(|e| anyhow!("Failed to set no new privileges: {}", e))?; } } @@ -238,7 +236,7 @@ impl Process { } pub fn set_id(&self, gid: Gid, uid: Uid) -> Result<()> { - set_keep_capabilities(true) + prctl::set_keep_capabilities(true) .map_err(|e| anyhow!("Failed to enable keeping capabilities: {}", e))?; setresgid(gid, gid, gid).with_context(|| "Failed to setresgid")?; setresuid(uid, uid, uid).with_context(|| "Failed to setresuid")?; @@ -247,7 +245,7 @@ impl Process { .with_context(|| OzonecErr::GetAllCaps("Permitted".to_string()))?; caps::set(None, CapSet::Effective, &permitted) .with_context(|| OzonecErr::SetCaps("Effective".to_string()))?; - set_keep_capabilities(false) + prctl::set_keep_capabilities(false) .map_err(|e| anyhow!("Failed to disable keeping capabilities: {}", e))?; Ok(()) } @@ -312,8 +310,10 @@ pub fn clone_process Result>(child_name: &str, cb: F) -> Res let mut clone3 = Clone3::default(); clone3.exit_signal(libc::SIGCHLD as u64); - // SAFETY: FFI call with valid arguments. - match unsafe { clone3.call().with_context(|| "Clone3() error")? } { + match clone3 + .call() + .map_err(|e| anyhow!("Clone3() error: {}", e))? + { 0 => { prctl::set_name(child_name) .map_err(|e| anyhow!("Failed to set process name: errno {}", e))?; diff --git a/ozonec/src/linux/terminal.rs b/ozonec/src/linux/terminal.rs index e7490d2b..66418793 100644 --- a/ozonec/src/linux/terminal.rs +++ b/ozonec/src/linux/terminal.rs @@ -13,7 +13,7 @@ use std::{ io::IoSlice, mem::ManuallyDrop, - os::fd::{AsRawFd, RawFd}, + os::unix::io::{AsRawFd, RawFd}, }; use anyhow::{Context, Result}; diff --git a/ozonec/src/main.rs b/ozonec/src/main.rs index 06d67a65..29c529bb 100644 --- a/ozonec/src/main.rs +++ b/ozonec/src/main.rs @@ -21,7 +21,7 @@ use std::{ process::exit, }; -use anyhow::{Context, Result}; +use anyhow::{anyhow, Context, Result}; use clap::{crate_description, Args, Parser, Subcommand}; use commands::{Delete, Exec, Kill, Start, State}; use log::info; @@ -87,10 +87,11 @@ fn cmd_run(command: Command, root: &Path) -> Result<()> { info!("Run command: {:?}", create); let mut root_exist = false; - create.run(root, &mut root_exist).inspect_err(|_| { + create.run(root, &mut root_exist).map_err(|e| { if !root_exist { let _ = remove_dir_all(root); } + anyhow!(e) })? } StandardCmd::Start(start) => { diff --git a/ozonec/src/utils/channel.rs b/ozonec/src/utils/channel.rs index b74c3a78..97ff2dc7 100644 --- a/ozonec/src/utils/channel.rs +++ b/ozonec/src/utils/channel.rs @@ -15,7 +15,7 @@ use std::{ io::{IoSlice, IoSliceMut}, marker::PhantomData, mem, - os::fd::RawFd, + os::unix::io::RawFd, slice, }; diff --git a/ozonec/src/utils/clone.rs b/ozonec/src/utils/clone.rs new file mode 100644 index 00000000..2476a2f3 --- /dev/null +++ b/ozonec/src/utils/clone.rs @@ -0,0 +1,121 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::os::unix::io::{AsRawFd, RawFd}; + +use anyhow::{bail, Result}; +use nix::errno::errno; + +bitflags::bitflags! { + #[derive(Default)] + pub struct Flags: u64 { + const CHILD_CLEARTID = 0x00200000; + const CHILD_SETTID = 0x01000000; + const FILES = 0x00000400; + const FS = 0x00000200; + const INTO_CGROUP = 0x200000000; + const IO = 0x80000000; + const NEWCGROUP = 0x02000000; + const NEWIPC = 0x08000000; + const NEWNET = 0x40000000; + const NEWNS = 0x00020000; + const NEWPID = 0x20000000; + const NEWTIME = 0x00000080; + const NEWUSER = 0x10000000; + const NEWUTS = 0x04000000; + const PARENT = 0x00008000; + const PARENT_SETTID = 0x00100000; + const PIDFD = 0x00001000; + const PTRACE = 0x00002000; + const SETTLS = 0x00080000; + const SIGHAND = 0x00000800; + const SYSVSEM = 0x00040000; + const THREAD = 0x00010000; + const UNTRACED = 0x00800000; + const VFORK = 0x00004000; + const VM = 0x00000100; + } +} + +#[repr(C, align(8))] +#[derive(Debug, Default)] +pub struct CloneArgs { + pub flags: u64, + pub pid_fd: u64, + pub child_tid: u64, + pub parent_tid: u64, + pub exit_signal: u64, + pub stack: u64, + pub stack_size: u64, + pub tls: u64, + pub cgroup: u64, +} + +#[derive(Default)] +pub struct Clone3<'a> { + flags: Flags, + pidfd: Option<&'a mut RawFd>, + child_tid: Option<&'a mut libc::pid_t>, + parent_tid: Option<&'a mut libc::pid_t>, + exit_signal: u64, + stack: Option<&'a mut [u8]>, + tls: Option, + cgroup: Option<&'a dyn AsRawFd>, +} + +fn option_as_mut_ptr(o: &mut Option<&mut T>) -> *mut T { + match o { + Some(inner) => *inner as *mut T, + None => std::ptr::null_mut(), + } +} + +fn option_slice_as_mut_ptr(o: &mut Option<&mut [T]>) -> *mut T { + match o { + Some(inner) => inner.as_mut_ptr(), + None => std::ptr::null_mut(), + } +} + +impl<'a> Clone3<'a> { + pub fn exit_signal(&mut self, exit_signal: u64) -> &mut Self { + self.exit_signal = exit_signal; + self + } + + pub fn call(&mut self) -> Result { + let clone_args = CloneArgs { + flags: self.flags.bits(), + pid_fd: option_as_mut_ptr(&mut self.pidfd) as u64, + child_tid: option_as_mut_ptr(&mut self.child_tid) as u64, + parent_tid: option_as_mut_ptr(&mut self.parent_tid) as u64, + exit_signal: self.exit_signal, + stack: option_slice_as_mut_ptr(&mut self.stack) as u64, + stack_size: self.stack.as_ref().map(|stack| stack.len()).unwrap_or(0) as u64, + tls: self.tls.unwrap_or(0), + cgroup: self.cgroup.map(AsRawFd::as_raw_fd).unwrap_or(0) as u64, + }; + + // SAFETY: FFI call with valid arguments. + let ret = unsafe { + libc::syscall( + libc::SYS_clone3, + &clone_args as *const CloneArgs, + core::mem::size_of::(), + ) + }; + if ret == -1 { + bail!("errno {}", errno()); + } + Ok(ret as libc::pid_t) + } +} diff --git a/ozonec/src/utils/mod.rs b/ozonec/src/utils/mod.rs index 0f37aae8..69b9517d 100644 --- a/ozonec/src/utils/mod.rs +++ b/ozonec/src/utils/mod.rs @@ -11,9 +11,12 @@ // See the Mulan PSL v2 for more details. pub mod logger; +pub mod prctl; mod channel; +mod clone; mod error; pub use channel::{Channel, Message}; +pub use clone::Clone3; pub use error::OzonecErr; diff --git a/ozonec/src/utils/prctl.rs b/ozonec/src/utils/prctl.rs new file mode 100644 index 00000000..5bc05441 --- /dev/null +++ b/ozonec/src/utils/prctl.rs @@ -0,0 +1,94 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::ffi::CString; + +use anyhow::{bail, Result}; +use libc::{c_int, c_ulong, prctl}; +use nix::errno::errno; + +#[allow(non_camel_case_types)] +enum PrctlOption { + PR_SET_DUMPABLE = 4, + PR_SET_KEEPCAPS = 8, + PR_SET_NAME = 15, + PR_SET_NO_NEW_PRIVS = 38, +} + +pub fn set_dumpable(dumpable: bool) -> Result<()> { + // SAFETY: FFI call with valid arguments. + let ret = unsafe { + prctl( + PrctlOption::PR_SET_DUMPABLE as c_int, + dumpable as c_ulong, + 0, + 0, + 0, + ) + }; + if ret != 0 { + bail!("errno {}", errno()); + } + Ok(()) +} + +pub fn set_keep_capabilities(keep_capabilities: bool) -> Result<()> { + // SAFETY: FFI call with valid arguments. + let ret = unsafe { + prctl( + PrctlOption::PR_SET_KEEPCAPS as c_int, + keep_capabilities as c_ulong, + 0, + 0, + 0, + ) + }; + if ret != 0 { + bail!("errno {}", errno()); + } + Ok(()) +} + +pub fn set_no_new_privileges(new_privileges: bool) -> Result<()> { + // SAFETY: FFI call with valid arguments. + let ret = unsafe { + prctl( + PrctlOption::PR_SET_NO_NEW_PRIVS as c_int, + new_privileges as c_ulong, + 0, + 0, + 0, + ) + }; + if ret != 0 { + bail!("errno {}", errno()); + } + Ok(()) +} + +pub fn set_name(name: &str) -> Result<()> { + let binding = CString::new(name).unwrap(); + // SAFETY: FFI call with valid arguments. + let ret = unsafe { + prctl( + PrctlOption::PR_SET_NAME as c_int, + binding.as_ptr() as c_ulong, + 0, + 0, + 0, + ) + }; + if ret != 0 { + bail!("errno {}", errno()); + } + Ok(()) +} -- Gitee From 4416a04a1ddd75becdcad7e3adb5b2b8e7dcae0b Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Fri, 6 Sep 2024 05:37:16 +0800 Subject: [PATCH 378/489] ozonec/linux: Provide /dev/console in container as default OCI spec requires /dev/console as a default device when terminal is enabled. --- ozonec/src/linux/container.rs | 20 +++++++-------- ozonec/src/linux/process.rs | 15 ++++++++--- ozonec/src/linux/terminal.rs | 48 +++++++++++++++++++++++++++-------- 3 files changed, 59 insertions(+), 24 deletions(-) diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index ff818920..c53e29b0 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -14,7 +14,7 @@ use std::{ collections::HashMap, fs::{self, canonicalize, create_dir_all, OpenOptions}, io::Write, - os::unix::{io::AsRawFd, net::UnixStream}, + os::unix::net::UnixStream, path::{Path, PathBuf}, thread::sleep, time::{Duration, SystemTime}, @@ -174,14 +174,12 @@ impl LinuxContainer { .set_scheduler() .with_context(|| "Failed to set scheduler")?; - if let Some(console_socket) = &self.console_socket { - let stream = UnixStream::connect(console_socket) - .with_context(|| "Failed to connect console socket")?; - process - .set_tty(Some(stream.as_raw_fd())) - .with_context(|| "Failed to set tty")?; - } - + let console_stream = match &self.console_socket { + Some(cs) => { + Some(UnixStream::connect(cs).with_context(|| "Failed to connect console socket")?) + } + None => None, + }; self.set_rest_namespaces()?; process.set_no_new_privileges()?; @@ -221,8 +219,10 @@ impl LinuxContainer { .with_context(|| "Failed to chroot")?; } + process + .set_tty(console_stream, process.init) + .with_context(|| "Failed to set tty")?; process.set_apparmor()?; - if self.config.root.readonly { LinuxContainer::mount_rootfs_readonly()?; } diff --git a/ozonec/src/linux/process.rs b/ozonec/src/linux/process.rs index 7fac8cf7..d2f70f9b 100644 --- a/ozonec/src/linux/process.rs +++ b/ozonec/src/linux/process.rs @@ -16,7 +16,10 @@ use std::{ fs::{self, read_to_string}, io::{stderr, stdin, stdout}, mem, - os::unix::io::{AsRawFd, RawFd}, + os::unix::{ + io::{AsRawFd, RawFd}, + net::UnixStream, + }, path::PathBuf, str::FromStr, }; @@ -61,9 +64,13 @@ impl Process { p } - pub fn set_tty(&self, console_fd: Option) -> Result<()> { - if self.tty && console_fd.is_some() { - setup_console(&console_fd.unwrap()).with_context(|| "Failed to setup console")?; + pub fn set_tty(&self, console_fd: Option, mount: bool) -> Result<()> { + if self.tty { + if console_fd.is_none() { + bail!("Terminal is specified, but no console socket set"); + } + setup_console(&console_fd.unwrap().as_raw_fd(), mount) + .with_context(|| "Failed to setup console")?; } else { connect_stdio( self.stdin.as_ref().unwrap(), diff --git a/ozonec/src/linux/terminal.rs b/ozonec/src/linux/terminal.rs index 66418793..6b11702e 100644 --- a/ozonec/src/linux/terminal.rs +++ b/ozonec/src/linux/terminal.rs @@ -11,15 +11,23 @@ // See the Mulan PSL v2 for more details. use std::{ + fs::File, io::IoSlice, mem::ManuallyDrop, os::unix::io::{AsRawFd, RawFd}, + path::PathBuf, }; -use anyhow::{Context, Result}; +use anyhow::{bail, Context, Result}; use nix::{ - pty::openpty, - sys::socket::{sendmsg, ControlMessage, MsgFlags, UnixAddr}, + errno::errno, + fcntl::{open, OFlag}, + mount::MsFlags, + pty::{posix_openpt, ptsname, unlockpt}, + sys::{ + socket::{sendmsg, ControlMessage, MsgFlags, UnixAddr}, + stat::{fchmod, Mode}, + }, unistd::{close, dup2}, }; @@ -31,14 +39,12 @@ pub enum Stdio { Stderr = 2, } -pub fn setup_console(console_fd: &RawFd) -> Result<()> { - let ret = openpty(None, None).with_context(|| "openpty error")?; +pub fn setup_console(console_fd: &RawFd, mount: bool) -> Result<()> { + let master_fd = posix_openpt(OFlag::O_RDWR).with_context(|| "openpt error")?; let pty_name: &[u8] = b"/dev/ptmx"; let iov = [IoSlice::new(pty_name)]; - // Use ManuallyDrop to keep fds open. - let master = ManuallyDrop::new(ret.master); - let slave = ManuallyDrop::new(ret.slave); + let master = ManuallyDrop::new(master_fd.as_raw_fd()); let fds = [master.as_raw_fd()]; let cmsg = ControlMessage::ScmRights(&fds); sendmsg::( @@ -51,8 +57,30 @@ pub fn setup_console(console_fd: &RawFd) -> Result<()> { .with_context(|| "sendmsg error")?; // SAFETY: FFI call with valid arguments. - let slave_fd = slave.as_raw_fd(); - unsafe { libc::ioctl(slave_fd, libc::TIOCSCTTY) }; + let slave_name = unsafe { ptsname(&master_fd).with_context(|| "ptsname error")? }; + unlockpt(&master_fd).with_context(|| "unlockpt error")?; + let slave_path = PathBuf::from(&slave_name); + if mount { + let file = File::create("/dev/console").with_context(|| "Failed to create /dev/console")?; + fchmod(file.as_raw_fd(), Mode::from_bits_truncate(0o666u32)) + .with_context(|| "chmod error")?; + nix::mount::mount( + Some(&slave_path), + "/dev/console", + Some("bind"), + MsFlags::MS_BIND, + None::<&str>, + ) + .with_context(|| OzonecErr::Mount(slave_name.clone()))?; + } + + let slave_fd = open(&slave_path, OFlag::O_RDWR, Mode::empty()) + .with_context(|| OzonecErr::OpenFile(slave_name.clone()))?; + let slave = ManuallyDrop::new(slave_fd); + // SAFETY: FFI call with valid arguments. + if unsafe { libc::ioctl(slave.as_raw_fd(), libc::TIOCSCTTY) } != 0 { + bail!("TIOCSCTTY error: {}", errno()); + } connect_stdio(&slave_fd, &slave_fd, &slave_fd)?; close(console_fd.as_raw_fd()).with_context(|| "Failed to close console socket")?; Ok(()) -- Gitee From 53ba75c0056e3c239c77ad75d9e3a57a32759d5b Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Sun, 8 Sep 2024 09:35:39 +0800 Subject: [PATCH 379/489] ozonec/device: Bind devices if mknod failed --- ozonec/src/linux/container.rs | 1 + ozonec/src/linux/device.rs | 18 +++++++++++++----- ozonec/src/utils/error.rs | 2 ++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index c53e29b0..e54ee3e2 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -191,6 +191,7 @@ impl LinuxContainer { .unwrap() .rootfsPropagation .clone(); + // Container running in a user namespace is not allowed to do mknod. let mknod_device = !self.is_namespace_set(NamespaceType::User)?; let mut devices: Vec = Vec::new(); if let Some(devs) = self.config.linux.as_ref().unwrap().devices.as_ref() { diff --git a/ozonec/src/linux/device.rs b/ozonec/src/linux/device.rs index baa67ab1..90575a07 100644 --- a/ozonec/src/linux/device.rs +++ b/ozonec/src/linux/device.rs @@ -166,11 +166,14 @@ impl Device { let default_devs = self.default_devices(); for dev in default_devs { if mknod { - self.mknod_device(&dev) - .with_context(|| format!("Failed to mknod device: {}", dev.path.display()))?; + if self.mknod_device(&dev).is_err() { + self.bind_device(&dev).with_context(|| { + OzonecErr::BindDev(dev.path.to_string_lossy().to_string()) + })?; + } } else { self.bind_device(&dev) - .with_context(|| format!("Failed to bind device: {}", dev.path.display()))?; + .with_context(|| OzonecErr::BindDev(dev.path.to_string_lossy().to_string()))?; } } Ok(()) @@ -211,9 +214,14 @@ impl Device { }; if mknod { - self.mknod_device(&dev_info)?; + if self.mknod_device(&dev_info).is_err() { + self.bind_device(&dev_info).with_context(|| { + OzonecErr::BindDev(dev_info.path.to_string_lossy().to_string()) + })?; + } } else { - self.bind_device(&dev_info)?; + self.bind_device(&dev_info) + .with_context(|| OzonecErr::BindDev(dev_info.path.to_string_lossy().to_string()))?; } Ok(()) } diff --git a/ozonec/src/utils/error.rs b/ozonec/src/utils/error.rs index ffe13756..142ef9fb 100644 --- a/ozonec/src/utils/error.rs +++ b/ozonec/src/utils/error.rs @@ -42,4 +42,6 @@ pub enum OzonecErr { LoadConState, #[error("Failed to get oci state")] GetOciState, + #[error("Failed to bind device: {0}")] + BindDev(String), } -- Gitee From 198098c33ccc50a2d4b5a74b7d87b704d1a6140e Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Tue, 10 Sep 2024 11:55:44 +0800 Subject: [PATCH 380/489] ozonec/tests: Add integration tests using Bats --- ozonec/tests/create.bats | 87 +++++++++++++++++++++++++++++++++++++++ ozonec/tests/helpers.bash | 46 +++++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 ozonec/tests/create.bats create mode 100644 ozonec/tests/helpers.bash diff --git a/ozonec/tests/create.bats b/ozonec/tests/create.bats new file mode 100644 index 00000000..02d44c8b --- /dev/null +++ b/ozonec/tests/create.bats @@ -0,0 +1,87 @@ +#! /usr/bin/env bats + +load helpers + +setup_file() +{ + setup_bundle +} + +teardown_file() +{ + remove_test_dir +} + +setup() +{ + CONTAINER_ID=$(uuidgen) + ROOT_DIR="$DEFAULT_ROOT_DIR" +} + +teardown() +{ + if [ "$ROOT_DIR" == "$DEFAULT_ROOT_DIR" ]; then + ozonec kill "$CONTAINER_ID" 9 + ozonec delete "$CONTAINER_ID" + else + ozonec --root "$ROOT_DIR" kill "$CONTAINER_ID" 9 + ozonec --root "$ROOT_DIR" delete "$CONTAINER_ID" + fi +} + +@test "ozonec create" { + ozonec create "$CONTAINER_ID" 3>&- + check_container_status "$CONTAINER_ID" created "" + [ -d "$ROOT_DIR/$CONTAINER_ID" ] + [ -S "$ROOT_DIR/$CONTAINER_ID/notify.sock" ] + [ -f "$ROOT_DIR/$CONTAINER_ID/state.json" ] +} + +@test "ozonec create with absolute path of rootfs" { + local rootfs_dir="$(pwd)/rootfs" + update_config '.root.path = "'$rootfs_dir'"' + ozonec create "$CONTAINER_ID" 3>&- + check_container_status "$CONTAINER_ID" created "" +} + +@test "ozonec create with pidfile" { + ozonec create --pid-file ./pidfile "$CONTAINER_ID" 3>&- + local pid=$(cat ./pidfile) + check_container_status "$CONTAINER_ID" created "" "$pid" +} + +@test "ozonec create with duplicate id" { + ozonec create "$CONTAINER_ID" 3>&- + check_container_status "$CONTAINER_ID" created "" + ! ozonec create "$CONTAINER_ID" 3>&- +} + +@test "ozonec create with absolute bundle path" { + local bundle_dir="$(dirname `pwd`)/bundle" + ozonec create --bundle "$bundle_dir" "$CONTAINER_ID" 3>&- + check_container_status "$CONTAINER_ID" created "" +} + +@test "ozonec create with relative bundle path" { + local bundle_dir="../bundle" + ozonec create --bundle "$bundle_dir" "$CONTAINER_ID" 3>&- + check_container_status "$CONTAINER_ID" created "" +} + +@test "ozonec create with absolute root path" { + ROOT_DIR="$(dirname `pwd`)/root" + ozonec --root "$ROOT_DIR" create "$CONTAINER_ID" 3>&- + check_container_status "$CONTAINER_ID" created "$ROOT_DIR" + [ -d "$ROOT_DIR/$CONTAINER_ID" ] + [ -S "$ROOT_DIR/$CONTAINER_ID/notify.sock" ] + [ -f "$ROOT_DIR/$CONTAINER_ID/state.json" ] +} + +@test "ozonec create with relative root path" { + ROOT_DIR="../root" + ozonec --root "$ROOT_DIR" create "$CONTAINER_ID" 3>&- + check_container_status "$CONTAINER_ID" created "$ROOT_DIR" + [ -d "$ROOT_DIR/$CONTAINER_ID" ] + [ -S "$ROOT_DIR/$CONTAINER_ID/notify.sock" ] + [ -f "$ROOT_DIR/$CONTAINER_ID/state.json" ] +} \ No newline at end of file diff --git a/ozonec/tests/helpers.bash b/ozonec/tests/helpers.bash new file mode 100644 index 00000000..781fa653 --- /dev/null +++ b/ozonec/tests/helpers.bash @@ -0,0 +1,46 @@ +#! /bin/bash + +bats_require_minimum_version 1.5.0 + +DEFAULT_ROOT_DIR="/var/run/user/$(echo $UID)/ozonec" + +# Reformat config.json file with jq command. +function update_config() +{ + jq "$@" config.json | awk 'BEGIN{RS="";getline<"-";print>ARGV[1]}' config.json +} + +function setup_bundle() +{ + # Directory for each container. + TEST_DIR=$(mktemp -d "$BATS_RUN_TMPDIR/ozonec.XXXXXX") + chmod a+x "$TEST_DIR" "$BATS_RUN_TMPDIR" + + local bundle="$BATS_TEST_DIRNAME/bundle.tar.gz" + tar --exclude 'rootfs/dev/*' -C "$TEST_DIR" -xf "$bundle" + cd "$TEST_DIR/bundle" +} + +function remove_test_dir() +{ + rm -rf "$TEST_DIR" +} + +function check_container_status() { + local container_id="$1" + local state="$2" + local root="$3" + + if [ "$root" == "" ]; then + run ozonec state "$container_id" + else + run ozonec --root "$root" state "$container_id" + fi + [[ $status -eq 0 ]] + [[ "$output" == *"\"status\": \"$state\""* ]] + + if [ $# -gt 3 ]; then + local pid="$4" + [[ "$(expr match "$output" '.*"pid": \([0-9]*\).*')" == "$pid" ]] + fi +} \ No newline at end of file -- Gitee From 9d5c59e5c0e9594f768547e529895d7228f73ba4 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Tue, 10 Sep 2024 12:45:30 +0800 Subject: [PATCH 381/489] ozonec/tests: Add exec.bats --- ozonec/tests/exec.bats | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 ozonec/tests/exec.bats diff --git a/ozonec/tests/exec.bats b/ozonec/tests/exec.bats new file mode 100644 index 00000000..ffdf6c38 --- /dev/null +++ b/ozonec/tests/exec.bats @@ -0,0 +1,33 @@ +#! /usr/bin/env bats + +load helpers + +setup_file() +{ + setup_bundle + + export ROOT_DIR="$TEST_DIR/root" + export CONTAINER_ID=$(uuidgen) + + ozonec --root "$ROOT_DIR" create "$CONTAINER_ID" 3>&- + check_container_status "$CONTAINER_ID" created "$ROOT_DIR" + ozonec --root "$ROOT_DIR" start "$CONTAINER_ID" + check_container_status "$CONTAINER_ID" running "$ROOT_DIR" +} + +teardown_file() +{ + ozonec --root "$ROOT_DIR" kill "$CONTAINER_ID" 9 + ozonec --root "$ROOT_DIR" delete "$CONTAINER_ID" + remove_test_dir +} + +@test "ozonec exec" { + ozonec --root "$ROOT_DIR" exec "$CONTAINER_ID" -- ls -alh +} + +@test "ozonec exec with pidfile" { + ozonec --root "$ROOT_DIR" exec --pid-file pidfile "$CONTAINER_ID" -- ls -alh + local pid=$(cat pidfile) + [[ "$pid" -gt 0 ]] +} \ No newline at end of file -- Gitee From ed813a9456996b5a77725eea1ff08f4456686637 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Sat, 31 Aug 2024 14:34:54 +0800 Subject: [PATCH 382/489] ozonec/container: Veryify current directory inside mount space rootfs If current working directory is outside mount space rootfs of the container process, getcwd() would fail. Fix CVE-2024-21626 --- ozonec/src/linux/container.rs | 3 +++ ozonec/src/linux/process.rs | 13 ++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index e54ee3e2..a980fc08 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -249,6 +249,9 @@ impl LinuxContainer { if chdir_cwd_ret { process.chdir_cwd()?; } + // Ensure that the current working directory is inside the mount namespace root + // of the current container process. + Process::getcwd()?; process.clean_envs(); process.set_envs(); if process.no_new_privileges() { diff --git a/ozonec/src/linux/process.rs b/ozonec/src/linux/process.rs index d2f70f9b..ae3add0d 100644 --- a/ozonec/src/linux/process.rs +++ b/ozonec/src/linux/process.rs @@ -26,7 +26,10 @@ use std::{ use anyhow::{anyhow, bail, Context, Result}; use caps::{self, CapSet, Capability, CapsHashSet}; -use nix::unistd::{self, chdir, setresgid, setresuid, Gid, Pid, Uid}; +use nix::{ + errno::Errno, + unistd::{self, chdir, setresgid, setresuid, Gid, Pid, Uid}, +}; use rlimit::{setrlimit, Resource, Rlim}; use super::{ @@ -310,6 +313,14 @@ impl Process { unreachable!() } + + pub fn getcwd() -> Result<()> { + unistd::getcwd().map_err(|e| match e { + Errno::ENOENT => anyhow!("Current working directory is out of container rootfs"), + _ => anyhow!("Failed to getcwd"), + })?; + Ok(()) + } } // Clone a new child process. -- Gitee From f19ef644a5f2e08a74cc16b98b48cfb7c775740b Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Sat, 31 Aug 2024 19:34:16 +0800 Subject: [PATCH 383/489] ozonec/rootfs: Close fds when opening root directory Fix commit 818da30 (ozonec/linux: Add rootfs.rs) --- ozonec/src/linux/rootfs.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/ozonec/src/linux/rootfs.rs b/ozonec/src/linux/rootfs.rs index ac67d325..a58d9e6b 100644 --- a/ozonec/src/linux/rootfs.rs +++ b/ozonec/src/linux/rootfs.rs @@ -21,7 +21,7 @@ use nix::{ fcntl::{open, OFlag}, mount::{umount2, MntFlags, MsFlags}, sys::stat::{umask, Mode}, - unistd::{chroot, fchdir, pivot_root}, + unistd::{chroot, close, fchdir, pivot_root}, NixPath, }; use procfs::process::Process; @@ -226,6 +226,9 @@ impl Rootfs { umount2(".", MntFlags::MNT_DETACH) .with_context(|| "Failed to umount old root directory")?; fchdir(new_root).with_context(|| "Failed to chdir to new root directory")?; + + close(old_root).with_context(|| "Failed to close old_root")?; + close(new_root).with_context(|| "Failed to close new_root")?; Ok(()) } } -- Gitee From cd9a802b550418d70e59ad5c43c973a0c128651a Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Tue, 17 Sep 2024 09:06:31 +0800 Subject: [PATCH 384/489] ozonec/tests: Add README.md --- ozonec/tests/README.md | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 ozonec/tests/README.md diff --git a/ozonec/tests/README.md b/ozonec/tests/README.md new file mode 100644 index 00000000..c33982d5 --- /dev/null +++ b/ozonec/tests/README.md @@ -0,0 +1,30 @@ +# Integration Tests + +ozonec uses [bats (Bash Automated Testing System)](https://github.com/bats-core/bats-core) framework to run +integration tests written in *bash*. + +## Before running tests + +Install [bats (Bash Automated Testing System)](https://github.com/bats-core/bats-core#installing-bats-from-source) from source: +``` +$ git clone https://github.com/bats-core/bats-core.git +$ cd bats-core +$ ./install.sh /usr/local +``` + +And *jq* is may also needed to modify json file in tests. + +## Running tests + +You can run tests using bats directly. For example: +``` +bats ./ +``` +Or you can just run a single test file. For example: +``` +bats create.bats +``` + +## Writing tests + +Please refer to [bats (Writing tests)](https://bats-core.readthedocs.io/en/stable/writing-tests.html). \ No newline at end of file -- Gitee From 7f598fd0eca1c800b9ae623527e906104eee1e03 Mon Sep 17 00:00:00 2001 From: zhanghan Date: Tue, 24 Sep 2024 15:10:46 +0800 Subject: [PATCH 385/489] ohcam:fix trace features Missing features are essential to trace ohcam, so add them. Signed-off-by: zhanghan --- Cargo.toml | 6 +++--- devices/Cargo.toml | 3 +++ machine/Cargo.toml | 3 +++ 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index bf79c900..4c78415f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -40,9 +40,9 @@ vnc_auth = ["machine/vnc_auth"] ohui_srv = ["machine/ohui_srv"] ramfb = ["machine/ramfb"] virtio_gpu = ["machine/virtio_gpu"] -trace_to_logger = ["trace/trace_to_logger"] -trace_to_ftrace = ["trace/trace_to_ftrace"] -trace_to_hitrace = ["trace/trace_to_hitrace"] +trace_to_logger = ["trace/trace_to_logger", "machine/trace_to_logger"] +trace_to_ftrace = ["trace/trace_to_ftrace", "machine/trace_to_ftrace"] +trace_to_hitrace = ["trace/trace_to_hitrace", "machine/trace_to_hitrace"] hisysevent = ["hisysevent/hisysevent"] vfio = ["machine/vfio_device"] usb_uas = ["machine/usb_uas"] diff --git a/devices/Cargo.toml b/devices/Cargo.toml index 932a0cdd..3dca2b41 100644 --- a/devices/Cargo.toml +++ b/devices/Cargo.toml @@ -54,3 +54,6 @@ usb_camera_v4l2 = ["usb_camera", "dep:v4l2-sys-mit", "machine_manager/usb_camera usb_camera_oh = ["usb_camera", "machine_manager/usb_camera_oh", "util/usb_camera_oh"] ramfb = ["ui/console", "util/pixman"] usb_uas = [] +trace_to_logger = [] +trace_to_ftrace = [] +trace_to_hitrace = [] diff --git a/machine/Cargo.toml b/machine/Cargo.toml index 2c8a22b6..ecead47e 100644 --- a/machine/Cargo.toml +++ b/machine/Cargo.toml @@ -58,3 +58,6 @@ vhost_vsock = ["virtio/vhost_vsock"] vhostuser_block = ["virtio/vhostuser_block"] vhostuser_net = ["virtio/vhostuser_net"] vhost_net = ["virtio/vhost_net"] +trace_to_logger = ["devices/trace_to_logger"] +trace_to_ftrace = ["devices/trace_to_ftrace"] +trace_to_hitrace = ["devices/trace_to_hitrace"] -- Gitee From 6b89ad6c7ecc21325a9cebc85dba422a73ed63d1 Mon Sep 17 00:00:00 2001 From: zhanghan Date: Thu, 5 Sep 2024 16:58:02 +0800 Subject: [PATCH 386/489] ohcam: fix Box type's default declaration RUST thinks Box::::default() is better than Box::new(T::default()). So we use former format for declaration. Signed-off-by: zhanghan --- devices/src/camera_backend/ohcam.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devices/src/camera_backend/ohcam.rs b/devices/src/camera_backend/ohcam.rs index 3527048c..260dcf7d 100755 --- a/devices/src/camera_backend/ohcam.rs +++ b/devices/src/camera_backend/ohcam.rs @@ -178,7 +178,7 @@ impl OhCameraBackend { feature = "trace_to_ftrace", all(target_env = "ohos", feature = "trace_to_hitrace") ))] - async_scope: Box::new(OhCameraAsyncScope::default()), + async_scope: Box::::default(), tokenid, }) } -- Gitee From 29156585fb1b6a6b386504be420b44f8c1c41850 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sun, 8 Sep 2024 00:59:03 +0800 Subject: [PATCH 387/489] xhci: fix potential left shift overflow Fix potential left shift overflow in `addr64_from_u32`. Signed-off-by: liuxiangdong --- devices/src/usb/xhci/xhci_controller.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index 8eca4640..5ac00313 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -2519,7 +2519,7 @@ pub fn dma_write_u32( } fn addr64_from_u32(low: u32, high: u32) -> u64 { - (u64::from(high << 16) << 16) | u64::from(low) + (u64::from(high) << 32) | u64::from(low) } // | ep id | < = > | ep direction | ep number | -- Gitee From a7028e90e14075bccc0f2aebe707a4ac0cf14409 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Sun, 8 Sep 2024 02:16:36 +0800 Subject: [PATCH 388/489] time: use i64 to represent the return value of `gettime` `struct timespace` is defined in `time` as: pub struct timespec { pub tv_sec: time_t, #[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] pub tv_nsec: i64, #[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] pub tv_nsec: ::c_long, } So, we should not truncate i64 value to u32 in the public function `gettime`. Fix it. Signed-off-by: liuxiangdong --- block_backend/src/qcow2/mod.rs | 15 +++++++++++++-- util/src/logger.rs | 4 ++-- util/src/time.rs | 4 ++-- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/block_backend/src/qcow2/mod.rs b/block_backend/src/qcow2/mod.rs index 151b9255..30c72b60 100644 --- a/block_backend/src/qcow2/mod.rs +++ b/block_backend/src/qcow2/mod.rs @@ -1013,6 +1013,17 @@ impl Qcow2Driver { // Alloc new snapshot table. let (date_sec, date_nsec) = gettime()?; + // Note: The `Snapshots` chapter in Qcow2 spec states: + // Snapshot table entry: + // Byte 16 - 19: Time at which the snapshot was taken in seconds since the + // Epoch + // Byte 20 - 23: Subsecond part of the time at which the snapshot was taken + // in nanoseconds + // + // 32 bits of seconds can represent a range of approximately 136 years since 1970. + // It's enough for current use. If an incorrect host time is used to inject error, + // there may be an issue of inaccurate creation time in the snapshot description. + // Considering compatibility, this issue of inaccurate time is acceptable. let snap = QcowSnapshot { l1_table_offset: new_l1_table_offset, l1_size: self.header.l1_size, @@ -1020,8 +1031,8 @@ impl Qcow2Driver { name, disk_size: self.virtual_disk_size(), vm_state_size: 0, - date_sec, - date_nsec, + date_sec: date_sec as u32, + date_nsec: date_nsec as u32, vm_clock_nsec, icount: u64::MAX, extra_data_size: size_of::() as u32, diff --git a/util/src/logger.rs b/util/src/logger.rs index 0f8634bb..de35d83f 100644 --- a/util/src/logger.rs +++ b/util/src/logger.rs @@ -34,7 +34,7 @@ fn format_now() -> String { println!("{:?}", e); (0, 0) }); - let format_time = get_format_time(i64::from(sec)); + let format_time = get_format_time(sec); format!( "{:04}-{:02}-{:02}T{:02}:{:02}:{:02}.{:09}", @@ -63,7 +63,7 @@ impl FileRotate { self.current_size += Wrapping(size_inc); let sec = gettime()?.0; - let today = get_format_time(i64::from(sec))[2]; + let today = get_format_time(sec)[2]; if self.current_size < Wrapping(LOG_ROTATE_SIZE_MAX) && self.create_day == today { return Ok(()); } diff --git a/util/src/time.rs b/util/src/time.rs index 44950661..ed9f4f33 100644 --- a/util/src/time.rs +++ b/util/src/time.rs @@ -33,9 +33,9 @@ pub fn mktime64(year: u64, mon: u64, day: u64, hour: u64, min: u64, sec: u64) -> } /// Get wall time. -pub fn gettime() -> Result<(u32, u32)> { +pub fn gettime() -> Result<(i64, i64)> { match clock_gettime(ClockId::CLOCK_REALTIME) { - Ok(ts) => Ok((ts.tv_sec() as u32, ts.tv_nsec() as u32)), + Ok(ts) => Ok((ts.tv_sec(), ts.tv_nsec())), Err(e) => bail!("clock_gettime failed: {:?}", e), } } -- Gitee From fea1472c85ed1700b5e66cebac33c0216c092a73 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Wed, 11 Sep 2024 22:38:59 +0800 Subject: [PATCH 389/489] xhci: change type of `dequeue` in `struct XhciStreamContext` to `GuestAddress` Change type of `dequeue` in `struct XhciStreamContext` to `GuestAddress`. Signed-off-by: liuxiangdong --- devices/src/usb/xhci/xhci_controller.rs | 20 ++++++-------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index 5ac00313..32705f4b 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -434,14 +434,10 @@ impl XhciEpContext { let locked_stream = stream.lock().unwrap(); let output_addr = locked_stream.dequeue; let ring = locked_stream.ring.as_ref(); - dma_read_u32( - &self.mem, - GuestAddress(output_addr), - stream_ctx.as_mut_dwords(), - )?; + dma_read_u32(&self.mem, output_addr, stream_ctx.as_mut_dwords())?; ring.update_dequeue_to_ctx(stream_ctx.as_mut_dwords()); ring.update_dequeue_to_ctx(&mut ep_ctx.as_mut_dwords()[2..]); - dma_write_u32(&self.mem, GuestAddress(output_addr), stream_ctx.as_dwords())?; + dma_write_u32(&self.mem, output_addr, stream_ctx.as_dwords())?; } dma_write_u32(&self.mem, GuestAddress(output_addr), ep_ctx.as_dwords())?; @@ -866,7 +862,7 @@ pub struct XhciStreamContext { /// Memory address space. mem: Arc, /// Dequeue pointer. - dequeue: u64, + dequeue: GuestAddress, /// Transfer Ring (no Secondary Streams for now). ring: Arc, /// Whether the context is up to date after reset. @@ -877,14 +873,14 @@ impl XhciStreamContext { fn new(mem: &Arc) -> Self { Self { mem: Arc::clone(mem), - dequeue: 0, + dequeue: GuestAddress(0), ring: Arc::new(XhciTransferRing::new(mem)), needs_refresh: true, } } fn init(&mut self, addr: u64) -> Result<()> { - self.dequeue = addr; + self.dequeue = GuestAddress(addr); self.refresh()?; Ok(()) } @@ -899,11 +895,7 @@ impl XhciStreamContext { fn refresh(&mut self) -> Result<()> { let mut stream_ctx = XhciStreamCtx::default(); - dma_read_u32( - &self.mem, - GuestAddress(self.dequeue), - stream_ctx.as_mut_dwords(), - )?; + dma_read_u32(&self.mem, self.dequeue, stream_ctx.as_mut_dwords())?; let dequeue = addr64_from_u32(stream_ctx.deq_lo & !0xf, stream_ctx.deq_hi); self.ring.init(dequeue); self.needs_refresh = false; -- Gitee From f2c06da41463a079b6e4aa71ff175e3f0aa1bbe6 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 12 Sep 2024 04:29:10 +0800 Subject: [PATCH 390/489] xhci: change type of `slot_ctx_addr` in `struct XhciSlot` to `GuestAddress` Change type of `slot_ctx_addr` in `struct XhciSlot` to `GuestAddress`. Signed-off-by: liuxiangdong --- devices/src/usb/xhci/xhci_controller.rs | 61 +++++++++---------------- 1 file changed, 22 insertions(+), 39 deletions(-) diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index 32705f4b..a49574a8 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -555,7 +555,7 @@ impl From for EpType { pub struct XhciSlot { pub enabled: bool, pub addressed: bool, - pub slot_ctx_addr: u64, + pub slot_ctx_addr: GuestAddress, pub usb_port: Option>>, pub endpoints: Vec, } @@ -570,7 +570,7 @@ impl XhciSlot { XhciSlot { enabled: false, addressed: false, - slot_ctx_addr: 0, + slot_ctx_addr: GuestAddress(0), usb_port: None, endpoints: eps, } @@ -579,18 +579,14 @@ impl XhciSlot { /// Get the slot context from the memory. fn get_slot_ctx(&self, mem: &Arc) -> Result { let mut slot_ctx = XhciSlotCtx::default(); - dma_read_u32( - mem, - GuestAddress(self.slot_ctx_addr), - slot_ctx.as_mut_dwords(), - )?; + dma_read_u32(mem, self.slot_ctx_addr, slot_ctx.as_mut_dwords())?; Ok(slot_ctx) } /// Get the slot state in slot context. fn get_slot_state_in_context(&self, mem: &Arc) -> Result { // Table 4-1: Device Slot State Code Definitions. - if self.slot_ctx_addr == 0 { + if self.slot_ctx_addr == GuestAddress(0) { return Ok(SLOT_DISABLED_ENABLED); } let slot_ctx = self.get_slot_ctx(mem)?; @@ -1315,7 +1311,7 @@ impl XhciDevice { self.slots[(slot_id - 1) as usize].enabled = false; self.slots[(slot_id - 1) as usize].addressed = false; self.slots[(slot_id - 1) as usize].usb_port = None; - self.slots[(slot_id - 1) as usize].slot_ctx_addr = 0; + self.slots[(slot_id - 1) as usize].slot_ctx_addr = GuestAddress(0); Ok(TRBCCode::Success) } @@ -1382,7 +1378,7 @@ impl XhciDevice { let mut locked_port = usb_port.lock().unwrap(); locked_port.slot_id = slot_id; self.slots[(slot_id - 1) as usize].usb_port = Some(usb_port.clone()); - self.slots[(slot_id - 1) as usize].slot_ctx_addr = octx; + self.slots[(slot_id - 1) as usize].slot_ctx_addr = GuestAddress(octx); let dev = locked_port.dev.as_ref().unwrap(); dev.lock().unwrap().reset(); if bsr { @@ -1484,7 +1480,7 @@ impl XhciDevice { slot_ctx.set_slot_state(SLOT_ADDRESSED); dma_write_u32( &self.mem_space, - GuestAddress(self.slots[(slot_id - 1) as usize].slot_ctx_addr), + self.slots[(slot_id - 1) as usize].slot_ctx_addr, slot_ctx.as_dwords(), )?; Ok(TRBCCode::Success) @@ -1514,7 +1510,7 @@ impl XhciDevice { } if ictl_ctx.add_flags & (1 << i) == 1 << i { self.disable_endpoint(slot_id, i)?; - self.enable_endpoint(slot_id, i, ictx, octx)?; + self.enable_endpoint(slot_id, i, ictx, octx.raw_value())?; } } // From section 4.6.6 Configure Endpoint of the spec: @@ -1539,7 +1535,7 @@ impl XhciDevice { slot_ctx.set_slot_state(SLOT_CONFIGURED); slot_ctx.set_context_entry(enabled_ep_idx); } - dma_write_u32(&self.mem_space, GuestAddress(octx), slot_ctx.as_dwords())?; + dma_write_u32(&self.mem_space, octx, slot_ctx.as_dwords())?; Ok(TRBCCode::Success) } @@ -1578,14 +1574,10 @@ impl XhciDevice { islot_ctx.as_mut_dwords(), )?; let mut slot_ctx = XhciSlotCtx::default(); - dma_read_u32( - &self.mem_space, - GuestAddress(octx), - slot_ctx.as_mut_dwords(), - )?; + dma_read_u32(&self.mem_space, octx, slot_ctx.as_mut_dwords())?; slot_ctx.set_max_exit_latency(islot_ctx.get_max_exit_latency()); slot_ctx.set_interrupter_target(islot_ctx.get_interrupter_target()); - dma_write_u32(&self.mem_space, GuestAddress(octx), slot_ctx.as_dwords())?; + dma_write_u32(&self.mem_space, octx, slot_ctx.as_dwords())?; } if ictl_ctx.add_flags & 0x2 == 0x2 { // Default control endpoint context. @@ -1599,21 +1591,16 @@ impl XhciDevice { iep_ctx.as_mut_dwords(), )?; let mut ep_ctx = XhciEpCtx::default(); - dma_read_u32( - &self.mem_space, - GuestAddress( - // It is safe to use plus here because we previously verify the address. - octx + EP_CTX_OFFSET, - ), - ep_ctx.as_mut_dwords(), - )?; + let ep_ctx_addr = octx.checked_add(EP_CTX_OFFSET).with_context(|| { + format!( + "Endpoint Context access overflow, addr {:x} size {:x}", + octx.raw_value(), + EP_CTX_OFFSET + ) + })?; + dma_read_u32(&self.mem_space, ep_ctx_addr, ep_ctx.as_mut_dwords())?; ep_ctx.set_max_packet_size(iep_ctx.get_max_packet_size()); - dma_write_u32( - &self.mem_space, - // It is safe to use plus here because we previously verify the address. - GuestAddress(octx + EP_CTX_OFFSET), - ep_ctx.as_dwords(), - )?; + dma_write_u32(&self.mem_space, ep_ctx_addr, ep_ctx.as_dwords())?; } Ok(TRBCCode::Success) } @@ -1622,11 +1609,7 @@ impl XhciDevice { trace::usb_xhci_reset_device(&slot_id); let mut slot_ctx = XhciSlotCtx::default(); let octx = self.slots[(slot_id - 1) as usize].slot_ctx_addr; - dma_read_u32( - &self.mem_space, - GuestAddress(octx), - slot_ctx.as_mut_dwords(), - )?; + dma_read_u32(&self.mem_space, octx, slot_ctx.as_mut_dwords())?; let slot_state = (slot_ctx.dev_state >> SLOT_STATE_SHIFT) & SLOT_STATE_MASK; if slot_state != SLOT_ADDRESSED && slot_state != SLOT_CONFIGURED @@ -1641,7 +1624,7 @@ impl XhciDevice { slot_ctx.set_slot_state(SLOT_DEFAULT); slot_ctx.set_context_entry(1); slot_ctx.set_usb_device_address(0); - dma_write_u32(&self.mem_space, GuestAddress(octx), slot_ctx.as_dwords())?; + dma_write_u32(&self.mem_space, octx, slot_ctx.as_dwords())?; Ok(TRBCCode::Success) } -- Gitee From 14602a7f011fd45dd4d62cdce43ed3906b2e7de0 Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 12 Sep 2024 04:59:39 +0800 Subject: [PATCH 391/489] xhci: change type of `output_ctx_addr` in `struct XhciEpContext` to `GuestAddress` Change type of `output_ctx_addr` in `struct XhciEpContext` to `GuestAddress`. Signed-off-by: liuxiangdong --- devices/src/usb/xhci/xhci_controller.rs | 23 ++++++++++++----------- devices/src/usb/xhci/xhci_ring.rs | 10 +++------- 2 files changed, 15 insertions(+), 18 deletions(-) diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index a49574a8..14cd1351 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -13,7 +13,7 @@ use std::collections::LinkedList; use std::mem::size_of; use std::slice::{from_raw_parts, from_raw_parts_mut}; -use std::sync::atomic::{AtomicU32, AtomicU64, Ordering}; +use std::sync::atomic::{AtomicU32, Ordering}; use std::sync::{Arc, Mutex, Weak}; use std::time::Duration; @@ -191,7 +191,7 @@ impl XhciTransfer { self.epid, self.slotid, self.streamid ) })?; - ring.refresh_dequeue_ptr(self.ep_context.output_ctx_addr.load(Ordering::Acquire))?; + ring.refresh_dequeue_ptr(*self.ep_context.output_ctx_addr.lock().unwrap())?; return Ok(()); } @@ -320,7 +320,7 @@ pub struct XhciEpContext { enabled: bool, ring: Option>, ep_type: EpType, - output_ctx_addr: Arc, + output_ctx_addr: Arc>, state: Arc, interval: u32, mfindex_last: u64, @@ -339,7 +339,7 @@ impl XhciEpContext { enabled: false, ring: None, ep_type: EpType::Invalid, - output_ctx_addr: Arc::new(AtomicU64::new(0)), + output_ctx_addr: Arc::new(Mutex::new(GuestAddress(0))), state: Arc::new(AtomicU32::new(0)), interval: 0, mfindex_last: 0, @@ -356,7 +356,7 @@ impl XhciEpContext { fn init_ctx(&mut self, output_ctx: DmaAddr, ctx: &XhciEpCtx) -> Result<()> { let dequeue: DmaAddr = addr64_from_u32(ctx.deq_lo & !0xf, ctx.deq_hi); self.ep_type = ((ctx.ep_info2 >> EP_TYPE_SHIFT) & EP_TYPE_MASK).into(); - self.output_ctx_addr.store(output_ctx, Ordering::SeqCst); + *self.output_ctx_addr.lock().unwrap() = GuestAddress(output_ctx); self.max_pstreams = (ctx.ep_info >> EP_CTX_MAX_PSTREAMS_SHIFT) & EP_CTX_MAX_PSTREAMS_MASK; self.lsa = ((ctx.ep_info >> EP_CTX_LSA_SHIFT) & EP_CTX_LSA_MASK) != 0; self.interval = 1 << ((ctx.ep_info >> EP_CTX_INTERVAL_SHIFT) & EP_CTX_INTERVAL_MASK); @@ -388,11 +388,12 @@ impl XhciEpContext { /// Update the endpoint state and write the state to memory. fn set_state(&self, state: u32, stream_id: Option) -> Result<()> { let mut ep_ctx = XhciEpCtx::default(); - let output_addr = self.output_ctx_addr.load(Ordering::Acquire); - dma_read_u32(&self.mem, GuestAddress(output_addr), ep_ctx.as_mut_dwords())?; + let output_addr = self.output_ctx_addr.lock().unwrap(); + dma_read_u32(&self.mem, *output_addr, ep_ctx.as_mut_dwords())?; ep_ctx.ep_info &= !EP_STATE_MASK; ep_ctx.ep_info |= state; - dma_write_u32(&self.mem, GuestAddress(output_addr), ep_ctx.as_dwords())?; + dma_write_u32(&self.mem, *output_addr, ep_ctx.as_dwords())?; + drop(output_addr); self.flush_dequeue_to_memory(stream_id)?; self.set_ep_state(state); trace::usb_xhci_set_state(self.epid, state); @@ -422,8 +423,8 @@ impl XhciEpContext { /// Stream Endpoints flush ring dequeue to both Endpoint and Stream context. fn flush_dequeue_to_memory(&self, stream_id: Option) -> Result<()> { let mut ep_ctx = XhciEpCtx::default(); - let output_addr = self.output_ctx_addr.load(Ordering::Acquire); - dma_read_u32(&self.mem, GuestAddress(output_addr), ep_ctx.as_mut_dwords())?; + let output_addr = self.output_ctx_addr.lock().unwrap(); + dma_read_u32(&self.mem, *output_addr, ep_ctx.as_mut_dwords())?; if self.max_pstreams == 0 { let ring = self.get_ring(0)?; @@ -440,7 +441,7 @@ impl XhciEpContext { dma_write_u32(&self.mem, output_addr, stream_ctx.as_dwords())?; } - dma_write_u32(&self.mem, GuestAddress(output_addr), ep_ctx.as_dwords())?; + dma_write_u32(&self.mem, *output_addr, ep_ctx.as_dwords())?; Ok(()) } diff --git a/devices/src/usb/xhci/xhci_ring.rs b/devices/src/usb/xhci/xhci_ring.rs index b7a5df43..35cda571 100644 --- a/devices/src/usb/xhci/xhci_ring.rs +++ b/devices/src/usb/xhci/xhci_ring.rs @@ -206,15 +206,11 @@ impl XhciTransferRing { } /// Refresh dequeue pointer to output context. - pub fn refresh_dequeue_ptr(&self, output_ctx_addr: u64) -> Result<()> { + pub fn refresh_dequeue_ptr(&self, output_ctx_addr: GuestAddress) -> Result<()> { let mut ep_ctx = XhciEpCtx::default(); - dma_read_u32( - &self.mem, - GuestAddress(output_ctx_addr), - ep_ctx.as_mut_dwords(), - )?; + dma_read_u32(&self.mem, output_ctx_addr, ep_ctx.as_mut_dwords())?; self.update_dequeue_to_ctx(&mut ep_ctx.as_mut_dwords()[2..]); - dma_write_u32(&self.mem, GuestAddress(output_ctx_addr), ep_ctx.as_dwords())?; + dma_write_u32(&self.mem, output_ctx_addr, ep_ctx.as_dwords())?; Ok(()) } -- Gitee From df6710c84d148a4574ab038ebf939d514d3cd712 Mon Sep 17 00:00:00 2001 From: zhanghan64 Date: Mon, 2 Sep 2024 17:40:54 +0800 Subject: [PATCH 392/489] ohui: fix integer calculation issues Use suitable calculation methods. Signed-off-by: zhanghan64 --- ui/src/ohui_srv/mod.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ui/src/ohui_srv/mod.rs b/ui/src/ohui_srv/mod.rs index 45a51a8e..92e22ea8 100755 --- a/ui/src/ohui_srv/mod.rs +++ b/ui/src/ohui_srv/mod.rs @@ -14,7 +14,6 @@ pub mod channel; pub mod msg; pub mod msg_handle; -use std::mem::size_of; use std::os::unix::io::RawFd; use std::path::Path; use std::ptr; @@ -24,7 +23,7 @@ use std::sync::{ Arc, Mutex, RwLock, }; -use anyhow::{anyhow, bail, Result}; +use anyhow::{anyhow, bail, Context, Result}; use log::{error, info}; use once_cell::sync::OnceCell; use vmm_sys_util::epoll::EventSet; @@ -384,7 +383,12 @@ impl DisplayChangeListenerOperations for OhUiServer { return Ok(()); } - let len = cursor.width * cursor.height * size_of::() as u32; + let len = cursor + .width + .checked_mul(cursor.height) + .with_context(|| "Invalid cursor width * height")? + .checked_mul(bytes_per_pixel() as u32) + .with_context(|| "Invalid cursor size")?; if len > CURSOR_SIZE as u32 || len > cursor.data.len().try_into()? { error!("Too large cursor length {}.", len); // No need to return Err for this situation is not fatal @@ -405,7 +409,7 @@ impl DisplayChangeListenerOperations for OhUiServer { cursor.height, cursor.hot_x, cursor.hot_y, - size_of::() as u32, + bytes_per_pixel() as u32, ); Ok(()) } -- Gitee From e43ba85fdf0490e6a9941695f1c0e872fa5558d5 Mon Sep 17 00:00:00 2001 From: zhanghan64 Date: Mon, 2 Sep 2024 17:44:27 +0800 Subject: [PATCH 393/489] ohaudio: fix integer calculation issues Signed-off-by: zhanghan64 --- devices/src/misc/scream/mod.rs | 45 +++++++++++++++++------------- devices/src/misc/scream/ohaudio.rs | 4 +++ 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index 806f00bf..5272553a 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -155,11 +155,12 @@ impl ShmemStreamHeader { if self.chunk_idx > self.max_chunks { error!( - "The chunk index of stream {} exceeds the maximum number of chunks {}", - self.chunk_idx, self.max_chunks + "Invalid max_chunks: {} or chunk_idx: {}", + self.max_chunks, self.chunk_idx ); return false; } + if self.fmt.channels == 0 || self.fmt.channel_map == 0 { error!( "The fmt channels {} or channel_map {} is invalid", @@ -274,7 +275,12 @@ impl ScreamCond { #[derive(Debug, Default)] pub struct StreamData { pub fmt: ShmemStreamFmt, + max_chunks: u16, chunk_idx: u16, + /// Start address of header implies. + start_addr: u64, + /// Length of total data which header implies. + data_shm_len: u64, /// Size of the data to be played or recorded. pub audio_size: u32, /// Location of the played or recorded audio data in the shared memory. @@ -284,10 +290,14 @@ pub struct StreamData { } impl StreamData { - fn init(&mut self, header: &ShmemStreamHeader) { + fn init(&mut self, header: &ShmemStreamHeader, hva: u64) { fence(Ordering::Acquire); self.fmt = header.fmt; self.chunk_idx = header.chunk_idx; + self.max_chunks = header.max_chunks; + self.data_shm_len = u64::from(header.chunk_size) * u64::from(self.max_chunks); + self.start_addr = hva + u64::from(header.offset); + self.audio_size = header.chunk_size; } fn register_pause_notifier(&mut self, cond: Arc) { @@ -328,7 +338,7 @@ impl StreamData { header = // SAFETY: hva is allocated by libc:::mmap, it can be guaranteed to be legal. &unsafe { std::slice::from_raw_parts(hva as *const ShmemHeader, 1) }[0]; - self.init(stream_header); + self.init(stream_header, hva); let mut last_end = 0_u64; // The recording buffer is behind the playback buffer. Thereforce, the end position of @@ -355,18 +365,14 @@ impl StreamData { shmem_size: u64, stream_header: &ShmemStreamHeader, ) -> bool { - self.audio_size = stream_header.chunk_size; - self.audio_base = hva - + u64::from(stream_header.offset) - + u64::from(stream_header.chunk_size) * u64::from(self.chunk_idx); - - if (self.audio_base + u64::from(self.audio_size)) > (hva + shmem_size) { + self.audio_base = self + .start_addr + .saturating_add(u64::from(self.audio_size) * u64::from(self.chunk_idx)); + let buf_end = hva + shmem_size; + if self.audio_base.saturating_add(u64::from(self.audio_size)) > buf_end { error!( "Scream: wrong header: offset {} chunk_idx {} chunk_size {} max_chunks {}", - stream_header.offset, - stream_header.chunk_idx, - stream_header.chunk_size, - stream_header.max_chunks, + stream_header.offset, stream_header.chunk_idx, self.audio_size, self.max_chunks, ); return false; } @@ -400,15 +406,15 @@ impl StreamData { // slow and the backward data is skipped. if play .chunk_idx - .wrapping_add(play.max_chunks) + .wrapping_add(self.max_chunks) .wrapping_sub(self.chunk_idx) - % play.max_chunks + % self.max_chunks > 4 { self.chunk_idx = - play.chunk_idx.wrapping_add(play.max_chunks).wrapping_sub(1) % play.max_chunks; + play.chunk_idx.wrapping_add(self.max_chunks).wrapping_sub(1) % self.max_chunks; } else { - self.chunk_idx = (self.chunk_idx + 1) % play.max_chunks; + self.chunk_idx = (self.chunk_idx + 1) % self.max_chunks; } if !self.update_buffer_by_chunk_idx(hva, shmem_size, play) { @@ -429,9 +435,8 @@ impl StreamData { // of the address range during the header check. let header = &mut unsafe { std::slice::from_raw_parts_mut(hva as *mut ShmemHeader, 1) }[0]; let capt = &mut header.capt; - let addr = hva + u64::from(capt.offset); - interface.lock().unwrap().pre_receive(addr, capt); + interface.lock().unwrap().pre_receive(self.start_addr, capt); while capt.is_started != 0 { cond.wait_if_paused(interface.clone()); diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index 752e4d29..8040ea88 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -454,6 +454,10 @@ extern "C" fn on_read_data_cb( break; } } + if capture.align == 0 { + error!("on_read_data_cb, capture.align is 0"); + return 0; + } let old_pos = capture.cur_pos - ((capture.cur_pos - capture.shm_addr) % u64::from(capture.align)); let buf_end = capture.shm_addr + capture.shm_len; -- Gitee From eccb2e6c67e8f975ebdd8822a5d65d003a3d78fc Mon Sep 17 00:00:00 2001 From: zhanghan64 Date: Mon, 2 Sep 2024 17:45:05 +0800 Subject: [PATCH 394/489] ohcamera: fix integer calculation issues Signed-off-by: zhanghan64 --- devices/src/camera_backend/ohcam.rs | 9 ++++----- devices/src/usb/camera.rs | 26 ++++++++++++++++++++++---- util/src/ohos_binding/camera.rs | 3 +++ 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/devices/src/camera_backend/ohcam.rs b/devices/src/camera_backend/ohcam.rs index 260dcf7d..075f1c17 100755 --- a/devices/src/camera_backend/ohcam.rs +++ b/devices/src/camera_backend/ohcam.rs @@ -260,7 +260,10 @@ impl CameraBackend for OhCameraBackend { fmt_list.push(CameraFormatList { format: cam_fmt_from_oh(fmt)?, frame: vec![frame], - fmt_index: (idx) + 1, + fmt_index: idx.checked_add(1).unwrap_or_else(|| { + error!("list_format: too much profile ID"); + u8::MAX + }), }); } Err(e) => error!("{:?}", e), @@ -354,10 +357,6 @@ impl CameraBackend for OhCameraBackend { bail!("Invalid frame src_len {}", src_len); } - if frame_offset + len > src_len as usize { - bail!("Invalid frame offset {} or len {}", frame_offset, len); - } - trace::trace_scope_start!(ohcam_get_frame, args = (frame_offset, len)); let mut copied = 0_usize; diff --git a/devices/src/usb/camera.rs b/devices/src/usb/camera.rs index 159a33ca..e05f89b9 100644 --- a/devices/src/usb/camera.rs +++ b/devices/src/usb/camera.rs @@ -886,7 +886,12 @@ impl UvcPayload { let mut frame_data_size = iov_size; let header_len = self.header.len(); // Within the scope of the frame. - if self.frame_offset + frame_data_size as usize >= current_frame_size { + if self + .frame_offset + .checked_add(frame_data_size as usize) + .with_context(|| "get_frame_data_size: invalid frame data")? + >= current_frame_size + { if self.frame_offset > current_frame_size { bail!( "Invalid frame offset {} {}", @@ -897,7 +902,12 @@ impl UvcPayload { frame_data_size = (current_frame_size - self.frame_offset) as u64; } // Within the scope of the payload. - if self.payload_offset + frame_data_size as usize >= MAX_PAYLOAD as usize { + if self + .payload_offset + .checked_add(frame_data_size as usize) + .with_context(|| "get_frame_data_size: invalid payload data")? + >= MAX_PAYLOAD as usize + { if self.payload_offset > MAX_PAYLOAD as usize { bail!( "Invalid payload offset {} {}", @@ -908,7 +918,12 @@ impl UvcPayload { frame_data_size = u64::from(MAX_PAYLOAD) - self.payload_offset as u64; } // payload start, reserve the header. - if self.payload_offset == 0 && frame_data_size + header_len as u64 > iov_size { + if self.payload_offset == 0 + && frame_data_size + .checked_add(header_len as u64) + .with_context(|| "get_frame_data_size: invalid header_len")? + > iov_size + { if iov_size <= header_len as u64 { bail!("Invalid iov size {}", iov_size); } @@ -1092,7 +1107,10 @@ fn gen_fmt_desc(fmt_list: Vec) -> Result fn gen_intface_header_desc(fmt_num: u8) -> VsDescInputHeader { VsDescInputHeader { - bLength: 0xd + fmt_num, + bLength: 0xd_u8.checked_add(fmt_num).unwrap_or_else(|| { + error!("gen_intface_header_desc: too large fmt num"); + u8::MAX + }), bDescriptorType: CS_INTERFACE, bDescriptorSubtype: VS_INPUT_HEADER, bNumFormats: fmt_num, diff --git a/util/src/ohos_binding/camera.rs b/util/src/ohos_binding/camera.rs index eadeb0d1..4121fcf3 100644 --- a/util/src/ohos_binding/camera.rs +++ b/util/src/ohos_binding/camera.rs @@ -69,6 +69,9 @@ impl OhCamera { bail!("OH Camera: failed to init profiles"); } } + if fmt_cnt > i32::from(u8::MAX) { + bail!("Invalid format counts: {fmt_cnt}"); + } Ok((Self { ctx, capi }, fmt_cnt)) } -- Gitee From fe8284893ffc290fc4c3005bb8ab19776f4f9c7e Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Thu, 26 Sep 2024 17:03:23 +0800 Subject: [PATCH 395/489] scream: optimize capture logic This patch optimizes scream capture logic and fixes up some issues: 1. Simplify the logic of audio data transfer. 2. Use condvar to wait for audio data and the max timeout is 200ms. If timed out, reinit capture context. 3. This can fixup the issue that audio capture hangs up when the users did the host system suspend and resume. 4. This can fixup the issue that capture thread enters into infinite loop while waiting for audio data but the audio framework has error occurred. Signed-off-by: Zhao Yi Min --- devices/src/misc/scream/mod.rs | 4 - devices/src/misc/scream/ohaudio.rs | 146 +++++++++++++++-------------- 2 files changed, 75 insertions(+), 75 deletions(-) diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index 5272553a..328bef20 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -436,7 +436,6 @@ impl StreamData { let header = &mut unsafe { std::slice::from_raw_parts_mut(hva as *mut ShmemHeader, 1) }[0]; let capt = &mut header.capt; - interface.lock().unwrap().pre_receive(self.start_addr, capt); while capt.is_started != 0 { cond.wait_if_paused(interface.clone()); @@ -766,9 +765,6 @@ impl Scream { pub trait AudioInterface: Send { fn send(&mut self, recv_data: &StreamData); - // For OHOS's audio task. It confirms shmem info. - #[allow(unused_variables)] - fn pre_receive(&mut self, start_addr: u64, sh_header: &ShmemStreamHeader) {} fn receive(&mut self, recv_data: &StreamData) -> i32; fn destroy(&mut self); fn get_status(&self) -> AudioStatus; diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index 8040ea88..d011c04d 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -13,16 +13,16 @@ use std::collections::VecDeque; use std::os::raw::c_void; use std::sync::{ - atomic::{fence, AtomicBool, AtomicI32, Ordering}, - Arc, Mutex, RwLock, + atomic::{fence, AtomicBool, Ordering}, + Arc, Condvar, Mutex, RwLock, }; use std::{cmp, io::Read, ptr, thread, time::Duration}; -use log::error; +use log::{error, warn}; use crate::misc::ivshmem::Ivshmem; use crate::misc::scream::{ - AudioExtension, AudioInterface, AudioStatus, ScreamDirection, ShmemStreamHeader, StreamData, + AudioExtension, AudioInterface, AudioStatus, ScreamDirection, StreamData, IVSHMEM_VOLUME_SYNC_VECTOR, }; use util::ohos_binding::audio::*; @@ -31,11 +31,11 @@ const STREAM_DATA_VEC_CAPACITY: usize = 15; const FLUSH_DELAY_MS: u64 = 5; const FLUSH_DELAY_CNT: u64 = 200; const SCREAM_MAX_VOLUME: u32 = 110; +const CAPTURE_WAIT_TIMEOUT: u64 = 200; trait OhAudioProcess { fn init(&mut self, stream: &StreamData) -> bool; fn destroy(&mut self); - fn preprocess(&mut self, _start_addr: u64, _sh_header: &ShmemStreamHeader) {} fn process(&mut self, recv_data: &StreamData) -> i32; fn get_status(&self) -> AudioStatus; } @@ -293,15 +293,63 @@ impl OhAudioProcess for OhAudioRender { } } +struct CaptureStream { + cond: Condvar, + data: Mutex>, + expected: usize, +} + +impl Default for CaptureStream { + fn default() -> Self { + Self { + cond: Condvar::new(), + data: Mutex::new(Vec::with_capacity(1 << 20)), + expected: 0, + } + } +} + +impl CaptureStream { + fn wait_for_data(&mut self, buf: &mut [u8]) -> bool { + let mut locked_data = self.data.lock().unwrap(); + self.expected = buf.len(); + while locked_data.len() < self.expected { + let ret = self + .cond + .wait_timeout(locked_data, Duration::from_millis(CAPTURE_WAIT_TIMEOUT)) + .unwrap(); + if ret.1.timed_out() { + return false; + } + locked_data = ret.0; + } + buf.copy_from_slice(&locked_data[..self.expected]); + *locked_data = locked_data[self.expected..].to_vec(); + self.expected = 0; + true + } + + fn append_data(&mut self, buf: &[u8]) { + let mut locked_data = self.data.lock().unwrap(); + locked_data.extend_from_slice(buf); + if locked_data.len() > self.expected { + self.cond.notify_all(); + } + } + + fn reset(&mut self) { + let mut locked_data = self.data.lock().unwrap(); + locked_data.clear(); + self.expected = 0; + self.cond.notify_all(); + } +} + #[derive(Default)] struct OhAudioCapture { ctx: Option, - align: u32, - new_chunks: AtomicI32, - shm_addr: u64, - shm_len: u64, - cur_pos: u64, status: AudioStatus, + stream: CaptureStream, } impl OhAudioCapture { @@ -350,18 +398,10 @@ impl OhAudioProcess for OhAudioCapture { fn destroy(&mut self) { self.status = AudioStatus::Ready; self.ctx = None; + self.stream.reset(); trace::oh_scream_capture_destroy(); } - fn preprocess(&mut self, start_addr: u64, sh_header: &ShmemStreamHeader) { - self.align = sh_header.chunk_size; - self.new_chunks.store(0, Ordering::Release); - self.shm_addr = start_addr; - self.shm_len = u64::from(sh_header.max_chunks) * u64::from(sh_header.chunk_size); - self.cur_pos = - start_addr + u64::from(sh_header.chunk_idx) * u64::from(sh_header.chunk_size); - } - fn process(&mut self, recv_data: &StreamData) -> i32 { self.check_fmt_update(recv_data); @@ -375,15 +415,19 @@ impl OhAudioProcess for OhAudioCapture { self.destroy(); return -1; } - self.new_chunks.store(0, Ordering::Release); - while self.new_chunks.load(Ordering::Acquire) == 0 { - if self.status == AudioStatus::Error { - return -1; - } - thread::sleep(Duration::from_millis(10)); + // SAFETY: the buffer is from ivshmem and the caller ensures its validation. + let buf = unsafe { + std::slice::from_raw_parts_mut( + recv_data.audio_base as *mut u8, + recv_data.audio_size as usize, + ) + }; + if !self.stream.wait_for_data(buf) { + warn!("timed out to wait for capture audio data"); + self.status = AudioStatus::Error; + return 0; } - - self.new_chunks.load(Ordering::Acquire) + 1 } fn get_status(&self) -> AudioStatus { @@ -446,49 +490,13 @@ extern "C" fn on_read_data_cb( trace::trace_scope_start!(ohaudio_read_cb, args = (length)); - loop { - if capture.status != AudioStatus::Started { - return 0; - } - if capture.new_chunks.load(Ordering::Acquire) == 0 { - break; - } - } - if capture.align == 0 { - error!("on_read_data_cb, capture.align is 0"); + if capture.status != AudioStatus::Started { return 0; } - let old_pos = - capture.cur_pos - ((capture.cur_pos - capture.shm_addr) % u64::from(capture.align)); - let buf_end = capture.shm_addr + capture.shm_len; - let mut src_addr = buffer as u64; - let mut left = length as u64; - while left > 0 { - let len = cmp::min(left, buf_end - capture.cur_pos); - // SAFETY: we checked len. - unsafe { - ptr::copy_nonoverlapping( - src_addr as *const u8, - capture.cur_pos as *mut u8, - len as usize, - ) - }; - trace::oh_scream_on_read_data_cb(len as usize); - left -= len; - src_addr += len; - capture.cur_pos += len; - if capture.cur_pos == buf_end { - capture.cur_pos = capture.shm_addr; - } - } - let new_chunks = match capture.cur_pos <= old_pos { - true => (capture.shm_len - (old_pos - capture.cur_pos)) / u64::from(capture.align), - false => (capture.cur_pos - old_pos) / u64::from(capture.align), - }; - capture - .new_chunks - .store(new_chunks as i32, Ordering::Release); + // SAFETY: the buffer is checked above. + let buf = unsafe { std::slice::from_raw_parts(buffer as *mut u8, length as usize) }; + capture.stream.append_data(buf); 0 } @@ -517,10 +525,6 @@ impl AudioInterface for OhAudio { self.processor.process(recv_data); } - fn pre_receive(&mut self, start_addr: u64, sh_header: &ShmemStreamHeader) { - self.processor.preprocess(start_addr, sh_header); - } - fn receive(&mut self, recv_data: &StreamData) -> i32 { self.processor.process(recv_data) } -- Gitee From b3639fac2c6fa9747dc9135b57da64c6e95caee7 Mon Sep 17 00:00:00 2001 From: zhanghan Date: Mon, 29 Jul 2024 15:45:11 +0800 Subject: [PATCH 396/489] ohaudio: add logs We need to know when to start/stop for audio tasks for issues analysis, so we add two logs. Signed-off-by: zhanghan64 --- devices/src/misc/scream/ohaudio.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index d011c04d..f7ad7117 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -18,7 +18,7 @@ use std::sync::{ }; use std::{cmp, io::Read, ptr, thread, time::Duration}; -use log::{error, warn}; +use log::{error, info, warn}; use crate::misc::ivshmem::Ivshmem; use crate::misc::scream::{ @@ -237,6 +237,7 @@ impl OhAudioProcess for OhAudioRender { } match self.ctx.as_ref().unwrap().start() { Ok(()) => { + info!("Renderer start"); self.status = AudioStatus::Started; trace::oh_scream_render_init(&self.ctx); } @@ -248,6 +249,7 @@ impl OhAudioProcess for OhAudioRender { } fn destroy(&mut self) { + info!("Renderer destroy"); match self.status { AudioStatus::Error => { self.ctx = None; @@ -384,6 +386,7 @@ impl OhAudioProcess for OhAudioCapture { } match self.ctx.as_ref().unwrap().start() { Ok(()) => { + info!("Capturer start"); self.status = AudioStatus::Started; trace::oh_scream_capture_init(&self.ctx); true @@ -396,6 +399,7 @@ impl OhAudioProcess for OhAudioCapture { } fn destroy(&mut self) { + info!("Capturer destroy"); self.status = AudioStatus::Ready; self.ctx = None; self.stream.reset(); -- Gitee From c76bb173ae8aeff281bb6ee3fb86fb00228eb860 Mon Sep 17 00:00:00 2001 From: zhanghan Date: Tue, 30 Jul 2024 11:44:50 +0800 Subject: [PATCH 397/489] ohaudio: stream interruption event process When host's audio render interrupts our render task, we destoy current render task. When host's audio capture interrupts our capture task, we just print logs. Because now no host audio capture will interrupt us, in case of potential problems, we do some log. Signed-off-by: zhanghan64 --- devices/src/misc/scream/mod.rs | 4 +- devices/src/misc/scream/ohaudio.rs | 60 +++++++++++++++++++++++++++--- util/src/ohos_binding/audio/mod.rs | 30 ++++++++++++--- util/src/ohos_binding/audio/sys.rs | 43 ++++++++++++++++++++- 4 files changed, 122 insertions(+), 15 deletions(-) diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index 328bef20..ead35388 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -72,7 +72,7 @@ const POLL_DELAY_US: u64 = (TARGET_LATENCY_MS as u64) * 1000 / 8; pub const SCREAM_MAGIC: u64 = 0x02032023; -#[derive(Copy, Clone, Default, PartialEq, Eq, PartialOrd)] +#[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd)] pub enum AudioStatus { // Processor is ready and waiting for play/capture. #[default] @@ -81,6 +81,8 @@ pub enum AudioStatus { Started, // OH audio framework error occurred. Error, + // OH audio stream is interrupted. + Intr, } type AuthorityNotify = dyn Fn() + Send + Sync; diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index f7ad7117..eaea009c 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -225,7 +225,7 @@ impl OhAudioProcess for OhAudioRender { stream.fmt.size, stream.fmt.get_rate(), stream.fmt.channels, - AudioProcessCb::RendererCb(Some(on_write_data_cb)), + AudioProcessCb::RendererCb(Some(on_write_data_cb), Some(render_on_interrupt_cb)), ptr::addr_of!(*self) as *mut c_void, ) { Ok(()) => self.ctx = Some(context), @@ -251,7 +251,7 @@ impl OhAudioProcess for OhAudioRender { fn destroy(&mut self) { info!("Renderer destroy"); match self.status { - AudioStatus::Error => { + AudioStatus::Error | AudioStatus::Intr => { self.ctx = None; self.status = AudioStatus::Ready; return; @@ -278,8 +278,11 @@ impl OhAudioProcess for OhAudioRender { recv_data.audio_size as usize, )); - if self.status == AudioStatus::Error { - error!("Audio server error occurred. Destroy and reconnect it."); + if self.status == AudioStatus::Error || self.status == AudioStatus::Intr { + error!( + "Audio server {:?} occurred. Destroy and reconnect it.", + self.status + ); self.destroy(); } @@ -375,7 +378,7 @@ impl OhAudioProcess for OhAudioCapture { stream.fmt.size, stream.fmt.get_rate(), stream.fmt.channels, - AudioProcessCb::CapturerCb(Some(on_read_data_cb)), + AudioProcessCb::CapturerCb(Some(on_read_data_cb), Some(capture_on_interrupt_cb)), ptr::addr_of!(*self) as *mut c_void, ) { Ok(()) => self.ctx = Some(context), @@ -411,7 +414,7 @@ impl OhAudioProcess for OhAudioCapture { trace::trace_scope_start!(ohaudio_capturer_process, args = (recv_data)); - if self.status == AudioStatus::Error { + if self.status == AudioStatus::Error || self.status == AudioStatus::Intr { self.destroy(); } @@ -439,6 +442,51 @@ impl OhAudioProcess for OhAudioCapture { } } +extern "C" fn render_on_interrupt_cb( + _renderer: *mut OhAudioRenderer, + user_data: *mut ::std::os::raw::c_void, + source_type: capi::OHAudioInterruptSourceType, + hint: capi::OHAudioInterruptHint, +) -> i32 { + info!( + "Render interrupts, type is {}, hint is {}", + source_type, hint + ); + // SAFETY: we make sure that it is OhAudioRender when register callback. + let render = unsafe { + (user_data as *mut OhAudioRender) + .as_mut() + .unwrap_unchecked() + }; + if hint == capi::AUDIOSTREAM_INTERRUPT_HINT_PAUSE { + render.status = AudioStatus::Intr; + } + 0 +} + +extern "C" fn capture_on_interrupt_cb( + _capturer: *mut OhAudioCapturer, + user_data: *mut ::std::os::raw::c_void, + source_type: capi::OHAudioInterruptSourceType, + hint: capi::OHAudioInterruptHint, +) -> i32 { + info!( + "Capture interrupts, type is {}, hint is {}", + source_type, hint + ); + + // SAFETY: we make sure that it is OhAudioCapture when register callback. + let capture = unsafe { + (user_data as *mut OhAudioCapture) + .as_mut() + .unwrap_unchecked() + }; + if hint == capi::AUDIOSTREAM_INTERRUPT_HINT_PAUSE { + capture.status = AudioStatus::Intr; + } + 0 +} + extern "C" fn on_write_data_cb( _renderer: *mut OhAudioRenderer, user_data: *mut ::std::os::raw::c_void, diff --git a/util/src/ohos_binding/audio/mod.rs b/util/src/ohos_binding/audio/mod.rs index 61364719..07b2cb09 100755 --- a/util/src/ohos_binding/audio/mod.rs +++ b/util/src/ohos_binding/audio/mod.rs @@ -10,7 +10,7 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -mod sys; +pub mod sys; use std::os::raw::c_void; use std::ptr; @@ -20,7 +20,7 @@ use log::error; use once_cell::sync::Lazy; use super::hwf_adapter::{hwf_adapter_volume_api, volume::VolumeFuncTable}; -use sys as capi; +pub use sys as capi; const AUDIO_SAMPLE_RATE_44KHZ: u32 = 44100; const AUDIO_SAMPLE_RATE_48KHZ: u32 = 48000; @@ -187,6 +187,14 @@ pub enum AudioProcessCb { length: i32, ) -> i32, >, + Option< + extern "C" fn( + capturer: *mut capi::OhAudioCapturer, + userData: *mut c_void, + source_type: capi::OHAudioInterruptSourceType, + hint: capi::OHAudioInterruptHint, + ) -> i32, + >, ), RendererCb( Option< @@ -197,6 +205,14 @@ pub enum AudioProcessCb { length: i32, ) -> i32, >, + Option< + extern "C" fn( + capturer: *mut capi::OhAudioRenderer, + userData: *mut c_void, + source_type: capi::OHAudioInterruptSourceType, + hint: capi::OHAudioInterruptHint, + ) -> i32, + >, ), } @@ -258,8 +274,9 @@ impl AudioContext { fn create_renderer(&mut self, cb: AudioProcessCb) -> Result<(), OAErr> { let mut cbs = capi::OhAudioRendererCallbacks::default(); - if let AudioProcessCb::RendererCb(f) = cb { - cbs.oh_audio_renderer_on_write_data = f; + if let AudioProcessCb::RendererCb(data_cb, interrupt_cb) = cb { + cbs.oh_audio_renderer_on_write_data = data_cb; + cbs.oh_audio_renderer_on_interrupt_event = interrupt_cb; } call_capi!(OH_AudioStreamBuilder_SetRendererCallback( self.builder, @@ -274,8 +291,9 @@ impl AudioContext { fn create_capturer(&mut self, cb: AudioProcessCb) -> Result<(), OAErr> { let mut cbs = capi::OhAudioCapturerCallbacks::default(); - if let AudioProcessCb::CapturerCb(v) = cb { - cbs.oh_audio_capturer_on_read_data = v; + if let AudioProcessCb::CapturerCb(data_cb, interrupt_cb) = cb { + cbs.oh_audio_capturer_on_read_data = data_cb; + cbs.oh_audio_capturer_on_interrupt_event = interrupt_cb; } call_capi!(OH_AudioStreamBuilder_SetCapturerCallback( self.builder, diff --git a/util/src/ohos_binding/audio/sys.rs b/util/src/ohos_binding/audio/sys.rs index 289becbe..56dcee2e 100755 --- a/util/src/ohos_binding/audio/sys.rs +++ b/util/src/ohos_binding/audio/sys.rs @@ -131,6 +131,31 @@ pub const OH_AUDIO_STREAM_SOURCE_TYPE_AUDIOSTREAM_SOURCE_TYPE_VOICE_COMMUNICATIO /// @since 10 pub type OHAudioStreamSourceType = ::std::os::raw::c_int; +#[allow(unused)] +pub const AUDIOSTREAM_INTERRUPT_FORCE: OHAudioInterruptSourceType = 0; +#[allow(unused)] +pub const AUDIOSTREAM_INTERRUPT_SHARE: OHAudioInterruptSourceType = 1; + +/// Defines the audio interrupt source type. +/// +/// @since 10 +pub type OHAudioInterruptSourceType = ::std::os::raw::c_int; + +#[allow(unused)] +pub const AUDIOSTREAM_INTERRUPT_HINT_RESUME: OHAudioInterruptHint = 1; +pub const AUDIOSTREAM_INTERRUPT_HINT_PAUSE: OHAudioInterruptHint = 2; +#[allow(unused)] +pub const AUDIOSTREAM_INTERRUPT_HINT_STOP: OHAudioInterruptHint = 3; +#[allow(unused)] +pub const AUDIOSTREAM_INTERRUPT_HINT_DUCK: OHAudioInterruptHint = 4; +#[allow(unused)] +pub const AUDIOSTREAM_INTERRUPT_HINT_UNDUCK: OHAudioInterruptHint = 5; + +/// Defines the audio interrupt hint type. +/// +/// @since 10 +pub type OHAudioInterruptHint = ::std::os::raw::c_int; + #[repr(C)] #[derive(Debug, Copy, Clone)] pub struct OH_AudioStreamBuilderStruct { @@ -183,7 +208,14 @@ pub struct OhAudioRendererCallbacks { ) -> i32, >, pub oh_audio_renderer_on_stream_event: PlaceHolderFn, - pub oh_audio_renderer_on_interrpt_event: PlaceHolderFn, + pub oh_audio_renderer_on_interrupt_event: ::std::option::Option< + extern "C" fn( + renderer: *mut OhAudioRenderer, + userData: *mut ::std::os::raw::c_void, + source_type: OHAudioInterruptSourceType, + hint: OHAudioInterruptHint, + ) -> i32, + >, pub oh_audio_renderer_on_error: PlaceHolderFn, } @@ -204,7 +236,14 @@ pub struct OhAudioCapturerCallbacks { ) -> i32, >, pub oh_audio_capturer_on_stream_event: PlaceHolderFn, - pub oh_audio_capturer_on_interrpt_event: PlaceHolderFn, + pub oh_audio_capturer_on_interrupt_event: ::std::option::Option< + extern "C" fn( + capturer: *mut OhAudioCapturer, + userData: *mut ::std::os::raw::c_void, + source_type: OHAudioInterruptSourceType, + hint: OHAudioInterruptHint, + ) -> i32, + >, pub oh_audio_capturer_on_error: PlaceHolderFn, } -- Gitee From 302b021c1e3afae9b21d76c413cb2a96ac13686c Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Fri, 20 Sep 2024 09:12:09 +0800 Subject: [PATCH 398/489] ozonec/mount: Introduce openat2() to validate mount target A mount target path could be specified containing symlinks that would allow processes in the container to escape to the host filesystem. Nowadays Linux kernel provides the syscall openat2() which can effectively block symlink attacks. However, mount syscall only operates on paths, so we can get a file descriptor by openat2() and build the proc path "/proc/self/fd/xx" to do mounting. Fixes: CVE-2021-30465,CVE-2024-21626 --- ozonec/src/linux/mount.rs | 107 +++++++++++++++++--------------------- ozonec/src/utils/error.rs | 2 + ozonec/src/utils/mod.rs | 102 ++++++++++++++++++++++++++++++++++++ 3 files changed, 151 insertions(+), 60 deletions(-) diff --git a/ozonec/src/linux/mount.rs b/ozonec/src/linux/mount.rs index 972be73a..de9a1b12 100644 --- a/ozonec/src/linux/mount.rs +++ b/ozonec/src/linux/mount.rs @@ -12,7 +12,7 @@ use std::{ collections::HashMap, - fs::{self, canonicalize, create_dir_all, read_to_string, File}, + fs::{self, canonicalize, create_dir_all, read_to_string}, path::{Path, PathBuf}, }; @@ -20,11 +20,12 @@ use anyhow::{anyhow, bail, Context, Result}; use nix::{ mount::MsFlags, sys::statfs::{statfs, CGROUP2_SUPER_MAGIC}, + unistd::close, }; +use procfs::process::{MountInfo, Process}; -use crate::utils::OzonecErr; +use crate::utils::{openat2_in_root, proc_fd_path, OzonecErr}; use oci_spec::runtime::Mount as OciMount; -use procfs::process::{MountInfo, Process}; enum CgroupType { CgroupV1, @@ -98,9 +99,8 @@ impl Mount { } fn do_one_mount(&self, mount: &OciMount, label: &Option) -> Result<()> { - let fs_type = mount.fs_type.as_deref(); - let (flag, mut data) = self.get_mount_flag_data(mount); - + let mut fs_type = mount.fs_type.as_deref(); + let (mut mnt_flags, mut data) = self.get_mount_flag_data(mount); if let Some(label) = label { if fs_type != Some("proc") && fs_type != Some("sysfs") { match data.is_empty() { @@ -110,16 +110,13 @@ impl Mount { } } - // If destination begins with "/", then ignore the first "/". - let binding = self.rootfs.join(&mount.destination[1..]); - let dest_path = Path::new(&binding); - let binding = &mount + let src_binding = mount .source .clone() .ok_or(anyhow!("Mount source not set"))?; - let source = Path::new(&binding); + let source = Path::new(&src_binding); let canonicalized; - let src_path = match fs_type { + let source = match fs_type { Some("bind") => { canonicalized = canonicalize(source) .with_context(|| format!("Failed to canonicalize {}", source.display()))?; @@ -127,54 +124,49 @@ impl Mount { } _ => source, }; + // Strip the first "/". + let target_binding = self.rootfs.join(&mount.destination[1..]); + let target = Path::new(&target_binding); match fs_type { Some("bind") => { - let dir = if src_path.is_file() { - dest_path.parent().ok_or(anyhow!( + let dir = if source.is_file() { + target.parent().ok_or(anyhow!( "Failed to get parent directory: {}", - dest_path.display() + target.display() ))? } else { - dest_path + target }; - create_dir_all(dir) .with_context(|| OzonecErr::CreateDir(dir.to_string_lossy().to_string()))?; - if src_path.is_file() && !dest_path.exists() { - File::create(dest_path) - .with_context(|| format!("Failed to create {}", dest_path.display()))?; - } - nix::mount::mount( - Some(src_path), - dest_path, - None::<&str>, - MsFlags::MS_BIND | MsFlags::MS_REC, - Some(data.as_str()), - ) - .with_context(|| OzonecErr::Mount(src_path.to_string_lossy().to_string()))?; + mnt_flags = MsFlags::MS_BIND | MsFlags::MS_REC; + fs_type = None::<&str>; } _ => { - create_dir_all(&dest_path).with_context(|| { - OzonecErr::CreateDir(dest_path.to_string_lossy().to_string()) - })?; // Sysfs doesn't support duplicate mounting to one directory. - if self.is_mounted_sysfs_dir(&dest_path.to_string_lossy().to_string()) { - nix::mount::umount(dest_path) - .with_context(|| format!("Failed to umount {}", dest_path.display()))?; + if self.is_mounted_sysfs_dir(&target.to_string_lossy().to_string()) { + nix::mount::umount(target) + .with_context(|| format!("Failed to umount {}", target.display()))?; } - nix::mount::mount( - Some(src_path), - dest_path, - fs_type, - flag, - Some(data.as_str()), - ) - .with_context(|| OzonecErr::Mount(src_path.to_string_lossy().to_string()))?; } } + let target_fd = openat2_in_root( + &Path::new(&self.rootfs), + &Path::new(&mount.destination[1..]), + !source.is_file(), + )?; + nix::mount::mount( + Some(source), + &proc_fd_path(target_fd), + fs_type, + mnt_flags, + Some(data.as_str()), + ) + .with_context(|| OzonecErr::Mount(source.to_string_lossy().to_string()))?; + close(target_fd).with_context(|| OzonecErr::CloseFd)?; Ok(()) } @@ -210,22 +202,22 @@ impl Mount { } fn do_cgroup_mount(&self, mount: &OciMount) -> Result<()> { - // If destination begins with "/", then ignore the first "/". - let binding = self.rootfs.join(&mount.destination[1..]); - let mut dest = Path::new(&binding); + // Strip the first "/". + let rel_target = Path::new(&mount.destination[1..]); + let target_fd = openat2_in_root(&Path::new(&self.rootfs), rel_target, true)?; nix::mount::mount( Some("tmpfs"), - dest, + &proc_fd_path(target_fd), Some("tmpfs"), MsFlags::MS_NOEXEC | MsFlags::MS_NOSUID | MsFlags::MS_NODEV, None::<&str>, ) .with_context(|| OzonecErr::Mount(String::from("tmpfs")))?; + close(target_fd).with_context(|| OzonecErr::CloseFd)?; let process = Process::myself().with_context(|| OzonecErr::AccessProcSelf)?; let mnt_info: Vec = process.mountinfo().with_context(|| OzonecErr::GetMntInfo)?; - let proc_cgroups: HashMap = process .cgroups() .with_context(|| "Failed to get cgroups belong to")? @@ -239,12 +231,6 @@ impl Mount { .map(|m| m.mount_point) .collect(); for cg_path in host_cgroups { - let binding = self.rootfs.join( - cg_path - .strip_prefix("/") - .with_context(|| format!("Strip {} error", cg_path.display()))?, - ); - dest = Path::new(&binding); let cg = cg_path .file_name() .ok_or(anyhow!("Failed to get controller file"))? @@ -261,19 +247,20 @@ impl Mount { if let Some(src) = proc_cgroups.get(&proc_cg_key) { let source = cg_path.join(&src[1..]); - if !dest.exists() { - create_dir_all(dest).with_context(|| { - OzonecErr::CreateDir(dest.to_string_lossy().to_string()) - })?; - } + let rel_target = cg_path + .strip_prefix("/") + .with_context(|| format!("{} doesn't start with '/'", cg_path.display()))?; + let target_fd = openat2_in_root(&Path::new(&self.rootfs), rel_target, true)?; + nix::mount::mount( Some(&source), - dest, + &proc_fd_path(target_fd), Some("bind"), MsFlags::MS_BIND | MsFlags::MS_REC, None::<&str>, ) .with_context(|| OzonecErr::Mount(source.to_string_lossy().to_string()))?; + close(target_fd).with_context(|| OzonecErr::CloseFd)?; } } diff --git a/ozonec/src/utils/error.rs b/ozonec/src/utils/error.rs index 142ef9fb..b3f93728 100644 --- a/ozonec/src/utils/error.rs +++ b/ozonec/src/utils/error.rs @@ -44,4 +44,6 @@ pub enum OzonecErr { GetOciState, #[error("Failed to bind device: {0}")] BindDev(String), + #[error("Close fd error")] + CloseFd, } diff --git a/ozonec/src/utils/mod.rs b/ozonec/src/utils/mod.rs index 69b9517d..59da672a 100644 --- a/ozonec/src/utils/mod.rs +++ b/ozonec/src/utils/mod.rs @@ -20,3 +20,105 @@ mod error; pub use channel::{Channel, Message}; pub use clone::Clone3; pub use error::OzonecErr; + +use std::{ + fs::create_dir_all, + mem, + os::unix::io::{AsRawFd, RawFd}, + path::{Path, PathBuf}, +}; + +use anyhow::{bail, Context, Result}; +use nix::{ + errno::errno, + fcntl::{open, OFlag}, + sys::stat::Mode, + NixPath, +}; + +struct OpenHow(libc::open_how); + +bitflags::bitflags! { + struct ResolveFlag: libc::c_ulonglong { + const RESOLVE_BENEATH = libc::RESOLVE_BENEATH; + const RESOLVE_IN_ROOT = libc::RESOLVE_IN_ROOT; + const RESOLVE_NO_MAGICLINKS = libc::RESOLVE_NO_MAGICLINKS; + const RESOLVE_NO_SYMLINKS = libc::RESOLVE_NO_SYMLINKS; + const RESOLVE_NO_XDEV = libc::RESOLVE_NO_XDEV; + } +} + +impl OpenHow { + fn new() -> Self { + // SAFETY: FFI call with valid arguments. + unsafe { mem::zeroed() } + } + + fn flags(mut self, flags: OFlag) -> Self { + let flags = flags.bits() as libc::c_ulonglong; + self.0.flags = flags; + self + } + + fn mode(mut self, mode: Mode) -> Self { + let mode = mode.bits() as libc::c_ulonglong; + self.0.mode = mode; + self + } + + fn resolve(mut self, resolve: ResolveFlag) -> Self { + let resolve = resolve.bits() as libc::c_ulonglong; + self.0.resolve = resolve; + self + } +} + +/// Get a file descriptor by openat2 with `root` path, relative `target` path in `root` +/// and whether is director or not. If the target directory or file doesn't exist, create +/// automatically. +pub fn openat2_in_root(root: &Path, target: &Path, is_dir: bool) -> Result { + let mut flags = OFlag::O_CLOEXEC; + let mode; + if is_dir { + flags |= OFlag::O_DIRECTORY | OFlag::O_PATH; + mode = Mode::empty(); + create_dir_all(root.join(target)) + .with_context(|| OzonecErr::CreateDir(target.to_string_lossy().to_string()))?; + } else { + flags |= OFlag::O_CREAT; + mode = Mode::S_IRWXU; + }; + + let mut open_how = OpenHow::new() + .flags(flags) + .mode(mode) + .resolve(ResolveFlag::RESOLVE_IN_ROOT); + let dirfd = open(root, flags & !OFlag::O_CREAT, Mode::empty()) + .with_context(|| OzonecErr::OpenFile(root.to_string_lossy().to_string()))?; + + // SAFETY: FFI call with valid arguments. + let fd = target + .with_nix_path(|p| unsafe { + libc::syscall( + libc::SYS_openat2, + dirfd.as_raw_fd(), + p.as_ptr(), + &mut open_how as *mut OpenHow, + mem::size_of::(), + ) + }) + .with_context(|| "with_nix_path error")?; + if fd < 0 { + bail!( + "openat2 {} error with RESOLVE_IN_ROOT: {}", + target.display(), + errno() + ); + } + Ok(RawFd::try_from(fd)?) +} + +/// Build path "/proc/self/fd/{}" with an opened file descriptor. +pub fn proc_fd_path(dirfd: RawFd) -> PathBuf { + PathBuf::from(format!("/proc/self/fd/{}", dirfd)) +} -- Gitee From 884880dec251e1138c94fb27501ac9b70ffb2c73 Mon Sep 17 00:00:00 2001 From: sujerry1991 Date: Thu, 10 Oct 2024 16:16:01 +0800 Subject: [PATCH 399/489] util: do not handle DISCARD in thread pool In qcow2, discard operation(fallocate) should not be execute in thread pool which will cause the following error: 1) discard operation release the qcow2 cluster A. 2) discard operation execute fallocate in the thread pool. 3) write operation alloc cluster A and write data to it. 4) fallocate in the thread pool clear the data in cluster A. The step 1)/2)/4) should be handle in one thread. So, handle discard operation synchronously. Signed-off-by: Yan Wang --- util/src/aio/mod.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/util/src/aio/mod.rs b/util/src/aio/mod.rs index ac10fa16..4422bc7f 100644 --- a/util/src/aio/mod.rs +++ b/util/src/aio/mod.rs @@ -564,7 +564,14 @@ impl Aio { pub fn submit_request(&mut self, mut cb: AioCb) -> Result<()> { trace::aio_submit_request(cb.file_fd, &cb.opcode, cb.offset, cb.nbytes); - if self.ctx.is_none() { + if self.ctx.is_none() + || [ + OpCode::Discard, + OpCode::WriteZeroes, + OpCode::WriteZeroesUnmap, + ] + .contains(&cb.opcode) + { return self.handle_sync_request(cb); } -- Gitee From 8db17d37fbceaa4bdf7a87f0a68d84261f4c9c46 Mon Sep 17 00:00:00 2001 From: Li Huachao Date: Fri, 11 Oct 2024 17:38:28 +0800 Subject: [PATCH 400/489] Pflash: fix unchecked add Signed-off-by: Li Huachao --- devices/src/legacy/pflash.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/devices/src/legacy/pflash.rs b/devices/src/legacy/pflash.rs index 209c9ecd..5ea22a3b 100644 --- a/devices/src/legacy/pflash.rs +++ b/devices/src/legacy/pflash.rs @@ -329,7 +329,11 @@ impl PFlash { } // Unwrap is safe, because after realize function, rom isn't none. let mr = self.rom.as_ref().unwrap(); - if offset + u64::from(size) > mr.size() { + if offset + .checked_add(size as u64) + .map(|sum| sum > mr.size()) + .unwrap_or(true) + { return Err(anyhow!(LegacyError::PFlashWriteOverflow( mr.size(), offset, @@ -361,7 +365,11 @@ impl PFlash { fn read_data(&mut self, data: &mut [u8], offset: u64) -> Result<()> { // Unwrap is safe, because after realize function, rom isn't none. let mr = self.rom.as_ref().unwrap(); - if offset + data.len() as u64 > mr.size() { + if offset + .checked_add(data.len() as u64) + .map(|sum| sum > mr.size()) + .unwrap_or(true) + { return Err(anyhow!(LegacyError::PFlashReadOverflow( mr.size(), offset, @@ -390,7 +398,11 @@ impl PFlash { ); // Unwrap is safe, because after realize function, rom isn't none. let mr = self.rom.as_ref().unwrap(); - if offset + data.len() as u64 > mr.size() { + if offset + .checked_add(data.len() as u64) + .map(|sum| sum > mr.size()) + .unwrap_or(true) + { return Err(anyhow!(LegacyError::PFlashWriteOverflow( mr.size(), offset, -- Gitee From 069074d25aaf819f7416131894a41117d714210b Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Tue, 24 Sep 2024 00:06:01 +0800 Subject: [PATCH 401/489] ozonec/mount: Create a bind mount when bind option is set There is no filesystem called bind. Actually when bind option is set in mount options, i.e. MS_BIND is set, filesystem is ignored by mount systemcall. --- ozonec/src/linux/mount.rs | 55 ++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/ozonec/src/linux/mount.rs b/ozonec/src/linux/mount.rs index de9a1b12..55ab4536 100644 --- a/ozonec/src/linux/mount.rs +++ b/ozonec/src/linux/mount.rs @@ -100,7 +100,7 @@ impl Mount { fn do_one_mount(&self, mount: &OciMount, label: &Option) -> Result<()> { let mut fs_type = mount.fs_type.as_deref(); - let (mut mnt_flags, mut data) = self.get_mount_flag_data(mount); + let (mnt_flags, mut data) = self.get_mount_flag_data(mount); if let Some(label) = label { if fs_type != Some("proc") && fs_type != Some("sysfs") { match data.is_empty() { @@ -114,42 +114,33 @@ impl Mount { .source .clone() .ok_or(anyhow!("Mount source not set"))?; - let source = Path::new(&src_binding); + let mut source = Path::new(&src_binding); let canonicalized; - let source = match fs_type { - Some("bind") => { - canonicalized = canonicalize(source) - .with_context(|| format!("Failed to canonicalize {}", source.display()))?; - canonicalized.as_path() - } - _ => source, - }; // Strip the first "/". let target_binding = self.rootfs.join(&mount.destination[1..]); let target = Path::new(&target_binding); - match fs_type { - Some("bind") => { - let dir = if source.is_file() { - target.parent().ok_or(anyhow!( - "Failed to get parent directory: {}", - target.display() - ))? - } else { - target - }; - create_dir_all(dir) - .with_context(|| OzonecErr::CreateDir(dir.to_string_lossy().to_string()))?; - - mnt_flags = MsFlags::MS_BIND | MsFlags::MS_REC; - fs_type = None::<&str>; - } - _ => { - // Sysfs doesn't support duplicate mounting to one directory. - if self.is_mounted_sysfs_dir(&target.to_string_lossy().to_string()) { - nix::mount::umount(target) - .with_context(|| format!("Failed to umount {}", target.display()))?; - } + if !(mnt_flags & MsFlags::MS_BIND).is_empty() { + canonicalized = canonicalize(source) + .with_context(|| format!("Failed to canonicalize {}", source.display()))?; + source = canonicalized.as_path(); + let dir = if source.is_file() { + target.parent().ok_or(anyhow!( + "Failed to get parent directory: {}", + target.display() + ))? + } else { + target + }; + create_dir_all(dir) + .with_context(|| OzonecErr::CreateDir(dir.to_string_lossy().to_string()))?; + // Actually when MS_BIND is set, filesystemtype is ignored by mount syscall. + fs_type = Some("bind"); + } else { + // Sysfs doesn't support duplicate mounting to one directory. + if self.is_mounted_sysfs_dir(&target.to_string_lossy().to_string()) { + nix::mount::umount(target) + .with_context(|| format!("Failed to umount {}", target.display()))?; } } -- Gitee From d9568b7a240b05f8e049864f10fc15f716a26bfd Mon Sep 17 00:00:00 2001 From: zhanghan Date: Fri, 16 Aug 2024 09:30:14 +0800 Subject: [PATCH 402/489] ohaudio: extend waiting time for capture data We now have 200 ms for waiting capture data, if no data was accuqired during 200 ms, we destroy this capturer and restart again. But now the fact shows that 200 ms is too short for ohaudio to give us data, let's change it to 500 ms. Signed-off-by: zhanghan64 --- devices/src/misc/scream/ohaudio.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index eaea009c..a4d89254 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -31,7 +31,7 @@ const STREAM_DATA_VEC_CAPACITY: usize = 15; const FLUSH_DELAY_MS: u64 = 5; const FLUSH_DELAY_CNT: u64 = 200; const SCREAM_MAX_VOLUME: u32 = 110; -const CAPTURE_WAIT_TIMEOUT: u64 = 200; +const CAPTURE_WAIT_TIMEOUT: u64 = 500; trait OhAudioProcess { fn init(&mut self, stream: &StreamData) -> bool; -- Gitee From 0e8ef5fc044ae15db35bd78502d397dae3672978 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Tue, 24 Sep 2024 02:29:42 +0800 Subject: [PATCH 403/489] ozonec/seccomp: Add support for SCMP_CMP_MASKED_EQ valueTwo is set to 0 as default to be masked datum value only when op is SCMP_CMP_MASKED_EQ. --- ozonec/src/linux/seccomp.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/ozonec/src/linux/seccomp.rs b/ozonec/src/linux/seccomp.rs index e9586610..36903d43 100644 --- a/ozonec/src/linux/seccomp.rs +++ b/ozonec/src/linux/seccomp.rs @@ -35,7 +35,7 @@ fn parse_action(action: OciSeccompAction, errno: Option) -> ScmpAction { } } -fn parse_cmp(op: SeccompOp) -> ScmpCompareOp { +fn parse_cmp(op: SeccompOp, mask: u64) -> ScmpCompareOp { match op { SeccompOp::ScmpCmpNe => ScmpCompareOp::NotEqual, SeccompOp::ScmpCmpLt => ScmpCompareOp::Less, @@ -43,7 +43,7 @@ fn parse_cmp(op: SeccompOp) -> ScmpCompareOp { SeccompOp::ScmpCmpEq => ScmpCompareOp::Equal, SeccompOp::ScmpCmpGe => ScmpCompareOp::GreaterEqual, SeccompOp::ScmpCmpGt => ScmpCompareOp::Greater, - _ => ScmpCompareOp::Equal, + SeccompOp::ScmpCmpMaskedEq => ScmpCompareOp::MaskedEqual(mask), } } @@ -97,8 +97,13 @@ pub fn set_seccomp(seccomp: &Seccomp) -> Result<()> { let mut comparators: Vec = vec![]; if let Some(args) = &syscall.args { for arg in args { - let op = parse_cmp(arg.op); - let cmp = ScmpArgCompare::new(arg.index as u32, op, arg.value); + let op = parse_cmp(arg.op, arg.value); + let cmp = match arg.op { + SeccompOp::ScmpCmpMaskedEq => { + ScmpArgCompare::new(arg.index as u32, op, arg.valueTwo.unwrap_or(0)) + } + _ => ScmpArgCompare::new(arg.index as u32, op, arg.value), + }; comparators.push(cmp); } } -- Gitee From 3b6eafd5eddd8a710f17f4806b244a36a7aa4b50 Mon Sep 17 00:00:00 2001 From: Xu Yandong Date: Fri, 20 Sep 2024 07:53:05 +0000 Subject: [PATCH 404/489] address_space: fix numa support in micro machine Signed-off-by: Xu Yandong --- machine/src/aarch64/micro.rs | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/machine/src/aarch64/micro.rs b/machine/src/aarch64/micro.rs index 8cd32b5d..4cf52504 100644 --- a/machine/src/aarch64/micro.rs +++ b/machine/src/aarch64/micro.rs @@ -255,14 +255,33 @@ trait CompileFDTHelper { impl CompileFDTHelper for LightMachine { fn generate_memory_node(&self, fdt: &mut FdtBuilder) -> Result<()> { - let mem_base = MEM_LAYOUT[LayoutEntryType::Mem as usize].0; - let mem_size = self.base.sys_mem.memory_end_address().raw_value() - - MEM_LAYOUT[LayoutEntryType::Mem as usize].0; - let node = "memory"; - let memory_node_dep = fdt.begin_node(node)?; - fdt.set_property_string("device_type", "memory")?; - fdt.set_property_array_u64("reg", &[mem_base, mem_size])?; - fdt.end_node(memory_node_dep) + if self.base.numa_nodes.is_none() { + let mem_base = MEM_LAYOUT[LayoutEntryType::Mem as usize].0; + let mem_size = self.base.sys_mem.memory_end_address().raw_value() + - MEM_LAYOUT[LayoutEntryType::Mem as usize].0; + let node = "memory"; + let memory_node_dep = fdt.begin_node(node)?; + fdt.set_property_string("device_type", "memory")?; + fdt.set_property_array_u64("reg", &[mem_base, mem_size])?; + fdt.end_node(memory_node_dep)?; + + return Ok(()); + } + + // Set NUMA node information. + let mut mem_base = MEM_LAYOUT[LayoutEntryType::Mem as usize].0; + for (id, node) in self.base.numa_nodes.as_ref().unwrap().iter().enumerate() { + let mem_size = node.1.size; + let node = format!("memory@{:x}", mem_base); + let memory_node_dep = fdt.begin_node(&node)?; + fdt.set_property_string("device_type", "memory")?; + fdt.set_property_array_u64("reg", &[mem_base, mem_size])?; + fdt.set_property_u32("numa-node-id", id as u32)?; + fdt.end_node(memory_node_dep)?; + mem_base += mem_size; + } + + Ok(()) } fn generate_chosen_node(&self, fdt: &mut FdtBuilder) -> Result<()> { -- Gitee From 61950142347e1ec6955007d64c617e69d93857aa Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Thu, 16 May 2024 16:00:58 +0300 Subject: [PATCH 405/489] docs: Add USB Uas device entry to config_guidebook.md Signed-off-by: goriainovstanislav --- docs/config_guidebook.md | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/docs/config_guidebook.md b/docs/config_guidebook.md index c37d0437..29b0e14b 100644 --- a/docs/config_guidebook.md +++ b/docs/config_guidebook.md @@ -939,6 +939,22 @@ Note: Please see the [4. Build with features](docs/build_guide.md) if you want to enable usb-host. +#### 2.13.7 USB Uas +USB Mass Storage Device that is based on the USB Attached Scsi (UAS) protocol. It should be attached to USB controller. + +Three properties can be set for USB Uas. + +* id: unique device id. +* file: the path of backend image file. +* media: the media type of storage. Possible values are `disk` or `cdrom`. If not set, default is `disk`. + +```shell +-device usb-uas,drive=,id= +-drive id=,file=[,media={disk|cdrom}],aio=off,direct=false +``` + +Note: "aio=off,direct=false" must be configured and other aio/direct values are not supported. + ### 2.14 Virtio Scsi Controller Virtio Scsi controller is a pci device which can be attached scsi device. -- Gitee From aca47a010af04f30b52e677b2ff2a22ffbb196cf Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Thu, 18 Apr 2024 18:47:08 +0300 Subject: [PATCH 406/489] usb: Implement Debug for UsbDeviceRequest Make debug output for usb device request more comprehensible. Signed-off-by: goriainovstanislav --- devices/src/usb/config.rs | 2 ++ devices/src/usb/mod.rs | 62 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/devices/src/usb/config.rs b/devices/src/usb/config.rs index 1b34345f..776efb95 100644 --- a/devices/src/usb/config.rs +++ b/devices/src/usb/config.rs @@ -155,6 +155,8 @@ pub const USB_RECIPIENT_DEVICE: u8 = 0; pub const USB_RECIPIENT_INTERFACE: u8 = 1; pub const USB_RECIPIENT_ENDPOINT: u8 = 2; pub const USB_RECIPIENT_OTHER: u8 = 3; +pub const USB_TYPE_MASK: u8 = 3 << 5; +pub const USB_RECIPIENT_MASK: u8 = 0x1F; /// USB device request combination pub const USB_DEVICE_IN_REQUEST: u8 = diff --git a/devices/src/usb/mod.rs b/devices/src/usb/mod.rs index ff4927f9..110152b8 100644 --- a/devices/src/usb/mod.rs +++ b/devices/src/usb/mod.rs @@ -65,7 +65,7 @@ pub enum UsbPacketStatus { /// USB request used to transfer to USB device. #[repr(C)] -#[derive(Debug, Copy, Clone, PartialEq, Eq, Default)] +#[derive(Copy, Clone, PartialEq, Eq, Default)] pub struct UsbDeviceRequest { pub request_type: u8, pub request: u8, @@ -76,6 +76,66 @@ pub struct UsbDeviceRequest { impl ByteCode for UsbDeviceRequest {} +impl std::fmt::Debug for UsbDeviceRequest { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("UsbDeviceRequest") + .field("request_type", &parse_request_type(self.request_type)) + .field("request", &parse_request(self.request)) + .field("value", &self.value) + .field("index", &self.index) + .field("length", &self.length) + .finish() + } +} + +fn parse_request_type(request_type: u8) -> String { + let mut ret = "".to_string(); + + match request_type & USB_DIRECTION_DEVICE_TO_HOST { + USB_DIRECTION_DEVICE_TO_HOST => ret.push_str("IN"), + _ => ret.push_str("OUT"), + } + + ret.push(' '); + + match request_type & USB_TYPE_MASK { + USB_TYPE_STANDARD => ret.push_str("STD"), + USB_TYPE_CLASS => ret.push_str("CLASS"), + USB_TYPE_VENDOR => ret.push_str("VEND"), + _ => ret.push_str("RSVD"), + } + + ret.push(' '); + + match request_type & USB_RECIPIENT_MASK { + USB_RECIPIENT_DEVICE => ret.push_str("DEV"), + USB_RECIPIENT_INTERFACE => ret.push_str("IFACE"), + USB_RECIPIENT_ENDPOINT => ret.push_str("EP"), + _ => ret.push_str("OTHER"), + } + + ret +} + +fn parse_request(request: u8) -> String { + match request { + USB_REQUEST_GET_STATUS => "GET STAT".to_string(), + USB_REQUEST_CLEAR_FEATURE => "CLR FEAT".to_string(), + USB_REQUEST_SET_FEATURE => "SET FEAT".to_string(), + USB_REQUEST_SET_ADDRESS => "SET ADDR".to_string(), + USB_REQUEST_GET_DESCRIPTOR => "GET DESC".to_string(), + USB_REQUEST_SET_DESCRIPTOR => "SET DESC".to_string(), + USB_REQUEST_GET_CONFIGURATION => "GET CONF".to_string(), + USB_REQUEST_SET_CONFIGURATION => "SET CONF".to_string(), + USB_REQUEST_GET_INTERFACE => "GET IFACE".to_string(), + USB_REQUEST_SET_INTERFACE => "SET IFACE".to_string(), + USB_REQUEST_SYNCH_FRAME => "SYN FRAME".to_string(), + USB_REQUEST_SET_SEL => "SET SEL".to_string(), + USB_REQUEST_SET_ISOCH_DELAY => "SET ISO DEL".to_string(), + _ => format!("UNKNOWN {}", request), + } +} + /// The data transmission channel. #[derive(Default, Clone, Copy)] pub struct UsbEndpoint { -- Gitee From 3e66dfbb9d2e0f937be59fc630405456f85cb274 Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Tue, 23 Apr 2024 11:58:08 +0300 Subject: [PATCH 407/489] usb: Support arbitrary capability descriptors for super speed devices Now super speed USB devices can set custom capability descriptors via set_capability_descriptors. Signed-off-by: goriainovstanislav --- devices/src/usb/descriptor.rs | 44 ++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 14 deletions(-) diff --git a/devices/src/usb/descriptor.rs b/devices/src/usb/descriptor.rs index 956dc3e9..55858cd4 100644 --- a/devices/src/usb/descriptor.rs +++ b/devices/src/usb/descriptor.rs @@ -132,7 +132,7 @@ impl ByteCode for UsbBOSDescriptor {} #[allow(non_snake_case)] #[repr(C, packed)] #[derive(Copy, Clone, Debug, Default)] -struct UsbSuperSpeedCapDescriptor { +pub struct UsbSuperSpeedCapDescriptor { pub bLength: u8, pub bDescriptorType: u8, pub bDevCapabilityType: u8, @@ -221,6 +221,7 @@ pub struct UsbDescriptor { pub altsetting: Vec, pub interface_number: u32, pub strings: Vec, + pub capabilities: Vec, } impl UsbDescriptor { @@ -232,6 +233,7 @@ impl UsbDescriptor { altsetting: vec![0; USB_MAX_INTERFACES as usize], interface_number: 0, strings: Vec::new(), + capabilities: Vec::new(), } } @@ -374,20 +376,27 @@ impl UsbDescriptor { let mut cap_num = 0; if speed == USB_SPEED_SUPER { - let super_cap = UsbSuperSpeedCapDescriptor { - bLength: USB_DT_SS_CAP_SIZE, - bDescriptorType: USB_DT_DEVICE_CAPABILITY, - bDevCapabilityType: USB_SS_DEVICE_CAP, - bmAttributes: 0, - wSpeedsSupported: USB_SS_DEVICE_SPEED_SUPPORTED_SUPER, - bFunctionalitySupport: USB_SS_DEVICE_FUNCTIONALITY_SUPPORT_SUPER, - bU1DevExitLat: 0xa, - wU2DevExitLat: 0x20, + let default_cap = if self.capabilities.is_empty() { + vec![UsbSuperSpeedCapDescriptor { + bLength: USB_DT_SS_CAP_SIZE, + bDescriptorType: USB_DT_DEVICE_CAPABILITY, + bDevCapabilityType: USB_SS_DEVICE_CAP, + bmAttributes: 0, + wSpeedsSupported: USB_SS_DEVICE_SPEED_SUPPORTED_SUPER, + bFunctionalitySupport: USB_SS_DEVICE_FUNCTIONALITY_SUPPORT_SUPER, + bU1DevExitLat: 0xa, + wU2DevExitLat: 0x20, + }] + } else { + Vec::new() }; - let mut super_buf = super_cap.as_bytes().to_vec(); - cap_num += 1; - total += super_buf.len() as u16; - cap.append(&mut super_buf); + + for desc in default_cap.iter().chain(self.capabilities.iter()) { + let mut super_buf = (*desc).as_bytes().to_vec(); + cap_num += 1; + total += super_buf.len() as u16; + cap.append(&mut super_buf); + } } let bos = UsbBOSDescriptor { @@ -443,6 +452,9 @@ pub trait UsbDescriptorOps { /// Set interface descriptor with the Interface and Alternate Setting. fn set_interface_descriptor(&mut self, index: u32, v: u32) -> Result<()>; + /// Set super speed capability descriptors. + fn set_capability_descriptors(&mut self, caps: Vec); + /// Init all endpoint descriptors and reset the USB endpoint. fn init_endpoint(&mut self) -> Result<()>; @@ -517,6 +529,10 @@ impl UsbDescriptorOps for UsbDeviceBase { Ok(()) } + fn set_capability_descriptors(&mut self, caps: Vec) { + self.descriptor.capabilities = caps; + } + fn init_endpoint(&mut self) -> Result<()> { self.reset_usb_endpoint(); for i in 0..self.descriptor.interface_number { -- Gitee From c854bf4959bbf5b83b3a2c5bee47bc738aae41e3 Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Tue, 23 Apr 2024 11:53:06 +0300 Subject: [PATCH 408/489] uas: Support real BOT interface for UAS alternate setting Replace fake BOT interface hack with a real BOT interface as UAS alternate setting. Usb-uas device now supports both protocols. Signed-off-by: goriainovstanislav --- devices/src/usb/config.rs | 2 + devices/src/usb/storage.rs | 75 ++++++++-------- devices/src/usb/uas.rs | 172 ++++++++++++++++++++++++++++++------- machine/src/lib.rs | 2 +- 4 files changed, 185 insertions(+), 66 deletions(-) diff --git a/devices/src/usb/config.rs b/devices/src/usb/config.rs index 776efb95..aef89932 100644 --- a/devices/src/usb/config.rs +++ b/devices/src/usb/config.rs @@ -213,7 +213,9 @@ pub const USB_DT_ENDPOINT_COMPANION: u8 = 48; /// USB SuperSpeed Device Capability. pub const USB_SS_DEVICE_CAP: u8 = 0x3; +pub const USB_SS_DEVICE_SPEED_SUPPORTED_HIGH: u16 = 1 << 2; pub const USB_SS_DEVICE_SPEED_SUPPORTED_SUPER: u16 = 1 << 3; +pub const USB_SS_DEVICE_FUNCTIONALITY_SUPPORT_HIGH: u8 = 2; pub const USB_SS_DEVICE_FUNCTIONALITY_SUPPORT_SUPER: u8 = 3; /// USB Descriptor size diff --git a/devices/src/usb/storage.rs b/devices/src/usb/storage.rs index bec30977..aaa04aa0 100644 --- a/devices/src/usb/storage.rs +++ b/devices/src/usb/storage.rs @@ -233,9 +233,9 @@ pub struct UsbStorageConfig { #[arg(long)] pub drive: String, #[arg(long)] - bus: Option, + pub(super) bus: Option, #[arg(long)] - port: Option, + pub(super) port: Option, } /// USB storage device. @@ -346,7 +346,42 @@ impl UsbStorage { }) } - fn handle_control_packet(&mut self, packet: &mut UsbPacket, device_req: &UsbDeviceRequest) { + pub fn do_realize(&mut self) -> Result<()> { + self.base.reset_usb_endpoint(); + self.base.speed = USB_SPEED_HIGH; + let mut s: Vec = DESC_STRINGS.iter().map(|&s| s.to_string()).collect(); + let prefix = &s[STR_SERIAL_STORAGE_INDEX as usize]; + s[STR_SERIAL_STORAGE_INDEX as usize] = self.base.generate_serial_number(prefix); + self.base.init_descriptor(DESC_DEVICE_STORAGE.clone(), s)?; + + // NOTE: "aio=off,direct=false" must be configured and other aio/direct values are not + // supported. + let scsidev_classtype = match self.drive_cfg.media.as_str() { + "disk" => "scsi-hd".to_string(), + _ => "scsi-cd".to_string(), + }; + let scsi_dev_cfg = ScsiDevConfig { + classtype: scsidev_classtype, + drive: self.dev_cfg.drive.clone(), + ..Default::default() + }; + let scsi_device = ScsiDevice::new( + scsi_dev_cfg, + self.drive_cfg.clone(), + self.drive_files.clone(), + None, + self.scsi_bus.clone(), + ); + let realized_scsi = scsi_device.realize()?; + self.scsi_dev = Some(realized_scsi.clone()); + + self.scsi_bus + .lock() + .unwrap() + .attach_child(get_scsi_key(0, 0), realized_scsi) + } + + pub fn handle_control_packet(&mut self, packet: &mut UsbPacket, device_req: &UsbDeviceRequest) { match device_req.request_type { USB_ENDPOINT_OUT_REQUEST => { if device_req.request == USB_REQUEST_CLEAR_FEATURE { @@ -534,39 +569,7 @@ impl UsbDevice for UsbStorage { gen_base_func!(usb_device_base, usb_device_base_mut, UsbDeviceBase, base); fn realize(mut self) -> Result>> { - self.base.reset_usb_endpoint(); - self.base.speed = USB_SPEED_HIGH; - let mut s: Vec = DESC_STRINGS.iter().map(|&s| s.to_string()).collect(); - let prefix = &s[STR_SERIAL_STORAGE_INDEX as usize]; - s[STR_SERIAL_STORAGE_INDEX as usize] = self.base.generate_serial_number(prefix); - self.base.init_descriptor(DESC_DEVICE_STORAGE.clone(), s)?; - - // NOTE: "aio=off,direct=false" must be configured and other aio/direct values are not - // supported. - let scsidev_classtype = match self.drive_cfg.media.as_str() { - "disk" => "scsi-hd".to_string(), - _ => "scsi-cd".to_string(), - }; - let scsi_dev_cfg = ScsiDevConfig { - classtype: scsidev_classtype, - drive: self.dev_cfg.drive.clone(), - ..Default::default() - }; - let scsi_device = ScsiDevice::new( - scsi_dev_cfg, - self.drive_cfg.clone(), - self.drive_files.clone(), - None, - self.scsi_bus.clone(), - ); - let realized_scsi = scsi_device.realize()?; - self.scsi_dev = Some(realized_scsi.clone()); - - self.scsi_bus - .lock() - .unwrap() - .attach_child(get_scsi_key(0, 0), realized_scsi)?; - + self.do_realize()?; let storage: Arc> = Arc::new(Mutex::new(self)); Ok(storage) } diff --git a/devices/src/usb/uas.rs b/devices/src/usb/uas.rs index 04ce8745..301dff08 100644 --- a/devices/src/usb/uas.rs +++ b/devices/src/usb/uas.rs @@ -27,8 +27,9 @@ use super::config::*; use super::descriptor::{ UsbConfigDescriptor, UsbDescConfig, UsbDescDevice, UsbDescEndpoint, UsbDescIface, UsbDescriptorOps, UsbDeviceDescriptor, UsbEndpointDescriptor, UsbInterfaceDescriptor, - UsbSuperSpeedEndpointCompDescriptor, + UsbSuperSpeedCapDescriptor, UsbSuperSpeedEndpointCompDescriptor, }; +use super::storage::{UsbStorage, UsbStorageConfig, GET_MAX_LUN, MASS_STORAGE_RESET}; use super::xhci::xhci_controller::XhciDevice; use super::{ UsbDevice, UsbDeviceBase, UsbDeviceRequest, UsbPacket, UsbPacketStatus, @@ -42,8 +43,8 @@ use crate::ScsiBus::{ use crate::ScsiDisk::{ScsiDevConfig, ScsiDevice}; use crate::{Bus, Device}; use machine_manager::config::{DriveConfig, DriveFile}; -use util::byte_code::ByteCode; use util::gen_base_func; +use util::{aio::AioEngine, byte_code::ByteCode}; // Size of UasIUBody const UAS_IU_BODY_SIZE: usize = 30; @@ -87,6 +88,10 @@ const _UAS_TMF_QUERY_TASK: u8 = 0x80; const _UAS_TMF_QUERY_TASK_SET: u8 = 0x81; const _UAS_TMF_QUERY_ASYNC_EVENT: u8 = 0x82; +// Interface alt settings +const UAS_ALT_SETTING_BOT: u8 = 0; +const UAS_ALT_SETTING_UAS: u8 = 1; + #[derive(Parser, Clone, Debug)] #[command(no_binary_name(true))] pub struct UsbUasConfig { @@ -95,15 +100,25 @@ pub struct UsbUasConfig { #[arg(long)] pub drive: String, #[arg(long)] - pub id: Option, - #[arg(long)] - pub speed: Option, + pub id: String, #[arg(long)] bus: Option, #[arg(long)] port: Option, } +impl From for UsbStorageConfig { + fn from(uas_config: UsbUasConfig) -> Self { + Self { + classtype: uas_config.classtype, + id: String::new(), + drive: uas_config.drive, + bus: uas_config.bus, + port: uas_config.port, + } + } +} + pub struct UsbUas { base: UsbDeviceBase, uas_config: UsbUasConfig, @@ -114,6 +129,8 @@ pub struct UsbUas { commands: [Option; UAS_MAX_STREAMS + 1], statuses: [Option>>; UAS_MAX_STREAMS + 1], data: [Option>>; UAS_MAX_STREAMS + 1], + bot: UsbStorage, + is_bot: bool, } #[derive(Debug, Default, EnumCount)] @@ -296,7 +313,7 @@ static DESC_IFACE_UAS: Lazy> = Lazy::new(|| { bLength: USB_DT_INTERFACE_SIZE, bDescriptorType: USB_DT_INTERFACE, bInterfaceNumber: 0, - bAlternateSetting: 1, + bAlternateSetting: UAS_ALT_SETTING_UAS, bNumEndpoints: 4, bInterfaceClass: USB_CLASS_MASS_STORAGE, bInterfaceSubClass: USB_SUBCLASS_SCSI, @@ -425,27 +442,74 @@ static DESC_IFACE_UAS: Lazy> = Lazy::new(|| { }) }); -// NOTE: Fake BOT interface descriptor is needed here since Windows UASP driver always expects two -// interfaces: both BOT and UASP. It also anticipates the UASP descriptor to be the second one. -// Therefore, the first one can be a BOT storage stub. static DESC_IFACE_BOT: Lazy> = Lazy::new(|| { Arc::new(UsbDescIface { interface_desc: UsbInterfaceDescriptor { bLength: USB_DT_INTERFACE_SIZE, bDescriptorType: USB_DT_INTERFACE, bInterfaceNumber: 0, - bAlternateSetting: 0, - bNumEndpoints: 0, + bAlternateSetting: UAS_ALT_SETTING_BOT, + bNumEndpoints: 2, bInterfaceClass: USB_CLASS_MASS_STORAGE, bInterfaceSubClass: USB_SUBCLASS_SCSI, bInterfaceProtocol: USB_IFACE_PROTOCOL_BOT, iInterface: 0, }, other_desc: vec![], - endpoints: vec![], + endpoints: vec![ + Arc::new(UsbDescEndpoint { + endpoint_desc: UsbEndpointDescriptor { + bLength: USB_DT_ENDPOINT_SIZE, + bDescriptorType: USB_DT_ENDPOINT, + bEndpointAddress: USB_DIRECTION_DEVICE_TO_HOST | 0x01, + bmAttributes: USB_ENDPOINT_ATTR_BULK, + wMaxPacketSize: 1024, + bInterval: 0, + }, + extra: UsbSuperSpeedEndpointCompDescriptor { + bLength: USB_DT_SS_EP_COMP_SIZE, + bDescriptorType: USB_DT_ENDPOINT_COMPANION, + bMaxBurst: 15, + bmAttributes: 0, + wBytesPerInterval: 0, + } + .as_bytes() + .to_vec(), + }), + Arc::new(UsbDescEndpoint { + endpoint_desc: UsbEndpointDescriptor { + bLength: USB_DT_ENDPOINT_SIZE, + bDescriptorType: USB_DT_ENDPOINT, + bEndpointAddress: USB_DIRECTION_HOST_TO_DEVICE | 0x02, + bmAttributes: USB_ENDPOINT_ATTR_BULK, + wMaxPacketSize: 1024, + bInterval: 0, + }, + extra: UsbSuperSpeedEndpointCompDescriptor { + bLength: USB_DT_SS_EP_COMP_SIZE, + bDescriptorType: USB_DT_ENDPOINT_COMPANION, + bMaxBurst: 15, + bmAttributes: 0, + wBytesPerInterval: 0, + } + .as_bytes() + .to_vec(), + }), + ], }) }); +static DESC_CAP_UAS: UsbSuperSpeedCapDescriptor = UsbSuperSpeedCapDescriptor { + bLength: USB_DT_SS_CAP_SIZE, + bDescriptorType: USB_DT_DEVICE_CAPABILITY, + bDevCapabilityType: USB_SS_DEVICE_CAP, + bmAttributes: 0, + wSpeedsSupported: USB_SS_DEVICE_SPEED_SUPPORTED_SUPER | USB_SS_DEVICE_SPEED_SUPPORTED_HIGH, + bFunctionalitySupport: USB_SS_DEVICE_FUNCTIONALITY_SUPPORT_HIGH, + bU1DevExitLat: 0xA, + wU2DevExitLat: 0x20, +}; + fn complete_async_packet(packet: &Arc>) { let locked_packet = packet.lock().unwrap(); @@ -462,21 +526,24 @@ impl UsbUas { uas_config: UsbUasConfig, drive_cfg: DriveConfig, drive_files: Arc>>, - ) -> Self { - Self { - base: UsbDeviceBase::new( - uas_config.id.as_ref().unwrap().clone(), - USB_DEVICE_BUFFER_DEFAULT_LEN, - ), - uas_config, + ) -> Result { + if drive_cfg.aio != AioEngine::Off || drive_cfg.direct { + bail!("USB UAS: \"aio=off,direct=false\" must be configured."); + } + + Ok(Self { + base: UsbDeviceBase::new(uas_config.id.clone(), USB_DEVICE_BUFFER_DEFAULT_LEN), + uas_config: uas_config.clone(), scsi_bus: Arc::new(Mutex::new(ScsiBus::new("".to_string()))), scsi_device: None, - drive_cfg, - drive_files, + drive_cfg: drive_cfg.clone(), + drive_files: drive_files.clone(), commands: array::from_fn(|_| None), statuses: array::from_fn(|_| None), data: array::from_fn(|_| None), - } + bot: UsbStorage::new(uas_config.into(), drive_cfg, drive_files)?, + is_bot: true, + }) } fn cancel_io(&mut self) { @@ -485,6 +552,43 @@ impl UsbUas { self.data = array::from_fn(|_| None); } + /// Class (Mass Storage) specific requests. + fn handle_control_for_device(&mut self, packet: &mut UsbPacket, device_req: &UsbDeviceRequest) { + match device_req.request_type { + USB_ENDPOINT_OUT_REQUEST => { + if device_req.request == USB_REQUEST_CLEAR_FEATURE { + return; + } + } + USB_INTERFACE_CLASS_OUT_REQUEST => { + // NOTE: See USB Mass Storage Class specification: 3.1 Bulk-Only Mass Storage Reset + if device_req.request == MASS_STORAGE_RESET { + // Set storage state mode. + self.bot.handle_control_packet(packet, device_req); + self.cancel_io(); + return; + } + } + USB_INTERFACE_CLASS_IN_REQUEST => { + // NOTE: See USB Mass Storage Class specification: 3.2 Get Max LUN + if device_req.request == GET_MAX_LUN { + // Now only supports 1 LUN. + self.base.data_buf[0] = 0; + packet.actual_length = 1; + return; + } + } + _ => (), + } + + error!( + "UAS {} device unhandled control request {:?}.", + self.device_id(), + device_req + ); + packet.status = UsbPacketStatus::Stall; + } + fn handle_iu_command( &mut self, iu: &UasIU, @@ -732,7 +836,7 @@ impl UsbUas { match result { Ok(result) => result, Err(err) => { - error!("UAS {} device error: {:#?}.", self.device_id(), err); + error!("UAS {} device error: {:?}.", self.device_id(), err); UasPacketStatus::Completed } } @@ -750,6 +854,7 @@ impl UsbDevice for UsbUas { let prefix = &s[UsbUasStringId::SerialNumber as usize]; s[UsbUasStringId::SerialNumber as usize] = self.base.generate_serial_number(prefix); self.base.init_descriptor(DESC_DEVICE_UAS.clone(), s)?; + self.base.set_capability_descriptors(vec![DESC_CAP_UAS]); // NOTE: "aio=off,direct=false" must be configured and other aio/direct values are not // supported. @@ -775,6 +880,8 @@ impl UsbDevice for UsbUas { .lock() .unwrap() .attach_child(get_scsi_key(0, 0), realized_scsi)?; + + self.bot.do_realize()?; let uas = Arc::new(Mutex::new(self)); Ok(uas) } @@ -788,6 +895,8 @@ impl UsbDevice for UsbUas { self.base.remote_wakeup = 0; self.base.addr = 0; self.cancel_io(); + // Reset storage state. + self.bot.reset(); } fn handle_control(&mut self, packet: &Arc>, device_req: &UsbDeviceRequest) { @@ -798,6 +907,12 @@ impl UsbDevice for UsbUas { device_req.as_bytes(), ); + if device_req.request_type == USB_INTERFACE_OUT_REQUEST + && device_req.request == USB_REQUEST_SET_INTERFACE + { + self.is_bot = device_req.value != UAS_ALT_SETTING_UAS as u16; + } + match self .base .handle_control_for_descriptor(&mut locked_packet, device_req) @@ -811,12 +926,7 @@ impl UsbDevice for UsbUas { return; } - error!( - "UAS {} device unhandled control request {:?}.", - self.device_id(), - device_req - ); - locked_packet.status = UsbPacketStatus::Stall; + self.handle_control_for_device(&mut locked_packet, device_req); } Err(err) => { warn!( @@ -830,6 +940,10 @@ impl UsbDevice for UsbUas { } fn handle_data(&mut self, packet: &Arc>) { + if self.is_bot { + return self.bot.handle_data(packet); + } + let locked_packet = packet.lock().unwrap(); let stream = locked_packet.stream as usize; let ep_number = locked_packet.ep_number; diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 484aaf25..8ec8ad77 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -1872,7 +1872,7 @@ pub trait MachineOps: MachineLifecycle { .drives .remove(&device_cfg.drive) .with_context(|| "No drive configured matched for usb uas device.")?; - let uas = UsbUas::new(device_cfg, drive_cfg, self.get_drive_files()); + let uas = UsbUas::new(device_cfg, drive_cfg, self.get_drive_files())?; uas.realize() .with_context(|| "Failed to realize usb uas device")? } -- Gitee From d16b2f2ea07bf4c4de201f0f8d21780e04c84424 Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Tue, 21 May 2024 15:42:22 +0300 Subject: [PATCH 409/489] uas: Support USB UAS device hotplug with qmp commands Add usb-uas entry for USB hotplug. Signed-off-by: goriainovstanislav --- machine/src/standard_common/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index b493c6f4..f33b8b18 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -1279,7 +1279,7 @@ impl DeviceInterface for StdMachine { ); } } - "usb-kbd" | "usb-tablet" | "usb-camera" | "usb-host" | "usb-storage" => { + "usb-kbd" | "usb-tablet" | "usb-camera" | "usb-host" | "usb-storage" | "usb-uas" => { let cfg_args = locked_vmconfig.add_device_config(args.as_ref()); if let Err(e) = self.add_usb_device(&mut vm_config_clone, &cfg_args) { error!("{:?}", e); -- Gitee From ec7c9ee24060d1fce1f5f4416539a3b94587570a Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Mon, 14 Oct 2024 15:13:07 +0300 Subject: [PATCH 410/489] list: Implement len, is_empty, iter and iter_mut for List Implement useful methods for List and change existing code to use them. This ensures encapsulation and makes code much more readable. Signed-off-by: goriainovstanislav --- devices/src/usb/usbhost/mod.rs | 10 ++-- machine/src/standard_common/mod.rs | 2 +- tests/mod_test/tests/net_test.rs | 2 +- util/src/aio/mod.rs | 6 +-- util/src/link_list.rs | 76 +++++++++++++++++++++++++++++- util/src/thread_pool.rs | 8 ++-- vfio/src/vfio_pci.rs | 2 +- 7 files changed, 88 insertions(+), 18 deletions(-) diff --git a/devices/src/usb/usbhost/mod.rs b/devices/src/usb/usbhost/mod.rs index bc79fd38..17a888a5 100644 --- a/devices/src/usb/usbhost/mod.rs +++ b/devices/src/usb/usbhost/mod.rs @@ -843,18 +843,14 @@ impl UsbHost { } pub fn abort_host_transfers(&mut self) -> Result<()> { - let mut locked_requests = self.requests.lock().unwrap(); - for _i in 0..locked_requests.len { - let mut node = locked_requests.pop_head().unwrap(); - node.value.abort_req(); - locked_requests.add_tail(node); + for req in self.requests.lock().unwrap().iter_mut() { + req.abort_req(); } - drop(locked_requests); // Max counts of uncompleted request to be handled. let mut limit: i32 = 100; loop { - if self.requests.lock().unwrap().len == 0 { + if self.requests.lock().unwrap().is_empty() { return Ok(()); } let timeout = Some(Duration::from_millis(HANDLE_TIMEOUT_MS)); diff --git a/machine/src/standard_common/mod.rs b/machine/src/standard_common/mod.rs index f33b8b18..7ac6bcbb 100644 --- a/machine/src/standard_common/mod.rs +++ b/machine/src/standard_common/mod.rs @@ -1878,7 +1878,7 @@ impl DeviceInterface for StdMachine { } let qcow2_list = QCOW2_LIST.lock().unwrap(); - if qcow2_list.len() == 0 { + if qcow2_list.is_empty() { return Response::create_response( serde_json::to_value("There is no snapshot available.\r\n").unwrap(), None, diff --git a/tests/mod_test/tests/net_test.rs b/tests/mod_test/tests/net_test.rs index 19fba808..34ffe1d3 100644 --- a/tests/mod_test/tests/net_test.rs +++ b/tests/mod_test/tests/net_test.rs @@ -332,7 +332,7 @@ impl ByteCode for VirtioNetHdr {} fn execute_cmd(cmd: String, check: bool) { let args = cmd.split(' ').collect::>(); - if args.len() <= 0 { + if args.is_empty() { return; } diff --git a/util/src/aio/mod.rs b/util/src/aio/mod.rs index 4422bc7f..100dd018 100644 --- a/util/src/aio/mod.rs +++ b/util/src/aio/mod.rs @@ -663,10 +663,10 @@ impl Aio { warn!("Can not process aio list with invalid ctx."); return Ok(()); } - while self.aio_in_queue.len > 0 && self.aio_in_flight.len < self.max_events { + while !self.aio_in_queue.is_empty() && self.aio_in_flight.len() < self.max_events { let mut iocbs = Vec::new(); - for _ in self.aio_in_flight.len..self.max_events { + for _ in self.aio_in_flight.len()..self.max_events { match self.aio_in_queue.pop_tail() { Some(node) => { iocbs.push(&node.value as *const AioCb); @@ -729,7 +729,7 @@ impl Aio { self.aio_in_queue.add_head(node); self.incomplete_cnt.fetch_add(1, Ordering::SeqCst); - if self.aio_in_queue.len + self.aio_in_flight.len >= self.max_events { + if self.aio_in_queue.len() + self.aio_in_flight.len() >= self.max_events { self.process_list()?; } diff --git a/util/src/link_list.rs b/util/src/link_list.rs index 264b5d6f..a779bce1 100644 --- a/util/src/link_list.rs +++ b/util/src/link_list.rs @@ -23,7 +23,7 @@ pub struct Node { pub struct List { head: Option>>, tail: Option>>, - pub len: usize, + len: usize, marker: PhantomData>>, } @@ -139,4 +139,78 @@ impl List { node }) } + + #[inline(always)] + pub fn len(&self) -> usize { + self.len + } + + #[inline(always)] + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + #[inline(always)] + pub fn iter(&'_ self) -> impl Iterator { + Iter::new(self) + } + + #[inline(always)] + pub fn iter_mut(&'_ mut self) -> impl Iterator { + IterMut::new(self) + } +} + +struct Iter<'a, T> { + curr: Option>>, + list: PhantomData<&'a List>, +} + +impl<'a, T> Iter<'a, T> { + fn new(list: &'a List) -> Self { + Self { + curr: list.head, + list: PhantomData, + } + } +} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = &'a T; + + fn next(&mut self) -> Option { + self.curr.map(|node| { + // SAFETY: node is guaranteed not to be null. + let node = unsafe { node.as_ref() }; + self.curr = node.next; + &node.value + }) + } +} + +struct IterMut<'a, T> { + curr: Option>>, + list: PhantomData<&'a mut List>, +} + +impl<'a, T> IterMut<'a, T> { + fn new(list: &'a mut List) -> Self { + Self { + curr: list.head, + list: PhantomData, + } + } +} + +impl<'a, T> Iterator for IterMut<'a, T> { + type Item = &'a mut T; + + fn next(&mut self) -> Option { + self.curr.map(|mut node| { + // SAFETY: node is guaranteed not to be null. + let node = unsafe { node.as_mut() }; + self.curr = node.next; + &mut node.value + }) + } } diff --git a/util/src/thread_pool.rs b/util/src/thread_pool.rs index 570d4256..63c8891d 100644 --- a/util/src/thread_pool.rs +++ b/util/src/thread_pool.rs @@ -167,7 +167,7 @@ fn worker_thread(pool: Arc) { while locked_state.is_running() { let result; - if locked_state.req_lists.len == 0 { + if locked_state.req_lists.is_empty() { locked_state.blocked_threads += 1; match pool .request_cond @@ -186,7 +186,7 @@ fn worker_thread(pool: Arc) { locked_state.blocked_threads -= 1; if result.timed_out() - && locked_state.req_lists.len == 0 + && locked_state.req_lists.is_empty() && locked_state.total_threads > locked_state.min_threads { // If wait time_out and no pending task and current total number @@ -205,7 +205,7 @@ fn worker_thread(pool: Arc) { locked_state = pool.pool_state.lock().unwrap(); } locked_state.total_threads -= 1; - trace::thread_pool_exit_thread(&locked_state.total_threads, &locked_state.req_lists.len); + trace::thread_pool_exit_thread(&locked_state.total_threads, &locked_state.req_lists.len()); pool.stop_cond.notify_one(); pool.request_cond.notify_one(); @@ -243,7 +243,7 @@ mod test { } // Waiting for creating. - while pool.pool_state.lock().unwrap().req_lists.len != 0 { + while !pool.pool_state.lock().unwrap().req_lists.is_empty() { thread::sleep(time::Duration::from_millis(10)); let now = time::SystemTime::now(); diff --git a/vfio/src/vfio_pci.rs b/vfio/src/vfio_pci.rs index aea7891c..d4c0dfee 100644 --- a/vfio/src/vfio_pci.rs +++ b/vfio/src/vfio_pci.rs @@ -723,7 +723,7 @@ impl VfioPciDevice { fn vfio_enable_msix(&mut self) -> Result<()> { let mut gsi_routes = self.gsi_msi_routes.lock().unwrap(); - if gsi_routes.len() == 0 { + if gsi_routes.is_empty() { let irq_fd = create_new_eventfd().unwrap(); let gsi_route = GsiMsiRoute { irq_fd: Some(Arc::new(irq_fd)), -- Gitee From 9db97faa68b5dfacd662ad117ab1c651ea042811 Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Mon, 7 Oct 2024 16:47:17 +0300 Subject: [PATCH 411/489] thread_pool: Change ThreadPool to use std::LinkedList Use standard linked list implementation in thread pool because it doesn't require extra Box wrapping and provides more features. Signed-off-by: goriainovstanislav --- util/src/thread_pool.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/util/src/thread_pool.rs b/util/src/thread_pool.rs index 63c8891d..48ac9af9 100644 --- a/util/src/thread_pool.rs +++ b/util/src/thread_pool.rs @@ -10,6 +10,7 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. +use std::collections::LinkedList; use std::sync::{Arc, Condvar, Mutex}; use std::thread; use std::time::Duration; @@ -17,8 +18,6 @@ use std::time::Duration; use anyhow::{bail, Context, Result}; use log::error; -use crate::link_list::{List, Node}; - const MIN_THREADS: u64 = 1; const MAX_THREADS: u64 = 10; type PoolTask = Box; @@ -45,7 +44,7 @@ struct PoolState { /// The maximum number of threads that thread pool can create. max_threads: u64, /// List of pending tasks in the thread pool. - req_lists: List, + req_lists: LinkedList, } /// SAFETY: All the operations on req_lists are protected by the mutex, @@ -61,7 +60,7 @@ impl PoolState { pending_threads: 0, min_threads: MIN_THREADS, max_threads: MAX_THREADS, - req_lists: List::new(), + req_lists: LinkedList::new(), } } @@ -131,7 +130,7 @@ impl ThreadPool { if locked_state.spawn_thread_needed() { locked_state.spawn_thread(pool.clone())? } - locked_state.req_lists.add_tail(Box::new(Node::new(task))); + locked_state.req_lists.push_back(task); drop(locked_state); pool.request_cond.notify_one(); @@ -197,10 +196,10 @@ fn worker_thread(pool: Arc) { continue; } - let mut req = locked_state.req_lists.pop_head().unwrap(); + let mut req = locked_state.req_lists.pop_front().unwrap(); drop(locked_state); - (*req.value).run(); + req.run(); locked_state = pool.pool_state.lock().unwrap(); } -- Gitee From a7a69c5204d0ba9e050a45e2c7161e411920da8a Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Tue, 15 Oct 2024 20:26:37 +0800 Subject: [PATCH 412/489] ozonec/clone: Fallback to clone() when clone3() failed clone3() is introduced in Linux Kernel 5.3. --- ozonec/src/linux/container.rs | 8 ++++---- ozonec/src/linux/process.rs | 38 +++++++++++++++++++++++++++-------- ozonec/src/utils/clone.rs | 14 ++++++++----- 3 files changed, 43 insertions(+), 17 deletions(-) diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index a980fc08..f13475c5 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -127,7 +127,7 @@ impl LinuxContainer { process: &mut Process, parent_channel: &Channel, fst_stage_channel: &Channel, - notify_listener: Option, + notify_listener: &Option, ) -> Result<()> { debug!("First stage process start"); @@ -146,7 +146,7 @@ impl LinuxContainer { // Spawn a child process to perform the second stage to initialize container. let init_pid = clone_process("ozonec:[2:INIT]", || { - self.do_second_stage(process, parent_channel, notify_listener) + self.do_second_stage(process, parent_channel, ¬ify_listener) .with_context(|| "Second stage process encounters errors")?; Ok(0) })?; @@ -162,7 +162,7 @@ impl LinuxContainer { &mut self, process: &mut Process, parent_channel: &Channel, - notify_listener: Option, + notify_listener: &Option, ) -> Result<()> { debug!("Second stage process start"); @@ -677,7 +677,7 @@ impl Container for LinuxContainer { process, &parent_channel, &fst_stage_channel, - notify_listener, + ¬ify_listener, ) .with_context(|| "First stage process encounters errors")?; Ok(0) diff --git a/ozonec/src/linux/process.rs b/ozonec/src/linux/process.rs index ae3add0d..6215a24b 100644 --- a/ozonec/src/linux/process.rs +++ b/ozonec/src/linux/process.rs @@ -26,8 +26,10 @@ use std::{ use anyhow::{anyhow, bail, Context, Result}; use caps::{self, CapSet, Capability, CapsHashSet}; +use libc::SIGCHLD; use nix::{ errno::Errno, + sched::{clone, CloneFlags}, unistd::{self, chdir, setresgid, setresuid, Gid, Pid, Uid}, }; use rlimit::{setrlimit, Resource, Rlim}; @@ -324,15 +326,35 @@ impl Process { } // Clone a new child process. -pub fn clone_process Result>(child_name: &str, cb: F) -> Result { +pub fn clone_process Result>(child_name: &str, mut cb: F) -> Result { let mut clone3 = Clone3::default(); - clone3.exit_signal(libc::SIGCHLD as u64); + clone3.exit_signal(SIGCHLD as u64); + + let mut ret = clone3.call(); + if ret.is_err() { + // clone3() may not be supported in the kernel, fallback to clone(); + let mut stack = [0; 1024 * 1024]; + ret = clone( + Box::new(|| match cb() { + Ok(r) => r as isize, + Err(e) => { + eprintln!("{}", e); + -1 + } + }), + &mut stack, + CloneFlags::empty(), + Some(SIGCHLD), + ) + .map_err(|e| anyhow!("Clone error: errno {}", e)); + } + + match ret { + Ok(pid) => { + if pid.as_raw() != 0 { + return Ok(pid); + } - match clone3 - .call() - .map_err(|e| anyhow!("Clone3() error: {}", e))? - { - 0 => { prctl::set_name(child_name) .map_err(|e| anyhow!("Failed to set process name: errno {}", e))?; let ret = match cb() { @@ -344,7 +366,7 @@ pub fn clone_process Result>(child_name: &str, cb: F) -> Res }; std::process::exit(ret); } - pid => Ok(Pid::from_raw(pid)), + Err(e) => bail!(e), } } diff --git a/ozonec/src/utils/clone.rs b/ozonec/src/utils/clone.rs index 2476a2f3..2dd99e66 100644 --- a/ozonec/src/utils/clone.rs +++ b/ozonec/src/utils/clone.rs @@ -12,8 +12,9 @@ use std::os::unix::io::{AsRawFd, RawFd}; -use anyhow::{bail, Result}; -use nix::errno::errno; +use anyhow::{bail, Context, Result}; +use libc::pid_t; +use nix::{errno::errno, unistd::Pid}; bitflags::bitflags! { #[derive(Default)] @@ -92,7 +93,7 @@ impl<'a> Clone3<'a> { self } - pub fn call(&mut self) -> Result { + pub fn call(&mut self) -> Result { let clone_args = CloneArgs { flags: self.flags.bits(), pid_fd: option_as_mut_ptr(&mut self.pidfd) as u64, @@ -114,8 +115,11 @@ impl<'a> Clone3<'a> { ) }; if ret == -1 { - bail!("errno {}", errno()); + bail!("clone3 error: errno {}", errno()); } - Ok(ret as libc::pid_t) + + Ok(Pid::from_raw( + pid_t::try_from(ret).with_context(|| "Invalid pid")?, + )) } } -- Gitee From 4ef150140aa7d439488412d378c55fe4987eeff9 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Tue, 24 Sep 2024 07:56:52 +0800 Subject: [PATCH 413/489] ozonec/device: Add unit test cases --- ozonec/src/linux/device.rs | 198 +++++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) diff --git a/ozonec/src/linux/device.rs b/ozonec/src/linux/device.rs index 90575a07..a008fd0f 100644 --- a/ozonec/src/linux/device.rs +++ b/ozonec/src/linux/device.rs @@ -236,3 +236,201 @@ struct DeviceInfo { uid: Option, gid: Option, } + +#[cfg(test)] +mod tests { + use std::{ + fs, + os::unix::fs::{FileTypeExt, MetadataExt, PermissionsExt}, + }; + + use nix::mount::umount; + + use super::*; + + #[test] + fn test_mknod_dev() { + let rootfs = PathBuf::from("/tmp/ozonec/mknod_dev"); + create_dir_all(&rootfs).unwrap(); + let dev = Device::new(rootfs.clone()); + let path = rootfs.join("mknod_dev"); + if path.exists() { + remove_file(&path).unwrap(); + } + let dev_info = DeviceInfo { + path: path.clone(), + dev_type: "c".to_string(), + major: 1, + minor: 3, + file_mode: Some(0o644u32), + uid: Some(1000u32), + gid: Some(1000u32), + }; + + assert!(dev.mknod_device(&dev_info).is_ok()); + assert!(path.exists()); + + let metadata = fs::metadata(&path).unwrap(); + assert!(metadata.file_type().is_char_device()); + let major = (metadata.rdev() >> 8) as u32; + let minor = (metadata.rdev() & 0xff) as u32; + assert_eq!(major, 1); + assert_eq!(minor, 3); + let file_mode = metadata.permissions().mode(); + assert_eq!(file_mode & 0o777, 0o644u32); + assert_eq!(metadata.uid(), 1000); + assert_eq!(metadata.gid(), 1000); + + fs::remove_dir_all("/tmp/ozonec").unwrap(); + } + + #[test] + #[ignore = "mount may not be permitted"] + fn test_bind_dev() { + let rootfs = PathBuf::from("/tmp/ozonec/bind_dev"); + create_dir_all(&rootfs).unwrap(); + let dev_path = PathBuf::from("/mknod_dev"); + if dev_path.exists() { + remove_file(&dev_path).unwrap(); + } + let dev = makedev(1, 3); + mknod( + &dev_path, + SFlag::S_IFCHR, + Mode::from_bits_truncate(0o644u32), + dev, + ) + .unwrap(); + let dev_to_bind = Device::new(rootfs.clone()); + let binded_path = rootfs.join("mknod_dev"); + if binded_path.exists() { + umount(&binded_path).unwrap(); + remove_file(&binded_path).unwrap(); + } + let dev_info = DeviceInfo { + path: binded_path.clone(), + dev_type: "c".to_string(), + major: 1, + minor: 3, + file_mode: Some(0o644u32), + uid: Some(1000u32), + gid: Some(1000u32), + }; + + assert!(dev_to_bind.bind_device(&dev_info).is_ok()); + + let metadata = fs::metadata(&dev_path).unwrap(); + let binded_metadata = fs::metadata(&binded_path).unwrap(); + assert_eq!(binded_metadata.file_type(), metadata.file_type()); + assert_eq!(binded_metadata.rdev(), metadata.rdev()); + assert_eq!(binded_metadata.permissions(), metadata.permissions()); + assert_eq!(binded_metadata.uid(), metadata.uid()); + assert_eq!(binded_metadata.gid(), metadata.gid()); + + umount(&binded_path).unwrap(); + fs::remove_dir_all("/tmp/ozonec").unwrap(); + fs::remove_file(dev_path).unwrap(); + } + + #[test] + fn test_create_device() { + let oci_dev = OciDevice { + dev_type: "c".to_string(), + path: "/mknod_dev".to_string(), + major: Some(1), + minor: Some(3), + fileMode: Some(0o644u32), + uid: Some(1000), + gid: Some(1000), + }; + let rootfs = PathBuf::from("/tmp/ozonec/create_device"); + create_dir_all(&rootfs).unwrap(); + let path = rootfs.join("mknod_dev"); + if path.exists() { + remove_file(&path).unwrap(); + } + let dev = Device::new(rootfs.clone()); + + assert!(dev.create_device(&oci_dev, true).is_ok()); + assert!(path.exists()); + + let metadata = fs::metadata(&path).unwrap(); + assert!(metadata.file_type().is_char_device()); + let major = (metadata.rdev() >> 8) as u32; + let minor = (metadata.rdev() & 0xff) as u32; + assert_eq!(major, 1); + assert_eq!(minor, 3); + let file_mode = metadata.permissions().mode(); + assert_eq!(file_mode & 0o777, 0o644u32); + assert_eq!(metadata.uid(), 1000); + assert_eq!(metadata.gid(), 1000); + + fs::remove_dir_all("/tmp/ozonec").unwrap(); + } + + #[test] + fn test_delete_device() { + let oci_dev = OciDevice { + dev_type: "c".to_string(), + path: "/mknod_dev".to_string(), + major: Some(1), + minor: Some(3), + fileMode: Some(0o644u32), + uid: Some(1000), + gid: Some(1000), + }; + let rootfs = PathBuf::from("/tmp/ozonec/delete_device"); + create_dir_all(&rootfs).unwrap(); + let path = rootfs.join("mknod_dev"); + if path.exists() { + remove_file(&path).unwrap(); + } + let dev = Device::new(rootfs.clone()); + dev.create_device(&oci_dev, true).unwrap(); + + assert!(dev.delete_device(&oci_dev).is_ok()); + assert!(!path.exists()); + + fs::remove_dir_all("/tmp/ozonec").unwrap(); + } + + #[test] + fn test_default_device() { + let rootfs = PathBuf::from("/tmp/ozonec/default_device"); + let dev = Device::new(rootfs.clone()); + + let mut oci_dev = OciDevice { + dev_type: "c".to_string(), + path: "mknod_dev".to_string(), + major: Some(1), + minor: Some(3), + fileMode: Some(0o644u32), + uid: Some(1000), + gid: Some(1000), + }; + assert!(!dev.is_default_device(&oci_dev)); + oci_dev.path = "/dev/null".to_string(); + assert!(dev.is_default_device(&oci_dev)); + oci_dev.path = "/dev/zero".to_string(); + assert!(dev.is_default_device(&oci_dev)); + oci_dev.path = "/dev/full".to_string(); + assert!(dev.is_default_device(&oci_dev)); + oci_dev.path = "/dev/random".to_string(); + assert!(dev.is_default_device(&oci_dev)); + oci_dev.path = "/dev/urandom".to_string(); + assert!(dev.is_default_device(&oci_dev)); + oci_dev.path = "/dev/tty".to_string(); + assert!(dev.is_default_device(&oci_dev)); + } + + #[test] + fn test_get_sflag() { + let rootfs = PathBuf::from("/tmp/ozonec/test_get_sflag"); + let dev = Device::new(rootfs.clone()); + + assert_eq!(dev.get_sflag("c").unwrap(), SFlag::S_IFCHR); + assert_eq!(dev.get_sflag("b").unwrap(), SFlag::S_IFBLK); + assert_eq!(dev.get_sflag("p").unwrap(), SFlag::S_IFIFO); + assert_eq!(dev.get_sflag("u").unwrap(), SFlag::S_IFCHR); + } +} -- Gitee From f54363ff72d4893bea8bcbc3a1abee532a0eebba Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Tue, 24 Sep 2024 12:37:39 +0800 Subject: [PATCH 414/489] ozonec/mount: Add unit test cases --- ozonec/Cargo.lock | 103 +++++++++++++++++-- ozonec/Cargo.toml | 1 + ozonec/src/linux/mount.rs | 181 ++++++++++++++++++++++++++++++++++ ozonec/src/linux/namespace.rs | 17 ++++ 4 files changed, 294 insertions(+), 8 deletions(-) diff --git a/ozonec/Cargo.lock b/ozonec/Cargo.lock index 6274f9c4..b67a79bb 100644 --- a/ozonec/Cargo.lock +++ b/ozonec/Cargo.lock @@ -41,6 +41,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + [[package]] name = "bumpalo" version = "3.16.0" @@ -97,7 +103,7 @@ version = "4.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76" dependencies = [ - "bitflags", + "bitflags 1.3.2", "clap_derive", "clap_lex", "once_cell", @@ -150,6 +156,12 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "fastrand" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" + [[package]] name = "flate2" version = "1.0.31" @@ -160,6 +172,12 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + [[package]] name = "heck" version = "0.4.1" @@ -245,7 +263,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "21c57fd8981a80019807b7b68118618d29a87177c63d704fc96e6ecd003ae5b3" dependencies = [ - "bitflags", + "bitflags 1.3.2", "libc", "libseccomp-sys", "pkg-config", @@ -263,6 +281,12 @@ version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f051f77a7c8e6957c0696eac88f26b0117e54f52d3fc682ab19397a8812846a4" +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + [[package]] name = "log" version = "0.4.18" @@ -293,7 +317,7 @@ version = "0.26.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "libc", "memoffset", @@ -338,7 +362,7 @@ name = "ozonec" version = "0.1.0" dependencies = [ "anyhow", - "bitflags", + "bitflags 1.3.2", "caps", "chrono", "clap", @@ -349,6 +373,7 @@ dependencies = [ "oci_spec", "procfs", "rlimit", + "rusty-fork", "serde", "serde_json", "thiserror", @@ -405,15 +430,21 @@ version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1de8dacb0873f77e6aefc6d71e044761fcc68060290f5b1089fcdf84626bb69" dependencies = [ - "bitflags", + "bitflags 1.3.2", "byteorder", "chrono", "flate2", "hex", "lazy_static", - "rustix", + "rustix 0.36.17", ] +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + [[package]] name = "quote" version = "1.0.36" @@ -423,6 +454,15 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + [[package]] name = "rlimit" version = "0.5.4" @@ -438,14 +478,39 @@ version = "0.36.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "305efbd14fde4139eb501df5f136994bb520b033fa9fbdce287507dc23b8c7ed" dependencies = [ - "bitflags", + "bitflags 1.3.2", "errno", "io-lifetimes", "libc", - "linux-raw-sys", + "linux-raw-sys 0.1.4", "windows-sys 0.45.0", ] +[[package]] +name = "rustix" +version = "0.38.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac5ffa1efe7548069688cd7028f32591853cd7b5b756d41bcffd2353e4fc75b4" +dependencies = [ + "bitflags 2.6.0", + "errno", + "libc", + "linux-raw-sys 0.4.14", + "windows-sys 0.48.0", +] + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error", + "tempfile", + "wait-timeout", +] + [[package]] name = "ryu" version = "1.0.18" @@ -517,6 +582,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "tempfile" +version = "3.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall", + "rustix 0.38.3", + "windows-sys 0.48.0", +] + [[package]] name = "thiserror" version = "1.0.40" @@ -549,6 +627,15 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + [[package]] name = "wasm-bindgen" version = "0.2.93" diff --git a/ozonec/Cargo.toml b/ozonec/Cargo.toml index ac0977b3..a617a89a 100644 --- a/ozonec/Cargo.toml +++ b/ozonec/Cargo.toml @@ -19,6 +19,7 @@ nix = "= 0.26.2" oci_spec = { path = "oci_spec" } procfs = "0.14.0" rlimit = "0.5.3" +rusty-fork = "0.3.0" serde = { version = "= 1.0.163", features = ["derive"] } serde_json = "= 1.0.96" thiserror = "= 1.0.40" diff --git a/ozonec/src/linux/mount.rs b/ozonec/src/linux/mount.rs index 55ab4536..af44bd3c 100644 --- a/ozonec/src/linux/mount.rs +++ b/ozonec/src/linux/mount.rs @@ -27,6 +27,7 @@ use procfs::process::{MountInfo, Process}; use crate::utils::{openat2_in_root, proc_fd_path, OzonecErr}; use oci_spec::runtime::Mount as OciMount; +#[derive(PartialEq, Debug)] enum CgroupType { CgroupV1, CgroupV2, @@ -271,3 +272,183 @@ impl Mount { Ok(CgroupType::CgroupV1) } } + +#[cfg(test)] +mod tests { + use rusty_fork::rusty_fork_test; + + use crate::linux::namespace::tests::set_namespace; + use oci_spec::linux::NamespaceType; + + use super::*; + + fn init_mount(rootfs: &str) -> Mount { + let path = PathBuf::from(rootfs); + create_dir_all(&path).unwrap(); + Mount::new(&path) + } + + #[test] + fn test_is_mounted_sysfs_dir() { + let mut path = PathBuf::from("/test"); + let mut mnt = Mount::new(&path); + assert!(!mnt.is_mounted_sysfs_dir(path.to_str().unwrap())); + + path = PathBuf::from("/sys"); + mnt = Mount::new(&path); + assert!(mnt.is_mounted_sysfs_dir(path.to_str().unwrap())); + } + + #[test] + fn test_cgroup_type() { + let rootfs = PathBuf::from("/tmp/ozonec/test_cgroup_type"); + let mnt = Mount::new(&rootfs); + let cgroup_path = Path::new("/sys/fs/cgroup"); + + if !cgroup_path.exists() { + assert!(mnt.cgroup_type().is_err()); + } else { + let st = statfs(cgroup_path).unwrap(); + if st.filesystem_type() == CGROUP2_SUPER_MAGIC { + assert_eq!(mnt.cgroup_type().unwrap(), CgroupType::CgroupV2); + } else { + assert_eq!(mnt.cgroup_type().unwrap(), CgroupType::CgroupV1); + } + } + } + + #[test] + fn test_get_mount_flag_data() { + let rootfs = PathBuf::from("/test_get_mount_flag_data"); + let mnt = Mount::new(&rootfs); + let mut oci_mnt = OciMount { + destination: String::new(), + source: None, + options: Some(vec![ + String::from("defaults"), + String::from("rw"), + String::from("suid"), + String::from("dev"), + String::from("exec"), + String::from("async"), + String::from("nomand"), + String::from("atime"), + String::from("diratime"), + String::from("norelatime"), + String::from("nostrictatime"), + ]), + fs_type: None, + uidMappings: None, + gidMappings: None, + }; + + let (flags, _data) = mnt.get_mount_flag_data(&oci_mnt); + assert_eq!(flags, MsFlags::empty()); + + oci_mnt.options = Some(vec![ + String::from("ro"), + String::from("nosuid"), + String::from("nodev"), + String::from("noexec"), + String::from("sync"), + String::from("dirsync"), + String::from("remount"), + String::from("mand"), + String::from("noatime"), + String::from("nodiratime"), + String::from("bind"), + String::from("unbindable"), + String::from("private"), + String::from("shared"), + String::from("slave"), + String::from("relatime"), + String::from("strictatime"), + ]); + let (flags, _data) = mnt.get_mount_flag_data(&oci_mnt); + assert_eq!( + flags, + MsFlags::MS_RDONLY + | MsFlags::MS_NOSUID + | MsFlags::MS_NODEV + | MsFlags::MS_NOEXEC + | MsFlags::MS_SYNCHRONOUS + | MsFlags::MS_DIRSYNC + | MsFlags::MS_REMOUNT + | MsFlags::MS_MANDLOCK + | MsFlags::MS_NOATIME + | MsFlags::MS_NODIRATIME + | MsFlags::MS_BIND + | MsFlags::MS_UNBINDABLE + | MsFlags::MS_PRIVATE + | MsFlags::MS_SHARED + | MsFlags::MS_SLAVE + | MsFlags::MS_RELATIME + | MsFlags::MS_STRICTATIME + ); + + oci_mnt.options = Some(vec![String::from("rbind")]); + let (flags, _data) = mnt.get_mount_flag_data(&oci_mnt); + assert_eq!(flags, MsFlags::MS_BIND | MsFlags::MS_REC); + oci_mnt.options = Some(vec![String::from("runbindable")]); + let (flags, _data) = mnt.get_mount_flag_data(&oci_mnt); + assert_eq!(flags, MsFlags::MS_UNBINDABLE | MsFlags::MS_REC); + oci_mnt.options = Some(vec![String::from("rprivate")]); + let (flags, _data) = mnt.get_mount_flag_data(&oci_mnt); + assert_eq!(flags, MsFlags::MS_PRIVATE | MsFlags::MS_REC); + oci_mnt.options = Some(vec![String::from("rshared")]); + let (flags, _data) = mnt.get_mount_flag_data(&oci_mnt); + assert_eq!(flags, MsFlags::MS_SHARED | MsFlags::MS_REC); + oci_mnt.options = Some(vec![String::from("rslave")]); + let (flags, _data) = mnt.get_mount_flag_data(&oci_mnt); + assert_eq!(flags, MsFlags::MS_SLAVE | MsFlags::MS_REC); + } + + rusty_fork_test! { + #[test] + #[ignore = "unshare may not be permitted"] + fn test_do_mounts_cgroup() { + set_namespace(NamespaceType::Mount); + + let mounts = vec![OciMount { + destination: String::from("/sys/fs/cgroup"), + source: Some(String::from("cgroup")), + options: Some(vec![ + String::from("nosuid"), + String::from("noexec"), + String::from("nodev"), + String::from("relatime"), + String::from("ro"), + ]), + fs_type: Some(String::from("cgroup")), + uidMappings: None, + gidMappings: None, + }]; + let mnt = init_mount("/tmp/ozonec/test_do_mounts_cgroup"); + + assert!(mnt.do_mounts(&mounts, &None).is_ok()); + assert!(mnt.rootfs.join("sys/fs/cgroup").exists()); + } + + #[test] + #[ignore = "unshare may not be permitted"] + fn test_do_mounts_bind() { + set_namespace(NamespaceType::Mount); + + let mounts = vec![OciMount { + destination: String::from("/dest"), + source: Some(String::from("/tmp/ozonec/test_do_mounts_bind/source")), + options: Some(vec![ + String::from("rbind") + ]), + fs_type: None, + uidMappings: None, + gidMappings: None, + }]; + let mnt = init_mount("/tmp/ozonec/test_do_mounts_bind"); + create_dir_all(&mnt.rootfs.join("source")).unwrap(); + + assert!(mnt.do_mounts(&mounts, &None).is_ok()); + assert!(mnt.rootfs.join("dest").exists()); + } + } +} diff --git a/ozonec/src/linux/namespace.rs b/ozonec/src/linux/namespace.rs index 5928e3d0..8adf610f 100644 --- a/ozonec/src/linux/namespace.rs +++ b/ozonec/src/linux/namespace.rs @@ -64,3 +64,20 @@ impl NsController { Ok(self.namespaces.get(&clone_flags)) } } + +#[cfg(test)] +pub mod tests { + use super::*; + + pub fn set_namespace(ns_type: NamespaceType) { + let mut ns_ctrl = NsController { + namespaces: HashMap::new(), + }; + let ns = Namespace { + ns_type, + path: None, + }; + ns_ctrl.namespaces.insert(ns_type.try_into().unwrap(), ns); + ns_ctrl.set_namespace(ns_type).unwrap(); + } +} -- Gitee From c2de02f93d5957fa595d022d894c2735959fada2 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Tue, 24 Sep 2024 13:48:46 +0800 Subject: [PATCH 415/489] ozonec/notify_socket: Add unit test cases --- ozonec/src/linux/notify_socket.rs | 39 +++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/ozonec/src/linux/notify_socket.rs b/ozonec/src/linux/notify_socket.rs index 956c415e..356be384 100644 --- a/ozonec/src/linux/notify_socket.rs +++ b/ozonec/src/linux/notify_socket.rs @@ -88,3 +88,42 @@ impl NotifySocket { Ok(()) } } + +#[cfg(test)] +mod test { + use std::fs::{create_dir_all, remove_dir_all}; + + use nix::sys::wait::{waitpid, WaitStatus}; + + use crate::linux::process::clone_process; + + use super::*; + + #[test] + fn test_notify_socket() { + remove_dir_all("/tmp/ozonec").unwrap_or_default(); + + let root = PathBuf::from("/tmp/ozonec/notify_socket"); + create_dir_all(&root).unwrap(); + + let socket_path = root.join(NOTIFY_SOCKET); + let mut socket = NotifySocket::new(&socket_path); + let listener = NotifyListener::new(root.clone()).unwrap(); + let child = clone_process("notify_socket", || { + listener.wait_for_start_container().unwrap(); + Ok(1) + }) + .unwrap(); + socket.notify_container_start().unwrap(); + + match waitpid(child, None) { + Ok(WaitStatus::Exited(_, s)) => { + assert_eq!(s, 1); + } + Ok(_) => (), + Err(e) => { + panic!("Failed to waitpid for child process: {e}"); + } + } + } +} -- Gitee From b12c167cadd3d4fef970d35bf53950e331c12867 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Tue, 24 Sep 2024 15:07:22 +0800 Subject: [PATCH 416/489] ozonec/terminal: Add unit test cases --- ozonec/src/linux/terminal.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ozonec/src/linux/terminal.rs b/ozonec/src/linux/terminal.rs index 6b11702e..26da7376 100644 --- a/ozonec/src/linux/terminal.rs +++ b/ozonec/src/linux/terminal.rs @@ -95,3 +95,17 @@ pub fn connect_stdio(stdin: &RawFd, stdout: &RawFd, stderr: &RawFd) -> Result<() .with_context(|| OzonecErr::Dup2("stderr".to_string()))?; Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_connect_stdio() { + let stdin: RawFd = 0; + let stdout: RawFd = 0; + let stderr: RawFd = 0; + + assert!(connect_stdio(&stdin, &stdout, &stderr).is_ok()); + } +} -- Gitee From a9d7cb6b09d0d7e00e2e7f49677fe3902e2f12c8 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Tue, 24 Sep 2024 18:17:56 +0800 Subject: [PATCH 417/489] ozonec/container: Add unit test cases --- ozonec/src/linux/container.rs | 198 ++++++++++++++++++++++++++++++++++ 1 file changed, 198 insertions(+) diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index f13475c5..583a64f0 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -792,3 +792,201 @@ impl Container for LinuxContainer { Ok(()) } } + +#[cfg(test)] +mod tests { + use chrono::DateTime; + use fs::{remove_dir_all, File}; + use nix::sys::stat::stat; + use unistd::getpid; + + use oci_spec::{ + linux::LinuxPlatform, + posix::{Root, User}, + process::Process as OciProcess, + }; + + use super::*; + + fn init_config() -> RuntimeConfig { + let root = Root { + path: String::from("/tmp/ozonec/bundle/rootfs"), + readonly: true, + }; + let user = User { + uid: 0, + gid: 0, + umask: None, + additionalGids: None, + }; + let process = OciProcess { + cwd: String::from("/"), + args: Some(vec![String::from("bash")]), + env: None, + terminal: false, + consoleSize: None, + rlimits: None, + apparmorProfile: None, + capabilities: None, + noNewPrivileges: None, + oomScoreAdj: None, + scheduler: None, + selinuxLabel: None, + ioPriority: None, + execCPUAffinity: None, + user, + }; + let linux = LinuxPlatform { + namespaces: Vec::new(), + uidMappings: None, + gidMappings: None, + timeOffsets: None, + devices: None, + cgroupsPath: None, + rootfsPropagation: None, + maskedPaths: None, + readonlyPaths: None, + mountLabel: None, + personality: None, + resources: None, + rdma: None, + unified: None, + sysctl: None, + seccomp: None, + #[cfg(target_arch = "x86_64")] + intelRdt: None, + }; + RuntimeConfig { + ociVersion: String::from("1.2"), + root, + mounts: Vec::new(), + process, + hostname: None, + domainname: None, + linux: Some(linux), + vm: None, + hooks: None, + annotations: None, + } + } + + #[test] + fn test_linux_container_new() { + remove_dir_all("/tmp/ozonec").unwrap_or_default(); + + let config = init_config(); + let mut exist: bool = false; + let container = LinuxContainer::new( + &String::from("LinuxContainer_new"), + &String::from("/tmp/ozonec"), + &config, + &None, + &mut exist, + ) + .unwrap(); + + let root = Path::new(&container.root); + assert!(root.exists()); + let root_stat = stat(root).unwrap(); + assert_eq!(root_stat.st_uid, geteuid().as_raw()); + assert_eq!(root_stat.st_gid, getegid().as_raw()); + + assert!(LinuxContainer::new( + &String::from("LinuxContainer_new"), + &String::from("/tmp/ozonec"), + &config, + &None, + &mut exist, + ) + .is_err()); + assert_eq!(exist, true); + } + + #[test] + fn test_validate_config() { + let mut config = init_config(); + config.linux = None; + assert!(LinuxContainer::validate_config(&config).is_err()); + + let linux = LinuxPlatform { + namespaces: Vec::new(), + uidMappings: None, + gidMappings: None, + timeOffsets: None, + devices: None, + cgroupsPath: None, + rootfsPropagation: None, + maskedPaths: None, + readonlyPaths: None, + mountLabel: None, + personality: None, + resources: None, + rdma: None, + unified: None, + sysctl: None, + seccomp: None, + #[cfg(target_arch = "x86_64")] + intelRdt: None, + }; + config.process.args = None; + config.linux = Some(linux); + assert!(LinuxContainer::validate_config(&config).is_err()); + } + + #[test] + fn test_load_from_state() { + let mut state = State { + oci_version: String::from("1.2"), + id: String::from("load_from_state"), + pid: 0, + root: PathBuf::from("/tmp/ozonec/root"), + bundle: PathBuf::from("/tmp/ozonec/bundle"), + rootfs: String::from("/tmp/ozonec/bundle/rootfs"), + start_time: 0, + created_time: DateTime::from(SystemTime::now()), + config: None, + }; + assert!(LinuxContainer::load_from_state(&state, &None).is_err()); + + let config = init_config(); + state.config = Some(config); + assert!(LinuxContainer::load_from_state(&state, &None).is_ok()); + } + + #[test] + fn test_status() { + remove_dir_all("/tmp/ozonec").unwrap_or_default(); + + let config = init_config(); + create_dir_all(&config.root.path).unwrap(); + let mut exist: bool = false; + let mut container = LinuxContainer::new( + &String::from("get_container_status"), + &String::from("/tmp/ozonec"), + &config, + &None, + &mut exist, + ) + .unwrap(); + container.pid = -1; + + assert_eq!(container.status().unwrap(), ContainerStatus::Creating); + + container.pid = 0; + assert_eq!(container.status().unwrap(), ContainerStatus::Stopped); + + container.pid = getpid().as_raw(); + assert_eq!(container.status().unwrap(), ContainerStatus::Stopped); + + let proc_stat = procfs::process::Process::new(container.pid) + .unwrap() + .stat() + .unwrap(); + container.start_time = proc_stat.starttime; + assert_eq!(container.status().unwrap(), ContainerStatus::Running); + + let notify_socket = PathBuf::from(&container.root).join(NOTIFY_SOCKET); + File::create(¬ify_socket).unwrap(); + assert_eq!(container.status().unwrap(), ContainerStatus::Created); + } +} -- Gitee From db8dda54f2d5283c008af5ea51537fbd6b9e9747 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Tue, 24 Sep 2024 23:17:09 +0800 Subject: [PATCH 418/489] ozonec/process: Add unit test cases --- ozonec/src/linux/process.rs | 140 ++++++++++++++++++++++++++++++++++++ 1 file changed, 140 insertions(+) diff --git a/ozonec/src/linux/process.rs b/ozonec/src/linux/process.rs index 6215a24b..e3c96224 100644 --- a/ozonec/src/linux/process.rs +++ b/ozonec/src/linux/process.rs @@ -429,3 +429,143 @@ fn to_cap(value: &str) -> Result { _ => bail!("Invalid capability: {}", value), } } + +#[cfg(test)] +mod tests { + use std::path::Path; + + use nix::sys::resource::{getrlimit, Resource}; + use rusty_fork::rusty_fork_test; + + use oci_spec::{ + linux::{IoPriority, SchedPolicy, Scheduler}, + posix::{Rlimits, User}, + }; + + use super::*; + + fn init_oci_process() -> OciProcess { + let user = User { + uid: 0, + gid: 0, + umask: None, + additionalGids: None, + }; + OciProcess { + cwd: String::from("/"), + args: Some(vec![String::from("bash")]), + env: None, + terminal: false, + consoleSize: None, + rlimits: None, + apparmorProfile: None, + capabilities: None, + noNewPrivileges: None, + oomScoreAdj: None, + scheduler: None, + selinuxLabel: None, + ioPriority: None, + execCPUAffinity: None, + user, + } + } + + #[test] + fn test_process_new() { + let mut oci_process = init_oci_process(); + + let process = Process::new(&oci_process, false); + assert_eq!(process.stdin.unwrap(), stdin().as_raw_fd()); + assert_eq!(process.stdout.unwrap(), stdout().as_raw_fd()); + assert_eq!(process.stderr.unwrap(), stderr().as_raw_fd()); + + oci_process.terminal = true; + let process = Process::new(&oci_process, false); + assert!(process.stdin.is_none()); + assert!(process.stdout.is_none()); + assert!(process.stderr.is_none()); + } + + #[test] + fn test_set_tty() { + let mut oci_process = init_oci_process(); + + let process = Process::new(&oci_process, false); + assert!(process.set_tty(None, false).is_ok()); + + oci_process.terminal = true; + let process = Process::new(&oci_process, false); + assert!(process.set_tty(None, false).is_err()); + } + + rusty_fork_test! { + #[test] + #[ignore = "oom_score_adj may not be permitted to set"] + fn test_set_oom_score_adj() { + let mut oci_process = init_oci_process(); + oci_process.oomScoreAdj = Some(100); + let process = Process::new(&oci_process, false); + + assert!(process.set_oom_score_adj().is_ok()); + assert_eq!( + read_to_string(Path::new("/proc/self/oom_score_adj")).unwrap(), + String::from("100\n") + ); + } + + #[test] + #[ignore = "setrlimit may not be permitted"] + fn test_set_rlimits() { + let mut oci_process = init_oci_process(); + let rlimits = Rlimits { + rlimit_type: String::from("RLIMIT_CORE"), + soft: 10, + hard: 20, + }; + oci_process.rlimits = Some(vec![rlimits]); + let process = Process::new(&oci_process, false); + + assert!(process.set_rlimits().is_ok()); + assert_eq!(getrlimit(Resource::RLIMIT_CORE).unwrap().0, 10); + assert_eq!(getrlimit(Resource::RLIMIT_CORE).unwrap().1, 20); + } + + #[test] + fn test_set_io_priority() { + let mut oci_process = init_oci_process(); + let io_pri = IoPriority { + class: IoPriClass::IoprioClassBe, + priority: 7, + }; + oci_process.ioPriority = Some(io_pri.clone()); + let process = Process::new(&oci_process, false); + + assert!(process.set_io_priority().is_ok()); + + let io_prio_who_process: libc::c_int = 1; + let io_prio_who_pid = 0; + let ioprio = unsafe { + libc::syscall(libc::SYS_ioprio_get, io_prio_who_process, io_prio_who_pid) + }; + assert_eq!(ioprio, (2 as i64) << 13 | io_pri.priority); + } + + #[test] + fn test_set_scheduler() { + let mut oci_process = init_oci_process(); + let scheduler = Scheduler { + policy: SchedPolicy::SchedOther, + nice: None, + priority: None, + flags: None, + runtime: None, + deadline: None, + period: None, + }; + oci_process.scheduler = Some(scheduler); + let process = Process::new(&oci_process, false); + + assert!(process.set_scheduler().is_ok()); + } + } +} -- Gitee From e02e7f8307475d3547d9bc9f76f9461a93b22e6d Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Wed, 25 Sep 2024 04:06:14 +0800 Subject: [PATCH 419/489] ozonec/process: Add more unit test cases --- ozonec/src/linux/process.rs | 112 +++++++++++++++++++++++++++++++++++- 1 file changed, 111 insertions(+), 1 deletion(-) diff --git a/ozonec/src/linux/process.rs b/ozonec/src/linux/process.rs index e3c96224..da93545a 100644 --- a/ozonec/src/linux/process.rs +++ b/ozonec/src/linux/process.rs @@ -436,9 +436,10 @@ mod tests { use nix::sys::resource::{getrlimit, Resource}; use rusty_fork::rusty_fork_test; + use unistd::getcwd; use oci_spec::{ - linux::{IoPriority, SchedPolicy, Scheduler}, + linux::{Capbilities, IoPriority, SchedPolicy, Scheduler}, posix::{Rlimits, User}, }; @@ -498,6 +499,39 @@ mod tests { assert!(process.set_tty(None, false).is_err()); } + #[test] + fn test_chdir_cwd() { + let oci_process = init_oci_process(); + let process = Process::new(&oci_process, false); + + assert!(process.chdir_cwd().is_ok()); + assert_eq!(getcwd().unwrap().to_str().unwrap(), "/"); + } + + #[test] + fn test_set_envs() { + let mut oci_process = init_oci_process(); + oci_process.env = Some(vec![ + String::from("OZONEC_ENV_1=1"), + String::from("=OZONEC_ENV_2"), + String::from("OZONEC_ENV"), + ]); + let process = Process::new(&oci_process, false); + + process.set_envs(); + for (key, value) in env::vars() { + if key == "OZONEC_ENV_1" { + assert_eq!(value, "1"); + continue; + } + assert_ne!(value, "OZONEC_ENV_2"); + assert_ne!(key, "OZONEC_ENV"); + assert_ne!(value, "OZONEC_ENV"); + } + + env::remove_var("OZONEC_ENV_1"); + } + rusty_fork_test! { #[test] #[ignore = "oom_score_adj may not be permitted to set"] @@ -567,5 +601,81 @@ mod tests { assert!(process.set_scheduler().is_ok()); } + + #[test] + fn test_set_no_new_privileges() { + let mut oci_process = init_oci_process(); + oci_process.noNewPrivileges = Some(true); + let process = Process::new(&oci_process, false); + + assert!(process.set_no_new_privileges().is_ok()); + } + + #[test] + #[ignore = "capset may not be permitted"] + fn test_drop_capabilities() { + let mut oci_process = init_oci_process(); + let caps = Capbilities { + effective: Some(vec![ + String::from("CAP_DAC_OVERRIDE"), + String::from("CAP_DAC_READ_SEARCH"), + String::from("CAP_SETFCAP"), + ]), + bounding: Some(vec![ + String::from("CAP_DAC_OVERRIDE"), + String::from("CAP_DAC_READ_SEARCH"), + ]), + inheritable: Some(vec![String::from("CAP_DAC_READ_SEARCH")]), + permitted: Some(vec![ + String::from("CAP_DAC_OVERRIDE"), + String::from("CAP_DAC_READ_SEARCH"), + String::from("CAP_SETFCAP"), + ]), + ambient: Some(vec![String::from("CAP_DAC_READ_SEARCH")]), + }; + oci_process.capabilities = Some(caps); + let process = Process::new(&oci_process, false); + + assert!(process.drop_capabilities().is_ok()); + let mut caps = caps::read(None, CapSet::Bounding).unwrap(); + assert_eq!(caps.len(), 2); + assert!(caps.get(&Capability::CAP_DAC_OVERRIDE).is_some()); + assert!(caps.get(&Capability::CAP_DAC_READ_SEARCH).is_some()); + caps = caps::read(None, CapSet::Effective).unwrap(); + assert_eq!(caps.len(), 3); + assert!(caps.get(&Capability::CAP_DAC_OVERRIDE).is_some()); + assert!(caps.get(&Capability::CAP_DAC_READ_SEARCH).is_some()); + assert!(caps.get(&Capability::CAP_SETFCAP).is_some()); + caps = caps::read(None, CapSet::Inheritable).unwrap(); + assert_eq!(caps.len(), 1); + assert!(caps.get(&Capability::CAP_DAC_READ_SEARCH).is_some()); + caps = caps::read(None, CapSet::Permitted).unwrap(); + assert_eq!(caps.len(), 3); + assert!(caps.get(&Capability::CAP_DAC_OVERRIDE).is_some()); + assert!(caps.get(&Capability::CAP_DAC_READ_SEARCH).is_some()); + assert!(caps.get(&Capability::CAP_SETFCAP).is_some()); + caps = caps::read(None, CapSet::Ambient).unwrap(); + assert_eq!(caps.len(), 1); + assert!(caps.get(&Capability::CAP_DAC_READ_SEARCH).is_some()); + } + + #[test] + fn test_reset_capabilities() { + let oci_process = init_oci_process(); + let process = Process::new(&oci_process, false); + + assert!(process.reset_capabilities().is_ok()); + let permit_caps = caps::read(None, CapSet::Permitted).unwrap(); + let eff_caps = caps::read(None, CapSet::Effective).unwrap(); + assert_eq!(permit_caps, eff_caps); + } + + #[test] + fn test_clean_envs() { + let oci_process = init_oci_process(); + let process = Process::new(&oci_process, false); + process.clean_envs(); + assert_eq!(env::vars().count(), 0); + } } } -- Gitee From cc2f69955ebddd7a97b498069aa5192ac7bf6697 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Sun, 29 Sep 2024 09:47:20 +0800 Subject: [PATCH 420/489] ozonec/namespace: Add unit test cases --- ozonec/src/linux/namespace.rs | 60 ++++++++++++++++++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/ozonec/src/linux/namespace.rs b/ozonec/src/linux/namespace.rs index 8adf610f..819bd99e 100644 --- a/ozonec/src/linux/namespace.rs +++ b/ozonec/src/linux/namespace.rs @@ -67,9 +67,18 @@ impl NsController { #[cfg(test)] pub mod tests { + use std::{path::PathBuf, thread::sleep, time::Duration}; + + use nix::sys::{ + signal::{self, Signal}, + wait::{waitpid, WaitStatus}, + }; + + use crate::linux::process::clone_process; + use super::*; - pub fn set_namespace(ns_type: NamespaceType) { + fn init_ns_controller(ns_type: NamespaceType) -> NsController { let mut ns_ctrl = NsController { namespaces: HashMap::new(), }; @@ -78,6 +87,55 @@ pub mod tests { path: None, }; ns_ctrl.namespaces.insert(ns_type.try_into().unwrap(), ns); + ns_ctrl + } + + pub fn set_namespace(ns_type: NamespaceType) { + let ns_ctrl = init_ns_controller(ns_type); ns_ctrl.set_namespace(ns_type).unwrap(); } + + #[test] + #[ignore = "unshare may not be permitted"] + fn test_set_namespace() { + let mut ns_ctrl = init_ns_controller(NamespaceType::Mount); + let fst_child = clone_process("test_set_namespace_with_unshare", || { + assert!(ns_ctrl.set_namespace(NamespaceType::Mount).is_ok()); + sleep(Duration::from_secs(10)); + Ok(1) + }) + .unwrap(); + + let ns_path = PathBuf::from(format!("/proc/{}/ns/mnt", fst_child.as_raw())); + ns_ctrl + .namespaces + .get_mut(&CloneFlags::CLONE_NEWNS) + .unwrap() + .path = Some(ns_path); + let sec_child = clone_process("test_set_namespace_with_setns", || { + assert!(ns_ctrl.set_namespace(NamespaceType::Mount).is_ok()); + Ok(1) + }) + .unwrap(); + + match waitpid(sec_child, None) { + Ok(WaitStatus::Exited(_, s)) => { + assert_eq!(s, 1); + } + Ok(_) => (), + Err(e) => { + panic!("Failed to waitpid for unshare process: {e}"); + } + } + signal::kill(fst_child.clone(), Signal::SIGKILL).unwrap(); + match waitpid(fst_child, None) { + Ok(WaitStatus::Exited(_, s)) => { + assert_eq!(s, 1); + } + Ok(_) => (), + Err(e) => { + panic!("Failed to waitpid for setns process: {e}"); + } + } + } } -- Gitee From 4ae2d5c41e0ebe93f36c1b83c23469ee9bc240b1 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Sun, 29 Sep 2024 14:26:51 +0800 Subject: [PATCH 421/489] ozonec/rootfs: Add unit test cases --- ozonec/src/linux/container.rs | 4 +- ozonec/src/linux/rootfs.rs | 153 ++++++++++++++++++++++++++++++++++ 2 files changed, 155 insertions(+), 2 deletions(-) diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index 583a64f0..261e2fbd 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -794,7 +794,7 @@ impl Container for LinuxContainer { } #[cfg(test)] -mod tests { +pub mod tests { use chrono::DateTime; use fs::{remove_dir_all, File}; use nix::sys::stat::stat; @@ -808,7 +808,7 @@ mod tests { use super::*; - fn init_config() -> RuntimeConfig { + pub fn init_config() -> RuntimeConfig { let root = Root { path: String::from("/tmp/ozonec/bundle/rootfs"), readonly: true, diff --git a/ozonec/src/linux/rootfs.rs b/ozonec/src/linux/rootfs.rs index a58d9e6b..5dd0a314 100644 --- a/ozonec/src/linux/rootfs.rs +++ b/ozonec/src/linux/rootfs.rs @@ -232,3 +232,156 @@ impl Rootfs { Ok(()) } } + +#[cfg(test)] +mod tests { + use std::fs::{self, create_dir_all, read_link, remove_dir_all}; + + use nix::unistd::chdir; + use rusty_fork::rusty_fork_test; + + use crate::linux::{container::tests::init_config, namespace::tests::set_namespace}; + use oci_spec::linux::NamespaceType; + + use super::*; + + fn init_rootfs(path: &str, propagation: Option, mounts: Vec) -> Rootfs { + let path = PathBuf::from(path); + create_dir_all(&path).unwrap(); + Rootfs::new(path, propagation, mounts, true, Vec::new()).unwrap() + } + + #[test] + fn test_rootfs_new() { + let path = PathBuf::from("/test_rootfs_new"); + assert!(Rootfs::new(path, None, Vec::new(), true, Vec::new()).is_err()); + } + + #[test] + fn test_get_mount_flags() { + assert_eq!( + Rootfs::get_mount_flags(Some(String::from("shared"))).unwrap(), + MsFlags::MS_SHARED + ); + assert_eq!( + Rootfs::get_mount_flags(Some(String::from("private"))).unwrap(), + MsFlags::MS_PRIVATE + ); + assert_eq!( + Rootfs::get_mount_flags(Some(String::from("slave"))).unwrap(), + MsFlags::MS_SLAVE + ); + assert_eq!( + Rootfs::get_mount_flags(Some(String::from("unbindable"))).unwrap(), + MsFlags::MS_UNBINDABLE + ); + assert_eq!( + Rootfs::get_mount_flags(None).unwrap(), + MsFlags::MS_REC | MsFlags::MS_SLAVE + ); + assert!(Rootfs::get_mount_flags(Some(String::from("unbind"))).is_err()); + } + + rusty_fork_test! { + #[test] + #[ignore = "unshare may not be permitted"] + fn test_set_propagation() { + remove_dir_all("/tmp/ozonec").unwrap_or_default(); + + set_namespace(NamespaceType::Mount); + let rootfs = init_rootfs( + "/tmp/ozonec/test_set_propagation", + Some(String::from("shared")), + Vec::new(), + ); + + assert!(rootfs.set_propagation().is_ok()); + } + + #[test] + #[ignore = "unshare may not be permitted"] + fn test_make_parent_mount_private() { + remove_dir_all("/tmp/ozonec").unwrap_or_default(); + + set_namespace(NamespaceType::Mount); + + let parent = PathBuf::from("/tmp/ozonec/test_make_parent_mount_private"); + create_dir_all(&parent).unwrap(); + nix::mount::mount( + Some(&parent), + &parent, + None::<&str>, + MsFlags::MS_BIND, + None::<&str>, + ) + .unwrap(); + let rootfs = init_rootfs( + "/tmp/ozonec/test_make_parent_mount_private/rootfs", + Some(String::from("shared")), + Vec::new(), + ); + + assert!(rootfs.make_parent_mount_private().is_ok()); + } + + #[test] + #[ignore = "unshare may not be permitted"] + fn test_set_default_symlinks() { + remove_dir_all("/tmp/ozonec").unwrap_or_default(); + + set_namespace(NamespaceType::Mount); + let mounts = vec![ + OciMount { + destination: String::from("/proc"), + source: Some(String::from("/proc")), + options: Some(Vec::new()), + fs_type: Some(String::from("proc")), + uidMappings: None, + gidMappings: None, + }, + OciMount { + destination: String::from("/dev"), + source: Some(String::from("tmpfs")), + options: Some(vec![ + String::from("nosuid"), + String::from("strictatime"), + String::from("mode=755"), + String::from("size=65536k"), + ]), + fs_type: Some(String::from("tmpfs")), + uidMappings: None, + gidMappings: None, + }, + ]; + let rootfs = init_rootfs( + "/tmp/ozonec/test_set_default_symlinks", + Some(String::from("shared")), + mounts, + ); + rootfs.mount().unwrap(); + + let mut config = init_config(); + config.root.path = rootfs.path.to_string_lossy().to_string(); + rootfs.do_mounts(&config).unwrap(); + + assert!(rootfs.set_default_symlinks().is_ok()); + chdir(&rootfs.path).unwrap(); + let mut path = PathBuf::from("dev/fd"); + let mut metadata = fs::symlink_metadata(&path).unwrap(); + assert!(metadata.is_symlink()); + assert_eq!(read_link(&path).unwrap(), PathBuf::from("/proc/self/fd")); + path = PathBuf::from("dev/stdin"); + metadata = fs::symlink_metadata(&path).unwrap(); + assert!(metadata.is_symlink()); + assert_eq!(read_link(&path).unwrap(), PathBuf::from("/proc/self/fd/0")); + path = PathBuf::from("dev/stdout"); + metadata = fs::symlink_metadata(&path).unwrap(); + assert!(metadata.is_symlink()); + assert_eq!(read_link(&path).unwrap(), PathBuf::from("/proc/self/fd/1")); + path = PathBuf::from("dev/stderr"); + metadata = fs::symlink_metadata(&path).unwrap(); + assert!(metadata.is_symlink()); + assert_eq!(read_link(&path).unwrap(), PathBuf::from("/proc/self/fd/2")); + } + } +} -- Gitee From d6c021639dfc3220da1da57215382185fb76b862 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Sun, 29 Sep 2024 17:13:13 +0800 Subject: [PATCH 422/489] ozonec/rootfs: Add more unit test cases --- ozonec/src/linux/device.rs | 6 +- ozonec/src/linux/rootfs.rs | 123 ++++++++++++++++++++++++++++++++++++- 2 files changed, 125 insertions(+), 4 deletions(-) diff --git a/ozonec/src/linux/device.rs b/ozonec/src/linux/device.rs index a008fd0f..8ecc568b 100644 --- a/ozonec/src/linux/device.rs +++ b/ozonec/src/linux/device.rs @@ -34,7 +34,7 @@ impl Device { Self { rootfs } } - fn default_devices(&self) -> Vec { + pub fn default_devices(&self) -> Vec { vec![ DeviceInfo { path: self.rootfs.join("dev/null"), @@ -227,8 +227,8 @@ impl Device { } } -struct DeviceInfo { - path: PathBuf, +pub struct DeviceInfo { + pub path: PathBuf, dev_type: String, major: i64, minor: i64, diff --git a/ozonec/src/linux/rootfs.rs b/ozonec/src/linux/rootfs.rs index 5dd0a314..b7854a3f 100644 --- a/ozonec/src/linux/rootfs.rs +++ b/ozonec/src/linux/rootfs.rs @@ -235,7 +235,10 @@ impl Rootfs { #[cfg(test)] mod tests { - use std::fs::{self, create_dir_all, read_link, remove_dir_all}; + use std::{ + fs::{self, create_dir_all, read_link, remove_dir_all}, + os::unix::fs::FileTypeExt, + }; use nix::unistd::chdir; use rusty_fork::rusty_fork_test; @@ -383,5 +386,123 @@ mod tests { assert!(metadata.is_symlink()); assert_eq!(read_link(&path).unwrap(), PathBuf::from("/proc/self/fd/2")); } + + #[test] + #[ignore = "unshare may not be permitted"] + fn test_link_ptmx() { + remove_dir_all("/tmp/ozonec").unwrap_or_default(); + + set_namespace(NamespaceType::Mount); + let mounts = vec![OciMount { + destination: String::from("/dev"), + source: Some(String::from("tmpfs")), + options: Some(vec![ + String::from("nosuid"), + String::from("strictatime"), + String::from("mode=755"), + String::from("size=65536k"), + ]), + fs_type: Some(String::from("tmpfs")), + uidMappings: None, + gidMappings: None, + }]; + let rootfs = init_rootfs( + "/tmp/ozonec/test_link_ptmx", + Some(String::from("shared")), + mounts, + ); + let mut config = init_config(); + config.root.path = rootfs.path.to_string_lossy().to_string(); + rootfs.do_mounts(&config).unwrap(); + + assert!(rootfs.link_ptmx().is_ok()); + + chdir(&rootfs.path).unwrap(); + let path = PathBuf::from("dev/ptmx"); + let metadata = fs::symlink_metadata(&path).unwrap(); + assert!(metadata.is_symlink()); + assert_eq!(read_link(&path).unwrap(), PathBuf::from("pts/ptmx")); + } + + #[test] + #[ignore = "unshare may not be permitted"] + fn test_create_default_devices() { + remove_dir_all("/tmp/ozonec").unwrap_or_default(); + + set_namespace(NamespaceType::Mount); + let mounts = vec![OciMount { + destination: String::from("/dev"), + source: Some(String::from("tmpfs")), + options: Some(vec![ + String::from("nosuid"), + String::from("strictatime"), + String::from("mode=755"), + String::from("size=65536k"), + ]), + fs_type: Some(String::from("tmpfs")), + uidMappings: None, + gidMappings: None, + }]; + let rootfs = init_rootfs( + "/tmp/ozonec/test_create_default_devices", + Some(String::from("shared")), + mounts, + ); + let mut config = init_config(); + config.root.path = rootfs.path.to_string_lossy().to_string(); + rootfs.do_mounts(&config).unwrap(); + + assert!(rootfs.create_default_devices(false).is_ok()); + for dev in Device::new(rootfs.path.clone()).default_devices() { + assert!(dev.path.exists()); + let metadata = fs::metadata(&dev.path).unwrap(); + assert!(metadata.file_type().is_char_device()); + } + } + + #[test] + #[ignore = "unshare may not be permitted"] + fn test_create_devices() { + remove_dir_all("/tmp/ozonec").unwrap_or_default(); + + set_namespace(NamespaceType::Mount); + + let mounts = vec![OciMount { + destination: String::from("/dev"), + source: Some(String::from("tmpfs")), + options: Some(vec![ + String::from("nosuid"), + String::from("strictatime"), + String::from("mode=755"), + String::from("size=65536k"), + ]), + fs_type: Some(String::from("tmpfs")), + uidMappings: None, + gidMappings: None, + }]; + let rootfs = init_rootfs( + "/tmp/ozonec/test_create_devices", + Some(String::from("shared")), + mounts, + ); + let mut config = init_config(); + config.root.path = rootfs.path.to_string_lossy().to_string(); + rootfs.do_mounts(&config).unwrap(); + + let devices = vec![OciDevice { + dev_type: String::from("c"), + path: String::from("/dev/test"), + major: Some(1), + minor: Some(3), + fileMode: Some(0o666u32), + uid: None, + gid: None, + }]; + assert!(rootfs.create_devices(&devices, true).is_ok()); + let path = rootfs.path.join("dev/test"); + assert!(path.exists()); + let metadata = fs::metadata(&path).unwrap(); + assert!(metadata.file_type().is_char_device()); + } } } -- Gitee From fa4afe412d966275409fe94535e45261337a9237 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Sun, 29 Sep 2024 20:06:39 +0800 Subject: [PATCH 423/489] ozonec/seccomp: Add unit test cases --- ozonec/src/linux/seccomp.rs | 72 +++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/ozonec/src/linux/seccomp.rs b/ozonec/src/linux/seccomp.rs index 36903d43..3fdc35e3 100644 --- a/ozonec/src/linux/seccomp.rs +++ b/ozonec/src/linux/seccomp.rs @@ -119,3 +119,75 @@ pub fn set_seccomp(seccomp: &Seccomp) -> Result<()> { Ok(()) } + +#[cfg(test)] +mod tests { + use rusty_fork::rusty_fork_test; + + use oci_spec::linux::{SeccompSyscall, SeccompSyscallArg}; + + use super::*; + + #[test] + fn test_check_seccomp() { + let mut seccomp = Seccomp { + defaultAction: OciSeccompAction::ScmpActNotify, + defaultErrnoRet: None, + architectures: None, + flags: None, + listennerPath: None, + seccompFd: None, + listenerMetadata: None, + syscalls: None, + }; + assert!(check_seccomp(&seccomp).is_err()); + + seccomp.defaultAction = OciSeccompAction::ScmpActAllow; + let syscall = SeccompSyscall { + names: vec![String::from("write")], + action: OciSeccompAction::ScmpActNotify, + errnoRet: None, + args: None, + }; + seccomp.syscalls = Some(vec![syscall]); + assert!(check_seccomp(&seccomp).is_err()); + } + + rusty_fork_test! { + #[test] + fn test_set_seccomp() { + let mut seccomp = Seccomp { + defaultAction: OciSeccompAction::ScmpActAllow, + defaultErrnoRet: None, + architectures: None, + flags: None, + listennerPath: None, + seccompFd: None, + listenerMetadata: None, + syscalls: None, + }; + let syscall = SeccompSyscall { + names: vec![String::from("write")], + action: OciSeccompAction::ScmpActKill, + errnoRet: None, + args: Some(vec![ + SeccompSyscallArg { + index: 0, + value: 0, + valueTwo: Some(0), + op: SeccompOp::ScmpCmpEq, + }, + SeccompSyscallArg { + index: 2, + value: 0, + valueTwo: Some(0), + op: SeccompOp::ScmpCmpMaskedEq, + }, + ]), + }; + seccomp.syscalls = Some(vec![syscall]); + + assert!(set_seccomp(&seccomp).is_ok()); + } + } +} -- Gitee From cd423103e68da247334727b709d8383ec73a5b2f Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Sun, 29 Sep 2024 20:37:15 +0800 Subject: [PATCH 424/489] ozonec/channel: Add unit test cases --- ozonec/src/linux/mod.rs | 2 ++ ozonec/src/utils/channel.rs | 46 +++++++++++++++++++++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/ozonec/src/linux/mod.rs b/ozonec/src/linux/mod.rs index bde83b87..2ea9b63f 100644 --- a/ozonec/src/linux/mod.rs +++ b/ozonec/src/linux/mod.rs @@ -23,4 +23,6 @@ mod terminal; pub use container::LinuxContainer; pub use notify_socket::NotifyListener; +#[allow(unused_imports)] +pub use process::clone_process; pub use process::Process; diff --git a/ozonec/src/utils/channel.rs b/ozonec/src/utils/channel.rs index 97ff2dc7..41b2b08b 100644 --- a/ozonec/src/utils/channel.rs +++ b/ozonec/src/utils/channel.rs @@ -213,3 +213,49 @@ impl Channel { .with_context(|| "Failed to send container process pid") } } + +#[cfg(test)] +mod tests { + use nix::sys::wait::{waitpid, WaitStatus}; + use unistd::getpid; + + use crate::linux::clone_process; + + use super::*; + + #[test] + fn test_channel() { + let channel = Channel::::new().unwrap(); + let child = clone_process("test_channel", || { + channel.receiver.close().unwrap(); + + channel.send_container_created().unwrap(); + channel.send_init_pid(getpid()).unwrap(); + channel.send_id_mappings().unwrap(); + channel.send_id_mappings_done().unwrap(); + + channel.sender.close().unwrap(); + Ok(0) + }) + .unwrap(); + + channel.sender.close().unwrap(); + + channel.recv_container_created().unwrap(); + channel.recv_init_pid().unwrap(); + channel.recv_id_mappings().unwrap(); + channel.recv_id_mappings_done().unwrap(); + + channel.receiver.close().unwrap(); + + match waitpid(child, None) { + Ok(WaitStatus::Exited(_, s)) => { + assert_eq!(s, 0); + } + Ok(_) => (), + Err(e) => { + panic!("Failed to waitpid for child process: {e}"); + } + } + } +} -- Gitee From 6fb9ee59ce0b809dd114204f6166ba6a0cfc5edd Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Mon, 30 Sep 2024 11:14:55 +0800 Subject: [PATCH 425/489] ozonec/logger: Add unit test cases --- ozonec/src/utils/logger.rs | 52 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 52 insertions(+) diff --git a/ozonec/src/utils/logger.rs b/ozonec/src/utils/logger.rs index 47265023..1251de8a 100644 --- a/ozonec/src/utils/logger.rs +++ b/ozonec/src/utils/logger.rs @@ -238,3 +238,55 @@ pub fn init(path: &Option, debug: bool) -> Result<()> { .with_context(|| "Logger has been already set")?; Ok(()) } + +#[cfg(test)] +mod tests { + use std::{fs, os::unix::fs::MetadataExt}; + + use super::*; + + #[test] + fn test_logger_init() { + assert!(init(&Some(PathBuf::from("/tmp/ozonec.log")), false).is_ok()); + remove_file(Path::new("/tmp/ozonec.log")).unwrap(); + } + + #[test] + fn test_logger_rotate() { + let log_file = PathBuf::from("/tmp/ozonec.log"); + let logger = Logger::new(&Some(log_file.clone()), Level::Debug).unwrap(); + let mut locked_rotate = logger.rotate.lock().unwrap(); + // Time in metadata are not changed as the file descriptor is still opened. + let inode = fs::metadata(&log_file).unwrap().ino(); + for i in 1..LOG_ROTATE_CNT_MAX { + let file = format!("{}{}", locked_rotate.path, i); + let path = Path::new(&file); + File::create(path).unwrap(); + } + + locked_rotate.size = Wrapping(0); + assert!(locked_rotate.rotate(1024).is_ok()); + let mut new_inode = fs::metadata(&log_file).unwrap().ino(); + assert_eq!(inode, new_inode); + + locked_rotate.size = Wrapping(LOG_ROTATE_SIZE_MAX); + assert!(locked_rotate.rotate(1024).is_ok()); + new_inode = fs::metadata(&log_file).unwrap().ino(); + assert_ne!(inode, new_inode); + assert_eq!(locked_rotate.size, Wrapping(0)); + + locked_rotate.size = Wrapping(0); + locked_rotate.created_day = formatted_time(wall_time().0)[2] - 1; + assert!(locked_rotate.rotate(1024).is_ok()); + new_inode = fs::metadata(&log_file).unwrap().ino(); + assert_ne!(inode, new_inode); + assert_eq!(locked_rotate.size, Wrapping(0)); + + for i in 1..LOG_ROTATE_CNT_MAX { + let file = format!("{}{}", locked_rotate.path, i); + let path = Path::new(&file); + remove_file(path).unwrap(); + } + remove_file(Path::new("/tmp/ozonec.log")).unwrap(); + } +} -- Gitee From e6c08b6a7ec2983ecfb28a79a242e91042a666f6 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Wed, 2 Oct 2024 10:57:48 +0800 Subject: [PATCH 426/489] ozonec/oci_spec: Add a unit test case for ContainerStatus --- ozonec/oci_spec/src/state.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/ozonec/oci_spec/src/state.rs b/ozonec/oci_spec/src/state.rs index fe818052..960e3b0f 100644 --- a/ozonec/oci_spec/src/state.rs +++ b/ozonec/oci_spec/src/state.rs @@ -87,4 +87,24 @@ mod tests { assert!(state.annotations.contains_key("myKey")); assert_eq!(state.annotations.get("myKey"), Some(&"myValue".to_string())); } + + #[test] + fn test_container_status_to_string() { + assert_eq!( + ContainerStatus::Creating.to_string(), + String::from("creating") + ); + assert_eq!( + ContainerStatus::Created.to_string(), + String::from("created") + ); + assert_eq!( + ContainerStatus::Running.to_string(), + String::from("running") + ); + assert_eq!( + ContainerStatus::Stopped.to_string(), + String::from("stopped") + ); + } } -- Gitee From 6f6d5490bdcd258fea61f8f3d844394aac0a18ee Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Wed, 2 Oct 2024 11:11:18 +0800 Subject: [PATCH 427/489] ozonec/container: Add more unit test cases --- ozonec/src/linux/container.rs | 272 +++++++++++++++++++++++++++++++++- ozonec/src/linux/process.rs | 4 +- 2 files changed, 271 insertions(+), 5 deletions(-) diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index 261e2fbd..0e627fb4 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -795,15 +795,23 @@ impl Container for LinuxContainer { #[cfg(test)] pub mod tests { + use std::ffi::CStr; + use chrono::DateTime; - use fs::{remove_dir_all, File}; + use fs::{read_to_string, remove_dir_all, File}; + use libc::getdomainname; use nix::sys::stat::stat; - use unistd::getpid; + use rusty_fork::rusty_fork_test; + use unistd::{gethostname, getpid}; + use crate::linux::{ + mount::Mount, namespace::tests::set_namespace, process::tests::init_oci_process, + }; use oci_spec::{ - linux::LinuxPlatform, + linux::{LinuxPlatform, Namespace}, posix::{Root, User}, process::Process as OciProcess, + runtime::Mount as OciMount, }; use super::*; @@ -989,4 +997,262 @@ pub mod tests { File::create(¬ify_socket).unwrap(); assert_eq!(container.status().unwrap(), ContainerStatus::Created); } + + #[test] + fn test_is_namespace_set() { + remove_dir_all("/tmp/ozonec").unwrap_or_default(); + + let mut config = init_config(); + config.linux.as_mut().unwrap().namespaces.push(Namespace { + ns_type: NamespaceType::Mount, + path: None, + }); + let mut exist = false; + let container = LinuxContainer::new( + &String::from("test_is_namespace_set"), + &String::from("/tmp/ozonec/test_is_namespace_set"), + &config, + &None, + &mut exist, + ) + .unwrap(); + + assert!(container.is_namespace_set(NamespaceType::Mount).unwrap()); + assert!(!container.is_namespace_set(NamespaceType::User).unwrap()); + } + + #[test] + #[ignore = "unshare may not be permitted"] + fn test_set_pid_namespace() { + remove_dir_all("/tmp/ozonec").unwrap_or_default(); + + let mut config = init_config(); + config.linux.as_mut().unwrap().namespaces.push(Namespace { + ns_type: NamespaceType::Pid, + path: None, + }); + let mut exist = false; + let container = LinuxContainer::new( + &String::from("test_set_pid_namespace"), + &String::from("/tmp/ozonec/test_set_pid_namespace"), + &config, + &None, + &mut exist, + ) + .unwrap(); + + assert!(container.set_pid_namespace().is_ok()); + } + + #[test] + #[ignore = "unshare may not be permitted"] + fn test_set_id_mappings() { + remove_dir_all("/tmp/ozonec").unwrap_or_default(); + + let mut config = init_config(); + let linux = config.linux.as_mut().unwrap(); + linux.namespaces = vec![Namespace { + ns_type: NamespaceType::User, + path: None, + }]; + linux.uidMappings = Some(vec![IdMapping { + containerID: 0, + hostID: 0, + size: 1000, + }]); + linux.gidMappings = Some(vec![IdMapping { + containerID: 0, + hostID: 0, + size: 1000, + }]); + let mut exist = false; + let container = LinuxContainer::new( + &String::from("test_set_id_mappings"), + &String::from("/tmp/ozonec/test_set_id_mappings"), + &config, + &None, + &mut exist, + ) + .unwrap(); + + let fst_channel = Channel::::new().unwrap(); + let sec_channel = Channel::::new().unwrap(); + let child = clone_process("test_set_id_mappings", || { + let process = Process::new(&init_oci_process(), false); + assert!(container + .set_user_namespace(&fst_channel, &sec_channel, &process) + .is_ok()); + Ok(1) + }) + .unwrap(); + + assert!(container + .set_id_mappings(&fst_channel, &sec_channel, &child) + .is_ok()); + let path = format!("/proc/{}/setgroups", child.as_raw().to_string()); + let setgroups = fs::read_to_string(path).unwrap(); + assert_eq!(setgroups.trim(), "deny"); + let path = format!("/proc/{}/uid_map", child.as_raw().to_string()); + let uid_map = fs::read_to_string(path).unwrap(); + let mut iter = uid_map.split_ascii_whitespace(); + assert_eq!(iter.next(), Some("0")); + assert_eq!(iter.next(), Some("0")); + assert_eq!(iter.next(), Some("1000")); + assert_eq!(iter.next(), None); + let path = format!("/proc/{}/gid_map", child.as_raw().to_string()); + let gid_map = fs::read_to_string(path).unwrap(); + let mut iter = gid_map.split_ascii_whitespace(); + assert_eq!(iter.next(), Some("0")); + assert_eq!(iter.next(), Some("0")); + assert_eq!(iter.next(), Some("1000")); + assert_eq!(iter.next(), None); + + match waitpid(child, None) { + Ok(WaitStatus::Exited(_, s)) => { + assert_eq!(s, 1); + } + Ok(_) => (), + Err(e) => { + panic!("Failed to waitpid for child process: {e}"); + } + } + } + + rusty_fork_test! { + #[test] + #[ignore = "unshare may not be permitted"] + fn test_set_readonly_paths() { + remove_dir_all("/tmp/ozonec").unwrap_or_default(); + + set_namespace(NamespaceType::Mount); + let root = PathBuf::from("/tmp/ozonec/test_set_readonly_paths"); + let mut config = init_config(); + let path = root.to_string_lossy().to_string(); + config.linux.as_mut().unwrap().readonlyPaths = Some(vec![path.clone()]); + let mut exist = false; + let container = LinuxContainer::new( + &String::from("test_set_readonly_paths"), + &root.to_string_lossy().to_string(), + &config, + &None, + &mut exist, + ) + .unwrap(); + File::create(root.join("test")).unwrap(); + + assert!(container.set_readonly_paths().is_ok()); + let path = PathBuf::from(path).join("test"); + assert!(File::create(&path).is_err()); + } + + #[test] + #[ignore = "unshare may not be permitted"] + fn test_set_masked_paths() { + remove_dir_all("/tmp/ozonec").unwrap_or_default(); + + set_namespace(NamespaceType::Mount); + let root = PathBuf::from("/tmp/ozonec/test_set_masked_paths"); + let mut config = init_config(); + config.linux.as_mut().unwrap().maskedPaths = Some(vec![root.to_string_lossy().to_string()]); + let mut exist = false; + let container = LinuxContainer::new( + &String::from("test_set_masked_paths"), + &root.to_string_lossy().to_string(), + &config, + &None, + &mut exist, + ) + .unwrap(); + + File::create(root.join("test")).unwrap(); + assert!(container.set_masked_paths().is_ok()); + assert!(!root.join("test").exists()); + } + + #[test] + #[ignore = "unshare may not be permitted"] + fn test_set_rest_namespaces() { + remove_dir_all("/tmp/ozonec").unwrap_or_default(); + + let root = PathBuf::from("/tmp/ozonec/test_set_rest_namespaces"); + let mut config = init_config(); + config.linux.as_mut().unwrap().namespaces = vec![ + Namespace { + ns_type: NamespaceType::User, + path: None, + }, + Namespace { + ns_type: NamespaceType::Uts, + path: None, + }, + ]; + config.hostname = Some(String::from("test_set_rest_namespaces")); + config.domainname = Some(String::from("test_set_rest_namespaces")); + let mut exist = false; + let container = LinuxContainer::new( + &String::from("test_set_rest_namespaces"), + &root.to_string_lossy().to_string(), + &config, + &None, + &mut exist, + ) + .unwrap(); + + assert!(container.set_rest_namespaces().is_ok()); + assert_eq!( + gethostname().unwrap().to_str().unwrap(), + "test_set_rest_namespaces" + ); + let len = 100; + let mut domain: Vec = Vec::with_capacity(len); + unsafe { + getdomainname(domain.as_mut_ptr().cast(), len); + // Ensure always null-terminated. + domain.as_mut_ptr().wrapping_add(len - 1).write(0); + let len = CStr::from_ptr(domain.as_ptr().cast()).to_bytes().len(); + domain.set_len(len); + } + assert_eq!(String::from_utf8_lossy(&domain), "test_set_rest_namespaces"); + } + + #[test] + #[ignore = "unshare may not be permitted"] + fn test_set_sysctl_parameters() { + remove_dir_all("/tmp/ozonec").unwrap_or_default(); + + set_namespace(NamespaceType::Mount); + let root = PathBuf::from("/tmp/ozonec/test_set_sysctl_parameters"); + let mut config = init_config(); + config.linux.as_mut().unwrap().sysctl = Some(HashMap::new()); + let sysctl = &mut config.linux.as_mut().unwrap().sysctl; + sysctl + .as_mut() + .unwrap() + .insert(String::from("vm.oom_dump_tasks"), String::from("0")); + + let mut exist = false; + let container = LinuxContainer::new( + &String::from("test_set_sysctl_parameters"), + &root.to_string_lossy().to_string(), + &config, + &None, + &mut exist, + ) + .unwrap(); + + let mounts = vec![OciMount { + destination: String::from("/proc"), + source: Some(String::from("proc")), + options: None, + fs_type: Some(String::from("proc")), + uidMappings: None, + gidMappings: None, + }]; + let mnt = Mount::new(&root); + mnt.do_mounts(&mounts, &None).unwrap(); + + assert!(container.set_sysctl_parameters().is_ok()); + assert_eq!(read_to_string("/proc/sys/vm/oom_dump_tasks").unwrap().trim(), "0"); + } + } } diff --git a/ozonec/src/linux/process.rs b/ozonec/src/linux/process.rs index da93545a..17b67cb6 100644 --- a/ozonec/src/linux/process.rs +++ b/ozonec/src/linux/process.rs @@ -431,7 +431,7 @@ fn to_cap(value: &str) -> Result { } #[cfg(test)] -mod tests { +pub mod tests { use std::path::Path; use nix::sys::resource::{getrlimit, Resource}; @@ -445,7 +445,7 @@ mod tests { use super::*; - fn init_oci_process() -> OciProcess { + pub fn init_oci_process() -> OciProcess { let user = User { uid: 0, gid: 0, -- Gitee From 22e4b79625e07e04635be150feefde049040bafd Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Wed, 9 Oct 2024 10:47:00 +0800 Subject: [PATCH 428/489] ozonec/exec: Add unit test cases --- ozonec/src/commands/exec.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/ozonec/src/commands/exec.rs b/ozonec/src/commands/exec.rs index 51347ff7..ce15f572 100644 --- a/ozonec/src/commands/exec.rs +++ b/ozonec/src/commands/exec.rs @@ -112,3 +112,17 @@ impl Exec { Ok(()) } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_key_val() { + let (key, value): (String, String) = parse_key_val("OZONEC_LOG_LEVEL=info").unwrap(); + assert_eq!(key, "OZONEC_LOG_LEVEL"); + assert_eq!(value, "info"); + + assert!(parse_key_val::("OZONEC_LOG_LEVEL").is_err()); + } +} -- Gitee From 3706f6ba0a78cb0591ad04025562bdbeb6bc1da4 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Wed, 9 Oct 2024 10:54:54 +0800 Subject: [PATCH 429/489] ozonec/kill: Add unit test cases --- ozonec/src/commands/kill.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/ozonec/src/commands/kill.rs b/ozonec/src/commands/kill.rs index d67a0079..e9ab6350 100644 --- a/ozonec/src/commands/kill.rs +++ b/ozonec/src/commands/kill.rs @@ -53,3 +53,19 @@ fn parse_signal(signal: &str) -> Result { } Ok(Signal::from_str(&uppercase_sig)?) } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_parse_signal() { + assert_eq!(parse_signal("9").unwrap(), Signal::SIGKILL); + assert_eq!(parse_signal("sigterm").unwrap(), Signal::SIGTERM); + assert_eq!(parse_signal("SIGBUS").unwrap(), Signal::SIGBUS); + assert_eq!(parse_signal("hup").unwrap(), Signal::SIGHUP); + assert_eq!(parse_signal("ABRT").unwrap(), Signal::SIGABRT); + assert!(parse_signal("100").is_err()); + assert!(parse_signal("ERROR").is_err()); + } +} -- Gitee From 628088139e16458b088114e4124397f31e5c85ab Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Wed, 9 Oct 2024 22:50:34 +0800 Subject: [PATCH 430/489] ozonec/state: Add unit test cases --- ozonec/src/container/state.rs | 85 +++++++++++++++++++++++++++++++++++ ozonec/src/linux/mod.rs | 3 +- 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/ozonec/src/container/state.rs b/ozonec/src/container/state.rs index e689a1ee..659752a0 100644 --- a/ozonec/src/container/state.rs +++ b/ozonec/src/container/state.rs @@ -117,3 +117,88 @@ impl State { root.join(id).join("state.json") } } + +#[cfg(test)] +mod tests { + use std::collections::HashMap; + + use fs::{create_dir_all, remove_dir_all}; + use nix::unistd::getpid; + + use crate::linux::container::tests::init_config; + use oci_spec::{ + linux::{Namespace, NamespaceType}, + state::ContainerStatus, + }; + + use super::*; + + fn init_state(root: &Path, id: &str) -> State { + let oci_state = OciState { + ociVersion: String::from("1.2"), + id: String::from(id), + status: ContainerStatus::Created, + pid: 100, + bundle: root.to_string_lossy().to_string(), + annotations: HashMap::new(), + }; + State::new(root, root, oci_state, 0, SystemTime::now(), &init_config()) + } + + #[test] + fn test_state_update() { + let root = "/tmp/ozonec"; + remove_dir_all(root).unwrap_or_default(); + let mut state = init_state(Path::new(root), "test_state_update"); + state + .config + .as_mut() + .unwrap() + .linux + .as_mut() + .unwrap() + .namespaces + .push(Namespace { + ns_type: NamespaceType::Mount, + path: None, + }); + state.pid = getpid().as_raw(); + state.update(); + + for ns in &state + .config + .as_ref() + .unwrap() + .linux + .as_ref() + .unwrap() + .namespaces + { + assert_eq!( + ns.path.as_ref().unwrap().to_str().unwrap(), + format!( + "/proc/{}/ns/{}", + state.pid, + >::into(ns.ns_type) + ) + ); + } + } + + #[test] + fn test_state_load() { + let root = "/tmp/ozonec"; + remove_dir_all(root).unwrap_or_default(); + + let state = init_state(Path::new(root), "test_state_load"); + let dir = PathBuf::from(String::from(root)).join("test_state_load"); + create_dir_all(&dir).unwrap(); + + assert!(state.save().is_ok()); + assert!(dir.join("state.json").exists()); + let loaded_state = State::load(Path::new(root), "test_state_load").unwrap(); + assert_eq!(loaded_state.id, state.id); + assert!(state.remove_dir().is_ok()); + assert!(State::load(Path::new(root), "test_state_load").is_err()); + } +} diff --git a/ozonec/src/linux/mod.rs b/ozonec/src/linux/mod.rs index 2ea9b63f..658f50c7 100644 --- a/ozonec/src/linux/mod.rs +++ b/ozonec/src/linux/mod.rs @@ -10,8 +10,9 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. +pub mod container; + mod apparmor; -mod container; mod device; mod mount; mod namespace; -- Gitee From 79481ebed8cf1955813f8c3ead20d30ecf2162f0 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Thu, 10 Oct 2024 13:04:45 +0800 Subject: [PATCH 431/489] ozonec/process: Add unit test case for to_cap() --- ozonec/src/linux/process.rs | 97 +++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/ozonec/src/linux/process.rs b/ozonec/src/linux/process.rs index 17b67cb6..2159727d 100644 --- a/ozonec/src/linux/process.rs +++ b/ozonec/src/linux/process.rs @@ -532,6 +532,103 @@ pub mod tests { env::remove_var("OZONEC_ENV_1"); } + #[test] + fn test_to_cap() { + assert_eq!( + to_cap("CAP_AUDIT_CONTROL").unwrap(), + Capability::CAP_AUDIT_CONTROL + ); + assert_eq!( + to_cap("CAP_AUDIT_READ").unwrap(), + Capability::CAP_AUDIT_READ + ); + assert_eq!( + to_cap("CAP_AUDIT_WRITE").unwrap(), + Capability::CAP_AUDIT_WRITE + ); + assert_eq!( + to_cap("CAP_BLOCK_SUSPEND").unwrap(), + Capability::CAP_BLOCK_SUSPEND + ); + assert_eq!(to_cap("CAP_BPF").unwrap(), Capability::CAP_BPF); + assert_eq!( + to_cap("CAP_CHECKPOINT_RESTORE").unwrap(), + Capability::CAP_CHECKPOINT_RESTORE + ); + assert_eq!(to_cap("CAP_CHOWN").unwrap(), Capability::CAP_CHOWN); + assert_eq!( + to_cap("CAP_DAC_OVERRIDE").unwrap(), + Capability::CAP_DAC_OVERRIDE + ); + assert_eq!( + to_cap("CAP_DAC_READ_SEARCH").unwrap(), + Capability::CAP_DAC_READ_SEARCH + ); + assert_eq!(to_cap("CAP_FOWNER").unwrap(), Capability::CAP_FOWNER); + assert_eq!(to_cap("CAP_FSETID").unwrap(), Capability::CAP_FSETID); + assert_eq!(to_cap("CAP_IPC_LOCK").unwrap(), Capability::CAP_IPC_LOCK); + assert_eq!(to_cap("CAP_IPC_OWNER").unwrap(), Capability::CAP_IPC_OWNER); + assert_eq!(to_cap("CAP_KILL").unwrap(), Capability::CAP_KILL); + assert_eq!(to_cap("CAP_LEASE").unwrap(), Capability::CAP_LEASE); + assert_eq!( + to_cap("CAP_LINUX_IMMUTABLE").unwrap(), + Capability::CAP_LINUX_IMMUTABLE + ); + assert_eq!(to_cap("CAP_MAC_ADMIN").unwrap(), Capability::CAP_MAC_ADMIN); + assert_eq!( + to_cap("CAP_MAC_OVERRIDE").unwrap(), + Capability::CAP_MAC_OVERRIDE + ); + assert_eq!(to_cap("CAP_MKNOD").unwrap(), Capability::CAP_MKNOD); + assert_eq!(to_cap("CAP_NET_ADMIN").unwrap(), Capability::CAP_NET_ADMIN); + assert_eq!( + to_cap("CAP_NET_BIND_SERVICE").unwrap(), + Capability::CAP_NET_BIND_SERVICE + ); + assert_eq!( + to_cap("CAP_NET_BROADCAST").unwrap(), + Capability::CAP_NET_BROADCAST + ); + assert_eq!(to_cap("CAP_NET_RAW").unwrap(), Capability::CAP_NET_RAW); + assert_eq!(to_cap("CAP_PERFMON").unwrap(), Capability::CAP_PERFMON); + assert_eq!(to_cap("CAP_SETGID").unwrap(), Capability::CAP_SETGID); + assert_eq!(to_cap("CAP_SETFCAP").unwrap(), Capability::CAP_SETFCAP); + assert_eq!(to_cap("CAP_SETPCAP").unwrap(), Capability::CAP_SETPCAP); + assert_eq!(to_cap("CAP_SETUID").unwrap(), Capability::CAP_SETUID); + assert_eq!(to_cap("CAP_SYS_ADMIN").unwrap(), Capability::CAP_SYS_ADMIN); + assert_eq!(to_cap("CAP_SYS_BOOT").unwrap(), Capability::CAP_SYS_BOOT); + assert_eq!( + to_cap("CAP_SYS_CHROOT").unwrap(), + Capability::CAP_SYS_CHROOT + ); + assert_eq!( + to_cap("CAP_SYS_MODULE").unwrap(), + Capability::CAP_SYS_MODULE + ); + assert_eq!(to_cap("CAP_SYS_NICE").unwrap(), Capability::CAP_SYS_NICE); + assert_eq!(to_cap("CAP_SYS_PACCT").unwrap(), Capability::CAP_SYS_PACCT); + assert_eq!( + to_cap("CAP_SYS_PTRACE").unwrap(), + Capability::CAP_SYS_PTRACE + ); + assert_eq!(to_cap("CAP_SYS_RAWIO").unwrap(), Capability::CAP_SYS_RAWIO); + assert_eq!( + to_cap("CAP_SYS_RESOURCE").unwrap(), + Capability::CAP_SYS_RESOURCE + ); + assert_eq!(to_cap("CAP_SYS_TIME").unwrap(), Capability::CAP_SYS_TIME); + assert_eq!( + to_cap("CAP_SYS_TTY_CONFIG").unwrap(), + Capability::CAP_SYS_TTY_CONFIG + ); + assert_eq!(to_cap("CAP_SYSLOG").unwrap(), Capability::CAP_SYSLOG); + assert_eq!( + to_cap("CAP_WAKE_ALARM").unwrap(), + Capability::CAP_WAKE_ALARM + ); + assert!(to_cap("CAP_TO_CAP").is_err()); + } + rusty_fork_test! { #[test] #[ignore = "oom_score_adj may not be permitted to set"] -- Gitee From 2e3a69570c8901b17e87ecf791ef9d8ba4994dbc Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Tue, 15 Oct 2024 09:57:23 +0800 Subject: [PATCH 432/489] drive: add log when opening file Print logs when opening files. Signed-off-by: liuxiangdong --- machine_manager/src/config/mod.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index ce4c313b..6f793d4e 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -61,13 +61,14 @@ pub use vnc::*; use std::collections::HashMap; use std::fs::{canonicalize, File}; use std::io::Read; +use std::os::unix::io::AsRawFd; use std::path::Path; use std::str::FromStr; use std::sync::Arc; use anyhow::{anyhow, bail, Context, Result}; use clap::Parser; -use log::error; +use log::{error, info}; use serde::{Deserialize, Serialize}; use trace::{enable_state_by_type, set_state_by_pattern, TraceType}; @@ -314,6 +315,7 @@ impl VmConfig { req_align, buf_align, }; + info!("Open file {}, fd: {}", path, drive_file.file.as_raw_fd()); drive_files.insert(path.to_string(), drive_file); Ok(()) } -- Gitee From 396e887ebd43dc76301a82f66244ae23c32cab11 Mon Sep 17 00:00:00 2001 From: sujerry1991 Date: Tue, 22 Oct 2024 16:06:05 +0800 Subject: [PATCH 433/489] iothread: iothread exit should after TempCleaner::clean The qcow2 drain inflight IO operation in TempCleaner should called before the disk-iothread exit. Otherwise, due to the disk-iothread has been exit, the drain operation will be stucked. Signed-off-by: Yan Wang --- block_backend/src/lib.rs | 1 + machine/src/lib.rs | 2 +- machine_manager/src/event_loop.rs | 21 ++++++++++++++------- machine_manager/src/signal_handler.rs | 2 +- machine_manager/src/temp_cleaner.rs | 17 ++++++++++++++++- src/main.rs | 3 ++- util/src/loop_context.rs | 14 +++++++------- 7 files changed, 42 insertions(+), 18 deletions(-) diff --git a/block_backend/src/lib.rs b/block_backend/src/lib.rs index 525c1c66..ea146dc0 100644 --- a/block_backend/src/lib.rs +++ b/block_backend/src/lib.rs @@ -444,6 +444,7 @@ pub fn create_block_backend( if let Err(e) = qcow2.lock().unwrap().flush() { error!("Failed to flush qcow2 {:?}", e); } + info!("Flush qcow2 {} metadata success.", cloned_drive_id); } }) as Arc; TempCleaner::add_exit_notifier(prop.id.clone(), exit_notifier); diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 8ec8ad77..cb26a3a8 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -2324,7 +2324,7 @@ fn handle_destroy_request(vm: &Arc>) -> bool { } info!("vm destroy"); - EventLoop::kick_all(); + EventLoop::get_ctx(None).unwrap().kick(); true } diff --git a/machine_manager/src/event_loop.rs b/machine_manager/src/event_loop.rs index 79d7cf6f..d8d858b3 100644 --- a/machine_manager/src/event_loop.rs +++ b/machine_manager/src/event_loop.rs @@ -16,12 +16,13 @@ use std::sync::{Arc, Barrier, Mutex}; use std::{process, thread}; use anyhow::{bail, Result}; -use log::info; +use log::{error, info}; use super::config::IothreadConfig; use crate::machine::IOTHREADS; use crate::qmp::qmp_schema::IothreadInfo; use crate::signal_handler::get_signal; +use crate::temp_cleaner::TempCleaner; use util::loop_context::{ gen_delete_notifiers, get_notifiers_fds, EventLoopContext, EventLoopManager, EventNotifier, }; @@ -84,11 +85,16 @@ impl EventLoop { id: id.to_string(), }; IOTHREADS.lock().unwrap().push(iothread_info); - while let Ok(ret) = ctx.iothread_run() { - if !ret || get_signal() != 0 { + while let Ok(_) = ctx.iothread_run() { + // If is_cleaned() is true, it means the main thread will exit. + // So, exit the iothread. + if TempCleaner::is_cleaned() { break; } } + if let Err(e) = ctx.clean_event_loop() { + error!("Failed to clean event loop {:?}", e); + } ctx.thread_exit_barrier.wait(); })?; } @@ -167,12 +173,10 @@ impl EventLoop { let sig_num = get_signal(); if sig_num != 0 { info!("MainLoop exits due to receive signal {}", sig_num); - event_loop.main_loop.thread_exit_barrier.wait(); return Ok(()); } if !event_loop.main_loop.run()? { info!("MainLoop exits due to guest internal operation."); - event_loop.main_loop.thread_exit_barrier.wait(); return Ok(()); } } @@ -183,21 +187,24 @@ impl EventLoop { } pub fn loop_clean() { + EventLoop::kick_iothreads(); // SAFETY: the main_loop ctx is dedicated for main thread, thus no concurrent // accessing. unsafe { + if let Some(event_loop) = GLOBAL_EVENT_LOOP.as_mut() { + event_loop.main_loop.thread_exit_barrier.wait(); + } GLOBAL_EVENT_LOOP = None; } } - pub fn kick_all() { + pub fn kick_iothreads() { // SAFETY: All concurrently accessed data of EventLoopContext is protected. unsafe { if let Some(event_loop) = GLOBAL_EVENT_LOOP.as_mut() { for (_name, io_thread) in event_loop.io_threads.iter_mut() { io_thread.kick(); } - event_loop.main_loop.kick(); } } } diff --git a/machine_manager/src/signal_handler.rs b/machine_manager/src/signal_handler.rs index 6d679192..2f1ba86e 100644 --- a/machine_manager/src/signal_handler.rs +++ b/machine_manager/src/signal_handler.rs @@ -50,7 +50,7 @@ pub fn set_signal(num: c_int) { unsafe { RECEIVED_SIGNAL.store(num, Ordering::SeqCst); } - EventLoop::kick_all(); + EventLoop::get_ctx(None).unwrap().kick(); } } diff --git a/machine_manager/src/temp_cleaner.rs b/machine_manager/src/temp_cleaner.rs index cd5b2f42..ba92cd78 100644 --- a/machine_manager/src/temp_cleaner.rs +++ b/machine_manager/src/temp_cleaner.rs @@ -13,7 +13,10 @@ use std::collections::HashMap; use std::fs; use std::path::Path; -use std::sync::Arc; +use std::sync::{ + atomic::{fence, Ordering}, + Arc, +}; use log::{error, info}; @@ -105,7 +108,19 @@ impl TempCleaner { if let Some(tmp) = GLOBAL_TEMP_CLEANER.as_mut() { tmp.clean_files(); tmp.exit_notifier(); + fence(Ordering::SeqCst); + GLOBAL_TEMP_CLEANER = None; } } } + + pub fn is_cleaned() -> bool { + // SAFETY: This global variable is read but not modified by iothread. + // so there is not need to add lock to it. + unsafe { + let ret = GLOBAL_TEMP_CLEANER.is_none(); + fence(Ordering::SeqCst); + ret + } + } } diff --git a/src/main.rs b/src/main.rs index c2e81909..de3fd8e6 100644 --- a/src/main.rs +++ b/src/main.rs @@ -117,6 +117,7 @@ fn run() -> Result<()> { info!("MainLoop over, Vm exit"); // clean temporary file TempCleaner::clean(); + EventLoop::loop_clean(); handle_signal(); } Err(ref e) => { @@ -124,6 +125,7 @@ fn run() -> Result<()> { error!("{}", format!("{:?}\r\n", e)); // clean temporary file TempCleaner::clean(); + EventLoop::loop_clean(); exit_with_code(VM_EXIT_GENE_ERR); } } @@ -228,6 +230,5 @@ fn real_main(cmd_args: &arg_parser::ArgMatches, vm_config: &mut VmConfig) -> Res machine::vm_run(&vm, cmd_args).with_context(|| "Failed to start VM.")?; EventLoop::loop_run().with_context(|| "MainLoop exits unexpectedly: error occurs")?; - EventLoop::loop_clean(); Ok(()) } diff --git a/util/src/loop_context.rs b/util/src/loop_context.rs index 8e956982..91c96989 100644 --- a/util/src/loop_context.rs +++ b/util/src/loop_context.rs @@ -557,13 +557,6 @@ impl EventLoopContext { } pub fn iothread_run(&mut self) -> Result { - if let Some(manager) = &self.manager { - if manager.lock().unwrap().loop_should_exit() { - manager.lock().unwrap().loop_cleanup()?; - return Ok(false); - } - } - let min_timeout_ns = self.timers_min_duration(); if min_timeout_ns.is_none() { for _i in 0..AIO_PRFETCH_CYCLE_TIME { @@ -721,6 +714,13 @@ impl EventLoopContext { self.clear_gc(); Ok(true) } + + pub fn clean_event_loop(&mut self) -> Result<()> { + if let Some(manager) = &self.manager { + manager.lock().unwrap().loop_cleanup()?; + } + Ok(()) + } } pub fn read_fd(fd: RawFd) -> u64 { -- Gitee From 1fddcfb044ac6814a34b55aa9a98dab8e05ac2fb Mon Sep 17 00:00:00 2001 From: sujerry1991 Date: Wed, 23 Oct 2024 16:04:21 +0800 Subject: [PATCH 434/489] util: delete unused return value for epoll_wait_manager Delete unused return value for epoll_wait_manager. Signed-off-by: Yan Wang --- util/src/loop_context.rs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/util/src/loop_context.rs b/util/src/loop_context.rs index 91c96989..d1a3f9bf 100644 --- a/util/src/loop_context.rs +++ b/util/src/loop_context.rs @@ -553,10 +553,11 @@ impl EventLoopContext { } } - self.epoll_wait_manager(self.timers_min_duration()) + self.epoll_wait_manager(self.timers_min_duration())?; + Ok(true) } - pub fn iothread_run(&mut self) -> Result { + pub fn iothread_run(&mut self) -> Result<()> { let min_timeout_ns = self.timers_min_duration(); if min_timeout_ns.is_none() { for _i in 0..AIO_PRFETCH_CYCLE_TIME { @@ -572,7 +573,8 @@ impl EventLoopContext { } } } - self.epoll_wait_manager(min_timeout_ns) + self.epoll_wait_manager(min_timeout_ns)?; + Ok(()) } /// Call the function given by `func` after `delay` time. @@ -651,7 +653,7 @@ impl EventLoopContext { } } - fn epoll_wait_manager(&mut self, mut time_out: Option) -> Result { + fn epoll_wait_manager(&mut self, mut time_out: Option) -> Result<()> { let need_kick = !(time_out.is_some() && *time_out.as_ref().unwrap() == Duration::ZERO); if need_kick { self.kick_me.store(true, Ordering::SeqCst); @@ -712,7 +714,7 @@ impl EventLoopContext { self.run_timers(); self.clear_gc(); - Ok(true) + Ok(()) } pub fn clean_event_loop(&mut self) -> Result<()> { -- Gitee From af639e635cb1c0e5dc77d1c31faf62542008f0f0 Mon Sep 17 00:00:00 2001 From: sujerry1991 Date: Wed, 23 Oct 2024 16:37:10 +0800 Subject: [PATCH 435/489] machine_manager: fix cargo clippy warnings Using "xxx.is_ok()" instead of "let Ok(_) = xxx". Signed-off-by: Yan Wang --- machine_manager/src/event_loop.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/machine_manager/src/event_loop.rs b/machine_manager/src/event_loop.rs index d8d858b3..c3eb2999 100644 --- a/machine_manager/src/event_loop.rs +++ b/machine_manager/src/event_loop.rs @@ -85,7 +85,7 @@ impl EventLoop { id: id.to_string(), }; IOTHREADS.lock().unwrap().push(iothread_info); - while let Ok(_) = ctx.iothread_run() { + while ctx.iothread_run().is_ok() { // If is_cleaned() is true, it means the main thread will exit. // So, exit the iothread. if TempCleaner::is_cleaned() { -- Gitee From 21d30b29d0dd6b00cafd155eb72c25ee4b1aaa58 Mon Sep 17 00:00:00 2001 From: sujerry1991 Date: Wed, 23 Oct 2024 18:32:33 +0800 Subject: [PATCH 436/489] virtio-block: fix the ut test_iothread Add TempCleaner::object_init()/clean() to fix the ut test_iothread. Signed-off-by: Yan Wang --- virtio/src/device/block.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/virtio/src/device/block.rs b/virtio/src/device/block.rs index 45b91944..25b18036 100644 --- a/virtio/src/device/block.rs +++ b/virtio/src/device/block.rs @@ -1448,6 +1448,7 @@ mod tests { use machine_manager::config::{ str_slip_to_clap, IothreadConfig, VmConfig, DEFAULT_VIRTQUEUE_SIZE, }; + use machine_manager::temp_cleaner::TempCleaner; const QUEUE_NUM_BLK: usize = 1; const CONFIG_SPACE_SIZE: usize = 60; @@ -1628,6 +1629,7 @@ mod tests { // io request will be handled by this thread. #[test] fn test_iothread() { + TempCleaner::object_init(); let thread_name = "io1".to_string(); // spawn io thread @@ -1785,6 +1787,7 @@ mod tests { break; } } + TempCleaner::clean(); EventLoop::loop_clean(); } } -- Gitee From 405fa1231bdf75db60a0dad53bf8826884ff8959 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Tue, 22 Oct 2024 16:33:16 +0800 Subject: [PATCH 437/489] ozonec/seccomp: Fix parsing notify action Futhermore, more unit test cases are added. --- ozonec/src/linux/seccomp.rs | 58 ++++++++++++++++++++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/ozonec/src/linux/seccomp.rs b/ozonec/src/linux/seccomp.rs index 3fdc35e3..14f4ea4c 100644 --- a/ozonec/src/linux/seccomp.rs +++ b/ozonec/src/linux/seccomp.rs @@ -31,7 +31,7 @@ fn parse_action(action: OciSeccompAction, errno: Option) -> ScmpAction { OciSeccompAction::ScmpActTrace => ScmpAction::Trace(errno as u16), OciSeccompAction::ScmpActLog => ScmpAction::Log, OciSeccompAction::ScmpActAllow => ScmpAction::Allow, - _ => ScmpAction::KillThread, + OciSeccompAction::ScmpActNotify => ScmpAction::Notify, } } @@ -128,6 +128,62 @@ mod tests { use super::*; + #[test] + fn test_parse_action() { + assert_eq!( + parse_action(OciSeccompAction::ScmpActKill, None), + ScmpAction::KillThread + ); + assert_eq!( + parse_action(OciSeccompAction::ScmpActKillProcess, None), + ScmpAction::KillProcess + ); + assert_eq!( + parse_action(OciSeccompAction::ScmpActTrap, None), + ScmpAction::Trap + ); + assert_eq!( + parse_action(OciSeccompAction::ScmpActErrno, Some(1)), + ScmpAction::Errno(1) + ); + assert_eq!( + parse_action(OciSeccompAction::ScmpActTrace, Some(1)), + ScmpAction::Trace(1) + ); + assert_eq!( + parse_action(OciSeccompAction::ScmpActLog, None), + ScmpAction::Log + ); + assert_eq!( + parse_action(OciSeccompAction::ScmpActAllow, None), + ScmpAction::Allow + ); + assert_eq!( + parse_action(OciSeccompAction::ScmpActNotify, None), + ScmpAction::Notify + ); + } + + #[test] + fn test_parse_cmp() { + assert_eq!(parse_cmp(SeccompOp::ScmpCmpNe, 0), ScmpCompareOp::NotEqual); + assert_eq!(parse_cmp(SeccompOp::ScmpCmpLt, 0), ScmpCompareOp::Less); + assert_eq!( + parse_cmp(SeccompOp::ScmpCmpLe, 0), + ScmpCompareOp::LessOrEqual + ); + assert_eq!(parse_cmp(SeccompOp::ScmpCmpEq, 0), ScmpCompareOp::Equal); + assert_eq!( + parse_cmp(SeccompOp::ScmpCmpGe, 0), + ScmpCompareOp::GreaterEqual + ); + assert_eq!(parse_cmp(SeccompOp::ScmpCmpGt, 0), ScmpCompareOp::Greater); + assert_eq!( + parse_cmp(SeccompOp::ScmpCmpMaskedEq, 1), + ScmpCompareOp::MaskedEqual(1) + ); + } + #[test] fn test_check_seccomp() { let mut seccomp = Seccomp { -- Gitee From 320ec06ccbda3acfbc8d2fd4ec8112da0dcfcb08 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Tue, 22 Oct 2024 16:53:40 +0800 Subject: [PATCH 438/489] ozonec/process: No operations needed when --console-socket not specified --- ozonec/src/linux/process.rs | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/ozonec/src/linux/process.rs b/ozonec/src/linux/process.rs index 2159727d..6ce1b911 100644 --- a/ozonec/src/linux/process.rs +++ b/ozonec/src/linux/process.rs @@ -34,10 +34,7 @@ use nix::{ }; use rlimit::{setrlimit, Resource, Rlim}; -use super::{ - apparmor, - terminal::{connect_stdio, setup_console}, -}; +use super::{apparmor, terminal::setup_console}; use crate::utils::{prctl, Clone3, OzonecErr}; use oci_spec::{linux::IoPriClass, process::Process as OciProcess}; @@ -76,14 +73,6 @@ impl Process { } setup_console(&console_fd.unwrap().as_raw_fd(), mount) .with_context(|| "Failed to setup console")?; - } else { - connect_stdio( - self.stdin.as_ref().unwrap(), - self.stdout.as_ref().unwrap(), - self.stderr.as_ref().unwrap(), - )?; - // SAFETY: FFI call with valid arguments. - unsafe { libc::ioctl(0, libc::TIOCSCTTY) }; } Ok(()) } -- Gitee From cacda1fdfc11818ff65619fcede220e378cef19f Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Wed, 23 Oct 2024 10:52:48 +0800 Subject: [PATCH 439/489] ozonec/container: Set rlimits before entering user namespace After entering user namespace, some permissions may lost to raise the limits. --- ozonec/src/linux/container.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index 0e627fb4..48c0d7ea 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -131,8 +131,6 @@ impl LinuxContainer { ) -> Result<()> { debug!("First stage process start"); - self.set_user_namespace(parent_channel, fst_stage_channel, process)?; - fst_stage_channel .receiver .close() @@ -141,6 +139,7 @@ impl LinuxContainer { process .set_rlimits() .with_context(|| "Failed to set rlimit")?; + self.set_user_namespace(parent_channel, fst_stage_channel, process)?; // New pid namespace goes intto effect in cloned child processes. self.set_pid_namespace()?; -- Gitee From cee6e460825a332da04216966d4a24acc07d4263 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Wed, 23 Oct 2024 11:19:02 +0800 Subject: [PATCH 440/489] ozonec/container: Fix setting mount namespace by default Fix commit c438901 (ozonec/linux: Add namespace support) --- ozonec/src/linux/container.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index 48c0d7ea..cb023a48 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -480,13 +480,15 @@ impl LinuxContainer { fn set_rest_namespaces(&self) -> Result<()> { let ns_config = &self.config.linux.as_ref().unwrap().namespaces; let ns_controller: NsController = ns_config.clone().try_into()?; + let mut mnt_ns = false; for ns in ns_config { match ns.ns_type { // User namespace and pid namespace have been set in the first stage. // Mount namespace is going to be set later to avoid failure with // existed namespaces. - NamespaceType::User | NamespaceType::Pid | NamespaceType::Mount => (), + NamespaceType::User | NamespaceType::Pid => (), + NamespaceType::Mount => mnt_ns = true, _ => ns_controller.set_namespace(ns.ns_type).with_context(|| { format!( "Failed to set {} namespace", @@ -518,9 +520,11 @@ impl LinuxContainer { } } - ns_controller - .set_namespace(NamespaceType::Mount) - .with_context(|| "Failed to set mount namespace")?; + if mnt_ns { + ns_controller + .set_namespace(NamespaceType::Mount) + .with_context(|| "Failed to set mount namespace")?; + } Ok(()) } -- Gitee From 69ed1476528bf55544b188e19ccde98d7217c9c1 Mon Sep 17 00:00:00 2001 From: Mingwang Li Date: Tue, 22 Oct 2024 20:55:07 +0800 Subject: [PATCH 441/489] usbhost: add Muext for usbhost when VM exits abnormally When the VM exits abnormally, the usbhost may be running commands. In this case, attach_kernel may trigger the usbhost busy and do not release to the host. Signed-off-by: Mingwang Li --- devices/src/usb/usbhost/mod.rs | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/devices/src/usb/usbhost/mod.rs b/devices/src/usb/usbhost/mod.rs index 17a888a5..4dcade11 100644 --- a/devices/src/usb/usbhost/mod.rs +++ b/devices/src/usb/usbhost/mod.rs @@ -401,8 +401,6 @@ pub struct UsbHost { /// Configuration interface number. ifs_num: u8, ifs: [InterfaceStatus; USB_MAX_INTERFACES as usize], - /// Callback for release dev to Host after the vm exited. - exit: Option>, /// All pending asynchronous usb request. requests: Arc>>, /// ISO queues corresponding to all endpoints. @@ -439,7 +437,6 @@ impl UsbHost { ifs_num: 0, ifs: [InterfaceStatus::default(); USB_MAX_INTERFACES as usize], base: UsbDeviceBase::new(id, USB_HOST_BUFFER_LEN), - exit: None, requests: Arc::new(Mutex::new(List::new())), iso_queues: Arc::new(Mutex::new(LinkedList::new())), iso_urb_frames, @@ -685,19 +682,6 @@ impl UsbHost { Ok(()) } - fn register_exit(&mut self) { - let exit = self as *const Self as u64; - let exit_notifier = Arc::new(move || { - let usb_host = - // SAFETY: This callback is deleted after the device hot-unplug, so it is called only - // when the vm exits abnormally. - &mut unsafe { std::slice::from_raw_parts_mut(exit as *mut UsbHost, 1) }[0]; - usb_host.release_dev_to_host(); - }) as Arc; - self.exit = Some(exit_notifier.clone()); - TempCleaner::add_exit_notifier(self.device_id().to_string(), exit_notifier); - } - fn release_interfaces(&mut self) { for i in 0..self.ifs_num { if !self.ifs[i as usize].claimed { @@ -1053,6 +1037,17 @@ impl EventNotifierHelper for UsbHost { } } +fn register_exit(usbhost: Arc>) { + let usbhost_cloned = usbhost.clone(); + let exit_notifier = Arc::new(move || { + usbhost_cloned.lock().unwrap().release_dev_to_host(); + }) as Arc; + TempCleaner::add_exit_notifier( + usbhost.lock().unwrap().device_id().to_string(), + exit_notifier, + ); +} + impl UsbDevice for UsbHost { gen_base_func!(usb_device_base, usb_device_base_mut, UsbDeviceBase, base); @@ -1065,7 +1060,7 @@ impl UsbDevice for UsbHost { let notifiers = EventNotifierHelper::internal_notifiers(usbhost.clone()); register_event_helper(notifiers, None, &mut usbhost.lock().unwrap().libevt)?; // UsbHost addr is changed after Arc::new, so so the registration must be here. - usbhost.lock().unwrap().register_exit(); + register_exit(usbhost.clone()); Ok(usbhost) } -- Gitee From 8f82f7c0b864e3de0e55313d7898a6c9d0576eed Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Wed, 16 Oct 2024 02:24:04 +0800 Subject: [PATCH 442/489] ozonec/tests: Add description about bundle preparation Signed-off-by: frankyj915 --- ozonec/tests/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ozonec/tests/README.md b/ozonec/tests/README.md index c33982d5..c9d98cfe 100644 --- a/ozonec/tests/README.md +++ b/ozonec/tests/README.md @@ -12,7 +12,7 @@ $ cd bats-core $ ./install.sh /usr/local ``` -And *jq* is may also needed to modify json file in tests. +*bundle* directory which includes *config.json* and *rootfs* directory may be required to archived to bundle.tar.gz under the directory the test script belongs to. And *jq* may also be needed to modify json file in tests. ## Running tests -- Gitee From e5334923c3a9890de2bc3ce1407f00749281b485 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Wed, 16 Oct 2024 13:10:56 +0800 Subject: [PATCH 443/489] ozonec/tests: Add pty-server tool to test --console-socket api Signed-off-by: frankyj915 --- ozonec/tests/tools/pty-server/Cargo.lock | 194 ++++++++++++++++++++++ ozonec/tests/tools/pty-server/Cargo.toml | 24 +++ ozonec/tests/tools/pty-server/src/main.rs | 123 ++++++++++++++ 3 files changed, 341 insertions(+) create mode 100644 ozonec/tests/tools/pty-server/Cargo.lock create mode 100644 ozonec/tests/tools/pty-server/Cargo.toml create mode 100644 ozonec/tests/tools/pty-server/src/main.rs diff --git a/ozonec/tests/tools/pty-server/Cargo.lock b/ozonec/tests/tools/pty-server/Cargo.lock new file mode 100644 index 00000000..68cf35c3 --- /dev/null +++ b/ozonec/tests/tools/pty-server/Cargo.lock @@ -0,0 +1,194 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anyhow" +version = "1.0.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c7d0618f0e0b7e8ff11427422b64564d5fb0be1940354bfe2e0529b18a9d9b8" + +[[package]] +name = "autocfg" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "4.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f13b9c79b5d1dd500d20ef541215a6423c75829ef43117e1b4d17fd8af0b5d76" +dependencies = [ + "bitflags", + "clap_derive", + "clap_lex", + "once_cell", +] + +[[package]] +name = "clap_derive" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "684a277d672e91966334af371f1a7b5833f9aa00b07c84e92fbce95e00208ce8" +dependencies = [ + "heck", + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "033f6b7a4acb1f358c742aaca805c939ee73b4c6209ae4318ec7aca81c42e646" +dependencies = [ + "os_str_bytes", +] + +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + +[[package]] +name = "libc" +version = "0.2.159" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "561d97a539a36e26a9a5fad1ea11a3039a67714694aaa379433e580854bc3dc5" + +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + +[[package]] +name = "nix" +version = "0.26.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfdda3d196821d6af13126e40375cdf7da646a96114af134d5f417a9a1dc8e1a" +dependencies = [ + "bitflags", + "cfg-if", + "libc", + "memoffset", + "pin-utils", + "static_assertions", +] + +[[package]] +name = "once_cell" +version = "1.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775" + +[[package]] +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "syn", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.87" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3e4daa0dcf6feba26f985457cdf104d4b4256fc5a09547140f3631bb076b19a" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "pty-server" +version = "0.1.0" +dependencies = [ + "anyhow", + "clap", + "nix", +] + +[[package]] +name = "quote" +version = "1.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b9d34b8991d19d98081b46eacdd8eb58c6f2b201139f7c5f643cc155a633af" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" diff --git a/ozonec/tests/tools/pty-server/Cargo.toml b/ozonec/tests/tools/pty-server/Cargo.toml new file mode 100644 index 00000000..93889af0 --- /dev/null +++ b/ozonec/tests/tools/pty-server/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "pty-server" +version = "0.1.0" +authors = ["Huawei StratoVirt Team"] +edition = "2021" +license = "Mulan PSL v2" +description = "A reference implementation of a consumer of ozonec's --console-socket API." + +[dependencies] +anyhow = "= 1.0.71" +clap = { version = "= 4.1.4", default-features = false, features = ["derive", "cargo", "std", "help", "usage"] } +nix = "= 0.26.2" + +[workspace] + +[profile.dev] +panic = "unwind" + +[profile.release] +lto = true +strip = true +opt-level = 'z' +codegen-units = 1 +panic = "abort" diff --git a/ozonec/tests/tools/pty-server/src/main.rs b/ozonec/tests/tools/pty-server/src/main.rs new file mode 100644 index 00000000..533dfb46 --- /dev/null +++ b/ozonec/tests/tools/pty-server/src/main.rs @@ -0,0 +1,123 @@ +// Copyright (c) 2024 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::{ + fs::File, + io::{self, stdin, stdout, IoSliceMut}, + os::{ + fd::{AsRawFd, FromRawFd, RawFd}, + unix::net::{UnixListener, UnixStream}, + }, + process::exit, + thread, +}; + +use anyhow::{anyhow, bail, Context, Result}; +use clap::{builder::NonEmptyStringValueParser, crate_description, Parser}; +use nix::{ + cmsg_space, + errno::errno, + sys::{ + socket::{recvmsg, ControlMessageOwned, MsgFlags, UnixAddr}, + termios::{tcgetattr, tcsetattr, OutputFlags, SetArg}, + }, +}; + +#[derive(Parser, Debug)] +#[command(version, author, about = crate_description!())] +struct Cli { + #[arg(short, long)] + pub no_stdin: bool, + // Specify path of console socket to connect. + #[arg(value_parser = NonEmptyStringValueParser::new(), required = true)] + pub console_socket: String, +} + +fn clear_onlcr(fd: RawFd) -> Result<()> { + let mut termios = + tcgetattr(fd).with_context(|| anyhow!("tcgetattr error: errno {}, fd: {}", errno(), fd))?; + termios.output_flags &= !OutputFlags::ONLCR; + tcsetattr(fd, SetArg::TCSANOW, &termios) + .with_context(|| anyhow!("tcsetattr error: errno {}", errno()))?; + Ok(()) +} + +fn handle_connection(stream: &UnixStream, no_stdin: bool) -> Result<()> { + let mut msg_iov = Vec::with_capacity(10); + let mut iov = [IoSliceMut::new(msg_iov.as_mut_slice())]; + let mut cmsg_buffer = cmsg_space!([RawFd; 1]); + let mut master: RawFd = -1; + + let ret = recvmsg::( + stream.as_raw_fd(), + &mut iov, + Some(&mut cmsg_buffer), + MsgFlags::empty(), + ) + .with_context(|| "recvmsg error")?; + for ctl_msg in ret.cmsgs() { + match ctl_msg { + ControlMessageOwned::ScmRights(fds) => master = fds[0], + _ => (), + } + } + + clear_onlcr(master)?; + let output = thread::spawn(move || { + let mut us = unsafe { File::from_raw_fd(master) }; + io::copy(&mut us, &mut stdout()) + }); + if !no_stdin { + let input = thread::spawn(move || { + let mut us = unsafe { File::from_raw_fd(master) }; + io::copy(&mut stdin(), &mut us) + }); + if let Err(e) = input.join().expect("Input thread has exited.") { + eprintln!("Input thread error: {}", e); + } + } + if let Err(e) = output.join().expect("Output thread has exited.") { + eprintln!("Output thread error: {}", e); + } + + Ok(()) +} + +fn listen_on_socket(listener: &UnixListener, no_stdin: bool) -> Result<()> { + for stream in listener.incoming() { + match stream { + Ok(s) => handle_connection(&s, no_stdin)?, + Err(e) => bail!("Failed to accept incoming connection: {}", e), + } + } + Ok(()) +} + +fn real_main() -> Result<()> { + let cli = Cli::parse(); + + let listener = + UnixListener::bind(&cli.console_socket).with_context(|| "Failed to bind to the socket")?; + listen_on_socket(&listener, cli.no_stdin)?; + + Ok(()) +} + +fn main() { + match real_main() { + Ok(_) => exit(0), + Err(e) => { + eprintln!("{}", e); + exit(1) + } + } +} -- Gitee From 65573b984953311a956ac71609313cf0256cab87 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Mon, 21 Oct 2024 09:20:52 +0800 Subject: [PATCH 444/489] ozonec/tests: Add console.bats Signed-off-by: frankyj915 --- ozonec/tests/console.bats | 44 +++++++++++++++++++++++++++++++++++++++ ozonec/tests/create.bats | 5 ----- ozonec/tests/exec.bats | 1 - ozonec/tests/helpers.bash | 10 ++++++--- 4 files changed, 51 insertions(+), 9 deletions(-) create mode 100644 ozonec/tests/console.bats diff --git a/ozonec/tests/console.bats b/ozonec/tests/console.bats new file mode 100644 index 00000000..480f310a --- /dev/null +++ b/ozonec/tests/console.bats @@ -0,0 +1,44 @@ +#! /usr/bin/env bats + +load helpers + +setup_file() +{ + setup_bundle +} + +setup() +{ + CONTAINER_ID=$(uuidgen) + setup_pty_server +} + +teardown() +{ + ozonec kill "$CONTAINER_ID" + ozonec delete "$CONTAINER_ID" + killall -9 pty-server + rm -f $TEST_DIR/console* +} + +@test "ozonec create with console socket" { + update_config '.process.terminal = true' + update_config '.process.args = ["ls", "-alh"]' + ozonec create --console-socket "$CONSOLE_PATH" "$CONTAINER_ID" 3>&- + + run ozonec start "$CONTAINER_ID" + [[ $status -eq 0 ]] + run sed -n '1p' $TEST_DIR/console.log + [[ ${lines[0]} == *"total "* ]] +} + +@test "ozonec exec with console socket" { + update_config '.process.terminal = false' + update_config '.process.args = ["sleep", "3600"]' + ozonec create "$CONTAINER_ID" 3>&- + ozonec start "$CONTAINER_ID" + + run ozonec exec -t --console-socket "$CONSOLE_PATH" "$CONTAINER_ID" -- ls -alh + run sed -n '1p' $TEST_DIR/console.log + [[ ${lines[0]} == *"total "* ]] +} \ No newline at end of file diff --git a/ozonec/tests/create.bats b/ozonec/tests/create.bats index 02d44c8b..15b06b7a 100644 --- a/ozonec/tests/create.bats +++ b/ozonec/tests/create.bats @@ -7,11 +7,6 @@ setup_file() setup_bundle } -teardown_file() -{ - remove_test_dir -} - setup() { CONTAINER_ID=$(uuidgen) diff --git a/ozonec/tests/exec.bats b/ozonec/tests/exec.bats index ffdf6c38..418c07a1 100644 --- a/ozonec/tests/exec.bats +++ b/ozonec/tests/exec.bats @@ -19,7 +19,6 @@ teardown_file() { ozonec --root "$ROOT_DIR" kill "$CONTAINER_ID" 9 ozonec --root "$ROOT_DIR" delete "$CONTAINER_ID" - remove_test_dir } @test "ozonec exec" { diff --git a/ozonec/tests/helpers.bash b/ozonec/tests/helpers.bash index 781fa653..b37f098d 100644 --- a/ozonec/tests/helpers.bash +++ b/ozonec/tests/helpers.bash @@ -13,7 +13,7 @@ function update_config() function setup_bundle() { # Directory for each container. - TEST_DIR=$(mktemp -d "$BATS_RUN_TMPDIR/ozonec.XXXXXX") + export TEST_DIR=$(mktemp -d "$BATS_RUN_TMPDIR/ozonec.XXXXXX") chmod a+x "$TEST_DIR" "$BATS_RUN_TMPDIR" local bundle="$BATS_TEST_DIRNAME/bundle.tar.gz" @@ -21,9 +21,13 @@ function setup_bundle() cd "$TEST_DIR/bundle" } -function remove_test_dir() +function setup_pty_server() { - rm -rf "$TEST_DIR" + export CONSOLE_PATH="$TEST_DIR/console.sock" + rm -f $CONSOLE_PATH + # Fork twice to avoid sending SIGTTIN/SIGTTOU to pty-server. + # --no-stdin option is set to avoid SIGHUP sent to ozonec. + (pty-server --no-stdin $CONSOLE_PATH > $TEST_DIR/console.log &) & } function check_container_status() { -- Gitee From ba9152c8a0888142ac55b82e2504b19d74274bdc Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Mon, 21 Oct 2024 09:21:14 +0800 Subject: [PATCH 445/489] ozonec/tests: Archive the basic config.json for test Signed-off-by: frankyj915 --- ozonec/tests/config.json | 170 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 ozonec/tests/config.json diff --git a/ozonec/tests/config.json b/ozonec/tests/config.json new file mode 100644 index 00000000..4698e5e5 --- /dev/null +++ b/ozonec/tests/config.json @@ -0,0 +1,170 @@ +{ + "ociVersion": "1.0.2-dev", + "process": { + "user": { + "uid": 0, + "gid": 0 + }, + "args": [ + "sleep", + "3600" + ], + "env": [ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "TERM=xterm" + ], + "cwd": "/", + "capabilities": { + "bounding": [ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE" + ], + "effective": [ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE" + ], + "permitted": [ + "CAP_AUDIT_WRITE", + "CAP_KILL", + "CAP_NET_BIND_SERVICE" + ] + }, + "rlimits": [ + { + "type": "RLIMIT_NOFILE", + "hard": 1024, + "soft": 1024 + } + ], + "noNewPrivileges": true + }, + "root": { + "path": "rootfs", + "readonly": true + }, + "hostname": "runc", + "mounts": [ + { + "destination": "/proc", + "type": "proc", + "source": "proc" + }, + { + "destination": "/dev", + "type": "tmpfs", + "source": "tmpfs", + "options": [ + "nosuid", + "strictatime", + "mode=755", + "size=65536k" + ] + }, + { + "destination": "/dev/pts", + "type": "devpts", + "source": "devpts", + "options": [ + "nosuid", + "noexec", + "newinstance", + "ptmxmode=0666", + "mode=0620", + "gid=5" + ] + }, + { + "destination": "/dev/shm", + "type": "tmpfs", + "source": "shm", + "options": [ + "nosuid", + "noexec", + "nodev", + "mode=1777", + "size=65536k" + ] + }, + { + "destination": "/dev/mqueue", + "type": "mqueue", + "source": "mqueue", + "options": [ + "nosuid", + "noexec", + "nodev" + ] + }, + { + "destination": "/sys", + "type": "sysfs", + "source": "sysfs", + "options": [ + "nosuid", + "noexec", + "nodev", + "ro" + ] + }, + { + "destination": "/sys/fs/cgroup", + "type": "cgroup", + "source": "cgroup", + "options": [ + "nosuid", + "noexec", + "nodev", + "relatime", + "ro" + ] + } + ], + "linux": { + "resources": { + "devices": [ + { + "allow": false, + "access": "rwm" + } + ] + }, + "namespaces": [ + { + "type": "pid" + }, + { + "type": "network" + }, + { + "type": "ipc" + }, + { + "type": "uts" + }, + { + "type": "mount" + } + ], + "maskedPaths": [ + "/proc/acpi", + "/proc/asound", + "/proc/kcore", + "/proc/keys", + "/proc/latency_stats", + "/proc/timer_list", + "/proc/timer_stats", + "/proc/sched_debug", + "/sys/firmware", + "/proc/scsi" + ], + "readonlyPaths": [ + "/proc/bus", + "/proc/fs", + "/proc/irq", + "/proc/sys", + "/proc/sysrq-trigger" + ] + } +} -- Gitee From 815f16e1db85edfc1e76fefbf810dd45e3c7a932 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Tue, 22 Oct 2024 11:44:58 +0800 Subject: [PATCH 446/489] ozonec/tests: Add mount.bats Signed-off-by: frankyj915 --- ozonec/tests/mount.bats | 107 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 ozonec/tests/mount.bats diff --git a/ozonec/tests/mount.bats b/ozonec/tests/mount.bats new file mode 100644 index 00000000..ab563541 --- /dev/null +++ b/ozonec/tests/mount.bats @@ -0,0 +1,107 @@ +#! /usr/bin/env bats + +load helpers + +setup_file() +{ + setup_bundle +} + +setup() +{ + CONTAINER_ID=$(uuidgen) + setup_pty_server +} + +teardown() +{ + ozonec kill "$CONTAINER_ID" 9 + ozonec delete "$CONTAINER_ID" + killall -9 pty-server + rm -f $TEST_DIR/console* +} + +@test "ozonec with bind mount" { + update_config '.mounts += [{ + source: ".", + destination: "/tmp/rbind", + options: ["rbind"] + }]' + + ozonec create "$CONTAINER_ID" 3>&- + ozonec start "$CONTAINER_ID" + ozonec exec -t --console-socket "$CONSOLE_PATH" "$CONTAINER_ID" -- ls /tmp/rbind/config.json + run sed -n '1p' $TEST_DIR/console.log + [[ ${lines[0]} == *"/tmp/rbind/config.json"* ]] +} + +@test "ozonec mount /proc" { + ozonec create "$CONTAINER_ID" 3>&- + ozonec start "$CONTAINER_ID" + ozonec exec -t --console-socket "$CONSOLE_PATH" "$CONTAINER_ID" -- grep "^proc /proc proc " /proc/mounts + run sed -n '1p' $TEST_DIR/console.log + [[ ${lines[0]} == *"proc /proc proc "* ]] +} + +@test "ozonec mount /sys" { + ozonec create "$CONTAINER_ID" 3>&- + ozonec start "$CONTAINER_ID" + ozonec exec -t --console-socket "$CONSOLE_PATH" "$CONTAINER_ID" -- grep "^sysfs /sys sysfs " /proc/mounts + run sed -n '1p' $TEST_DIR/console.log + [[ ${lines[0]} == *"sysfs /sys "*"ro"*"nosuid"*"nodev"*"noexec"* ]] +} + +@test "ozonec mount /dev/pts" { + ozonec create "$CONTAINER_ID" 3>&- + ozonec start "$CONTAINER_ID" + ozonec exec -t --console-socket "$CONSOLE_PATH" "$CONTAINER_ID" -- grep "^devpts /dev/pts devpts " /proc/mounts + run sed -n '1p' $TEST_DIR/console.log + [[ ${lines[0]} == *"devpts /dev/pts devpts "*"nosuid"*"noexec"*"gid=5"*"mode=620"*"ptmxmode=666"* ]] +} + +@test "ozonec mount /dev/shm" { + ozonec create "$CONTAINER_ID" 3>&- + ozonec start "$CONTAINER_ID" + ozonec exec -t --console-socket "$CONSOLE_PATH" "$CONTAINER_ID" -- grep "^shm /dev/shm tmpfs" /proc/mounts + run sed -n '1p' $TEST_DIR/console.log + [[ ${lines[0]} == *"/dev/shm tmpfs "*"nosuid"*"nodev"*"noexec"*"size=65536k"* ]] +} + +@test "ozonec default devices" { + ozonec create "$CONTAINER_ID" 3>&- + ozonec start "$CONTAINER_ID" + + ozonec exec -t --console-socket "$CONSOLE_PATH" "$CONTAINER_ID" -- ls -al /dev/ + run grep -w "null" $TEST_DIR/console.log + [[ $status -eq 0 ]] + run grep -w "zero" $TEST_DIR/console.log + [[ $status -eq 0 ]] + run grep -w "full" $TEST_DIR/console.log + [[ $status -eq 0 ]] + run grep -w "random" $TEST_DIR/console.log + [[ $status -eq 0 ]] + run grep -w "urandom" $TEST_DIR/console.log + [[ $status -eq 0 ]] + run grep -w "tty" $TEST_DIR/console.log + [[ $status -eq 0 ]] + run grep -w "console" $TEST_DIR/console.log + [[ $status -ne 0 ]] + run grep -w "console" $TEST_DIR/console.log + [[ $status -ne 0 ]] + + rm -f $TEST_DIR/console.log + ozonec exec -t --console-socket "$CONSOLE_PATH" "$CONTAINER_ID" -- ls -al /dev/pts/ptmx + run grep -w "/dev/pts/ptmx" $TEST_DIR/console.log + [[ $status -ne 0 ]] +} + +@test "ozonec create /dev/console" { + update_config '.process.terminal = true' + update_config '.process.args = ["ls", "/dev/console"]' + ozonec create --console-socket "$CONSOLE_PATH" "$CONTAINER_ID" 3>&- + ozonec start "$CONTAINER_ID" + + cat $TEST_DIR/console.log + run sed -n '1p' $TEST_DIR/console.log + [[ ${lines[0]} == *"/dev/console"* ]] +} \ No newline at end of file -- Gitee From 9feec92d8bf760cb1f3728fe5b1ba2f0c9691ad6 Mon Sep 17 00:00:00 2001 From: frankyj915 Date: Tue, 22 Oct 2024 15:28:19 +0800 Subject: [PATCH 447/489] ozonec/tests: Add namespace.bats Signed-off-by: frankyj915 --- ozonec/tests/namespace.bats | 51 +++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 ozonec/tests/namespace.bats diff --git a/ozonec/tests/namespace.bats b/ozonec/tests/namespace.bats new file mode 100644 index 00000000..e4e22b4d --- /dev/null +++ b/ozonec/tests/namespace.bats @@ -0,0 +1,51 @@ +#! /usr/bin/env bats + +load helpers + +setup_file() +{ + setup_bundle +} + +setup() +{ + CONTAINER_ID=$(uuidgen) +} + +teardown() +{ + ozonec kill "$CONTAINER_ID" 9 + ozonec delete "$CONTAINER_ID" +} + +@test "ozonec create new namespace" { + ozonec create -p $TEST_DIR/ozonec.pid "$CONTAINER_ID" 3>&- + ozonec start "$CONTAINER_ID" + + local self_mnt_ns=$(readlink /proc/self/ns/mnt) + local container_pid=$(cat $TEST_DIR/ozonec.pid) + local container_mnt_ns=$(readlink /proc/$container_pid/ns/mnt) + [[ "$self_mnt_ns" != "$container_mnt_ns" ]] +} + +@test "ozonec join existed namespace" { + ozonec create -p $TEST_DIR/fst.pid "$CONTAINER_ID" 3>&- + ozonec start "$CONTAINER_ID" + local fst_container_pid=$(cat $TEST_DIR/fst.pid) + local fst_pid_ns=$(readlink /proc/$fst_container_pid/ns/pid) + + update_config '.linux.namespaces |= [{ + type: "pid", + path: "'/proc/$fst_container_pid/ns/pid'" + }, { + type: "mount" + }]' + local sec_container_id=$(uuidgen) + ozonec create -p $TEST_DIR/second.pid "$sec_container_id" 3>&- + ozonec start "$sec_container_id" + local sec_container_pid=$(cat $TEST_DIR/second.pid) + local sec_pid_ns=$(readlink /proc/$sec_container_pid/ns/pid) + ozonec kill "$sec_container_id" 9 + ozonec delete "$sec_container_id" + [[ "$fst_pid_ns" == "$sec_pid_ns" ]] +} \ No newline at end of file -- Gitee From ad3e806d5f2eb2253da8fbf156893d56e1d5f8ec Mon Sep 17 00:00:00 2001 From: liuxiangdong Date: Thu, 10 Oct 2024 21:17:13 +0800 Subject: [PATCH 448/489] image: add `-r` to rename snapshot name Add `-r` in stratovirt-img snapshot method. eg: stratovirt-img snapshot -r old_snapshot_name new_snapshot_name img_path Signed-off-by: liuxiangdong --- block_backend/src/qcow2/mod.rs | 67 ++++++++++-- block_backend/src/qcow2/snapshot.rs | 8 +- docs/stratovirt-img.md | 4 +- image/src/img.rs | 156 +++++++++++++++++++++++++++- 4 files changed, 217 insertions(+), 18 deletions(-) diff --git a/block_backend/src/qcow2/mod.rs b/block_backend/src/qcow2/mod.rs index 30c72b60..011b4485 100644 --- a/block_backend/src/qcow2/mod.rs +++ b/block_backend/src/qcow2/mod.rs @@ -928,7 +928,7 @@ impl Qcow2Driver { if self.snapshot.snapshots_number() > 0 { new_snapshots_offset = self.alloc_cluster(new_snapshot_table_clusters, true)?; self.snapshot - .save_snapshot_table(new_snapshots_offset, &snap, false)?; + .save_snapshot_table(new_snapshots_offset, Some(&snap), false)?; } self.snapshot.snapshot_table_offset = new_snapshots_offset; @@ -968,7 +968,7 @@ impl Qcow2Driver { self.table.save_l1_table()?; // Update the snapshot information in qcow2 header. - self.update_snapshot_info_in_header(new_snapshots_offset, false)?; + self.update_snapshot_info_in_header(new_snapshots_offset, -1)?; // Discard unused clusters. self.refcount.sync_process_discards(OpCode::Discard); @@ -1048,7 +1048,7 @@ impl Qcow2Driver { // Append the new snapshot to the snapshot table and write new snapshot table to file. self.snapshot - .save_snapshot_table(new_snapshots_offset, &snap, true)?; + .save_snapshot_table(new_snapshots_offset, Some(&snap), true)?; // Free the old snapshot table cluster if snapshot exists. if self.header.snapshots_offset != 0 { @@ -1068,7 +1068,7 @@ impl Qcow2Driver { self.table.save_l1_table()?; // Update snapshot offset and num in qcow2 header. - self.update_snapshot_info_in_header(new_snapshots_offset, true)?; + self.update_snapshot_info_in_header(new_snapshots_offset, 1)?; // Add and update snapshot information in memory. self.snapshot.add_snapshot(snap); @@ -1080,14 +1080,10 @@ impl Qcow2Driver { Ok(()) } - fn update_snapshot_info_in_header(&mut self, snapshot_offset: u64, add: bool) -> Result<()> { + fn update_snapshot_info_in_header(&mut self, snapshot_offset: u64, add: i32) -> Result<()> { let mut new_header = self.header.clone(); new_header.snapshots_offset = snapshot_offset; - if add { - new_header.nb_snapshots += 1; - } else { - new_header.nb_snapshots -= 1; - } + new_header.nb_snapshots = (new_header.nb_snapshots as i32 + add) as u32; self.sync_aio .borrow_mut() .write_buffer(0, &new_header.to_vec())?; @@ -1422,6 +1418,11 @@ pub trait InternalSnapshotOps: Send + Sync { fn apply_snapshot(&mut self, name: String) -> Result<()>; fn list_snapshots(&self) -> String; fn get_status(&self) -> Arc>; + fn rename_snapshot( + &mut self, + old_snapshot_name: String, + new_snapshot_name: String, + ) -> Result<()>; } impl InternalSnapshotOps for Qcow2Driver { @@ -1461,6 +1462,52 @@ impl InternalSnapshotOps for Qcow2Driver { fn get_status(&self) -> Arc> { self.status.clone() } + + fn rename_snapshot( + &mut self, + old_snapshot_name: String, + new_snapshot_name: String, + ) -> Result<()> { + if self.get_snapshot_by_name(&new_snapshot_name) != -1 { + bail!("New snapshot name {} exits!", new_snapshot_name); + } + + let snap_id = self.get_snapshot_by_name(&old_snapshot_name); + if snap_id < 0 { + bail!("Snapshot name {} doesn't exit!", old_snapshot_name); + } + + // Update snapshot info in memory. Note: Stratovirt-img will exit if next actions fail. + // And these modified snapshot information in memory will not affect. + self.snapshot.snapshots[snap_id as usize].name = new_snapshot_name; + + // Write new snapshot info to new snapshot table. + let old_snapshots_offset = self.header.snapshots_offset; + let cluster_size = self.header.cluster_size(); + let snapshot_table_len = self.snapshot.snapshot_size; + let snapshot_table_clusters = bytes_to_clusters(snapshot_table_len, cluster_size).unwrap(); + let new_snapshots_offset = self.alloc_cluster(snapshot_table_clusters, true)?; + self.snapshot + .save_snapshot_table(new_snapshots_offset, None, true)?; + + // Update the snapshot information in qcow2 header. + self.update_snapshot_info_in_header(new_snapshots_offset, 0)?; + + // Delete old snapshot: Free the cluster of the old snapshot table. + self.refcount.update_refcount( + old_snapshots_offset, + snapshot_table_clusters, + -1, + false, + &Qcow2DiscardType::Snapshot, + )?; + self.flush()?; + + // Discard unused clusters. + self.refcount.sync_process_discards(OpCode::Discard); + + Ok(()) + } } // SAFETY: Send and Sync is not auto-implemented for raw pointer type in Aio. diff --git a/block_backend/src/qcow2/snapshot.rs b/block_backend/src/qcow2/snapshot.rs index 9e8345d5..f0b638f2 100644 --- a/block_backend/src/qcow2/snapshot.rs +++ b/block_backend/src/qcow2/snapshot.rs @@ -98,18 +98,20 @@ impl InternalSnapshot { pub fn save_snapshot_table( &self, addr: u64, - extra_snap: &QcowSnapshot, + extra_snap: Option<&QcowSnapshot>, attach: bool, ) -> Result<()> { let mut buf = Vec::new(); for snap in &self.snapshots { - if !attach && snap.id == extra_snap.id { + if !attach && extra_snap.is_some() && snap.id == extra_snap.unwrap().id { continue; } buf.append(&mut snap.gen_snapshot_table_entry()); } if attach { - buf.append(&mut extra_snap.gen_snapshot_table_entry()); + if let Some(extra) = extra_snap { + buf.append(&mut extra.gen_snapshot_table_entry()); + } } self.sync_aio.borrow_mut().write_buffer(addr, &buf) } diff --git a/docs/stratovirt-img.md b/docs/stratovirt-img.md index 7021e565..cca517a9 100644 --- a/docs/stratovirt-img.md +++ b/docs/stratovirt-img.md @@ -91,13 +91,14 @@ Operating internal snapshot for disk, it is only supported by qcow2. Command syntax: ```shell -snapshot [-l | -a snapshot_name | -c snapshot_name | -d snapshot_name] img_path +snapshot [-l | -a snapshot_name | -c snapshot_name | -d snapshot_name | -r old_snapshot_name new_snapshot_name] img_path ``` - -a snapshot_name: applies a snapshot (revert disk to saved state). - -c snapshot_name: creates a snapshot. - -d snapshot_name: deletes a snapshot. - -l: lists all snapshots in the given image. +- -r old_snapshot_name new_snapshot_name: change the name from 'old_Snapshot_name' to 'new_Snapshot_name'. Sample Configuration: @@ -106,6 +107,7 @@ stratovirt-img snapshot -c snapshot_name img_path stratovirt-img snapshot -a snapshot_name img_path stratovirt-img snapshot -d snapshot_name img_path stratovirt-img snapshot -l img_path +stratovirt-img snapshot -r old_snapshot_name new_snapshot_name img_path ``` Note: The internal snapshot is not supported by raw. diff --git a/image/src/img.rs b/image/src/img.rs index 3e359a3f..2a4f3a40 100644 --- a/image/src/img.rs +++ b/image/src/img.rs @@ -37,6 +37,7 @@ enum SnapshotOperation { Delete, Apply, List, + Rename, } pub struct ImageFile { @@ -380,8 +381,11 @@ pub(crate) fn image_resize(mut args: Vec) -> Result<()> { } pub(crate) fn image_snapshot(args: Vec) -> Result<()> { - let mut arg_parser = - ArgsParse::create(vec!["l", "h", "help"], vec!["f", "c", "d", "a"], vec![]); + let mut arg_parser = ArgsParse::create( + vec!["l", "h", "help", "r"], + vec!["f", "c", "d", "a"], + vec![], + ); arg_parser.parse(args)?; if arg_parser.opt_present("h") || arg_parser.opt_present("help") { @@ -426,11 +430,25 @@ pub(crate) fn image_snapshot(args: Vec) -> Result<()> { snapshot_name = name; } - // Parse image path. let len = arg_parser.free.len(); + + // Rename snapshot name. + let mut old_snapshot_name = String::from(""); + let mut new_snapshot_name = String::from(""); + if arg_parser.opt_present("r") { + if len != 3 { + bail!("Invalid args number."); + } + snapshot_operation = Some(SnapshotOperation::Rename); + old_snapshot_name = arg_parser.free[0].clone(); + new_snapshot_name = arg_parser.free[1].clone(); + } + + // Parse image path. let path = match len { 0 => bail!("Image snapshot requires path"), 1 => arg_parser.free[0].clone(), + 3 => arg_parser.free[2].clone(), _ => { let param = arg_parser.free[1].clone(); bail!("Unexpected argument: {}", param); @@ -475,6 +493,9 @@ pub(crate) fn image_snapshot(args: Vec) -> Result<()> { Some(SnapshotOperation::Apply) => { qcow2_driver.apply_snapshot(snapshot_name)?; } + Some(SnapshotOperation::Rename) => { + qcow2_driver.rename_snapshot(old_snapshot_name, new_snapshot_name)?; + } None => return Ok(()), }; @@ -531,7 +552,7 @@ create [-f fmt] [-o options] filename [size] info filename check [-r [leaks | all]] [-no_print_error] [-f fmt] filename resize [-f fmt] filename [+]size -snapshot [-l | -a snapshot | -c snapshot | -d snapshot] filename +snapshot [-l | -a snapshot | -c snapshot | -d snapshot | -r old_snapshot_name new_snapshot_name] filename Command parameters: 'filename' is a disk image filename @@ -552,6 +573,7 @@ Parameters to snapshot subcommand: '-c' creates a snapshot '-d' deletes a snapshot '-l' lists all snapshots in the given image + '-r' change the name of a snapshot "#, ); } @@ -1569,9 +1591,15 @@ mod test { let test_case = [ ("qcow2", "-c snapshot0 img_path", true), ("qcow2", "-f qcow2 -l img_path", true), + ("qcow2", "-r old_snapshot_name img_path", false), ("qcow2", "-d snapshot0 img_path", false), ("qcow2", "-a snapshot0 img_path", false), ("qcow2", "-c snapshot0 -l img_path", false), + ( + "raw", + "-r old_snapshot_name new_snapshot_name img_path", + false, + ), ("raw", "-f qcow2 -l img_path", false), ("raw", "-l img_path", false), ]; @@ -1683,6 +1711,126 @@ mod test { } } + /// Test the function of snapshot rename. + /// + /// TestStep: + /// 1. Create a new image. alloc a new cluster and write 1. + /// 2. Create snapshot named test_snapshot0, write 2 to the cluster. + /// 3. Create snapshot named test_snapshot1, write 3 to the cluster. + /// 4. Rename test_snapshot0 to test_snapshot0-new. + /// 5. Apply snapshot named test_snapshot0. + /// 6. Apply snapshot named test_snapshot0-new. + /// Expect: + /// 1. step 5 is failure and step 1/2/3/4/6 is success. + /// 2. The data read after snapshot apply is 2. + #[test] + fn test_snapshot_rename_basic() { + let path = "/tmp/test_snapshot_rename_basic.qcow2"; + let cluster_bits = 16; + let cluster_size = 1 << cluster_bits; + let refcount_bits = 16; + + // Create a new image. alloc a new cluster and write 1. + let test_image = TestQcow2Image::create(cluster_bits, refcount_bits, path, "+1G"); + let buf = vec![1_u8; cluster_size as usize]; + assert!(test_image.write_data(0, &buf).is_ok()); + + // Create snapshot named test_snapshot0, write 2 to the cluster. + assert!(image_snapshot(vec![ + "-c".to_string(), + "test_snapshot0".to_string(), + path.to_string() + ]) + .is_ok()); + let buf = vec![2_u8; cluster_size as usize]; + assert!(test_image.write_data(0, &buf).is_ok()); + + // Create snapshot named test_snapshot1, write 3 to the cluster. + assert!(image_snapshot(vec![ + "-c".to_string(), + "test_snapshot1".to_string(), + path.to_string() + ]) + .is_ok()); + let buf = vec![3_u8; cluster_size as usize]; + assert!(test_image.write_data(0, &buf).is_ok()); + + // Rename test_snapshot0 to test_snapshot1. + assert!(image_snapshot(vec![ + "-r".to_string(), + "test_snapshot0".to_string(), + "test_snapshot1".to_string(), + path.to_string() + ]) + .is_err()); + + // Rename test_snapshot0 to test_snapshot0-new. + assert!(image_snapshot(vec![ + "-r".to_string(), + "test_snapshot0".to_string(), + "test_snapshot0-new".to_string(), + path.to_string() + ]) + .is_ok()); + + // Apply snapshot named test_snapshot0. + assert!(image_snapshot(vec![ + "-a".to_string(), + "test_snapshot0".to_string(), + path.to_string() + ]) + .is_err()); + + // Apply snapshot named test_snapshot-new. + assert!(image_snapshot(vec![ + "-a".to_string(), + "test_snapshot0-new".to_string(), + path.to_string() + ]) + .is_ok()); + + // The data read after snapshot apply is 2. + let buf = vec![0_u8; cluster_size as usize]; + assert!(test_image.read_data(0, &buf).is_ok()); + for elem in buf { + assert_eq!(elem, 1); + } + + // Rename non-existed snapshot name. + assert!(image_snapshot(vec![ + "-r".to_string(), + "test_snapshot11111".to_string(), + "test_snapshot11111-new".to_string(), + path.to_string() + ]) + .is_err()); + + let buf = vec![4_u8; cluster_size as usize]; + assert!(test_image.write_data(0, &buf).is_ok()); + + // Rename test_snapshot1 to test_snapshot123. + assert!(image_snapshot(vec![ + "-r".to_string(), + "test_snapshot1".to_string(), + "test_snapshot123".to_string(), + path.to_string() + ]) + .is_ok()); + + // Apply snapshot named test_snapshot123 + assert!(image_snapshot(vec![ + "-a".to_string(), + "test_snapshot123".to_string(), + path.to_string() + ]) + .is_ok()); + let buf = vec![0_u8; cluster_size as usize]; + assert!(test_image.read_data(0, &buf).is_ok()); + for elem in buf { + assert_eq!(elem, 2); + } + } + /// Test the function of resize image. /// /// TestStep: -- Gitee From 3cec519cda87a128b04b815eef7ab19a0e118b7b Mon Sep 17 00:00:00 2001 From: zhanghan Date: Sun, 25 Aug 2024 10:53:56 +0800 Subject: [PATCH 449/489] scream: fix scream's workload query callback Scream's workload query callback occupied lock of "audio Interface" to judge audio task's status, which may disturb process of audio tasks. Let's use another flag to judge it, which won't use that lock. Signed-off-by: zhanghan64 --- devices/src/misc/scream/mod.rs | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index ead35388..06bdf687 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -271,6 +271,10 @@ impl ScreamCond { fn set_stream_pause(&self, paused: bool) { self.set_value(Self::STREAM_PAUSE_BIT, paused); } + + fn stream_paused(&self) -> bool { + *self.paused.lock().unwrap() != 0 + } } /// Audio stream data structure. @@ -584,8 +588,7 @@ impl Scream { let shmem_size = self.size; let interface = self.interface_init("ScreamPlay", ScreamDirection::Playback); self.interface_resource.push(interface.clone()); - let cloned_interface = interface.clone(); - self.register_state_query("scream-play".to_string(), cloned_interface); + self.register_state_query("scream-play".to_string(), cond.clone()); thread::Builder::new() .name("scream audio play worker".to_string()) .spawn(move || { @@ -619,8 +622,7 @@ impl Scream { let interface = self.interface_init("ScreamCapt", ScreamDirection::Record); let _ti = self.token_id.clone(); self.interface_resource.push(interface.clone()); - let cloned_interface = interface.clone(); - self.register_state_query("scream-record".to_string(), cloned_interface); + self.register_state_query("scream-record".to_string(), cond.clone()); thread::Builder::new() .name("scream audio capt worker".to_string()) .spawn(move || { @@ -648,12 +650,12 @@ impl Scream { Ok(()) } - fn register_state_query(&self, module: String, interface: Arc>) { + fn register_state_query(&self, module: String, cond: Arc) { register_state_query_callback( module, - Arc::new(move || match interface.lock().unwrap().get_status() { - AudioStatus::Started => "On".to_string(), - _ => "Off".to_string(), + Arc::new(move || match cond.stream_paused() { + false => "On".to_string(), + true => "Off".to_string(), }), ); } -- Gitee From 23170c0ea4d67e8143be52d7f4411c531f5e715d Mon Sep 17 00:00:00 2001 From: zhanghan Date: Mon, 2 Sep 2024 12:26:24 +0800 Subject: [PATCH 450/489] OHCAM: fix camera reset logic Sometimes VM reboot with blue screen, which will not leave app closing camera. We close camera at next camera booting process. Signed-off-by: zhanghan64 --- devices/src/camera_backend/ohcam.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/devices/src/camera_backend/ohcam.rs b/devices/src/camera_backend/ohcam.rs index 075f1c17..64743591 100755 --- a/devices/src/camera_backend/ohcam.rs +++ b/devices/src/camera_backend/ohcam.rs @@ -277,6 +277,11 @@ impl CameraBackend for OhCameraBackend { if let Some(cb) = OHCAM_CALLBACKS.write().unwrap().get_mut(&self.camid) { cb.clear_buffer(); } + if self.stream_on { + self.video_stream_off().unwrap_or_else(|e| { + error!("OHCAM: stream off failed: {:?}", e); + }); + } if let Err(e) = self.ctx.reset_camera(self.camid.clone()) { error!("OHCAM: reset failed, err: {e}"); } -- Gitee From 2d1817cfe1529beae052481f13ec9c0d21271a2f Mon Sep 17 00:00:00 2001 From: zhanghan Date: Mon, 2 Sep 2024 10:20:13 +0800 Subject: [PATCH 451/489] OHUI:fix cursor image update logic When uds finishes connecting, stratovirt first send greet event to client. On this time we let client update cursor with current image. Current image is 0 if it's firtst connection, and is last image if it's reconnection. Move image buffer reset to deivces' part. Empty cursor buffer or not shuold be decided by deivce (such as viogpu, svga.) itself. Signed-off-by: zhanghan64 --- ui/src/console.rs | 4 ++++ ui/src/ohui_srv/mod.rs | 21 --------------------- ui/src/ohui_srv/msg_handle.rs | 26 ++++++++++++++++++++++++++ virtio/src/device/gpu.rs | 12 ++++++++++++ 4 files changed, 42 insertions(+), 21 deletions(-) diff --git a/ui/src/console.rs b/ui/src/console.rs index f4461c8c..7d0e27bc 100644 --- a/ui/src/console.rs +++ b/ui/src/console.rs @@ -55,6 +55,10 @@ pub const DISPLAY_UPDATE_INTERVAL_INC: u64 = 50; /// Maximum refresh interval in ms. pub const DISPLAY_UPDATE_INTERVAL_MAX: u64 = 3_000; +pub const DEFAULT_CURSOR_WIDTH: usize = 32; +pub const DEFAULT_CURSOR_HEIGHT: usize = 32; +pub const DEFAULT_CURSOR_BPP: usize = 4; + pub enum ConsoleType { Graphic, Text, diff --git a/ui/src/ohui_srv/mod.rs b/ui/src/ohui_srv/mod.rs index 92e22ea8..fbd8bb9b 100755 --- a/ui/src/ohui_srv/mod.rs +++ b/ui/src/ohui_srv/mod.rs @@ -84,8 +84,6 @@ impl GuestSurface { } const CURSOR_SIZE: u64 = 16 * 1024; -const DEFAULT_CURSOR_WIDTH: u32 = 128; -const DEFAULT_CURSOR_HEIGHT: u32 = 128; pub struct OhUiServer { // framebuffer passthru to the guest @@ -283,17 +281,6 @@ impl OhUiServer { error!("Failed to initialize iothread of OHUI Server."); } } - - fn clear_cursor_buffer(&self) { - if self.cursorbuffer == 0 { - error!("Cursor buffer is invalid."); - return; - } - //SAFETY: we make sure that buffer info is valid. - unsafe { - ptr::write_bytes(self.cursorbuffer as *mut u8, 0, CURSOR_SIZE as usize); - } - } } impl DisplayChangeListenerOperations for OhUiServer { @@ -319,20 +306,12 @@ impl DisplayChangeListenerOperations for OhUiServer { true, ) }; - self.clear_cursor_buffer(); if !self.connected() { return Ok(()); } self.msg_handler .send_windowinfo(locked_surface.width as u32, locked_surface.height as u32); - self.msg_handler.handle_cursor_define( - DEFAULT_CURSOR_WIDTH, - DEFAULT_CURSOR_HEIGHT, - 0, - 0, - bytes_per_pixel().try_into()?, - ); Ok(()) } diff --git a/ui/src/ohui_srv/msg_handle.rs b/ui/src/ohui_srv/msg_handle.rs index 21a11637..0463c15c 100755 --- a/ui/src/ohui_srv/msg_handle.rs +++ b/ui/src/ohui_srv/msg_handle.rs @@ -53,10 +53,20 @@ fn trans_mouse_pos(x: f64, y: f64, w: f64, h: f64) -> (u32, u32) { ) } +#[derive(Clone, Default)] +struct CursorState { + w: u32, + h: u32, + hot_x: u32, + hot_y: u32, + size_per_pixel: u32, +} + #[derive(Default)] struct WindowState { width: u32, height: u32, + cursor: CursorState, } impl WindowState { @@ -188,6 +198,14 @@ impl OhUiMsgHandler { let body = GreetEvent::from_bytes(&body_bytes[..]).unwrap(); trace::oh_event_greet(body.token_id); *token_id.write().unwrap() = body.token_id; + let cursor = self.state.lock().unwrap().cursor.clone(); + self.handle_cursor_define( + cursor.w, + cursor.h, + cursor.hot_x, + cursor.hot_y, + cursor.size_per_pixel, + ); Ok(()) } _ => { @@ -231,6 +249,14 @@ impl OhUiMsgHandler { hot_y: u32, size_per_pixel: u32, ) { + self.state.lock().unwrap().cursor = CursorState { + w, + h, + hot_x, + hot_y, + size_per_pixel, + }; + if let Some(writer) = self.writer.lock().unwrap().as_mut() { let body = HWCursorEvent::new(w, h, hot_x, hot_y, size_per_pixel); if let Err(e) = writer.send_message(EventType::CursorDefine, &body) { diff --git a/virtio/src/device/gpu.rs b/virtio/src/device/gpu.rs index 0725c09d..9cc88448 100644 --- a/virtio/src/device/gpu.rs +++ b/virtio/src/device/gpu.rs @@ -44,6 +44,7 @@ use ui::console::{ console_close, console_init, display_cursor_define, display_graphic_update, display_replace_surface, display_set_major_screen, get_run_stage, set_run_stage, ConsoleType, DisplayConsole, DisplayMouse, DisplaySurface, HardWareOperations, VmRunningStage, + DEFAULT_CURSOR_BPP, DEFAULT_CURSOR_HEIGHT, DEFAULT_CURSOR_WIDTH, }; use ui::pixman::{ create_pixman_image, get_image_data, get_image_format, get_image_height, get_image_stride, @@ -793,6 +794,17 @@ impl GpuIoHandler { let scanout = &mut self.scanouts[scanout_id]; display_replace_surface(&scanout.con, None) .unwrap_or_else(|e| error!("Error occurs during surface switching: {:?}", e)); + + let mouse = DisplayMouse { + height: DEFAULT_CURSOR_WIDTH as u32, + width: DEFAULT_CURSOR_HEIGHT as u32, + hot_x: 0, + hot_y: 0, + data: vec![0_u8; DEFAULT_CURSOR_WIDTH * DEFAULT_CURSOR_HEIGHT * DEFAULT_CURSOR_BPP], + }; + display_cursor_define(&scanout.con, &mouse) + .unwrap_or_else(|e| error!("Error occurs during display_cursor_define: {:?}", e)); + scanout.clear(); } -- Gitee From fee09263b3c343d3dff24ad93666b405fb437d83 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Wed, 30 Oct 2024 19:45:55 +0800 Subject: [PATCH 452/489] gtk: check if the dumped file is existed According to security rule, we should ensure the file to dump doesn't exist otherwise report error. Signed-off-by: Zhao Yi Min --- ui/src/gtk/mod.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/ui/src/gtk/mod.rs b/ui/src/gtk/mod.rs index 2b055adc..9c3fdcaa 100644 --- a/ui/src/gtk/mod.rs +++ b/ui/src/gtk/mod.rs @@ -18,6 +18,7 @@ use std::{ cmp, collections::HashMap, env, fs, + os::unix::fs::OpenOptionsExt, path::Path, ptr, rc::Rc, @@ -1104,6 +1105,10 @@ fn create_file(gpu_info: &mut GpuInfo, dev_name: &String) -> Result { gpu_info.fileDir = file_dir.clone(); let nsec = gettime()?.1; let file_name = file_dir + "/stratovirt-display-" + dev_name + "-" + &nsec.to_string() + ".png"; - let file = fs::File::create(file_name)?; + let file = fs::OpenOptions::new() + .create_new(true) + .write(true) + .mode(0o600) + .open(file_name)?; Ok(file) } -- Gitee From bd228a38daca642871ddfd2ea13992e3d2edf2b4 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Wed, 30 Oct 2024 19:48:09 +0800 Subject: [PATCH 453/489] ramfb: check image size less than ramfb mem size We should check surface size is valid before create surface. Signed-off-by: Zhao Yi Min --- devices/src/legacy/ramfb.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/devices/src/legacy/ramfb.rs b/devices/src/legacy/ramfb.rs index 569a5936..b0a1dc98 100644 --- a/devices/src/legacy/ramfb.rs +++ b/devices/src/legacy/ramfb.rs @@ -130,7 +130,8 @@ impl RamfbState { .addr_cache_init(GuestAddress(addr), AddressAttr::Ram) { Some((hva, len)) => { - if len < u64::from(stride) { + let sf_len = u64::from(stride) * u64::from(height); + if len < sf_len { error!("Insufficient contiguous memory length"); return; } -- Gitee From 0a4cfbfdc6e2e1764ba82fc9bd4113f4f7c417d9 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Wed, 30 Oct 2024 19:53:19 +0800 Subject: [PATCH 454/489] ohui: check surface size valid Let's ensure the size of new surface should be less or equal to ohui framebuffer size. Signed-off-by: Zhao Yi Min --- ui/src/ohui_srv/mod.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/ui/src/ohui_srv/mod.rs b/ui/src/ohui_srv/mod.rs index fbd8bb9b..7fc8b631 100755 --- a/ui/src/ohui_srv/mod.rs +++ b/ui/src/ohui_srv/mod.rs @@ -285,6 +285,15 @@ impl OhUiServer { impl DisplayChangeListenerOperations for OhUiServer { fn dpy_switch(&self, surface: &DisplaySurface) -> Result<()> { + let height = surface.height() as u64; + let stride = surface.stride() as u64; + if self.framebuffer != 0 && height * stride > VIRTIO_GPU_ENABLE_BAR0_SIZE { + bail!( + "surface size is larger than ohui buffer size {}", + VIRTIO_GPU_ENABLE_BAR0_SIZE + ); + } + let mut locked_surface = self.surface.write().unwrap(); unref_pixman_image(locked_surface.guest_image); -- Gitee From c6e00a6a8845267c4826a40e2548256e63e9a167 Mon Sep 17 00:00:00 2001 From: Zhao Yi Min Date: Thu, 7 Nov 2024 11:05:53 +0800 Subject: [PATCH 455/489] scream/pulseaudio: check channels validation We should check channels of format to avoid DoS attack. Signed-off-by: Zhao Yi Min --- devices/src/misc/scream/pulseaudio.rs | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/devices/src/misc/scream/pulseaudio.rs b/devices/src/misc/scream/pulseaudio.rs index 22105585..e0d1dc26 100644 --- a/devices/src/misc/scream/pulseaudio.rs +++ b/devices/src/misc/scream/pulseaudio.rs @@ -123,8 +123,15 @@ impl PulseStreamData { } } - fn transfer_channel_map(&mut self, format: &ShmemStreamFmt) { + fn transfer_channel_map(&mut self, format: &ShmemStreamFmt) -> bool { self.channel_map.init(); + let channels = format.channels; + if channels <= Map::CHANNELS_MAX { + self.channel_map.set_len(channels); + } else { + error!("invalid channels {}", channels); + return false; + } self.channel_map.set_len(format.channels); let map: &mut [Position] = self.channel_map.get_mut(); // In Windows, the channel mask shows as following figure. @@ -149,6 +156,7 @@ impl PulseStreamData { *item = Position::FrontCenter; } } + true } fn check_fmt_update(&mut self, recv_data: &StreamData) { @@ -181,8 +189,8 @@ impl PulseStreamData { self.channel_map.init_mono(); } else if recv_data.fmt.channels == 2 { self.channel_map.init_stereo(); - } else { - self.transfer_channel_map(&recv_data.fmt); + } else if !self.transfer_channel_map(&recv_data.fmt) { + return; } if !self.channel_map.is_valid() { @@ -318,7 +326,8 @@ mod tests { // set 8: BC, 6: FLC, 4: BL, 2: FC, 0: FL test_data.fmt.channels = 5; test_data.fmt.channel_map = 0b1_0101_0101; - pulse.transfer_channel_map(&test_data.fmt); + let ret = pulse.transfer_channel_map(&test_data.fmt); + assert_eq!(ret, true); assert_eq!(pulse.channel_map.len(), 5); let map = pulse.channel_map.get_mut(); @@ -331,7 +340,8 @@ mod tests { // The first 12 bits are set to 1. test_data.fmt.channels = 12; test_data.fmt.channel_map = 0b1111_1111_1111; - pulse.transfer_channel_map(&test_data.fmt); + let ret = pulse.transfer_channel_map(&test_data.fmt); + assert_eq!(ret, true); assert_eq!(pulse.channel_map.len(), 12); let map = pulse.channel_map.get_mut(); -- Gitee From 46cb2b8580e374eda9e044aa77c99a6c2f053ba9 Mon Sep 17 00:00:00 2001 From: zhanghan Date: Sun, 1 Sep 2024 05:59:25 +0800 Subject: [PATCH 456/489] scream:use communication type for record on OHOS On OHOS, many features are not applied with normal record type, such as "eliminate the sound played by machine itself", "noise cancellation". While these features are applied with communication type, we choose communication type to record. Signed-off-by: zhanghan64 --- devices/src/misc/scream/mod.rs | 2 ++ devices/src/misc/scream/ohaudio.rs | 46 ++++++++++++++++++++++++++++-- util/src/ohos_binding/audio/mod.rs | 8 +++++- 3 files changed, 53 insertions(+), 3 deletions(-) diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index 06bdf687..51bbafd5 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -83,6 +83,8 @@ pub enum AudioStatus { Error, // OH audio stream is interrupted. Intr, + // OH audio stream interruption ends. + IntrResume, } type AuthorityNotify = dyn Fn() + Send + Sync; diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index a4d89254..d2f79b78 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -25,6 +25,7 @@ use crate::misc::scream::{ AudioExtension, AudioInterface, AudioStatus, ScreamDirection, StreamData, IVSHMEM_VOLUME_SYNC_VECTOR, }; +use machine_manager::event_loop::EventLoop; use util::ohos_binding::audio::*; const STREAM_DATA_VEC_CAPACITY: usize = 15; @@ -32,6 +33,7 @@ const FLUSH_DELAY_MS: u64 = 5; const FLUSH_DELAY_CNT: u64 = 200; const SCREAM_MAX_VOLUME: u32 = 110; const CAPTURE_WAIT_TIMEOUT: u64 = 500; +const MS_PER_SECOND: u64 = 1000; trait OhAudioProcess { fn init(&mut self, stream: &StreamData) -> bool; @@ -355,6 +357,8 @@ struct OhAudioCapture { ctx: Option, status: AudioStatus, stream: CaptureStream, + timer_start: bool, + data_size_per_second: u64, } impl OhAudioCapture { @@ -387,6 +391,9 @@ impl OhAudioProcess for OhAudioCapture { return false; } } + self.data_size_per_second = (stream.fmt.size as u64 >> 3) + * stream.fmt.get_rate() as u64 + * stream.fmt.channels as u64; match self.ctx.as_ref().unwrap().start() { Ok(()) => { info!("Capturer start"); @@ -414,7 +421,9 @@ impl OhAudioProcess for OhAudioCapture { trace::trace_scope_start!(ohaudio_capturer_process, args = (recv_data)); - if self.status == AudioStatus::Error || self.status == AudioStatus::Intr { + // We expect capture stream can be resumed when another stream stops interrupting it, + // but OHOS does not resume it. We resume it manually. + if self.status == AudioStatus::Error || self.status == AudioStatus::IntrResume { self.destroy(); } @@ -429,7 +438,16 @@ impl OhAudioProcess for OhAudioCapture { recv_data.audio_size as usize, ) }; - if !self.stream.wait_for_data(buf) { + if self.status == AudioStatus::Intr { + // When capture stream is interrupted, we need to send mute data to front end. Without this, + // some applications may pop-up error window for no data received. + if !self.timer_start { + let period: u64 = MS_PER_SECOND * buf.len() as u64 / self.data_size_per_second; + mute_capture_data_gen(ptr::addr_of_mut!(*self), period, buf.len()); + return 0; + } + } + if !self.stream.wait_for_data(buf) && self.status != AudioStatus::Intr { warn!("timed out to wait for capture audio data"); self.status = AudioStatus::Error; return 0; @@ -442,6 +460,28 @@ impl OhAudioProcess for OhAudioCapture { } } +fn mute_capture_data_gen(capture: *mut OhAudioCapture, period: u64, len: usize) { + let buffer: Vec = vec![0; len]; + let buf = buffer.as_slice(); + + //SAFETY: we make sure that capture we passed is valid. + let capt = unsafe { capture.as_mut().unwrap_unchecked() }; + capt.stream.append_data(buf); + + let mute_capture_cb = Box::new(move || { + mute_capture_data_gen(capture, period, len); + }); + + if capt.status == AudioStatus::Intr { + EventLoop::get_ctx(None) + .unwrap() + .timer_add(mute_capture_cb, Duration::from_millis(period)); + capt.timer_start = true; + } else { + capt.timer_start = false; + } +} + extern "C" fn render_on_interrupt_cb( _renderer: *mut OhAudioRenderer, user_data: *mut ::std::os::raw::c_void, @@ -483,6 +523,8 @@ extern "C" fn capture_on_interrupt_cb( }; if hint == capi::AUDIOSTREAM_INTERRUPT_HINT_PAUSE { capture.status = AudioStatus::Intr; + } else if hint == capi::AUDIOSTREAM_INTERRUPT_HINT_RESUME { + capture.status = AudioStatus::IntrResume; } 0 } diff --git a/util/src/ohos_binding/audio/mod.rs b/util/src/ohos_binding/audio/mod.rs index 07b2cb09..166e3d8b 100755 --- a/util/src/ohos_binding/audio/mod.rs +++ b/util/src/ohos_binding/audio/mod.rs @@ -300,6 +300,10 @@ impl AudioContext { cbs, self.userdata ))?; + call_capi!(OH_AudioStreamBuilder_SetCapturerInfo( + self.builder, + capi::OH_AUDIO_STREAM_SOURCE_TYPE_AUDIOSTREAM_SOURCE_TYPE_VOICE_COMMUNICATION + ))?; call_capi!(OH_AudioStreamBuilder_GenerateCapturer( self.builder, &mut self.capturer @@ -349,7 +353,9 @@ impl AudioContext { self.set_fmt(size, rate, channels)?; self.set_sample_rate()?; self.set_sample_format()?; - self.set_latency_mode()?; + if let capi::OH_AUDIO_STREAM_TYPE_AUDIOSTREAM_TYPE_RERNDERER = self.stream_type.into() { + self.set_latency_mode()?; + } self.create_processor(cb) } -- Gitee From 488c276ff2587a3a7d4de7d58f1cb06ad7f14e7d Mon Sep 17 00:00:00 2001 From: goriainovstanislav Date: Fri, 24 May 2024 11:53:38 +0300 Subject: [PATCH 457/489] machine: Move USB host device initialization into a separate thread USB Host initialization includes detaching an attached kernel driver from the device, which can be complex and time-consuming. Factoring it out into a separate thread prevents it from holding the VM lock for too long. Signed-off-by: goriainovstanislav --- machine/src/lib.rs | 51 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/machine/src/lib.rs b/machine/src/lib.rs index cb26a3a8..47b1b11b 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -33,6 +33,7 @@ use std::os::unix::net::UnixListener; use std::path::Path; use std::rc::Rc; use std::sync::{Arc, Barrier, Condvar, Mutex, RwLock, Weak}; +use std::thread; #[cfg(feature = "windows_emu_pid")] use std::time::Duration; use std::u64; @@ -1880,10 +1881,52 @@ pub trait MachineOps: MachineLifecycle { "usb-host" => { let config = UsbHostConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; - let usbhost = UsbHost::new(config)?; - usbhost - .realize() - .with_context(|| "Failed to realize usb host device")? + let parent_dev = self + .get_pci_dev_by_id_and_type(vm_config, None, "nec-usb-xhci") + .with_context(|| "No nec-usb-xhci device found")?; + + thread::Builder::new() + .name("usb host initialization".to_string()) + .spawn(move || { + let usbhost = match UsbHost::new(config) { + Ok(dev) => dev, + Err(err) => { + log::error!("Failed to create usb host device: {:?}", err); + return; + } + }; + + let usbhost = match usbhost.realize() { + Ok(dev) => dev, + Err(err) => { + log::error!("Failed to realize usb host device: {:?}", err); + return; + } + }; + + let res = match parent_dev + .lock() + .unwrap() + .as_any() + .downcast_ref::() + { + Some(xhci_pci) => xhci_pci.attach_device(&(usbhost)), + None => { + log::error!("Failed to downcast PciDevOps to XhciPciDevice"); + return; + } + }; + + if let Err(err) = res { + log::error!( + "Failed to attach usb host device to xhci controller: {:?}", + err + ); + } + }) + .with_context(|| "Failed to spawn usb host initializer thread")?; + + return Ok(()); } _ => bail!("Unknown usb device classes."), }; -- Gitee From 3473d7994890a03cc568d993700029c679ed873a Mon Sep 17 00:00:00 2001 From: zhanghan64 Date: Mon, 11 Nov 2024 14:35:50 +0800 Subject: [PATCH 458/489] OHAudio: fix render stream's zero-append logic When OH Audio system wants render while we areanot ready, we try to wait 40ms for next chunk, instead of appending zero directly. If long time no chunk, append zero. Signed-off-by: zhanghan64 --- devices/src/misc/scream/mod.rs | 8 ++++---- devices/src/misc/scream/ohaudio.rs | 21 +++++++++++++++++++-- util/src/ohos_binding/audio/mod.rs | 13 +++++++++++-- util/src/ohos_binding/audio/sys.rs | 4 ++++ 4 files changed, 38 insertions(+), 8 deletions(-) diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index 51bbafd5..d74234f7 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -51,7 +51,7 @@ pub const AUDIO_SAMPLE_RATE_48KHZ: u32 = 48000; pub const WINDOWS_SAMPLE_BASE_RATE: u8 = 128; -pub const TARGET_LATENCY_MS: u32 = 50; +pub const TARGET_LATENCY_MS: u32 = 20; #[cfg(all(target_env = "ohos", feature = "scream_ohaudio"))] const IVSHMEM_VOLUME_SYNC_VECTOR: u16 = 0; @@ -64,10 +64,10 @@ pub const STATUS_PLAY_BIT: u32 = 0x1; pub const STATUS_START_BIT: u32 = 0x2; const STATUS_MIC_AVAIL_BIT: u32 = 0x4; -// A frame of back-end audio data is 50ms, and the next frame of audio data needs -// to be trained in polling within 50ms. Theoretically, the shorter the polling time, +// A frame of back-end audio data is 20ms, and the next frame of audio data needs +// to be trained in polling within 20ms. Theoretically, the shorter the polling time, // the better. However, if the value is too small, the overhead is high. So take a -// compromise: 50 * 1000 / 8 us. +// compromise: 20 * 1000 / 8 us. const POLL_DELAY_US: u64 = (TARGET_LATENCY_MS as u64) * 1000 / 8; pub const SCREAM_MAGIC: u64 = 0x02032023; diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index d2f79b78..0fd3a8d5 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -23,7 +23,7 @@ use log::{error, info, warn}; use crate::misc::ivshmem::Ivshmem; use crate::misc::scream::{ AudioExtension, AudioInterface, AudioStatus, ScreamDirection, StreamData, - IVSHMEM_VOLUME_SYNC_VECTOR, + IVSHMEM_VOLUME_SYNC_VECTOR, TARGET_LATENCY_MS, }; use machine_manager::event_loop::EventLoop; use util::ohos_binding::audio::*; @@ -33,6 +33,7 @@ const FLUSH_DELAY_MS: u64 = 5; const FLUSH_DELAY_CNT: u64 = 200; const SCREAM_MAX_VOLUME: u32 = 110; const CAPTURE_WAIT_TIMEOUT: u64 = 500; +const RENDER_WAIT_TIMEOUT: u64 = TARGET_LATENCY_MS as u64 * 2; const MS_PER_SECOND: u64 = 1000; trait OhAudioProcess { @@ -166,6 +167,7 @@ struct OhAudioRender { stream_data: Arc>, flushing: AtomicBool, status: AudioStatus, + cond: Condvar, } impl Default for OhAudioRender { @@ -175,6 +177,7 @@ impl Default for OhAudioRender { stream_data: Arc::new(Mutex::new(StreamQueue::new(STREAM_DATA_VEC_CAPACITY))), flushing: AtomicBool::new(false), status: AudioStatus::default(), + cond: Condvar::new(), } } } @@ -279,6 +282,7 @@ impl OhAudioProcess for OhAudioRender { recv_data.audio_base as usize, recv_data.audio_size as usize, )); + self.cond.notify_all(); if self.status == AudioStatus::Error || self.status == AudioStatus::Intr { error!( @@ -553,7 +557,20 @@ extern "C" fn on_write_data_cb( trace::oh_scream_on_write_data_cb(len); trace::trace_scope_start!(ohaudio_write_cb, args = (len)); - match render.stream_data.lock().unwrap().read_exact(wbuf) { + let mut locked_stream_data = match render.stream_data.lock().unwrap().data_size() == 0 { + true => { + render + .cond + .wait_timeout( + render.stream_data.lock().unwrap(), + Duration::from_millis(RENDER_WAIT_TIMEOUT), + ) + .unwrap() + .0 + } + false => render.stream_data.lock().unwrap(), + }; + match locked_stream_data.read_exact(wbuf) { Ok(()) => { if render.is_flushing() { render.flush_renderer(); diff --git a/util/src/ohos_binding/audio/mod.rs b/util/src/ohos_binding/audio/mod.rs index 166e3d8b..7c5585c1 100755 --- a/util/src/ohos_binding/audio/mod.rs +++ b/util/src/ohos_binding/audio/mod.rs @@ -24,6 +24,7 @@ pub use sys as capi; const AUDIO_SAMPLE_RATE_44KHZ: u32 = 44100; const AUDIO_SAMPLE_RATE_48KHZ: u32 = 48000; +const RENDER_CB_FREQUENCY: i32 = 50; macro_rules! call_capi { ( $f: ident ( $($x: expr),* ) ) => { @@ -265,6 +266,7 @@ impl AudioContext { )) } + #[allow(unused)] fn set_latency_mode(&self) -> Result<(), OAErr> { call_capi!(OH_AudioStreamBuilder_SetLatencyMode( self.builder, @@ -272,6 +274,13 @@ impl AudioContext { )) } + pub fn set_frame_size(&self, size: i32) -> Result<(), OAErr> { + call_capi!(OH_AudioStreamBuilder_SetFrameSizeInCallback( + self.builder, + size + )) + } + fn create_renderer(&mut self, cb: AudioProcessCb) -> Result<(), OAErr> { let mut cbs = capi::OhAudioRendererCallbacks::default(); if let AudioProcessCb::RendererCb(data_cb, interrupt_cb) = cb { @@ -353,8 +362,8 @@ impl AudioContext { self.set_fmt(size, rate, channels)?; self.set_sample_rate()?; self.set_sample_format()?; - if let capi::OH_AUDIO_STREAM_TYPE_AUDIOSTREAM_TYPE_RERNDERER = self.stream_type.into() { - self.set_latency_mode()?; + if capi::OH_AUDIO_STREAM_TYPE_AUDIOSTREAM_TYPE_RERNDERER == self.stream_type.into() { + self.set_frame_size(rate as i32 / RENDER_CB_FREQUENCY)?; } self.create_processor(cb) } diff --git a/util/src/ohos_binding/audio/sys.rs b/util/src/ohos_binding/audio/sys.rs index 56dcee2e..66440c38 100755 --- a/util/src/ohos_binding/audio/sys.rs +++ b/util/src/ohos_binding/audio/sys.rs @@ -288,6 +288,10 @@ extern "C" { renderer: *mut OhAudioRenderer, encodingType: *mut OhAudioStreamEncodingType, ) -> OhAudioStreamResult; + pub fn OH_AudioStreamBuilder_SetFrameSizeInCallback( + builder: *mut OhAudioStreamBuilder, + size: i32, + ) -> OhAudioStreamResult; /// Create a streamBuilder can be used to open a renderer or capturer client. /// /// OH_AudioStreamBuilder_Destroy() must be called when you are done using the builder. -- Gitee From 1c526ed793c4b895f62b986121c2af97a45175c8 Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Fri, 10 Jan 2025 18:31:54 +0800 Subject: [PATCH 459/489] QMP: bugfix quit wait for vcpu stop if handle quit, process exit directly, residual vcpu threads will occur. Thereforce, handle quit must wait for vcpu stop. Signed-off-by: Fei Xu --- machine_manager/src/qmp/qmp_socket.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/machine_manager/src/qmp/qmp_socket.rs b/machine_manager/src/qmp/qmp_socket.rs index f0b4ace2..aa6ee53f 100644 --- a/machine_manager/src/qmp/qmp_socket.rs +++ b/machine_manager/src/qmp/qmp_socket.rs @@ -31,13 +31,11 @@ use crate::event_loop::EventLoop; use crate::machine::{MachineExternalInterface, VmState}; use crate::socket::SocketHandler; use crate::socket::SocketRWHandler; -use crate::temp_cleaner::TempCleaner; use util::leak_bucket::LeakBucket; use util::loop_context::{ gen_delete_notifiers, read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, }; -use util::set_termi_canon_mode; use util::socket::{SocketListener, SocketStream}; use util::unix::parse_unix_uri; @@ -402,10 +400,6 @@ fn handle_qmp( reason: "host-qmp-quit".to_string(), }; event!(Shutdown; shutdown_msg); - TempCleaner::clean(); - set_termi_canon_mode().expect("Failed to set terminal to canonical mode."); - - std::process::exit(0); } Ok(()) -- Gitee From ed8f26d7aaa6f0e9fd9efd702e5b3a48b4546463 Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Mon, 13 Jan 2025 14:40:32 +0800 Subject: [PATCH 460/489] machine: Add event broadcast of usbhost initialization thread's final result In the current implementation of decomposing the usbhost device initialization into a seperate thread, there may be situations where the initialization fails but the qmp command gives back an adding success massage, meanwhile the invalid device information will remain in the VmConfig. Signed-off-by: Fei Xu --- devices/src/usb/usbhost/mod.rs | 2 +- machine/src/lib.rs | 85 +++++++++++++++++---------- machine_manager/src/qmp/qmp_schema.rs | 25 +++++++- 3 files changed, 78 insertions(+), 34 deletions(-) diff --git a/devices/src/usb/usbhost/mod.rs b/devices/src/usb/usbhost/mod.rs index 4dcade11..9bba07a3 100644 --- a/devices/src/usb/usbhost/mod.rs +++ b/devices/src/usb/usbhost/mod.rs @@ -367,7 +367,7 @@ pub struct UsbHostConfig { #[arg(long)] pub classtype: String, #[arg(long, value_parser = valid_id)] - id: String, + pub id: String, #[arg(long, default_value = "0")] hostbus: u8, #[arg(long, default_value = "0", value_parser = clap::value_parser!(u8).range(..=USBHOST_ADDR_MAX))] diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 47b1b11b..5e90172d 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -20,6 +20,11 @@ pub mod x86_64; mod micro_common; pub use crate::error::MachineError; +#[cfg(feature = "usb_host")] +use machine_manager::{ + event, + qmp::{qmp_channel::QmpChannel, qmp_schema::UsbHostAddRes}, +}; pub use micro_common::LightMachine; pub use standard_common::StdMachine; @@ -33,6 +38,7 @@ use std::os::unix::net::UnixListener; use std::path::Path; use std::rc::Rc; use std::sync::{Arc, Barrier, Condvar, Mutex, RwLock, Weak}; +#[cfg(feature = "usb_host")] use std::thread; #[cfg(feature = "windows_emu_pid")] use std::time::Duration; @@ -1885,43 +1891,37 @@ pub trait MachineOps: MachineLifecycle { .get_pci_dev_by_id_and_type(vm_config, None, "nec-usb-xhci") .with_context(|| "No nec-usb-xhci device found")?; + let update_vm_config = self.get_vm_config(); + thread::Builder::new() .name("usb host initialization".to_string()) .spawn(move || { - let usbhost = match UsbHost::new(config) { - Ok(dev) => dev, - Err(err) => { - log::error!("Failed to create usb host device: {:?}", err); - return; + let dev_id = config.id.clone(); + match initialize_usb_host(config, parent_dev) { + Ok(_) => { + if QmpChannel::is_connected() { + let success_msg = UsbHostAddRes { + device: Some(dev_id), + state_msg: Some("Add usb host device success".to_string()), + }; + event!(UsbHostAddRes; success_msg); + } } - }; - - let usbhost = match usbhost.realize() { - Ok(dev) => dev, - Err(err) => { - log::error!("Failed to realize usb host device: {:?}", err); - return; - } - }; - - let res = match parent_dev - .lock() - .unwrap() - .as_any() - .downcast_ref::() - { - Some(xhci_pci) => xhci_pci.attach_device(&(usbhost)), - None => { - log::error!("Failed to downcast PciDevOps to XhciPciDevice"); - return; + Err(e) => { + error!("Usb host device initialization failed: {:?}", e); + let mut locked_vm_config = update_vm_config.lock().unwrap(); + locked_vm_config.del_device_by_id(dev_id.clone()); + if QmpChannel::is_connected() { + let fail_msg = UsbHostAddRes { + device: Some(dev_id), + state_msg: Some(format!( + "Usb host device initialization failed: {:?}", + e + )), + }; + event!(UsbHostAddRes; fail_msg); + } } - }; - - if let Err(err) = res { - log::error!( - "Failed to attach usb host device to xhci controller: {:?}", - err - ); } }) .with_context(|| "Failed to spawn usb host initializer thread")?; @@ -2561,3 +2561,24 @@ pub fn type_init() -> Result<()> { Ok(()) } + +#[cfg(feature = "usb_host")] +fn initialize_usb_host(config: UsbHostConfig, parent_dev: Arc>) -> Result<()> { + let usbhost = UsbHost::new(config).with_context(|| "Failed to create usb host device")?; + + let usbhost = usbhost + .realize() + .with_context(|| "Failed to realize usb host device")?; + + let parent = parent_dev.lock().unwrap(); + let xhci_pci = parent + .as_any() + .downcast_ref::() + .ok_or_else(|| anyhow!("Failed to downcast PciDevOps to XhciPciDevice"))?; + + xhci_pci + .attach_device(&usbhost) + .with_context(|| "Failed to attach usb host device to xhci controller")?; + + Ok(()) +} diff --git a/machine_manager/src/qmp/qmp_schema.rs b/machine_manager/src/qmp/qmp_schema.rs index ba43fc01..5d5558d9 100644 --- a/machine_manager/src/qmp/qmp_schema.rs +++ b/machine_manager/src/qmp/qmp_schema.rs @@ -1798,7 +1798,8 @@ define_qmp_event_enum!( Powerdown("POWERDOWN", Powerdown, default), CpuResize("CPU_RESIZE", CpuResize, default), DeviceDeleted("DEVICE_DELETED", DeviceDeleted), - BalloonChanged("BALLOON_CHANGED", BalloonInfo) + BalloonChanged("BALLOON_CHANGED", BalloonInfo), + UsbHostAddRes("USB_HOST_ADD_RES", UsbHostAddRes) ); /// Shutdown @@ -1910,6 +1911,28 @@ pub struct Powerdown {} #[serde(deny_unknown_fields)] pub struct CpuResize {} +/// UsbHostAddRes +/// +/// Emitted whenever the usb host device add completion is acknowledged. +/// At this point, it's safe to reuse the specified device ID. +/// +/// # Examples +/// +/// ```text +/// <- { "event": "USB_HOST_ADD_RES", +/// "data": { "device": "hw_vid_pid" }, +/// "timestamp": { "seconds": 1265044230, "microseconds": 450486 } } +/// ``` +#[derive(Debug, Clone, Serialize, Deserialize, Default)] +#[serde(deny_unknown_fields)] +pub struct UsbHostAddRes { + /// Device name. + #[serde(rename = "device", default, skip_serializing_if = "Option::is_none")] + pub device: Option, + #[serde(rename = "state_msg", default, skip_serializing_if = "Option::is_none")] + pub state_msg: Option, +} + /// DeviceDeleted /// /// Emitted whenever the device removal completion is acknowledged by the guest. -- Gitee From 545fc714b444b23d0313bdf2a5f11c3cbc5c7580 Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Wed, 15 Jan 2025 18:14:46 +0800 Subject: [PATCH 461/489] Bugfix: Fix ohaudio's dead lock We get a lock in a "{}" code zone, while we fetch it in the zone, which will result in dead lock. Signed-off-by: Fei Xu --- devices/src/misc/scream/ohaudio.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/devices/src/misc/scream/ohaudio.rs b/devices/src/misc/scream/ohaudio.rs index 0fd3a8d5..315c6c33 100755 --- a/devices/src/misc/scream/ohaudio.rs +++ b/devices/src/misc/scream/ohaudio.rs @@ -557,7 +557,8 @@ extern "C" fn on_write_data_cb( trace::oh_scream_on_write_data_cb(len); trace::trace_scope_start!(ohaudio_write_cb, args = (len)); - let mut locked_stream_data = match render.stream_data.lock().unwrap().data_size() == 0 { + let is_empty = render.stream_data.lock().unwrap().data_size() == 0; + let mut locked_stream_data = match is_empty { true => { render .cond -- Gitee From dd6f60960891c9bc2b299dc753472128c6873100 Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Thu, 16 Jan 2025 15:20:51 +0800 Subject: [PATCH 462/489] ohui: release pressed buttons when focus-out If foucus-out happens while mouse button is pressed, and released outside, VM inside is out of mouse order. Let stratovirt release pressed button when focus out. Signed-off-by: Fei Xu --- ui/src/input.rs | 25 +++++++++++++++++++++++++ ui/src/ohui_srv/msg_handle.rs | 10 ++++++---- 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/ui/src/input.rs b/ui/src/input.rs index f72119cf..c59926be 100644 --- a/ui/src/input.rs +++ b/ui/src/input.rs @@ -34,6 +34,7 @@ pub const INPUT_BUTTON_WHEEL_DOWN: u32 = 0x40; pub const INPUT_BUTTON_WHEEL_LEFT: u32 = 0x80; pub const INPUT_BUTTON_WHEEL_RIGHT: u32 = 0x100; pub const INPUT_BUTTON_MASK: u32 = 0x1f; +pub const INPUT_POINT_MAX: u32 = INPUT_POINT_FORWARD; // ASCII value. pub const ASCII_A: i32 = 65; @@ -261,6 +262,7 @@ struct Inputs { tablet_ids: Vec, tablet_lists: HashMap>>, keyboard_state: KeyBoardState, + btn_state: u32, } impl Inputs { @@ -326,6 +328,14 @@ impl Inputs { } Ok(()) } + + fn update_button_state(&mut self, btn: u32, press: bool) { + if press { + self.btn_state |= btn; + } else { + self.btn_state &= !btn; + } + } } pub fn register_keyboard(device: &str, kbd: Arc>) { @@ -365,11 +375,26 @@ pub fn input_button(button: u32, down: bool) -> Result<()> { let mouse = INPUTS.lock().unwrap().get_active_mouse(); if let Some(m) = mouse { m.lock().unwrap().update_point_state(input_event)?; + INPUTS.lock().unwrap().update_button_state(button, down); } Ok(()) } +/// Release all pressed button. +pub fn release_all_btn() -> Result<()> { + let state = INPUTS.lock().unwrap().btn_state; + let mut checked_btn = INPUT_POINT_LEFT; + while checked_btn <= INPUT_POINT_MAX { + if (state & checked_btn) != 0 { + input_button(checked_btn, false)?; + input_point_sync()?; + } + checked_btn <<= 1; + } + Ok(()) +} + pub fn input_point_sync() -> Result<()> { let mouse = INPUTS.lock().unwrap().get_active_mouse(); if let Some(m) = mouse { diff --git a/ui/src/ohui_srv/msg_handle.rs b/ui/src/ohui_srv/msg_handle.rs index 0463c15c..47d2939f 100755 --- a/ui/src/ohui_srv/msg_handle.rs +++ b/ui/src/ohui_srv/msg_handle.rs @@ -27,10 +27,11 @@ use crate::{ console::{get_active_console, graphic_hardware_ui_info}, input::{ self, get_kbd_led_state, input_button, input_move_abs, input_point_sync, keyboard_update, - release_all_key, trigger_key, Axis, ABS_MAX, CAPS_LOCK_LED, INPUT_BUTTON_WHEEL_DOWN, - INPUT_BUTTON_WHEEL_LEFT, INPUT_BUTTON_WHEEL_RIGHT, INPUT_BUTTON_WHEEL_UP, INPUT_POINT_BACK, - INPUT_POINT_FORWARD, INPUT_POINT_LEFT, INPUT_POINT_MIDDLE, INPUT_POINT_RIGHT, - KEYCODE_CAPS_LOCK, KEYCODE_NUM_LOCK, KEYCODE_SCR_LOCK, NUM_LOCK_LED, SCROLL_LOCK_LED, + release_all_btn, release_all_key, trigger_key, Axis, ABS_MAX, CAPS_LOCK_LED, + INPUT_BUTTON_WHEEL_DOWN, INPUT_BUTTON_WHEEL_LEFT, INPUT_BUTTON_WHEEL_RIGHT, + INPUT_BUTTON_WHEEL_UP, INPUT_POINT_BACK, INPUT_POINT_FORWARD, INPUT_POINT_LEFT, + INPUT_POINT_MIDDLE, INPUT_POINT_RIGHT, KEYCODE_CAPS_LOCK, KEYCODE_NUM_LOCK, + KEYCODE_SCR_LOCK, NUM_LOCK_LED, SCROLL_LOCK_LED, }, keycode::{DpyMod, KeyCode}, }; @@ -190,6 +191,7 @@ impl OhUiMsgHandler { if body.state == CLIENT_FOCUSOUT_EVENT { reader.clear(); release_all_key()?; + release_all_btn()?; } Ok(()) } -- Gitee From 85527660c9936321a5ac4c08016c4af66957c1c0 Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Sat, 18 Jan 2025 20:05:13 +0800 Subject: [PATCH 463/489] scream: create a thread to do destroy Harmony audio release interface might block our destroy function. While doing destroy, the audio thread is holding condition lock. Then when we restart audio stream. The trapped vcpu would be holding VMLock and then try to get audio condition lock. Then it is blocked and other vcpu can't get VMLock. This causes VM blocked. So let's do it in another thread. The worst case is the sound can't work but this would not block vcpu thread. Signed-off-by: Fei Xu --- devices/src/misc/scream/mod.rs | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/devices/src/misc/scream/mod.rs b/devices/src/misc/scream/mod.rs index d74234f7..9dc1b396 100644 --- a/devices/src/misc/scream/mod.rs +++ b/devices/src/misc/scream/mod.rs @@ -247,11 +247,28 @@ impl ScreamCond { } fn wait_if_paused(&self, interface: Arc>) { + let mut destroy_thread_handle = None; let mut locked_pause = self.paused.lock().unwrap(); while *locked_pause != 0 { - interface.lock().unwrap().destroy(); + if destroy_thread_handle.is_none() { + let cloned_interface = interface.clone(); + destroy_thread_handle = Some( + thread::Builder::new() + .name("scream destroy".to_string()) + .spawn(move || { + cloned_interface.lock().unwrap().destroy(); + }) + .unwrap(), + ); + } locked_pause = self.cond.wait(locked_pause).unwrap(); } + drop(locked_pause); + if let Some(handle) = destroy_thread_handle { + if let Err(e) = handle.join() { + error!("failed to join destroy thread, {:?}", e); + } + } } fn set_value(&self, bv: u8, set: bool) { -- Gitee From 3b8b273163da553467b352192f4271aa0e88e739 Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Mon, 20 Jan 2025 22:02:57 +0800 Subject: [PATCH 464/489] msix: add checked_add avoid integer overflow Signed-off-by: Fei Xu --- devices/src/pci/msix.rs | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/devices/src/pci/msix.rs b/devices/src/pci/msix.rs index 428c4e83..3fac9e97 100644 --- a/devices/src/pci/msix.rs +++ b/devices/src/pci/msix.rs @@ -301,7 +301,12 @@ impl Msix { let cloned_msix = msix.clone(); let table_read = move |data: &mut [u8], _addr: GuestAddress, offset: u64| -> bool { - if offset as usize + data.len() > cloned_msix.lock().unwrap().table.len() { + let offset = offset as usize; + if offset + .checked_add(data.len()) + .filter(|&sum| sum <= cloned_msix.lock().unwrap().table.len()) + .is_none() + { error!( "It's forbidden to read out of the msix table(size: {}), with offset of {} and size of {}", cloned_msix.lock().unwrap().table.len(), @@ -310,13 +315,17 @@ impl Msix { ); return false; } - let offset = offset as usize; data.copy_from_slice(&cloned_msix.lock().unwrap().table[offset..(offset + data.len())]); true }; let cloned_msix = msix.clone(); let table_write = move |data: &[u8], _addr: GuestAddress, offset: u64| -> bool { - if offset as usize + data.len() > cloned_msix.lock().unwrap().table.len() { + let offset = offset as usize; + if offset + .checked_add(data.len()) + .filter(|&sum| sum <= cloned_msix.lock().unwrap().table.len()) + .is_none() + { error!( "It's forbidden to write out of the msix table(size: {}), with offset of {} and size of {}", cloned_msix.lock().unwrap().table.len(), @@ -328,7 +337,6 @@ impl Msix { let mut locked_msix = cloned_msix.lock().unwrap(); let vector: u16 = offset as u16 / MSIX_TABLE_ENTRY_SIZE; let was_masked: bool = locked_msix.is_vector_masked(vector); - let offset = offset as usize; locked_msix.table[offset..(offset + 4)].copy_from_slice(data); let is_masked: bool = locked_msix.is_vector_masked(vector); @@ -357,7 +365,12 @@ impl Msix { let cloned_msix = msix.clone(); let pba_read = move |data: &mut [u8], _addr: GuestAddress, offset: u64| -> bool { - if offset as usize + data.len() > cloned_msix.lock().unwrap().pba.len() { + let offset = offset as usize; + if offset + .checked_add(data.len()) + .filter(|&sum| sum <= cloned_msix.lock().unwrap().pba.len()) + .is_none() + { error!( "Fail to read msi pba, illegal data length {}, offset {}", data.len(), @@ -365,7 +378,6 @@ impl Msix { ); return false; } - let offset = offset as usize; data.copy_from_slice(&cloned_msix.lock().unwrap().pba[offset..(offset + data.len())]); true }; -- Gitee From 3fa357757ce78e45f3ae93b5b5d17033f5c51507 Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Tue, 21 Jan 2025 11:02:57 +0800 Subject: [PATCH 465/489] xhci: adjust the order of locking in doorbell_write Adjust the order of locking to avoid redundant unlocking processes. Signed-off-by: Fei Xu --- devices/src/usb/xhci/xhci_regs.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/devices/src/usb/xhci/xhci_regs.rs b/devices/src/usb/xhci/xhci_regs.rs index abf3128d..6c56bea3 100644 --- a/devices/src/usb/xhci/xhci_regs.rs +++ b/devices/src/usb/xhci/xhci_regs.rs @@ -709,11 +709,11 @@ pub fn build_doorbell_ops(xhci_dev: &Arc>) -> RegionOps { if !read_data_u32(data, &mut value) { return false; } - if !xhci.lock().unwrap().running() { + let mut xhci = xhci.lock().unwrap(); + if !xhci.running() { error!("Failed to write doorbell, XHCI is not running"); return false; } - let mut xhci = xhci.lock().unwrap(); let slot_id = (offset >> 2) as u32; if slot_id == 0 { error!("Invalid slot id 0 !"); -- Gitee From 398ae49076b024be79d11db94bf9dab01cf37f07 Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Thu, 23 Jan 2025 11:47:57 +0800 Subject: [PATCH 466/489] xhci: fix incorrect judgment Fix incorrect judgment in `check_intr_iso_kick`. Fix: 239aa9dcf9(xhci: support iso trb transfer) Signed-off-by: Fei Xu --- devices/src/usb/xhci/xhci_controller.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index 14cd1351..842b3f3e 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -2090,7 +2090,7 @@ impl XhciDevice { } }; let ep_state = epctx.get_ep_state(); - if ep_state == EP_STOPPED && ep_state == EP_ERROR { + if ep_state == EP_STOPPED || ep_state == EP_ERROR { return; } if let Err(e) = locked_xhci.kick_endpoint(slotid, epid, 0) { -- Gitee From 55fc8046bd144e25d0a02a7b37d4c0ae950c3bbc Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Sat, 25 Jan 2025 10:32:57 +0800 Subject: [PATCH 467/489] cmdline: print incorrect parameters for debugging Currently, if there is a command line error, specific information will not be printed, which causes difficulties for debugging. Print out incorrect parameters when failing. Signed-off-by: Fei Xu --- machine_manager/src/cmdline.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/machine_manager/src/cmdline.rs b/machine_manager/src/cmdline.rs index f29804e6..daa06be9 100644 --- a/machine_manager/src/cmdline.rs +++ b/machine_manager/src/cmdline.rs @@ -38,7 +38,8 @@ use util::{ macro_rules! add_args_to_config { ( $x:tt, $z:expr, $s:tt ) => { if let Some(temp) = &$x { - $z.$s(temp)?; + $z.$s(temp) + .with_context(|| format!("Add args {:?} error.", temp))?; } }; ( $x:tt, $z:expr, $s:tt, vec ) => { @@ -65,7 +66,8 @@ macro_rules! add_args_to_config_multi { ( $x:tt, $z:expr, $s:tt ) => { if let Some(temps) = &$x { for temp in temps { - $z.$s(temp)?; + $z.$s(temp) + .with_context(|| format!("Add args {:?} error.", temp))?; } } }; -- Gitee From cc91128504e04435ea313fc210ac49d78eac9d63 Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Mon, 27 Jan 2025 20:56:30 +0800 Subject: [PATCH 468/489] drive: Only deactivate drive files for migration We should not allow other process lock files during normal VM pause. Signed-off-by: Fei Xu --- machine/src/lib.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 5e90172d..f227807c 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -2206,11 +2206,15 @@ pub trait MachineOps: MachineLifecycle { ) -> Result<()> { EventLoop::get_ctx(None).unwrap().disable_clock(); - self.deactive_drive_files()?; - + // Deactive files so that VM on the other end can active files. + if MigrationManager::is_active() { + self.deactive_drive_files()?; + } for (cpu_index, cpu) in cpus.iter().enumerate() { if let Err(e) = cpu.pause() { - self.active_drive_files()?; + if MigrationManager::is_active() { + self.active_drive_files()?; + } return Err(anyhow!("Failed to pause vcpu{}, {:?}", cpu_index, e)); } } -- Gitee From 181f82cd699e7f59a8801b49370ea9518f08c995 Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Wed, 29 Jan 2025 15:39:27 +0800 Subject: [PATCH 469/489] snapshot: bugfix VM run failed from memory snapshot The kernel does not need to be loaded for snapshot restoration. Signed-off-by: Fei Xu --- cpu/src/lib.rs | 22 +++++++------- cpu/src/x86_64/mod.rs | 2 +- devices/src/acpi/cpu_controller.rs | 4 +-- machine/src/aarch64/micro.rs | 42 +++++++++++++++----------- machine/src/aarch64/standard.rs | 48 ++++++++++++++++++------------ machine/src/lib.rs | 2 +- machine/src/x86_64/micro.rs | 9 ++++-- machine/src/x86_64/standard.rs | 17 ++++++++--- 8 files changed, 89 insertions(+), 57 deletions(-) diff --git a/cpu/src/lib.rs b/cpu/src/lib.rs index 704ef604..21f6bb01 100644 --- a/cpu/src/lib.rs +++ b/cpu/src/lib.rs @@ -120,7 +120,7 @@ pub trait CPUInterface { /// Realize `CPU` structure, set registers value for `CPU`. fn realize( &self, - boot: &CPUBootConfig, + boot: &Option, topology: &CPUTopology, #[cfg(target_arch = "aarch64")] features: &CPUFeatures, ) -> Result<()>; @@ -313,7 +313,7 @@ impl CPU { impl CPUInterface for CPU { fn realize( &self, - boot: &CPUBootConfig, + boot: &Option, topology: &CPUTopology, #[cfg(target_arch = "aarch64")] config: &CPUFeatures, ) -> Result<()> { @@ -326,14 +326,16 @@ impl CPUInterface for CPU { )))); } - self.hypervisor_cpu - .set_boot_config( - self.arch_cpu.clone(), - boot, - #[cfg(target_arch = "aarch64")] - config, - ) - .with_context(|| "Failed to realize arch cpu")?; + if let Some(boot) = boot { + self.hypervisor_cpu + .set_boot_config( + self.arch_cpu.clone(), + boot, + #[cfg(target_arch = "aarch64")] + config, + ) + .with_context(|| "Failed to realize arch cpu")?; + } self.arch_cpu .lock() diff --git a/cpu/src/x86_64/mod.rs b/cpu/src/x86_64/mod.rs index 09fdf5db..06b2cc4e 100644 --- a/cpu/src/x86_64/mod.rs +++ b/cpu/src/x86_64/mod.rs @@ -75,7 +75,7 @@ pub enum X86RegsIndex { /// X86 CPU booting configure information #[allow(clippy::upper_case_acronyms)] -#[derive(Default, Clone, Debug)] +#[derive(Default, Clone, Debug, Copy)] pub struct X86CPUBootConfig { pub prot64_mode: bool, /// Register %rip value diff --git a/devices/src/acpi/cpu_controller.rs b/devices/src/acpi/cpu_controller.rs index 797f44d4..3f85e288 100644 --- a/devices/src/acpi/cpu_controller.rs +++ b/devices/src/acpi/cpu_controller.rs @@ -162,8 +162,8 @@ impl CpuController { None } - pub fn get_boot_config(&self) -> &CPUBootConfig { - &self.cpu_config.as_ref().unwrap().boot_config + pub fn get_boot_config(&self) -> CPUBootConfig { + self.cpu_config.as_ref().unwrap().boot_config } pub fn get_hotplug_cpu_info(&self) -> (String, u8) { diff --git a/machine/src/aarch64/micro.rs b/machine/src/aarch64/micro.rs index 4cf52504..b79f13b3 100644 --- a/machine/src/aarch64/micro.rs +++ b/machine/src/aarch64/micro.rs @@ -21,7 +21,7 @@ use cpu::CPUTopology; use devices::legacy::{PL011, PL031}; use devices::{Device, ICGICConfig, ICGICv2Config, ICGICv3Config, GIC_IRQ_MAX}; use hypervisor::kvm::aarch64::*; -use machine_manager::config::{Param, SerialConfig, VmConfig}; +use machine_manager::config::{MigrateMode, Param, SerialConfig, VmConfig}; use migration::{MigrationManager, MigrationStatus}; use util::device_tree::{self, CompileFDT, FdtBuilder}; use util::gen_base_func; @@ -153,8 +153,12 @@ impl MachineOps for LightMachine { vm_config.machine_config.nr_cpus, )?; - let boot_config = - locked_vm.load_boot_source(None, MEM_LAYOUT[LayoutEntryType::Mem as usize].0)?; + let migrate_info = locked_vm.get_migrate_info(); + let boot_config = if migrate_info.0 == MigrateMode::Unknown { + Some(locked_vm.load_boot_source(None, MEM_LAYOUT[LayoutEntryType::Mem as usize].0)?) + } else { + None + }; let cpu_config = locked_vm.load_cpu_features(vm_config)?; let hypervisor = locked_vm.base.hypervisor.clone(); @@ -179,21 +183,23 @@ impl MachineOps for LightMachine { locked_vm.add_devices(vm_config)?; trace::replaceable_info(&locked_vm.replaceable_info); - let mut fdt_helper = FdtBuilder::new(); - locked_vm - .generate_fdt_node(&mut fdt_helper) - .with_context(|| MachineError::GenFdtErr)?; - let fdt_vec = fdt_helper.finish()?; - locked_vm - .base - .sys_mem - .write( - &mut fdt_vec.as_slice(), - GuestAddress(boot_config.fdt_addr), - fdt_vec.len() as u64, - AddressAttr::Ram, - ) - .with_context(|| MachineError::WrtFdtErr(boot_config.fdt_addr, fdt_vec.len()))?; + if let Some(boot_cfg) = boot_config { + let mut fdt_helper = FdtBuilder::new(); + locked_vm + .generate_fdt_node(&mut fdt_helper) + .with_context(|| MachineError::GenFdtErr)?; + let fdt_vec = fdt_helper.finish()?; + locked_vm + .base + .sys_mem + .write( + &mut fdt_vec.as_slice(), + GuestAddress(boot_cfg.fdt_addr), + fdt_vec.len() as u64, + AddressAttr::Ram, + ) + .with_context(|| MachineError::WrtFdtErr(boot_cfg.fdt_addr, fdt_vec.len()))?; + } register_shutdown_event(locked_vm.shutdown_req.clone(), vm.clone()) .with_context(|| "Failed to register shutdown event")?; diff --git a/machine/src/aarch64/standard.rs b/machine/src/aarch64/standard.rs index fd1aa349..8612b3f1 100644 --- a/machine/src/aarch64/standard.rs +++ b/machine/src/aarch64/standard.rs @@ -60,7 +60,7 @@ use machine_manager::config::str_slip_to_clap; #[cfg(feature = "gtk")] use machine_manager::config::UiContext; use machine_manager::config::{ - BootIndexInfo, DriveConfig, NumaNode, Param, SerialConfig, VmConfig, + BootIndexInfo, DriveConfig, MigrateMode, NumaNode, Param, SerialConfig, VmConfig, }; use machine_manager::event; use machine_manager::machine::{MachineLifecycle, VmState}; @@ -556,8 +556,16 @@ impl MachineOps for StdMachine { .with_context(|| MachineError::InitPCIeHostErr)?; let fwcfg = locked_vm.add_fwcfg_device(nr_cpus)?; - let boot_config = locked_vm - .load_boot_source(fwcfg.as_ref(), MEM_LAYOUT[LayoutEntryType::Mem as usize].0)?; + let migrate = locked_vm.get_migrate_info(); + let boot_config = + if migrate.0 == MigrateMode::Unknown { + Some(locked_vm.load_boot_source( + fwcfg.as_ref(), + MEM_LAYOUT[LayoutEntryType::Mem as usize].0, + )?) + } else { + None + }; let cpu_config = locked_vm.load_cpu_features(vm_config)?; let hypervisor = locked_vm.base.hypervisor.clone(); @@ -582,22 +590,24 @@ impl MachineOps for StdMachine { .add_devices(vm_config) .with_context(|| "Failed to add devices")?; - let mut fdt_helper = FdtBuilder::new(); - locked_vm - .generate_fdt_node(&mut fdt_helper) - .with_context(|| MachineError::GenFdtErr)?; - let fdt_vec = fdt_helper.finish()?; - locked_vm.dtb_vec = fdt_vec.clone(); - locked_vm - .base - .sys_mem - .write( - &mut fdt_vec.as_slice(), - GuestAddress(boot_config.fdt_addr), - fdt_vec.len() as u64, - AddressAttr::Ram, - ) - .with_context(|| MachineError::WrtFdtErr(boot_config.fdt_addr, fdt_vec.len()))?; + if let Some(boot_cfg) = boot_config { + let mut fdt_helper = FdtBuilder::new(); + locked_vm + .generate_fdt_node(&mut fdt_helper) + .with_context(|| MachineError::GenFdtErr)?; + let fdt_vec = fdt_helper.finish()?; + locked_vm.dtb_vec = fdt_vec.clone(); + locked_vm + .base + .sys_mem + .write( + &mut fdt_vec.as_slice(), + GuestAddress(boot_cfg.fdt_addr), + fdt_vec.len() as u64, + AddressAttr::Ram, + ) + .with_context(|| MachineError::WrtFdtErr(boot_cfg.fdt_addr, fdt_vec.len()))?; + } // If it is direct kernel boot mode, the ACPI can not be enabled. if let Some(fw_cfg) = fwcfg { diff --git a/machine/src/lib.rs b/machine/src/lib.rs index f227807c..701c76f6 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -513,7 +513,7 @@ pub trait MachineOps: MachineLifecycle { nr_cpus: u8, #[cfg(target_arch = "x86_64")] max_cpus: u8, topology: &CPUTopology, - boot_cfg: &CPUBootConfig, + boot_cfg: &Option, #[cfg(target_arch = "aarch64")] vcpu_cfg: &CPUFeatures, ) -> Result>> where diff --git a/machine/src/x86_64/micro.rs b/machine/src/x86_64/micro.rs index 80c3c1b9..ba7c8fe3 100644 --- a/machine/src/x86_64/micro.rs +++ b/machine/src/x86_64/micro.rs @@ -22,7 +22,7 @@ use devices::legacy::{FwCfgOps, Serial, SERIAL_ADDR}; use devices::Device; use hypervisor::kvm::x86_64::*; use hypervisor::kvm::*; -use machine_manager::config::{SerialConfig, VmConfig}; +use machine_manager::config::{MigrateMode, SerialConfig, VmConfig}; use migration::{MigrationManager, MigrationStatus}; use util::gen_base_func; use util::seccomp::{BpfRule, SeccompCmpOpt}; @@ -170,7 +170,12 @@ impl MachineOps for LightMachine { locked_vm.add_devices(vm_config)?; trace::replaceable_info(&locked_vm.replaceable_info); - let boot_config = locked_vm.load_boot_source(None)?; + let migrate_info = locked_vm.get_migrate_info(); + let boot_config = if migrate_info.0 == MigrateMode::Unknown { + Some(locked_vm.load_boot_source(None)?) + } else { + None + }; let hypervisor = locked_vm.base.hypervisor.clone(); locked_vm.base.cpus.extend(::init_vcpu( vm.clone(), diff --git a/machine/src/x86_64/standard.rs b/machine/src/x86_64/standard.rs index 61007855..e85042bf 100644 --- a/machine/src/x86_64/standard.rs +++ b/machine/src/x86_64/standard.rs @@ -42,7 +42,9 @@ use hypervisor::kvm::x86_64::*; use hypervisor::kvm::*; #[cfg(feature = "gtk")] use machine_manager::config::UiContext; -use machine_manager::config::{BootIndexInfo, DriveConfig, NumaNode, SerialConfig, VmConfig}; +use machine_manager::config::{ + BootIndexInfo, DriveConfig, MigrateMode, NumaNode, SerialConfig, VmConfig, +}; use machine_manager::event; use machine_manager::qmp::{qmp_channel::QmpChannel, qmp_schema}; use migration::{MigrationManager, MigrationStatus}; @@ -321,7 +323,7 @@ impl StdMachineOps for StdMachine { hypervisor, self.base.cpu_topo.max_cpus, )?; - vcpu.realize(boot_cfg, topology).with_context(|| { + vcpu.realize(&Some(boot_cfg), topology).with_context(|| { format!( "Failed to realize arch cpu register/features for CPU {}", vcpu_id @@ -507,7 +509,12 @@ impl MachineOps for StdMachine { locked_vm.add_devices(vm_config)?; let fwcfg = locked_vm.add_fwcfg_device(nr_cpus, max_cpus)?; - let boot_config = locked_vm.load_boot_source(fwcfg.as_ref())?; + let migrate = locked_vm.get_migrate_info(); + let boot_config = if migrate.0 == MigrateMode::Unknown { + Some(locked_vm.load_boot_source(fwcfg.as_ref())?) + } else { + None + }; let topology = CPUTopology::new().set_topology(( vm_config.machine_config.nr_threads, vm_config.machine_config.nr_cores, @@ -523,7 +530,9 @@ impl MachineOps for StdMachine { &boot_config, )?); - locked_vm.init_cpu_controller(boot_config, topology, vm.clone())?; + if migrate.0 == MigrateMode::Unknown { + locked_vm.init_cpu_controller(boot_config.unwrap(), topology, vm.clone())?; + } if let Some(fw_cfg) = fwcfg { locked_vm -- Gitee From 4564843c26802acbc4135ab41f0c19dddf7c3014 Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Fri, 31 Jan 2025 10:13:27 +0800 Subject: [PATCH 470/489] raw: drain io when exiting Drain io for raw format when exiting. Signed-off-by: Fei Xu --- block_backend/src/lib.rs | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/block_backend/src/lib.rs b/block_backend/src/lib.rs index ea146dc0..3a29a19c 100644 --- a/block_backend/src/lib.rs +++ b/block_backend/src/lib.rs @@ -398,6 +398,9 @@ pub fn create_block_backend( aio: Aio, prop: BlockProperty, ) -> Result>>> { + let cloned_drive_id = prop.id.clone(); + // NOTE: we can drain request when request in io thread. + let drain = prop.iothread.is_some(); match prop.format { DiskFormat::Raw => { let mut raw_file = RawDriver::new(file, aio, prop.clone()); @@ -405,7 +408,28 @@ pub fn create_block_backend( if file_size & (u64::from(prop.req_align) - 1) != 0 { bail!("The size of raw file is not aligned to {}.", prop.req_align); } - Ok(Arc::new(Mutex::new(raw_file))) + let new_raw = Arc::new(Mutex::new(raw_file)); + + let cloned_raw = Arc::downgrade(&new_raw); + let exit_notifier = Arc::new(move || { + if let Some(raw) = cloned_raw.upgrade() { + info!("clean up raw {:?} resources.", cloned_drive_id); + if drain { + info!("Drain the inflight IO for drive \"{}\"", cloned_drive_id); + let incomplete = raw.lock().unwrap().get_inflight(); + while incomplete.load(Ordering::SeqCst) != 0 { + yield_now(); + } + } + info!( + "Drain the inflight IO for drive \"{}\" ends.", + cloned_drive_id + ); + } + }) as Arc; + TempCleaner::add_exit_notifier(prop.id, exit_notifier); + + Ok(new_raw) } DiskFormat::Qcow2 => { let mut qcow2 = Qcow2Driver::new(file, aio, prop.clone()) @@ -426,11 +450,8 @@ pub fn create_block_backend( .lock() .unwrap() .insert(prop.id.clone(), new_qcow2.clone()); - let cloned_qcow2 = Arc::downgrade(&new_qcow2); - // NOTE: we can drain request when request in io thread. - let drain = prop.iothread.is_some(); - let cloned_drive_id = prop.id.clone(); + let cloned_qcow2 = Arc::downgrade(&new_qcow2); let exit_notifier = Arc::new(move || { if let Some(qcow2) = cloned_qcow2.upgrade() { info!("clean up qcow2 {:?} resources.", cloned_drive_id); -- Gitee From 7bde1d6443daf44033cab28cb8f9dc1f4aacf330 Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Mon, 3 Feb 2025 16:13:27 +0800 Subject: [PATCH 471/489] usb/xhci: Check BME before issuing memory or I/O requests Signed-off-by: Fei Xu --- devices/src/misc/ivshmem.rs | 3 +- devices/src/misc/pvpanic.rs | 3 +- devices/src/pci/config.rs | 4 +++ devices/src/pci/demo_device/mod.rs | 3 +- devices/src/pci/mod.rs | 4 +++ devices/src/pci/msix.rs | 4 +++ devices/src/pci/root_port.rs | 3 +- devices/src/usb/xhci/xhci_controller.rs | 39 +++++++++++++++++++++++-- devices/src/usb/xhci/xhci_pci.rs | 12 ++++++-- devices/src/usb/xhci/xhci_regs.rs | 2 +- machine/src/aarch64/pci_host_root.rs | 3 +- machine/src/x86_64/ich9_lpc.rs | 3 +- machine/src/x86_64/mch.rs | 3 +- vfio/src/vfio_pci.rs | 3 +- virtio/src/transport/virtio_pci.rs | 3 +- 15 files changed, 77 insertions(+), 15 deletions(-) diff --git a/devices/src/misc/ivshmem.rs b/devices/src/misc/ivshmem.rs index a98a4a11..86b92381 100644 --- a/devices/src/misc/ivshmem.rs +++ b/devices/src/misc/ivshmem.rs @@ -11,7 +11,7 @@ // See the Mulan PSL v2 for more details. use std::sync::{ - atomic::{AtomicU16, Ordering}, + atomic::{AtomicBool, AtomicU16, Ordering}, Arc, Mutex, RwLock, Weak, }; @@ -73,6 +73,7 @@ impl Ivshmem { base: DeviceBase::new(name, false, Some(parent_bus)), config: PciConfig::new(devfn, PCI_CONFIG_SPACE_SIZE, PCI_BAR_MAX_IVSHMEM), devfn, + bme: Arc::new(AtomicBool::new(false)), }, dev_id: Arc::new(AtomicU16::new(0)), ram_mem_region, diff --git a/devices/src/misc/pvpanic.rs b/devices/src/misc/pvpanic.rs index 23e200d0..08cbebd0 100644 --- a/devices/src/misc/pvpanic.rs +++ b/devices/src/misc/pvpanic.rs @@ -11,7 +11,7 @@ // See the Mulan PSL v2 for more details. use std::sync::{ - atomic::{AtomicU16, Ordering}, + atomic::{AtomicBool, AtomicU16, Ordering}, Arc, Mutex, Weak, }; @@ -115,6 +115,7 @@ impl PvPanicPci { base: DeviceBase::new(config.id.clone(), false, Some(parent_bus)), config: PciConfig::new(devfn, PCI_CONFIG_SPACE_SIZE, 1), devfn, + bme: Arc::new(AtomicBool::new(false)), }, dev_id: AtomicU16::new(0), pvpanic: Arc::new(PvPanicState::new(config.supported_features)), diff --git a/devices/src/pci/config.rs b/devices/src/pci/config.rs index 84bf48d1..db84bef8 100644 --- a/devices/src/pci/config.rs +++ b/devices/src/pci/config.rs @@ -1208,6 +1208,10 @@ impl PciConfig { let max_vector = table_len / MSIX_TABLE_ENTRY_SIZE as usize; vector_nr < max_vector as u32 } + + pub fn bus_maser_enable(&self) -> bool { + self.config[COMMAND as usize] as u16 & COMMAND_BUS_MASTER != 0 + } } #[cfg(test)] diff --git a/devices/src/pci/demo_device/mod.rs b/devices/src/pci/demo_device/mod.rs index e8264b0d..8f6fe602 100644 --- a/devices/src/pci/demo_device/mod.rs +++ b/devices/src/pci/demo_device/mod.rs @@ -33,7 +33,7 @@ pub mod dpy_device; pub mod gpu_device; pub mod kbd_pointer_device; -use std::sync::atomic::{AtomicU16, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicU16, Ordering}; use std::sync::{Arc, Mutex, Weak}; use anyhow::Result; @@ -105,6 +105,7 @@ impl DemoDev { base: DeviceBase::new(cfg.id.clone(), false, Some(parent_bus)), config: PciConfig::new(devfn, PCIE_CONFIG_SPACE_SIZE, cfg.bar_num), devfn, + bme: Arc::new(AtomicBool::new(false)), }, cmd_cfg: cfg, mem_region: Region::init_container_region(u64::from(u32::MAX), "DemoDev"), diff --git a/devices/src/pci/mod.rs b/devices/src/pci/mod.rs index e2b64ff8..2866b3c4 100644 --- a/devices/src/pci/mod.rs +++ b/devices/src/pci/mod.rs @@ -33,6 +33,7 @@ pub use root_port::{RootPort, RootPortConfig}; use std::any::{Any, TypeId}; use std::collections::HashMap; use std::mem::size_of; +use std::sync::atomic::AtomicBool; use std::sync::{Arc, Mutex, Weak}; use anyhow::{bail, Result}; @@ -143,6 +144,8 @@ pub struct PciDevBase { pub config: PciConfig, /// Devfn. pub devfn: u8, + /// Bus master enable. + pub bme: Arc, } pub trait PciDevOps: Device + Send { @@ -416,6 +419,7 @@ mod tests { base: DeviceBase::new(name.to_string(), false, Some(parent_bus)), config: PciConfig::new(devfn, PCI_CONFIG_SPACE_SIZE, 0), devfn, + bme: Arc::new(AtomicBool::new(false)), }, } } diff --git a/devices/src/pci/msix.rs b/devices/src/pci/msix.rs index 3fac9e97..986dcfe8 100644 --- a/devices/src/pci/msix.rs +++ b/devices/src/pci/msix.rs @@ -646,6 +646,8 @@ pub fn init_msix( #[cfg(test)] mod tests { + use std::sync::atomic::AtomicBool; + use super::*; use crate::pci::config::{PciConfig, PCI_CONFIG_SPACE_SIZE}; use crate::pci::host::tests::create_pci_host; @@ -660,6 +662,7 @@ mod tests { base: DeviceBase::new("msix".to_string(), false, Some(root_bus)), config: PciConfig::new(1, PCI_CONFIG_SPACE_SIZE, 2), devfn: 1, + bme: Arc::new(AtomicBool::new(false)), }; // Too many vectors. assert!(init_msix( @@ -765,6 +768,7 @@ mod tests { base: DeviceBase::new("msix".to_string(), false, Some(root_bus)), config: PciConfig::new(1, PCI_CONFIG_SPACE_SIZE, 2), devfn: 1, + bme: Arc::new(AtomicBool::new(false)), }; init_msix(&mut base, 0, 2, Arc::new(AtomicU16::new(0)), None, None).unwrap(); let msix = base.config.msix.as_ref().unwrap(); diff --git a/devices/src/pci/root_port.rs b/devices/src/pci/root_port.rs index 16808344..fdf4ef47 100644 --- a/devices/src/pci/root_port.rs +++ b/devices/src/pci/root_port.rs @@ -10,7 +10,7 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use std::sync::atomic::{AtomicU16, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicU16, Ordering}; use std::sync::{Arc, Mutex, Weak}; use anyhow::{anyhow, bail, Context, Result}; @@ -128,6 +128,7 @@ impl RootPort { base: dev_base, config: PciConfig::new(devfn, PCIE_CONFIG_SPACE_SIZE, 2), devfn, + bme: Arc::new(AtomicBool::new(false)), }, port_num: cfg.port, #[cfg(target_arch = "x86_64")] diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index 842b3f3e..5991f234 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -13,7 +13,7 @@ use std::collections::LinkedList; use std::mem::size_of; use std::slice::{from_raw_parts, from_raw_parts_mut}; -use std::sync::atomic::{AtomicU32, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicU32, Ordering}; use std::sync::{Arc, Mutex, Weak}; use std::time::Duration; @@ -929,10 +929,15 @@ pub struct XhciDevice { mfindex_start: Duration, timer_id: Option, packet_count: u32, + bme: Arc, } impl XhciDevice { - pub fn new(mem_space: &Arc, config: &XhciConfig) -> Arc> { + pub fn new( + mem_space: &Arc, + config: &XhciConfig, + bme: &Arc, + ) -> Arc> { let mut p2 = XHCI_DEFAULT_PORT; let mut p3 = XHCI_DEFAULT_PORT; if config.p2.is_some() { @@ -976,6 +981,7 @@ impl XhciDevice { mem_space: mem_space.clone(), mfindex_start: EventLoop::get_ctx(None).unwrap().get_virtual_clock(), timer_id: None, + bme: bme.clone(), }; let xhci = Arc::new(Mutex::new(xhci)); let clone_xhci = xhci.clone(); @@ -1052,7 +1058,7 @@ impl XhciDevice { self.oper.get_usb_status() & USB_STS_HCH != USB_STS_HCH } - pub fn host_controller_error(&mut self) { + pub fn host_controller_error(&self) { error!("Xhci host controller error!"); self.oper.set_usb_status_flag(USB_STS_HCE) } @@ -1121,9 +1127,15 @@ impl XhciDevice { } trace::usb_xhci_port_notify(&locked_port.port_id, &flag); locked_port.portsc |= flag; + if !self.running() { return Ok(()); } + self.check_bme_valid().map_err(|e| { + self.host_controller_error(); + e + })?; + let mut evt = XhciEvent::new(TRBType::ErPortStatusChange, TRBCCode::Success); evt.ptr = u64::from(u32::from(locked_port.port_id) << PORT_EVENT_ID_SHIFT); self.intrs[0].lock().unwrap().send_event(&evt)?; @@ -1199,6 +1211,9 @@ impl XhciDevice { /// Control plane pub fn handle_command(&mut self) -> Result<()> { + // The caller will set HCE if handle_command() returns error. + self.check_bme_valid()?; + self.oper.start_cmd_ring(); let mut slot_id: u32 = 0; let mut event = XhciEvent::new(TRBType::ErCommandComplete, TRBCCode::Success); @@ -1822,6 +1837,11 @@ impl XhciDevice { return Ok(()); } + self.check_bme_valid().map_err(|e| { + self.host_controller_error(); + e + })?; + trace::usb_xhci_ep_kick(&slot_id, &ep_id, &ring.get_dequeue_ptr()); if self.slots[(slot_id - 1) as usize].endpoints[(ep_id - 1) as usize] .retry @@ -2343,6 +2363,12 @@ impl XhciDevice { locked_intr.er_size = 0; return Ok(()); } + + self.check_bme_valid().map_err(|e| { + self.host_controller_error(); + e + })?; + let mut seg = XhciEventRingSeg::new(&self.mem_space); seg.fetch_event_ring_seg(locked_intr.erstba)?; if seg.size < 16 || seg.size > 4096 { @@ -2407,6 +2433,13 @@ impl XhciDevice { } None } + + fn check_bme_valid(&self) -> Result<()> { + if !self.bme.load(Ordering::SeqCst) { + bail!("BME is cleared.") + } + Ok(()) + } } fn usb_packet_status_to_trb_code(status: UsbPacketStatus) -> Result { diff --git a/devices/src/usb/xhci/xhci_pci.rs b/devices/src/usb/xhci/xhci_pci.rs index f91461e3..dc9dd9ce 100644 --- a/devices/src/usb/xhci/xhci_pci.rs +++ b/devices/src/usb/xhci/xhci_pci.rs @@ -14,7 +14,7 @@ use std::cmp::max; use std::os::unix::io::AsRawFd; use std::os::unix::prelude::RawFd; use std::rc::Rc; -use std::sync::atomic::{AtomicU16, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicU16, Ordering}; use std::sync::{Arc, Mutex, Weak}; use anyhow::{bail, Context, Result}; @@ -111,13 +111,15 @@ impl XhciPciDevice { parent_bus: Weak>, mem_space: &Arc, ) -> Self { + let bme = Arc::new(AtomicBool::new(false)); Self { base: PciDevBase { base: DeviceBase::new(config.id.clone().unwrap(), true, Some(parent_bus)), config: PciConfig::new(devfn, PCI_CONFIG_SPACE_SIZE, 1), devfn, + bme: bme.clone(), }, - xhci: XhciDevice::new(mem_space, config), + xhci: XhciDevice::new(mem_space, config, &bme), dev_id: Arc::new(AtomicU16::new(0)), mem_region: Region::init_container_region( u64::from(XHCI_PCI_CONFIG_LENGTH), @@ -369,6 +371,12 @@ impl PciDevOps for XhciPciDevice { Some(&pci_bus.io_region), Some(&pci_bus.mem_region), ); + + // Make sure synchronize with memory or I/O access. + let _locked_xhci = self.xhci.lock().unwrap(); + self.base + .bme + .store(self.base.config.bus_maser_enable(), Ordering::SeqCst); } } diff --git a/devices/src/usb/xhci/xhci_regs.rs b/devices/src/usb/xhci/xhci_regs.rs index 6c56bea3..c027e0d3 100644 --- a/devices/src/usb/xhci/xhci_regs.rs +++ b/devices/src/usb/xhci/xhci_regs.rs @@ -160,7 +160,7 @@ impl XhciOperReg { self.usb_status.load(Ordering::Acquire) } - pub fn set_usb_status_flag(&mut self, value: u32) { + pub fn set_usb_status_flag(&self, value: u32) { self.usb_status.fetch_or(value, Ordering::SeqCst); } diff --git a/machine/src/aarch64/pci_host_root.rs b/machine/src/aarch64/pci_host_root.rs index 65ec778f..11b9caa7 100644 --- a/machine/src/aarch64/pci_host_root.rs +++ b/machine/src/aarch64/pci_host_root.rs @@ -10,7 +10,7 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use std::sync::{Arc, Mutex, Weak}; +use std::sync::{atomic::AtomicBool, Arc, Mutex, Weak}; use anyhow::Result; @@ -36,6 +36,7 @@ impl PciHostRoot { base: DeviceBase::new("PCI Host Root".to_string(), false, Some(parent_bus)), config: PciConfig::new(0, PCI_CONFIG_SPACE_SIZE, 0), devfn: 0, + bme: Arc::new(AtomicBool::new(false)), }, } } diff --git a/machine/src/x86_64/ich9_lpc.rs b/machine/src/x86_64/ich9_lpc.rs index e4c40c58..4ce47680 100644 --- a/machine/src/x86_64/ich9_lpc.rs +++ b/machine/src/x86_64/ich9_lpc.rs @@ -11,7 +11,7 @@ // See the Mulan PSL v2 for more details. use std::sync::{ - atomic::{AtomicU8, Ordering}, + atomic::{AtomicBool, AtomicU8, Ordering}, Arc, Mutex, Weak, }; @@ -67,6 +67,7 @@ impl LPCBridge { base: DeviceBase::new("ICH9 LPC bridge".to_string(), false, Some(parent_bus)), config: PciConfig::new(0x1F << 3, PCI_CONFIG_SPACE_SIZE, 0), devfn: 0x1F << 3, + bme: Arc::new(AtomicBool::new(false)), }, sys_io, pm_timer: Arc::new(Mutex::new(AcpiPMTimer::new())), diff --git a/machine/src/x86_64/mch.rs b/machine/src/x86_64/mch.rs index 13a47cdf..570cdcb3 100644 --- a/machine/src/x86_64/mch.rs +++ b/machine/src/x86_64/mch.rs @@ -10,7 +10,7 @@ // NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. // See the Mulan PSL v2 for more details. -use std::sync::{Arc, Mutex, Weak}; +use std::sync::{atomic::AtomicBool, Arc, Mutex, Weak}; use anyhow::{bail, Result}; use log::error; @@ -60,6 +60,7 @@ impl Mch { base: DeviceBase::new("Memory Controller Hub".to_string(), false, Some(parent_bus)), config: PciConfig::new(0, PCI_CONFIG_SPACE_SIZE, 0), devfn: 0, + bme: Arc::new(AtomicBool::new(false)), }, mmconfig_region: Some(mmconfig_region), mmconfig_ops, diff --git a/vfio/src/vfio_pci.rs b/vfio/src/vfio_pci.rs index d4c0dfee..6cf8d75c 100644 --- a/vfio/src/vfio_pci.rs +++ b/vfio/src/vfio_pci.rs @@ -12,7 +12,7 @@ use std::mem::size_of; use std::os::unix::io::{AsRawFd, RawFd}; -use std::sync::atomic::{AtomicU16, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicU16, Ordering}; use std::sync::{Arc, Mutex, Weak}; use anyhow::{anyhow, bail, Context, Result}; @@ -135,6 +135,7 @@ impl VfioPciDevice { base: DeviceBase::new(name, true, Some(parent_bus)), config: PciConfig::new(devfn, PCIE_CONFIG_SPACE_SIZE, PCI_NUM_BARS), devfn, + bme: Arc::new(AtomicBool::new(false)), }, config_size: 0, config_offset: 0, diff --git a/virtio/src/transport/virtio_pci.rs b/virtio/src/transport/virtio_pci.rs index 0c4bfc88..405927b8 100644 --- a/virtio/src/transport/virtio_pci.rs +++ b/virtio/src/transport/virtio_pci.rs @@ -12,7 +12,7 @@ use std::cmp::{max, min}; use std::mem::size_of; -use std::sync::atomic::{AtomicU16, Ordering}; +use std::sync::atomic::{AtomicBool, AtomicU16, Ordering}; use std::sync::{Arc, Mutex, Weak}; use anyhow::{anyhow, bail, Context, Result}; @@ -337,6 +337,7 @@ impl VirtioPciDevice { base: DeviceBase::new(name, true, Some(parent_bus)), config: PciConfig::new(devfn, PCIE_CONFIG_SPACE_SIZE, VIRTIO_PCI_BAR_MAX), devfn, + bme: Arc::new(AtomicBool::new(false)), }, device, dev_id: Arc::new(AtomicU16::new(0)), -- Gitee From 7b78be4f180374a59fc162b4b275d9ca3a0da24b Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Wed, 12 Feb 2025 16:14:27 +0800 Subject: [PATCH 472/489] kvm: arm: Fix reg_id type converting The reg_id is of type u64, use as to convert it. Signed-off-by: Fei Xu --- hypervisor/src/kvm/aarch64/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hypervisor/src/kvm/aarch64/mod.rs b/hypervisor/src/kvm/aarch64/mod.rs index 7e42f61a..122cfac9 100644 --- a/hypervisor/src/kvm/aarch64/mod.rs +++ b/hypervisor/src/kvm/aarch64/mod.rs @@ -422,7 +422,7 @@ impl KvmCpu { } fn reg_sync_by_cpreg_list(reg_id: u64) -> Result { - let coproc = u32::try_from(reg_id)? & KVM_REG_ARM_COPROC_MASK; + let coproc = reg_id as u32 & KVM_REG_ARM_COPROC_MASK; if coproc == KVM_REG_ARM_CORE { return Ok(false); } -- Gitee From 0408db938fcd2513ec2b36d0a92ad9ebd203b592 Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Fri, 14 Feb 2025 11:54:27 +0800 Subject: [PATCH 473/489] dfx: output error information stack If is_err is used, the error information stack is ignored, which makes it difficult to locate the cause. Signed-off-by: Fei Xu --- devices/src/legacy/fwcfg.rs | 8 ++------ devices/src/legacy/pflash.rs | 17 ++++++----------- devices/src/pci/msix.rs | 8 +++++--- devices/src/usb/usbhost/mod.rs | 12 ++++-------- 4 files changed, 17 insertions(+), 28 deletions(-) diff --git a/devices/src/legacy/fwcfg.rs b/devices/src/legacy/fwcfg.rs index b6a57a27..59b2d250 100644 --- a/devices/src/legacy/fwcfg.rs +++ b/devices/src/legacy/fwcfg.rs @@ -974,12 +974,8 @@ impl SysBusDevOps for FwCfgMem { self.fwcfg.select_entry(value as u16); } 16..=23 => { - if self - .fwcfg - .dma_mem_write(offset - 0x10, value, size) - .is_err() - { - error!("Failed to write dma at offset=0x{:x}.", offset); + if let Err(e) = self.fwcfg.dma_mem_write(offset - 0x10, value, size) { + error!("Failed to write dma at offset=0x{:x} {:?}.", offset, e); return false; } } diff --git a/devices/src/legacy/pflash.rs b/devices/src/legacy/pflash.rs index 5ea22a3b..58e752f1 100644 --- a/devices/src/legacy/pflash.rs +++ b/devices/src/legacy/pflash.rs @@ -743,8 +743,8 @@ impl SysBusDevOps for PFlash { // - cmd 0x98 represents PFlash CFI query. match self.cmd { 0x00 => { - if self.read_data(data, offset).is_err() { - error!("Failed to read data from PFlash."); + if let Err(e) = self.read_data(data, offset) { + error!("Failed to read data from PFlash {:?}.", e); } return true; } @@ -885,15 +885,10 @@ impl SysBusDevOps for PFlash { let data_len: u8 = data.len() as u8; trace::pflash_io_write(offset, data_len, value, self.write_cycle); - if self.write_cycle == 0 - && self - .rom - .as_ref() - .unwrap() - .set_rom_device_romd(false) - .is_err() - { - error!("Failed PFlash to set device to read array mode."); + if self.write_cycle == 0 { + if let Err(e) = self.rom.as_ref().unwrap().set_rom_device_romd(false) { + error!("Failed PFlash to set device to read array mode {:?}.", e); + } } // Write: diff --git a/devices/src/pci/msix.rs b/devices/src/pci/msix.rs index 986dcfe8..23562999 100644 --- a/devices/src/pci/msix.rs +++ b/devices/src/pci/msix.rs @@ -340,9 +340,11 @@ impl Msix { locked_msix.table[offset..(offset + 4)].copy_from_slice(data); let is_masked: bool = locked_msix.is_vector_masked(vector); - if was_masked != is_masked && locked_msix.update_irq_routing(vector, is_masked).is_err() - { - return false; + if was_masked != is_masked { + if let Err(e) = locked_msix.update_irq_routing(vector, is_masked) { + error!("Failed to update irq routing: {:?}", e); + return false; + } } // Clear the pending vector just when it is pending. Otherwise, it diff --git a/devices/src/usb/usbhost/mod.rs b/devices/src/usb/usbhost/mod.rs index 9bba07a3..591cdbba 100644 --- a/devices/src/usb/usbhost/mod.rs +++ b/devices/src/usb/usbhost/mod.rs @@ -558,13 +558,8 @@ impl UsbHost { } fn attach_kernel(&mut self) { - if self - .libdev - .as_ref() - .unwrap() - .active_config_descriptor() - .is_err() - { + if let Err(e) = self.libdev.as_ref().unwrap().active_config_descriptor() { + warn!("Failed to active config descriptor: {:?}.", e); return; } for i in 0..self.ifs_num { @@ -699,7 +694,8 @@ impl UsbHost { fn claim_interfaces(&mut self) -> UsbPacketStatus { self.base.altsetting = [0; USB_MAX_INTERFACES as usize]; - if self.detach_kernel().is_err() { + if let Err(e) = self.detach_kernel() { + error!("Failed to detach kernel for usbhost: {:?}.", e); return UsbPacketStatus::Stall; } -- Gitee From 0b3608804651574f96089ec1ae216ca2e493eaf2 Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Sat, 15 Feb 2025 19:27:42 +0800 Subject: [PATCH 474/489] usb/xhci: Set BME to false when reset Fix commit b8138b9 (usb/xhci: Check BME before issuing memory or I/O requests) Signed-off-by: Fei Xu --- devices/src/usb/xhci/xhci_pci.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/devices/src/usb/xhci/xhci_pci.rs b/devices/src/usb/xhci/xhci_pci.rs index dc9dd9ce..493a501b 100644 --- a/devices/src/usb/xhci/xhci_pci.rs +++ b/devices/src/usb/xhci/xhci_pci.rs @@ -243,9 +243,8 @@ impl Device for XhciPciDevice { fn reset(&mut self, _reset_child_device: bool) -> Result<()> { self.xhci.lock().unwrap().reset(); - self.base.config.reset()?; - + self.base.bme.store(false, Ordering::SeqCst); Ok(()) } -- Gitee From 939598181b0fe9766e0a90a926218842afbcb955 Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Mon, 17 Feb 2025 14:13:27 +0800 Subject: [PATCH 475/489] usb_host: Fixed the deadlock problem that may occur with extremely low probability There is a very low probability that when the xhci-iothread responds to the front-end driver sending a stop_endpoint command, the epoll_wait on the same device also returns and enters the processing flow. In this case, the two threads will hold the locks on xfer and dev respectively and fall into a deadlock. Signed-off-by: Fei Xu --- devices/src/usb/usbhost/mod.rs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/devices/src/usb/usbhost/mod.rs b/devices/src/usb/usbhost/mod.rs index 591cdbba..3c94ceb1 100644 --- a/devices/src/usb/usbhost/mod.rs +++ b/devices/src/usb/usbhost/mod.rs @@ -1016,11 +1016,8 @@ impl EventNotifierHelper for UsbHost { let timeout = Some(Duration::new(0, 0)); let handler: Rc = Rc::new(move |_, _fd: RawFd| { - cloned_usbhost - .lock() - .unwrap() - .context - .handle_events(timeout) + let ctx = cloned_usbhost.lock().unwrap().context.clone(); + ctx.handle_events(timeout) .unwrap_or_else(|e| error!("Failed to handle event: {:?}", e)); None }); -- Gitee From c4d3cb70b4b48815fc1b07a8bf3c74622a4161b9 Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Fri, 21 Feb 2025 17:13:27 +0800 Subject: [PATCH 476/489] util: refactoring the judgment method of zero buffer 1. fix the error in determining whether IO is zero buffer: Now, non 8-bytes aligned IO can also determine whether it is zero buffer. 2. improving performance: Calling 20 times judgments on a 10MB zero buffer, the new method takes about half the time of the old method. Double performance improvement. Fix: 561b0ba607(virtio-blk: support feature VIRTIO_BLK_F_WRITE_ZEROES) Signed-off-by: Fei Xu --- util/src/aio/mod.rs | 76 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 66 insertions(+), 10 deletions(-) diff --git a/util/src/aio/mod.rs b/util/src/aio/mod.rs index 100dd018..e308181f 100644 --- a/util/src/aio/mod.rs +++ b/util/src/aio/mod.rs @@ -835,20 +835,21 @@ pub fn iov_discard_front_direct(iovec: &mut [Iovec], mut size: u64) -> Option<&m None } +// Caller should have valid buffer base/len. +unsafe fn buffer_is_zero(base: u64, len: u64) -> bool { + let slice = std::slice::from_raw_parts(base as *const u8, len as usize); + let (prefix, aligned, suffix) = slice.align_to::(); + prefix.iter().all(|&x| x == 0) + && aligned.iter().all(|&x| x == 0) + && suffix.iter().all(|&x| x == 0) +} + // Caller should have valid hva iovec. unsafe fn iovec_is_zero(iovecs: &[Iovec]) -> bool { - let size = std::mem::size_of::() as u64; for iov in iovecs { - if iov.iov_len % size != 0 { - return false; - } // SAFETY: iov_base and iov_len has been checked in pop_avail(). - let slice = - std::slice::from_raw_parts(iov.iov_base as *const u64, (iov.iov_len / size) as usize); - for val in slice.iter() { - if *val != 0 { - return false; - } + if !buffer_is_zero(iov.iov_base, iov.iov_len) { + return false; } } true @@ -1059,4 +1060,59 @@ mod tests { assert_eq!(buf1, vec![0_u8; 100]); assert_eq!(buf2, vec![0_u8; 40]); } + + #[test] + fn test_buffer_is_zero() { + let buf1: Vec = vec![0; 6]; + let result1 = unsafe { buffer_is_zero(buf1.as_ptr() as u64, buf1.len() as u64) }; + assert_eq!(result1, true); + + let buf2: Vec = vec![0; 128]; + let result2 = unsafe { buffer_is_zero(buf2.as_ptr() as u64, buf2.len() as u64) }; + assert_eq!(result2, true); + + let buf3: Vec = vec![0; 513]; + let result3 = unsafe { buffer_is_zero(buf3.as_ptr() as u64, buf3.len() as u64) }; + assert_eq!(result3, true); + + let buf4: Vec = Vec::new(); + let result4 = unsafe { buffer_is_zero(buf4.as_ptr() as u64, buf4.len() as u64) }; + assert_eq!(result4, true); + + let buf5: Vec = vec![0, 1, 0]; + let result5 = unsafe { buffer_is_zero(buf5.as_ptr() as u64, buf5.len() as u64) }; + assert_eq!(result5, false); + + let buf6: Vec = vec![0, 0, 0, 0, 0, 0, 0, 0, 1, 0]; + let result6 = unsafe { buffer_is_zero(buf6.as_ptr() as u64, buf6.len() as u64) }; + assert_eq!(result6, false); + + let mut buf7: Vec = vec![0; 1025]; + buf7[700] = 1; + let result7 = unsafe { buffer_is_zero(buf7.as_ptr() as u64, buf7.len() as u64) }; + assert_eq!(result7, false); + } + + #[test] + fn test_iovec_is_zero() { + let buf1: Vec = vec![0; 5]; + let buf2: Vec = vec![0; 16]; + let iovecs1 = vec![ + Iovec::new(buf1.as_ptr() as u64, buf1.len() as u64), + Iovec::new(buf2.as_ptr() as u64, buf2.len() as u64), + ]; + + let result1 = unsafe { iovec_is_zero(&iovecs1) }; + assert_eq!(result1, true); + + let buf3: Vec = vec![0, 1, 0]; + let buf4: Vec = vec![0, 0, 0, 0, 0, 0, 0, 0, 1, 0]; + let iovecs2 = vec![ + Iovec::new(buf3.as_ptr() as u64, buf3.len() as u64), + Iovec::new(buf4.as_ptr() as u64, buf4.len() as u64), + ]; + + let result2 = unsafe { iovec_is_zero(&iovecs2) }; + assert_eq!(result2, false); + } } -- Gitee From acb483328bfd6210dc0fc72c7a3577a432baa690 Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Wed, 26 Feb 2025 19:13:27 +0800 Subject: [PATCH 477/489] ohcam: fix reported formats' sequence This patch is just for some APP. This fucking stupid APP just uses the format we report first to realize camera-related functions, while it may not support this format actually. For this reason, we put YUY2 format on first position. (On OHOS, we just support YUY2 and NV12 for camera now.) Signed-off-by: Fei Xu --- devices/src/camera_backend/mod.rs | 2 +- devices/src/camera_backend/ohcam.rs | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/devices/src/camera_backend/mod.rs b/devices/src/camera_backend/mod.rs index d9fd95f9..a02f4921 100644 --- a/devices/src/camera_backend/mod.rs +++ b/devices/src/camera_backend/mod.rs @@ -54,7 +54,7 @@ impl CamBasicFmt { } } -#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, Default)] +#[derive(Clone, Copy, Debug, Hash, Eq, PartialEq, PartialOrd, Default)] pub enum FmtType { #[default] Yuy2 = 0, diff --git a/devices/src/camera_backend/ohcam.rs b/devices/src/camera_backend/ohcam.rs index 64743591..51d7d049 100755 --- a/devices/src/camera_backend/ohcam.rs +++ b/devices/src/camera_backend/ohcam.rs @@ -269,6 +269,11 @@ impl CameraBackend for OhCameraBackend { Err(e) => error!("{:?}", e), } } + + // Just for APP ToDesk, This stupid APP uses the format reported first + // to realize camera-related functions. It doesn't support NV12, so + // we put YUY2 forward.s + fmt_list.sort_by(|a, b| a.format.partial_cmp(&b.format).unwrap()); self.fmt_list = fmt_list.clone(); Ok(fmt_list) } -- Gitee From 62a4c420505e741a805713822d8fc2c33b849402 Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Fri, 28 Feb 2025 17:13:27 +0800 Subject: [PATCH 478/489] stratovirt-img: refactoring image-create Encapsulating functions for use by image-convert. No functional change. Signed-off-by: Fei Xu --- image/src/img.rs | 57 ++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/image/src/img.rs b/image/src/img.rs index 2a4f3a40..63b54e2f 100644 --- a/image/src/img.rs +++ b/image/src/img.rs @@ -113,6 +113,32 @@ impl Drop for ImageFile { } } +fn image_do_create(create_options: &CreateOptions, print_info: bool) -> Result<()> { + let path = create_options.path.clone(); + let file = Arc::new( + std::fs::OpenOptions::new() + .read(true) + .write(true) + .custom_flags(libc::O_CREAT | libc::O_TRUNC) + .mode(0o660) + .open(path)?, + ); + + let aio = Aio::new(Arc::new(SyncAioInfo::complete_func), AioEngine::Off, None)?; + + let mut driver: Box> = match create_options.conf.format { + DiskFormat::Raw => Box::new(RawDriver::new(file, aio, create_options.conf.clone())), + DiskFormat::Qcow2 => Box::new(Qcow2Driver::new(file, aio, create_options.conf.clone())?), + }; + let image_info = driver.as_mut().create_image(create_options)?; + + if print_info { + println!("Stratovirt-img: {}", image_info); + } + + Ok(()) +} + pub(crate) fn image_create(args: Vec) -> Result<()> { let mut create_options = CreateOptions::default(); let mut arg_parser = ArgsParse::create(vec!["h", "help"], vec!["f"], vec!["o"]); @@ -123,10 +149,8 @@ pub(crate) fn image_create(args: Vec) -> Result<()> { return Ok(()); } - let mut disk_fmt = DiskFormat::Raw; - if let Some(fmt) = arg_parser.opt_str("f") { - disk_fmt = DiskFormat::from_str(&fmt)?; - }; + let fmt = arg_parser.opt_str("f").unwrap_or_else(|| "raw".to_string()); + create_options.conf.format = DiskFormat::from_str(&fmt)?; let extra_options = arg_parser.opt_strs("o"); for option in extra_options { @@ -165,30 +189,7 @@ pub(crate) fn image_create(args: Vec) -> Result<()> { } } - let path = create_options.path.clone(); - let file = Arc::new( - std::fs::OpenOptions::new() - .read(true) - .write(true) - .custom_flags(libc::O_CREAT | libc::O_TRUNC) - .mode(0o660) - .open(path)?, - ); - - let aio = Aio::new(Arc::new(SyncAioInfo::complete_func), AioEngine::Off, None)?; - let image_info = match disk_fmt { - DiskFormat::Raw => { - create_options.conf.format = DiskFormat::Raw; - let mut raw_driver = RawDriver::new(file, aio, create_options.conf.clone()); - raw_driver.create_image(&create_options)? - } - DiskFormat::Qcow2 => { - create_options.conf.format = DiskFormat::Qcow2; - let mut qcow2_driver = Qcow2Driver::new(file, aio, create_options.conf.clone())?; - qcow2_driver.create_image(&create_options)? - } - }; - println!("Stratovirt-img: {}", image_info); + image_do_create(&create_options, true)?; Ok(()) } -- Gitee From 3f5b72184c3eb64789a042d99c45f358fb54bfa2 Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Mon, 3 Mar 2025 19:44:27 +0800 Subject: [PATCH 479/489] util: expose function `buffer_is_zero` Expose function `buffer_is_zero` to other modules for use. Signed-off-by: Fei Xu --- util/src/aio/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/util/src/aio/mod.rs b/util/src/aio/mod.rs index e308181f..7c3410fb 100644 --- a/util/src/aio/mod.rs +++ b/util/src/aio/mod.rs @@ -835,8 +835,10 @@ pub fn iov_discard_front_direct(iovec: &mut [Iovec], mut size: u64) -> Option<&m None } -// Caller should have valid buffer base/len. -unsafe fn buffer_is_zero(base: u64, len: u64) -> bool { +/// # Safety +/// +/// Caller should have valid buffer base/len. +pub unsafe fn buffer_is_zero(base: u64, len: u64) -> bool { let slice = std::slice::from_raw_parts(base as *const u8, len as usize); let (prefix, aligned, suffix) = slice.align_to::(); prefix.iter().all(|&x| x == 0) -- Gitee From bea1c2d4a38daf8cc5809d204ba85262f6d8ab98 Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Fri, 7 Mar 2025 19:53:27 +0800 Subject: [PATCH 480/489] stratovirt-img: add `convert` for image format conversion Add `convert` for image format conversion. Usage: stratovirt-img convert [ -f input_fmt | -O output_fmt | -S sparse_size ] input_filename output_filename Signed-off-by: Fei Xu --- block_backend/src/lib.rs | 15 ++ block_backend/src/qcow2/mod.rs | 15 +- docs/stratovirt-img.md | 23 +++ image/src/img.rs | 258 ++++++++++++++++++++++++++++++++- image/src/main.rs | 4 +- 5 files changed, 309 insertions(+), 6 deletions(-) diff --git a/block_backend/src/lib.rs b/block_backend/src/lib.rs index 3a29a19c..5e711a89 100644 --- a/block_backend/src/lib.rs +++ b/block_backend/src/lib.rs @@ -349,6 +349,11 @@ impl Default for BlockProperty { } } +pub enum BlockAllocStatus { + DATA, + ZERO, +} + pub trait BlockDriverOps: Send { fn create_image(&mut self, options: &CreateOptions) -> Result; @@ -391,6 +396,16 @@ pub trait BlockDriverOps: Send { fn unregister_io_event(&mut self) -> Result<()>; fn get_status(&mut self) -> Arc>; + + // Get a continuous address with the same allocation status starting from `offset`. + // Returns this continuous address's allocation status(data or zero) and size. + fn get_address_alloc_status( + &mut self, + _offset: u64, + _bytes: u64, + ) -> Result<(BlockAllocStatus, u64)> { + bail!("Not support!"); + } } pub fn create_block_backend( diff --git a/block_backend/src/qcow2/mod.rs b/block_backend/src/qcow2/mod.rs index 011b4485..1151798d 100644 --- a/block_backend/src/qcow2/mod.rs +++ b/block_backend/src/qcow2/mod.rs @@ -49,8 +49,8 @@ use crate::{ snapshot::{InternalSnapshot, QcowSnapshot, QcowSnapshotExtraData, QCOW2_MAX_SNAPSHOTS}, table::{Qcow2ClusterType, Qcow2Table}, }, - BlockDriverOps, BlockIoErrorCallback, BlockProperty, BlockStatus, CheckResult, CreateOptions, - ImageInfo, SECTOR_SIZE, + BlockAllocStatus, BlockDriverOps, BlockIoErrorCallback, BlockProperty, BlockStatus, + CheckResult, CreateOptions, ImageInfo, SECTOR_SIZE, }; use machine_manager::event_loop::EventLoop; use machine_manager::qmp::qmp_schema::SnapshotInfo; @@ -1982,6 +1982,17 @@ impl BlockDriverOps for Qcow2Driver { fn get_status(&mut self) -> Arc> { self.status.clone() } + + fn get_address_alloc_status( + &mut self, + offset: u64, + bytes: u64, + ) -> Result<(BlockAllocStatus, u64)> { + match self.host_offset_for_read(offset, bytes)? { + HostRange::DataNotInit(size) => Ok((BlockAllocStatus::ZERO, size)), + HostRange::DataAddress(_, size) => Ok((BlockAllocStatus::DATA, size)), + } + } } pub fn is_aligned(cluster_sz: u64, offset: u64) -> bool { diff --git a/docs/stratovirt-img.md b/docs/stratovirt-img.md index cca517a9..ec956c1d 100644 --- a/docs/stratovirt-img.md +++ b/docs/stratovirt-img.md @@ -111,3 +111,26 @@ stratovirt-img snapshot -r old_snapshot_name new_snapshot_name img_path ``` Note: The internal snapshot is not supported by raw. + +## Convert + +Convert the disk image to a new disk image using new format. +Command syntax: + +```shell +convert [ -f input_fmt | -O output_fmt | -S sparse_size ] input_filename output_filename +``` + +- -f fmt: Input image format. +- -O output_fmt: Output image format. +- -S sparse_size: the consecutive number of bytes that must contain only zeroes to create a sparse image during conversion. Unit: sector(512 bytes). Default is 8. +- input_filename: name of the input file using *input_fmt* image format. +- output_filename: name of the output file using *output_fmt* image format. + +Sample Configuration: + +```shell +stratovirt-img convert -f qcow2 -O raw qcow2_img_path raw_img_path +``` + +Note: Only qcow2 image to raw image conversion is supported currently. diff --git a/image/src/img.rs b/image/src/img.rs index 63b54e2f..dd645564 100644 --- a/image/src/img.rs +++ b/image/src/img.rs @@ -23,12 +23,12 @@ use crate::{cmdline::ArgsParse, BINARY_NAME}; use block_backend::{ qcow2::{header::QcowHeader, InternalSnapshotOps, Qcow2Driver, SyncAioInfo}, raw::RawDriver, - BlockDriverOps, BlockProperty, CheckResult, CreateOptions, ImageInfo, FIX_ERRORS, FIX_LEAKS, - NO_FIX, SECTOR_SIZE, + BlockAllocStatus, BlockDriverOps, BlockProperty, CheckResult, CreateOptions, ImageInfo, + FIX_ERRORS, FIX_LEAKS, NO_FIX, SECTOR_SIZE, }; use machine_manager::config::{memory_unit_conversion, DiskFormat}; use util::{ - aio::{Aio, AioEngine, WriteZeroesState}, + aio::{buffer_is_zero, Aio, AioEngine, Iovec, WriteZeroesState}, file::{lock_file, open_file, unlock_file}, }; @@ -381,6 +381,250 @@ pub(crate) fn image_resize(mut args: Vec) -> Result<()> { Ok(()) } +// Default 4k(8 sectors) for sparse detection. +const DEFAULT_SPARSE_SIZE: u8 = 8; +// Default 2M buffer size for convert. +const DEFAULT_BUF_SIZE: usize = 1 << 21; + +#[derive(Debug, PartialEq, Eq)] +enum ConvertDataStatus { + Zero = 0, + Data, +} + +impl ConvertDataStatus { + fn from_bool(is_zero: bool) -> Self { + if is_zero { + ConvertDataStatus::Zero + } else { + ConvertDataStatus::Data + } + } +} + +// Describe a continuous address segment which has the same allocation status when converting. +#[derive(PartialEq, Eq)] +struct ConvertSeg { + start: u64, + len: u64, + status: ConvertDataStatus, +} + +impl ConvertSeg { + fn new(start: u64, len: u64, is_zero: bool) -> Self { + Self { + start, + len, + status: ConvertDataStatus::from_bool(is_zero), + } + } +} + +fn convert_do_read( + driver: &mut dyn BlockDriverOps<()>, + buf: &mut [u8], + len: u64, + offset: u64, +) -> Result<()> { + let iov = vec![Iovec { + iov_base: buf.as_ptr() as u64, + iov_len: len, + }]; + driver.read_vectored(iov, offset as usize, ()) +} + +fn convert_do_seg_write( + driver: &mut dyn BlockDriverOps<()>, + buf: &mut [u8], + data_seg: &ConvertSeg, +) -> Result<()> { + match data_seg.status { + ConvertDataStatus::Data => { + let iov = vec![Iovec { + iov_base: buf.as_ptr() as u64, + iov_len: data_seg.len, + }]; + driver.write_vectored(iov, data_seg.start as usize, ()) + } + ConvertDataStatus::Zero => { + // The output image is a newly created sparse file, which defaults to all holes. + // Sequential writing does not require writing zeroes again. Do nothing. + Ok(()) + } + } +} + +fn convert_do_write( + driver: &mut dyn BlockDriverOps<()>, + buf: &mut [u8], + buf_len: u64, + offset: u64, + sparse_size: u64, +) -> Result<()> { + let mut convert_seg = ConvertSeg::new(offset, 0, true); + let mut first_check = true; + + let mut pos = 0_u64; + while pos < buf_len { + let detect_size = std::cmp::min(sparse_size, buf_len - pos); + let detect_buf = &buf[pos as usize..(pos + detect_size) as usize]; + + // SAFETY: Buffer is a local `Vec` variable in `image_convert`, its base and len are both valid values. + let local_zero = unsafe { buffer_is_zero(detect_buf.as_ptr() as u64, detect_size) }; + + if first_check { + convert_seg.status = ConvertDataStatus::from_bool(local_zero); + first_check = false; + } + + if ConvertDataStatus::from_bool(local_zero) != convert_seg.status { + convert_do_seg_write( + driver, + &mut buf[(convert_seg.start - offset) as usize..pos as usize], + &convert_seg, + )?; + + convert_seg.status = ConvertDataStatus::from_bool(local_zero); + convert_seg.start = offset + pos; + convert_seg.len = detect_size; + + pos += detect_size; + continue; + } + + convert_seg.len += detect_size; + pos += detect_size; + } + + if !first_check { + convert_do_seg_write( + driver, + &mut buf[(convert_seg.start - offset) as usize..pos as usize], + &convert_seg, + )?; + } + Ok(()) +} + +fn image_create_blockdriver( + file: Arc, + format: DiskFormat, +) -> Result>> { + let conf = BlockProperty { + format, + ..Default::default() + }; + let aio = Aio::new(Arc::new(SyncAioInfo::complete_func), AioEngine::Off, None).unwrap(); + + match format { + DiskFormat::Qcow2 => { + let mut qcow2_driver = Qcow2Driver::new(file, aio, conf.clone())?; + qcow2_driver.load_metadata(conf)?; + Ok(Box::new(qcow2_driver)) + } + DiskFormat::Raw => Ok(Box::new(RawDriver::new(file, aio, conf))), + } +} + +pub(crate) fn image_convert(args: Vec) -> Result<()> { + let mut arg_parser = ArgsParse::create(vec!["h", "help"], vec!["f", "O", "S"], vec![]); + arg_parser.parse(args)?; + + if arg_parser.opt_present("h") || arg_parser.opt_present("help") { + print_help(); + return Ok(()); + } + + // Parse the image path. Command line should have 2 args at the end(input filename and output filename). + if arg_parser.free.len() != 2 { + bail!("Invalid input/output filenames."); + } + let input_path = arg_parser.free[0].clone(); + let output_path = arg_parser.free[1].clone(); + + // Check output image filename: to avoid accidentally deleting existing files, + // it is prohibited to use the name of an existing file as the output image name. + if std::path::Path::new(&output_path).exists() { + bail!( + "The file {} already exists, please use a different name.", + output_path + ); + } + + // Parse the input image format. If not set, it will detect the corresponding image file to determine the image format. + let input_fmt_str = arg_parser.opt_str("f").unwrap_or_default(); + let input_image_file = ImageFile::create(&input_path, true)?; + let detect_input_fmt = input_image_file.detect_img_format()?; + if !input_fmt_str.is_empty() { + let input_fmt = DiskFormat::from_str(&input_fmt_str)?; + if detect_input_fmt != input_fmt { + bail!("'{}' is not a {} file.", input_path, input_fmt_str); + } + } + + // Parse the output image format. Default is "raw". + let output_fmt_str = arg_parser.opt_str("O").unwrap_or_else(|| "raw".to_string()); + let output_fmt = DiskFormat::from_str(&output_fmt_str)?; + + // Parse the min sparse. + let min_sparse_str = arg_parser + .opt_str("S") + .unwrap_or_else(|| DEFAULT_SPARSE_SIZE.to_string()); + let min_sparse = min_sparse_str.parse::()? * SECTOR_SIZE; + + // Create input image driver. + let mut input_driver_box = + image_create_blockdriver(input_image_file.file.clone(), detect_input_fmt)?; + let input_driver = input_driver_box.as_mut(); + let size = input_driver.disk_size()?; + + // Create new output file. + let mut create_options = CreateOptions { + path: output_path.clone(), + img_size: size, + ..Default::default() + }; + create_options.conf.format = output_fmt; + image_do_create(&create_options, false)?; + + // Create output image driver. + let output_image_file = ImageFile::create(&output_path, false)?; + let mut output_driver_box = + image_create_blockdriver(output_image_file.file.clone(), output_fmt)?; + let output_driver = output_driver_box.as_mut(); + + // Convert from src image to dst image. + let mut offset = 0; + let mut buf = vec![0_u8; DEFAULT_BUF_SIZE]; + while offset < size { + // Get address segments with the same allocation status. + let (status, len) = input_driver.get_address_alloc_status(offset as u64, size - offset)?; + match status { + // `DATA` means that these data should be read from the src image and be written to the dst image. + BlockAllocStatus::DATA => { + let mut need_convert = len; + let mut cur_offset = offset; + while need_convert > 0 { + let data_len = std::cmp::min(DEFAULT_BUF_SIZE as u64, need_convert); + convert_do_read(input_driver, &mut buf, data_len, cur_offset)?; + convert_do_write(output_driver, &mut buf, data_len, cur_offset, min_sparse)?; + cur_offset += data_len; + need_convert -= data_len; + } + } + // `ZERO` means that these data can be treated as holes. + BlockAllocStatus::ZERO => { + // The output image is a newly created sparse file, which defaults to all holes. + // Sequential writing does not require writing zeroes again. Do nothing. + } + }; + + offset += len; + } + + Ok(()) +} + pub(crate) fn image_snapshot(args: Vec) -> Result<()> { let mut arg_parser = ArgsParse::create( vec!["l", "h", "help", "r"], @@ -554,6 +798,7 @@ info filename check [-r [leaks | all]] [-no_print_error] [-f fmt] filename resize [-f fmt] filename [+]size snapshot [-l | -a snapshot | -c snapshot | -d snapshot | -r old_snapshot_name new_snapshot_name] filename +convert [-f input_fmt | -O output_fmt | -S sparse_size ] input_filename output_filename Command parameters: 'filename' is a disk image filename @@ -575,6 +820,13 @@ Parameters to snapshot subcommand: '-d' deletes a snapshot '-l' lists all snapshots in the given image '-r' change the name of a snapshot + +Parameters to convert subcommand: + '-f fmt' is input image format. + '-O output_fmt' is output image format. + '-S sparse_size' is the consecutive number of bytes that must contain only zeroes to create a sparse image during conversion. Unit: sector(512 bytes). Default is 8. + 'input_filename' is the name of the input file using *input_fmt* image format. + 'output_filename' is the name of the output file using *output_fmt* image format. "#, ); } diff --git a/image/src/main.rs b/image/src/main.rs index b9c7aef5..341c0f0e 100644 --- a/image/src/main.rs +++ b/image/src/main.rs @@ -21,7 +21,8 @@ use std::{ use anyhow::{bail, Result}; use crate::img::{ - image_check, image_create, image_info, image_resize, image_snapshot, print_help, print_version, + image_check, image_convert, image_create, image_info, image_resize, image_snapshot, print_help, + print_version, }; const BINARY_NAME: &str = "stratovirt-img"; @@ -86,6 +87,7 @@ fn run(args: Vec) -> Result<()> { ("info", image_info, cmd_args), ("check", image_check, cmd_args), ("resize", image_resize, cmd_args), + ("convert", image_convert, cmd_args), ("snapshot", image_snapshot, cmd_args); ("-v" | "--version", print_version), ("-h" | "--help", print_help) -- Gitee From 51cda933e2519599ab7b3dd251240d201f218f90 Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Thu, 13 Mar 2025 20:59:27 +0800 Subject: [PATCH 481/489] stratovirt-img: add test for image_convert Add test for image_convert. Signed-off-by: Fei Xu --- image/src/img.rs | 177 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 177 insertions(+) diff --git a/image/src/img.rs b/image/src/img.rs index dd645564..bc5b58eb 100644 --- a/image/src/img.rs +++ b/image/src/img.rs @@ -845,6 +845,7 @@ mod test { }; use util::aio::Iovec; + const K: u64 = 1024; const M: u64 = 1024 * 1024; const G: u64 = 1024 * 1024 * 1024; @@ -2370,4 +2371,180 @@ mod test { drop(driver); assert!(test_image.check_image(quite, fix)); } + + /// Test image convert from qcow2 to raw. + /// + /// TestStep: + /// 1. Create a qcow2 image with size of 10G. + /// 2. Write data to this image in different position. + /// 3. Convert this qcow2 to raw. + /// 4. Read data in the same position. + #[test] + fn test_image_convert_from_qcow2_to_raw() { + let src_path = "/tmp/test_image_convert_src.qcow2"; + let dst_path = "/tmp/test_image_convert_dst.raw"; + let _ = remove_file(src_path.clone()); + let _ = remove_file(dst_path.clone()); + + let test_image = TestQcow2Image::create(16, 16, src_path, "10G"); + let mut src_driver = test_image.create_driver(); + + // Write 1M data(number 1) in offset 0. + let buf1 = vec![1_u8; 1 * M as usize]; + assert!(image_write(&mut src_driver, 0, &buf1).is_ok()); + // Write 1M data(number 2) in offset 5G. + let buf2 = vec![2_u8; 1 * M as usize]; + assert!(image_write(&mut src_driver, 5 * G as usize, &buf2).is_ok()); + // Write 1M data(number 3) in last 1M. + let buf3 = vec![3_u8; 1 * M as usize]; + assert!(image_write(&mut src_driver, 10 * G as usize - 1 * M as usize, &buf3).is_ok()); + // Write 1M data(number 0) in random offset (eg: 300M offset). + let buf4 = vec![0_u8; 1 * M as usize]; + assert!(image_write(&mut src_driver, 300 * M as usize, &buf4).is_ok()); + + drop(src_driver); + + assert!(image_convert(vec![ + "-f".to_string(), + "qcow2".to_string(), + "-O".to_string(), + "raw".to_string(), + src_path.to_string(), + dst_path.to_string() + ]) + .is_ok()); + + // Open the converted raw image. + let conf = BlockProperty::default(); + let aio = Aio::new(Arc::new(SyncAioInfo::complete_func), AioEngine::Off, None).unwrap(); + let file = open_file(dst_path, true, false).unwrap(); + let mut dst_driver = RawDriver::new(Arc::new(file), aio, conf); + + // Read 1M data in offset 0. + let buf = vec![0; 1 * M as usize]; + assert!(image_read(&mut dst_driver, 0, &buf).is_ok()); + assert_eq!(buf, buf1); + // Read 1M data in offset 5G. + assert!(image_read(&mut dst_driver, 5 * G as usize, &buf).is_ok()); + assert_eq!(buf, buf2); + // Read 1M data in last 1M. + assert!(image_read(&mut dst_driver, 10 * G as usize - 1 * M as usize, &buf).is_ok()); + assert_eq!(buf, buf3); + + let mut img_info = ImageInfo::default(); + assert!(dst_driver.query_image(&mut img_info).is_ok()); + assert_eq!(img_info.virtual_size, 10 * G); + // 1M data(number 0) in offset 300M will not consume space. + assert_eq!(img_info.actual_size, 3 * M); + + // Clean. + assert!(remove_file(dst_path.clone()).is_ok()); + } + + /// Test image convert parameters parsing. + /// + /// TestStep: + /// 1. Create a qcow2 image with size of 1G. + /// 2. Write two continuous `4k 0 buffer + 4k 1 buffer` to this image. + /// 3. Test default parameters. + /// 4. Test existed destination file. + /// 5. Test min sparse. + #[test] + fn test_image_convert_parameters_parsing() { + let src_path = "/tmp/test_image_convert_paring_src.qcow2"; + let dst_path = "/tmp/test_image_convert_paring_dst.raw"; + let _ = remove_file(src_path.clone()); + let _ = remove_file(dst_path.clone()); + + let test_image = TestQcow2Image::create(16, 16, src_path, "1G"); + let mut src_driver = test_image.create_driver(); + + // Write 4k data(number 0) in offset 16k. + assert!(image_write( + &mut src_driver, + 16 * K as usize, + &vec![0_u8; 4 * K as usize] + ) + .is_ok()); + // Write 4k data(number 1) in offset 20k. + assert!(image_write( + &mut src_driver, + 20 * K as usize, + &vec![1_u8; 4 * K as usize] + ) + .is_ok()); + // Write 4k data(number 0) in offset 24k. + assert!(image_write( + &mut src_driver, + 24 * K as usize, + &vec![0_u8; 4 * K as usize] + ) + .is_ok()); + // Write 4k data(number 1) in offset 28k. + assert!(image_write( + &mut src_driver, + 28 * K as usize, + &vec![1_u8; 4 * K as usize] + ) + .is_ok()); + + drop(src_driver); + + // test1: The default value of the parameters. + // `stratovirt-img convert src_path dst_path` + // Eq: `stratovirt-img convert -f qcow2 -O raw -S 8 src_path dst_path` + assert!(image_convert(vec![src_path.to_string(), dst_path.to_string()]).is_ok()); + // Check output format. + let output_image_file = ImageFile::create(&dst_path, true).unwrap(); + let detect_output_fmt = output_image_file.detect_img_format().unwrap(); + assert_eq!(detect_output_fmt, DiskFormat::Raw); + drop(output_image_file); + // Check sparse size by querying output file size. + let conf = BlockProperty::default(); + let aio = Aio::new(Arc::new(SyncAioInfo::complete_func), AioEngine::Off, None).unwrap(); + let file = open_file(dst_path, true, false).unwrap(); + let mut img_info = ImageInfo::default(); + let mut dst_driver = RawDriver::new(Arc::new(file), aio, conf); + assert!(dst_driver.query_image(&mut img_info).is_ok()); + // Raw file has allocated filled first part (sized 4k(host page size), see function `alloc_first_block`) for + // detecting the alignment length. + assert_eq!(img_info.actual_size, 4 * K + 8 * K); // 4K allocated filled first part + 8K data. + drop(dst_driver); + assert!(remove_file(dst_path.clone()).is_ok()); + + // test2: The destination file already exists. + let existed_raw = TestRawImage::create(dst_path.to_string(), "1G".to_string()); + assert!(image_convert(vec![ + "-f".to_string(), + "qcow2".to_string(), + "-O".to_string(), + "raw".to_string(), + src_path.to_string(), + dst_path.to_string() + ]) + .is_err()); + drop(existed_raw); + + // test3: Sparse test. + // stratovirt-img convert -f qcow2 -O raw -S 16 src_path dst_path + assert!(image_convert(vec![ + "-S".to_string(), + "16".to_string(), // 16 sectors.(8K) + src_path.to_string(), + dst_path.to_string() + ]) + .is_ok()); + // Query the image size. + let conf = BlockProperty::default(); + let aio = Aio::new(Arc::new(SyncAioInfo::complete_func), AioEngine::Off, None).unwrap(); + let file = open_file(dst_path, true, false).unwrap(); + let mut img_info = ImageInfo::default(); + let mut dst_driver = RawDriver::new(Arc::new(file), aio, conf); + assert!(dst_driver.query_image(&mut img_info).is_ok()); + // min_sparse is 16k. So, these continuous `4K 0 buffer + 4K 1 buffer` will be considered as all data buffer sized 8k. + // Will not create holes here. + assert_eq!(img_info.actual_size, 4 * K + 16 * K); + drop(dst_driver); + assert!(remove_file(dst_path.clone()).is_ok()); + } } -- Gitee From 9f518b45e299733571d59164ebeb0d3b524090d8 Mon Sep 17 00:00:00 2001 From: Xu Yandong Date: Fri, 14 Mar 2025 20:01:17 +0800 Subject: [PATCH 482/489] virtio: introduce virtio-input device The virtio-input device allows to passthrough host evdev input event to the guest. stratovirt -device virtio-input-device,id=vioinput0,evdev=/path/to/evdev --- machine/src/lib.rs | 36 +- machine_manager/src/cmdline.rs | 2 + util/src/evdev.rs | 181 ++++++++++ util/src/lib.rs | 1 + virtio/src/device/input.rs | 597 +++++++++++++++++++++++++++++++++ virtio/src/device/mod.rs | 1 + virtio/src/lib.rs | 2 + 7 files changed, 817 insertions(+), 3 deletions(-) create mode 100644 util/src/evdev.rs create mode 100644 virtio/src/device/input.rs diff --git a/machine/src/lib.rs b/machine/src/lib.rs index 701c76f6..bda1c9cc 100644 --- a/machine/src/lib.rs +++ b/machine/src/lib.rs @@ -128,9 +128,9 @@ use virtio::VhostUser; use virtio::VirtioDeviceQuirk; use virtio::{ balloon_allow_list, find_port_by_nr, get_max_nr, vhost, virtio_register_pcidevops_type, - virtio_register_sysbusdevops_type, Balloon, BalloonConfig, Block, BlockState, Serial, - SerialPort, VirtioBlkDevConfig, VirtioDevice, VirtioMmioDevice, VirtioMmioState, - VirtioNetState, VirtioPciDevice, VirtioSerialState, VIRTIO_TYPE_CONSOLE, + virtio_register_sysbusdevops_type, Balloon, BalloonConfig, Block, BlockState, Input, + InputConfig, Serial, SerialPort, VirtioBlkDevConfig, VirtioDevice, VirtioMmioDevice, + VirtioMmioState, VirtioNetState, VirtioPciDevice, VirtioSerialState, VIRTIO_TYPE_CONSOLE, }; #[cfg(feature = "virtio_gpu")] use virtio::{Gpu, GpuDevConfig}; @@ -916,6 +916,35 @@ pub trait MachineOps: MachineLifecycle { bail!("No pci host found"); } + /// Add virtio-input device + /// + /// # Arguments + /// + /// * `cfg_args` - Device configuration arguments. + fn add_virtio_input(&mut self, cfg_args: &str) -> Result<()> { + let cfg = InputConfig::try_parse_from(str_slip_to_clap(cfg_args, true, false))?; + let dev = Arc::new(Mutex::new(Input::new(cfg.clone())?)); + match cfg.classtype.as_str() { + "virtio-input-device" => { + check_arg_nonexist!( + ("bus", cfg.bus), + ("addr", cfg.addr), + ("multifunction", cfg.multifunction) + ); + self.add_virtio_mmio_device(cfg.id.clone(), dev) + .with_context(|| "Failed to add virtio mmio input device")?; + } + _ => { + check_arg_exist!(("bus", cfg.bus), ("addr", cfg.addr)); + let bdf = PciBdf::new(cfg.bus.clone().unwrap(), cfg.addr.unwrap()); + let multi_func = cfg.multifunction.unwrap_or_default(); + self.add_virtio_pci_device(&cfg.id, &bdf, dev, multi_func, false) + .with_context(|| "Failed to add virtio pci input device")?; + } + } + Ok(()) + } + /// Add virtioFs device. /// /// # Arguments @@ -1978,6 +2007,7 @@ pub trait MachineOps: MachineLifecycle { ("virtio-net-pci", add_virtio_pci_net, vm_config, cfg_args, false), ("pcie-root-port", add_pci_root_port, cfg_args), ("virtio-balloon-device" | "virtio-balloon-pci", add_virtio_balloon, vm_config, cfg_args), + ("virtio-input-device" | "virtio-input-pci", add_virtio_input, cfg_args), ("virtio-serial-device" | "virtio-serial-pci", add_virtio_serial, vm_config, cfg_args), ("virtconsole" | "virtserialport", add_virtio_serial_port, vm_config, cfg_args), ("vhost-user-fs-pci" | "vhost-user-fs-device", add_virtio_fs, vm_config, cfg_args), diff --git a/machine_manager/src/cmdline.rs b/machine_manager/src/cmdline.rs index daa06be9..b056b571 100644 --- a/machine_manager/src/cmdline.rs +++ b/machine_manager/src/cmdline.rs @@ -249,6 +249,8 @@ pub fn create_args_parser<'a>() -> ArgParser<'a> { \n\t\tadd virtio pci balloon: -device virtio-balloon-pci,id=,bus=,addr=<0x4>[,deflate-on-oom=true|false][,free-page-reporting=true|false][,multifunction=on|off]; \ \n\t\tadd virtio mmio rng: -device virtio-rng-device,rng=,max-bytes=<1234>,period=<1000>; \ \n\t\tadd virtio pci rng: -device virtio-rng-pci,id=,rng=,max-bytes=<1234>,period=<1000>,bus=,addr=<0x1>[,multifunction=on|off]; \ + \n\t\tadd virtio mmio input: -device virtio-input-device,id=,evdev=; \ + \n\t\tadd virtio pci input: -device virtio-input-pci,id=,evdev=,bus=,addr=<0x1>[,multifunction=on|off]; \ \n\t\tadd pcie root port: -device pcie-root-port,id=,port=<0x1>,bus=,addr=<0x1>[,multifunction=on|off]; \ \n\t\tadd vfio pci: -device vfio-pci,id=,host=<0000:1a:00.3>,bus=,addr=<0x03>[,multifunction=on|off]; \ \n\t\tadd usb controller: -device nec-usb-xhci,id=,bus=,addr=<0xa>; \ diff --git a/util/src/evdev.rs b/util/src/evdev.rs new file mode 100644 index 00000000..76573f0a --- /dev/null +++ b/util/src/evdev.rs @@ -0,0 +1,181 @@ +// Copyright (c) 2025 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::collections::BTreeMap; +use std::fs::File; + +use anyhow::{bail, Result}; +use libc::c_int; +use log::error; +use vmm_sys_util::{ioctl::ioctl_with_mut_ref, ioctl_ioc_nr, ioctl_ior_nr, ioctl_iow_nr}; + +use crate::byte_code::ByteCode; + +/// Event Code type, used for autorepeating devices. +pub const EV_REP: u8 = 0x14; +/// Max event type. +pub const EV_MAX: u8 = 0x1F; +/// Max ABS_* event type. +pub const ABS_MAX: u8 = 0x3F; + +/// Sync event type. +pub const EV_SYN: u16 = 0x00; +/// Synchronization event. +pub const SYN_REPORT: u16 = 0x00; + +/// The payload(union) size of the virtio_input_config. +pub const VIRTIO_INPUT_CFG_PAYLOAD_SIZE: usize = 128; + +#[derive(Copy, Clone)] +pub struct EvdevBuf { + pub buf: [u8; VIRTIO_INPUT_CFG_PAYLOAD_SIZE], + pub len: usize, +} + +impl EvdevBuf { + pub fn new() -> Self { + Self { + buf: [0_u8; VIRTIO_INPUT_CFG_PAYLOAD_SIZE], + len: 0, + } + } + + pub fn get_bit(&self, bit: usize) -> bool { + if (bit + 7) / 8 > self.len { + return false; + } + let idx = bit / 8; + let offset = bit % 8; + self.buf[idx] & (1u8 << offset) != 0 + } + + pub fn to_vec(self) -> Vec { + self.buf[0..self.len].to_vec() + } +} + +impl Default for EvdevBuf { + fn default() -> Self { + Self::new() + } +} + +impl ByteCode for EvdevBuf {} + +#[derive(Copy, Clone, Default)] +#[repr(C)] +pub struct EvdevId { + pub bustype: u16, + pub vendor: u16, + pub product: u16, + pub version: u16, +} + +impl EvdevId { + pub fn from_buf(buf: EvdevBuf) -> Self { + *Self::from_bytes(buf.to_vec().as_slice()).unwrap() + } +} + +impl ByteCode for EvdevId {} + +#[derive(Copy, Clone, Default)] +#[repr(C)] +pub struct InputAbsInfo { + pub value: u32, + pub minimum: u32, + pub maximum: u32, + pub fuzz: u32, + pub flat: u32, + pub resolution: u32, +} + +const EVDEV: u32 = 69; // 'E' +ioctl_ior_nr!(EVIOCGVERSION, EVDEV, 0x01, c_int); +ioctl_ior_nr!(EVIOCGID, EVDEV, 0x02, EvdevId); +ioctl_ior_nr!(EVIOCGNAME, EVDEV, 0x06, EvdevBuf); +ioctl_ior_nr!(EVIOCGUNIQ, EVDEV, 0x08, EvdevBuf); +ioctl_ior_nr!(EVIOCGPROP, EVDEV, 0x09, EvdevBuf); +ioctl_ior_nr!(EVIOCGBIT, EVDEV, 0x20 + evt, EvdevBuf, evt); +ioctl_ior_nr!(EVIOCGABS, EVDEV, 0x40 + abs, InputAbsInfo, abs); +ioctl_iow_nr!(EVIOCGRAB, EVDEV, 0x90, c_int); + +pub fn evdev_ioctl(fd: &File, req: u64, len: usize) -> EvdevBuf { + let mut evbuf = EvdevBuf::new(); + // SAFETY: file is `evdev` fd, and we check the return. + let ret = unsafe { ioctl_with_mut_ref(fd, req, &mut evbuf.buf) }; + if ret < 0 { + error!( + "Ioctl {} failed, error is {}.", + req, + std::io::Error::last_os_error() + ); + evbuf.len = 0; + return evbuf; + } + + evbuf.len = len; + if evbuf.len == 0 { + if ret != 0 { + evbuf.len = ret as usize; + } else { + evbuf.len = VIRTIO_INPUT_CFG_PAYLOAD_SIZE; + } + } + + evbuf +} + +pub fn evdev_evt_supported(fd: &File) -> Result> { + let mut evts: BTreeMap = BTreeMap::new(); + let evt_type = evdev_ioctl(fd, EVIOCGBIT(0), 0); + if evt_type.len == 0 { + bail!(format!( + "Failed to get bit 0, error {}", + std::io::Error::last_os_error() + )) + } + for ev in 1..EV_MAX { + if ev == EV_REP || !evt_type.get_bit(ev as usize) { + // Not supported event + continue; + } + evts.insert(ev, evdev_ioctl(fd, EVIOCGBIT(ev as u32), 0)); + } + + Ok(evts) +} + +pub fn evdev_abs(fd: &File) -> Result> { + let mut absinfo_db: BTreeMap = BTreeMap::new(); + for abs in 0..ABS_MAX { + let mut absinfo = InputAbsInfo::default(); + // SAFETY: file is `evdev` fd, and we check the return. + let len = unsafe { ioctl_with_mut_ref(fd, EVIOCGABS(abs as u32), &mut absinfo) }; + if len == 0 { + absinfo_db.insert(abs, absinfo); + } + } + + Ok(absinfo_db) +} + +#[repr(C)] +#[derive(Clone, Copy, Default)] +pub struct InputEvent { + pub timestamp: [u64; 2], + pub ev_type: u16, + pub code: u16, + pub value: i32, +} + +impl ByteCode for InputEvent {} diff --git a/util/src/lib.rs b/util/src/lib.rs index 60fa43d2..33d77690 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -21,6 +21,7 @@ pub mod daemonize; pub mod device_tree; pub mod edid; pub mod error; +pub mod evdev; pub mod file; pub mod leak_bucket; pub mod link_list; diff --git a/virtio/src/device/input.rs b/virtio/src/device/input.rs new file mode 100644 index 00000000..ab4ee8a9 --- /dev/null +++ b/virtio/src/device/input.rs @@ -0,0 +1,597 @@ +// Copyright (c) 2025 Huawei Technologies Co.,Ltd. All rights reserved. +// +// StratoVirt is licensed under Mulan PSL v2. +// You can use this software according to the terms and conditions of the Mulan +// PSL v2. +// You may obtain a copy of Mulan PSL v2 at: +// http://license.coscl.org.cn/MulanPSL2 +// THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY +// KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO +// NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE. +// See the Mulan PSL v2 for more details. + +use std::collections::BTreeMap; +use std::fs::{File, OpenOptions}; +use std::io::{Read, Write}; +use std::mem::size_of; +use std::os::unix::io::{AsRawFd, RawFd}; +use std::os::unix::prelude::OpenOptionsExt; +use std::rc::Rc; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::sync::{Arc, Mutex}; + +use anyhow::{anyhow, bail, Context, Result}; +use clap::{ArgAction, Parser}; +use libc::c_int; +use log::{error, warn}; +use vmm_sys_util::{epoll::EventSet, eventfd::EventFd}; + +use crate::{ + check_config_space_rw, error::*, iov_read_object, read_config_default, report_virtio_error, + Queue, VirtioBase, VirtioDevice, VirtioInterrupt, VirtioInterruptType, VIRTIO_F_VERSION_1, + VIRTIO_TYPE_INPUT, +}; +use address_space::AddressSpace; +use machine_manager::{ + config::{get_pci_df, parse_bool, valid_id, DEFAULT_VIRTQUEUE_SIZE}, + event_loop::{register_event_helper, unregister_event_helper}, +}; +use util::byte_code::ByteCode; +use util::evdev::*; +use util::loop_context::{ + read_fd, EventNotifier, EventNotifierHelper, NotifierCallback, NotifierOperation, +}; + +/// Unset select cfg. +const VIRTIO_INPUT_CFG_UNSET: u8 = 0x00; +/// Returns the name of the device +const VIRTIO_INPUT_CFG_ID_NAME: u8 = 0x01; +/// Returns the serial number of the device. +const VIRTIO_INPUT_CFG_ID_SERIAL: u8 = 0x02; +/// Returns ID information of the device. +const VIRTIO_INPUT_CFG_ID_DEVIDS: u8 = 0x03; +/// Returns input properties of the device. +const VIRTIO_INPUT_CFG_PROP_BITS: u8 = 0x10; +/// subsel specifies the event type using EV_* constants in the underlying evdev implementation. +const VIRTIO_INPUT_CFG_EV_BITS: u8 = 0x11; +/// subsel specifies the absolute axis using ABS_* constants in the underlying evdev implementation. +const VIRTIO_INPUT_CFG_ABS_INFO: u8 = 0x12; + +/// Number of virtqueues. +const QUEUE_NUM_INPUT: usize = 2; + +#[derive(Parser, Debug, Clone, Default)] +#[command(no_binary_name(true))] +pub struct InputConfig { + #[arg(long, value_parser = ["virtio-input-device", "virtio-input-pci"])] + pub classtype: String, + #[arg(long, value_parser = valid_id)] + pub id: String, + #[arg(long)] + pub bus: Option, + #[arg(long, value_parser=get_pci_df)] + pub addr: Option<(u8, u8)>, + #[arg(long, value_parser=parse_bool, action = ArgAction::Append)] + pub multifunction: Option, + #[arg(long)] + pub evdev: String, +} + +#[derive(Copy, Clone, Default)] +#[repr(C)] +struct virtio_input_device_ids { + bustype: [u8; size_of::()], + vendor: [u8; size_of::()], + product: [u8; size_of::()], + version: [u8; size_of::()], +} + +impl virtio_input_device_ids { + fn from_evdevid(evdev_id: EvdevId) -> Self { + Self { + bustype: evdev_id.bustype.to_le_bytes(), + vendor: evdev_id.vendor.to_le_bytes(), + product: evdev_id.product.to_le_bytes(), + version: evdev_id.version.to_le_bytes(), + } + } +} + +impl ByteCode for virtio_input_device_ids {} + +#[derive(Copy, Clone, Default)] +#[repr(C)] +struct VirtioInputAbsInfo { + min: [u8; size_of::()], + max: [u8; size_of::()], + fuzz: [u8; size_of::()], + flat: [u8; size_of::()], +} + +impl VirtioInputAbsInfo { + fn from_absinfo(absinfo: InputAbsInfo) -> Self { + Self { + min: absinfo.minimum.to_le_bytes(), + max: absinfo.maximum.to_le_bytes(), + fuzz: absinfo.fuzz.to_le_bytes(), + flat: absinfo.flat.to_le_bytes(), + } + } +} + +impl ByteCode for VirtioInputAbsInfo {} + +#[repr(C)] +#[derive(Copy, Clone)] +struct VirtioInputConfig { + select: u8, + subsel: u8, + size: u8, + reserved: [u8; 5], + payload: [u8; VIRTIO_INPUT_CFG_PAYLOAD_SIZE], +} + +impl VirtioInputConfig { + fn new() -> Self { + Self { + select: VIRTIO_INPUT_CFG_UNSET, + subsel: 0, + size: 0, + reserved: [0_u8; 5], + payload: [0_u8; VIRTIO_INPUT_CFG_PAYLOAD_SIZE], + } + } + + fn set_payload(&mut self, payload: &[u8]) { + let len = (&mut self.payload[..]).write(payload).unwrap(); + self.size = len as u8; + } +} + +impl Default for VirtioInputConfig { + fn default() -> Self { + Self::new() + } +} + +impl ByteCode for VirtioInputConfig {} + +#[repr(C)] +#[derive(Copy, Clone, Default)] +struct VirtioInputEvent { + ev_type: [u8; size_of::()], + code: [u8; size_of::()], + value: [u8; size_of::()], +} + +impl VirtioInputEvent { + fn to_evt(self) -> InputEvent { + use byteorder::{ByteOrder, LittleEndian}; + InputEvent { + timestamp: [0_u64, 2], + ev_type: LittleEndian::read_u16(&self.ev_type), + code: LittleEndian::read_u16(&self.code), + value: LittleEndian::read_i32(&self.value), + } + } + + fn from_evt(evt: &InputEvent) -> Self { + Self { + ev_type: evt.ev_type.to_le_bytes(), + code: evt.code.to_le_bytes(), + value: evt.value.to_le_bytes(), + } + } +} + +impl ByteCode for VirtioInputEvent {} + +struct EvdevConfig { + /// config select + select: u8, + /// config sub select + subsel: u8, + /// ID information of the device + device_ids: virtio_input_device_ids, + /// Name of the device + name: Vec, + /// Serial of the device + serial: Vec, + /// Properties of the device + properties: EvdevBuf, + /// Events supported of the device + event_supported: BTreeMap, + /// Axis information of the device + abs_info: BTreeMap, +} + +impl EvdevConfig { + fn new(fd: &File) -> Result { + if evdev_ioctl(fd, EVIOCGVERSION(), size_of::()).len == 0 { + bail!("It's not an evdev device"); + } + + let id = EvdevId::from_buf(evdev_ioctl(fd, EVIOCGID(), size_of::())); + Ok(Self { + select: VIRTIO_INPUT_CFG_UNSET, + subsel: 0, + device_ids: virtio_input_device_ids::from_evdevid(id), + name: evdev_ioctl(fd, EVIOCGNAME(), 0).to_vec(), + serial: evdev_ioctl(fd, EVIOCGUNIQ(), 0).to_vec(), + properties: evdev_ioctl(fd, EVIOCGPROP(), 0), + event_supported: evdev_evt_supported(fd)?, + abs_info: evdev_abs(fd)?, + }) + } + + fn get_device_config(&self) -> VirtioInputConfig { + let mut cfg = VirtioInputConfig { + select: self.select, + subsel: self.subsel, + ..Default::default() + }; + + match self.select { + VIRTIO_INPUT_CFG_ID_NAME => { + cfg.set_payload(self.name.as_slice()); + } + VIRTIO_INPUT_CFG_ID_SERIAL => { + cfg.set_payload(self.serial.as_slice()); + } + VIRTIO_INPUT_CFG_ID_DEVIDS => { + cfg.set_payload(self.device_ids.as_bytes()); + } + VIRTIO_INPUT_CFG_PROP_BITS => { + cfg.set_payload(self.properties.to_vec().as_slice()); + } + VIRTIO_INPUT_CFG_EV_BITS => { + if let Some(bitmap) = self.event_supported.get(&self.subsel) { + cfg.set_payload(bitmap.as_bytes()); + } + } + VIRTIO_INPUT_CFG_ABS_INFO => { + if let Some(absinfo) = self.abs_info.get(&self.subsel) { + cfg.set_payload(VirtioInputAbsInfo::from_absinfo(*absinfo).as_bytes()); + } + } + VIRTIO_INPUT_CFG_UNSET => {} + _ => { + log::warn!("select type {} is not supported", self.select); + } + } + cfg + } +} + +struct InputIoHandler { + /// The features of driver + driver_features: u64, + /// Address space + mem_space: Arc, + /// event queue. + event_queue: Arc>, + /// event queue EventFd + event_queue_evt: Arc, + /// status queue + status_queue: Arc>, + /// status queue EventFd + status_queue_evt: Arc, + /// Used to cache events + event_buf: Vec, + /// Device is broken or not + device_broken: Arc, + /// The interrupt call back function. + interrupt_cb: Arc, + /// fd of the evdev file + evdev_fd: Option>, +} + +impl InputIoHandler { + fn process_status_queue(&mut self) -> Result<()> { + let mut locked_status_queue = self.status_queue.lock().unwrap(); + loop { + let elem = locked_status_queue + .vring + .pop_avail(&self.mem_space, self.driver_features) + .with_context(|| "Failed to pop avail ring for process input status queue")?; + if elem.desc_num == 0 { + break; + } + let evt = iov_read_object::( + &self.mem_space, + &elem.out_iovec, + locked_status_queue.vring.get_cache(), + )? + .to_evt(); + match &self.evdev_fd.clone() { + Some(evdev_fd) => { + let _ = evdev_fd.as_ref().write(evt.as_bytes()); + } + None => {} + } + locked_status_queue + .vring + .add_used(elem.index, 0) + .with_context(|| { + format!( + "Failed to add input response into used status queue, index {}, len {}", + elem.index, 0 + ) + })?; + (self.interrupt_cb)( + &VirtioInterruptType::Vring, + Some(&locked_status_queue), + false, + ) + .with_context(|| VirtioError::InterruptTrigger("Input", VirtioInterruptType::Vring))?; + } + Ok(()) + } + + fn input_event_send(&mut self, evt: &InputEvent) -> Result<()> { + let mut locked_event_queue = self.event_queue.lock().unwrap(); + self.event_buf.push(VirtioInputEvent::from_evt(evt)); + if evt.ev_type != EV_SYN || evt.code != SYN_REPORT { + return Ok(()); + } + let mut event_index_list = Vec::new(); + for event in self.event_buf.iter() { + let elem = locked_event_queue + .vring + .pop_avail(&self.mem_space, self.driver_features) + .with_context(|| "Failed to pop avail ring for process input queue")?; + if elem.desc_num == 0 { + warn!("event queue buffer is full, drop current events"); + for _ in event_index_list.iter() { + locked_event_queue.vring.push_back(); + } + self.event_buf.clear(); + return Ok(()); + } + self.mem_space.write_object( + event, + elem.in_iovec[0].addr, + address_space::AddressAttr::Ram, + )?; + event_index_list.push(elem.index); + } + for index in event_index_list.iter() { + locked_event_queue + .vring + .add_used(*index, size_of::() as u32) + .with_context(|| "Failed to add input response into used queue")?; + } + (self.interrupt_cb)( + &VirtioInterruptType::Vring, + Some(&locked_event_queue), + false, + ) + .with_context(|| VirtioError::InterruptTrigger("input", VirtioInterruptType::Vring))?; + self.event_buf.clear(); + Ok(()) + } + + fn do_event(&mut self) { + let event_fd = &self.evdev_fd.clone().unwrap(); + loop { + let mut evt = InputEvent::default(); + match event_fd.as_ref().read(evt.as_mut_bytes()) { + Ok(sz) => { + if sz != size_of::() { + warn!("mismatch InputEvent length"); + return; + } + if let Err(e) = self.input_event_send(&evt) { + error!("Failed to send event: {:?}", e); + report_virtio_error( + self.interrupt_cb.clone(), + self.driver_features, + &self.device_broken, + ); + return; + } + } + Err(e) => { + error!("Failed to read event from evdev_fd: {:?}", e); + return; + } + } + } + } +} + +/// Create a new EventNotifier. +/// +/// # Arguments +/// +/// * `fd` - Raw file descriptor. +/// * `handler` - Handle function. +fn build_event_notifier(fd: RawFd, handler: Rc) -> EventNotifier { + EventNotifier::new( + NotifierOperation::AddShared, + fd, + None, + EventSet::IN, + vec![handler], + ) +} + +impl EventNotifierHelper for InputIoHandler { + fn internal_notifiers(input: Arc>) -> Vec { + let mut notifiers = Vec::new(); + let locked_input = input.lock().unwrap(); + // register event notifier for event queue. + let handler: Rc = Rc::new(move |_, fd: RawFd| { + read_fd(fd); + // Do nothing. + None + }); + notifiers.push(build_event_notifier( + locked_input.event_queue_evt.as_raw_fd(), + handler, + )); + // register event notifier for status queue. + let local_input = input.clone(); + let handler: Rc = Rc::new(move |_, fd: RawFd| { + read_fd(fd); + let mut locked_local_input = local_input.lock().unwrap(); + if locked_local_input.device_broken.load(Ordering::SeqCst) { + return None; + } + if locked_local_input.process_status_queue().is_err() { + report_virtio_error( + locked_local_input.interrupt_cb.clone(), + locked_local_input.driver_features, + &locked_local_input.device_broken, + ); + }; + None + }); + notifiers.push(build_event_notifier( + locked_input.status_queue_evt.as_raw_fd(), + handler, + )); + + // register evdev fd handler + if let Some(fd) = &locked_input.evdev_fd { + let local_input = input.clone(); + let handler: Rc = Rc::new(move |_, _| { + let mut locked_local_input = local_input.lock().unwrap(); + if locked_local_input.device_broken.load(Ordering::SeqCst) { + // The virtio-input device has broken, drop event + let event_fd = &locked_local_input.evdev_fd.clone().unwrap(); + let mut evt = InputEvent::default(); + let _ = event_fd.as_ref().read(evt.as_mut_bytes()); + return None; + } + locked_local_input.do_event(); + None + }); + notifiers.push(build_event_notifier(fd.as_raw_fd(), handler)); + }; + notifiers + } +} + +pub struct Input { + /// Virtio device base property. + base: VirtioBase, + /// Interrupt callback function. + interrupt_cb: Option>, + /// Input device config data. + evdev_cfg: EvdevConfig, + /// EventFd for device deactivate. + deactivate_evts: Vec, + /// Event file fd. + fd: Option>, +} + +impl Input { + pub fn new(option: InputConfig) -> Result { + let fd = OpenOptions::new() + .read(true) + .write(true) + .custom_flags(libc::O_NONBLOCK) + .open(option.evdev.clone()) + .with_context(|| { + format!( + "Open evdev {} failed({:?})", + option.evdev, + std::io::Error::last_os_error() + ) + })?; + let evdev_cfg = EvdevConfig::new(&fd)?; + Ok(Self { + base: VirtioBase::new(VIRTIO_TYPE_INPUT, QUEUE_NUM_INPUT, DEFAULT_VIRTQUEUE_SIZE), + interrupt_cb: None, + evdev_cfg, + deactivate_evts: Vec::new(), + fd: Some(Arc::new(fd)), + }) + } +} + +impl VirtioDevice for Input { + fn virtio_base(&self) -> &VirtioBase { + &self.base + } + + fn virtio_base_mut(&mut self) -> &mut VirtioBase { + &mut self.base + } + + fn realize(&mut self) -> Result<()> { + self.init_config_features() + } + + fn init_config_features(&mut self) -> Result<()> { + self.base.device_features = 1u64 << VIRTIO_F_VERSION_1; + Ok(()) + } + + fn read_config(&self, offset: u64, data: &mut [u8]) -> Result<()> { + let config = self.evdev_cfg.get_device_config(); + read_config_default(config.as_bytes(), offset, data) + } + + fn write_config(&mut self, offset: u64, data: &[u8]) -> Result<()> { + let mut config = self.evdev_cfg.get_device_config(); + let config_slice = config.as_mut_bytes(); + check_config_space_rw(config_slice, offset, data)?; + config_slice[(offset as usize)..(offset as usize + data.len())].copy_from_slice(data); + + self.evdev_cfg.select = config.select; + self.evdev_cfg.subsel = config.subsel; + Ok(()) + } + + fn activate( + &mut self, + mem_space: Arc, + interrupt_cb: Arc, + queue_evts: Vec>, + ) -> Result<()> { + let queues = &self.base.queues; + if queues.len() != self.queue_num() { + return Err(anyhow!(VirtioError::IncorrectQueueNum( + self.queue_num(), + queues.len() + ))); + } + + let event_queue = queues[0].clone(); + let event_queue_evt = queue_evts[0].clone(); + let status_queue = queues[1].clone(); + let status_queue_evt = queue_evts[1].clone(); + + self.interrupt_cb = Some(interrupt_cb.clone()); + let handler = InputIoHandler { + driver_features: self.base.driver_features, + mem_space, + event_queue, + event_queue_evt, + status_queue, + status_queue_evt, + event_buf: Vec::new(), + device_broken: self.base.broken.clone(), + interrupt_cb: interrupt_cb.clone(), + evdev_fd: self.fd.clone(), + }; + register_event_helper( + EventNotifierHelper::internal_notifiers(Arc::new(Mutex::new(handler))), + None, + &mut self.deactivate_evts, + ) + .with_context(|| "Failed to register input handler to Mainloop")?; + self.base.broken.store(false, Ordering::SeqCst); + Ok(()) + } + + fn deactivate(&mut self) -> Result<()> { + unregister_event_helper(None, &mut self.deactivate_evts) + } + + fn reset(&mut self) -> Result<()> { + Ok(()) + } +} diff --git a/virtio/src/device/mod.rs b/virtio/src/device/mod.rs index 1f9ddba8..f8914b3a 100644 --- a/virtio/src/device/mod.rs +++ b/virtio/src/device/mod.rs @@ -14,6 +14,7 @@ pub mod balloon; pub mod block; #[cfg(feature = "virtio_gpu")] pub mod gpu; +pub mod input; pub mod net; #[cfg(feature = "virtio_rng")] pub mod rng; diff --git a/virtio/src/lib.rs b/virtio/src/lib.rs index 0c8e7673..2b48c9fb 100644 --- a/virtio/src/lib.rs +++ b/virtio/src/lib.rs @@ -36,6 +36,7 @@ pub use device::balloon::*; pub use device::block::{Block, BlockState, VirtioBlkConfig, VirtioBlkDevConfig}; #[cfg(feature = "virtio_gpu")] pub use device::gpu::*; +pub use device::input::*; pub use device::net::*; #[cfg(feature = "virtio_rng")] pub use device::rng::{Rng, RngConfig, RngState}; @@ -83,6 +84,7 @@ pub const VIRTIO_TYPE_RNG: u32 = 4; pub const VIRTIO_TYPE_BALLOON: u32 = 5; pub const VIRTIO_TYPE_SCSI: u32 = 8; pub const VIRTIO_TYPE_GPU: u32 = 16; +pub const VIRTIO_TYPE_INPUT: u32 = 18; pub const VIRTIO_TYPE_VSOCK: u32 = 19; pub const VIRTIO_TYPE_FS: u32 = 26; -- Gitee From af482c3f48aa98dc8263497e7a755e6cdabccaf6 Mon Sep 17 00:00:00 2001 From: Yandong Xu Date: Sat, 15 Mar 2025 19:27:42 +0800 Subject: [PATCH 483/489] virtio/input: add tests case to virtio-input device --- virtio/src/device/input.rs | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/virtio/src/device/input.rs b/virtio/src/device/input.rs index ab4ee8a9..721b4e3d 100644 --- a/virtio/src/device/input.rs +++ b/virtio/src/device/input.rs @@ -595,3 +595,40 @@ impl VirtioDevice for Input { Ok(()) } } + +#[cfg(test)] +mod tests { + use super::*; + use machine_manager::config::str_slip_to_clap; + + #[test] + fn test_input_config_cmdline_parse() { + // Test1: virtio-input-device(mmio). + let input_cmd = "virtio-input-device,id=input0,evdev=/dev/input/event0"; + let input_config = + InputConfig::try_parse_from(str_slip_to_clap(input_cmd, true, false)).unwrap(); + assert_eq!(input_config.multifunction, None); + + // Test2: virtio-input-pci. + let input_cmd = "virtio-input-pci,bus=pcie.0,addr=0x1,id=input0,evdev=/dev/input/event0"; + let input_config = + InputConfig::try_parse_from(str_slip_to_clap(input_cmd, true, false)).unwrap(); + assert_eq!(input_config.bus.unwrap(), "pcie.0"); + assert_eq!(input_config.addr.unwrap(), (1, 0)); + assert_eq!(input_config.evdev, "/dev/input/event0"); + } + + #[test] + fn test_input_init() { + let input_config = InputConfig { + classtype: "virtio-input-pci".to_string(), + id: "input0".to_string(), + evdev: "/evdev/path".to_string(), + bus: Some("pcie.0".to_string()), + addr: Some((3, 0)), + ..Default::default() + }; + let input = Input::new(input_config); + assert!(input.is_err()); + } +} -- Gitee From aa35530dd06c4dda751828de62a66f1e0de1583a Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Mon, 31 Mar 2025 19:27:42 +0800 Subject: [PATCH 484/489] docs: add virtio-input device config Signed-off-by: Fei Xu --- docs/config_guidebook.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/config_guidebook.md b/docs/config_guidebook.md index 29b0e14b..483cf9c4 100644 --- a/docs/config_guidebook.md +++ b/docs/config_guidebook.md @@ -1205,6 +1205,30 @@ Sample Configuration: Please see the [4. Build with features](docs/build_guide.md) if you want to enable pvpanic. +### 2.22 virtio-input +virtio-input is a virtualized input device can be used to create human interface devices such as tablet, mouse. + +Five properties are supported for virtio-input. +* id: unique device id. +* evdev: the path of character evdev device in host. + +For virtio-input-pci, two more properties are required. +* bus: name of bus which to attach. +* addr: including slot number and function number. the first number represents slot number +of device and the second one represents function number of it. As virtio pci input device is a +single function device, the function number should be set to zero. + +Sample Configuration: +```shell +# virtio mmio input device +-device virtio-input-device,id=,evdev= +# virtio pci input device +-device virtio-input-pci,id=,evdev=,bus=,addr=<0x1>[,multifunction=on|off] +``` + +Note: +1. Only host evdev passthrough supported. + ## 3. Trace Users can specify a configuration file which lists the traces that needs to be enabled, or specify the trace type that needs to be enabled. Setting both file and type is also allowed, so that traces with the specified type and traces listed in the file will all be enabled. -- Gitee From f4fed4f7dad0281b67f9b76fa1e4d736a92a2f81 Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Thu, 10 Apr 2025 19:27:42 +0800 Subject: [PATCH 485/489] qcow2: do not merge discard task Call the `fallocate` tasks less time in large block space than multiple consecutive small block space. However, the merging algorithm with O(n^2) complexity leads to excessive merging time in discrete data situations. Block the merging algorithm here first, and consider using other solutions later. Signed-off-by: Fei Xu --- block_backend/src/qcow2/refcount.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/block_backend/src/qcow2/refcount.rs b/block_backend/src/qcow2/refcount.rs index 6e403da5..1c7ff10e 100644 --- a/block_backend/src/qcow2/refcount.rs +++ b/block_backend/src/qcow2/refcount.rs @@ -500,18 +500,8 @@ impl RefCount { /// Add discard task to the list. fn update_discard_list(&mut self, offset: u64, nbytes: u64) -> Result<()> { - let mut discard_task = DiscardTask { offset, nbytes }; - let len = self.discard_list.len(); - let mut discard_list: Vec = Vec::with_capacity(len + 1); - for task in self.discard_list.iter() { - if discard_task.is_overlap(task) { - discard_task.merge_task(task); - } else { - discard_list.push(task.clone()); - } - } - discard_list.push(discard_task); - self.discard_list = discard_list; + let discard_task = DiscardTask { offset, nbytes }; + self.discard_list.push(discard_task); Ok(()) } -- Gitee From efcd0584e07f2675aafb4e40b766105cc980233c Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Thu, 24 Apr 2025 16:21:43 +0800 Subject: [PATCH 486/489] ozonec: Eliminate lint warnings Signed-off-by: Fei Xu --- ozonec/oci_spec/src/state.rs | 4 ++-- ozonec/src/commands/exec.rs | 2 +- ozonec/src/container/launcher.rs | 2 +- ozonec/src/linux/container.rs | 31 ++++++++++++++---------------- ozonec/src/linux/device.rs | 15 +++++++-------- ozonec/src/linux/mount.rs | 32 +++++++++++++++---------------- ozonec/src/linux/notify_socket.rs | 2 +- ozonec/src/linux/process.rs | 7 +++---- ozonec/src/linux/rootfs.rs | 15 ++++++--------- ozonec/src/utils/channel.rs | 2 ++ ozonec/src/utils/logger.rs | 6 +++--- ozonec/src/utils/mod.rs | 3 +-- 12 files changed, 56 insertions(+), 65 deletions(-) diff --git a/ozonec/oci_spec/src/state.rs b/ozonec/oci_spec/src/state.rs index 960e3b0f..105f128e 100644 --- a/ozonec/oci_spec/src/state.rs +++ b/ozonec/oci_spec/src/state.rs @@ -15,7 +15,7 @@ use std::collections::HashMap; use serde::{Deserialize, Serialize}; /// Runtime state of the container. -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Copy, Default)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Copy, Default, Eq)] #[serde(rename_all = "lowercase")] pub enum ContainerStatus { Creating, @@ -38,7 +38,7 @@ impl ToString for ContainerStatus { /// The state of a container. #[allow(non_snake_case)] -#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)] +#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)] pub struct State { /// Version of the Open Container Initiative Runtime Specification /// with which the state complies. diff --git a/ozonec/src/commands/exec.rs b/ozonec/src/commands/exec.rs index ce15f572..9ee4e521 100644 --- a/ozonec/src/commands/exec.rs +++ b/ozonec/src/commands/exec.rs @@ -62,7 +62,7 @@ where { let pos = s .find('=') - .ok_or(anyhow!("Invalid KEY=value: no '=' found in '{}'", s))?; + .ok_or_else(|| anyhow!("Invalid KEY=value: no '=' found in '{}'", s))?; Ok((s[..pos].parse()?, s[pos + 1..].parse()?)) } diff --git a/ozonec/src/container/launcher.rs b/ozonec/src/container/launcher.rs index ef68c392..b9dca85d 100644 --- a/ozonec/src/container/launcher.rs +++ b/ozonec/src/container/launcher.rs @@ -37,7 +37,7 @@ use anyhow::{Context, Result}; use super::{state::State, Container}; use crate::{linux::Process, utils::OzonecErr}; -#[derive(Debug, Clone, Copy, PartialEq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum Action { Create, Start, diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index cb023a48..2b51d21b 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -95,11 +95,11 @@ impl LinuxContainer { } pub fn load_from_state(state: &State, console_socket: &Option) -> Result { - let root_path = format!("{}/{}", state.root.to_string_lossy().to_string(), &state.id); + let root_path = format!("{}/{}", state.root.to_string_lossy(), &state.id); let config = state .config .clone() - .ok_or(anyhow!("Can't find config in state"))?; + .ok_or_else(|| anyhow!("Can't find config in state"))?; Ok(Self { id: state.id.clone(), @@ -145,7 +145,7 @@ impl LinuxContainer { // Spawn a child process to perform the second stage to initialize container. let init_pid = clone_process("ozonec:[2:INIT]", || { - self.do_second_stage(process, parent_channel, ¬ify_listener) + self.do_second_stage(process, parent_channel, notify_listener) .with_context(|| "Second stage process encounters errors")?; Ok(0) })?; @@ -334,14 +334,13 @@ impl LinuxContainer { } fn ns_controller(&self) -> Result { - Ok(self - .config + self.config .linux .as_ref() .unwrap() .namespaces .clone() - .try_into()?) + .try_into() } fn set_user_namespace( @@ -502,19 +501,17 @@ impl LinuxContainer { sethostname(hostname).with_context(|| "Failed to set hostname")?; } if let Some(domainname) = &self.config.domainname { - let errno; - // SAFETY: FFI call with valid arguments. - match unsafe { + let errno = match unsafe { setdomainname( domainname.as_bytes().as_ptr() as *const c_char, domainname.len(), ) } { 0 => return Ok(()), - -1 => errno = nix::Error::last(), - _ => errno = nix::Error::UnknownErrno, - } + -1 => nix::Error::last(), + _ => nix::Error::UnknownErrno, + }; bail!("Failed to set domainname: {}", errno); } } @@ -560,7 +557,7 @@ impl LinuxContainer { } fn write_id_mapping(&self, mappings: &Vec, pid: &Pid, file: &str) -> Result<()> { - let path = format!("/proc/{}/{}", pid.as_raw().to_string(), file); + let path = format!("/proc/{}/{}", pid.as_raw(), file); let mut opened_file = OpenOptions::new() .write(true) .open(&path) @@ -572,14 +569,14 @@ impl LinuxContainer { id_mappings = id_mappings + &mapping; } opened_file - .write_all(&id_mappings.as_bytes()) + .write_all(id_mappings.as_bytes()) .with_context(|| "Failed to write id mappings")?; Ok(()) } fn set_groups(pid: &Pid, allow: bool) -> Result<()> { - let path = format!("/proc/{}/setgroups", pid.as_raw().to_string()); - if allow == true { + let path = format!("/proc/{}/setgroups", pid.as_raw()); + if allow { std::fs::write(&path, "allow")? } else { std::fs::write(&path, "deny")? @@ -626,7 +623,7 @@ impl Container for LinuxContainer { let bundle = match rootfs.parent() { Some(p) => p .to_str() - .ok_or(anyhow!("root path is not valid unicode"))? + .ok_or_else(|| anyhow!("root path is not valid unicode"))? .to_string(), None => bail!("Failed to get bundle directory"), }; diff --git a/ozonec/src/linux/device.rs b/ozonec/src/linux/device.rs index 8ecc568b..c483d2eb 100644 --- a/ozonec/src/linux/device.rs +++ b/ozonec/src/linux/device.rs @@ -94,10 +94,9 @@ impl Device { } fn create_device_dir(&self, path: &PathBuf) -> Result<()> { - let dir = Path::new(path).parent().ok_or(anyhow!( - "Failed to get parent directory: {}", - path.display() - ))?; + let dir = Path::new(path) + .parent() + .ok_or_else(|| anyhow!("Failed to get parent directory: {}", path.display()))?; if !dir.exists() { create_dir_all(dir) .with_context(|| OzonecErr::CreateDir(dir.to_string_lossy().to_string()))?; @@ -122,7 +121,7 @@ impl Device { let binding = dev.path.to_string_lossy().to_string(); let stripped_path = binding .strip_prefix(&self.rootfs.to_string_lossy().to_string()) - .ok_or(anyhow!("Invalid device path"))?; + .ok_or_else(|| anyhow!("Invalid device path"))?; let src_path = PathBuf::from(stripped_path); if !dev.path.exists() { @@ -186,7 +185,7 @@ impl Device { return true; } } - return false; + false } pub fn delete_device(&self, dev: &OciDevice) -> Result<()> { @@ -199,10 +198,10 @@ impl Device { let path = self.rootfs.join(&dev.path.clone()[1..]); let major = dev .major - .ok_or(anyhow!("major not set for device {}", dev.path))?; + .ok_or_else(|| anyhow!("major not set for device {}", dev.path))?; let minor = dev .minor - .ok_or(anyhow!("minor not set for device {}", dev.path))?; + .ok_or_else(|| anyhow!("minor not set for device {}", dev.path))?; let dev_info = DeviceInfo { path, dev_type: dev.dev_type.clone(), diff --git a/ozonec/src/linux/mount.rs b/ozonec/src/linux/mount.rs index af44bd3c..c01aa457 100644 --- a/ozonec/src/linux/mount.rs +++ b/ozonec/src/linux/mount.rs @@ -38,9 +38,9 @@ pub struct Mount { } impl Mount { - pub fn new(rootfs: &PathBuf) -> Self { + pub fn new(rootfs: &Path) -> Self { Self { - rootfs: rootfs.clone(), + rootfs: rootfs.to_path_buf(), } } @@ -114,7 +114,7 @@ impl Mount { let src_binding = mount .source .clone() - .ok_or(anyhow!("Mount source not set"))?; + .ok_or_else(|| anyhow!("Mount source not set"))?; let mut source = Path::new(&src_binding); let canonicalized; // Strip the first "/". @@ -126,10 +126,9 @@ impl Mount { .with_context(|| format!("Failed to canonicalize {}", source.display()))?; source = canonicalized.as_path(); let dir = if source.is_file() { - target.parent().ok_or(anyhow!( - "Failed to get parent directory: {}", - target.display() - ))? + target.parent().ok_or_else(|| { + anyhow!("Failed to get parent directory: {}", target.display()) + })? } else { target }; @@ -139,15 +138,15 @@ impl Mount { fs_type = Some("bind"); } else { // Sysfs doesn't support duplicate mounting to one directory. - if self.is_mounted_sysfs_dir(&target.to_string_lossy().to_string()) { + if self.is_mounted_sysfs_dir(&target.to_string_lossy()) { nix::mount::umount(target) .with_context(|| format!("Failed to umount {}", target.display()))?; } } let target_fd = openat2_in_root( - &Path::new(&self.rootfs), - &Path::new(&mount.destination[1..]), + Path::new(&self.rootfs), + Path::new(&mount.destination[1..]), !source.is_file(), )?; nix::mount::mount( @@ -196,7 +195,7 @@ impl Mount { fn do_cgroup_mount(&self, mount: &OciMount) -> Result<()> { // Strip the first "/". let rel_target = Path::new(&mount.destination[1..]); - let target_fd = openat2_in_root(&Path::new(&self.rootfs), rel_target, true)?; + let target_fd = openat2_in_root(Path::new(&self.rootfs), rel_target, true)?; nix::mount::mount( Some("tmpfs"), &proc_fd_path(target_fd), @@ -225,12 +224,11 @@ impl Mount { for cg_path in host_cgroups { let cg = cg_path .file_name() - .ok_or(anyhow!("Failed to get controller file"))? + .ok_or_else(|| anyhow!("Failed to get controller file"))? .to_str() - .ok_or(anyhow!( - "Convert {:?} to string error", - cg_path.file_name().unwrap() - ))?; + .ok_or_else(|| { + anyhow!("Convert {:?} to string error", cg_path.file_name().unwrap()) + })?; let proc_cg_key = if cg == "systemd" { String::from("systemd") } else { @@ -242,7 +240,7 @@ impl Mount { let rel_target = cg_path .strip_prefix("/") .with_context(|| format!("{} doesn't start with '/'", cg_path.display()))?; - let target_fd = openat2_in_root(&Path::new(&self.rootfs), rel_target, true)?; + let target_fd = openat2_in_root(Path::new(&self.rootfs), rel_target, true)?; nix::mount::mount( Some(&source), diff --git a/ozonec/src/linux/notify_socket.rs b/ozonec/src/linux/notify_socket.rs index 356be384..5db9c57d 100644 --- a/ozonec/src/linux/notify_socket.rs +++ b/ozonec/src/linux/notify_socket.rs @@ -77,7 +77,7 @@ impl NotifySocket { let root_path = self .path .parent() - .ok_or(anyhow!("Invalid notify socket path"))?; + .ok_or_else(|| anyhow!("Invalid notify socket path"))?; chdir(root_path).with_context(|| "Failed to chdir to root directory")?; let mut stream = diff --git a/ozonec/src/linux/process.rs b/ozonec/src/linux/process.rs index 6ce1b911..20bd35d6 100644 --- a/ozonec/src/linux/process.rs +++ b/ozonec/src/linux/process.rs @@ -170,9 +170,8 @@ impl Process { .with_context(|| OzonecErr::GetAllCaps("Bounding".to_string()))?; let caps_hash_set = to_cap_set(bounding)?; for cap in all_caps.difference(&caps_hash_set) { - caps::drop(None, CapSet::Bounding, *cap).with_context(|| { - format!("Failed to drop {} from bonding set", cap.to_string()) - })?; + caps::drop(None, CapSet::Bounding, *cap) + .with_context(|| format!("Failed to drop {} from bonding set", cap))?; } } if let Some(effective) = caps.effective.as_ref() { @@ -363,7 +362,7 @@ fn to_cap_set(caps: &Vec) -> Result { let mut caps_hash_set = CapsHashSet::new(); for c in caps { - let cap = to_cap(&c)?; + let cap = to_cap(c)?; caps_hash_set.insert(cap); } Ok(caps_hash_set) diff --git a/ozonec/src/linux/rootfs.rs b/ozonec/src/linux/rootfs.rs index b7854a3f..48e43366 100644 --- a/ozonec/src/linux/rootfs.rs +++ b/ozonec/src/linux/rootfs.rs @@ -103,17 +103,14 @@ impl Rootfs { let process = Process::myself().with_context(|| OzonecErr::AccessProcSelf)?; let mount_info = process.mountinfo().with_context(|| OzonecErr::GetMntInfo)?; - match mount_info + if let Some(m) = mount_info .into_iter() .filter(|m| self.path.starts_with(&m.mount_point) && m.mount_point != self.path) .map(|m| m.mount_point) .max_by_key(|m| m.len()) .as_ref() { - Some(m) => { - nix::mount::mount(Some(m), m, None::<&str>, MsFlags::MS_PRIVATE, None::<&str>)? - } - None => (), + nix::mount::mount(Some(m), m, None::<&str>, MsFlags::MS_PRIVATE, None::<&str>)?; } Ok(()) } @@ -126,10 +123,10 @@ impl Rootfs { // dev/stderr -> /proc/self/fd/2 fn set_default_symlinks(&self) -> Result<()> { let link_pairs = vec![ - ((&self.path).join("dev/fd"), "/proc/self/fd"), - ((&self.path).join("dev/stdin"), "/proc/self/fd/0"), - ((&self.path).join("dev/stdout"), "/proc/self/fd/1"), - ((&self.path).join("dev/stderr"), "/proc/self/fd/2"), + ((self.path).join("dev/fd"), "/proc/self/fd"), + ((self.path).join("dev/stdin"), "/proc/self/fd/0"), + ((self.path).join("dev/stdout"), "/proc/self/fd/1"), + ((self.path).join("dev/stderr"), "/proc/self/fd/2"), ]; for pair in link_pairs { diff --git a/ozonec/src/utils/channel.rs b/ozonec/src/utils/channel.rs index 41b2b08b..b5d850e3 100644 --- a/ozonec/src/utils/channel.rs +++ b/ozonec/src/utils/channel.rs @@ -59,6 +59,7 @@ where let msg_vec = serde_json::to_vec(&msg).with_context(|| "Failed to load message")?; let msg_len = msg_vec.len() as u64; let iov = [ + // SAFETY: FFI call with valid arguments. IoSlice::new(unsafe { slice::from_raw_parts((&msg_len as *const u64) as *const u8, mem::size_of::()) }), @@ -110,6 +111,7 @@ where let mut buf = vec![0u8; msg_len as usize]; let bytes = { let mut iov = [ + // SAFETY: FFI call with valid arguments. IoSliceMut::new(unsafe { slice::from_raw_parts_mut( (&mut received_len as *mut u64) as *mut u8, diff --git a/ozonec/src/utils/logger.rs b/ozonec/src/utils/logger.rs index 1251de8a..33ecd86b 100644 --- a/ozonec/src/utils/logger.rs +++ b/ozonec/src/utils/logger.rs @@ -99,8 +99,8 @@ fn open_log_file(path: &PathBuf) -> Result { fn formatted_time(seconds: i64) -> [i32; 6] { // SAFETY: an all-zero value is valid for libc::tm. let mut ti: libc::tm = unsafe { std::mem::zeroed() }; + // SAFETY: seconds and ti are both local variables and valid. unsafe { - // SAFETY: seconds and ti are both local variables and valid. libc::localtime_r(&seconds, &mut ti); } [ @@ -118,8 +118,8 @@ fn wall_time() -> (i64, i64) { tv_sec: 0, tv_nsec: 0, }; + // SAFETY: ts is a local variable and valid. unsafe { - // SAFETY: ts is a local variable and valid. libc::clock_gettime(libc::CLOCK_REALTIME, &mut ts); } (ts.tv_sec, ts.tv_nsec) @@ -150,7 +150,7 @@ impl Logger { fn new(path: &Option, level: Level) -> Result { let (log_file, log_size, created_day) = match path { Some(p) => { - let file = Box::new(open_log_file(&p)?); + let file = Box::new(open_log_file(p)?); let metadata = file.metadata().with_context(|| "Failed to get metadata")?; let mod_time = metadata .modified() diff --git a/ozonec/src/utils/mod.rs b/ozonec/src/utils/mod.rs index 59da672a..4e86fc35 100644 --- a/ozonec/src/utils/mod.rs +++ b/ozonec/src/utils/mod.rs @@ -95,9 +95,8 @@ pub fn openat2_in_root(root: &Path, target: &Path, is_dir: bool) -> Result Date: Fri, 9 May 2025 20:11:53 +0800 Subject: [PATCH 487/489] ozonec/linux: Ignore some unit tests Some unit tests are not permitted in some enviroments. Signed-off-by: Fei Xu --- ozonec/src/linux/device.rs | 3 +++ ozonec/src/linux/mount.rs | 1 + 2 files changed, 4 insertions(+) diff --git a/ozonec/src/linux/device.rs b/ozonec/src/linux/device.rs index c483d2eb..f48d87f8 100644 --- a/ozonec/src/linux/device.rs +++ b/ozonec/src/linux/device.rs @@ -248,6 +248,7 @@ mod tests { use super::*; #[test] + #[ignore = "mount may not be permitted"] fn test_mknod_dev() { let rootfs = PathBuf::from("/tmp/ozonec/mknod_dev"); create_dir_all(&rootfs).unwrap(); @@ -332,6 +333,7 @@ mod tests { } #[test] + #[ignore = "mknod may not be permitted"] fn test_create_device() { let oci_dev = OciDevice { dev_type: "c".to_string(), @@ -368,6 +370,7 @@ mod tests { } #[test] + #[ignore = "mount may not be permitted"] fn test_delete_device() { let oci_dev = OciDevice { dev_type: "c".to_string(), diff --git a/ozonec/src/linux/mount.rs b/ozonec/src/linux/mount.rs index c01aa457..7e9d51fd 100644 --- a/ozonec/src/linux/mount.rs +++ b/ozonec/src/linux/mount.rs @@ -298,6 +298,7 @@ mod tests { } #[test] + #[ignore = "mount may not be permitted"] fn test_cgroup_type() { let rootfs = PathBuf::from("/tmp/ozonec/test_cgroup_type"); let mnt = Mount::new(&rootfs); -- Gitee From 12eb8ffad188b49351b72e6159e7f42171734e3c Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Mon, 12 May 2025 11:21:57 +0800 Subject: [PATCH 488/489] ozonec/linux: Fix needless borrow in container.rs Accroding to cargo clippy result, adding `&` to self.config.root.path.clone() is needless, so just remove it. Signed-off-by: Fei Xu --- ozonec/src/linux/container.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ozonec/src/linux/container.rs b/ozonec/src/linux/container.rs index 2b51d21b..776a65e7 100644 --- a/ozonec/src/linux/container.rs +++ b/ozonec/src/linux/container.rs @@ -618,7 +618,7 @@ impl Container for LinuxContainer { 0 }; - let rootfs = canonicalize(&self.config.root.path.clone()) + let rootfs = canonicalize(self.config.root.path.clone()) .with_context(|| "Failed to canonicalize root path")?; let bundle = match rootfs.parent() { Some(p) => p -- Gitee From 912aa25553fab84abf07ebb742f81d2c591982d0 Mon Sep 17 00:00:00 2001 From: Fei Xu Date: Fri, 16 May 2025 10:00:18 +0800 Subject: [PATCH 489/489] xhci: Fix possible stuck According to xHCI Spec 3.2.7/6.4.1/4.9.1, zero-length packet is required when exact multiple of max packet size is transferred, it is essential for proper stream termination in bulk/interrupt transfers, skip TRB submission for zero-byte transfers may end up in Device hanging, waiting for status phase completion. zero-length packet usually comes with the default address 0. In this case, the correct way to handle it is to skip the address translation and leave the iovec empty. Signed-off-by: Fei Xu --- devices/src/usb/xhci/xhci_controller.rs | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/devices/src/usb/xhci/xhci_controller.rs b/devices/src/usb/xhci/xhci_controller.rs index 5991f234..e437283b 100644 --- a/devices/src/usb/xhci/xhci_controller.rs +++ b/devices/src/usb/xhci/xhci_controller.rs @@ -2200,9 +2200,21 @@ impl XhciDevice { || trb_type == TRBType::TrNormal || trb_type == TRBType::TrIsoch { - let chunk = trb.status & TRB_TR_LEN_MASK; + let trb_len = trb.status & TRB_TR_LEN_MASK; + + // According to xHCI Spec 3.2.7/6.4.1/4.9.1, zero-length packet is required + // when exact multiple of max packet size is transferred, it is essential + // for proper stream termination in bulk/interrupt transfers, skip TRB + // submission for zero-byte transfers may end up in Device hanging, waiting + // for status phase completion. zero-length packet usually comes with the + // default address 0. In this case, the correct way to handle it is to skip + // the address translation and leave the iovec empty. + if trb_len == 0 { + continue; + } + let dma_addr = if trb.control & TRB_TR_IDT == TRB_TR_IDT { - if chunk > 8 && locked_xfer.in_xfer { + if trb_len > 8 && locked_xfer.in_xfer { bail!("Invalid immediate data TRB"); } trb.addr @@ -2213,7 +2225,7 @@ impl XhciDevice { self.mem_space.get_address_map( &None, GuestAddress(dma_addr), - u64::from(chunk), + u64::from(trb_len), &mut vec, )?; } -- Gitee