8
8
use std:: cmp;
9
9
use std:: convert:: From ;
10
10
use std:: fs:: { File , OpenOptions } ;
11
- use std:: io:: { self , Seek , SeekFrom , Write } ;
11
+ use std:: io:: { self , Write } ;
12
12
#[ cfg( target_os = "linux" ) ]
13
13
use std:: os:: linux:: fs:: MetadataExt ;
14
14
#[ cfg( target_os = "macos" ) ]
@@ -19,6 +19,9 @@ use std::sync::atomic::AtomicUsize;
19
19
use std:: sync:: { Arc , Mutex } ;
20
20
use std:: thread:: JoinHandle ;
21
21
22
+ use imago:: file:: File as ImagoFile ;
23
+ use imago:: qcow2:: Qcow2 ;
24
+ use imago:: SyncFormatAccess ;
22
25
use log:: { error, warn} ;
23
26
use utils:: eventfd:: { EventFd , EFD_NONBLOCK } ;
24
27
use virtio_bindings:: {
@@ -35,6 +38,8 @@ use super::{
35
38
use crate :: legacy:: Gic ;
36
39
use crate :: virtio:: { block:: disk, ActivateError } ;
37
40
41
+ use disk:: ImageType ;
42
+
38
43
/// Configuration options for disk caching.
39
44
#[ derive( Clone , Copy , Debug , Default , Eq , PartialEq ) ]
40
45
pub enum CacheType {
@@ -51,22 +56,18 @@ pub enum CacheType {
51
56
/// Helper object for setting up all `Block` fields derived from its backing file.
52
57
pub ( crate ) struct DiskProperties {
53
58
cache_type : CacheType ,
54
- pub ( crate ) file : File ,
59
+ file : Arc < SyncFormatAccess < ImagoFile > > ,
55
60
nsectors : u64 ,
56
61
image_id : Vec < u8 > ,
57
62
}
58
63
59
64
impl DiskProperties {
60
65
pub fn new (
61
- disk_image_path : String ,
62
- is_disk_read_only : bool ,
66
+ disk_image : Arc < SyncFormatAccess < ImagoFile > > ,
67
+ disk_image_id : Vec < u8 > ,
63
68
cache_type : CacheType ,
64
69
) -> io:: Result < Self > {
65
- let mut disk_image = OpenOptions :: new ( )
66
- . read ( true )
67
- . write ( !is_disk_read_only)
68
- . open ( PathBuf :: from ( & disk_image_path) ) ?;
69
- let disk_size = disk_image. seek ( SeekFrom :: End ( 0 ) ) ?;
70
+ let disk_size = disk_image. size ( ) ;
70
71
71
72
// We only support disk size, which uses the first two words of the configuration space.
72
73
// If the image is not a multiple of the sector size, the tail bits are not exposed.
@@ -81,13 +82,13 @@ impl DiskProperties {
81
82
Ok ( Self {
82
83
cache_type,
83
84
nsectors : disk_size >> SECTOR_SHIFT ,
84
- image_id : Self :: build_disk_image_id ( & disk_image ) ,
85
+ image_id : disk_image_id ,
85
86
file : disk_image,
86
87
} )
87
88
}
88
89
89
- pub fn file_mut ( & mut self ) -> & mut File {
90
- & mut self . file
90
+ pub fn file ( & mut self ) -> & SyncFormatAccess < ImagoFile > {
91
+ self . file . as_ref ( )
91
92
}
92
93
93
94
pub fn nsectors ( & self ) -> u64 {
@@ -141,7 +142,7 @@ impl Drop for DiskProperties {
141
142
error ! ( "Failed to flush block data on drop." ) ;
142
143
}
143
144
// Sync data out to physical media on host.
144
- if self . file . sync_all ( ) . is_err ( ) {
145
+ if self . file . sync ( ) . is_err ( ) {
145
146
error ! ( "Failed to sync block data on drop." )
146
147
}
147
148
}
@@ -168,8 +169,8 @@ pub struct Block {
168
169
// Host file and properties.
169
170
disk : Option < DiskProperties > ,
170
171
cache_type : CacheType ,
171
- disk_image_path : String ,
172
- is_disk_read_only : bool ,
172
+ disk_image : Arc < SyncFormatAccess < ImagoFile > > ,
173
+ disk_image_id : Vec < u8 > ,
173
174
worker_thread : Option < JoinHandle < ( ) > > ,
174
175
worker_stopfd : EventFd ,
175
176
@@ -205,8 +206,31 @@ impl Block {
205
206
disk_image_path : String ,
206
207
is_disk_read_only : bool ,
207
208
) -> io:: Result < Block > {
209
+ let disk_image = OpenOptions :: new ( )
210
+ . read ( true )
211
+ . write ( !is_disk_read_only)
212
+ . open ( PathBuf :: from ( & disk_image_path) ) ?;
213
+
214
+ let disk_image_id = DiskProperties :: build_disk_image_id ( & disk_image) ;
215
+
216
+ let image_type = disk:: detect_image_type ( & disk_image, false ) . unwrap ( ) ;
217
+
218
+ let disk_image = match image_type {
219
+ ImageType :: Qcow2 => {
220
+ let mut qcow_disk_image =
221
+ Qcow2 :: < ImagoFile > :: open_path_sync ( disk_image_path, !is_disk_read_only) ?;
222
+ qcow_disk_image. open_implicit_dependencies_sync ( ) ?;
223
+ SyncFormatAccess :: new ( qcow_disk_image) ?
224
+ }
225
+ ImageType :: Raw => {
226
+ let raw = imago:: raw:: Raw :: open_path_sync ( disk_image_path, !is_disk_read_only) ?;
227
+ SyncFormatAccess :: new ( raw) ?
228
+ }
229
+ } ;
230
+ let disk_image = Arc :: new ( disk_image) ;
231
+
208
232
let disk_properties =
209
- DiskProperties :: new ( disk_image_path . clone ( ) , is_disk_read_only , cache_type) ?;
233
+ DiskProperties :: new ( Arc :: clone ( & disk_image ) , disk_image_id . clone ( ) , cache_type) ?;
210
234
211
235
let mut avail_features = ( 1u64 << VIRTIO_F_VERSION_1 )
212
236
| ( 1u64 << VIRTIO_BLK_F_FLUSH )
@@ -234,8 +258,8 @@ impl Block {
234
258
config,
235
259
disk : Some ( disk_properties) ,
236
260
cache_type,
237
- disk_image_path ,
238
- is_disk_read_only ,
261
+ disk_image ,
262
+ disk_image_id ,
239
263
avail_features,
240
264
acked_features : 0u64 ,
241
265
interrupt_status : Arc :: new ( AtomicUsize :: new ( 0 ) ) ,
@@ -348,8 +372,8 @@ impl VirtioDevice for Block {
348
372
let disk = match self . disk . take ( ) {
349
373
Some ( d) => d,
350
374
None => DiskProperties :: new (
351
- self . disk_image_path . clone ( ) ,
352
- self . is_disk_read_only ,
375
+ Arc :: clone ( & self . disk_image ) ,
376
+ self . disk_image_id . clone ( ) ,
353
377
self . cache_type ,
354
378
)
355
379
. map_err ( |_| ActivateError :: BadActivate ) ?,
0 commit comments