Skip to content

Commit 7a61c07

Browse files
committed
Use SyncFormatAccess<File> in DiskProperties
Instead of using a standard `File` for the `file` attribute in `DiskProperties`, use `SyncFormatAccess<File>`. This allows libkrun to take advantage of imago's support for multiple disk image formats. Libkrun now supports the use of Raw or Qcow2 image file formats for disk images. Signed-off-by: Jake Correnti <[email protected]>
1 parent 4a069cd commit 7a61c07

File tree

3 files changed

+62
-40
lines changed

3 files changed

+62
-40
lines changed

src/devices/src/virtio/block/device.rs

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
use std::cmp;
99
use std::convert::From;
1010
use std::fs::{File, OpenOptions};
11-
use std::io::{self, Seek, SeekFrom, Write};
11+
use std::io::{self, Write};
1212
#[cfg(target_os = "linux")]
1313
use std::os::linux::fs::MetadataExt;
1414
#[cfg(target_os = "macos")]
@@ -19,6 +19,9 @@ use std::sync::atomic::AtomicUsize;
1919
use std::sync::{Arc, Mutex};
2020
use std::thread::JoinHandle;
2121

22+
use imago::file::File as ImagoFile;
23+
use imago::qcow2::Qcow2;
24+
use imago::SyncFormatAccess;
2225
use log::{error, warn};
2326
use utils::eventfd::{EventFd, EFD_NONBLOCK};
2427
use virtio_bindings::{
@@ -35,6 +38,8 @@ use super::{
3538
use crate::legacy::Gic;
3639
use crate::virtio::{block::disk, ActivateError};
3740

41+
use disk::ImageType;
42+
3843
/// Configuration options for disk caching.
3944
#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
4045
pub enum CacheType {
@@ -51,22 +56,18 @@ pub enum CacheType {
5156
/// Helper object for setting up all `Block` fields derived from its backing file.
5257
pub(crate) struct DiskProperties {
5358
cache_type: CacheType,
54-
pub(crate) file: File,
59+
file: Arc<SyncFormatAccess<ImagoFile>>,
5560
nsectors: u64,
5661
image_id: Vec<u8>,
5762
}
5863

5964
impl DiskProperties {
6065
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>,
6368
cache_type: CacheType,
6469
) -> 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();
7071

7172
// We only support disk size, which uses the first two words of the configuration space.
7273
// If the image is not a multiple of the sector size, the tail bits are not exposed.
@@ -81,13 +82,13 @@ impl DiskProperties {
8182
Ok(Self {
8283
cache_type,
8384
nsectors: disk_size >> SECTOR_SHIFT,
84-
image_id: Self::build_disk_image_id(&disk_image),
85+
image_id: disk_image_id,
8586
file: disk_image,
8687
})
8788
}
8889

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()
9192
}
9293

9394
pub fn nsectors(&self) -> u64 {
@@ -141,7 +142,7 @@ impl Drop for DiskProperties {
141142
error!("Failed to flush block data on drop.");
142143
}
143144
// Sync data out to physical media on host.
144-
if self.file.sync_all().is_err() {
145+
if self.file.sync().is_err() {
145146
error!("Failed to sync block data on drop.")
146147
}
147148
}
@@ -168,8 +169,8 @@ pub struct Block {
168169
// Host file and properties.
169170
disk: Option<DiskProperties>,
170171
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>,
173174
worker_thread: Option<JoinHandle<()>>,
174175
worker_stopfd: EventFd,
175176

@@ -205,8 +206,31 @@ impl Block {
205206
disk_image_path: String,
206207
is_disk_read_only: bool,
207208
) -> 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+
208232
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)?;
210234

211235
let mut avail_features = (1u64 << VIRTIO_F_VERSION_1)
212236
| (1u64 << VIRTIO_BLK_F_FLUSH)
@@ -234,8 +258,8 @@ impl Block {
234258
config,
235259
disk: Some(disk_properties),
236260
cache_type,
237-
disk_image_path,
238-
is_disk_read_only,
261+
disk_image,
262+
disk_image_id,
239263
avail_features,
240264
acked_features: 0u64,
241265
interrupt_status: Arc::new(AtomicUsize::new(0)),
@@ -348,8 +372,8 @@ impl VirtioDevice for Block {
348372
let disk = match self.disk.take() {
349373
Some(d) => d,
350374
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(),
353377
self.cache_type,
354378
)
355379
.map_err(|_| ActivateError::BadActivate)?,

src/devices/src/virtio/block/worker.rs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,7 +228,7 @@ impl BlockWorker {
228228
Err(RequestError::InvalidDataLength)
229229
} else {
230230
writer
231-
.write_from_at(&self.disk.file, data_len, request_header.sector * 512)
231+
.write_from_at(self.disk.file(), data_len, request_header.sector * 512)
232232
.map_err(RequestError::WritingToDescriptor)
233233
}
234234
}
@@ -238,15 +238,15 @@ impl BlockWorker {
238238
Err(RequestError::InvalidDataLength)
239239
} else {
240240
reader
241-
.read_to_at(&self.disk.file, data_len, request_header.sector * 512)
241+
.read_to_at(self.disk.file(), data_len, request_header.sector * 512)
242242
.map_err(RequestError::ReadingFromDescriptor)
243243
}
244244
}
245245
VIRTIO_BLK_T_FLUSH => match self.disk.cache_type() {
246246
CacheType::Writeback => {
247-
let diskfile = self.disk.file_mut();
247+
let diskfile = self.disk.file();
248248
diskfile.flush().map_err(RequestError::FlushingToDisk)?;
249-
diskfile.sync_all().map_err(RequestError::FlushingToDisk)?;
249+
diskfile.sync().map_err(RequestError::FlushingToDisk)?;
250250
Ok(0)
251251
}
252252
CacheType::Unsafe => Ok(0),

src/devices/src/virtio/file_traits.rs

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -425,14 +425,13 @@ impl FileReadWriteAtVolatile for imago::SyncFormatAccess<imago::file::File> {
425425
return Ok(0);
426426
}
427427

428-
let mut offset = offset as usize;
429-
let mut read = 0;
430-
for buf in bufs {
431-
let bytes = self.read_at_volatile(*buf, offset as u64)?;
432-
offset += bytes;
433-
read += bytes;
434-
}
435-
Ok(read)
428+
let (iovec, _guard) = imago::io_buffers::IoVectorMut::from_volatile_slice(bufs);
429+
let full_length = iovec
430+
.len()
431+
.try_into()
432+
.map_err(|e| Error::new(ErrorKind::InvalidData, e))?;
433+
self.readv(iovec, offset)?;
434+
Ok(full_length)
436435
}
437436

438437
fn write_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<usize> {
@@ -447,13 +446,12 @@ impl FileReadWriteAtVolatile for imago::SyncFormatAccess<imago::file::File> {
447446
return Ok(0);
448447
}
449448

450-
let mut offset = offset as usize;
451-
let mut written = 0;
452-
for buf in bufs {
453-
let bytes = self.write_at_volatile(*buf, offset as u64)?;
454-
offset += bytes;
455-
written += bytes;
456-
}
457-
Ok(written)
449+
let (iovec, _guard) = imago::io_buffers::IoVector::from_volatile_slice(bufs);
450+
let full_length = iovec
451+
.len()
452+
.try_into()
453+
.map_err(|e| Error::new(ErrorKind::InvalidData, e))?;
454+
self.writev(iovec, offset)?;
455+
Ok(full_length)
458456
}
459457
}

0 commit comments

Comments
 (0)