block: aligned: Query direct alignment in AlignedFile

Move the statx STATX_DIOALIGN probe out of DiskTopology into a free
probe_direct_alignment helper keyed on a raw fd. The helper gates on the
O_DIRECT open flag and returns the kernel reported alignment only when
direct I/O is in effect, and None otherwise. DiskTopology::probe keeps
the same call path and result.

AlignedFile::new now determines its O_DIRECT block alignment from
probe_direct_alignment instead of trial reads at 512 and 4096, falling
back to SECTOR_SIZE when the kernel does not report a value. This
matches how the raw and fixed VHD workers determine alignment, so all
backends agree on one source of truth.

Signed-off-by: Anatol Belski <anbelski@linux.microsoft.com>
This commit is contained in:
Anatol Belski
2026-06-17 22:06:20 +02:00
committed by Rob Bradford
parent 80cc980d05
commit 4c7e2b83c1
2 changed files with 68 additions and 74 deletions

View File

@@ -5,11 +5,10 @@
use std::fs::File;
use std::io;
use std::os::unix::fs::FileExt;
use std::os::unix::io::AsRawFd;
use crate::aligned_buffer::AlignedBuffer;
/// O_DIRECT block-alignment candidates, smallest first.
const BLK_ALIGNMENTS: [usize; 2] = [512, 4096];
use crate::{SECTOR_SIZE, probe_direct_alignment};
/// True when `buf_ptr`/`len`/`offset` already satisfy `alignment`
/// (`alignment == 0` means no O_DIRECT, so everything is "aligned").
@@ -32,21 +31,13 @@ pub(crate) struct AlignedFile {
}
impl AlignedFile {
/// Wrap `file`, probing the O_DIRECT block alignment when `direct_io`.
/// Wrap `file`, querying the O_DIRECT block alignment when `direct_io`.
pub fn new(file: File, direct_io: bool) -> Self {
let mut alignment = 0;
if direct_io {
for align in &BLK_ALIGNMENTS {
// Probe: an aligned read at `align` succeeds (a short read at
// EOF still counts) iff the fd accepts that O_DIRECT block size.
let ok = AlignedBuffer::new(*align as u64, *align, *align)
.is_ok_and(|mut b| b.read_from(&file).is_ok());
if ok {
alignment = *align;
break;
}
}
}
let alignment = if direct_io {
probe_direct_alignment(file.as_raw_fd()).unwrap_or(SECTOR_SIZE) as usize
} else {
0
};
AlignedFile { file, alignment }
}
@@ -130,8 +121,8 @@ mod tests {
#[test]
fn new_probes_alignment_and_accessors() {
let tf = pattern_file(8192);
// Non-O_DIRECT tempfile: an aligned read at `align` still succeeds,
// so the probe selects 512 (exercises new + probe).
// A tempfile is not O_DIRECT, so probe_direct_alignment reports
// None and new() falls back to SECTOR_SIZE (512).
let mut af = AlignedFile::new(tf.as_file().try_clone().unwrap(), true);
assert_eq!(af.alignment(), 512);
let _ = af.file();