mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
block: Convert qcow raw file table and cluster writes to positional
Replace the seek then read/write metadata access in QcowRawFile with positional read_exact_at, write_all_at, and write_all_zeroes_at on the AlignedFile. read_pointer_table, write_pointer_table, write_pointer_table_direct, zero_cluster, and write_cluster no longer move the file cursor. These calls still route through AlignedFile, which implements FileExt and WriteZeroesAt with the O_DIRECT alignment bounce, so the unaligned behavior is preserved. Each access already issued an absolute seek before touching the file, so the cursor never carried state between calls and dropping it is unobservable. Decoding the pointer table now uses native from_be_bytes over the read buffer, matching the to_be_bytes path on the write side. Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
This commit is contained in:
@@ -7,9 +7,10 @@
|
|||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::io::{self, BufWriter, Read, Seek, SeekFrom, Write};
|
use std::io::{self, BufWriter, Read, Seek, SeekFrom, Write};
|
||||||
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, RawFd};
|
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, RawFd};
|
||||||
|
use std::os::unix::fs::FileExt;
|
||||||
|
|
||||||
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
|
||||||
use vmm_sys_util::write_zeroes::WriteZeroes;
|
use vmm_sys_util::write_zeroes::WriteZeroesAt;
|
||||||
|
|
||||||
use crate::aligned_file::AlignedFile;
|
use crate::aligned_file::AlignedFile;
|
||||||
|
|
||||||
@@ -205,14 +206,13 @@ impl QcowRawFile {
|
|||||||
count: u64,
|
count: u64,
|
||||||
mask: Option<u64>,
|
mask: Option<u64>,
|
||||||
) -> io::Result<Vec<u64>> {
|
) -> io::Result<Vec<u64>> {
|
||||||
let mut table = vec![0; count as usize];
|
let mut bytes = vec![0u8; count as usize * size_of::<u64>()];
|
||||||
self.file.seek(SeekFrom::Start(offset))?;
|
self.file.read_exact_at(&mut bytes, offset)?;
|
||||||
self.file.read_u64_into::<BigEndian>(&mut table)?;
|
let m = mask.unwrap_or(u64::MAX);
|
||||||
if let Some(m) = mask {
|
let table = bytes
|
||||||
for ptr in &mut table {
|
.chunks_exact(size_of::<u64>())
|
||||||
*ptr &= m;
|
.map(|c| u64::from_be_bytes(c.try_into().unwrap()) & m)
|
||||||
}
|
.collect();
|
||||||
}
|
|
||||||
Ok(table)
|
Ok(table)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -227,7 +227,7 @@ impl QcowRawFile {
|
|||||||
/// Entries are computed on-the-fly by the callback.
|
/// Entries are computed on-the-fly by the callback.
|
||||||
///
|
///
|
||||||
/// The callback may perform metadata I/O on this `QcowRawFile`, so all
|
/// The callback may perform metadata I/O on this `QcowRawFile`, so all
|
||||||
/// entries are materialized before seeking to the final write offset.
|
/// entries are materialized before the final positional write.
|
||||||
pub fn write_pointer_table<'a, T: Copy + 'a>(
|
pub fn write_pointer_table<'a, T: Copy + 'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
offset: u64,
|
offset: u64,
|
||||||
@@ -239,8 +239,7 @@ impl QcowRawFile {
|
|||||||
let entry = f(self, *addr)?;
|
let entry = f(self, *addr)?;
|
||||||
buffer.extend_from_slice(&entry.to_be_bytes());
|
buffer.extend_from_slice(&entry.to_be_bytes());
|
||||||
}
|
}
|
||||||
self.file.seek(SeekFrom::Start(offset))?;
|
self.file.write_all_at(&buffer, offset)
|
||||||
self.file.write_all(&buffer)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes a pointer table directly without transforming values.
|
/// Writes a pointer table directly without transforming values.
|
||||||
@@ -255,8 +254,7 @@ impl QcowRawFile {
|
|||||||
for &entry in entries {
|
for &entry in entries {
|
||||||
buffer.extend_from_slice(&entry.to_be_bytes());
|
buffer.extend_from_slice(&entry.to_be_bytes());
|
||||||
}
|
}
|
||||||
self.file.seek(SeekFrom::Start(offset))?;
|
self.file.write_all_at(&buffer, offset)
|
||||||
self.file.write_all(&buffer)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read a refcount block from the file and returns a Vec containing the block.
|
/// Read a refcount block from the file and returns a Vec containing the block.
|
||||||
@@ -318,16 +316,14 @@ impl QcowRawFile {
|
|||||||
/// Zeros out a cluster in the file.
|
/// Zeros out a cluster in the file.
|
||||||
pub fn zero_cluster(&mut self, address: u64) -> io::Result<()> {
|
pub fn zero_cluster(&mut self, address: u64) -> io::Result<()> {
|
||||||
let cluster_size = self.cluster_size as usize;
|
let cluster_size = self.cluster_size as usize;
|
||||||
self.file.seek(SeekFrom::Start(address))?;
|
self.file.write_all_zeroes_at(address, cluster_size)?;
|
||||||
self.file.write_zeroes(cluster_size)?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes
|
/// Writes
|
||||||
pub fn write_cluster(&mut self, address: u64, data: &[u8]) -> io::Result<()> {
|
pub fn write_cluster(&mut self, address: u64, data: &[u8]) -> io::Result<()> {
|
||||||
let cluster_size = self.cluster_size as usize;
|
let cluster_size = self.cluster_size as usize;
|
||||||
self.file.seek(SeekFrom::Start(address))?;
|
self.file.write_all_at(&data[0..cluster_size], address)
|
||||||
self.file.write_all(&data[0..cluster_size])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn physical_size(&self) -> io::Result<u64> {
|
pub fn physical_size(&self) -> io::Result<u64> {
|
||||||
|
|||||||
Reference in New Issue
Block a user