diff options
author | A. Cody Schuffelen <schuffelen@google.com> | 2019-12-26 12:28:11 -0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2020-02-21 21:52:56 +0000 |
commit | d8144a56e26ca09e2c7ff97ed63c57e7e7965674 (patch) | |
tree | 86ae5e5d11c74984f125d7cc3e303f973c53dfc7 /disk/src | |
parent | 9ca6039b030a5c83062cfec9a5ff52f42814fa13 (diff) | |
download | crosvm-d8144a56e26ca09e2c7ff97ed63c57e7e7965674.tar crosvm-d8144a56e26ca09e2c7ff97ed63c57e7e7965674.tar.gz crosvm-d8144a56e26ca09e2c7ff97ed63c57e7e7965674.tar.bz2 crosvm-d8144a56e26ca09e2c7ff97ed63c57e7e7965674.tar.lz crosvm-d8144a56e26ca09e2c7ff97ed63c57e7e7965674.tar.xz crosvm-d8144a56e26ca09e2c7ff97ed63c57e7e7965674.tar.zst crosvm-d8144a56e26ca09e2c7ff97ed63c57e7e7965674.zip |
Read from the backing file if present on read miss
Reads to qcow files with backing files will fall through to the backing file if there is no allocated cluster. As of this change, a write will still trash the cluster and hide any data already present. TEST=unit tests BUG=b:140069322 Change-Id: Iba353fa1e7c25bb6267eb96b30b8f5a6ac61d423 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/crosvm/+/1982831 Tested-by: kokoro <noreply+kokoro@google.com> Commit-Queue: Daniel Verkamp <dverkamp@chromium.org> Reviewed-by: Daniel Verkamp <dverkamp@chromium.org>
Diffstat (limited to 'disk/src')
-rw-r--r-- | disk/src/qcow/mod.rs | 35 |
1 files changed, 30 insertions, 5 deletions
diff --git a/disk/src/qcow/mod.rs b/disk/src/qcow/mod.rs index 1e3a451..dfc8acd 100644 --- a/disk/src/qcow/mod.rs +++ b/disk/src/qcow/mod.rs @@ -620,6 +620,10 @@ impl QcowFile { Ok(qcow) } + pub fn set_backing_file(&mut self, backing: Option<Box<dyn DiskFile>>) { + self.backing_file = backing; + } + /// Returns the `QcowHeader` for this file. pub fn header(&self) -> &QcowHeader { &self.header @@ -1459,6 +1463,8 @@ impl QcowFile { if let Some(offset) = file_offset { cb(Some(self.raw_file.file_mut()), nread, offset, count)?; + } else if let Some(backing) = self.backing_file.as_mut() { + cb(Some(backing.as_mut()), nread, curr_addr, count)?; } else { cb(None, nread, 0, count)?; } @@ -1795,17 +1801,20 @@ mod tests { ] } - fn with_basic_file<F>(header: &[u8], mut testfn: F) - where - F: FnMut(File), - { + fn basic_file(header: &[u8]) -> File { let shm = SharedMemory::anon().unwrap(); let mut disk_file: File = shm.into(); disk_file.write_all(&header).unwrap(); disk_file.set_len(0x1_0000_0000).unwrap(); disk_file.seek(SeekFrom::Start(0)).unwrap(); + disk_file + } - testfn(disk_file); // File closed when the function exits. + fn with_basic_file<F>(header: &[u8], mut testfn: F) + where + F: FnMut(File), + { + testfn(basic_file(header)); // File closed when the function exits. } fn with_default_file<F>(file_size: u64, mut testfn: F) @@ -1971,6 +1980,22 @@ mod tests { } #[test] + fn write_read_start_backing() { + let disk_file = basic_file(&valid_header()); + let mut backing = QcowFile::from(disk_file).unwrap(); + backing + .write(b"test first bytes") + .expect("Failed to write test string."); + let mut buf = [0u8; 4]; + let wrapping_disk_file = basic_file(&valid_header()); + let mut wrapping = QcowFile::from(wrapping_disk_file).unwrap(); + wrapping.set_backing_file(Some(Box::new(backing))); + wrapping.seek(SeekFrom::Start(0)).expect("Failed to seek."); + wrapping.read(&mut buf).expect("Failed to read."); + assert_eq!(&buf, b"test"); + } + + #[test] fn offset_write_read() { with_basic_file(&valid_header(), |disk_file: File| { let mut q = QcowFile::from(disk_file).unwrap(); |