Skip to content

Commit 2570915

Browse files
committed
feat: updated BlockDeviceConfig with vhost-user-block parameters
Updated `BlockDeviceConfig` with vhost-user-block specific field. Updated methods to convert `BlockDeviceConfig` into `VirtIOBlockConfig` or `VhostUserBlockConfig`. Updated integration tests with new ordering of fields in the `BlockDeviceConfig`. Signed-off-by: Egor Lazarchuk <[email protected]>
1 parent 6f9c738 commit 2570915

File tree

13 files changed

+439
-216
lines changed

13 files changed

+439
-216
lines changed

src/vmm/src/builder.rs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1122,24 +1122,31 @@ pub mod tests {
11221122
) -> Vec<TempFile> {
11231123
let mut block_dev_configs = BlockBuilder::new();
11241124
let mut block_files = Vec::new();
1125-
for custom_block_cfg in &custom_block_cfgs {
1125+
for custom_block_cfg in custom_block_cfgs {
11261126
block_files.push(TempFile::new().unwrap());
1127+
11271128
let block_device_config = BlockDeviceConfig {
11281129
drive_id: String::from(&custom_block_cfg.drive_id),
1129-
path_on_host: block_files
1130-
.last()
1131-
.unwrap()
1132-
.as_path()
1133-
.to_str()
1134-
.unwrap()
1135-
.to_string(),
1130+
partuuid: custom_block_cfg.partuuid,
11361131
is_root_device: custom_block_cfg.is_root_device,
1137-
partuuid: custom_block_cfg.partuuid.clone(),
1138-
is_read_only: custom_block_cfg.is_read_only,
11391132
cache_type: custom_block_cfg.cache_type,
1133+
1134+
is_read_only: Some(custom_block_cfg.is_read_only),
1135+
path_on_host: Some(
1136+
block_files
1137+
.last()
1138+
.unwrap()
1139+
.as_path()
1140+
.to_str()
1141+
.unwrap()
1142+
.to_string(),
1143+
),
11401144
rate_limiter: None,
11411145
file_engine_type: FileEngineType::default(),
1146+
1147+
socket: None,
11421148
};
1149+
11431150
block_dev_configs.insert(block_device_config).unwrap();
11441151
}
11451152

src/vmm/src/device_manager/persist.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -869,13 +869,14 @@ mod tests {
869869
"drives": [
870870
{{
871871
"drive_id": "root",
872-
"path_on_host": "{}",
873-
"is_root_device": true,
874872
"partuuid": null,
875-
"is_read_only": true,
873+
"is_root_device": true,
876874
"cache_type": "Unsafe",
875+
"is_read_only": true,
876+
"path_on_host": "{}",
877877
"rate_limiter": null,
878-
"io_engine": "Sync"
878+
"io_engine": "Sync",
879+
"socket": null
879880
}}
880881
],
881882
"boot-source": {{

src/vmm/src/devices/virtio/block/device.rs

Lines changed: 84 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -53,20 +53,15 @@ pub enum CacheType {
5353
}
5454

5555
/// The engine file type, either Sync or Async (through io_uring).
56-
#[derive(Debug, PartialEq, Eq, Deserialize, Serialize)]
56+
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
5757
pub enum FileEngineType {
5858
/// Use an Async engine, based on io_uring.
5959
Async,
6060
/// Use a Sync engine, based on blocking system calls.
61+
#[default]
6162
Sync,
6263
}
6364

64-
impl Default for FileEngineType {
65-
fn default() -> Self {
66-
Self::Sync
67-
}
68-
}
69-
7065
impl FileEngineType {
7166
/// Whether the Async engine is supported on the current host kernel.
7267
pub fn is_supported(&self) -> Result<bool, utils::kernel_version::Error> {
@@ -203,22 +198,23 @@ impl DiskProperties {
203198
pub struct VirtioBlockConfig {
204199
/// Unique identifier of the drive.
205200
pub drive_id: String,
206-
/// Path of the backing file on the host
207-
pub path_on_host: String,
201+
/// Part-UUID. Represents the unique id of the boot partition of this device. It is
202+
/// optional and it will be used only if the `is_root_device` field is true.
203+
pub partuuid: Option<String>,
208204
/// If set to true, it makes the current device the root block device.
209205
/// Setting this flag to true will mount the block device in the
210206
/// guest under /dev/vda unless the partuuid is present.
211207
pub is_root_device: bool,
212-
/// Part-UUID. Represents the unique id of the boot partition of this device. It is
213-
/// optional and it will be used only if the `is_root_device` field is true.
214-
pub partuuid: Option<String>,
215-
/// If set to true, the drive is opened in read-only mode. Otherwise, the
216-
/// drive is opened as read-write.
217-
pub is_read_only: bool,
218208
/// If set to true, the drive will ignore flush requests coming from
219209
/// the guest driver.
220210
#[serde(default)]
221211
pub cache_type: CacheType,
212+
213+
/// If set to true, the drive is opened in read-only mode. Otherwise, the
214+
/// drive is opened as read-write.
215+
pub is_read_only: bool,
216+
/// Path of the backing file on the host
217+
pub path_on_host: String,
222218
/// Rate Limiter for I/O operations.
223219
pub rate_limiter: Option<RateLimiterConfig>,
224220
/// The type of IO engine used by the device.
@@ -227,17 +223,24 @@ pub struct VirtioBlockConfig {
227223
pub file_engine_type: FileEngineType,
228224
}
229225

230-
impl From<BlockDeviceConfig> for VirtioBlockConfig {
231-
fn from(value: BlockDeviceConfig) -> Self {
232-
Self {
233-
drive_id: value.drive_id,
234-
path_on_host: value.path_on_host,
235-
is_root_device: value.is_root_device,
236-
partuuid: value.partuuid,
237-
is_read_only: value.is_read_only,
238-
cache_type: value.cache_type,
239-
rate_limiter: value.rate_limiter,
240-
file_engine_type: value.file_engine_type,
226+
impl TryFrom<&BlockDeviceConfig> for VirtioBlockConfig {
227+
type Error = VirtioBlockError;
228+
229+
fn try_from(value: &BlockDeviceConfig) -> Result<Self, Self::Error> {
230+
if value.path_on_host.is_some() && value.socket.is_none() {
231+
Ok(Self {
232+
drive_id: value.drive_id.clone(),
233+
partuuid: value.partuuid.clone(),
234+
is_root_device: value.is_root_device,
235+
cache_type: value.cache_type,
236+
237+
is_read_only: value.is_read_only.unwrap_or(false),
238+
path_on_host: value.path_on_host.as_ref().unwrap().clone(),
239+
rate_limiter: value.rate_limiter,
240+
file_engine_type: value.file_engine_type,
241+
})
242+
} else {
243+
Err(VirtioBlockError::Config)
241244
}
242245
}
243246
}
@@ -246,13 +249,16 @@ impl From<VirtioBlockConfig> for BlockDeviceConfig {
246249
fn from(value: VirtioBlockConfig) -> Self {
247250
Self {
248251
drive_id: value.drive_id,
249-
path_on_host: value.path_on_host,
250-
is_root_device: value.is_root_device,
251252
partuuid: value.partuuid,
252-
is_read_only: value.is_read_only,
253+
is_root_device: value.is_root_device,
253254
cache_type: value.cache_type,
255+
256+
is_read_only: Some(value.is_read_only),
257+
path_on_host: Some(value.path_on_host),
254258
rate_limiter: value.rate_limiter,
255259
file_engine_type: value.file_engine_type,
260+
261+
socket: None,
256262
}
257263
}
258264
}
@@ -363,7 +369,7 @@ impl VirtioBlock {
363369
}
364370
}
365371

366-
/// Process a single event in the VirtIO queue.
372+
/// Process a single event in the Virtio queue.
367373
///
368374
/// This function is called by the event manager when the guest notifies us
369375
/// about new buffers in the queue.
@@ -747,6 +753,54 @@ mod tests {
747753
use crate::rate_limiter::TokenType;
748754
use crate::vstate::memory::{Address, Bytes, GuestAddress};
749755

756+
#[test]
757+
fn test_from_config() {
758+
let block_config = BlockDeviceConfig {
759+
drive_id: "".to_string(),
760+
partuuid: None,
761+
is_root_device: false,
762+
cache_type: CacheType::Unsafe,
763+
764+
is_read_only: Some(true),
765+
path_on_host: Some("path".to_string()),
766+
rate_limiter: None,
767+
file_engine_type: Default::default(),
768+
769+
socket: None,
770+
};
771+
assert!(VirtioBlockConfig::try_from(&block_config).is_ok());
772+
773+
let block_config = BlockDeviceConfig {
774+
drive_id: "".to_string(),
775+
partuuid: None,
776+
is_root_device: false,
777+
cache_type: CacheType::Unsafe,
778+
779+
is_read_only: None,
780+
path_on_host: None,
781+
rate_limiter: None,
782+
file_engine_type: Default::default(),
783+
784+
socket: Some("sock".to_string()),
785+
};
786+
assert!(VirtioBlockConfig::try_from(&block_config).is_err());
787+
788+
let block_config = BlockDeviceConfig {
789+
drive_id: "".to_string(),
790+
partuuid: None,
791+
is_root_device: false,
792+
cache_type: CacheType::Unsafe,
793+
794+
is_read_only: Some(true),
795+
path_on_host: Some("path".to_string()),
796+
rate_limiter: None,
797+
file_engine_type: Default::default(),
798+
799+
socket: Some("sock".to_string()),
800+
};
801+
assert!(VirtioBlockConfig::try_from(&block_config).is_err());
802+
}
803+
750804
#[test]
751805
fn test_disk_backing_file_helper() {
752806
let num_sectors = 2;

src/vmm/src/devices/virtio/block/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ pub const IO_URING_NUM_ENTRIES: u16 = 128;
3535
/// Errors the block device can trigger.
3636
#[derive(Debug)]
3737
pub enum VirtioBlockError {
38+
/// Can not create config
39+
Config,
3840
/// Guest gave us too few descriptors in a descriptor chain.
3941
DescriptorChainTooShort,
4042
/// Guest gave us a descriptor that was too short to use.

src/vmm/src/devices/virtio/vhost_user_block/device.rs

Lines changed: 80 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@ use vhost::vhost_user::message::*;
1616
use vhost::vhost_user::VhostUserFrontend;
1717

1818
use super::{VhostUserBlockError, NUM_QUEUES, QUEUE_SIZE};
19-
use crate::devices::virtio::block::device::FileEngineType;
2019
use crate::devices::virtio::gen::virtio_blk::{
2120
VIRTIO_BLK_F_FLUSH, VIRTIO_BLK_F_RO, VIRTIO_F_VERSION_1,
2221
};
@@ -47,18 +46,30 @@ pub struct VhostUserBlockConfig {
4746
/// If set to true, the drive will ignore flush requests coming from
4847
/// the guest driver.
4948
pub cache_type: CacheType,
49+
5050
/// Socket path of the vhost-user process
5151
pub socket: String,
5252
}
5353

54-
impl From<BlockDeviceConfig> for VhostUserBlockConfig {
55-
fn from(value: BlockDeviceConfig) -> Self {
56-
Self {
57-
drive_id: value.drive_id,
58-
is_root_device: value.is_root_device,
59-
partuuid: value.partuuid,
60-
cache_type: value.cache_type,
61-
socket: Default::default(),
54+
impl TryFrom<&BlockDeviceConfig> for VhostUserBlockConfig {
55+
type Error = VhostUserBlockError;
56+
57+
fn try_from(value: &BlockDeviceConfig) -> Result<Self, Self::Error> {
58+
if value.socket.is_some()
59+
&& value.is_read_only.is_none()
60+
&& value.path_on_host.is_none()
61+
&& value.rate_limiter.is_none()
62+
{
63+
Ok(Self {
64+
drive_id: value.drive_id.clone(),
65+
partuuid: value.partuuid.clone(),
66+
is_root_device: value.is_root_device,
67+
cache_type: value.cache_type,
68+
69+
socket: value.socket.as_ref().unwrap().clone(),
70+
})
71+
} else {
72+
Err(VhostUserBlockError::Config)
6273
}
6374
}
6475
}
@@ -67,13 +78,16 @@ impl From<VhostUserBlockConfig> for BlockDeviceConfig {
6778
fn from(value: VhostUserBlockConfig) -> Self {
6879
Self {
6980
drive_id: value.drive_id,
70-
path_on_host: Default::default(),
71-
is_root_device: value.is_root_device,
7281
partuuid: value.partuuid,
73-
is_read_only: false,
82+
is_root_device: value.is_root_device,
7483
cache_type: value.cache_type,
84+
85+
is_read_only: None,
86+
path_on_host: None,
7587
rate_limiter: None,
76-
file_engine_type: FileEngineType::default(),
88+
file_engine_type: Default::default(),
89+
90+
socket: Some(value.socket),
7791
}
7892
}
7993
}
@@ -280,3 +294,56 @@ impl VirtioDevice for VhostUserBlock {
280294
self.device_state.is_activated()
281295
}
282296
}
297+
298+
#[cfg(test)]
299+
mod tests {
300+
use super::*;
301+
302+
#[test]
303+
fn test_from_config() {
304+
let block_config = BlockDeviceConfig {
305+
drive_id: "".to_string(),
306+
partuuid: None,
307+
is_root_device: false,
308+
cache_type: CacheType::Unsafe,
309+
310+
is_read_only: None,
311+
path_on_host: None,
312+
rate_limiter: None,
313+
file_engine_type: Default::default(),
314+
315+
socket: Some("sock".to_string()),
316+
};
317+
assert!(VhostUserBlockConfig::try_from(&block_config).is_ok());
318+
319+
let block_config = BlockDeviceConfig {
320+
drive_id: "".to_string(),
321+
partuuid: None,
322+
is_root_device: false,
323+
cache_type: CacheType::Unsafe,
324+
325+
is_read_only: Some(true),
326+
path_on_host: Some("path".to_string()),
327+
rate_limiter: None,
328+
file_engine_type: Default::default(),
329+
330+
socket: None,
331+
};
332+
assert!(VhostUserBlockConfig::try_from(&block_config).is_err());
333+
334+
let block_config = BlockDeviceConfig {
335+
drive_id: "".to_string(),
336+
partuuid: None,
337+
is_root_device: false,
338+
cache_type: CacheType::Unsafe,
339+
340+
is_read_only: Some(true),
341+
path_on_host: Some("path".to_string()),
342+
rate_limiter: None,
343+
file_engine_type: Default::default(),
344+
345+
socket: Some("sock".to_string()),
346+
};
347+
assert!(VhostUserBlockConfig::try_from(&block_config).is_err());
348+
}
349+
}

src/vmm/src/devices/virtio/vhost_user_block/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ pub const QUEUE_SIZE: u16 = 256;
1717
/// Vhost-user block device error.
1818
#[derive(Debug, displaydoc::Display)]
1919
pub enum VhostUserBlockError {
20+
/// Cannot create config
21+
Config,
2022
/// Persistence error: {0:?}
2123
Persist(crate::devices::virtio::persist::PersistError),
2224
/// Vhost-user error: {0}

0 commit comments

Comments
 (0)