On 01.08.24 14:58, Alice Ryhl wrote: > diff --git a/rust/kernel/mm.rs b/rust/kernel/mm.rs > new file mode 100644 > index 000000000000..ed2db893fb79 > --- /dev/null > +++ b/rust/kernel/mm.rs > @@ -0,0 +1,337 @@ > +// SPDX-License-Identifier: GPL-2.0 > + > +// Copyright (C) 2024 Google LLC. > + > +//! Memory management. > +//! > +//! C header: [`include/linux/mm.h`](../../../../include/linux/mm.h) > + > +use crate::{ > + bindings, > + types::{ARef, AlwaysRefCounted, Opaque}, > +}; > + > +use core::{ > + ops::Deref, > + ptr::{self, NonNull}, > +}; > + > +pub mod virt; > + > +/// A wrapper for the kernel's `struct mm_struct`. > +/// > +/// Since `mm_users` may be zero, the associated address space may not exist anymore. You must use Can it also be the case that the space never existed to begin with? Then I would write "the associated address space may not exist." Also I think it makes more sense to use "You can use [`mmget_not_zero`] to be able to access the address space." instead of the second sentence. > +/// [`mmget_not_zero`] before accessing the address space. > +/// > +/// The `ARef<Mm>` smart pointer holds an `mmgrab` refcount. Its destructor may sleep. > +/// > +/// # Invariants > +/// > +/// Values of this type are always refcounted. Would be good to record the refcount used in the invariant. > +/// > +/// [`mmget_not_zero`]: Mm::mmget_not_zero > +pub struct Mm { > + mm: Opaque<bindings::mm_struct>, > +} > + > +// SAFETY: It is safe to call `mmdrop` on another thread than where `mmgrab` was called. > +unsafe impl Send for Mm {} > +// SAFETY: All methods on `Mm` can be called in parallel from several threads. > +unsafe impl Sync for Mm {} > + > +// SAFETY: By the type invariants, this type is always refcounted. > +unsafe impl AlwaysRefCounted for Mm { > + fn inc_ref(&self) { > + // SAFETY: The pointer is valid since self is a reference. > + unsafe { bindings::mmgrab(self.as_raw()) }; > + } > + > + unsafe fn dec_ref(obj: NonNull<Self>) { > + // SAFETY: The caller is giving up their refcount. > + unsafe { bindings::mmdrop(obj.cast().as_ptr()) }; > + } > +} > + > +/// A wrapper for the kernel's `struct mm_struct`. > +/// > +/// This type is used only when `mm_users` is known to be non-zero at compile-time. It can be used I find the "This type is used only when" a bit weird, what about "Like an [`Mm`], but with non-zero `mm_users`."? > +/// to access the associated address space. > +/// > +/// The `ARef<MmWithUser>` smart pointer holds an `mmget` refcount. Its destructor may sleep. > +/// > +/// # Invariants > +/// > +/// Values of this type are always refcounted. The value of `mm_users` is non-zero. > +#[repr(transparent)] > +pub struct MmWithUser { > + mm: Mm, > +} > + > +// SAFETY: It is safe to call `mmput` on another thread than where `mmget` was called. > +unsafe impl Send for MmWithUser {} > +// SAFETY: All methods on `MmWithUser` can be called in parallel from several threads. > +unsafe impl Sync for MmWithUser {} > + > +// SAFETY: By the type invariants, this type is always refcounted. > +unsafe impl AlwaysRefCounted for MmWithUser { > + fn inc_ref(&self) { > + // SAFETY: The pointer is valid since self is a reference. > + unsafe { bindings::mmget(self.as_raw()) }; > + } > + > + unsafe fn dec_ref(obj: NonNull<Self>) { > + // SAFETY: The caller is giving up their refcount. > + unsafe { bindings::mmput(obj.cast().as_ptr()) }; > + } > +} > + > +// Make all `Mm` methods available on `MmWithUser`. > +impl Deref for MmWithUser { > + type Target = Mm; > + > + #[inline] > + fn deref(&self) -> &Mm { > + &self.mm > + } > +} > + > +/// A wrapper for the kernel's `struct mm_struct`. > +/// > +/// This type is identical to `MmWithUser` except that it uses `mmput_async` when dropping a > +/// refcount. This means that the destructor of `ARef<MmWithUserAsync>` is safe to call in atomic > +/// context. Missing Invariants. > +#[repr(transparent)] > +pub struct MmWithUserAsync { > + mm: MmWithUser, > +} > + > +// SAFETY: It is safe to call `mmput_async` on another thread than where `mmget` was called. > +unsafe impl Send for MmWithUserAsync {} > +// SAFETY: All methods on `MmWithUserAsync` can be called in parallel from several threads. > +unsafe impl Sync for MmWithUserAsync {} > + > +// SAFETY: By the type invariants, this type is always refcounted. > +unsafe impl AlwaysRefCounted for MmWithUserAsync { > + fn inc_ref(&self) { > + // SAFETY: The pointer is valid since self is a reference. > + unsafe { bindings::mmget(self.as_raw()) }; > + } > + > + unsafe fn dec_ref(obj: NonNull<Self>) { > + // SAFETY: The caller is giving up their refcount. > + unsafe { bindings::mmput_async(obj.cast().as_ptr()) }; > + } > +} > + > +// Make all `MmWithUser` methods available on `MmWithUserAsync`. > +impl Deref for MmWithUserAsync { > + type Target = MmWithUser; > + > + #[inline] > + fn deref(&self) -> &MmWithUser { > + &self.mm > + } > +} > + > +// These methods are safe to call even if `mm_users` is zero. > +impl Mm { > + /// Call `mmgrab` on `current.mm`. > + #[inline] > + pub fn mmgrab_current() -> Option<ARef<Mm>> { > + // SAFETY: It's safe to get the `mm` field from current. > + let mm = unsafe { > + let current = bindings::get_current(); > + (*current).mm > + }; > + > + let mm = NonNull::new(mm)?; > + > + // SAFETY: We just checked that `mm` is not null. > + unsafe { bindings::mmgrab(mm.as_ptr()) }; > + > + // SAFETY: We just created an `mmgrab` refcount. Layouts are compatible due to > + // repr(transparent). > + Some(unsafe { ARef::from_raw(mm.cast()) }) > + } > + > + /// Returns a raw pointer to the inner `mm_struct`. > + #[inline] > + pub fn as_raw(&self) -> *mut bindings::mm_struct { > + self.mm.get() > + } > + > + /// Obtain a reference from a raw pointer. > + /// > + /// # Safety > + /// > + /// The caller must ensure that `ptr` points at an `mm_struct`, and that it is not deallocated > + /// during the lifetime 'a. > + #[inline] > + pub unsafe fn from_raw_mm<'a>(ptr: *const bindings::mm_struct) -> &'a Mm { Why not just `from_raw`? --- Cheers, Benno > + // SAFETY: Caller promises that the pointer is valid for 'a. Layouts are compatible due to > + // repr(transparent). > + unsafe { &*ptr.cast() } > + }