Skip to content

Commit

Permalink
Update for recent kernels (up to 6.10) (#296)
Browse files Browse the repository at this point in the history
* Updated for new capabilities in kernels 6.8, 6.9, 6.10 including FixedFdInstall, FTruncate operations as well as bundled recv and send.
Added test for bundled send and recv feature flag (available from kernel 6.10).
Implemented tests accordingly.

* Fixed formatting

* Updated comment spelling.
Renamed FTruncate to Ftruncate for consistency.

* Changed sys::IOSQE_FIXED_FILE_BIT with Flags::FIXED_FILE.bits as requested

* Replaced sys::IOSQE_BUFFER_SELECT_BIT with BUFFER_SELECT.bits as requested
  • Loading branch information
yaroslavros authored Dec 28, 2024
1 parent c1c3773 commit b175a22
Show file tree
Hide file tree
Showing 6 changed files with 608 additions and 18 deletions.
6 changes: 6 additions & 0 deletions io-uring-test/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ fn test<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
#[cfg(not(feature = "ci"))]
tests::fs::test_statx(&mut ring, &test)?;
tests::fs::test_file_splice(&mut ring, &test)?;
tests::fs::test_ftruncate(&mut ring, &test)?;
tests::fs::test_fixed_fd_install(&mut ring, &test)?;

// timeout
tests::timeout::test_timeout(&mut ring, &test)?;
Expand All @@ -117,6 +119,7 @@ fn test<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
tests::net::test_tcp_write_read(&mut ring, &test)?;
tests::net::test_tcp_writev_readv(&mut ring, &test)?;
tests::net::test_tcp_send_recv(&mut ring, &test)?;
tests::net::test_tcp_send_bundle(&mut ring, &test)?;
tests::net::test_tcp_zero_copy_send_recv(&mut ring, &test)?;
tests::net::test_tcp_zero_copy_send_fixed(&mut ring, &test)?;
tests::net::test_tcp_sendmsg_recvmsg(&mut ring, &test)?;
Expand All @@ -130,6 +133,9 @@ fn test<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
tests::net::test_tcp_buffer_select_recvmsg(&mut ring, &test)?;
tests::net::test_tcp_buffer_select_readv(&mut ring, &test)?;
tests::net::test_tcp_recv_multi(&mut ring, &test)?;
tests::net::test_tcp_recv_bundle(&mut ring, &test)?;
tests::net::test_tcp_recv_multi_bundle(&mut ring, &test)?;

tests::net::test_tcp_shutdown(&mut ring, &test)?;
tests::net::test_socket(&mut ring, &test)?;
tests::net::test_udp_recvmsg_multishot(&mut ring, &test)?;
Expand Down
129 changes: 128 additions & 1 deletion io-uring-test/src/tests/fs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::Test;
use io_uring::{cqueue, opcode, squeue, types, IoUring};
use std::ffi::CString;
use std::fs;
use std::io::Write;
use std::io::{Read, Write};
use std::os::unix::ffi::OsStrExt;
use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd};

Expand Down Expand Up @@ -810,3 +810,130 @@ pub fn test_file_splice<S: squeue::EntryMarker, C: cqueue::EntryMarker>(

Ok(())
}

pub fn test_ftruncate<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
ring: &mut IoUring<S, C>,
test: &Test,
) -> anyhow::Result<()> {
require!(
test;
test.probe.is_supported(opcode::Ftruncate::CODE);
);

println!("test ftruncate");

let dir = tempfile::TempDir::new_in(".")?;
let dir = dir.path();
let file = dir.join("io-uring-test-file-input");

let input = &[0x9f; 1024];

fs::write(&file, input)?;
let fd = fs::OpenOptions::new().write(true).open(&file)?;
let fd = types::Fd(fd.as_raw_fd());
let ftruncate_e = opcode::Ftruncate::new(fd, 512);

unsafe {
ring.submission()
.push(&ftruncate_e.build().user_data(0x33).into())
.expect("queue is full");
}

ring.submit_and_wait(1)?;

let cqes: Vec<cqueue::Entry> = ring.completion().map(Into::into).collect();

assert_eq!(cqes.len(), 1);
assert_eq!(cqes[0].user_data(), 0x33);
assert_eq!(cqes[0].result(), 0);
assert_eq!(
fs::read(&file).expect("could not read truncated file"),
&input[..512]
);

let ftruncate_e = opcode::Ftruncate::new(fd, 0);

unsafe {
ring.submission()
.push(&ftruncate_e.build().user_data(0x34).into())
.expect("queue is full");
}

ring.submit_and_wait(1)?;

let cqes: Vec<cqueue::Entry> = ring.completion().map(Into::into).collect();

assert_eq!(cqes.len(), 1);
assert_eq!(cqes[0].user_data(), 0x34);
assert_eq!(cqes[0].result(), 0);
assert_eq!(
fs::metadata(&file)
.expect("could not read truncated file")
.len(),
0
);

Ok(())
}

pub fn test_fixed_fd_install<S: squeue::EntryMarker, C: cqueue::EntryMarker>(
ring: &mut IoUring<S, C>,
test: &Test,
) -> anyhow::Result<()> {
require!(
test;
test.probe.is_supported(opcode::Read::CODE);
test.probe.is_supported(opcode::FixedFdInstall::CODE);
);

println!("test fixed_fd_install");

let dir = tempfile::TempDir::new_in(".")?;
let dir = dir.path();
let file = dir.join("io-uring-test-file-input");

let input = &[0x9f; 1024];
let mut output = vec![0; 1024];

fs::write(&file, input)?;
let fd = fs::OpenOptions::new().read(true).open(&file)?;
let fd = types::Fd(fd.as_raw_fd());
ring.submitter().register_files(&[fd.0])?;
let fd = types::Fixed(0);

let read_e = opcode::Read::new(fd, output.as_mut_ptr(), output.len() as _);
unsafe {
ring.submission()
.push(&read_e.build().user_data(0x01).into())
.expect("queue is full");
}

assert_eq!(ring.submit_and_wait(1)?, 1);
let cqes: Vec<cqueue::Entry> = ring.completion().map(Into::into).collect();
assert_eq!(cqes.len(), 1);
assert_eq!(cqes[0].user_data(), 0x01);
assert_eq!(cqes[0].result(), 1024);
assert_eq!(output, input);

let fixed_fd_install_e = opcode::FixedFdInstall::new(fd, 0);

unsafe {
ring.submission()
.push(&fixed_fd_install_e.build().user_data(0x02).into())
.expect("queue is full");
}

ring.submit_and_wait(1)?;

let cqes: Vec<cqueue::Entry> = ring.completion().map(Into::into).collect();

assert_eq!(cqes.len(), 1);
assert_eq!(cqes[0].user_data(), 0x02);
let fd = cqes[0].result();
assert!(fd > 0);
let mut file = unsafe { fs::File::from_raw_fd(fd) };
file.read_exact(&mut output)?;
assert_eq!(output, input);

Ok(())
}
Loading

0 comments on commit b175a22

Please # to comment.