Skip to content

Commit fb25ee9

Browse files
authored
feat(driver): add more flags to Extra (#858)
1 parent 50470ef commit fb25ee9

5 files changed

Lines changed: 198 additions & 121 deletions

File tree

compio-driver/src/key.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,17 @@ impl<C: ?Sized> RawOp<C> {
5353
}
5454
}
5555

56+
#[cfg(io_uring)]
57+
impl<C: crate::Carry + ?Sized> RawOp<C> {
58+
pub fn create_entry<const FALLBACK: bool>(&mut self) -> crate::OpEntry {
59+
if FALLBACK {
60+
self.carrier.create_entry_fallback().with_extra(&self.extra)
61+
} else {
62+
self.carrier.create_entry().with_extra(&self.extra)
63+
}
64+
}
65+
}
66+
5667
#[cfg(windows)]
5768
impl<C: crate::Carry + ?Sized> RawOp<C> {
5869
/// Call [`OpCode::operate`] and assume that it is not an overlapped op,

compio-driver/src/sys/extra.rs

Lines changed: 134 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -16,116 +16,153 @@ impl Debug for Extra {
1616

1717
impl<I: Into<imp::Extra>> From<I> for Extra {
1818
fn from(inner: I) -> Self {
19-
Self::new(inner.into())
19+
Self(inner.into())
2020
}
2121
}
2222

2323
impl Extra {
24-
pub(in crate::sys) fn new(inner: imp::Extra) -> Self {
25-
Self(inner)
26-
}
24+
iour_only! {
25+
/// Checks whether this completion reports a notification (2nd CQE returned for a zerocopy op).
26+
///
27+
/// # Behaviour
28+
///
29+
/// This is only supported on `io_uring` drivers, in which the driver will
30+
/// check whether the `IORING_CQE_F_NOTIF` flag was set by the kernel for
31+
/// the CQE. On other platforms, this will always return the
32+
/// [`Unsupported`] error.
33+
///
34+
/// [`Unsupported`]: io::ErrorKind::Unsupported
35+
get fn is_notification(&self) -> io::Result<bool> = |extra| Ok(extra.is_notification());
2736

28-
/// Set the personality, returning the modified Extra.
29-
///
30-
/// This is a no-op when not using `io_uring` driver.
31-
pub fn with_personality(mut self, personality: u16) -> Self {
32-
self.set_personality(personality);
33-
self
34-
}
37+
/// Try to get the buffer ID associated with this operation.
38+
///
39+
/// # Behavior
40+
///
41+
/// This is only supported on `io_uring` drivers, in which the driver will
42+
/// try to extract `buffer_id` returned by the kernel as a part of `flags`.
43+
/// If the id cannot be extracted from the flag, an [`InvalidInput`]
44+
/// [`io::Error`] will be returned. On other platforms, this will always
45+
/// return [`Unsupported`] error.
46+
///
47+
/// [`InvalidInput`]: io::ErrorKind::InvalidInput
48+
/// [`Unsupported`]: io::ErrorKind::Unsupported
49+
get fn buffer_id(&self) -> io::Result<u16> =
50+
|extra| extra
51+
.buffer_id()
52+
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "Buffer id was not set"));
3553

36-
/// Set the personality for this operation.
37-
///
38-
/// This is a no-op when not using `io_uring` driver.
39-
pub fn set_personality(&mut self, personality: u16) {
40-
#[cfg(io_uring)]
41-
if let Some(extra) = self.try_as_iour_mut() {
42-
extra.set_personality(personality);
43-
}
44-
#[cfg(not(io_uring))]
45-
let _ = personality;
46-
}
4754

48-
/// Get the personality for this operation.
49-
///
50-
/// If the personality was not set with [`set_personality`] or the platform
51-
/// does not support it, returns [`None`].
52-
///
53-
/// [`set_personality`]: Extra::set_personality
54-
pub fn get_personality(&self) -> Option<u16> {
55-
#[cfg(io_uring)]
56-
if let Some(extra) = self.try_as_iour() {
57-
extra.get_personality()
58-
} else {
59-
None
60-
}
61-
#[cfg(not(io_uring))]
62-
None
55+
/// Get the personality for this operation.
56+
///
57+
/// # Behavior
58+
///
59+
/// - If the driver is not `io_uring`, return [`Unsupported`] error,
60+
/// - If the personality was not set with [`set_personality`], return `Ok(None)`
61+
/// - Otherwise, return `Ok(Some(personality))`
62+
///
63+
/// [`Unsupported`]: io::ErrorKind::Unsupported
64+
/// [`set_personality`]: Extra::set_personality
65+
get fn get_personality(&self) -> io::Result<Option<u16>> = |extra| Ok(extra.get_personality());
66+
67+
/// Checks whether the underlying socket has more data to be read.
68+
///
69+
/// # Behaviour
70+
///
71+
/// This method must be used only on the flags for any of the `receive`
72+
/// variants supported by `IO_URING`. The driver will try to check whether
73+
/// the `IORING_CQE_F_SOCK_NONEMPTY` flag was set by the kernel for the CQE.
74+
/// On other platforms, this will always return the [`Unsupported`] error.
75+
///
76+
/// [`Unsupported`]: io::ErrorKind::Unsupported
77+
get fn sock_nonempty(&self) -> io::Result<bool> = |extra| Ok(extra.sock_nonempty());
78+
79+
/// Set the `IOSQE_IO_DRAIN` flag for this operation.
80+
///
81+
/// This ensures that this operation won't start until all previously submitted operations complete.
82+
///
83+
/// See [`io_uring_sqe_set_flags(3)`] for more details.
84+
///
85+
/// [`io_uring_sqe_set_flags(3)`]: https://man7.org/linux/man-pages/man3/io_uring_sqe_set_flags.3.html
86+
set fn drain(&mut self) = |extra| extra.set_drain();
87+
88+
/// Set the `IOSQE_IO_LINK` flag for this operation.
89+
///
90+
/// This links this operation with the next one. The next operation will not start until this operation
91+
/// completed successfully.
92+
///
93+
/// See [`io_uring_sqe_set_flags(3)`] for more details.
94+
///
95+
/// [`io_uring_sqe_set_flags(3)`]: https://man7.org/linux/man-pages/man3/io_uring_sqe_set_flags.3.html
96+
set fn link(&mut self) = |extra| extra.set_link();
97+
98+
/// Set the `IOSQE_IO_HARDLINK` flag for this operation.
99+
///
100+
/// Like link, but the next operation will execute regardless of this operation's result.
101+
///
102+
/// See [`io_uring_sqe_set_flags(3)`] for more details.
103+
///
104+
/// [`io_uring_sqe_set_flags(3)`]: https://man7.org/linux/man-pages/man3/io_uring_sqe_set_flags.3.html
105+
set fn hardlink(&mut self) = |extra| extra.set_hardlink();
106+
107+
/// Set the personality for this operation.
108+
///
109+
/// A personality represents a set of credentials (uid, gid, etc.) that will be used for this operation.
110+
///
111+
/// The personality can be retrieved with [`Proactor::register_personality`].
112+
///
113+
/// [`Proactor::register_personality`]: crate::Proactor::register_personality
114+
set fn personality(&mut self, personality: u16) = |extra| extra.set_personality(personality);
63115
}
116+
}
64117

65-
/// Try to get the buffer ID associated with this operation.
66-
///
67-
/// # Behavior
68-
///
69-
/// This is only supported on `io_uring` drivers, in which the driver will
70-
/// try to extract `buffer_id` returned by the kernel as a part of `flags`.
71-
/// If the id cannot be extracted from the flag, an [`InvalidInput`]
72-
/// [`io::Error`] will be returned. On other platforms, this will always
73-
/// return [`Unsupported`] error.
74-
///
75-
/// [`InvalidInput`]: io::ErrorKind::InvalidInput
76-
/// [`Unsupported`]: io::ErrorKind::Unsupported
77-
pub fn buffer_id(&self) -> io::Result<u16> {
78-
#[cfg(io_uring)]
79-
{
80-
if let Some(extra) = self.try_as_iour() {
81-
extra
82-
.buffer_id()
83-
.ok_or_else(|| io::Error::new(io::ErrorKind::InvalidInput, "flags are invalid"))
118+
macro_rules! iour_only {
119+
{} => {};
120+
{
121+
$(#[$doc:meta])*
122+
get fn $fn:ident(&$this:ident) -> io::Result<$ret:ty> = |$extra:ident| $body:expr;
123+
$($rest:tt)*
124+
} => {
125+
$(#[$doc])*
126+
pub fn $fn (&$this) -> io::Result<$ret> {
127+
const UNSUPPORTED: &str = concat!(stringify!($fn), " is only supported on the io_uring driver");
128+
#[cfg(io_uring)]
129+
if let Some($extra) = $this.try_as_iour() {
130+
$body
84131
} else {
85-
Err(io::Error::new(
86-
io::ErrorKind::Unsupported,
87-
"buffer_id is only supported on io_uring driver",
88-
))
132+
Err(io::Error::new(io::ErrorKind::Unsupported, UNSUPPORTED))
89133
}
134+
#[cfg(not(io_uring))]
135+
Err(io::Error::new(io::ErrorKind::Unsupported, UNSUPPORTED))
90136
}
91-
#[cfg(not(io_uring))]
92-
{
93-
Err(io::Error::new(
94-
io::ErrorKind::Unsupported,
95-
"buffer_id is only supported on io_uring driver",
96-
))
97-
}
98-
}
137+
iour_only!($($rest)*);
138+
};
139+
{
140+
$(#[$doc:meta])*
141+
set fn $val:ident(&mut $this:ident $(, $arg:ident: $arg_ty:ty)*) = |$extra:ident| $body:expr;
142+
$($rest:tt)*
143+
} => {
144+
paste::paste! {
145+
$(#[$doc])*
146+
#[doc = " This is a no-op when not using `io_uring` driver."]
147+
pub fn [<set_ $val>] (&mut $this $(, $arg: $arg_ty)*) {
148+
#[cfg(io_uring)]
149+
if let Some($extra) = $this.try_as_iour_mut() {
150+
$body
151+
}
152+
#[cfg(not(io_uring))]
153+
{$(let _ = $arg;)*}
154+
}
99155

100-
/// Checks whether the underlying socket has more data to be read.
101-
///
102-
/// # Behaviour
103-
///
104-
/// This method must be used only on the flags for any of the `receive`
105-
/// variants supported by `IO_URING`.
106-
/// The driver will try to check whether the `IORING_CQE_F_SOCK_NONEMPTY`
107-
/// flag was set by the kernel for the CQE. On other platforms, this will
108-
/// always return the [`Unsupported`] error.
109-
///
110-
/// [`Unsupported`]: io::ErrorKind::Unsupported
111-
pub fn sock_nonempty(&self) -> io::Result<bool> {
112-
#[cfg(io_uring)]
113-
{
114-
if let Some(extra) = self.try_as_iour() {
115-
Ok(extra.sock_nonempty())
116-
} else {
117-
Err(io::Error::new(
118-
io::ErrorKind::Unsupported,
119-
"IORING_CQE_F_SOCK_NONEMPTY flag is available only on the io_uring driver",
120-
))
156+
#[doc = concat!("Call [`set_", stringify!($val), "`] and return the modified `Extra`.")]
157+
#[doc = ""]
158+
#[doc = concat!("[`set_", stringify!($val), "`]: Self::set_", stringify!($val))]
159+
pub fn [<with_ $val>] (mut $this $(, $arg: $arg_ty)*) -> Self {
160+
$this.[<set_ $val>]($($arg),*);
161+
$this
121162
}
122163
}
123-
#[cfg(not(io_uring))]
124-
{
125-
Err(io::Error::new(
126-
io::ErrorKind::Unsupported,
127-
"IORING_CQE_F_SOCK_NONEMPTY flag is available only on the io_uring driver",
128-
))
129-
}
130-
}
164+
iour_only!($($rest)*);
165+
};
131166
}
167+
168+
use iour_only;

compio-driver/src/sys/iour/extra.rs

Lines changed: 29 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
1+
use io_uring::squeue::Flags;
2+
13
/// Extra data for RawOp.
24
#[derive(Debug)]
35
pub(in crate::sys) struct Extra {
4-
flags: u32,
6+
sqe_flags: Flags,
7+
cqe_flags: u32,
58
personality: Option<u16>,
69
}
710

811
impl Extra {
912
pub fn new() -> Self {
1013
Self {
11-
flags: 0,
14+
sqe_flags: Flags::empty(),
15+
cqe_flags: 0,
1216
personality: None,
1317
}
1418
}
@@ -17,16 +21,36 @@ impl Extra {
1721
self.personality = Some(personality);
1822
}
1923

24+
pub fn set_link(&mut self) {
25+
self.sqe_flags |= Flags::IO_LINK;
26+
}
27+
28+
pub fn set_hardlink(&mut self) {
29+
self.sqe_flags |= Flags::IO_HARDLINK;
30+
}
31+
32+
pub fn set_drain(&mut self) {
33+
self.sqe_flags |= Flags::IO_DRAIN;
34+
}
35+
2036
pub fn get_personality(&self) -> Option<u16> {
2137
self.personality
2238
}
2339

40+
pub fn get_sqe_flags(&self) -> Flags {
41+
self.sqe_flags
42+
}
43+
2444
pub fn buffer_id(&self) -> Option<u16> {
25-
io_uring::cqueue::buffer_select(self.flags)
45+
io_uring::cqueue::buffer_select(self.cqe_flags)
2646
}
2747

2848
pub fn sock_nonempty(&self) -> bool {
29-
io_uring::cqueue::sock_nonempty(self.flags)
49+
io_uring::cqueue::sock_nonempty(self.cqe_flags)
50+
}
51+
52+
pub fn is_notification(&self) -> bool {
53+
io_uring::cqueue::notif(self.cqe_flags)
3054
}
3155
}
3256

@@ -60,7 +84,7 @@ impl crate::sys::Extra {
6084

6185
pub(crate) fn set_flags(&mut self, flag: u32) {
6286
if let Some(extra) = self.try_as_iour_mut() {
63-
extra.flags = flag;
87+
extra.cqe_flags = flag;
6488
}
6589
}
6690
}

0 commit comments

Comments
 (0)