Skip to content

Commit 0b7d90e

Browse files
committed
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.
1 parent 48576b5 commit 0b7d90e

File tree

1 file changed

+28
-2
lines changed

1 file changed

+28
-2
lines changed

tokio/src/fs/file.rs

+28-2
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,7 @@ impl Inner {
764764
#[cfg(all(target_os = "linux", not(test)))]
765765
mod read_nowait {
766766
use crate::io::ReadBuf;
767-
use libc::{c_int, c_void, iovec, off_t, preadv2};
767+
use libc::{c_int, c_long, c_void, iovec, off_t, ssize_t};
768768
use std::{
769769
os::unix::prelude::AsRawFd,
770770
sync::atomic::{AtomicBool, Ordering},
@@ -779,7 +779,7 @@ mod read_nowait {
779779
if !NONBLOCKING_READ_SUPPORTED.load(Ordering::Relaxed) {
780780
return None;
781781
}
782-
let out = preadv2_safe(file, dst, -1, libc::RWF_NOWAIT);
782+
let out = preadv2_safe(file, dst, -1, RWF_NOWAIT);
783783
if let Err(err) = &out {
784784
match err.raw_os_error() {
785785
Some(libc::ENOSYS) => {
@@ -822,6 +822,32 @@ mod read_nowait {
822822
}
823823
}
824824
}
825+
826+
fn pos_to_lohi(offset: off_t) -> (c_long, c_long) {
827+
// 64-bit offset is split over high and low 32-bits on 32-bit architectures.
828+
// 64-bit architectures still have high and low arguments, but only the low
829+
// one is inspected. See pos_from_hilo in linux/fs/read_write.c.
830+
const HALF_LONG_BITS: usize = core::mem::size_of::<c_long>() * 8 / 2;
831+
(
832+
offset as c_long,
833+
// We want to shift this off_t value by size_of::<c_long>(). We can't do
834+
// it in one shift because if they're both 64-bits we'd be doing u64 >> 64
835+
// which is implementation defined. Instead do it in two halves:
836+
((offset >> HALF_LONG_BITS) >> HALF_LONG_BITS) as c_long,
837+
)
838+
}
839+
840+
const RWF_NOWAIT: c_int = 0x00000008;
841+
unsafe fn preadv2(
842+
fd: c_int,
843+
iov: *const iovec,
844+
iovcnt: c_int,
845+
offset: off_t,
846+
flags: c_int,
847+
) -> ssize_t {
848+
let (lo, hi) = pos_to_lohi(offset);
849+
libc::syscall(libc::SYS_preadv2, fd, iov, iovcnt, lo, hi, flags) as ssize_t
850+
}
825851
}
826852

827853
#[cfg(any(not(target_os = "linux"), test))]

0 commit comments

Comments
 (0)