Skip to content

Commit a596f45

Browse files
authored
Gate statx syscall compat wrapper with feature flag (#501)
Signed-off-by: Alex Saveau <[email protected]>
1 parent 589039d commit a596f45

File tree

2 files changed

+76
-54
lines changed

2 files changed

+76
-54
lines changed

Cargo.toml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,3 +194,11 @@ os_pipe = ["io-lifetimes/os_pipe"]
194194
fs-err = ["io-lifetimes/fs-err"]
195195
#all-impls = ["async-std", "tokio", "os_pipe", "socket2", "mio", "fs-err"]
196196
all-impls = ["os_pipe", "fs-err"]
197+
198+
# OS compatability features
199+
200+
# Optimize for Linux 4.11 or later
201+
linux_4_11 = []
202+
203+
# Enable all optimizations for the latest Linux versions.
204+
linux_latest = ["linux_4_11"]

src/fs/statx.rs

Lines changed: 68 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,16 @@
11
//! Linux `statx`.
22
3-
use crate::fd::{AsFd, BorrowedFd};
4-
use crate::ffi::CStr;
3+
use crate::fd::AsFd;
54
use crate::fs::AtFlags;
65
use crate::{backend, io, path};
7-
use core::sync::atomic::{AtomicU8, Ordering};
86

97
pub use backend::fs::types::{Statx, StatxFlags, StatxTimestamp};
108

9+
#[cfg(feature = "linux_4_11")]
10+
use backend::fs::syscalls::statx as _statx;
11+
#[cfg(not(feature = "linux_4_11"))]
12+
use compat::statx as _statx;
13+
1114
/// `statx(dirfd, path, flags, mask, statxbuf)`
1215
///
1316
/// This function returns [`io::Errno::NOSYS`] if `statx` is not available on
@@ -29,63 +32,74 @@ pub fn statx<P: path::Arg, Fd: AsFd>(
2932
path.into_with_c_str(|path| _statx(dirfd.as_fd(), path, flags, mask))
3033
}
3134

32-
// Linux kernel prior to 4.11 old versions of Docker don't support `statx`. We
33-
// store the availability in a global to avoid unnecessary syscalls.
34-
//
35-
// 0: Unknown
36-
// 1: Not available
37-
// 2: Available
38-
static STATX_STATE: AtomicU8 = AtomicU8::new(0);
35+
#[cfg(not(feature = "linux_4_11"))]
36+
mod compat {
37+
use crate::fd::BorrowedFd;
38+
use crate::ffi::CStr;
39+
use crate::fs::AtFlags;
40+
use crate::{backend, io};
41+
use core::sync::atomic::{AtomicU8, Ordering};
3942

40-
#[inline]
41-
fn _statx(
42-
dirfd: BorrowedFd<'_>,
43-
path: &CStr,
44-
flags: AtFlags,
45-
mask: StatxFlags,
46-
) -> io::Result<Statx> {
47-
match STATX_STATE.load(Ordering::Relaxed) {
48-
0 => statx_init(dirfd, path, flags, mask),
49-
1 => Err(io::Errno::NOSYS),
50-
_ => backend::fs::syscalls::statx(dirfd, path, flags, mask),
43+
use backend::fs::types::{Statx, StatxFlags};
44+
45+
// Linux kernel prior to 4.11 old versions of Docker don't support `statx`. We
46+
// store the availability in a global to avoid unnecessary syscalls.
47+
//
48+
// 0: Unknown
49+
// 1: Not available
50+
// 2: Available
51+
static STATX_STATE: AtomicU8 = AtomicU8::new(0);
52+
53+
#[inline]
54+
pub fn statx(
55+
dirfd: BorrowedFd<'_>,
56+
path: &CStr,
57+
flags: AtFlags,
58+
mask: StatxFlags,
59+
) -> io::Result<Statx> {
60+
match STATX_STATE.load(Ordering::Relaxed) {
61+
0 => statx_init(dirfd, path, flags, mask),
62+
1 => Err(io::Errno::NOSYS),
63+
_ => backend::fs::syscalls::statx(dirfd, path, flags, mask),
64+
}
5165
}
52-
}
5366

54-
/// The first `statx` call. We don't know if `statx` is available yet.
55-
fn statx_init(
56-
dirfd: BorrowedFd<'_>,
57-
path: &CStr,
58-
flags: AtFlags,
59-
mask: StatxFlags,
60-
) -> io::Result<Statx> {
61-
match backend::fs::syscalls::statx(dirfd, path, flags, mask) {
62-
Err(io::Errno::NOSYS) => statx_error_nosys(),
63-
Err(io::Errno::PERM) => statx_error_perm(),
64-
result => {
65-
STATX_STATE.store(2, Ordering::Relaxed);
66-
result
67+
/// The first `statx` call. We don't know if `statx` is available yet.
68+
fn statx_init(
69+
dirfd: BorrowedFd<'_>,
70+
path: &CStr,
71+
flags: AtFlags,
72+
mask: StatxFlags,
73+
) -> io::Result<Statx> {
74+
match backend::fs::syscalls::statx(dirfd, path, flags, mask) {
75+
Err(io::Errno::NOSYS) => statx_error_nosys(),
76+
Err(io::Errno::PERM) => statx_error_perm(),
77+
result => {
78+
STATX_STATE.store(2, Ordering::Relaxed);
79+
result
80+
}
6781
}
6882
}
69-
}
7083

71-
/// The first `statx` call failed with `NOSYS` (or something we're treating
72-
/// like `NOSYS`).
73-
#[cold]
74-
fn statx_error_nosys() -> io::Result<Statx> {
75-
STATX_STATE.store(1, Ordering::Relaxed);
76-
Err(io::Errno::NOSYS)
77-
}
84+
/// The first `statx` call failed with `NOSYS` (or something we're treating
85+
/// like `NOSYS`).
86+
#[cold]
87+
fn statx_error_nosys() -> io::Result<Statx> {
88+
STATX_STATE.store(1, Ordering::Relaxed);
89+
Err(io::Errno::NOSYS)
90+
}
7891

79-
/// The first `statx` call failed with `PERM`.
80-
#[cold]
81-
fn statx_error_perm() -> io::Result<Statx> {
82-
// Some old versions of Docker have `statx` fail with `PERM` when it isn't
83-
// recognized. Check whether `statx` really is available, and if so, fail
84-
// with `PERM`, and if not, treat it like `NOSYS`.
85-
if backend::fs::syscalls::is_statx_available() {
86-
STATX_STATE.store(2, Ordering::Relaxed);
87-
Err(io::Errno::PERM)
88-
} else {
89-
statx_error_nosys()
92+
/// The first `statx` call failed with `PERM`.
93+
#[cold]
94+
fn statx_error_perm() -> io::Result<Statx> {
95+
// Some old versions of Docker have `statx` fail with `PERM` when it isn't
96+
// recognized. Check whether `statx` really is available, and if so, fail
97+
// with `PERM`, and if not, treat it like `NOSYS`.
98+
if backend::fs::syscalls::is_statx_available() {
99+
STATX_STATE.store(2, Ordering::Relaxed);
100+
Err(io::Errno::PERM)
101+
} else {
102+
statx_error_nosys()
103+
}
90104
}
91105
}

0 commit comments

Comments
 (0)