#![cfg(target_os = "linux")]
use std::fs::File;
use std::io::Write;
use std::os::fd::{AsRawFd, FromRawFd};
use std::sync::Arc;
use std::time::{Duration, Instant};
use rustfs_uring::UringDriver;
fn driver_or_skip(name: &str) -> Option<UringDriver> {
match UringDriver::probe_and_start(64) {
Ok(d) => Some(d),
Err(e) => {
assert!(
e.is_expected_restriction(),
"probe failed OUTSIDE the expected restriction errno class \
(EACCES/EPERM/ENOSYS/EINVAL/EOPNOTSUPP): {e:?}"
);
eprintln!("SKIP {name}: restricted environment, graceful degradation path taken ({e:?})");
None
}
}
}
fn sharded_driver_or_skip(name: &str, shards: usize) -> Option<UringDriver> {
match UringDriver::probe_and_start_sharded(64, shards) {
Ok(d) => Some(d),
Err(e) => {
assert!(
e.is_expected_restriction(),
"probe failed OUTSIDE the expected restriction errno class: {e:?}"
);
eprintln!("SKIP {name}: restricted environment, graceful degradation path taken ({e:?})");
None
}
}
}
fn make_content(len: usize) -> Vec<u8> {
let mut state: u64 = 0x2545F4914F6CDD1D;
(0..len)
.map(|_| {
state ^= state << 13;
state ^= state >> 7;
state ^= state << 17;
state as u8
})
.collect()
}
fn temp_file_with(content: &[u8], tag: &str) -> (std::path::PathBuf, Arc<File>) {
let path = std::env::temp_dir().join(format!("uring-spike-{tag}-{}", std::process::id()));
std::fs::write(&path, content).expect("write temp file");
let file = Arc::new(File::open(&path).expect("open temp file"));
(path, file)
}
fn os_pipe() -> (Arc<File>, File) {
let mut fds = [0i32; 2];
let rc = unsafe { libc::pipe(fds.as_mut_ptr()) };
assert_eq!(rc, 0, "pipe(2) failed");
let read = unsafe { File::from_raw_fd(fds[0]) };
let write = unsafe { File::from_raw_fd(fds[1]) };
(Arc::new(read), write)
}
async fn wait_until(deadline: Duration, mut cond: impl FnMut() -> bool) -> bool {
let start = Instant::now();
while start.elapsed() < deadline {
if cond() {
return true;
}
tokio::time::sleep(Duration::from_millis(5)).await;
}
cond()
}
#[tokio::test(flavor = "multi_thread")]
async fn read_matches_std() {
let Some(driver) = driver_or_skip("read_matches_std") else {
return;
};
const LEN: usize = 8 << 20;
let content = make_content(LEN);
let (path, file) = temp_file_with(&content, "correctness");
for i in 0..64usize {
let offset = (i * 131_071) % (LEN - 70_000);
let len = 1 + (i * 8_191) % 65_536;
let got = driver
.read_at(Arc::clone(&file), offset as u64, len)
.await
.expect("read failed");
assert_eq!(got, &content[offset..offset + len], "mismatch at offset {offset} len {len}");
}
let snap = driver.shutdown();
assert_eq!(snap.delivered, 64);
assert_eq!(snap.orphan_reclaimed, 0);
let _ = std::fs::remove_file(path);
}
#[tokio::test(flavor = "multi_thread")]
async fn dropped_future_buffer_lives_until_cqe() {
let Some(driver) = driver_or_skip("dropped_future_buffer_lives_until_cqe") else {
return;
};
let (pipe_read, mut pipe_write) = os_pipe();
let handle = driver.read_current(Arc::clone(&pipe_read), 4096).without_cancel_on_drop();
assert!(
wait_until(Duration::from_secs(2), || driver.stats().in_flight == 1).await,
"read never reached in-flight state"
);
drop(handle);
tokio::time::sleep(Duration::from_millis(300)).await;
let snap = driver.stats();
assert_eq!(snap.in_flight, 1, "op vanished without a CQE");
assert_eq!(snap.orphan_reclaimed, 0, "buffer reclaimed before CQE — UAF window!");
pipe_write.write_all(&[0xAB; 512]).expect("pipe write");
assert!(
wait_until(Duration::from_secs(2), || {
let s = driver.stats();
s.in_flight == 0 && s.orphan_reclaimed == 1
})
.await,
"orphaned op was not reclaimed at CQE: {:?}",
driver.stats()
);
driver.shutdown();
}
#[tokio::test(flavor = "multi_thread")]
async fn async_cancel_accelerates_reclaim() {
let Some(driver) = driver_or_skip("async_cancel_accelerates_reclaim") else {
return;
};
let (pipe_read, pipe_write) = os_pipe();
let handle = driver.read_current(Arc::clone(&pipe_read), 4096);
assert!(
wait_until(Duration::from_secs(2), || driver.stats().in_flight == 1).await,
"read never reached in-flight state"
);
drop(handle);
assert!(
wait_until(Duration::from_secs(2), || {
let s = driver.stats();
s.in_flight == 0 && s.orphan_reclaimed == 1
})
.await,
"cancel did not reclaim the orphan: {:?}",
driver.stats()
);
drop(pipe_write);
driver.shutdown();
}
#[tokio::test(flavor = "multi_thread")]
async fn cancel_stress_accounts_for_every_buffer() {
let Some(driver) = driver_or_skip("cancel_stress_accounts_for_every_buffer") else {
return;
};
const LEN: usize = 8 << 20;
const OPS: usize = 256;
const READ_LEN: usize = 64 << 10;
let content = make_content(LEN);
let (path, file) = temp_file_with(&content, "stress");
let mut kept = Vec::new();
for i in 0..OPS {
let offset = (i * 97_611) % (LEN - READ_LEN);
let handle = driver.read_at(Arc::clone(&file), offset as u64, READ_LEN);
if i % 2 == 0 {
drop(handle); } else {
kept.push((offset, handle));
}
}
for (offset, handle) in kept {
let got = handle.await.expect("kept read failed");
assert_eq!(got, &content[offset..offset + READ_LEN], "mismatch at offset {offset}");
}
let snap = driver.shutdown();
assert!(snap.submitted <= OPS as u64, "more ops submitted than requested: {snap:?}");
assert!(snap.delivered >= (OPS / 2) as u64, "kept half not all delivered: {snap:?}");
assert_eq!(
snap.delivered + snap.orphan_reclaimed,
snap.submitted,
"some buffers are unaccounted for: {snap:?}"
);
let _ = std::fs::remove_file(path);
}
#[tokio::test(flavor = "multi_thread")]
async fn shutdown_drains_in_flight_ops() {
let Some(driver) = driver_or_skip("shutdown_drains_in_flight_ops") else {
return;
};
let (pipe_read, pipe_write) = os_pipe();
let h1 = driver.read_current(Arc::clone(&pipe_read), 1024);
let h2 = driver.read_current(Arc::clone(&pipe_read), 1024);
assert!(
wait_until(Duration::from_secs(2), || driver.stats().in_flight == 2).await,
"reads never reached in-flight state"
);
let snap = driver.shutdown();
assert_eq!(snap.in_flight, 0);
assert_eq!(snap.delivered + snap.orphan_reclaimed, snap.submitted);
for h in [h1, h2] {
let err = h.await.expect_err("blocked pipe read cannot have succeeded");
assert_eq!(err.raw_os_error(), Some(libc::ECANCELED), "unexpected error: {err:?}");
}
drop(pipe_write);
}
#[tokio::test(flavor = "multi_thread")]
async fn pending_table_owns_fd_after_caller_drop() {
let Some(driver) = driver_or_skip("pending_table_owns_fd_after_caller_drop") else {
return;
};
let (pipe_read, mut pipe_write) = os_pipe();
let raw_fd = pipe_read.as_raw_fd();
let handle = driver.read_current(Arc::clone(&pipe_read), 64).without_cancel_on_drop();
assert!(
wait_until(Duration::from_secs(2), || driver.stats().in_flight == 1).await,
"read never reached in-flight state"
);
drop(handle);
drop(pipe_read);
tokio::time::sleep(Duration::from_millis(50)).await;
let rc = unsafe { libc::fcntl(raw_fd, libc::F_GETFD) };
assert_ne!(
rc,
-1,
"fd was closed while an op is in flight — the pending table does not own it \
(invariant 2 unprotected): {}",
std::io::Error::last_os_error()
);
pipe_write.write_all(&[0x5A; 64]).expect("pipe write");
assert!(
wait_until(Duration::from_secs(2), || driver.stats().in_flight == 0).await,
"op was not reclaimed at CQE"
);
driver.shutdown();
}
#[tokio::test(flavor = "multi_thread")]
async fn orphan_in_flight_does_not_corrupt_delivered_reads() {
let Some(driver) = driver_or_skip("orphan_in_flight_does_not_corrupt_delivered_reads") else {
return;
};
let (pipe_read, mut pipe_write) = os_pipe();
let orphan = driver.read_current(Arc::clone(&pipe_read), 4096).without_cancel_on_drop();
assert!(
wait_until(Duration::from_secs(2), || driver.stats().in_flight == 1).await,
"orphan never reached in-flight state"
);
drop(orphan);
const LEN: usize = 1 << 20;
let content = make_content(LEN);
let (path, file) = temp_file_with(&content, "canary");
for i in 0..64usize {
let offset = (i * 9_973) % (LEN - 4096);
let got = driver
.read_at(Arc::clone(&file), offset as u64, 4096)
.await
.expect("read failed");
assert_eq!(got, &content[offset..offset + 4096], "delivered read corrupted at offset {offset}");
}
assert_eq!(driver.stats().orphan_reclaimed, 0, "orphan buffer reclaimed before its CQE");
pipe_write.write_all(&[0u8; 512]).expect("pipe write");
driver.shutdown();
let _ = std::fs::remove_file(path);
}
#[tokio::test(flavor = "multi_thread")]
async fn no_cq_overflow_under_load() {
let Some(driver) = driver_or_skip("no_cq_overflow_under_load") else {
return;
};
const LEN: usize = 8 << 20;
const OPS: usize = 300; const READ_LEN: usize = 4096;
let content = make_content(LEN);
let (path, file) = temp_file_with(&content, "overflow");
let mut kept = Vec::new();
for i in 0..OPS {
let offset = (i * 4_093) % (LEN - READ_LEN);
kept.push((offset, driver.read_at(Arc::clone(&file), offset as u64, READ_LEN)));
}
for (offset, handle) in kept {
let got = handle.await.expect("read failed");
assert_eq!(got, &content[offset..offset + READ_LEN], "mismatch at offset {offset}");
}
let snap = driver.shutdown();
assert_eq!(snap.cq_overflow, 0, "CQ overflowed under load: {snap:?}");
assert_eq!(snap.delivered, OPS as u64);
let _ = std::fs::remove_file(path);
}
#[tokio::test(flavor = "multi_thread")]
async fn boundary_reads() {
let Some(driver) = driver_or_skip("boundary_reads") else {
return;
};
const LEN: usize = 4096;
let content = make_content(LEN);
let (path, file) = temp_file_with(&content, "boundary");
let got = driver.read_at(Arc::clone(&file), 0, 0).await.expect("len=0 read");
assert!(got.is_empty(), "len=0 should return empty, got {}", got.len());
let got = driver.read_at(Arc::clone(&file), LEN as u64, 128).await.expect("EOF read");
assert!(got.is_empty(), "read at EOF should be empty, got {}", got.len());
let got = driver
.read_at(Arc::clone(&file), (LEN - 10) as u64, 100)
.await
.expect("cross-EOF read");
assert_eq!(got, &content[LEN - 10..LEN], "cross-EOF read should return the tail only");
let err = driver
.read_at(Arc::clone(&file), 0, (1usize << 32) + 1)
.await
.expect_err("huge len must be rejected");
assert_eq!(err.kind(), std::io::ErrorKind::InvalidInput, "huge len error: {err:?}");
let err = driver
.read_at(Arc::clone(&file), (i64::MAX as u64) + 1, 16)
.await
.expect_err("huge offset must be rejected");
assert_eq!(err.kind(), std::io::ErrorKind::InvalidInput, "huge offset error: {err:?}");
driver.shutdown();
let _ = std::fs::remove_file(path);
}
#[tokio::test(flavor = "multi_thread")]
async fn pipe_half_close_reads_eof() {
let Some(driver) = driver_or_skip("pipe_half_close_reads_eof") else {
return;
};
let (pipe_read, pipe_write) = os_pipe();
let handle = driver.read_current(Arc::clone(&pipe_read), 128);
assert!(
wait_until(Duration::from_secs(2), || driver.stats().in_flight == 1).await,
"read never reached in-flight state"
);
drop(pipe_write); let got = handle.await.expect("pipe EOF read");
assert!(got.is_empty(), "closed-pipe read should be empty EOF, got {}", got.len());
driver.shutdown();
}
fn open_direct(path: &std::path::Path) -> Option<Arc<File>> {
use std::os::unix::ffi::OsStrExt;
let c_path = std::ffi::CString::new(path.as_os_str().as_bytes()).expect("temp path has no NUL");
loop {
let fd = unsafe { libc::open(c_path.as_ptr(), libc::O_RDONLY | libc::O_DIRECT | libc::O_CLOEXEC) };
if fd >= 0 {
return Some(Arc::new(unsafe { File::from_raw_fd(fd) }));
}
let err = std::io::Error::last_os_error();
match err.raw_os_error() {
Some(libc::EINTR) => continue,
Some(libc::EINVAL) | Some(libc::EOPNOTSUPP) => return None,
_ => panic!("open({}, O_DIRECT) failed unexpectedly: {err}", path.display()),
}
}
}
#[tokio::test(flavor = "multi_thread")]
async fn direct_read_returns_exact_unaligned_ranges() {
let Some(driver) = driver_or_skip("direct_read_returns_exact_unaligned_ranges") else {
return;
};
const ALIGN: usize = 4096;
const FILE_LEN: usize = ALIGN * 3 + 7; let content = make_content(FILE_LEN);
let path = std::env::temp_dir().join(format!("uring-odirect-{}", std::process::id()));
{
let mut f = File::create(&path).expect("create temp file");
f.write_all(&content).expect("write temp file");
f.sync_all().expect("sync temp file");
}
let Some(file) = open_direct(&path) else {
eprintln!("direct_read_returns_exact_unaligned_ranges: filesystem rejects O_DIRECT, assertions not exercised");
driver.shutdown();
let _ = std::fs::remove_file(&path);
return;
};
let ranges = [
(0usize, FILE_LEN),
(0, ALIGN),
(1, 17),
(ALIGN - 1, ALIGN + 2),
(ALIGN * 2, ALIGN + 7),
(FILE_LEN - 7, 7),
];
for (offset, len) in ranges {
let got = driver
.read_at_direct(Arc::clone(&file), offset as u64, len, ALIGN)
.await
.expect("O_DIRECT read failed");
assert_eq!(got, &content[offset..offset + len], "O_DIRECT read mismatch at offset={offset} len={len}");
}
let err = driver
.read_at_direct(Arc::clone(&file), 0, 16, 3)
.await
.expect_err("non-power-of-two alignment must be rejected");
assert_eq!(err.kind(), std::io::ErrorKind::InvalidInput, "unexpected error: {err:?}");
driver.shutdown();
let _ = std::fs::remove_file(&path);
}
#[tokio::test(flavor = "multi_thread")]
async fn saturated_submit_defers_instead_of_blocking() {
const DEPTH: u32 = 4;
let driver = match UringDriver::probe_and_start(DEPTH) {
Ok(d) => d,
Err(e) => {
assert!(
e.is_expected_restriction(),
"probe failed OUTSIDE the expected restriction errno class: {e:?}"
);
eprintln!("SKIP saturated_submit_defers_instead_of_blocking: restricted environment ({e:?})");
return;
}
};
let (pipe_read, mut pipe_write) = os_pipe();
const LEN: usize = 4096;
let content = make_content(LEN);
let (path, file) = temp_file_with(&content, "backpressure");
let mut held = Vec::new();
for _ in 0..DEPTH {
held.push(driver.read_current(Arc::clone(&pipe_read), 64));
}
assert!(
wait_until(Duration::from_secs(2), || driver.stats().in_flight == u64::from(DEPTH)).await,
"backpressure never saturated: {:?}",
driver.stats()
);
let extra = driver.read_at(Arc::clone(&file), 0, LEN);
let snap = driver.stats();
assert_eq!(snap.in_flight, u64::from(DEPTH), "saturated submit put an op in flight: {snap:?}");
assert_eq!(snap.submitted, u64::from(DEPTH), "saturated submit submitted an op: {snap:?}");
pipe_write
.write_all(&vec![0xAB; 64 * (DEPTH as usize + 1)])
.expect("pipe write");
for h in held {
let _ = h.await;
}
let got = extra.await.expect("deferred read must complete once a permit frees");
assert_eq!(got, content, "deferred read returned wrong bytes");
assert_eq!(driver.stats().submitted, u64::from(DEPTH) + 1);
driver.shutdown();
let _ = std::fs::remove_file(path);
}
#[tokio::test(flavor = "multi_thread")]
async fn drop_without_shutdown_drains_and_cancels() {
let Some(driver) = driver_or_skip("drop_without_shutdown_drains_and_cancels") else {
return;
};
let (pipe_read, pipe_write) = os_pipe();
let h1 = driver.read_current(Arc::clone(&pipe_read), 1024);
let h2 = driver.read_current(Arc::clone(&pipe_read), 1024);
assert!(
wait_until(Duration::from_secs(2), || driver.stats().in_flight == 2).await,
"reads never reached in-flight state"
);
drop(driver);
for h in [h1, h2] {
let err = h.await.expect_err("blocked pipe read cannot have succeeded");
assert_eq!(err.raw_os_error(), Some(libc::ECANCELED), "unexpected error: {err:?}");
}
drop(pipe_write);
}
#[tokio::test(flavor = "multi_thread")]
async fn sharded_driver_conserves_buffers_across_shards() {
const SHARDS: usize = 4;
let Some(driver) = sharded_driver_or_skip("sharded_driver_conserves_buffers_across_shards", SHARDS) else {
return;
};
const LEN: usize = 8 << 20;
const OPS: usize = 256;
const READ_LEN: usize = 64 << 10;
let content = make_content(LEN);
let (path, file) = temp_file_with(&content, "sharded-stress");
let mut kept = Vec::new();
for i in 0..OPS {
let offset = (i * 97_611) % (LEN - READ_LEN);
let handle = driver.read_at(Arc::clone(&file), offset as u64, READ_LEN);
if i % 2 == 0 {
drop(handle);
} else {
kept.push((offset, handle));
}
}
for (offset, handle) in kept {
let got = handle.await.expect("kept read failed");
assert_eq!(got, &content[offset..offset + READ_LEN], "mismatch at offset {offset}");
}
let snap = driver.shutdown();
assert!(snap.submitted <= OPS as u64, "more ops submitted than requested: {snap:?}");
assert!(snap.delivered >= (OPS / 2) as u64, "kept half not all delivered: {snap:?}");
assert_eq!(
snap.delivered + snap.orphan_reclaimed,
snap.submitted,
"some buffers are unaccounted for across shards: {snap:?}"
);
assert_eq!(snap.in_flight, 0, "shutdown left ops in flight: {snap:?}");
assert_eq!(snap.cq_overflow, 0, "per-shard in-flight cap must keep CQ overflow unreachable: {snap:?}");
let _ = std::fs::remove_file(path);
}
#[tokio::test(flavor = "multi_thread")]
async fn sharded_driver_with_one_shard_matches_single_ring() {
let Some(driver) = sharded_driver_or_skip("sharded_driver_with_one_shard_matches_single_ring", 1) else {
return;
};
const LEN: usize = 1 << 20;
let content = make_content(LEN);
let (path, file) = temp_file_with(&content, "sharded-one");
let got = driver.read_at(Arc::clone(&file), 4096, 8192).await.expect("read");
assert_eq!(got, &content[4096..4096 + 8192]);
let snap = driver.shutdown();
assert_eq!(snap.delivered + snap.orphan_reclaimed, snap.submitted, "{snap:?}");
let _ = std::fs::remove_file(path);
}
#[tokio::test(flavor = "multi_thread")]
async fn sharded_cancel_routes_to_the_owning_ring() {
const SHARDS: usize = 4;
const OPS: usize = 16;
let Some(driver) = sharded_driver_or_skip("sharded_cancel_routes_to_the_owning_ring", SHARDS) else {
return;
};
let (pipe_read, pipe_write) = os_pipe();
let mut handles = Vec::new();
for _ in 0..OPS {
handles.push(driver.read_current(Arc::clone(&pipe_read), 4096));
}
assert!(
wait_until(Duration::from_secs(2), || driver.stats().in_flight == OPS as u64).await,
"not all reads reached in-flight: {:?}",
driver.stats()
);
drop(handles);
assert!(
wait_until(Duration::from_secs(3), || {
let s = driver.stats();
s.in_flight == 0 && s.orphan_reclaimed == OPS as u64
})
.await,
"sharded cancels did not reclaim every orphan — a cancel routed to the wrong ring? {:?}",
driver.stats()
);
let snap = driver.stats();
assert!(snap.cancel_succeeded > 0, "orphans not reclaimed by cancel: {snap:?}");
drop(pipe_write);
driver.shutdown();
}