Skip to content

Commit b05ca88

Browse files
committed
Use SyncFormatAccess<ImagoFile> in DiskProperties
Changes the `file` attribute in `DiskProperties` to use `Arc<SyncFormatAccess<ImagoFile>>`. This allows libkrun to take advantage of imago's support for multiple disk image formats. Libkrun now supports the use of Raw or QCOW2 formats for disk images. Implements `FileReadWriteAtVolatile` trait on `DiskProperties` Signed-off-by: Jake Correnti <[email protected]>
1 parent 6720e98 commit b05ca88

File tree

3 files changed

+93
-24
lines changed

3 files changed

+93
-24
lines changed

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

Lines changed: 40 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::{
@@ -51,22 +54,18 @@ pub enum CacheType {
5154
/// Helper object for setting up all `Block` fields derived from its backing file.
5255
pub(crate) struct DiskProperties {
5356
cache_type: CacheType,
54-
pub(crate) file: File,
57+
pub(crate) file: Arc<SyncFormatAccess<ImagoFile>>,
5558
nsectors: u64,
5659
image_id: Vec<u8>,
5760
}
5861

5962
impl DiskProperties {
6063
pub fn new(
61-
disk_image_path: String,
62-
is_disk_read_only: bool,
64+
disk_image: Arc<SyncFormatAccess<ImagoFile>>,
65+
disk_image_id: Vec<u8>,
6366
cache_type: CacheType,
6467
) -> 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))?;
68+
let disk_size = disk_image.size();
7069

7170
// We only support disk size, which uses the first two words of the configuration space.
7271
// If the image is not a multiple of the sector size, the tail bits are not exposed.
@@ -81,13 +80,13 @@ impl DiskProperties {
8180
Ok(Self {
8281
cache_type,
8382
nsectors: disk_size >> SECTOR_SHIFT,
84-
image_id: Self::build_disk_image_id(&disk_image),
83+
image_id: disk_image_id,
8584
file: disk_image,
8685
})
8786
}
8887

89-
pub fn file_mut(&mut self) -> &mut File {
90-
&mut self.file
88+
pub fn file(&self) -> &SyncFormatAccess<ImagoFile> {
89+
self.file.as_ref()
9190
}
9291

9392
pub fn nsectors(&self) -> u64 {
@@ -141,7 +140,7 @@ impl Drop for DiskProperties {
141140
error!("Failed to flush block data on drop.");
142141
}
143142
// Sync data out to physical media on host.
144-
if self.file.sync_all().is_err() {
143+
if self.file.sync().is_err() {
145144
error!("Failed to sync block data on drop.")
146145
}
147146
}
@@ -168,8 +167,8 @@ pub struct Block {
168167
// Host file and properties.
169168
disk: Option<DiskProperties>,
170169
cache_type: CacheType,
171-
disk_image_path: String,
172-
is_disk_read_only: bool,
170+
disk_image: Arc<SyncFormatAccess<ImagoFile>>,
171+
disk_image_id: Vec<u8>,
173172
worker_thread: Option<JoinHandle<()>>,
174173
worker_stopfd: EventFd,
175174

@@ -206,8 +205,29 @@ impl Block {
206205
disk_image_format: disk::ImageType,
207206
is_disk_read_only: bool,
208207
) -> io::Result<Block> {
208+
let disk_image = OpenOptions::new()
209+
.read(true)
210+
.write(!is_disk_read_only)
211+
.open(PathBuf::from(&disk_image_path))?;
212+
213+
let disk_image_id = DiskProperties::build_disk_image_id(&disk_image);
214+
215+
let disk_image = match disk_image_format {
216+
disk::ImageType::Qcow2 => {
217+
let mut qcow_disk_image =
218+
Qcow2::<ImagoFile>::open_path_sync(disk_image_path, !is_disk_read_only)?;
219+
qcow_disk_image.open_implicit_dependencies_sync()?;
220+
SyncFormatAccess::new(qcow_disk_image)?
221+
}
222+
disk::ImageType::Raw => {
223+
let raw = imago::raw::Raw::open_path_sync(disk_image_path, !is_disk_read_only)?;
224+
SyncFormatAccess::new(raw)?
225+
}
226+
};
227+
let disk_image = Arc::new(disk_image);
228+
209229
let disk_properties =
210-
DiskProperties::new(disk_image_path.clone(), is_disk_read_only, cache_type)?;
230+
DiskProperties::new(Arc::clone(&disk_image), disk_image_id.clone(), cache_type)?;
211231

212232
let mut avail_features = (1u64 << VIRTIO_F_VERSION_1)
213233
| (1u64 << VIRTIO_BLK_F_FLUSH)
@@ -235,8 +255,8 @@ impl Block {
235255
config,
236256
disk: Some(disk_properties),
237257
cache_type,
238-
disk_image_path,
239-
is_disk_read_only,
258+
disk_image,
259+
disk_image_id,
240260
avail_features,
241261
acked_features: 0u64,
242262
interrupt_status: Arc::new(AtomicUsize::new(0)),
@@ -349,8 +369,8 @@ impl VirtioDevice for Block {
349369
let disk = match self.disk.take() {
350370
Some(d) => d,
351371
None => DiskProperties::new(
352-
self.disk_image_path.clone(),
353-
self.is_disk_read_only,
372+
Arc::clone(&self.disk_image),
373+
self.disk_image_id.clone(),
354374
self.cache_type,
355375
)
356376
.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, 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, 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: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,15 @@ use std::fs::File;
66
use std::io::{Error, ErrorKind, Result};
77
use std::os::unix::io::AsRawFd;
88

9+
#[cfg(feature = "blk")]
10+
use imago::io_buffers::{IoVector, IoVectorMut};
911
use vm_memory::VolatileSlice;
1012

1113
use libc::{c_int, c_void, read, readv, size_t, write, writev};
1214

1315
use super::bindings::{off64_t, pread64, preadv64, pwrite64, pwritev64};
16+
#[cfg(feature = "blk")]
17+
use super::block::device::DiskProperties;
1418

1519
/// A trait for setting the size of a file.
1620
/// This is equivalent to File's `set_len` method, but
@@ -411,3 +415,48 @@ macro_rules! volatile_impl {
411415
}
412416

413417
volatile_impl!(File);
418+
419+
#[cfg(feature = "blk")]
420+
impl FileReadWriteAtVolatile for DiskProperties {
421+
fn read_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<usize> {
422+
let slices = &[&slice];
423+
let iovec = IoVectorMut::from_volatile_slice(slices);
424+
self.file().readv(iovec.0, offset)?;
425+
Ok(slice.len())
426+
}
427+
428+
fn read_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
429+
if bufs.is_empty() {
430+
return Ok(0);
431+
}
432+
433+
let (iovec, _guard) = IoVectorMut::from_volatile_slice(bufs);
434+
let full_length = iovec
435+
.len()
436+
.try_into()
437+
.map_err(|e| Error::new(ErrorKind::InvalidData, e))?;
438+
self.file().readv(iovec, offset)?;
439+
Ok(full_length)
440+
}
441+
442+
fn write_at_volatile(&self, slice: VolatileSlice, offset: u64) -> Result<usize> {
443+
let slices = &[&slice];
444+
let iovec = IoVector::from_volatile_slice(slices);
445+
self.file().writev(iovec.0, offset)?;
446+
Ok(slice.len())
447+
}
448+
449+
fn write_vectored_at_volatile(&self, bufs: &[VolatileSlice], offset: u64) -> Result<usize> {
450+
if bufs.is_empty() {
451+
return Ok(0);
452+
}
453+
454+
let (iovec, _guard) = IoVector::from_volatile_slice(bufs);
455+
let full_length = iovec
456+
.len()
457+
.try_into()
458+
.map_err(|e| Error::new(ErrorKind::InvalidData, e))?;
459+
self.file().writev(iovec, offset)?;
460+
Ok(full_length)
461+
}
462+
}

0 commit comments

Comments
 (0)