@@ -16,6 +16,8 @@ use crate::devices::virtio::block::{BlockError, CacheType};
1616/// Errors associated with the operations allowed on a drive.
1717#[ derive( Debug , thiserror:: Error , displaydoc:: Display ) ]
1818pub enum DriveError {
19+ /// Attempt to add block as a root device while the root device defined as a pmem device
20+ AddingSecondRootDevice ,
1921 /// Unable to create the virtio block device: {0}
2022 CreateBlockDevice ( BlockError ) ,
2123 /// Cannot create RateLimiter: {0}
@@ -99,7 +101,7 @@ impl BlockBuilder {
99101 }
100102
101103 /// Specifies whether there is a root block device already present in the list.
102- fn has_root_device ( & self ) -> bool {
104+ pub fn has_root_device ( & self ) -> bool {
103105 // If there is a root device, it would be at the top of the list.
104106 if let Some ( block) = self . devices . front ( ) {
105107 block. lock ( ) . expect ( "Poisoned lock" ) . root_device ( )
@@ -127,11 +129,19 @@ impl BlockBuilder {
127129 /// Inserts a `Block` in the block devices list using the specified configuration.
128130 /// If a block with the same id already exists, it will overwrite it.
129131 /// Inserting a secondary root block device will fail.
130- pub fn insert ( & mut self , config : BlockDeviceConfig ) -> Result < ( ) , DriveError > {
132+ pub fn insert (
133+ & mut self ,
134+ config : BlockDeviceConfig ,
135+ has_pmem_root : bool ,
136+ ) -> Result < ( ) , DriveError > {
131137 let position = self . get_index_of_drive_id ( & config. drive_id ) ;
132138 let has_root_device = self . has_root_device ( ) ;
133139 let configured_as_root = config. is_root_device ;
134140
141+ if configured_as_root && has_pmem_root {
142+ return Err ( DriveError :: AddingSecondRootDevice ) ;
143+ }
144+
135145 // Don't allow adding a second root block device.
136146 // If the new device cfg is root and not an update to the existing root, fail fast.
137147 if configured_as_root && has_root_device && position != Some ( 0 ) {
@@ -234,7 +244,9 @@ mod tests {
234244 } ;
235245
236246 let mut block_devs = BlockBuilder :: new ( ) ;
237- block_devs. insert ( dummy_block_device. clone ( ) ) . unwrap ( ) ;
247+ block_devs
248+ . insert ( dummy_block_device. clone ( ) , false )
249+ . unwrap ( ) ;
238250
239251 assert ! ( !block_devs. has_root_device( ) ) ;
240252 assert_eq ! ( block_devs. devices. len( ) , 1 ) ;
@@ -266,7 +278,9 @@ mod tests {
266278 } ;
267279
268280 let mut block_devs = BlockBuilder :: new ( ) ;
269- block_devs. insert ( dummy_block_device. clone ( ) ) . unwrap ( ) ;
281+ block_devs
282+ . insert ( dummy_block_device. clone ( ) , false )
283+ . unwrap ( ) ;
270284
271285 assert ! ( block_devs. has_root_device( ) ) ;
272286 assert_eq ! ( block_devs. devices. len( ) , 1 ) ;
@@ -276,6 +290,36 @@ mod tests {
276290 assert_eq ! ( block. read_only( ) , dummy_block_device. is_read_only. unwrap( ) ) ;
277291 }
278292
293+ #[ test]
294+ fn test_add_one_root_block_device_with_pmem_already_as_root ( ) {
295+ let dummy_file = TempFile :: new ( ) . unwrap ( ) ;
296+ let dummy_path = dummy_file. as_path ( ) . to_str ( ) . unwrap ( ) . to_string ( ) ;
297+
298+ let dummy_block_device = BlockDeviceConfig {
299+ drive_id : String :: from ( "1" ) ,
300+ partuuid : None ,
301+ is_root_device : true ,
302+ cache_type : CacheType :: Unsafe ,
303+
304+ is_read_only : Some ( true ) ,
305+ path_on_host : Some ( dummy_path) ,
306+ rate_limiter : None ,
307+ file_engine_type : None ,
308+
309+ socket : None ,
310+ } ;
311+
312+ let mut block_devs = BlockBuilder :: new ( ) ;
313+ assert ! ( matches!(
314+ block_devs
315+ . insert( dummy_block_device. clone( ) , true )
316+ . unwrap_err( ) ,
317+ DriveError :: AddingSecondRootDevice ,
318+ ) ) ;
319+ assert ! ( !block_devs. has_root_device( ) ) ;
320+ assert_eq ! ( block_devs. devices. len( ) , 0 ) ;
321+ }
322+
279323 #[ test]
280324 fn test_add_two_root_block_devs ( ) {
281325 let dummy_file_1 = TempFile :: new ( ) . unwrap ( ) ;
@@ -311,9 +355,9 @@ mod tests {
311355 } ;
312356
313357 let mut block_devs = BlockBuilder :: new ( ) ;
314- block_devs. insert ( root_block_device_1) . unwrap ( ) ;
358+ block_devs. insert ( root_block_device_1, false ) . unwrap ( ) ;
315359 assert_eq ! (
316- block_devs. insert( root_block_device_2) . unwrap_err( ) ,
360+ block_devs. insert( root_block_device_2, false ) . unwrap_err( ) ,
317361 DriveError :: RootBlockDeviceAlreadyAdded
318362 ) ;
319363 }
@@ -370,9 +414,9 @@ mod tests {
370414 } ;
371415
372416 let mut block_devs = BlockBuilder :: new ( ) ;
373- block_devs. insert ( dummy_block_dev_2. clone ( ) ) . unwrap ( ) ;
374- block_devs. insert ( dummy_block_dev_3. clone ( ) ) . unwrap ( ) ;
375- block_devs. insert ( root_block_device. clone ( ) ) . unwrap ( ) ;
417+ block_devs. insert ( dummy_block_dev_2. clone ( ) , false ) . unwrap ( ) ;
418+ block_devs. insert ( dummy_block_dev_3. clone ( ) , false ) . unwrap ( ) ;
419+ block_devs. insert ( root_block_device. clone ( ) , false ) . unwrap ( ) ;
376420
377421 assert_eq ! ( block_devs. devices. len( ) , 3 ) ;
378422
@@ -443,9 +487,9 @@ mod tests {
443487 } ;
444488
445489 let mut block_devs = BlockBuilder :: new ( ) ;
446- block_devs. insert ( dummy_block_dev_2. clone ( ) ) . unwrap ( ) ;
447- block_devs. insert ( dummy_block_dev_3. clone ( ) ) . unwrap ( ) ;
448- block_devs. insert ( root_block_device. clone ( ) ) . unwrap ( ) ;
490+ block_devs. insert ( dummy_block_dev_2. clone ( ) , false ) . unwrap ( ) ;
491+ block_devs. insert ( dummy_block_dev_3. clone ( ) , false ) . unwrap ( ) ;
492+ block_devs. insert ( root_block_device. clone ( ) , false ) . unwrap ( ) ;
449493
450494 assert_eq ! ( block_devs. devices. len( ) , 3 ) ;
451495
@@ -503,8 +547,10 @@ mod tests {
503547 let mut block_devs = BlockBuilder :: new ( ) ;
504548
505549 // Add 2 block devices.
506- block_devs. insert ( root_block_device) . unwrap ( ) ;
507- block_devs. insert ( dummy_block_device_2. clone ( ) ) . unwrap ( ) ;
550+ block_devs. insert ( root_block_device, false ) . unwrap ( ) ;
551+ block_devs
552+ . insert ( dummy_block_device_2. clone ( ) , false )
553+ . unwrap ( ) ;
508554
509555 // Get index zero.
510556 assert_eq ! (
@@ -528,7 +574,9 @@ mod tests {
528574 ) ;
529575 // Update OK.
530576 dummy_block_device_2. is_read_only = Some ( true ) ;
531- block_devs. insert ( dummy_block_device_2. clone ( ) ) . unwrap ( ) ;
577+ block_devs
578+ . insert ( dummy_block_device_2. clone ( ) , false )
579+ . unwrap ( ) ;
532580
533581 let index = block_devs
534582 . get_index_of_drive_id ( & dummy_block_device_2. drive_id )
@@ -540,7 +588,7 @@ mod tests {
540588 let dummy_path_3 = String :: from ( "test_update_3" ) ;
541589 dummy_block_device_2. path_on_host = Some ( dummy_path_3) ;
542590 assert ! ( matches!(
543- block_devs. insert( dummy_block_device_2. clone( ) ) ,
591+ block_devs. insert( dummy_block_device_2. clone( ) , false ) ,
544592 Err ( DriveError :: CreateBlockDevice ( BlockError :: VirtioBackend (
545593 VirtioBlockError :: BackingFile ( _, _)
546594 ) ) )
@@ -550,7 +598,7 @@ mod tests {
550598 dummy_block_device_2. path_on_host = Some ( dummy_path_2. clone ( ) ) ;
551599 dummy_block_device_2. is_root_device = true ;
552600 assert_eq ! (
553- block_devs. insert( dummy_block_device_2) ,
601+ block_devs. insert( dummy_block_device_2, false ) ,
554602 Err ( DriveError :: RootBlockDeviceAlreadyAdded )
555603 ) ;
556604
@@ -584,9 +632,9 @@ mod tests {
584632 socket : None ,
585633 } ;
586634
587- block_devs. insert ( root_block_device_old) . unwrap ( ) ;
635+ block_devs. insert ( root_block_device_old, false ) . unwrap ( ) ;
588636 let root_block_id = root_block_device_new. drive_id . clone ( ) ;
589- block_devs. insert ( root_block_device_new) . unwrap ( ) ;
637+ block_devs. insert ( root_block_device_new, false ) . unwrap ( ) ;
590638 assert ! ( block_devs. has_root_device( ) ) ;
591639 // Verify it's been moved to the first position.
592640 assert_eq ! ( block_devs. devices[ 0 ] . lock( ) . unwrap( ) . id( ) , root_block_id) ;
@@ -611,7 +659,9 @@ mod tests {
611659 } ;
612660
613661 let mut block_devs = BlockBuilder :: new ( ) ;
614- block_devs. insert ( dummy_block_device. clone ( ) ) . unwrap ( ) ;
662+ block_devs
663+ . insert ( dummy_block_device. clone ( ) , false )
664+ . unwrap ( ) ;
615665
616666 let configs = block_devs. configs ( ) ;
617667 assert_eq ! ( configs. len( ) , 1 ) ;
0 commit comments