Query the O_DIRECT alignment requirement for a regular file. Uses `statx(STATX_DIOALIGN)` (Linux >= 6.1) to obtain the exact memory and offset alignment the kernel requires for direct I/O on this specific file. Unlike `fstatvfs().f_bsize`, which only returns the filesystem's preferred I/O block size, `STATX_DIOALIGN` reports the true per-file DIO constraints accounting for the filesystem, underly
(f: &File)
| 766 | /// the true per-file DIO constraints accounting for the filesystem, |
| 767 | /// underlying block device, and any stacking (loop, dm, etc.). |
| 768 | fn query_file_alignment(f: &File) -> u64 { |
| 769 | // The libc crate does not expose statx / STATX_DIOALIGN on all |
| 770 | // targets (e.g. musl), so define the constant and a minimal repr(C) |
| 771 | // struct locally and invoke the syscall directly. |
| 772 | const STATX_DIOALIGN: u32 = 0x2000; |
| 773 | |
| 774 | // Minimal statx layout, only the needed fields, |
| 775 | // everything else is padding. |
| 776 | #[repr(C)] |
| 777 | struct Statx { |
| 778 | stx_mask: u32, |
| 779 | _pad: [u8; 148], |
| 780 | stx_dio_mem_align: u32, |
| 781 | stx_dio_offset_align: u32, |
| 782 | _pad2: [u8; 96], |
| 783 | } |
| 784 | |
| 785 | let mut stx = mem::MaybeUninit::<Statx>::zeroed(); |
| 786 | // SAFETY: FFI syscall with valid fd and correctly sized buffer. |
| 787 | let ret = unsafe { |
| 788 | libc::syscall( |
| 789 | libc::SYS_statx, |
| 790 | f.as_raw_fd(), |
| 791 | c"".as_ptr(), |
| 792 | libc::AT_EMPTY_PATH, |
| 793 | STATX_DIOALIGN, |
| 794 | stx.as_mut_ptr(), |
| 795 | ) |
| 796 | }; |
| 797 | if ret == 0 { |
| 798 | // SAFETY: statx succeeded, the struct is fully initialized. |
| 799 | let stx = unsafe { stx.assume_init() }; |
| 800 | if stx.stx_mask & STATX_DIOALIGN != 0 && stx.stx_dio_mem_align > 0 { |
| 801 | let align = cmp::max(stx.stx_dio_mem_align, stx.stx_dio_offset_align) as u64; |
| 802 | debug!("statx(STATX_DIOALIGN) returned alignment {align}"); |
| 803 | return align; |
| 804 | } |
| 805 | } |
| 806 | |
| 807 | debug!("O_DIRECT alignment query failed, falling back to default {SECTOR_SIZE}"); |
| 808 | SECTOR_SIZE |
| 809 | } |
| 810 | |
| 811 | pub fn probe(f: &File) -> std::io::Result<Self> { |
| 812 | if !Self::is_block_device(f)? { |
nothing calls this directly
no test coverage detected