1#[derive(thiserror::Error, Debug)]
3#[non_exhaustive]
4pub enum Error {
5 #[error("unsupported kernel: {0}")]
9 Unsupported(String),
10
11 #[error("io error: {0}")]
13 Io(#[from] std::io::Error),
14}
15
16impl Error {
17 pub(crate) fn ring(err: std::io::Error) -> Self {
24 if err.raw_os_error() != Some(libc::ENOMEM) {
25 return Self::Io(err);
26 }
27 let mut limit = libc::rlimit {
28 rlim_cur: 0,
29 rlim_max: 0,
30 };
31 let limit = match unsafe { libc::getrlimit(libc::RLIMIT_MEMLOCK, &mut limit) } {
33 0 => format!("{} KiB", limit.rlim_cur / 1024),
34 _ => "unknown".into(),
35 };
36 Self::Io(std::io::Error::new(
37 err.kind(),
38 format!(
39 "{err}: io_uring memory counts against RLIMIT_MEMLOCK ({limit}), shared by every process of this user; \
40 raise it with `ulimit -l` or systemd's `LimitMEMLOCK=`"
41 ),
42 ))
43 }
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49
50 #[test]
51 fn a_ring_enomem_names_the_memlock_limit() {
52 let err = Error::ring(std::io::Error::from_raw_os_error(libc::ENOMEM));
53 assert!(err.to_string().contains("RLIMIT_MEMLOCK"), "{err}");
54
55 let err = Error::ring(std::io::Error::from_raw_os_error(libc::EBADF));
56 assert!(!err.to_string().contains("RLIMIT_MEMLOCK"), "{err}");
57 }
58}