@@ -94,6 +94,9 @@ pub struct HclCompatNvram<S> {
94
94
// reduced allocator pressure
95
95
#[ cfg_attr( feature = "inspect" , inspect( skip) ) ] // internal bookkeeping - not worth inspecting
96
96
nvram_buf : Vec < u8 > ,
97
+
98
+ // whether the NVRAM has been loaded, either from storage or saved state
99
+ loaded : bool ,
97
100
}
98
101
99
102
/// "Quirks" to take into account when loading/storing nvram blob data.
@@ -121,9 +124,8 @@ impl<S: StorageBackend> HclCompatNvram<S> {
121
124
pub async fn new (
122
125
storage : S ,
123
126
quirks : Option < HclCompatNvramQuirks > ,
124
- is_restoring : bool ,
125
127
) -> Result < Self , NvramStorageError > {
126
- let mut nvram = Self {
128
+ let nvram = Self {
127
129
quirks : quirks. unwrap_or ( HclCompatNvramQuirks {
128
130
skip_corrupt_vars_with_missing_null_term : false ,
129
131
} ) ,
@@ -133,16 +135,14 @@ impl<S: StorageBackend> HclCompatNvram<S> {
133
135
in_memory : in_memory:: InMemoryNvram :: new ( ) ,
134
136
135
137
nvram_buf : Vec :: new ( ) ,
138
+
139
+ loaded : false ,
136
140
} ;
137
- if !is_restoring {
138
- nvram. load_from_storage ( ) . await ?;
139
- }
140
141
Ok ( nvram)
141
142
}
142
143
143
- async fn load_from_storage ( & mut self ) -> Result < ( ) , NvramStorageError > {
144
- tracing:: info!( "loading uefi nvram from storage" ) ;
145
- let res = self . load_from_storage_inner ( ) . await ;
144
+ async fn lazy_load_from_storage ( & mut self ) -> Result < ( ) , NvramStorageError > {
145
+ let res = self . lazy_load_from_storage_inner ( ) . await ;
146
146
if let Err ( e) = & res {
147
147
tracing:: error!( CVM_ALLOWED , "storage contains corrupt nvram state" ) ;
148
148
tracing:: error!(
@@ -154,7 +154,13 @@ impl<S: StorageBackend> HclCompatNvram<S> {
154
154
res
155
155
}
156
156
157
- async fn load_from_storage_inner ( & mut self ) -> Result < ( ) , NvramStorageError > {
157
+ async fn lazy_load_from_storage_inner ( & mut self ) -> Result < ( ) , NvramStorageError > {
158
+ if self . loaded {
159
+ return Ok ( ( ) ) ;
160
+ }
161
+
162
+ tracing:: info!( "loading uefi nvram from storage" ) ;
163
+
158
164
let nvram_buf = self
159
165
. storage
160
166
. restore ( )
@@ -293,6 +299,7 @@ impl<S: StorageBackend> HclCompatNvram<S> {
293
299
) ) ;
294
300
}
295
301
302
+ self . loaded = true ;
296
303
Ok ( ( ) )
297
304
}
298
305
@@ -343,8 +350,11 @@ impl<S: StorageBackend> HclCompatNvram<S> {
343
350
344
351
/// Iterate over the NVRAM entries. This function asynchronously loads the
345
352
/// NVRAM contents into memory from the backing storage if necessary.
346
- pub fn iter ( & mut self ) -> impl Iterator < Item = in_memory:: VariableEntry < ' _ > > {
347
- self . in_memory . iter ( )
353
+ pub async fn iter (
354
+ & mut self ,
355
+ ) -> Result < impl Iterator < Item = in_memory:: VariableEntry < ' _ > > , NvramStorageError > {
356
+ self . lazy_load_from_storage ( ) . await ?;
357
+ Ok ( self . in_memory . iter ( ) )
348
358
}
349
359
}
350
360
@@ -355,6 +365,8 @@ impl<S: StorageBackend> NvramStorage for HclCompatNvram<S> {
355
365
name : & Ucs2LeSlice ,
356
366
vendor : Guid ,
357
367
) -> Result < Option < ( u32 , Vec < u8 > , EFI_TIME ) > , NvramStorageError > {
368
+ self . lazy_load_from_storage ( ) . await ?;
369
+
358
370
if name. as_bytes ( ) . len ( ) > EFI_MAX_VARIABLE_NAME_SIZE {
359
371
return Err ( NvramStorageError :: VariableNameTooLong ) ;
360
372
}
@@ -370,6 +382,8 @@ impl<S: StorageBackend> NvramStorage for HclCompatNvram<S> {
370
382
data : Vec < u8 > ,
371
383
timestamp : EFI_TIME ,
372
384
) -> Result < ( ) , NvramStorageError > {
385
+ self . lazy_load_from_storage ( ) . await ?;
386
+
373
387
if name. as_bytes ( ) . len ( ) > EFI_MAX_VARIABLE_NAME_SIZE {
374
388
return Err ( NvramStorageError :: VariableNameTooLong ) ;
375
389
}
@@ -404,14 +418,15 @@ impl<S: StorageBackend> NvramStorage for HclCompatNvram<S> {
404
418
405
419
Ok ( ( ) )
406
420
}
407
-
408
421
async fn append_variable (
409
422
& mut self ,
410
423
name : & Ucs2LeSlice ,
411
424
vendor : Guid ,
412
425
data : Vec < u8 > ,
413
426
timestamp : EFI_TIME ,
414
427
) -> Result < bool , NvramStorageError > {
428
+ self . lazy_load_from_storage ( ) . await ?;
429
+
415
430
if name. as_bytes ( ) . len ( ) > EFI_MAX_VARIABLE_NAME_SIZE {
416
431
return Err ( NvramStorageError :: VariableNameTooLong ) ;
417
432
}
@@ -442,6 +457,8 @@ impl<S: StorageBackend> NvramStorage for HclCompatNvram<S> {
442
457
name : & Ucs2LeSlice ,
443
458
vendor : Guid ,
444
459
) -> Result < bool , NvramStorageError > {
460
+ self . lazy_load_from_storage ( ) . await ?;
461
+
445
462
if name. as_bytes ( ) . len ( ) > EFI_MAX_VARIABLE_NAME_SIZE {
446
463
return Err ( NvramStorageError :: VariableNameTooLong ) ;
447
464
}
@@ -456,6 +473,8 @@ impl<S: StorageBackend> NvramStorage for HclCompatNvram<S> {
456
473
& mut self ,
457
474
name_vendor : Option < ( & Ucs2LeSlice , Guid ) > ,
458
475
) -> Result < NextVariable , NvramStorageError > {
476
+ self . lazy_load_from_storage ( ) . await ?;
477
+
459
478
if let Some ( ( name, _) ) = name_vendor {
460
479
if name. as_bytes ( ) . len ( ) > EFI_MAX_VARIABLE_NAME_SIZE {
461
480
return Err ( NvramStorageError :: VariableNameTooLong ) ;
@@ -481,7 +500,11 @@ mod save_restore {
481
500
}
482
501
483
502
fn restore ( & mut self , state : Self :: SavedState ) -> Result < ( ) , RestoreError > {
484
- self . in_memory . restore ( state)
503
+ if state. nvram . is_some ( ) {
504
+ self . in_memory . restore ( state) ?;
505
+ self . loaded = true ;
506
+ }
507
+ Ok ( ( ) )
485
508
}
486
509
}
487
510
}
@@ -516,36 +539,28 @@ mod test {
516
539
#[ async_test]
517
540
async fn test_single_variable ( ) {
518
541
let mut storage = EphemeralStorageBackend :: default ( ) ;
519
- let mut nvram = HclCompatNvram :: new ( & mut storage, None , false )
520
- . await
521
- . unwrap ( ) ;
542
+ let mut nvram = HclCompatNvram :: new ( & mut storage, None ) . await . unwrap ( ) ;
522
543
impl_agnostic_tests:: test_single_variable ( & mut nvram) . await ;
523
544
}
524
545
525
546
#[ async_test]
526
547
async fn test_multiple_variable ( ) {
527
548
let mut storage = EphemeralStorageBackend :: default ( ) ;
528
- let mut nvram = HclCompatNvram :: new ( & mut storage, None , false )
529
- . await
530
- . unwrap ( ) ;
549
+ let mut nvram = HclCompatNvram :: new ( & mut storage, None ) . await . unwrap ( ) ;
531
550
impl_agnostic_tests:: test_multiple_variable ( & mut nvram) . await ;
532
551
}
533
552
534
553
#[ async_test]
535
554
async fn test_next ( ) {
536
555
let mut storage = EphemeralStorageBackend :: default ( ) ;
537
- let mut nvram = HclCompatNvram :: new ( & mut storage, None , false )
538
- . await
539
- . unwrap ( ) ;
556
+ let mut nvram = HclCompatNvram :: new ( & mut storage, None ) . await . unwrap ( ) ;
540
557
impl_agnostic_tests:: test_next ( & mut nvram) . await ;
541
558
}
542
559
543
560
#[ async_test]
544
561
async fn boundary_conditions ( ) {
545
562
let mut storage = EphemeralStorageBackend :: default ( ) ;
546
- let mut nvram = HclCompatNvram :: new ( & mut storage, None , false )
547
- . await
548
- . unwrap ( ) ;
563
+ let mut nvram = HclCompatNvram :: new ( & mut storage, None ) . await . unwrap ( ) ;
549
564
550
565
let vendor = Guid :: new_random ( ) ;
551
566
let attr = 0x1234 ;
@@ -633,9 +648,7 @@ mod test {
633
648
let data = vec ! [ 0x1 , 0x2 , 0x3 , 0x4 , 0x5 ] ;
634
649
let timestamp = EFI_TIME :: default ( ) ;
635
650
636
- let mut nvram = HclCompatNvram :: new ( & mut storage, None , false )
637
- . await
638
- . unwrap ( ) ;
651
+ let mut nvram = HclCompatNvram :: new ( & mut storage, None ) . await . unwrap ( ) ;
639
652
nvram
640
653
. set_variable ( name1, vendor1, attr, data. clone ( ) , timestamp)
641
654
. await
@@ -652,9 +665,7 @@ mod test {
652
665
drop ( nvram) ;
653
666
654
667
// reload
655
- let mut nvram = HclCompatNvram :: new ( & mut storage, None , false )
656
- . await
657
- . unwrap ( ) ;
668
+ let mut nvram = HclCompatNvram :: new ( & mut storage, None ) . await . unwrap ( ) ;
658
669
659
670
let ( result_attr, result_data, result_timestamp) =
660
671
nvram. get_variable ( name1, vendor1) . await . unwrap ( ) . unwrap ( ) ;
0 commit comments