diff --git a/block_backend/src/qcow2/mod.rs b/block_backend/src/qcow2/mod.rs index ddb3f7e1e63c5f4e8a1c86da4d0e3930c9d06551..d697654dd15b3e5c7908ec71526b325672fe9971 100644 --- a/block_backend/src/qcow2/mod.rs +++ b/block_backend/src/qcow2/mod.rs @@ -2182,7 +2182,7 @@ mod test { None, ) .unwrap(); - let (req_align, buf_align) = get_file_alignment(&image.file, true); + let (req_align, buf_align) = get_file_alignment(&image.file, true).unwrap(); let conf = BlockProperty { id: path.to_string(), format: DiskFormat::Qcow2, @@ -2506,7 +2506,7 @@ mod test { let alloc_clusters: Vec = vec![1, 2, 4, 8, 16, 32]; for n_clusters in alloc_clusters { let image = TestImage::new(path, image_bits, cluster_bits); - let (req_align, buf_align) = get_file_alignment(&image.file, true); + let (req_align, buf_align) = get_file_alignment(&image.file, true).unwrap(); let conf = BlockProperty { id: path.to_string(), format: DiskFormat::Qcow2, @@ -2583,7 +2583,7 @@ mod test { // and then use the aligned interval for recying disk. for (offset_begin, offset_end) in test_data { let mut image = TestImage::new(path, image_bits, cluster_bits); - let (req_align, buf_align) = get_file_alignment(&image.file, true); + let (req_align, buf_align) = get_file_alignment(&image.file, true).unwrap(); conf.req_align = req_align; conf.buf_align = buf_align; let mut qcow2_driver = image.create_qcow2_driver(conf.clone()); @@ -2625,7 +2625,7 @@ mod test { let cluster_bits = 16; let cluster_size = 1 << cluster_bits; let mut image = TestImage::new(path, image_bits, cluster_bits); - let (req_align, buf_align) = get_file_alignment(&image.file, true); + let (req_align, buf_align) = get_file_alignment(&image.file, true).unwrap(); let conf = BlockProperty { id: path.to_string(), format: DiskFormat::Qcow2, diff --git a/machine_manager/src/config/mod.rs b/machine_manager/src/config/mod.rs index a3f96b04a1bc49ab386ee7a050794c5606428947..3044542d72e71e0e590135fd548ded99bb5c6762 100644 --- a/machine_manager/src/config/mod.rs +++ b/machine_manager/src/config/mod.rs @@ -298,7 +298,7 @@ impl VmConfig { } } let file = open_file(path, read_only, direct)?; - let (req_align, buf_align) = get_file_alignment(&file, direct); + let (req_align, buf_align) = get_file_alignment(&file, direct)?; if req_align == 0 || buf_align == 0 { bail!( "Failed to detect alignment requirement of drive file {}.", diff --git a/util/src/file.rs b/util/src/file.rs index c1efa02b21d1fef5142a48364f720cd3694cc5f4..a19394326e06590a9521930cc834c0adf308b525 100644 --- a/util/src/file.rs +++ b/util/src/file.rs @@ -11,7 +11,7 @@ // See the Mulan PSL v2 for more details. use std::fs::{remove_file, File, OpenOptions}; -use std::os::unix::fs::OpenOptionsExt; +use std::os::unix::fs::{MetadataExt, OpenOptionsExt}; use std::os::unix::io::AsRawFd; use std::path::Path; @@ -19,7 +19,6 @@ use anyhow::{bail, Context, Ok, Result}; use nix::fcntl::{fcntl, FcntlArg}; use nix::unistd::getpid; -const MIN_FILE_ALIGN: u32 = 512; pub const MAX_FILE_ALIGN: u32 = 4096; /// Permission to read const FILE_LOCK_READ: u64 = 0x01; @@ -49,65 +48,20 @@ pub fn open_file(path: &str, read_only: bool, direct: bool) -> Result { Ok(file) } -fn is_io_aligned(file: &File, buf: u64, size: usize) -> bool { - // SAFETY: file and buf is valid. - let ret = unsafe { - libc::pread( - file.as_raw_fd() as libc::c_int, - buf as *mut libc::c_void, - size as libc::size_t, - 0, - ) - }; - ret >= 0 || nix::errno::errno() != libc::EINVAL -} - -pub fn get_file_alignment(file: &File, direct: bool) -> (u32, u32) { +pub fn get_file_alignment(file: &File, direct: bool) -> Result<(u32, u32)> { if !direct { - return (1, 1); + return Ok((1, 1)); } - let mut req_align: u32 = 0; - let mut buf_align: u32 = 0; - // SAFETY: we allocate aligned memory and free it later. - let aligned_buffer = unsafe { - libc::memalign( - MAX_FILE_ALIGN as libc::size_t, - (MAX_FILE_ALIGN * 2) as libc::size_t, - ) - }; - if aligned_buffer.is_null() { - log::warn!("OOM occurs when get file alignment, assume max alignment"); - return (MAX_FILE_ALIGN, MAX_FILE_ALIGN); - } - - // Guess alignment requirement of request. - let mut align = MIN_FILE_ALIGN; - while align <= MAX_FILE_ALIGN { - if is_io_aligned(file, aligned_buffer as u64, align as usize) { - req_align = align; - break; - } - align <<= 1; - } - - // Guess alignment requirement of buffer. - let mut align = MIN_FILE_ALIGN; - while align <= MAX_FILE_ALIGN { - if is_io_aligned( - file, - aligned_buffer as u64 + u64::from(align), - MAX_FILE_ALIGN as usize, - ) { - buf_align = align; - break; - } - align <<= 1; - } + // DirectIO may degrade into bufferIO when not aligned, and IO will not report errors at this time. + // Detecting alignment by judging the return value of IO is unreliable. + // Directly obtain the alignment values presented by the Filesystem. + let metadata = file + .metadata() + .with_context(|| "Failed to get file metadata.")?; + let blk_size = metadata.blksize() as u32; - // SAFETY: the memory is allocated by us and will not be used anymore. - unsafe { libc::free(aligned_buffer) }; - (req_align, buf_align) + Ok((blk_size, blk_size)) } fn do_fcntl_lock(