Skip to content

Commit ed6fb94

Browse files
author
Sven Van Asbroeck
committed
rust/kernel: use zero-cost method to construct certain Errors
In a previous PR, the type invariant for `Error` is enforced using a runtime check. This is non-zero cost. However we may decide to trust the return value of certain kernel C functions. In such cases, no runtime check is required to enforce the type invariant. So we can return to zero-cost. This patch removes invariant checks from kernel C functions that return a positive value on success, or a non-zero errno on failure. Signed-off-by: Sven Van Asbroeck <[email protected]>
1 parent ddd659c commit ed6fb94

File tree

2 files changed

+38
-4
lines changed

2 files changed

+38
-4
lines changed

rust/kernel/error.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,3 +290,33 @@ pub(crate) unsafe fn from_kernel_int_result(retval: c_types::c_int) -> Result {
290290
errno => Err(Error::from_kernel_errno_unchecked(errno)),
291291
}
292292
}
293+
294+
/// Transform a kernel integer result to a [`Result<c_types::c_uint>`].
295+
///
296+
/// Some kernel C API functions return a result in the form of an integer:
297+
/// a positive value if ok, a negative errno on error. This function converts
298+
/// such a return value into an idiomatic [`Result<c_types::c_uint>`].
299+
///
300+
/// # Safety
301+
///
302+
/// `retval` must be non-negative or a valid negative errno (i.e. `retval` must
303+
/// be in `[-MAX_ERRNO..]`).
304+
///
305+
/// # Examples
306+
///
307+
/// ```rust,no_run
308+
/// let fd = unsafe { bindings::get_unused_fd_flags(flags) };
309+
/// // SAFETY: `bindings::get_unused_fd_flags()` returns a non-negative
310+
/// // `fd` on success, or a valid negative `errno` on error.
311+
/// let fd = unsafe { from_kernel_int_result_uint(fd)? };
312+
/// ```
313+
pub(crate) unsafe fn from_kernel_int_result_uint(
314+
retval: c_types::c_int,
315+
) -> Result<c_types::c_uint> {
316+
match retval {
317+
// CAST: a non-negative `c_types::c_int` always fits in a `c_types::c_uint`.
318+
success if success >= 0 => Ok(success as c_types::c_uint),
319+
// SAFETY: Safety above and match arm guarantee that `errno` is a valid negative `errno`.
320+
errno => Err(Error::from_kernel_errno_unchecked(errno)),
321+
}
322+
}

rust/kernel/file.rs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,11 @@
55
//! C headers: [`include/linux/fs.h`](../../../../include/linux/fs.h) and
66
//! [`include/linux/file.h`](../../../../include/linux/file.h)
77
8-
use crate::{bindings, error::Error, Result};
8+
use crate::{
9+
bindings,
10+
error::{from_kernel_int_result_uint, Error},
11+
Result,
12+
};
913
use core::{mem::ManuallyDrop, ops::Deref};
1014

1115
/// Wraps the kernel's `struct file`.
@@ -96,9 +100,9 @@ impl FileDescriptorReservation {
96100
/// Creates a new file descriptor reservation.
97101
pub fn new(flags: u32) -> Result<Self> {
98102
let fd = unsafe { bindings::get_unused_fd_flags(flags) };
99-
if fd < 0 {
100-
return Err(Error::from_kernel_errno(fd));
101-
}
103+
// SAFETY: `bindings::get_unused_fd_flags()` returns a non-negative
104+
// `fd` on success, or a valid negative `errno` on error.
105+
let fd = unsafe { from_kernel_int_result_uint(fd)? };
102106
Ok(Self { fd: fd as _ })
103107
}
104108

0 commit comments

Comments
 (0)