mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2024-12-22 13:45:20 +00:00
block: Ensure probing reads are block size aligned
This is necessary for O_DIRECT based use of raw block devices which may require access at a larger block size than that of a sector (512 bytes.) Fixes: #5722 Signed-off-by: Rob Bradford <rbradford@rivosinc.com>
This commit is contained in:
parent
9ca2c336f2
commit
01097aa130
@ -731,24 +731,33 @@ pub enum ImageType {
|
|||||||
const QCOW_MAGIC: u32 = 0x5146_49fb;
|
const QCOW_MAGIC: u32 = 0x5146_49fb;
|
||||||
const VHDX_SIGN: u64 = 0x656C_6966_7864_6876;
|
const VHDX_SIGN: u64 = 0x656C_6966_7864_6876;
|
||||||
|
|
||||||
|
/// Read a block into memory aligned by the source block size (needed for O_DIRECT)
|
||||||
|
pub fn read_aligned_block_size(f: &mut File) -> std::io::Result<Vec<u8>> {
|
||||||
|
let blocksize = DiskTopology::probe(f)?.logical_block_size as usize;
|
||||||
|
// SAFETY: We are allocating memory that is naturally aligned (size = alignment) and we meet
|
||||||
|
// requirements for safety from Vec::from_raw_parts() as we are using the global allocator
|
||||||
|
// and transferring ownership of the memory.
|
||||||
|
let mut data = unsafe {
|
||||||
|
Vec::from_raw_parts(
|
||||||
|
alloc_zeroed(Layout::from_size_align_unchecked(blocksize, blocksize)),
|
||||||
|
blocksize,
|
||||||
|
blocksize,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
f.read_exact(&mut data)?;
|
||||||
|
Ok(data)
|
||||||
|
}
|
||||||
|
|
||||||
/// Determine image type through file parsing.
|
/// Determine image type through file parsing.
|
||||||
pub fn detect_image_type(f: &mut File) -> std::io::Result<ImageType> {
|
pub fn detect_image_type(f: &mut File) -> std::io::Result<ImageType> {
|
||||||
// We must create a buffer aligned on 512 bytes with a size being a
|
let block = read_aligned_block_size(f)?;
|
||||||
// multiple of 512 bytes as the file might be opened with O_DIRECT flag.
|
|
||||||
#[repr(align(512))]
|
|
||||||
struct Sector {
|
|
||||||
data: [u8; 512],
|
|
||||||
}
|
|
||||||
let mut s = Sector { data: [0; 512] };
|
|
||||||
|
|
||||||
f.read_exact(&mut s.data)?;
|
|
||||||
|
|
||||||
// Check 4 first bytes to get the header value and determine the image type
|
// Check 4 first bytes to get the header value and determine the image type
|
||||||
let image_type = if u32::from_be_bytes(s.data[0..4].try_into().unwrap()) == QCOW_MAGIC {
|
let image_type = if u32::from_be_bytes(block[0..4].try_into().unwrap()) == QCOW_MAGIC {
|
||||||
ImageType::Qcow2
|
ImageType::Qcow2
|
||||||
} else if vhd::is_fixed_vhd(f)? {
|
} else if vhd::is_fixed_vhd(f)? {
|
||||||
ImageType::FixedVhd
|
ImageType::FixedVhd
|
||||||
} else if u64::from_le_bytes(s.data[0..8].try_into().unwrap()) == VHDX_SIGN {
|
} else if u64::from_le_bytes(block[0..8].try_into().unwrap()) == VHDX_SIGN {
|
||||||
ImageType::Vhdx
|
ImageType::Vhdx
|
||||||
} else {
|
} else {
|
||||||
ImageType::Raw
|
ImageType::Raw
|
||||||
|
@ -2,9 +2,10 @@
|
|||||||
//
|
//
|
||||||
// SPDX-License-Identifier: Apache-2.0
|
// SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
use crate::{read_aligned_block_size, DiskTopology};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io::{Read, Seek, SeekFrom};
|
use std::io::{Seek, SeekFrom};
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct VhdFooter {
|
pub struct VhdFooter {
|
||||||
@ -27,37 +28,33 @@ pub struct VhdFooter {
|
|||||||
|
|
||||||
impl VhdFooter {
|
impl VhdFooter {
|
||||||
pub fn new(file: &mut File) -> std::io::Result<VhdFooter> {
|
pub fn new(file: &mut File) -> std::io::Result<VhdFooter> {
|
||||||
// We must create a buffer aligned on 512 bytes with a size being a
|
let blocksize = DiskTopology::probe(file)?.logical_block_size as usize;
|
||||||
// multiple of 512 bytes as the file might be opened with O_DIRECT flag.
|
|
||||||
#[repr(align(512))]
|
|
||||||
struct Sector {
|
|
||||||
data: [u8; 512],
|
|
||||||
}
|
|
||||||
let mut s = Sector { data: [0; 512] };
|
|
||||||
|
|
||||||
// Place the cursor 512 bytes before the end of the file, as this is
|
// Place the cursor in the last block of the file
|
||||||
// where the footer starts.
|
file.seek(SeekFrom::End(0 - (blocksize as i64)))?;
|
||||||
file.seek(SeekFrom::End(-512))?;
|
// Read in the last block
|
||||||
|
let data = read_aligned_block_size(file)?;
|
||||||
|
|
||||||
// Fill in the VhdFooter structure
|
// We only care about the last sector
|
||||||
file.read_exact(&mut s.data)?;
|
let offset = blocksize - 512;
|
||||||
|
let sector = &data[offset..];
|
||||||
|
|
||||||
Ok(VhdFooter {
|
Ok(VhdFooter {
|
||||||
cookie: u64::from_be_bytes(s.data[0..8].try_into().unwrap()),
|
cookie: u64::from_be_bytes(sector[0..8].try_into().unwrap()),
|
||||||
features: u32::from_be_bytes(s.data[8..12].try_into().unwrap()),
|
features: u32::from_be_bytes(sector[8..12].try_into().unwrap()),
|
||||||
file_format_version: u32::from_be_bytes(s.data[12..16].try_into().unwrap()),
|
file_format_version: u32::from_be_bytes(sector[12..16].try_into().unwrap()),
|
||||||
data_offset: u64::from_be_bytes(s.data[16..24].try_into().unwrap()),
|
data_offset: u64::from_be_bytes(sector[16..24].try_into().unwrap()),
|
||||||
time_stamp: u32::from_be_bytes(s.data[24..28].try_into().unwrap()),
|
time_stamp: u32::from_be_bytes(sector[24..28].try_into().unwrap()),
|
||||||
creator_application: u32::from_be_bytes(s.data[28..32].try_into().unwrap()),
|
creator_application: u32::from_be_bytes(sector[28..32].try_into().unwrap()),
|
||||||
creator_version: u32::from_be_bytes(s.data[32..36].try_into().unwrap()),
|
creator_version: u32::from_be_bytes(sector[32..36].try_into().unwrap()),
|
||||||
creator_host_os: u32::from_be_bytes(s.data[36..40].try_into().unwrap()),
|
creator_host_os: u32::from_be_bytes(sector[36..40].try_into().unwrap()),
|
||||||
original_size: u64::from_be_bytes(s.data[40..48].try_into().unwrap()),
|
original_size: u64::from_be_bytes(sector[40..48].try_into().unwrap()),
|
||||||
current_size: u64::from_be_bytes(s.data[48..56].try_into().unwrap()),
|
current_size: u64::from_be_bytes(sector[48..56].try_into().unwrap()),
|
||||||
disk_geometry: u32::from_be_bytes(s.data[56..60].try_into().unwrap()),
|
disk_geometry: u32::from_be_bytes(sector[56..60].try_into().unwrap()),
|
||||||
disk_type: u32::from_be_bytes(s.data[60..64].try_into().unwrap()),
|
disk_type: u32::from_be_bytes(sector[60..64].try_into().unwrap()),
|
||||||
checksum: u32::from_be_bytes(s.data[64..68].try_into().unwrap()),
|
checksum: u32::from_be_bytes(sector[64..68].try_into().unwrap()),
|
||||||
unique_id: u128::from_be_bytes(s.data[68..84].try_into().unwrap()),
|
unique_id: u128::from_be_bytes(sector[68..84].try_into().unwrap()),
|
||||||
saved_state: u8::from_be_bytes(s.data[84..85].try_into().unwrap()),
|
saved_state: u8::from_be_bytes(sector[84..85].try_into().unwrap()),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user