From 977f873a4140c29f838712e6f37137df4f0cd840 Mon Sep 17 00:00:00 2001 From: Daniel Verkamp Date: Wed, 15 Jan 2020 12:53:43 -0800 Subject: sys_util: add FileAllocate trait This trait provides a generic interface for allocating space on the filesystem within a given file. It is equivalent to the fallocate(2) system call with the default mode (mode = 0). BUG=chromium:858815 TEST=cargo build --features=composite-disk Change-Id: I2f4e8aceb4878790e8dec2e3d539071915efd205 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/2015828 Reviewed-by: Dylan Reid Tested-by: kokoro Commit-Queue: Daniel Verkamp --- disk/src/composite.rs | 25 ++++++++++++++++++++++++- disk/src/disk.rs | 5 ++++- disk/src/qcow/mod.rs | 13 +++++++++++-- sys_util/src/file_traits.rs | 16 ++++++++++++++++ sys_util/src/lib.rs | 5 ++++- 5 files changed, 59 insertions(+), 5 deletions(-) diff --git a/disk/src/composite.rs b/disk/src/composite.rs index c3cca00..cd048c1 100644 --- a/disk/src/composite.rs +++ b/disk/src/composite.rs @@ -13,7 +13,9 @@ use crate::{create_disk_file, DiskFile, DiskGetLen, ImageType}; use data_model::VolatileSlice; use protos::cdisk_spec; use remain::sorted; -use sys_util::{AsRawFds, FileReadWriteAtVolatile, FileSetLen, FileSync, PunchHole, WriteZeroesAt}; +use sys_util::{ + AsRawFds, FileAllocate, FileReadWriteAtVolatile, FileSetLen, FileSync, PunchHole, WriteZeroesAt, +}; #[sorted] #[derive(Debug)] @@ -292,6 +294,27 @@ impl PunchHole for CompositeDiskFile { } } +impl FileAllocate for CompositeDiskFile { + fn allocate(&mut self, offset: u64, length: u64) -> io::Result<()> { + let range = offset..(offset + length); + let disks = self.disks_in_range(&range); + for disk in disks { + let intersection = range_intersection(&range, &disk.range()); + if intersection.start >= intersection.end { + continue; + } + let result = disk.file.allocate( + intersection.start - disk.offset, + intersection.end - intersection.start, + ); + if result.is_err() { + return result; + } + } + Ok(()) + } +} + impl WriteZeroesAt for CompositeDiskFile { fn write_zeroes_at(&mut self, offset: u64, length: usize) -> io::Result { let cursor_location = offset; diff --git a/disk/src/disk.rs b/disk/src/disk.rs index 49b8127..2f9ad72 100644 --- a/disk/src/disk.rs +++ b/disk/src/disk.rs @@ -10,7 +10,8 @@ use std::io::{self, Read, Seek, SeekFrom, Write}; use libc::EINVAL; use remain::sorted; use sys_util::{ - AsRawFds, FileReadWriteAtVolatile, FileSetLen, FileSync, PunchHole, SeekHole, WriteZeroesAt, + AsRawFds, FileAllocate, FileReadWriteAtVolatile, FileSetLen, FileSync, PunchHole, SeekHole, + WriteZeroesAt, }; mod qcow; @@ -64,6 +65,7 @@ pub trait DiskFile: + FileReadWriteAtVolatile + PunchHole + WriteZeroesAt + + FileAllocate + Send + AsRawFds + Debug @@ -76,6 +78,7 @@ impl< + PunchHole + FileReadWriteAtVolatile + WriteZeroesAt + + FileAllocate + Send + AsRawFds + Debug, diff --git a/disk/src/qcow/mod.rs b/disk/src/qcow/mod.rs index b1df192..add4f48 100644 --- a/disk/src/qcow/mod.rs +++ b/disk/src/qcow/mod.rs @@ -10,8 +10,8 @@ use data_model::{VolatileMemory, VolatileSlice}; use libc::{EINVAL, ENOSPC, ENOTSUP}; use remain::sorted; use sys_util::{ - error, FileReadWriteAtVolatile, FileReadWriteVolatile, FileSetLen, FileSync, PunchHole, - SeekHole, WriteZeroesAt, + error, FileAllocate, FileReadWriteAtVolatile, FileReadWriteVolatile, FileSetLen, FileSync, + PunchHole, SeekHole, WriteZeroesAt, }; use std::cmp::{max, min}; @@ -1582,6 +1582,15 @@ impl DiskGetLen for QcowFile { } } +impl FileAllocate for QcowFile { + fn allocate(&mut self, offset: u64, len: u64) -> io::Result<()> { + // Call write_cb with a do-nothing callback, which will have the effect + // of allocating all clusters in the specified range. + self.write_cb(offset, len as usize, |_file, _offset, _count| Ok(()))?; + Ok(()) + } +} + impl PunchHole for QcowFile { fn punch_hole(&mut self, offset: u64, length: u64) -> std::io::Result<()> { let mut remaining = length; diff --git a/sys_util/src/file_traits.rs b/sys_util/src/file_traits.rs index 7e615d6..54e710f 100644 --- a/sys_util/src/file_traits.rs +++ b/sys_util/src/file_traits.rs @@ -8,6 +8,8 @@ use std::os::unix::io::{AsRawFd, RawFd}; use data_model::VolatileSlice; +use crate::{fallocate, FallocateMode}; + /// A trait for flushing the contents of a file to disk. /// This is equivalent to File's `sync_all` method, but /// wrapped in a trait so that it can be implemented for @@ -54,6 +56,20 @@ impl FileGetLen for File { } } +/// A trait for allocating disk space in a sparse file. +/// This is equivalent to fallocate() with no special flags. +pub trait FileAllocate { + /// Allocate storage for the region of the file starting at `offset` and extending `len` bytes. + fn allocate(&mut self, offset: u64, len: u64) -> Result<()>; +} + +impl FileAllocate for File { + fn allocate(&mut self, offset: u64, len: u64) -> Result<()> { + fallocate(self, FallocateMode::Allocate, true, offset, len) + .map_err(|e| Error::from_raw_os_error(e.errno())) + } +} + /// A trait similar to `Read` and `Write`, but uses volatile memory as buffers. pub trait FileReadWriteVolatile { /// Read bytes from this file into the given slice, returning the number of bytes read on diff --git a/sys_util/src/lib.rs b/sys_util/src/lib.rs index bde5eb2..357e6b4 100644 --- a/sys_util/src/lib.rs +++ b/sys_util/src/lib.rs @@ -64,7 +64,8 @@ pub use crate::timerfd::*; pub use poll_token_derive::*; pub use crate::file_traits::{ - AsRawFds, FileGetLen, FileReadWriteAtVolatile, FileReadWriteVolatile, FileSetLen, FileSync, + AsRawFds, FileAllocate, FileGetLen, FileReadWriteAtVolatile, FileReadWriteVolatile, FileSetLen, + FileSync, }; pub use crate::guest_memory::Error as GuestMemoryError; pub use crate::mmap::Error as MmapError; @@ -175,6 +176,7 @@ pub fn flock(file: &dyn AsRawFd, op: FlockOperation, nonblocking: bool) -> Resul pub enum FallocateMode { PunchHole, ZeroRange, + Allocate, } /// Safe wrapper for `fallocate()`. @@ -200,6 +202,7 @@ pub fn fallocate( let mut mode = match mode { FallocateMode::PunchHole => libc::FALLOC_FL_PUNCH_HOLE, FallocateMode::ZeroRange => libc::FALLOC_FL_ZERO_RANGE, + FallocateMode::Allocate => 0, }; if keep_size { -- cgit 1.4.1