Skip to content

Commit fa45174

Browse files
ShadowCursekalyazin
andcommitted
refactor(vmm): introduce block device enum
In order to allow creation of other block device subtypes, we wrap former Block structure into an enum. At the moment it contains a single variant `VirtioBlock`. Further on it will be extended with other device subtypes. Signed-off-by: Egor Lazarchuk <[email protected]> Co-authored-by: Nikita Kalyazin <[email protected]>
1 parent 94bfd54 commit fa45174

File tree

3 files changed

+131
-83
lines changed

3 files changed

+131
-83
lines changed

src/vmm/src/builder.rs

Lines changed: 32 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ use crate::devices::legacy::serial::SerialOut;
4444
use crate::devices::legacy::RTCDevice;
4545
use crate::devices::legacy::{EventFdTrigger, SerialEventsWrapper, SerialWrapper};
4646
use crate::devices::virtio::{
47-
Balloon, Entropy, MmioTransport, Net, VirtioBlock, VirtioDevice, Vsock, VsockUnixBackend,
47+
Balloon, Entropy, MmioTransport, Net, VirtioDevice, Vsock, VsockUnixBackend,
4848
};
4949
use crate::devices::BusDevice;
5050
#[cfg(target_arch = "aarch64")]
@@ -53,6 +53,7 @@ use crate::logger::error;
5353
use crate::persist::{MicrovmState, MicrovmStateError};
5454
use crate::resources::VmResources;
5555
use crate::vmm_config::boot_source::BootConfig;
56+
use crate::vmm_config::drive::BlockDeviceType;
5657
use crate::vmm_config::instance_info::InstanceInfo;
5758
use crate::vmm_config::machine_config::{MachineConfigUpdate, VmConfig, VmConfigError};
5859
use crate::vstate::memory::{
@@ -303,7 +304,7 @@ pub fn build_microvm_for_boot(
303304
attach_block_devices(
304305
&mut vmm,
305306
&mut boot_cmdline,
306-
vm_resources.block.list.iter(),
307+
vm_resources.block.devices.iter(),
307308
event_manager,
308309
)?;
309310
attach_net_devices(
@@ -874,30 +875,35 @@ fn attach_entropy_device(
874875
attach_virtio_device(event_manager, vmm, id, entropy_device.clone(), cmdline)
875876
}
876877

877-
fn attach_block_devices<'a, I: Iterator<Item = &'a Arc<Mutex<VirtioBlock>>> + Debug>(
878+
fn attach_block_devices<'a, I: Iterator<Item = &'a BlockDeviceType> + Debug>(
878879
vmm: &mut Vmm,
879880
cmdline: &mut LoaderKernelCmdline,
880881
blocks: I,
881882
event_manager: &mut EventManager,
882883
) -> Result<(), StartMicrovmError> {
883884
for block in blocks {
884-
let id = {
885-
let locked = block.lock().expect("Poisoned lock");
886-
if locked.is_root_device() {
887-
cmdline.insert_str(if let Some(partuuid) = locked.partuuid() {
888-
format!("root=PARTUUID={}", partuuid)
889-
} else {
890-
// If no PARTUUID was specified for the root device, try with the /dev/vda.
891-
"root=/dev/vda".to_string()
892-
})?;
893-
894-
let flags = if locked.is_read_only() { "ro" } else { "rw" };
895-
cmdline.insert_str(flags)?;
885+
match block {
886+
BlockDeviceType::VirtioBlock(block) => {
887+
let id = {
888+
let locked = block.lock().expect("Poisoned lock");
889+
if locked.is_root_device() {
890+
cmdline.insert_str(if let Some(partuuid) = locked.partuuid() {
891+
format!("root=PARTUUID={}", partuuid)
892+
} else {
893+
// If no PARTUUID was specified for the root device, try with the
894+
// /dev/vda.
895+
"root=/dev/vda".to_string()
896+
})?;
897+
898+
let flags = if locked.is_read_only() { "ro" } else { "rw" };
899+
cmdline.insert_str(flags)?;
900+
}
901+
locked.id().clone()
902+
};
903+
// The device mutex mustn't be locked here otherwise it will deadlock.
904+
attach_virtio_device(event_manager, vmm, id, block.clone(), cmdline)?;
896905
}
897-
locked.id().clone()
898-
};
899-
// The device mutex mustn't be locked here otherwise it will deadlock.
900-
attach_virtio_device(event_manager, vmm, id, block.clone(), cmdline)?;
906+
}
901907
}
902908
Ok(())
903909
}
@@ -1117,7 +1123,13 @@ pub mod tests {
11171123
block_dev_configs.insert(block_device_config).unwrap();
11181124
}
11191125

1120-
attach_block_devices(vmm, cmdline, block_dev_configs.list.iter(), event_manager).unwrap();
1126+
attach_block_devices(
1127+
vmm,
1128+
cmdline,
1129+
block_dev_configs.devices.iter(),
1130+
event_manager,
1131+
)
1132+
.unwrap();
11211133
block_files
11221134
}
11231135

src/vmm/src/resources.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1499,9 +1499,9 @@ mod tests {
14991499
let tmp_file = TempFile::new().unwrap();
15001500
new_block_device_cfg.drive_id = "block2".to_string();
15011501
new_block_device_cfg.path_on_host = tmp_file.as_path().to_str().unwrap().to_string();
1502-
assert_eq!(vm_resources.block.list.len(), 1);
1502+
assert_eq!(vm_resources.block.devices.len(), 1);
15031503
vm_resources.set_block_device(new_block_device_cfg).unwrap();
1504-
assert_eq!(vm_resources.block.list.len(), 2);
1504+
assert_eq!(vm_resources.block.devices.len(), 2);
15051505
}
15061506

15071507
#[test]

src/vmm/src/vmm_config/drive.rs

Lines changed: 97 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,13 @@ pub struct BlockDeviceUpdateConfig {
7272
pub rate_limiter: Option<RateLimiterConfig>,
7373
}
7474

75+
/// Enum with all possible block device types.
76+
#[derive(Debug)]
77+
pub enum BlockDeviceType {
78+
/// VirtioBlock type
79+
VirtioBlock(Arc<Mutex<VirtioBlock>>),
80+
}
81+
7582
/// Wrapper for the collection that holds all the Block Devices
7683
#[derive(Debug, Default)]
7784
pub struct BlockBuilder {
@@ -80,40 +87,46 @@ pub struct BlockBuilder {
8087
// Root Device should be the first in the list whether or not PARTUUID is
8188
// specified in order to avoid bugs in case of switching from partuuid boot
8289
// scenarios to /dev/vda boot type.
83-
pub list: VecDeque<Arc<Mutex<VirtioBlock>>>,
90+
pub devices: VecDeque<BlockDeviceType>,
8491
}
8592

8693
impl BlockBuilder {
8794
/// Constructor for BlockDevices. It initializes an empty LinkedList.
8895
pub fn new() -> Self {
8996
Self {
90-
list: VecDeque::<Arc<Mutex<VirtioBlock>>>::new(),
97+
devices: Default::default(),
9198
}
9299
}
93100

94101
/// Specifies whether there is a root block device already present in the list.
95102
fn has_root_device(&self) -> bool {
96103
// If there is a root device, it would be at the top of the list.
97-
if let Some(block) = self.list.get(0) {
98-
block.lock().expect("Poisoned lock").is_root_device()
104+
if let Some(block) = self.devices.get(0) {
105+
match block {
106+
BlockDeviceType::VirtioBlock(b) => {
107+
b.lock().expect("Poisoned lock").is_root_device()
108+
}
109+
}
99110
} else {
100111
false
101112
}
102113
}
103114

104115
/// Gets the index of the device with the specified `drive_id` if it exists in the list.
105116
fn get_index_of_drive_id(&self, drive_id: &str) -> Option<usize> {
106-
self.list
107-
.iter()
108-
.position(|b| b.lock().expect("Poisoned lock").id().eq(drive_id))
117+
self.devices.iter().position(|b| match b {
118+
BlockDeviceType::VirtioBlock(b) => b.lock().expect("Poisoned lock").id().eq(drive_id),
119+
})
109120
}
110121

111122
/// Inserts an existing block device.
112123
pub fn add_device(&mut self, block_device: Arc<Mutex<VirtioBlock>>) {
113124
if block_device.lock().expect("Poisoned lock").is_root_device() {
114-
self.list.push_front(block_device);
125+
self.devices
126+
.push_front(BlockDeviceType::VirtioBlock(block_device));
115127
} else {
116-
self.list.push_back(block_device);
128+
self.devices
129+
.push_back(BlockDeviceType::VirtioBlock(block_device));
117130
}
118131
}
119132

@@ -139,19 +152,21 @@ impl BlockBuilder {
139152
// New block device.
140153
None => {
141154
if is_root_device {
142-
self.list.push_front(block_dev);
155+
self.devices
156+
.push_front(BlockDeviceType::VirtioBlock(block_dev));
143157
} else {
144-
self.list.push_back(block_dev);
158+
self.devices
159+
.push_back(BlockDeviceType::VirtioBlock(block_dev));
145160
}
146161
}
147162
// Update existing block device.
148163
Some(index) => {
149164
// Update the slot with the new block.
150-
self.list[index] = block_dev;
165+
self.devices[index] = BlockDeviceType::VirtioBlock(block_dev);
151166
// Check if the root block device is being updated.
152167
if index != 0 && is_root_device {
153168
// Make sure the root device is on the first position.
154-
self.list.swap(0, index);
169+
self.devices.swap(0, index);
155170
}
156171
}
157172
}
@@ -160,9 +175,11 @@ impl BlockBuilder {
160175

161176
/// Returns a vec with the structures used to configure the devices.
162177
pub fn configs(&self) -> Vec<BlockDeviceConfig> {
163-
self.list
178+
self.devices
164179
.iter()
165-
.map(|block| block.lock().unwrap().config().into())
180+
.map(|b| match b {
181+
BlockDeviceType::VirtioBlock(b) => b.lock().unwrap().config().into(),
182+
})
166183
.collect()
167184
}
168185
}
@@ -200,7 +217,7 @@ mod tests {
200217
#[test]
201218
fn test_create_block_devs() {
202219
let block_devs = BlockBuilder::new();
203-
assert_eq!(block_devs.list.len(), 0);
220+
assert_eq!(block_devs.devices.len(), 0);
204221
}
205222

206223
#[test]
@@ -223,13 +240,17 @@ mod tests {
223240
assert!(block_devs.insert(dummy_block_device.clone()).is_ok());
224241

225242
assert!(!block_devs.has_root_device());
226-
assert_eq!(block_devs.list.len(), 1);
243+
assert_eq!(block_devs.devices.len(), 1);
227244

228245
{
229-
let block = block_devs.list[0].lock().unwrap();
230-
assert_eq!(block.id(), &dummy_block_device.drive_id);
231-
assert_eq!(block.partuuid(), dummy_block_device.partuuid.as_ref());
232-
assert_eq!(block.is_read_only(), dummy_block_device.is_read_only);
246+
match block_devs.devices[0] {
247+
BlockDeviceType::VirtioBlock(ref b) => {
248+
let block = b.lock().unwrap();
249+
assert_eq!(block.id(), &dummy_block_device.drive_id);
250+
assert_eq!(block.partuuid(), dummy_block_device.partuuid.as_ref());
251+
assert_eq!(block.is_read_only(), dummy_block_device.is_read_only);
252+
}
253+
}
233254
}
234255
assert_eq!(block_devs.get_index_of_drive_id(&dummy_id), Some(0));
235256
}
@@ -254,12 +275,16 @@ mod tests {
254275
assert!(block_devs.insert(dummy_block_device.clone()).is_ok());
255276

256277
assert!(block_devs.has_root_device());
257-
assert_eq!(block_devs.list.len(), 1);
278+
assert_eq!(block_devs.devices.len(), 1);
258279
{
259-
let block = block_devs.list[0].lock().unwrap();
260-
assert_eq!(block.id(), &dummy_block_device.drive_id);
261-
assert_eq!(block.partuuid(), dummy_block_device.partuuid.as_ref());
262-
assert_eq!(block.is_read_only(), dummy_block_device.is_read_only);
280+
match block_devs.devices[0] {
281+
BlockDeviceType::VirtioBlock(ref b) => {
282+
let block = b.lock().unwrap();
283+
assert_eq!(block.id(), &dummy_block_device.drive_id);
284+
assert_eq!(block.partuuid(), dummy_block_device.partuuid.as_ref());
285+
assert_eq!(block.is_read_only(), dummy_block_device.is_read_only);
286+
}
287+
}
263288
}
264289
}
265290

@@ -346,21 +371,24 @@ mod tests {
346371
assert!(block_devs.insert(dummy_block_dev_3.clone()).is_ok());
347372
assert!(block_devs.insert(root_block_device.clone()).is_ok());
348373

349-
assert_eq!(block_devs.list.len(), 3);
374+
assert_eq!(block_devs.devices.len(), 3);
350375

351-
let mut block_iter = block_devs.list.iter();
352-
assert_eq!(
353-
block_iter.next().unwrap().lock().unwrap().id(),
354-
&root_block_device.drive_id
355-
);
356-
assert_eq!(
357-
block_iter.next().unwrap().lock().unwrap().id(),
358-
&dummy_block_dev_2.drive_id
359-
);
360-
assert_eq!(
361-
block_iter.next().unwrap().lock().unwrap().id(),
362-
&dummy_block_dev_3.drive_id
363-
);
376+
let mut block_iter = block_devs.devices.iter();
377+
match block_iter.next().unwrap() {
378+
BlockDeviceType::VirtioBlock(ref b) => {
379+
assert_eq!(b.lock().unwrap().id(), &root_block_device.drive_id)
380+
}
381+
}
382+
match block_iter.next().unwrap() {
383+
BlockDeviceType::VirtioBlock(ref b) => {
384+
assert_eq!(b.lock().unwrap().id(), &dummy_block_dev_2.drive_id)
385+
}
386+
}
387+
match block_iter.next().unwrap() {
388+
BlockDeviceType::VirtioBlock(ref b) => {
389+
assert_eq!(b.lock().unwrap().id(), &dummy_block_dev_3.drive_id)
390+
}
391+
}
364392
}
365393

366394
#[test]
@@ -410,23 +438,26 @@ mod tests {
410438
assert!(block_devs.insert(dummy_block_dev_3.clone()).is_ok());
411439
assert!(block_devs.insert(root_block_device.clone()).is_ok());
412440

413-
assert_eq!(block_devs.list.len(), 3);
441+
assert_eq!(block_devs.devices.len(), 3);
414442

415-
let mut block_iter = block_devs.list.iter();
443+
let mut block_iter = block_devs.devices.iter();
416444
// The root device should be first in the list no matter of the order in
417445
// which the devices were added.
418-
assert_eq!(
419-
block_iter.next().unwrap().lock().unwrap().id(),
420-
&root_block_device.drive_id
421-
);
422-
assert_eq!(
423-
block_iter.next().unwrap().lock().unwrap().id(),
424-
&dummy_block_dev_2.drive_id
425-
);
426-
assert_eq!(
427-
block_iter.next().unwrap().lock().unwrap().id(),
428-
&dummy_block_dev_3.drive_id
429-
);
446+
match block_iter.next().unwrap() {
447+
BlockDeviceType::VirtioBlock(ref b) => {
448+
assert_eq!(b.lock().unwrap().id(), &root_block_device.drive_id)
449+
}
450+
}
451+
match block_iter.next().unwrap() {
452+
BlockDeviceType::VirtioBlock(ref b) => {
453+
assert_eq!(b.lock().unwrap().id(), &dummy_block_dev_2.drive_id)
454+
}
455+
}
456+
match block_iter.next().unwrap() {
457+
BlockDeviceType::VirtioBlock(ref b) => {
458+
assert_eq!(b.lock().unwrap().id(), &dummy_block_dev_3.drive_id)
459+
}
460+
}
430461
}
431462

432463
#[test]
@@ -487,7 +518,9 @@ mod tests {
487518
.get_index_of_drive_id(&dummy_block_device_2.drive_id)
488519
.unwrap();
489520
// Validate update was successful.
490-
assert!(block_devs.list[index].lock().unwrap().is_read_only());
521+
match block_devs.devices[index] {
522+
BlockDeviceType::VirtioBlock(ref b) => assert!(b.lock().unwrap().is_read_only()),
523+
}
491524

492525
// Update with invalid path.
493526
let dummy_path_3 = String::from("test_update_3");
@@ -535,7 +568,11 @@ mod tests {
535568
assert!(block_devs.insert(root_block_device_new).is_ok());
536569
assert!(block_devs.has_root_device());
537570
// Verify it's been moved to the first position.
538-
assert_eq!(block_devs.list[0].lock().unwrap().id(), &root_block_id);
571+
match block_devs.devices[0] {
572+
BlockDeviceType::VirtioBlock(ref b) => {
573+
assert_eq!(b.lock().unwrap().id(), &root_block_id)
574+
}
575+
}
539576
}
540577

541578
#[test]
@@ -581,10 +618,9 @@ mod tests {
581618
let block = VirtioBlock::new(config).unwrap();
582619

583620
block_devs.add_device(Arc::new(Mutex::new(block)));
584-
assert_eq!(block_devs.list.len(), 1);
585-
assert_eq!(
586-
block_devs.list.pop_back().unwrap().lock().unwrap().id(),
587-
block_id
588-
)
621+
assert_eq!(block_devs.devices.len(), 1);
622+
match block_devs.devices.pop_back().unwrap() {
623+
BlockDeviceType::VirtioBlock(ref b) => assert_eq!(b.lock().unwrap().id(), block_id),
624+
}
589625
}
590626
}

0 commit comments

Comments
 (0)