mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
block: extract is_block_device() helper and dedupe inline fstat probes
probe_sparse_support() and DiskTopology::is_block_device() each carry
their own copy of the same fstat()+S_IFMT dance to ask "is this fd a
block device?". Hoist a single pub helper
pub(crate) fn is_block_device(fd: RawFd) -> bool
into block::lib and route both call sites through it. Drop the
MaybeUninit gymnastics in favour of mem::zeroed() since libc::stat is
POD.
Drop DiskTopology::is_block_device since it is now just a one line
wrapper around the new helper function.
Pure refactor in preparation for the BLKDISCARD/BLKZEROOUT support,
which needs the same probe in three more backends.
Signed-off-by: Wei Liu <liuwe@microsoft.com>
This commit is contained in:
+17
-31
@@ -45,7 +45,7 @@ use std::fs::{File, OpenOptions};
|
|||||||
use std::io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
|
use std::io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write};
|
||||||
use std::os::linux::fs::MetadataExt;
|
use std::os::linux::fs::MetadataExt;
|
||||||
use std::os::unix::fs::FileTypeExt;
|
use std::os::unix::fs::FileTypeExt;
|
||||||
use std::os::unix::io::AsRawFd;
|
use std::os::unix::io::{AsRawFd, RawFd};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::{cmp, mem, result};
|
use std::{cmp, mem, result};
|
||||||
@@ -332,26 +332,25 @@ pub fn block_io_uring_is_supported() -> bool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `true` iff `fd` refers to a block device.
|
||||||
|
///
|
||||||
|
/// Returns `false` if the `fstat()` probe itself fails. Callers that need to
|
||||||
|
/// distinguish "not a block device" from "couldn't tell" should fall back to
|
||||||
|
/// regular-file behaviour, which is what every current caller already does.
|
||||||
|
pub(crate) fn is_block_device(fd: RawFd) -> bool {
|
||||||
|
// SAFETY: `libc::stat` is POD; zero-initialization is a valid bit pattern
|
||||||
|
// and `fstat` overwrites every field it cares about on success.
|
||||||
|
let mut stat: libc::stat = unsafe { std::mem::zeroed() };
|
||||||
|
// SAFETY: FFI call with a valid fd and a valid out-pointer.
|
||||||
|
let ret = unsafe { libc::fstat(fd, &mut stat) };
|
||||||
|
ret == 0 && stat.st_mode & S_IFMT == S_IFBLK
|
||||||
|
}
|
||||||
|
|
||||||
/// Probe whether the file/device supports punch hole and zero range
|
/// Probe whether the file/device supports punch hole and zero range
|
||||||
pub fn probe_sparse_support(file: &File) -> bool {
|
pub fn probe_sparse_support(file: &File) -> bool {
|
||||||
let fd = file.as_raw_fd();
|
let fd = file.as_raw_fd();
|
||||||
|
|
||||||
let is_block_device = {
|
if is_block_device(fd) {
|
||||||
let mut stat = std::mem::MaybeUninit::<libc::stat>::uninit();
|
|
||||||
// SAFETY: FFI call with valid fd and buffer
|
|
||||||
let ret = unsafe { libc::fstat(fd, stat.as_mut_ptr()) };
|
|
||||||
if ret != 0 {
|
|
||||||
warn!(
|
|
||||||
"Failed to stat file descriptor for sparse probe: {}",
|
|
||||||
io::Error::last_os_error()
|
|
||||||
);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// SAFETY: stat result is valid at this point
|
|
||||||
unsafe { (*stat.as_ptr()).st_mode & S_IFMT == S_IFBLK }
|
|
||||||
};
|
|
||||||
|
|
||||||
if is_block_device {
|
|
||||||
probe_block_device_sparse_support(fd)
|
probe_block_device_sparse_support(fd)
|
||||||
} else {
|
} else {
|
||||||
probe_file_sparse_support(fd)
|
probe_file_sparse_support(fd)
|
||||||
@@ -721,19 +720,6 @@ enum BlockSize {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl DiskTopology {
|
impl DiskTopology {
|
||||||
fn is_block_device(f: &File) -> std::io::Result<bool> {
|
|
||||||
let mut stat = std::mem::MaybeUninit::<libc::stat>::uninit();
|
|
||||||
// SAFETY: FFI call with a valid fd and buffer
|
|
||||||
let ret = unsafe { libc::fstat(f.as_raw_fd(), stat.as_mut_ptr()) };
|
|
||||||
if ret != 0 {
|
|
||||||
return Err(std::io::Error::last_os_error());
|
|
||||||
}
|
|
||||||
|
|
||||||
// SAFETY: stat is valid at this point
|
|
||||||
let is_block = unsafe { (*stat.as_ptr()).st_mode & S_IFMT == S_IFBLK };
|
|
||||||
Ok(is_block)
|
|
||||||
}
|
|
||||||
|
|
||||||
// libc::ioctl() takes different types on different architectures
|
// libc::ioctl() takes different types on different architectures
|
||||||
fn query_block_size(f: &File, block_size_type: BlockSize) -> std::io::Result<u64> {
|
fn query_block_size(f: &File, block_size_type: BlockSize) -> std::io::Result<u64> {
|
||||||
let mut block_size = 0;
|
let mut block_size = 0;
|
||||||
@@ -809,7 +795,7 @@ impl DiskTopology {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn probe(f: &File) -> std::io::Result<Self> {
|
pub fn probe(f: &File) -> std::io::Result<Self> {
|
||||||
if !Self::is_block_device(f)? {
|
if !is_block_device(f.as_raw_fd()) {
|
||||||
// For regular files opened with O_DIRECT, the logical block size
|
// For regular files opened with O_DIRECT, the logical block size
|
||||||
// must reflect the filesystem DIO alignment so the guest issues
|
// must reflect the filesystem DIO alignment so the guest issues
|
||||||
// correctly sized I/O.
|
// correctly sized I/O.
|
||||||
|
|||||||
Reference in New Issue
Block a user