Skip to content

Commit 79fcf6b

Browse files
author
Sven Van Asbroeck
committed
rust/kernel: introduce zero-cost from_kernel_int_result_uint()
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 5e932f0 commit 79fcf6b

File tree

2 files changed

+42
-4
lines changed

2 files changed

+42
-4
lines changed

rust/kernel/error.rs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,4 +295,38 @@ pub(crate) unsafe fn from_kernel_int_result(retval: c_types::c_int) -> Result {
295295
}
296296
Ok(())
297297
}
298+
299+
/// Transform a kernel integer result to a [`Result<c_types::c_uint>`].
300+
///
301+
/// Some kernel C API functions return a result in the form of an integer:
302+
/// zero or positive if ok, a negative errno on error. This function converts
303+
/// such a return value into an idiomatic [`Result<c_types::c_uint>`].
304+
///
305+
/// Use this function when the C function returns a useful, positive value
306+
/// on success, or negative on error. If the C function only returns 0 on
307+
/// success, use [`from_kernel_int_result`] instead.
308+
///
309+
/// # Safety
310+
///
311+
/// `retval` must be non-negative or a valid negative errno (i.e. `retval` must
312+
/// be in `[-MAX_ERRNO..]`).
313+
///
314+
/// # Examples
315+
///
316+
/// ```rust,no_run
317+
/// let fd = unsafe { bindings::get_unused_fd_flags(flags) };
318+
/// // SAFETY: `bindings::get_unused_fd_flags()` returns a non-negative
319+
/// // `fd` on success, or a valid negative `errno` on error.
320+
/// let fd = unsafe { from_kernel_int_result_uint(fd)? };
321+
/// ```
322+
pub(crate) unsafe fn from_kernel_int_result_uint(
323+
retval: c_types::c_int,
324+
) -> Result<c_types::c_uint> {
325+
if retval < 0 {
326+
// SAFETY: This condition together with the function precondition
327+
// guarantee that `errno` is a valid negative `errno`.
328+
return Err(unsafe { Error::from_kernel_errno_unchecked(retval) });
329+
}
330+
// CAST: a non-negative `c_types::c_int` always fits in a `c_types::c_uint`.
331+
Ok(retval as c_types::c_uint)
298332
}

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)