diff --git a/rust/helpers.c b/rust/helpers.c index 0eb5c1abcd4db0..eedeae2d366387 100644 --- a/rust/helpers.c +++ b/rust/helpers.c @@ -627,6 +627,12 @@ void rust_helper___INIT_WORK_WITH_KEY(struct work_struct *work, } EXPORT_SYMBOL_GPL(rust_helper___INIT_WORK_WITH_KEY); +struct dentry *rust_helper_dget(struct dentry *dentry) +{ + return dget(dentry); +} +EXPORT_SYMBOL_GPL(rust_helper_dget); + /* * We use `bindgen`'s `--size_t-is-usize` option to bind the C `size_t` type * as the Rust `usize` type, so we can use it in contexts where Rust diff --git a/rust/kernel/amba.rs b/rust/kernel/amba.rs index e687cfcc603419..604e5d802e7277 100644 --- a/rust/kernel/amba.rs +++ b/rust/kernel/amba.rs @@ -95,7 +95,7 @@ impl driver::DriverOps for Adapter { } // SAFETY: By the safety requirements of this function, `reg` is valid and fully // initialised. - to_result(|| unsafe { bindings::amba_driver_register(reg) }) + to_result(unsafe { bindings::amba_driver_register(reg) }) } unsafe fn unregister(reg: *mut bindings::amba_driver) { diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs index 465462b9bc854e..1ec478d96abcc3 100644 --- a/rust/kernel/clk.rs +++ b/rust/kernel/clk.rs @@ -35,7 +35,7 @@ impl Clk { /// This function should not be called in atomic context. pub fn prepare_enable(self) -> Result { // SAFETY: The pointer is valid by the type invariant. - to_result(|| unsafe { bindings::clk_prepare_enable(self.0) })?; + to_result(unsafe { bindings::clk_prepare_enable(self.0) })?; Ok(EnabledClk(self)) } } diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs index 3f0722eefc80e8..8ff91f0306140b 100644 --- a/rust/kernel/error.rs +++ b/rust/kernel/error.rs @@ -551,10 +551,9 @@ pub(crate) fn from_kernel_err_ptr(ptr: *mut T) -> Result<*mut T> { Ok(ptr) } -/// Calls a kernel function that returns an integer error code on failure and converts the result -/// to a [`Result`]. -pub fn to_result(func: impl FnOnce() -> core::ffi::c_int) -> Result { - let err = func(); +/// Converts an integer as returned by a C kernel function to an error if it's negative, and +/// `Ok(())` otherwise. +pub fn to_result(err: core::ffi::c_int) -> Result { if err < 0 { Err(Error::from_kernel_errno(err)) } else { diff --git a/rust/kernel/fs.rs b/rust/kernel/fs.rs new file mode 100644 index 00000000000000..902714e3dd9e76 --- /dev/null +++ b/rust/kernel/fs.rs @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! File systems. +//! +//! C headers: [`include/linux/fs.h`](../../../../include/linux/fs.h) + +use crate::{bindings, AlwaysRefCounted}; +use core::{cell::UnsafeCell, ptr}; + +/// Wraps the kernel's `struct inode`. +/// +/// # Invariants +/// +/// Instances of this type are always ref-counted, that is, a call to `ihold` ensures that the +/// allocation remains valid at least until the matching call to `iput`. +#[repr(transparent)] +pub struct INode(pub(crate) UnsafeCell); + +// SAFETY: The type invariants guarantee that `INode` is always ref-counted. +unsafe impl AlwaysRefCounted for INode { + fn inc_ref(&self) { + // SAFETY: The existence of a shared reference means that the refcount is nonzero. + unsafe { bindings::ihold(self.0.get()) }; + } + + unsafe fn dec_ref(obj: ptr::NonNull) { + // SAFETY: The safety requirements guarantee that the refcount is nonzero. + unsafe { bindings::iput(obj.cast().as_ptr()) } + } +} + +/// Wraps the kernel's `struct dentry`. +/// +/// # Invariants +/// +/// Instances of this type are always ref-counted, that is, a call to `dget` ensures that the +/// allocation remains valid at least until the matching call to `dput`. +#[repr(transparent)] +pub struct DEntry(pub(crate) UnsafeCell); + +// SAFETY: The type invariants guarantee that `DEntry` is always ref-counted. +unsafe impl AlwaysRefCounted for DEntry { + fn inc_ref(&self) { + // SAFETY: The existence of a shared reference means that the refcount is nonzero. + unsafe { bindings::dget(self.0.get()) }; + } + + unsafe fn dec_ref(obj: ptr::NonNull) { + // SAFETY: The safety requirements guarantee that the refcount is nonzero. + unsafe { bindings::dput(obj.cast().as_ptr()) } + } +} diff --git a/rust/kernel/hwrng.rs b/rust/kernel/hwrng.rs index beae38d18f01c1..3e9bd354ab6b56 100644 --- a/rust/kernel/hwrng.rs +++ b/rust/kernel/hwrng.rs @@ -105,7 +105,7 @@ impl Registration { ); // SAFETY: `bindings::hwrng` is initialized above which guarantees safety. - to_result(|| unsafe { bindings::hwrng_register(this.hwrng.get()) })?; + to_result(unsafe { bindings::hwrng_register(this.hwrng.get()) })?; this.registered = true; this.name = Some(name); diff --git a/rust/kernel/irq.rs b/rust/kernel/irq.rs index 3726079ed63467..52706f78105876 100644 --- a/rust/kernel/irq.rs +++ b/rust/kernel/irq.rs @@ -9,8 +9,14 @@ #![allow(dead_code)] -use crate::{bindings, error::from_kernel_result, types::PointerWrapper, Error, Result}; -use core::ops::Deref; +use crate::{ + bindings, + error::{from_kernel_result, to_result}, + str::CString, + types::PointerWrapper, + Error, Result, ScopeGuard, +}; +use core::{fmt, marker::PhantomData, ops::Deref}; use macros::vtable; /// The type of irq hardware numbers. @@ -293,6 +299,301 @@ impl Descriptor { } } +struct InternalRegistration { + irq: u32, + data: *mut core::ffi::c_void, + name: CString, + _p: PhantomData, +} + +impl InternalRegistration { + /// Registers a new irq handler. + /// + /// # Safety + /// + /// Callers must ensure that `handler` and `thread_fn` are compatible with the registration, + /// that is, that they only use their second argument while the call is happening and that they + /// only call [`T::borrow`] on it (e.g., they shouldn't call [`T::from_pointer`] and consume + /// it). + unsafe fn try_new( + irq: core::ffi::c_uint, + handler: bindings::irq_handler_t, + thread_fn: bindings::irq_handler_t, + flags: usize, + data: T, + name: fmt::Arguments<'_>, + ) -> Result { + let ptr = data.into_pointer() as *mut _; + let name = CString::try_from_fmt(name)?; + let guard = ScopeGuard::new(|| { + // SAFETY: `ptr` came from a previous call to `into_pointer`. + unsafe { T::from_pointer(ptr) }; + }); + // SAFETY: `name` and `ptr` remain valid as long as the registration is alive. + to_result(unsafe { + bindings::request_threaded_irq( + irq, + handler, + thread_fn, + flags as _, + name.as_char_ptr(), + ptr, + ) + })?; + guard.dismiss(); + Ok(Self { + irq, + name, + data: ptr, + _p: PhantomData, + }) + } +} + +impl Drop for InternalRegistration { + fn drop(&mut self) { + // Unregister irq handler. + // + // SAFETY: When `try_new` succeeds, the irq was successfully requested, so it is ok to free + // it here. + unsafe { bindings::free_irq(self.irq, self.data) }; + + // Free context data. + // + // SAFETY: This matches the call to `into_pointer` from `try_new` in the success case. + unsafe { T::from_pointer(self.data) }; + } +} + +/// An irq handler. +pub trait Handler { + /// The context data associated with and made available to the handler. + type Data: PointerWrapper; + + /// Called from interrupt context when the irq happens. + fn handle_irq(data: ::Borrowed<'_>) -> Return; +} + +/// The registration of an interrupt handler. +/// +/// # Examples +/// +/// The following is an example of a regular handler with a boxed `u32` as data. +/// +/// ``` +/// # use kernel::prelude::*; +/// use kernel::irq; +/// +/// struct Example; +/// +/// impl irq::Handler for Example { +/// type Data = Box; +/// +/// fn handle_irq(_data: &u32) -> irq::Return { +/// irq::Return::None +/// } +/// } +/// +/// fn request_irq(irq: u32, data: Box) -> Result> { +/// irq::Registration::try_new( +/// irq, data, irq::flags::SHARED, fmt!("example_{irq}")) +/// } +/// ``` +pub struct Registration(InternalRegistration); + +impl Registration { + /// Registers a new irq handler. + /// + /// The valid values of `flags` come from the [`flags`] module. + pub fn try_new( + irq: u32, + data: H::Data, + flags: usize, + name: fmt::Arguments<'_>, + ) -> Result { + // SAFETY: `handler` only calls `H::Data::borrow` on `raw_data`. + Ok(Self(unsafe { + InternalRegistration::try_new(irq, Some(Self::handler), None, flags, data, name)? + })) + } + + unsafe extern "C" fn handler( + _irq: core::ffi::c_int, + raw_data: *mut core::ffi::c_void, + ) -> bindings::irqreturn_t { + // SAFETY: On registration, `into_pointer` was called, so it is safe to borrow from it here + // because `from_pointer` is called only after the irq is unregistered. + let data = unsafe { H::Data::borrow(raw_data) }; + H::handle_irq(data) as _ + } +} + +/// A threaded irq handler. +pub trait ThreadedHandler { + /// The context data associated with and made available to the handlers. + type Data: PointerWrapper; + + /// Called from interrupt context when the irq first happens. + fn handle_primary_irq(_data: ::Borrowed<'_>) -> Return { + Return::WakeThread + } + + /// Called from the handler thread. + fn handle_threaded_irq(data: ::Borrowed<'_>) -> Return; +} + +/// The registration of a threaded interrupt handler. +/// +/// # Examples +/// +/// The following is an example of a threaded handler with a ref-counted u32 as data: +/// +/// ``` +/// # use kernel::prelude::*; +/// use kernel::{irq, sync::{Ref, RefBorrow}}; +/// +/// struct Example; +/// +/// impl irq::ThreadedHandler for Example { +/// type Data = Ref; +/// +/// fn handle_threaded_irq(_data: RefBorrow<'_, u32>) -> irq::Return { +/// irq::Return::None +/// } +/// } +/// +/// fn request_irq(irq: u32, data: Ref) -> Result> { +/// irq::ThreadedRegistration::try_new( +/// irq, data, irq::flags::SHARED, fmt!("example_{irq}")) +/// } +/// ``` +pub struct ThreadedRegistration(InternalRegistration); + +impl ThreadedRegistration { + /// Registers a new threaded irq handler. + /// + /// The valid values of `flags` come from the [`flags`] module. + pub fn try_new( + irq: u32, + data: H::Data, + flags: usize, + name: fmt::Arguments<'_>, + ) -> Result { + // SAFETY: both `primary_handler` and `threaded_handler` only call `H::Data::borrow` on + // `raw_data`. + Ok(Self(unsafe { + InternalRegistration::try_new( + irq, + Some(Self::primary_handler), + Some(Self::threaded_handler), + flags, + data, + name, + )? + })) + } + + unsafe extern "C" fn primary_handler( + _irq: core::ffi::c_int, + raw_data: *mut core::ffi::c_void, + ) -> bindings::irqreturn_t { + // SAFETY: On registration, `into_pointer` was called, so it is safe to borrow from it here + // because `from_pointer` is called only after the irq is unregistered. + let data = unsafe { H::Data::borrow(raw_data) }; + H::handle_primary_irq(data) as _ + } + + unsafe extern "C" fn threaded_handler( + _irq: core::ffi::c_int, + raw_data: *mut core::ffi::c_void, + ) -> bindings::irqreturn_t { + // SAFETY: On registration, `into_pointer` was called, so it is safe to borrow from it here + // because `from_pointer` is called only after the irq is unregistered. + let data = unsafe { H::Data::borrow(raw_data) }; + H::handle_threaded_irq(data) as _ + } +} + +/// The return value from interrupt handlers. +pub enum Return { + /// The interrupt was not from this device or was not handled. + None = bindings::irqreturn_IRQ_NONE as _, + + /// The interrupt was handled by this device. + Handled = bindings::irqreturn_IRQ_HANDLED as _, + + /// The handler wants the handler thread to wake up. + WakeThread = bindings::irqreturn_IRQ_WAKE_THREAD as _, +} + +/// Container for interrupt flags. +pub mod flags { + use crate::bindings; + + /// Use the interrupt line as already configured. + pub const TRIGGER_NONE: usize = bindings::IRQF_TRIGGER_NONE as _; + + /// The interrupt is triggered when the signal goes from low to high. + pub const TRIGGER_RISING: usize = bindings::IRQF_TRIGGER_RISING as _; + + /// The interrupt is triggered when the signal goes from high to low. + pub const TRIGGER_FALLING: usize = bindings::IRQF_TRIGGER_FALLING as _; + + /// The interrupt is triggered while the signal is held high. + pub const TRIGGER_HIGH: usize = bindings::IRQF_TRIGGER_HIGH as _; + + /// The interrupt is triggered while the signal is held low. + pub const TRIGGER_LOW: usize = bindings::IRQF_TRIGGER_LOW as _; + + /// Allow sharing the irq among several devices. + pub const SHARED: usize = bindings::IRQF_SHARED as _; + + /// Set by callers when they expect sharing mismatches to occur. + pub const PROBE_SHARED: usize = bindings::IRQF_PROBE_SHARED as _; + + /// Flag to mark this interrupt as timer interrupt. + pub const TIMER: usize = bindings::IRQF_TIMER as _; + + /// Interrupt is per cpu. + pub const PERCPU: usize = bindings::IRQF_PERCPU as _; + + /// Flag to exclude this interrupt from irq balancing. + pub const NOBALANCING: usize = bindings::IRQF_NOBALANCING as _; + + /// Interrupt is used for polling (only the interrupt that is registered first in a shared + /// interrupt is considered for performance reasons). + pub const IRQPOLL: usize = bindings::IRQF_IRQPOLL as _; + + /// Interrupt is not reenabled after the hardirq handler finished. Used by threaded interrupts + /// which need to keep the irq line disabled until the threaded handler has been run. + pub const ONESHOT: usize = bindings::IRQF_ONESHOT as _; + + /// Do not disable this IRQ during suspend. Does not guarantee that this interrupt will wake + /// the system from a suspended state. + pub const NO_SUSPEND: usize = bindings::IRQF_NO_SUSPEND as _; + + /// Force enable it on resume even if [`NO_SUSPEND`] is set. + pub const FORCE_RESUME: usize = bindings::IRQF_FORCE_RESUME as _; + + /// Interrupt cannot be threaded. + pub const NO_THREAD: usize = bindings::IRQF_NO_THREAD as _; + + /// Resume IRQ early during syscore instead of at device resume time. + pub const EARLY_RESUME: usize = bindings::IRQF_EARLY_RESUME as _; + + /// If the IRQ is shared with a NO_SUSPEND user, execute this interrupt handler after + /// suspending interrupts. For system wakeup devices users need to implement wakeup detection + /// in their interrupt handlers. + pub const COND_SUSPEND: usize = bindings::IRQF_COND_SUSPEND as _; + + /// Don't enable IRQ or NMI automatically when users request it. Users will enable it + /// explicitly by `enable_irq` or `enable_nmi` later. + pub const NO_AUTOEN: usize = bindings::IRQF_NO_AUTOEN as _; + + /// Exclude from runnaway detection for IPI and similar handlers, depends on `PERCPU`. + pub const NO_DEBUG: usize = bindings::IRQF_NO_DEBUG as _; +} + /// A guard to call `chained_irq_exit` after `chained_irq_enter` was called. /// /// It is also used as evidence that a previous `chained_irq_enter` was called. So there are no diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 1cf04315d07fc5..8eb203a99c21db 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -51,6 +51,7 @@ pub mod device; pub mod driver; pub mod error; pub mod file; +pub mod fs; pub mod gpio; pub mod hwrng; pub mod irq; @@ -106,7 +107,7 @@ pub use build_error::build_error; pub use crate::error::{to_result, Error, Result}; pub use crate::types::{ bit, bits_iter, ARef, AlwaysRefCounted, Bool, Either, Either::Left, Either::Right, False, Mode, - Opaque, ScopeGuard, True, + Opaque, PointerWrapper, ScopeGuard, True, }; use core::marker::PhantomData; diff --git a/rust/kernel/mm.rs b/rust/kernel/mm.rs index 322f94f501e09b..8a69c69dddd985 100644 --- a/rust/kernel/mm.rs +++ b/rust/kernel/mm.rs @@ -66,7 +66,7 @@ pub mod virt { // SAFETY: The page is guaranteed to be order 0 by the type system. The range of // `address` is already checked by `vm_insert_page`. `self.vma` and `page.pages` are // guaranteed by their repective type invariants to be valid. - to_result(|| unsafe { bindings::vm_insert_page(self.vma, address as _, page.pages) }) + to_result(unsafe { bindings::vm_insert_page(self.vma, address as _, page.pages) }) } } diff --git a/rust/kernel/net.rs b/rust/kernel/net.rs index 0495ab77814472..0115f3a35cd0fc 100644 --- a/rust/kernel/net.rs +++ b/rust/kernel/net.rs @@ -260,7 +260,7 @@ impl TcpListener { }; // SAFETY: The namespace is valid and the output socket pointer is valid for write. - to_result(|| unsafe { + to_result(unsafe { bindings::sock_create_kern( ns.0.get(), pf as _, @@ -275,10 +275,10 @@ impl TcpListener { // SAFETY: The type invariant guarantees that the socket is valid, and `addr` and `addrlen` // were initialised based on valid values provided in the address enum. - to_result(|| unsafe { bindings::kernel_bind(socket, addr, addrlen as _) })?; + to_result(unsafe { bindings::kernel_bind(socket, addr, addrlen as _) })?; // SAFETY: The socket is valid per the type invariant. - to_result(|| unsafe { bindings::kernel_listen(socket, bindings::SOMAXCONN as _) })?; + to_result(unsafe { bindings::kernel_listen(socket, bindings::SOMAXCONN as _) })?; Ok(listener) } @@ -295,7 +295,7 @@ impl TcpListener { let flags = if block { 0 } else { bindings::O_NONBLOCK }; // SAFETY: The type invariant guarantees that the socket is valid, and the output argument // is also valid for write. - to_result(|| unsafe { bindings::kernel_accept(self.sock, &mut new, flags as _) })?; + to_result(unsafe { bindings::kernel_accept(self.sock, &mut new, flags as _) })?; Ok(TcpStream { sock: new }) } } diff --git a/rust/kernel/net/filter.rs b/rust/kernel/net/filter.rs index 95f47c6b4197e9..a50422d538480d 100644 --- a/rust/kernel/net/filter.rs +++ b/rust/kernel/net/filter.rs @@ -213,7 +213,7 @@ impl Registration { // SAFETY: `ns` has a valid reference to the namespace, and `this.hook` was just // initialised above, so they're both valid. - to_result(|| unsafe { bindings::nf_register_net_hook(ns.0.get(), &this.hook) })?; + to_result(unsafe { bindings::nf_register_net_hook(ns.0.get(), &this.hook) })?; this.dev = dev; this.ns = Some(ns); diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 7cf85d3fdc789f..d8cc0e0120aad6 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -49,7 +49,7 @@ impl driver::DriverOps for Adapter { // - `probe()` and `remove()` are static functions. // - `of_match_table` is either a raw pointer with static lifetime, // as guaranteed by the [`driver::IdTable`] type, or null. - to_result(|| unsafe { bindings::__platform_driver_register(reg, module.0) }) + to_result(unsafe { bindings::__platform_driver_register(reg, module.0) }) } unsafe fn unregister(reg: *mut bindings::platform_driver) { diff --git a/rust/kernel/security.rs b/rust/kernel/security.rs index eecf6dbf785116..0a33363289d3b2 100644 --- a/rust/kernel/security.rs +++ b/rust/kernel/security.rs @@ -10,21 +10,21 @@ use crate::{bindings, cred::Credential, file::File, to_result, Result}; /// context. pub fn binder_set_context_mgr(mgr: &Credential) -> Result { // SAFETY: `mrg.0` is valid because the shared reference guarantees a nonzero refcount. - to_result(|| unsafe { bindings::security_binder_set_context_mgr(mgr.0.get()) }) + to_result(unsafe { bindings::security_binder_set_context_mgr(mgr.0.get()) }) } /// Calls the security modules to determine if binder transactions are allowed from task `from` to /// task `to`. pub fn binder_transaction(from: &Credential, to: &Credential) -> Result { // SAFETY: `from` and `to` are valid because the shared references guarantee nonzero refcounts. - to_result(|| unsafe { bindings::security_binder_transaction(from.0.get(), to.0.get()) }) + to_result(unsafe { bindings::security_binder_transaction(from.0.get(), to.0.get()) }) } /// Calls the security modules to determine if task `from` is allowed to send binder objects /// (owned by itself or other processes) to task `to` through a binder transaction. pub fn binder_transfer_binder(from: &Credential, to: &Credential) -> Result { // SAFETY: `from` and `to` are valid because the shared references guarantee nonzero refcounts. - to_result(|| unsafe { bindings::security_binder_transfer_binder(from.0.get(), to.0.get()) }) + to_result(unsafe { bindings::security_binder_transfer_binder(from.0.get(), to.0.get()) }) } /// Calls the security modules to determine if task `from` is allowed to send the given file to @@ -32,7 +32,7 @@ pub fn binder_transfer_binder(from: &Credential, to: &Credential) -> Result { pub fn binder_transfer_file(from: &Credential, to: &Credential, file: &File) -> Result { // SAFETY: `from`, `to` and `file` are valid because the shared references guarantee nonzero // refcounts. - to_result(|| unsafe { + to_result(unsafe { bindings::security_binder_transfer_file(from.0.get(), to.0.get(), file.0.get()) }) } diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs index 01ed8e8d674e43..c8d11ca8f09681 100644 --- a/rust/kernel/task.rs +++ b/rust/kernel/task.rs @@ -180,13 +180,22 @@ impl Task { // SAFETY: Since the kthread creation succeeded and we haven't run it yet, we know the task // is valid. - let task = unsafe { &*(ktask as *const Task) }.into(); + let task: ARef<_> = unsafe { &*(ktask as *const Task) }.into(); + + // Wakes up the thread, otherwise it won't run. + task.wake_up(); - // SAFETY: Since the kthread creation succeeded, we know `ktask` is valid. - unsafe { bindings::wake_up_process(ktask) }; guard.dismiss(); Ok(task) } + + /// Wakes up the task. + pub fn wake_up(&self) { + // SAFETY: By the type invariant, we know that `self.0.get()` is non-null and valid. + // And `wake_up_process` is safe to be called for any valid task, even if the task is + // running. + unsafe { bindings::wake_up_process(self.0.get()) }; + } } // SAFETY: The type invariants guarantee that `Task` is always ref-counted. diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 26dcfd596f711c..f685e2e8876765 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -40,7 +40,8 @@ impl Mode { /// Used to convert an object into a raw pointer that represents it. /// /// It can eventually be converted back into the object. This is used to store objects as pointers -/// in kernel data structures, for example, an implementation of [`FileOperations`] in `struct +/// in kernel data structures, for example, an implementation of +/// [`Operations`][crate::file::Operations] in `struct /// file::private_data`. pub trait PointerWrapper { /// Type of values borrowed between calls to [`PointerWrapper::into_pointer`] and