From d012bcf8967ba518bfa5a05d2c166139f4d4a9a0 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Tue, 10 Oct 2023 08:46:25 -0700 Subject: [PATCH] Fixes needed by io_uring. (#873) * Fixes needed by io_uring. - Have the `io_uring` module export more types used in opcode entries. - Define a conversion from `SocketAddr` to `SocketAddrAny`. - Add comments to the `fadvise` implementation. * Pin regex to 1.9 in Rust 1.63 builds. * Make more `Epoll` types available to io_uring too. This enables most of the epoll module without needing "alloc". It doesn't enable `epoll_wait`, because that needs `Vec`, but this does potentially open up a path to having a non-allocating opetion for waiting on an epoll. --- .github/workflows/main.yml | 2 ++ Cargo.toml | 2 +- src/backend/libc/event/epoll.rs | 10 +++++- src/backend/libc/event/mod.rs | 2 +- src/backend/linux_raw/conv.rs | 2 +- src/backend/linux_raw/event/epoll.rs | 6 ++++ src/backend/linux_raw/event/mod.rs | 1 - src/backend/linux_raw/event/syscalls.rs | 20 +++++------- src/backend/linux_raw/fs/syscalls.rs | 6 ++++ src/event/mod.rs | 2 +- src/io_uring.rs | 42 ++++++++++++++++++++++++- src/net/socket_addr_any.rs | 12 ++++++- 12 files changed, 86 insertions(+), 21 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index a256d0a7a..e1136d6c3 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -52,6 +52,7 @@ jobs: if: matrix.rust == '1.63' run: | cargo update --package=dashmap --precise 5.4.0 + cargo update --package=regex --precise=1.9.0 - run: > rustup target add @@ -481,6 +482,7 @@ jobs: if: matrix.rust == '1.63' run: | cargo update --package=dashmap --precise 5.4.0 + cargo update --package=regex --precise=1.9.0 - run: | cargo test --verbose --features=all-apis --release --workspace -- --nocapture diff --git a/Cargo.toml b/Cargo.toml index 83d286822..45eef07c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -135,7 +135,7 @@ event = [] fs = [] # Enable `rustix::io_uring::*` (on platforms that support it). -io_uring = ["fs", "net", "linux-raw-sys/io_uring"] +io_uring = ["event", "fs", "net", "linux-raw-sys/io_uring"] # Enable `rustix::mount::*`. mount = [] diff --git a/src/backend/libc/event/epoll.rs b/src/backend/libc/event/epoll.rs index 9fba85cc6..39363bf25 100644 --- a/src/backend/libc/event/epoll.rs +++ b/src/backend/libc/event/epoll.rs @@ -74,10 +74,13 @@ //! ``` use crate::backend::c; -use crate::backend::conv::{ret, ret_owned_fd, ret_u32}; +#[cfg(feature = "alloc")] +use crate::backend::conv::ret_u32; +use crate::backend::conv::{ret, ret_owned_fd}; use crate::fd::{AsFd, AsRawFd, OwnedFd}; use crate::io; use crate::utils::as_mut_ptr; +#[cfg(feature = "alloc")] use alloc::vec::Vec; use bitflags::bitflags; use core::ffi::c_void; @@ -257,6 +260,8 @@ pub fn delete(epoll: impl AsFd, source: impl AsFd) -> io::Result<()> { /// /// For each event of interest, an element is written to `events`. On /// success, this returns the number of written elements. +#[cfg(feature = "alloc")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] pub fn wait(epoll: impl AsFd, event_list: &mut EventVec, timeout: c::c_int) -> io::Result<()> { // SAFETY: We're calling `epoll_wait` via FFI and we know how it // behaves. @@ -395,10 +400,12 @@ struct SixtyFourBitPointer { } /// A vector of `Event`s, plus context for interpreting them. +#[cfg(feature = "alloc")] pub struct EventVec { events: Vec, } +#[cfg(feature = "alloc")] impl EventVec { /// Constructs an `EventVec` from raw pointer, length, and capacity. /// @@ -473,6 +480,7 @@ impl EventVec { } } +#[cfg(feature = "alloc")] impl<'a> IntoIterator for &'a EventVec { type IntoIter = Iter<'a>; type Item = Event; diff --git a/src/backend/libc/event/mod.rs b/src/backend/libc/event/mod.rs index 44e8a090a..6aed4612a 100644 --- a/src/backend/libc/event/mod.rs +++ b/src/backend/libc/event/mod.rs @@ -5,5 +5,5 @@ pub(crate) mod types; #[cfg_attr(windows, path = "windows_syscalls.rs")] pub(crate) mod syscalls; -#[cfg(all(feature = "alloc", linux_kernel))] +#[cfg(linux_kernel)] pub mod epoll; diff --git a/src/backend/linux_raw/conv.rs b/src/backend/linux_raw/conv.rs index f915db140..3a3825266 100644 --- a/src/backend/linux_raw/conv.rs +++ b/src/backend/linux_raw/conv.rs @@ -581,7 +581,7 @@ impl<'a, Num: ArgNumber> From for ArgReg<'a, Num> { } } -#[cfg(all(feature = "alloc", feature = "event"))] +#[cfg(feature = "event")] impl<'a, Num: ArgNumber> From for ArgReg<'a, Num> { #[inline] fn from(flags: crate::event::epoll::CreateFlags) -> Self { diff --git a/src/backend/linux_raw/event/epoll.rs b/src/backend/linux_raw/event/epoll.rs index 9c9c34632..90fde2d83 100644 --- a/src/backend/linux_raw/event/epoll.rs +++ b/src/backend/linux_raw/event/epoll.rs @@ -79,6 +79,7 @@ use crate::backend::c; use crate::backend::event::syscalls; use crate::fd::{AsFd, AsRawFd, OwnedFd}; use crate::io; +#[cfg(feature = "alloc")] use alloc::vec::Vec; use bitflags::bitflags; use core::ffi::c_void; @@ -242,6 +243,8 @@ pub fn delete(epoll: impl AsFd, source: impl AsFd) -> io::Result<()> { /// /// For each event of interest, an element is written to `events`. On /// success, this returns the number of written elements. +#[cfg(feature = "alloc")] +#[cfg_attr(doc_cfg, doc(cfg(feature = "alloc")))] #[inline] pub fn wait(epoll: impl AsFd, event_list: &mut EventVec, timeout: c::c_int) -> io::Result<()> { // SAFETY: We're calling `epoll_wait` via FFI and we know how it @@ -371,10 +374,12 @@ struct SixtyFourBitPointer { } /// A vector of `Event`s, plus context for interpreting them. +#[cfg(feature = "alloc")] pub struct EventVec { events: Vec, } +#[cfg(feature = "alloc")] impl EventVec { /// Constructs an `EventVec` from raw pointer, length, and capacity. /// @@ -449,6 +454,7 @@ impl EventVec { } } +#[cfg(feature = "alloc")] impl<'a> IntoIterator for &'a EventVec { type IntoIter = Iter<'a>; type Item = Event; diff --git a/src/backend/linux_raw/event/mod.rs b/src/backend/linux_raw/event/mod.rs index 4148a8c7f..605de2538 100644 --- a/src/backend/linux_raw/event/mod.rs +++ b/src/backend/linux_raw/event/mod.rs @@ -1,4 +1,3 @@ -#[cfg(feature = "alloc")] pub mod epoll; pub(crate) mod poll_fd; pub(crate) mod syscalls; diff --git a/src/backend/linux_raw/event/syscalls.rs b/src/backend/linux_raw/event/syscalls.rs index a8003b004..6cb8d3d96 100644 --- a/src/backend/linux_raw/event/syscalls.rs +++ b/src/backend/linux_raw/event/syscalls.rs @@ -6,17 +6,15 @@ #![allow(unsafe_code, clippy::undocumented_unsafe_blocks)] use crate::backend::c; -use crate::backend::conv::{c_int, c_uint, ret_owned_fd, ret_usize, slice_mut}; -use crate::event::{EventfdFlags, PollFd}; -use crate::fd::OwnedFd; -use crate::io; #[cfg(feature = "alloc")] -use { - crate::backend::conv::{by_ref, pass_usize, raw_fd, ret, zero}, - crate::event::epoll, - crate::fd::BorrowedFd, - linux_raw_sys::general::{EPOLL_CTL_ADD, EPOLL_CTL_DEL, EPOLL_CTL_MOD}, +use crate::backend::conv::pass_usize; +use crate::backend::conv::{ + by_ref, c_int, c_uint, raw_fd, ret, ret_owned_fd, ret_usize, slice_mut, zero, }; +use crate::event::{epoll, EventfdFlags, PollFd}; +use crate::fd::{BorrowedFd, OwnedFd}; +use crate::io; +use linux_raw_sys::general::{EPOLL_CTL_ADD, EPOLL_CTL_DEL, EPOLL_CTL_MOD}; #[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))] use { crate::backend::conv::{opt_ref, size_of}, @@ -52,13 +50,11 @@ pub(crate) fn poll(fds: &mut [PollFd<'_>], timeout: c::c_int) -> io::Result io::Result { unsafe { ret_owned_fd(syscall_readonly!(__NR_epoll_create1, flags)) } } -#[cfg(feature = "alloc")] #[inline] pub(crate) unsafe fn epoll_add( epfd: BorrowedFd<'_>, @@ -74,7 +70,6 @@ pub(crate) unsafe fn epoll_add( )) } -#[cfg(feature = "alloc")] #[inline] pub(crate) unsafe fn epoll_mod( epfd: BorrowedFd<'_>, @@ -90,7 +85,6 @@ pub(crate) unsafe fn epoll_mod( )) } -#[cfg(feature = "alloc")] #[inline] pub(crate) unsafe fn epoll_del(epfd: BorrowedFd<'_>, fd: c::c_int) -> io::Result<()> { ret(syscall_readonly!( diff --git a/src/backend/linux_raw/fs/syscalls.rs b/src/backend/linux_raw/fs/syscalls.rs index 880d3927a..f856fa8b0 100644 --- a/src/backend/linux_raw/fs/syscalls.rs +++ b/src/backend/linux_raw/fs/syscalls.rs @@ -378,6 +378,7 @@ pub(crate) fn fadvise(fd: BorrowedFd<'_>, pos: u64, len: u64, advice: Advice) -> lo(len) )) } + // On mips, the arguments are not reordered, and padding is inserted // instead to ensure alignment. #[cfg(any(target_arch = "mips", target_arch = "mips32r6"))] @@ -393,6 +394,9 @@ pub(crate) fn fadvise(fd: BorrowedFd<'_>, pos: u64, len: u64, advice: Advice) -> advice )) } + + // For all other 32-bit architectures, use `fadvise64_64` so that we get a + // 64-bit length. #[cfg(all( target_pointer_width = "32", not(any( @@ -413,6 +417,8 @@ pub(crate) fn fadvise(fd: BorrowedFd<'_>, pos: u64, len: u64, advice: Advice) -> advice )) } + + // On 64-bit architectures, use `fadvise64` which is sufficient. #[cfg(target_pointer_width = "64")] unsafe { ret(syscall_readonly!( diff --git a/src/event/mod.rs b/src/event/mod.rs index 03abc9f12..b0b62e0a6 100644 --- a/src/event/mod.rs +++ b/src/event/mod.rs @@ -13,7 +13,7 @@ mod poll; #[cfg(solarish)] pub mod port; -#[cfg(all(feature = "alloc", linux_kernel))] +#[cfg(linux_kernel)] pub use crate::backend::event::epoll; #[cfg(any( linux_kernel, diff --git a/src/io_uring.rs b/src/io_uring.rs index c166e747a..eb95678eb 100644 --- a/src/io_uring.rs +++ b/src/io_uring.rs @@ -32,9 +32,47 @@ use core::ptr::{null_mut, write_bytes}; use linux_raw_sys::net; // Export types used in io_uring APIs. -pub use crate::fs::{Advice, AtFlags, OFlags, RenameFlags, ResolveFlags, Statx}; +pub use crate::event::epoll::{ + Event as EpollEvent, EventData as EpollEventData, EventFlags as EpollEventFlags, +}; +pub use crate::fs::{Advice, AtFlags, Mode, OFlags, RenameFlags, ResolveFlags, Statx, StatxFlags}; +pub use crate::io::ReadWriteFlags; pub use crate::net::{RecvFlags, SendFlags, SocketFlags}; pub use crate::timespec::Timespec; +pub use linux_raw_sys::general::sigset_t; + +pub use net::{__kernel_sockaddr_storage as sockaddr_storage, msghdr, sockaddr, socklen_t}; + +// Declare the `c_char` type for use with entries that take pointers +// to C strings. Define it as unsigned or signed according to the platform +// so that we match what Rust's `CStr` uses. +// +// When we can update to linux-raw-sys 0.5, we can remove this, as its +// `c_char` type will declare this. +/// The C `char` type. +#[cfg(any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "msp430", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "riscv32", + target_arch = "riscv64", + target_arch = "s390x", +))] +#[allow(non_camel_case_types)] +pub type c_char = u8; +/// The C `char` type. +#[cfg(any( + target_arch = "mips", + target_arch = "mips64", + target_arch = "sparc64", + target_arch = "x86", + target_arch = "x86_64", + target_arch = "xtensa", +))] +#[allow(non_camel_case_types)] +pub type c_char = i8; mod sys { pub(super) use linux_raw_sys::io_uring::*; @@ -1393,6 +1431,8 @@ impl Default for register_or_sqe_op_or_sqe_flags_union { fn io_uring_layouts() { use sys as c; + assert_eq_size!(io_uring_ptr, u64); + check_renamed_type!(off_or_addr2_union, io_uring_sqe__bindgen_ty_1); check_renamed_type!(addr_or_splice_off_in_union, io_uring_sqe__bindgen_ty_2); check_renamed_type!(addr3_or_cmd_union, io_uring_sqe__bindgen_ty_6); diff --git a/src/net/socket_addr_any.rs b/src/net/socket_addr_any.rs index 7cb124e4c..a649015f4 100644 --- a/src/net/socket_addr_any.rs +++ b/src/net/socket_addr_any.rs @@ -11,7 +11,7 @@ #[cfg(unix)] use crate::net::SocketAddrUnix; -use crate::net::{AddressFamily, SocketAddrV4, SocketAddrV6}; +use crate::net::{AddressFamily, SocketAddr, SocketAddrV4, SocketAddrV6}; use crate::{backend, io}; #[cfg(feature = "std")] use core::fmt; @@ -32,6 +32,16 @@ pub enum SocketAddrAny { Unix(SocketAddrUnix), } +impl From for SocketAddrAny { + #[inline] + fn from(from: SocketAddr) -> Self { + match from { + SocketAddr::V4(v4) => Self::V4(v4), + SocketAddr::V6(v6) => Self::V6(v6), + } + } +} + impl From for SocketAddrAny { #[inline] fn from(from: SocketAddrV4) -> Self {