From 6ff49323c5cc6a8529a8e83815b02c1ec526d1e2 Mon Sep 17 00:00:00 2001 From: William Manley Date: Fri, 26 Mar 2021 01:41:10 +0000 Subject: [PATCH] File: preadv2: Call the syscall directly rather than via glibc This way we don't need to worry about compatiblity with old glibc versions and it will work on Android and musl too. The downside is that you can't use `LD_PRELOAD` tricks any more to intercept these calls. --- tokio/src/fs/file.rs | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) 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))]