diff --git a/tokio/src/fs/file.rs b/tokio/src/fs/file.rs index 8eeee68eb99..177da5c0873 100644 --- a/tokio/src/fs/file.rs +++ b/tokio/src/fs/file.rs @@ -764,7 +764,7 @@ impl Inner { #[cfg(all(target_os = "linux", not(test)))] mod read_nowait { use crate::io::ReadBuf; - use libc::{c_int, c_void, iovec, off_t, preadv2}; + use libc::{c_int, c_long, c_void, iovec, off_t, ssize_t}; use std::{ os::unix::prelude::AsRawFd, sync::atomic::{AtomicBool, Ordering}, @@ -822,6 +822,32 @@ mod read_nowait { } } } + + fn pos_to_lohi(offset: off_t) -> (c_long, c_long) { + // 64-bit offset is split over high and low 32-bits on 32-bit architectures. + // 64-bit architectures still have high and low arguments, but only the low + // one is inspected. See pos_from_hilo in linux/fs/read_write.c. + const HALF_LONG_BITS: usize = core::mem::size_of::() * 8 / 2; + ( + offset as c_long, + ((offset >> HALF_LONG_BITS) >> HALF_LONG_BITS) as c_long, + ) + } + + unsafe fn preadv2( + fd: c_int, + iov: *const iovec, + iovcnt: c_int, + offset: off_t, + flags: c_int, + ) -> ssize_t { + if flags == 0 { + libc::preadv(fd, iov, iovcnt, offset) + } else { + let (lo, hi) = pos_to_lohi(offset); + libc::syscall(libc::SYS_preadv2, fd, iov, iovcnt, lo, hi, flags) as ssize_t + } + } } #[cfg(any(not(target_os = "linux"), test))]