diff --git a/drivers/char/rust_example.rs b/drivers/char/rust_example.rs index e1db8db782fb51..20b537336a06fe 100644 --- a/drivers/char/rust_example.rs +++ b/drivers/char/rust_example.rs @@ -148,7 +148,7 @@ impl KernelModule for RustExample { Ok(RustExample { message: "on the heap!".to_owned(), - _dev: miscdev::Registration::new_pinned::(cstr!("rust_miscdev"), None)?, + _dev: miscdev::Registration::new_pinned::(cstr!("rust_miscdev"), None, ())?, _chrdev: chrdev_reg, }) } diff --git a/rust/kernel/miscdev.rs b/rust/kernel/miscdev.rs index 1cdb4bee2a3f54..bdd07e6194b607 100644 --- a/rust/kernel/miscdev.rs +++ b/rust/kernel/miscdev.rs @@ -14,33 +14,38 @@ use core::marker::PhantomPinned; use core::pin::Pin; /// A registration of a miscellaneous device. -pub struct Registration { +pub struct Registration { registered: bool, mdev: bindings::miscdevice, _pin: PhantomPinned, + + /// Context initialised on construction. + pub context: T, } -impl Registration { +impl Registration { /// Creates a new [`Registration`] but does not register it yet. /// /// It is allowed to move. - pub fn new() -> Self { + pub fn new(context: T) -> Self { Self { registered: false, mdev: bindings::miscdevice::default(), _pin: PhantomPinned, + context, } } /// Registers a miscellaneous device. /// /// Returns a pinned heap-allocated representation of the registration. - pub fn new_pinned( + pub fn new_pinned( name: CStr<'static>, minor: Option, + context: T, ) -> KernelResult>> { - let mut r = Pin::from(Box::try_new(Self::new())?); - r.as_mut().register::(name, minor)?; + let mut r = Pin::from(Box::try_new(Self::new(context))?); + r.as_mut().register::(name, minor)?; Ok(r) } @@ -48,7 +53,7 @@ impl Registration { /// /// It must be pinned because the memory block that represents the registration is /// self-referential. If a minor is not given, the kernel allocates a new one if possible. - pub fn register( + pub fn register( self: Pin<&mut Self>, name: CStr<'static>, minor: Option, @@ -60,7 +65,7 @@ impl Registration { return Err(Error::EINVAL); } - this.mdev.fops = FileOperationsVtable::::build(); + this.mdev.fops = FileOperationsVtable::::build(); this.mdev.name = name.as_ptr() as *const c_types::c_char; this.mdev.minor = minor.unwrap_or(bindings::MISC_DYNAMIC_MINOR as i32); @@ -73,17 +78,17 @@ impl Registration { } } -impl Default for Registration { - fn default() -> Self { - Self::new() - } -} - // SAFETY: The only method is `register()`, which requires a (pinned) mutable `Registration`, so it -// is safe to pass `&Registration` to multiple threads because it offers no interior mutability. -unsafe impl Sync for Registration {} +// is safe to pass `&Registration` to multiple threads because it offers no interior mutability, +// except maybe through `Registration::context`, but it is itself `Sync`. +unsafe impl Sync for Registration {} + +// SAFETY: All functions work from any thread. So as long as the `Registration::context` is +// `Send`, so is `Registration`. `T` needs to be `Sync` because it's a requirement of +// `Registration`. +unsafe impl Send for Registration {} -impl Drop for Registration { +impl Drop for Registration { /// Removes the registration from the kernel if it has completed successfully before. fn drop(&mut self) { if self.registered {