Extract disk creation logic out of qcow and src.

Bug: b/133432409
Change-Id: Iba25d5f6bb5f60619bb2f5a3d72ddfd3a81650b4
Signed-off-by: Cody Schuffelen <schuffelen@google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1691460
Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Tested-by: kokoro <noreply+kokoro@google.com>
This commit is contained in:
Cody Schuffelen 2019-07-02 16:54:05 -07:00 committed by Commit Bot
parent 971589f7ec
commit 7d533e5952
12 changed files with 277 additions and 199 deletions

13
Cargo.lock generated
View file

@ -85,6 +85,7 @@ dependencies = [
"crosvm_plugin 0.17.0",
"data_model 0.1.0",
"devices 0.1.0",
"disk 0.1.0",
"enumn 0.1.0",
"gpu_buffer 0.1.0",
"io_jail 0.1.0",
@ -137,6 +138,7 @@ dependencies = [
"audio_streams 0.1.0",
"bit_field 0.1.0",
"data_model 0.1.0",
"disk 0.1.0",
"enumn 0.1.0",
"gpu_buffer 0.1.0",
"gpu_display 0.1.0",
@ -162,6 +164,16 @@ dependencies = [
"vm_control 0.1.0",
]
[[package]]
name = "disk"
version = "0.1.0"
dependencies = [
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
"qcow 0.1.0",
"remain 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"sys_util 0.1.0",
]
[[package]]
name = "enumn"
version = "0.1.0"
@ -397,6 +409,7 @@ dependencies = [
name = "qcow_utils"
version = "0.1.0"
dependencies = [
"disk 0.1.0",
"getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
"qcow 0.1.0",

View file

@ -45,6 +45,7 @@ bit_field = { path = "bit_field" }
crosvm_plugin = { path = "crosvm_plugin", optional = true }
data_model = "*"
devices = { path = "devices" }
disk = { path = "disk" }
enumn = { path = "enumn" }
gpu_buffer = { path = "gpu_buffer", optional = true }
io_jail = { path = "io_jail" }

View file

@ -15,6 +15,7 @@ x = ["gpu_display/x"]
audio_streams = "*"
bit_field = { path = "../bit_field" }
data_model = { path = "../data_model" }
disk = { path = "../disk" }
enumn = { path = "../enumn" }
gpu_buffer = { path = "../gpu_buffer", optional = true }
gpu_display = { path = "../gpu_display", optional = true }

View file

@ -13,16 +13,13 @@ use std::thread;
use std::time::Duration;
use std::u32;
use data_model::{DataInit, Le16, Le32, Le64};
use disk::DiskFile;
use msg_socket::{MsgReceiver, MsgSender};
use sync::Mutex;
use sys_util::Error as SysError;
use sys_util::Result as SysResult;
use sys_util::{
error, info, warn, EventFd, FileReadWriteVolatile, FileSetLen, FileSync, GuestMemory,
PollContext, PollToken, PunchHole, TimerFd, WriteZeroes,
};
use data_model::{DataInit, Le16, Le32, Le64};
use msg_socket::{MsgReceiver, MsgSender};
use sys_util::{error, info, warn, EventFd, GuestMemory, PollContext, PollToken, TimerFd};
use vm_control::{DiskControlCommand, DiskControlResponseSocket, DiskControlResult};
use super::{
@ -129,15 +126,6 @@ const VIRTIO_BLK_DISCARD_WRITE_ZEROES_FLAG_UNMAP: u32 = 1 << 0;
// Safe because it only has data and has no implicit padding.
unsafe impl DataInit for virtio_blk_discard_write_zeroes {}
pub trait DiskFile:
FileSetLen + FileSync + FileReadWriteVolatile + PunchHole + Seek + WriteZeroes
{
}
impl<D: FileSetLen + FileSync + PunchHole + FileReadWriteVolatile + Seek + WriteZeroes> DiskFile
for D
{
}
#[derive(Debug)]
enum ExecuteError {
Descriptor(DescriptorError),
@ -275,10 +263,10 @@ impl ExecuteError {
}
}
struct Worker<T: DiskFile> {
struct Worker {
queues: Vec<Queue>,
mem: GuestMemory,
disk_image: T,
disk_image: Box<dyn DiskFile>,
disk_size: Arc<Mutex<u64>>,
read_only: bool,
interrupt_status: Arc<AtomicUsize>,
@ -286,7 +274,7 @@ struct Worker<T: DiskFile> {
interrupt_resample_evt: EventFd,
}
impl<T: DiskFile> Worker<T> {
impl Worker {
fn process_queue(
&mut self,
queue_index: usize,
@ -305,7 +293,7 @@ impl<T: DiskFile> Worker<T> {
let status = match Block::execute_request(
avail_desc,
self.read_only,
&mut self.disk_image,
&mut *self.disk_image,
*disk_size,
flush_timer,
flush_timer_armed,
@ -480,9 +468,9 @@ impl<T: DiskFile> Worker<T> {
}
/// Virtio device for exposing block level read/write operations on a host file.
pub struct Block<T: DiskFile> {
pub struct Block {
kill_evt: Option<EventFd>,
disk_image: Option<T>,
disk_image: Option<Box<dyn DiskFile>>,
disk_size: Arc<Mutex<u64>>,
avail_features: u64,
read_only: bool,
@ -504,15 +492,15 @@ fn build_config_space(disk_size: u64) -> virtio_blk_config {
}
}
impl<T: DiskFile> Block<T> {
impl Block {
/// Create a new virtio block device that operates on the given file.
///
/// The given file must be seekable and sizable.
pub fn new(
mut disk_image: T,
mut disk_image: Box<dyn DiskFile>,
read_only: bool,
control_socket: Option<DiskControlResponseSocket>,
) -> SysResult<Block<T>> {
) -> SysResult<Block> {
let disk_size = disk_image.seek(SeekFrom::End(0))? as u64;
if disk_size % SECTOR_SIZE != 0 {
warn!(
@ -545,7 +533,7 @@ impl<T: DiskFile> Block<T> {
fn execute_request(
avail_desc: DescriptorChain,
read_only: bool,
disk: &mut T,
disk: &mut DiskFile,
disk_size: u64,
flush_timer: &mut TimerFd,
flush_timer_armed: &mut bool,
@ -705,7 +693,7 @@ impl<T: DiskFile> Block<T> {
}
}
impl<T: DiskFile> Drop for Block<T> {
impl Drop for Block {
fn drop(&mut self) {
if let Some(kill_evt) = self.kill_evt.take() {
// Ignore the result because there is nothing we can do about it.
@ -714,7 +702,7 @@ impl<T: DiskFile> Drop for Block<T> {
}
}
impl<T: 'static + AsRawFd + DiskFile + Send> VirtioDevice for Block<T> {
impl VirtioDevice for Block {
fn keep_fds(&self) -> Vec<RawFd> {
let mut keep_fds = Vec::new();
@ -820,7 +808,7 @@ mod tests {
let f = File::create(&path).unwrap();
f.set_len(0x1000).unwrap();
let b = Block::new(f, true, None).unwrap();
let b = Block::new(Box::new(f), true, None).unwrap();
let mut num_sectors = [0u8; 4];
b.read_config(0, &mut num_sectors);
// size is 0x1000, so num_sectors is 8 (4096/512).
@ -840,7 +828,7 @@ mod tests {
// read-write block device
{
let f = File::create(&path).unwrap();
let b = Block::new(f, false, None).unwrap();
let b = Block::new(Box::new(f), false, None).unwrap();
// writable device should set VIRTIO_BLK_F_FLUSH + VIRTIO_BLK_F_DISCARD
// + VIRTIO_BLK_F_WRITE_ZEROES + VIRTIO_F_VERSION_1 + VIRTIO_BLK_F_BLK_SIZE
assert_eq!(0x100006240, b.features());
@ -849,7 +837,7 @@ mod tests {
// read-only block device
{
let f = File::create(&path).unwrap();
let b = Block::new(f, true, None).unwrap();
let b = Block::new(Box::new(f), true, None).unwrap();
// read-only device should set VIRTIO_BLK_F_FLUSH and VIRTIO_BLK_F_RO
// + VIRTIO_F_VERSION_1 + VIRTIO_BLK_F_BLK_SIZE
assert_eq!(0x100000260, b.features());

View file

@ -281,9 +281,9 @@ impl<'a> Reader<'a> {
/// Returns the number of bytes read from the descriptor chain buffer.
/// The number of bytes read can be less than `count` if there isn't
/// enough data in the descriptor chain buffer.
pub fn read_to_volatile(
pub fn read_to_volatile<T: FileReadWriteVolatile + ?Sized>(
&mut self,
dst: &mut dyn FileReadWriteVolatile,
dst: &mut T,
count: usize,
) -> Result<usize> {
let mem = self.mem;
@ -399,9 +399,9 @@ impl<'a> Writer<'a> {
/// Returns the number of bytes written to the descriptor chain buffer.
/// The number of bytes written can be less than `count` if
/// there isn't enough data in the descriptor chain buffer.
pub fn write_from_volatile(
pub fn write_from_volatile<T: FileReadWriteVolatile + ?Sized>(
&mut self,
src: &mut dyn FileReadWriteVolatile,
src: &mut T,
count: usize,
) -> Result<usize> {
let mem = self.mem;

14
disk/Cargo.toml Normal file
View file

@ -0,0 +1,14 @@
[package]
name = "disk"
version = "0.1.0"
authors = ["The Chromium OS Authors"]
edition = "2018"
[lib]
path = "src/disk.rs"
[dependencies]
libc = "*"
remain = "*"
qcow = { path = "../qcow" }
sys_util = { path = "../sys_util" }

209
disk/src/disk.rs Normal file
View file

@ -0,0 +1,209 @@
// Copyright 2019 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use std::cmp::min;
use std::fmt::{self, Display};
use std::fs::File;
use std::io::{self, Read, Seek, SeekFrom, Write};
use std::os::unix::io::AsRawFd;
use libc::EINVAL;
use qcow::{QcowFile, QCOW_MAGIC};
use remain::sorted;
use sys_util::{FileReadWriteVolatile, FileSetLen, FileSync, PunchHole, SeekHole, WriteZeroes};
#[sorted]
#[derive(Debug)]
pub enum Error {
BlockDeviceNew(sys_util::Error),
QcowError(qcow::Error),
ReadingData(io::Error),
ReadingHeader(io::Error),
SeekingFile(io::Error),
SettingFileSize(io::Error),
UnknownType,
WritingData(io::Error),
}
pub type Result<T> = std::result::Result<T, Error>;
/// The prerequisites necessary to support a block device.
pub trait DiskFile:
FileSetLen + FileSync + FileReadWriteVolatile + PunchHole + Seek + WriteZeroes + Send + AsRawFd
{
}
impl<
D: FileSetLen
+ FileSync
+ PunchHole
+ FileReadWriteVolatile
+ Seek
+ WriteZeroes
+ Send
+ AsRawFd,
> DiskFile for D
{
}
impl Display for Error {
#[remain::check]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::Error::*;
#[sorted]
match self {
BlockDeviceNew(e) => write!(f, "failed to create block device: {}", e),
QcowError(e) => write!(f, "failure in qcow: {}", e),
ReadingData(e) => write!(f, "failed to read data: {}", e),
ReadingHeader(e) => write!(f, "failed to read header: {}", e),
SeekingFile(e) => write!(f, "failed to seek file: {}", e),
SettingFileSize(e) => write!(f, "failed to set file size: {}", e),
UnknownType => write!(f, "unknown disk type"),
WritingData(e) => write!(f, "failed to write data: {}", e),
}
}
}
/// The variants of image files on the host that can be used as virtual disks.
#[derive(Debug, PartialEq, Eq)]
pub enum ImageType {
Raw,
Qcow2,
}
fn convert_copy<R, W>(reader: &mut R, writer: &mut W, offset: u64, size: u64) -> Result<()>
where
R: Read + Seek,
W: Write + Seek,
{
const CHUNK_SIZE: usize = 65536;
let mut buf = [0; CHUNK_SIZE];
let mut read_count = 0;
reader
.seek(SeekFrom::Start(offset))
.map_err(Error::SeekingFile)?;
writer
.seek(SeekFrom::Start(offset))
.map_err(Error::SeekingFile)?;
loop {
let this_count = min(CHUNK_SIZE as u64, size - read_count) as usize;
let nread = reader
.read(&mut buf[..this_count])
.map_err(Error::ReadingData)?;
writer.write(&buf[..nread]).map_err(Error::WritingData)?;
read_count += nread as u64;
if nread == 0 || read_count == size {
break;
}
}
Ok(())
}
fn convert_reader_writer<R, W>(reader: &mut R, writer: &mut W, size: u64) -> Result<()>
where
R: Read + Seek + SeekHole,
W: Write + Seek,
{
let mut offset = 0;
while offset < size {
// Find the next range of data.
let next_data = match reader.seek_data(offset).map_err(Error::SeekingFile)? {
Some(o) => o,
None => {
// No more data in the file.
break;
}
};
let next_hole = match reader.seek_hole(next_data).map_err(Error::SeekingFile)? {
Some(o) => o,
None => {
// This should not happen - there should always be at least one hole
// after any data.
return Err(Error::SeekingFile(io::Error::from_raw_os_error(EINVAL)));
}
};
let count = next_hole - next_data;
convert_copy(reader, writer, next_data, count)?;
offset = next_hole;
}
Ok(())
}
fn convert_reader<R>(reader: &mut R, dst_file: File, dst_type: ImageType) -> Result<()>
where
R: Read + Seek + SeekHole,
{
let src_size = reader.seek(SeekFrom::End(0)).map_err(Error::SeekingFile)?;
reader
.seek(SeekFrom::Start(0))
.map_err(Error::SeekingFile)?;
// Ensure the destination file is empty before writing to it.
dst_file.set_len(0).map_err(Error::SettingFileSize)?;
match dst_type {
ImageType::Qcow2 => {
let mut dst_writer = QcowFile::new(dst_file, src_size).map_err(Error::QcowError)?;
convert_reader_writer(reader, &mut dst_writer, src_size)
}
ImageType::Raw => {
let mut dst_writer = dst_file;
// Set the length of the destination file to convert it into a sparse file
// of the desired size.
dst_writer
.set_len(src_size)
.map_err(Error::SettingFileSize)?;
convert_reader_writer(reader, &mut dst_writer, src_size)
}
}
}
/// Copy the contents of a disk image in `src_file` into `dst_file`.
/// The type of `src_file` is automatically detected, and the output file type is
/// determined by `dst_type`.
pub fn convert(src_file: File, dst_file: File, dst_type: ImageType) -> Result<()> {
let src_type = detect_image_type(&src_file)?;
match src_type {
ImageType::Qcow2 => {
let mut src_reader = QcowFile::from(src_file).map_err(Error::QcowError)?;
convert_reader(&mut src_reader, dst_file, dst_type)
}
ImageType::Raw => {
// src_file is a raw file.
let mut src_reader = src_file;
convert_reader(&mut src_reader, dst_file, dst_type)
}
}
}
/// Detect the type of an image file by checking for a valid qcow2 header.
pub fn detect_image_type(file: &File) -> Result<ImageType> {
let mut f = file;
let orig_seek = f.seek(SeekFrom::Current(0)).map_err(Error::SeekingFile)?;
f.seek(SeekFrom::Start(0)).map_err(Error::SeekingFile)?;
let mut magic = [0u8; 4];
f.read_exact(&mut magic).map_err(Error::ReadingHeader)?;
let magic = u32::from_be_bytes(magic);
let image_type = if magic == QCOW_MAGIC {
ImageType::Qcow2
} else {
ImageType::Raw
};
f.seek(SeekFrom::Start(orig_seek))
.map_err(Error::SeekingFile)?;
Ok(image_type)
}
/// Inspect the image file type and create an appropriate disk file to match it.
pub fn create_disk_file(raw_image: File) -> Result<Box<dyn DiskFile>> {
let image_type = detect_image_type(&raw_image)?;
Ok(match image_type {
ImageType::Raw => Box::new(raw_image) as Box<dyn DiskFile>,
ImageType::Qcow2 => {
Box::new(QcowFile::from(raw_image).map_err(Error::QcowError)?) as Box<dyn DiskFile>
}
})
}

View file

@ -46,7 +46,6 @@ pub enum Error {
NoRefcountClusters,
NotEnoughSpaceForRefcounts,
OpeningFile(io::Error),
ReadingData(io::Error),
ReadingHeader(io::Error),
ReadingPointers(io::Error),
ReadingRefCountBlock(refcount::Error),
@ -55,14 +54,12 @@ pub enum Error {
RefcountTableOffEnd,
RefcountTableTooLarge,
SeekingFile(io::Error),
SettingFileSize(io::Error),
SettingRefcountRefcount(io::Error),
SizeTooSmallForNumberOfClusters,
TooManyL1Entries(u64),
TooManyRefcounts(u64),
UnsupportedRefcountOrder,
UnsupportedVersion(u32),
WritingData(io::Error),
WritingHeader(io::Error),
}
@ -98,7 +95,6 @@ impl Display for Error {
NoRefcountClusters => write!(f, "no refcount clusters"),
NotEnoughSpaceForRefcounts => write!(f, "not enough space for refcounts"),
OpeningFile(e) => write!(f, "failed to open file: {}", e),
ReadingData(e) => write!(f, "failed to read data: {}", e),
ReadingHeader(e) => write!(f, "failed to read header: {}", e),
ReadingPointers(e) => write!(f, "failed to read pointers: {}", e),
ReadingRefCountBlock(e) => write!(f, "failed to read ref count block: {}", e),
@ -107,29 +103,22 @@ impl Display for Error {
RefcountTableOffEnd => write!(f, "refcount table offset past file end"),
RefcountTableTooLarge => write!(f, "too many clusters specified for refcount table"),
SeekingFile(e) => write!(f, "failed to seek file: {}", e),
SettingFileSize(e) => write!(f, "failed to set file size: {}", e),
SettingRefcountRefcount(e) => write!(f, "failed to set refcount refcount: {}", e),
SizeTooSmallForNumberOfClusters => write!(f, "size too small for number of clusters"),
TooManyL1Entries(count) => write!(f, "l1 entry table too large: {}", count),
TooManyRefcounts(count) => write!(f, "ref count table too large: {}", count),
UnsupportedRefcountOrder => write!(f, "unsupported refcount order"),
UnsupportedVersion(v) => write!(f, "unsupported version: {}", v),
WritingData(e) => write!(f, "failed to write data: {}", e),
WritingHeader(e) => write!(f, "failed to write header: {}", e),
}
}
}
pub enum ImageType {
Raw,
Qcow2,
}
// Maximum data size supported.
const MAX_QCOW_FILE_SIZE: u64 = 0x01 << 44; // 16 TB.
// QCOW magic constant that starts the header.
const QCOW_MAGIC: u32 = 0x5146_49fb;
pub const QCOW_MAGIC: u32 = 0x5146_49fb;
// Default to a cluster size of 2^DEFAULT_CLUSTER_BITS
const DEFAULT_CLUSTER_BITS: u32 = 16;
// Limit clusters to reasonable sizes. Choose the same limits as qemu. Making the clusters smaller
@ -1599,129 +1588,6 @@ fn div_round_up_u32(dividend: u32, divisor: u32) -> u32 {
dividend / divisor + if dividend % divisor != 0 { 1 } else { 0 }
}
fn convert_copy<R, W>(reader: &mut R, writer: &mut W, offset: u64, size: u64) -> Result<()>
where
R: Read + Seek,
W: Write + Seek,
{
const CHUNK_SIZE: usize = 65536;
let mut buf = [0; CHUNK_SIZE];
let mut read_count = 0;
reader
.seek(SeekFrom::Start(offset))
.map_err(Error::SeekingFile)?;
writer
.seek(SeekFrom::Start(offset))
.map_err(Error::SeekingFile)?;
loop {
let this_count = min(CHUNK_SIZE as u64, size - read_count) as usize;
let nread = reader
.read(&mut buf[..this_count])
.map_err(Error::ReadingData)?;
writer.write(&buf[..nread]).map_err(Error::WritingData)?;
read_count += nread as u64;
if nread == 0 || read_count == size {
break;
}
}
Ok(())
}
fn convert_reader_writer<R, W>(reader: &mut R, writer: &mut W, size: u64) -> Result<()>
where
R: Read + Seek + SeekHole,
W: Write + Seek,
{
let mut offset = 0;
while offset < size {
// Find the next range of data.
let next_data = match reader.seek_data(offset).map_err(Error::SeekingFile)? {
Some(o) => o,
None => {
// No more data in the file.
break;
}
};
let next_hole = match reader.seek_hole(next_data).map_err(Error::SeekingFile)? {
Some(o) => o,
None => {
// This should not happen - there should always be at least one hole
// after any data.
return Err(Error::SeekingFile(io::Error::from_raw_os_error(EINVAL)));
}
};
let count = next_hole - next_data;
convert_copy(reader, writer, next_data, count)?;
offset = next_hole;
}
Ok(())
}
fn convert_reader<R>(reader: &mut R, dst_file: File, dst_type: ImageType) -> Result<()>
where
R: Read + Seek + SeekHole,
{
let src_size = reader.seek(SeekFrom::End(0)).map_err(Error::SeekingFile)?;
reader
.seek(SeekFrom::Start(0))
.map_err(Error::SeekingFile)?;
// Ensure the destination file is empty before writing to it.
dst_file.set_len(0).map_err(Error::SettingFileSize)?;
match dst_type {
ImageType::Qcow2 => {
let mut dst_writer = QcowFile::new(dst_file, src_size)?;
convert_reader_writer(reader, &mut dst_writer, src_size)
}
ImageType::Raw => {
let mut dst_writer = dst_file;
// Set the length of the destination file to convert it into a sparse file
// of the desired size.
dst_writer
.set_len(src_size)
.map_err(Error::SettingFileSize)?;
convert_reader_writer(reader, &mut dst_writer, src_size)
}
}
}
/// Copy the contents of a disk image in `src_file` into `dst_file`.
/// The type of `src_file` is automatically detected, and the output file type is
/// determined by `dst_type`.
pub fn convert(src_file: File, dst_file: File, dst_type: ImageType) -> Result<()> {
let src_type = detect_image_type(&src_file)?;
match src_type {
ImageType::Qcow2 => {
let mut src_reader = QcowFile::from(src_file)?;
convert_reader(&mut src_reader, dst_file, dst_type)
}
ImageType::Raw => {
// src_file is a raw file.
let mut src_reader = src_file;
convert_reader(&mut src_reader, dst_file, dst_type)
}
}
}
/// Detect the type of an image file by checking for a valid qcow2 header.
pub fn detect_image_type(file: &File) -> Result<ImageType> {
let mut f = file;
let orig_seek = f.seek(SeekFrom::Current(0)).map_err(Error::SeekingFile)?;
f.seek(SeekFrom::Start(0)).map_err(Error::SeekingFile)?;
let magic = read_u32_from_file(f)?;
let image_type = if magic == QCOW_MAGIC {
ImageType::Qcow2
} else {
ImageType::Raw
};
f.seek(SeekFrom::Start(orig_seek))
.map_err(Error::SeekingFile)?;
Ok(image_type)
}
#[cfg(test)]
mod tests {
use super::*;

View file

@ -15,5 +15,6 @@ path = "src/qcow_img.rs"
[dependencies]
getopts = "*"
libc = "*"
disk = { path = "../disk" }
qcow = { path = "../qcow" }
sys_util = { path = "../sys_util" }

View file

@ -304,12 +304,12 @@ fn convert(src_path: &str, dst_path: &str) -> std::result::Result<(), ()> {
};
let dst_type = if dst_path.ends_with("qcow2") {
qcow::ImageType::Qcow2
disk::ImageType::Qcow2
} else {
qcow::ImageType::Raw
disk::ImageType::Raw
};
match qcow::convert(src_file, dst_file, dst_type) {
match disk::convert(src_file, dst_file, dst_type) {
Ok(_) => {
println!("Converted {} to {}", src_path, dst_path);
Ok(())

View file

@ -13,7 +13,8 @@ use std::os::raw::{c_char, c_int};
use std::os::unix::io::FromRawFd;
use std::panic::catch_unwind;
use qcow::{ImageType, QcowFile};
use disk::ImageType;
use qcow::QcowFile;
use sys_util::{flock, FileSetLen, FlockOperation};
trait DiskFile: FileSetLen + Seek {}
@ -71,7 +72,7 @@ pub unsafe extern "C" fn expand_disk_image(path: *const c_char, virtual_size: u6
return -EIO;
}
let image_type = match qcow::detect_image_type(&raw_image) {
let image_type = match disk::detect_image_type(&raw_image) {
Ok(t) => t,
Err(_) => return -EINVAL,
};
@ -120,7 +121,7 @@ pub unsafe extern "C" fn convert_to_qcow2(src_fd: c_int, dst_fd: c_int) -> c_int
match (src_file_owned, dst_file_owned) {
(Ok(src_file), Ok(dst_file)) => {
catch_unwind(
|| match qcow::convert(src_file, dst_file, ImageType::Qcow2) {
|| match disk::convert(src_file, dst_file, ImageType::Qcow2) {
Ok(_) => 0,
Err(_) => -EIO,
},
@ -145,7 +146,7 @@ pub unsafe extern "C" fn convert_to_raw(src_fd: c_int, dst_fd: c_int) -> c_int {
match (src_file_owned, dst_file_owned) {
(Ok(src_file), Ok(dst_file)) => {
catch_unwind(|| match qcow::convert(src_file, dst_file, ImageType::Raw) {
catch_unwind(|| match disk::convert(src_file, dst_file, ImageType::Raw) {
Ok(_) => 0,
Err(_) => -EIO,
})

View file

@ -32,7 +32,6 @@ use kvm::*;
use libcras::CrasClient;
use msg_socket::{MsgError, MsgReceiver, MsgSender, MsgSocket};
use net_util::{Error as NetError, MacAddress, Tap};
use qcow::{self, ImageType, QcowFile};
use rand_ish::SimpleRng;
use remain::sorted;
use resources::{Alloc, SystemAllocator};
@ -82,6 +81,7 @@ pub enum Error {
ChownTpmStorage(sys_util::Error),
CloneEventFd(sys_util::Error),
CreateCrasClient(libcras::Error),
CreateDiskError(disk::Error),
CreateEventFd(sys_util::Error),
CreatePollContext(sys_util::Error),
CreateSignalFd(sys_util::SignalFdError),
@ -90,7 +90,6 @@ pub enum Error {
CreateTimerFd(sys_util::Error),
CreateTpmStorage(PathBuf, io::Error),
CreateUsbProvider(devices::usb::host_backend::error::Error),
DetectImageType(qcow::Error),
DeviceJail(io_jail::Error),
DevicePivotRoot(io_jail::Error),
Disk(io::Error),
@ -114,7 +113,6 @@ pub enum Error {
PmemDeviceNew(sys_util::Error),
PollContextAdd(sys_util::Error),
PollContextDelete(sys_util::Error),
QcowDeviceCreate(qcow::Error),
ReadLowmemAvailable(io::Error),
ReadLowmemMargin(io::Error),
RegisterBalloon(arch::DeviceRegistrationError),
@ -162,6 +160,7 @@ impl Display for Error {
ChownTpmStorage(e) => write!(f, "failed to chown tpm storage: {}", e),
CloneEventFd(e) => write!(f, "failed to clone eventfd: {}", e),
CreateCrasClient(e) => write!(f, "failed to create cras client: {}", e),
CreateDiskError(e) => write!(f, "failed to create virtual disk: {}", e),
CreateEventFd(e) => write!(f, "failed to create eventfd: {}", e),
CreatePollContext(e) => write!(f, "failed to create poll context: {}", e),
CreateSignalFd(e) => write!(f, "failed to create signalfd: {}", e),
@ -172,7 +171,6 @@ impl Display for Error {
write!(f, "failed to create tpm storage dir {}: {}", p.display(), e)
}
CreateUsbProvider(e) => write!(f, "failed to create usb provider: {}", e),
DetectImageType(e) => write!(f, "failed to detect disk image type: {}", e),
DeviceJail(e) => write!(f, "failed to jail device: {}", e),
DevicePivotRoot(e) => write!(f, "failed to pivot root device: {}", e),
Disk(e) => write!(f, "failed to load disk image: {}", e),
@ -203,7 +201,6 @@ impl Display for Error {
PmemDeviceNew(e) => write!(f, "failed to create pmem device: {}", e),
PollContextAdd(e) => write!(f, "failed to add fd to poll context: {}", e),
PollContextDelete(e) => write!(f, "failed to remove fd from poll context: {}", e),
QcowDeviceCreate(e) => write!(f, "failed to read qcow formatted file {}", e),
ReadLowmemAvailable(e) => write!(
f,
"failed to read /sys/kernel/mm/chromeos-low_mem/available: {}",
@ -351,25 +348,12 @@ fn create_block_device(
};
flock(&raw_image, lock_op, true).map_err(Error::DiskImageLock)?;
let image_type = qcow::detect_image_type(&raw_image).map_err(Error::DetectImageType)?;
let dev = match image_type {
ImageType::Raw => {
// Access as a raw block device.
let dev = virtio::Block::new(raw_image, disk.read_only, Some(disk_device_socket))
.map_err(Error::BlockDeviceNew)?;
Box::new(dev) as Box<dyn VirtioDevice>
}
ImageType::Qcow2 => {
// Valid qcow header present
let qcow_image = QcowFile::from(raw_image).map_err(Error::QcowDeviceCreate)?;
let dev = virtio::Block::new(qcow_image, disk.read_only, Some(disk_device_socket))
.map_err(Error::BlockDeviceNew)?;
Box::new(dev) as Box<dyn VirtioDevice>
}
};
let disk_file = disk::create_disk_file(raw_image).map_err(Error::CreateDiskError)?;
let dev = virtio::Block::new(disk_file, disk.read_only, Some(disk_device_socket))
.map_err(Error::BlockDeviceNew)?;
Ok(VirtioDeviceStub {
dev,
dev: Box::new(dev),
jail: simple_jail(&cfg, "block_device.policy")?,
})
}