@@ -42,11 +42,11 @@ extern crate versionize_derive;
42
42
use std:: collections:: hash_map:: HashMap ;
43
43
use std:: io:: Read ;
44
44
use versionize:: crc:: { CRC64Reader , CRC64Writer } ;
45
- use versionize:: { Error , Result , VersionMap , Versionize } ;
45
+ use versionize:: { VersionMap , Versionize , VersionizeResult } ;
46
46
use versionize_derive:: Versionize ;
47
47
48
- // 256k max section size.
49
- const SNAPSHOT_MAX_SECTION_SIZE : usize = 0x40000 ;
48
+ // 128k max section size.
49
+ const SNAPSHOT_MAX_SECTION_SIZE : usize = 0x20000 ;
50
50
const SNAPSHOT_FORMAT_VERSION : u16 = 1 ;
51
51
const BASE_MAGIC_ID_MASK : u64 = !0xFFFFu64 ;
52
52
@@ -56,6 +56,21 @@ const BASE_MAGIC_ID: u64 = 0x0710_1984_8664_0000u64;
56
56
#[ cfg( target_arch = "aarch64" ) ]
57
57
const BASE_MAGIC_ID : u64 = 0x0710_1984_AAAA_0000u64 ;
58
58
59
+ /// Error definitions for the Snapshot API.
60
+ #[ derive( Debug , PartialEq ) ]
61
+ pub enum Error {
62
+ /// An IO error occured.
63
+ Io ( i32 ) ,
64
+ /// A versioned serialization/deserialization error occured.
65
+ Versionize ( versionize:: Error ) ,
66
+ /// CRC64 validation failed.
67
+ Crc64 ( u64 ) ,
68
+ /// Magic value does not match arch.
69
+ InvalidMagic ( u64 ) ,
70
+ /// Section does not exist.
71
+ SectionNotFound ,
72
+ }
73
+
59
74
#[ derive( Default , Debug , Versionize ) ]
60
75
struct SnapshotHdr {
61
76
/// Snapshot data version (firecracker version).
@@ -83,7 +98,7 @@ struct Section {
83
98
}
84
99
85
100
// Parse a magic_id and return the format version.
86
- fn get_format_version ( magic_id : u64 ) -> Result < u16 > {
101
+ fn get_format_version ( magic_id : u64 ) -> Result < u16 , Error > {
87
102
let magic_arch = magic_id & BASE_MAGIC_ID_MASK ;
88
103
if magic_arch == BASE_MAGIC_ID {
89
104
return Ok ( ( magic_id & !BASE_MAGIC_ID_MASK ) as u16 ) ;
@@ -108,23 +123,24 @@ impl Snapshot {
108
123
}
109
124
110
125
/// Attempts to load an existing snapshot.
111
- pub fn load < T > ( mut reader : & mut T , version_map : VersionMap ) -> Result < Snapshot >
126
+ pub fn load < T > ( mut reader : & mut T , version_map : VersionMap ) -> Result < Snapshot , Error >
112
127
where
113
128
T : Read ,
114
129
{
115
130
let format_version_map = Self :: format_version_map ( ) ;
116
- let magic_id = <u64 as Versionize >:: deserialize (
117
- & mut reader,
118
- & format_version_map,
119
- 0 , /* unused */
120
- ) ?;
121
- let format_version = get_format_version ( magic_id) . unwrap ( ) ;
131
+ let magic_id =
132
+ <u64 as Versionize >:: deserialize ( & mut reader, & format_version_map, 0 /* unused */ )
133
+ . map_err ( Error :: Versionize ) ?;
134
+
135
+ let format_version = get_format_version ( magic_id) ?;
122
136
let hdr: SnapshotHdr =
123
- SnapshotHdr :: deserialize ( & mut reader, & format_version_map, format_version) ?;
137
+ SnapshotHdr :: deserialize ( & mut reader, & format_version_map, format_version)
138
+ . map_err ( Error :: Versionize ) ?;
124
139
let mut sections = HashMap :: new ( ) ;
125
140
126
141
for _ in 0 ..hdr. section_count {
127
- let section = Section :: deserialize ( & mut reader, & format_version_map, format_version) ?;
142
+ let section = Section :: deserialize ( & mut reader, & format_version_map, format_version)
143
+ . map_err ( Error :: Versionize ) ?;
128
144
sections. insert ( section. name . clone ( ) , section) ;
129
145
}
130
146
@@ -139,7 +155,7 @@ impl Snapshot {
139
155
}
140
156
141
157
/// Attempts to load an existing snapshot and validate CRC.
142
- pub fn load_with_crc64 < T > ( reader : & mut T , version_map : VersionMap ) -> Result < Snapshot >
158
+ pub fn load_with_crc64 < T > ( reader : & mut T , version_map : VersionMap ) -> Result < Snapshot , Error >
143
159
where
144
160
T : Read ,
145
161
{
@@ -151,7 +167,8 @@ impl Snapshot {
151
167
// Since the reader updates the checksum as bytes ar being read from it, the order of these 2 statements is
152
168
// important, we first get the checksum computed on the read bytes then read the stored checksum.
153
169
let computed_checksum = crc_reader. checksum ( ) ;
154
- let stored_checksum: u64 = Versionize :: deserialize ( & mut crc_reader, & format_vm, 0 ) ?;
170
+ let stored_checksum: u64 =
171
+ Versionize :: deserialize ( & mut crc_reader, & format_vm, 0 ) . map_err ( Error :: Versionize ) ?;
155
172
156
173
if computed_checksum != stored_checksum {
157
174
return Err ( Error :: Crc64 ( computed_checksum) ) ;
@@ -161,20 +178,22 @@ impl Snapshot {
161
178
}
162
179
163
180
/// Saves a snapshot and include a CRC64 checksum.
164
- pub fn save_with_crc64 < T > ( & mut self , writer : & mut T ) -> Result < ( ) >
181
+ pub fn save_with_crc64 < T > ( & mut self , writer : & mut T ) -> Result < ( ) , Error >
165
182
where
166
183
T : std:: io:: Write ,
167
184
{
168
185
let mut crc_writer = CRC64Writer :: new ( writer) ;
169
186
self . save ( & mut crc_writer) ?;
170
187
171
188
let checksum = crc_writer. checksum ( ) ;
172
- checksum. serialize ( & mut crc_writer, & Self :: format_version_map ( ) , 0 ) ?;
189
+ checksum
190
+ . serialize ( & mut crc_writer, & Self :: format_version_map ( ) , 0 )
191
+ . map_err ( Error :: Versionize ) ?;
173
192
Ok ( ( ) )
174
193
}
175
194
176
195
/// Save a snapshot.
177
- pub fn save < T > ( & mut self , mut writer : & mut T ) -> Result < ( ) >
196
+ pub fn save < T > ( & mut self , mut writer : & mut T ) -> Result < ( ) , Error >
178
197
where
179
198
T : std:: io:: Write ,
180
199
{
@@ -187,23 +206,30 @@ impl Snapshot {
187
206
let magic_id = build_magic_id ( format_version_map. latest_version ( ) ) ;
188
207
189
208
// Serialize magic id using the format version map.
190
- magic_id. serialize ( & mut writer, & format_version_map, 0 /* unused */ ) ?;
209
+ magic_id
210
+ . serialize ( & mut writer, & format_version_map, 0 /* unused */ )
211
+ . map_err ( Error :: Versionize ) ?;
191
212
// Serialize header using the format version map.
192
- self . hdr . serialize (
193
- & mut writer,
194
- & format_version_map,
195
- format_version_map. latest_version ( ) ,
196
- ) ?;
213
+ self . hdr
214
+ . serialize (
215
+ & mut writer,
216
+ & format_version_map,
217
+ format_version_map. latest_version ( ) ,
218
+ )
219
+ . map_err ( Error :: Versionize ) ?;
197
220
198
221
// Serialize all the sections.
199
222
for section in self . sections . values ( ) {
200
223
// The sections are already serialized.
201
- section. serialize (
202
- & mut writer,
203
- & format_version_map,
204
- format_version_map. latest_version ( ) ,
205
- ) ?;
224
+ section
225
+ . serialize (
226
+ & mut writer,
227
+ & format_version_map,
228
+ format_version_map. latest_version ( ) ,
229
+ )
230
+ . map_err ( Error :: Versionize ) ?;
206
231
}
232
+
207
233
writer
208
234
. flush ( )
209
235
. map_err ( |ref err| Error :: Io ( err. raw_os_error ( ) . unwrap_or ( 0 ) ) ) ?;
@@ -212,7 +238,7 @@ impl Snapshot {
212
238
}
213
239
214
240
/// Attempts to find and reads a section (deserialize/translate) from a snapshot.
215
- pub fn read_section < T > ( & mut self , name : & str ) -> Result < T >
241
+ pub fn read_section < T > ( & mut self , name : & str ) -> Result < T , Error >
216
242
where
217
243
T : Versionize ,
218
244
{
@@ -221,14 +247,15 @@ impl Snapshot {
221
247
& mut section. data . as_mut_slice ( ) . as_ref ( ) ,
222
248
& self . version_map ,
223
249
self . hdr . data_version ,
224
- ) ?)
250
+ )
251
+ . map_err ( Error :: Versionize ) ?)
225
252
} else {
226
253
Err ( Error :: SectionNotFound )
227
254
}
228
255
}
229
256
230
257
/// Write a section (serialize/translate) to a snapshot.
231
- pub fn write_section < T > ( & mut self , name : & str , object : & T ) -> Result < usize >
258
+ pub fn write_section < T > ( & mut self , name : & str , object : & T ) -> Result < usize , Error >
232
259
where
233
260
T : Versionize ,
234
261
{
@@ -238,7 +265,9 @@ impl Snapshot {
238
265
} ;
239
266
240
267
let slice = & mut new_section. data . as_mut_slice ( ) ;
241
- object. serialize ( slice, & self . version_map , self . target_version ) ?;
268
+ object
269
+ . serialize ( slice, & self . version_map , self . target_version )
270
+ . map_err ( Error :: Versionize ) ?;
242
271
// Resize vec to serialized section len.
243
272
let serialized_len =
244
273
slice. as_ptr ( ) as usize - new_section. data . as_slice ( ) . as_ptr ( ) as usize ;
@@ -305,36 +334,38 @@ mod tests {
305
334
fn field4_default ( _: u16 ) -> Vec < u64 > {
306
335
vec ! [ 1 , 2 , 3 , 4 ]
307
336
}
308
- fn field4_serialize ( & mut self , target_version : u16 ) -> Result < ( ) > {
337
+ fn field4_serialize ( & mut self , target_version : u16 ) -> VersionizeResult < ( ) > {
309
338
// Fail if semantic serialization is called for the latest version.
310
339
assert_ne ! ( target_version, Test :: version( ) ) ;
311
340
self . field0 = self . field4 . iter ( ) . sum ( ) ;
312
341
313
342
if self . field0 == 6666 {
314
- return Err ( Error :: Semantic ( "field4 element sum is 6666" . to_owned ( ) ) ) ;
343
+ return Err ( versionize:: Error :: Semantic (
344
+ "field4 element sum is 6666" . to_owned ( ) ,
345
+ ) ) ;
315
346
}
316
347
Ok ( ( ) )
317
348
}
318
- fn field4_deserialize ( & mut self , source_version : u16 ) -> Result < ( ) > {
349
+ fn field4_deserialize ( & mut self , source_version : u16 ) -> VersionizeResult < ( ) > {
319
350
// Fail if semantic deserialization is called for the latest version.
320
351
assert_ne ! ( source_version, Test :: version( ) ) ;
321
352
self . field4 = vec ! [ self . field0; 4 ] ;
322
353
Ok ( ( ) )
323
354
}
324
355
325
- fn field3_serialize ( & mut self , target_version : u16 ) -> Result < ( ) > {
356
+ fn field3_serialize ( & mut self , target_version : u16 ) -> VersionizeResult < ( ) > {
326
357
// Fail if semantic serialization is called for the previous versions only.
327
358
assert ! ( target_version < 3 ) ;
328
359
self . field_x += 1 ;
329
360
Ok ( ( ) )
330
361
}
331
362
332
- fn field3_deserialize ( & mut self , source_version : u16 ) -> Result < ( ) > {
363
+ fn field3_deserialize ( & mut self , source_version : u16 ) -> VersionizeResult < ( ) > {
333
364
// Fail if semantic deserialization is called for the latest version.
334
365
assert ! ( source_version < 3 ) ;
335
366
self . field_x += 1 ;
336
367
if self . field0 == 7777 {
337
- return Err ( Error :: Semantic ( "field0 is 7777" . to_owned ( ) ) ) ;
368
+ return Err ( versionize :: Error :: Semantic ( "field0 is 7777" . to_owned ( ) ) ) ;
338
369
}
339
370
Ok ( ( ) )
340
371
}
@@ -426,7 +457,9 @@ mod tests {
426
457
// The section will fail due to a custom semantic error.
427
458
assert_eq ! (
428
459
snapshot. write_section( "test" , & state) ,
429
- Err ( Error :: Semantic ( "field4 element sum is 6666" . to_owned( ) ) )
460
+ Err ( Error :: Versionize ( versionize:: Error :: Semantic (
461
+ "field4 element sum is 6666" . to_owned( )
462
+ ) ) )
430
463
) ;
431
464
}
432
465
@@ -461,7 +494,7 @@ mod tests {
461
494
let section_read_error = snapshot. read_section :: < Test > ( "test" ) . unwrap_err ( ) ;
462
495
assert_eq ! (
463
496
section_read_error,
464
- Error :: Semantic ( "field0 is 7777" . to_owned( ) )
497
+ Error :: Versionize ( versionize :: Error :: Semantic ( "field0 is 7777" . to_owned( ) ) )
465
498
) ;
466
499
}
467
500
@@ -482,13 +515,33 @@ mod tests {
482
515
assert ! ( snapshot. write_section( "test" , & state_1) . is_ok( ) ) ;
483
516
assert_eq ! (
484
517
snapshot. save( & mut snapshot_mem. as_mut_slice( ) ) . unwrap_err( ) ,
485
- Error :: Serialize (
518
+ Error :: Versionize ( versionize :: Error :: Serialize (
486
519
"Io(Custom { kind: WriteZero, error: \" failed to write whole buffer\" })"
487
520
. to_owned( )
488
- )
521
+ ) )
489
522
) ;
490
523
}
491
524
525
+ #[ test]
526
+ fn test_read_invalid_section ( ) {
527
+ let vm = VersionMap :: new ( ) ;
528
+ let state = Test1 {
529
+ field_x : 0 ,
530
+ field0 : 0 ,
531
+ field1 : 1 ,
532
+ } ;
533
+
534
+ let mut snapshot_mem = vec ! [ 0u8 ; 1024 ] ;
535
+
536
+ let mut snapshot = Snapshot :: new ( vm. clone ( ) , 1 ) ;
537
+ assert ! ( snapshot. write_section( "test" , & state) . is_ok( ) ) ;
538
+ assert_eq ! ( snapshot. save( & mut snapshot_mem. as_mut_slice( ) ) , Ok ( ( ) ) ) ;
539
+
540
+ snapshot = Snapshot :: load ( & mut snapshot_mem. as_slice ( ) , vm. clone ( ) ) . unwrap ( ) ;
541
+ let section_read_error = snapshot. read_section :: < Test > ( "404" ) . unwrap_err ( ) ;
542
+ assert_eq ! ( section_read_error, Error :: SectionNotFound ) ;
543
+ }
544
+
492
545
#[ test]
493
546
fn test_crc_ok ( ) {
494
547
let vm = VersionMap :: new ( ) ;
@@ -571,10 +624,10 @@ mod tests {
571
624
Snapshot :: load ( & mut snapshot_mem. as_slice ( ) , vm. clone ( ) ) . unwrap_err ( ) ;
572
625
assert_eq ! (
573
626
snapshot_load_error,
574
- Error :: Deserialize (
627
+ Error :: Versionize ( versionize :: Error :: Deserialize (
575
628
"Io(Custom { kind: UnexpectedEof, error: \" failed to fill whole buffer\" })"
576
629
. to_owned( )
577
- )
630
+ ) )
578
631
) ;
579
632
}
580
633
@@ -796,7 +849,7 @@ mod tests {
796
849
"whatever" . to_owned ( )
797
850
}
798
851
799
- fn semantic_x ( & mut self , _target_version : u16 ) -> Result < ( ) > {
852
+ fn semantic_x ( & mut self , _target_version : u16 ) -> VersionizeResult < ( ) > {
800
853
self . x = self . q as u32 ;
801
854
Ok ( ( ) )
802
855
}
0 commit comments