297 lines · 9.7 KB · Rust
RawDownload
// SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2024 Google LLC. //! Memory management.//!//! This module deals with managing the address space of userspace processes. Each process has an//! instance of [`Mm`], which keeps track of multiple VMAs (virtual memory areas). Each VMA//! corresponds to a region of memory that the userspace process can access, and the VMA lets you//! control what happens when userspace reads or writes to that region of memory.//!//! C header: [`include/linux/mm.h`](srctree/include/linux/mm.h) use crate::{    bindings,    sync::aref::{ARef, AlwaysRefCounted},    types::{NotThreadSafe, Opaque},};use core::{ops::Deref, ptr::NonNull}; pub mod virt;use virt::VmaRef; #[cfg(CONFIG_MMU)]pub use mmput_async::MmWithUserAsync;mod mmput_async; /// A wrapper for the kernel's `struct mm_struct`.////// This represents the address space of a userspace process, so each process has one `Mm`/// instance. It may hold many VMAs internally.////// There is a counter called `mm_users` that counts the users of the address space; this includes/// the userspace process itself, but can also include kernel threads accessing the address space./// Once `mm_users` reaches zero, this indicates that the address space can be destroyed. To access/// the address space, you must prevent `mm_users` from reaching zero while you are accessing it./// The [`MmWithUser`] type represents an address space where this is guaranteed, and you can/// create one using [`mmget_not_zero`].////// The `ARef<Mm>` smart pointer holds an `mmgrab` refcount. Its destructor may sleep.////// # Invariants////// Values of this type are always refcounted using `mmgrab`.////// [`mmget_not_zero`]: Mm::mmget_not_zero#[repr(transparent)]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 {    #[inline]    fn inc_ref(&self) {        // SAFETY: The pointer is valid since self is a reference.        unsafe { bindings::mmgrab(self.as_raw()) };    }     #[inline]    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 like [`Mm`], but with non-zero `mm_users`. It can only be used when `mm_users` can/// be proven to be non-zero at compile-time, usually because the relevant code holds an `mmget`/// refcount. It can be used 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 using `mmget`. 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 {    #[inline]    fn inc_ref(&self) {        // SAFETY: The pointer is valid since self is a reference.        unsafe { bindings::mmget(self.as_raw()) };    }     #[inline]    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    }} // These methods are safe to call even if `mm_users` is zero.impl Mm {    /// 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<'a>(ptr: *const bindings::mm_struct) -> &'a Mm {        // SAFETY: Caller promises that the pointer is valid for 'a. Layouts are compatible due to        // repr(transparent).        unsafe { &*ptr.cast() }    }     /// Calls `mmget_not_zero` and returns a handle if it succeeds.    #[inline]    pub fn mmget_not_zero(&self) -> Option<ARef<MmWithUser>> {        // SAFETY: The pointer is valid since self is a reference.        let success = unsafe { bindings::mmget_not_zero(self.as_raw()) };         if success {            // SAFETY: We just created an `mmget` refcount.            Some(unsafe { ARef::from_raw(NonNull::new_unchecked(self.as_raw().cast())) })        } else {            None        }    }} // These methods require `mm_users` to be non-zero.impl MmWithUser {    /// Obtain a reference from a raw pointer.    ///    /// # Safety    ///    /// The caller must ensure that `ptr` points at an `mm_struct`, and that `mm_users` remains    /// non-zero for the duration of the lifetime 'a.    #[inline]    pub unsafe fn from_raw<'a>(ptr: *const bindings::mm_struct) -> &'a MmWithUser {        // SAFETY: Caller promises that the pointer is valid for 'a. The layout is compatible due        // to repr(transparent).        unsafe { &*ptr.cast() }    }     /// Attempt to access a vma using the vma read lock.    ///    /// This is an optimistic trylock operation, so it may fail if there is contention. In that    /// case, you should fall back to taking the mmap read lock.    ///    /// When per-vma locks are disabled, this always returns `None`.    #[inline]    pub fn lock_vma_under_rcu(&self, vma_addr: usize) -> Option<VmaReadGuard<'_>> {        #[cfg(CONFIG_PER_VMA_LOCK)]        {            // SAFETY: Calling `bindings::lock_vma_under_rcu` is always okay given an mm where            // `mm_users` is non-zero.            let vma = unsafe { bindings::lock_vma_under_rcu(self.as_raw(), vma_addr) };            if !vma.is_null() {                return Some(VmaReadGuard {                    // SAFETY: If `lock_vma_under_rcu` returns a non-null ptr, then it points at a                    // valid vma. The vma is stable for as long as the vma read lock is held.                    vma: unsafe { VmaRef::from_raw(vma) },                    _nts: NotThreadSafe,                });            }        }         // Silence warnings about unused variables.        #[cfg(not(CONFIG_PER_VMA_LOCK))]        let _ = vma_addr;         None    }     /// Lock the mmap read lock.    #[inline]    pub fn mmap_read_lock(&self) -> MmapReadGuard<'_> {        // SAFETY: The pointer is valid since self is a reference.        unsafe { bindings::mmap_read_lock(self.as_raw()) };         // INVARIANT: We just acquired the read lock.        MmapReadGuard {            mm: self,            _nts: NotThreadSafe,        }    }     /// Try to lock the mmap read lock.    #[inline]    pub fn mmap_read_trylock(&self) -> Option<MmapReadGuard<'_>> {        // SAFETY: The pointer is valid since self is a reference.        let success = unsafe { bindings::mmap_read_trylock(self.as_raw()) };         if success {            // INVARIANT: We just acquired the read lock.            Some(MmapReadGuard {                mm: self,                _nts: NotThreadSafe,            })        } else {            None        }    }} /// A guard for the mmap read lock.////// # Invariants////// This `MmapReadGuard` guard owns the mmap read lock.pub struct MmapReadGuard<'a> {    mm: &'a MmWithUser,    // `mmap_read_lock` and `mmap_read_unlock` must be called on the same thread    _nts: NotThreadSafe,} impl<'a> MmapReadGuard<'a> {    /// Look up a vma at the given address.    #[inline]    pub fn vma_lookup(&self, vma_addr: usize) -> Option<&virt::VmaRef> {        // SAFETY: By the type invariants we hold the mmap read guard, so we can safely call this        // method. Any value is okay for `vma_addr`.        let vma = unsafe { bindings::vma_lookup(self.mm.as_raw(), vma_addr) };         if vma.is_null() {            None        } else {            // SAFETY: We just checked that a vma was found, so the pointer references a valid vma.            //            // Furthermore, the returned vma is still under the protection of the read lock guard            // and can be used while the mmap read lock is still held. That the vma is not used            // after the MmapReadGuard gets dropped is enforced by the borrow-checker.            unsafe { Some(virt::VmaRef::from_raw(vma)) }        }    }} impl Drop for MmapReadGuard<'_> {    #[inline]    fn drop(&mut self) {        // SAFETY: We hold the read lock by the type invariants.        unsafe { bindings::mmap_read_unlock(self.mm.as_raw()) };    }} /// A guard for the vma read lock.////// # Invariants////// This `VmaReadGuard` guard owns the vma read lock.pub struct VmaReadGuard<'a> {    vma: &'a VmaRef,    // `vma_end_read` must be called on the same thread as where the lock was taken    _nts: NotThreadSafe,} // Make all `VmaRef` methods available on `VmaReadGuard`.impl Deref for VmaReadGuard<'_> {    type Target = VmaRef;     #[inline]    fn deref(&self) -> &VmaRef {        self.vma    }} impl Drop for VmaReadGuard<'_> {    #[inline]    fn drop(&mut self) {        // SAFETY: We hold the read lock by the type invariants.        unsafe { bindings::vma_end_read(self.vma.as_ptr()) };    }}