Re: [PATCH v16 8/9] task: rust: rework how current is accessed

Boqun Feng
2025-05-07T16:55:46Z

On Wed, May 07, 2025 at 09:46:23AM -0700, Boqun Feng wrote:
> On Wed, May 07, 2025 at 09:06:01AM -0700, Boqun Feng wrote:
> [...]
> > > +impl CurrentTask {
> > > + /// Access the address space of the current task.
> > > + ///
> > > + /// This function does not touch the refcount of the mm.
> > > + #[inline]
> > > + pub fn mm(&self) -> Option<&MmWithUser> {
> > > + // SAFETY: The `mm` field of `current` is not modified from other threads, so reading it is
> > > + // not a data race.
> > > + let mm = unsafe { (*self.as_ptr()).mm };
> > > +
> > > + if mm.is_null() {
> > > + return None;
> > > + }
> > > +
> > > + // SAFETY: If `current->mm` is non-null, then it references a valid mm with a non-zero
> > > + // value of `mm_users`. Furthermore, the returned `&MmWithUser` borrows from this
> > > + // `CurrentTask`, so it cannot escape the scope in which the current pointer was obtained.
> > > + //
> > > + // This is safe even if `kthread_use_mm()`/`kthread_unuse_mm()` are used. There are two
> > > + // relevant cases:
> > > + // * If the `&CurrentTask` was created before `kthread_use_mm()`, then it cannot be
> > > + // accessed during the `kthread_use_mm()`/`kthread_unuse_mm()` scope due to the
> > > + // `NotThreadSafe` field of `CurrentTask`.
> > > + // * If the `&CurrentTask` was created within a `kthread_use_mm()`/`kthread_unuse_mm()`
> > > + // scope, then the `&CurrentTask` cannot escape that scope, so the returned `&MmWithUser`
> > > + // also cannot escape that scope.
> > > + // In either case, it's not possible to read `current->mm` and keep using it after the
> > > + // scope is ended with `kthread_unuse_mm()`.
> > > + Some(unsafe { MmWithUser::from_raw(mm) })
> > > + }
> > > +
> >
> > Due to this:
> >
> > https://lore.kernel.org/oe-kbuild-all/202505072116.eSYC8igT-lkp@intel.com/
> >
> > , I think we should move this impl block into rust/kernel/mm.rs for now,
> > i.e. (in rust/kernel/mm.rs)
> >
> > impl crate::task::CurrentTask {
> > pub fn mm(&self) -> Option<&MmWithUser> { ... }
> > }
> >
> > Thoughts?
> >
>
> Hmm.. this alone won't be enough, because miscdevice also uses mm. Maybe
> you could most of mm defined even when CONFIG_MMU=n but keep
> MmWithUserAsync only available when CONFIG_MMU=y?
>

Something like this, probably? But your choice ;-) Make CONFIG_RUST
select CONFIG_MMU is fine but the question is who is going to unselect
that at when?

Regards,
Boqun

------------------>8
diff --git a/rust/kernel/mm.rs b/rust/kernel/mm.rs
index 615907a0f3b4..8a1c8158f2b3 100644
--- a/rust/kernel/mm.rs
+++ b/rust/kernel/mm.rs
@@ -10,7 +10,6 @@
//! control what happens when userspace reads or writes to that region of memory.
//!
//! C header: [`include/linux/mm.h`](srctree/include/linux/mm.h)
-#![cfg(CONFIG_MMU)]

use crate::{
bindings,
@@ -130,6 +129,7 @@ unsafe impl Send for MmWithUserAsync {}
// SAFETY: All methods on `MmWithUserAsync` can be called in parallel from several threads.
unsafe impl Sync for MmWithUserAsync {}

+#[cfg(CONFIG_MMU)]
// SAFETY: By the type invariants, this type is always refcounted.
unsafe impl AlwaysRefCounted for MmWithUserAsync {
#[inline]
@@ -207,6 +207,7 @@ pub unsafe fn from_raw<'a>(ptr: *const bindings::mm_struct) -> &'a MmWithUser {
}

/// Use `mmput_async` when dropping this refcount.
+ #[cfg(CONFIG_MMU)]
#[inline]
pub fn into_mmput_async(me: ARef<MmWithUser>) -> ARef<MmWithUserAsync> {
// SAFETY: The layouts and invariants are compatible.