Skip to main content

kernel/
mm.rs

1// SPDX-License-Identifier: GPL-2.0
2
3// Copyright (C) 2024 Google LLC.
4
5//! Memory management.
6//!
7//! This module deals with managing the address space of userspace processes. Each process has an
8//! instance of [`Mm`], which keeps track of multiple VMAs (virtual memory areas). Each VMA
9//! corresponds to a region of memory that the userspace process can access, and the VMA lets you
10//! control what happens when userspace reads or writes to that region of memory.
11//!
12//! C header: [`include/linux/mm.h`](srctree/include/linux/mm.h)
13
14use crate::{
15    bindings,
16    sync::aref::{ARef, AlwaysRefCounted},
17    types::{NotThreadSafe, Opaque},
18};
19use core::{ops::Deref, ptr::NonNull};
20
21pub mod virt;
22use virt::VmaRef;
23
24#[cfg(CONFIG_MMU)]
25pub use mmput_async::MmWithUserAsync;
26mod mmput_async;
27
28/// A wrapper for the kernel's `struct mm_struct`.
29///
30/// This represents the address space of a userspace process, so each process has one `Mm`
31/// instance. It may hold many VMAs internally.
32///
33/// There is a counter called `mm_users` that counts the users of the address space; this includes
34/// the userspace process itself, but can also include kernel threads accessing the address space.
35/// Once `mm_users` reaches zero, this indicates that the address space can be destroyed. To access
36/// the address space, you must prevent `mm_users` from reaching zero while you are accessing it.
37/// The [`MmWithUser`] type represents an address space where this is guaranteed, and you can
38/// create one using [`mmget_not_zero`].
39///
40/// The `ARef<Mm>` smart pointer holds an `mmgrab` refcount. Its destructor may sleep.
41///
42/// # Invariants
43///
44/// Values of this type are always refcounted using `mmgrab`.
45///
46/// [`mmget_not_zero`]: Mm::mmget_not_zero
47#[repr(transparent)]
48pub struct Mm {
49    mm: Opaque<bindings::mm_struct>,
50}
51
52// SAFETY: It is safe to call `mmdrop` on another thread than where `mmgrab` was called.
53unsafe impl Send for Mm {}
54// SAFETY: All methods on `Mm` can be called in parallel from several threads.
55unsafe impl Sync for Mm {}
56
57// SAFETY: By the type invariants, this type is always refcounted.
58unsafe impl AlwaysRefCounted for Mm {
59    #[inline]
60    fn inc_ref(&self) {
61        // SAFETY: The pointer is valid since self is a reference.
62        unsafe { bindings::mmgrab(self.as_raw()) };
63    }
64
65    #[inline]
66    unsafe fn dec_ref(obj: NonNull<Self>) {
67        // SAFETY: The caller is giving up their refcount.
68        unsafe { bindings::mmdrop(obj.cast().as_ptr()) };
69    }
70}
71
72/// A wrapper for the kernel's `struct mm_struct`.
73///
74/// This type is like [`Mm`], but with non-zero `mm_users`. It can only be used when `mm_users` can
75/// be proven to be non-zero at compile-time, usually because the relevant code holds an `mmget`
76/// refcount. It can be used to access the associated address space.
77///
78/// The `ARef<MmWithUser>` smart pointer holds an `mmget` refcount. Its destructor may sleep.
79///
80/// # Invariants
81///
82/// Values of this type are always refcounted using `mmget`. The value of `mm_users` is non-zero.
83#[repr(transparent)]
84pub struct MmWithUser {
85    mm: Mm,
86}
87
88// SAFETY: It is safe to call `mmput` on another thread than where `mmget` was called.
89unsafe impl Send for MmWithUser {}
90// SAFETY: All methods on `MmWithUser` can be called in parallel from several threads.
91unsafe impl Sync for MmWithUser {}
92
93// SAFETY: By the type invariants, this type is always refcounted.
94unsafe impl AlwaysRefCounted for MmWithUser {
95    #[inline]
96    fn inc_ref(&self) {
97        // SAFETY: The pointer is valid since self is a reference.
98        unsafe { bindings::mmget(self.as_raw()) };
99    }
100
101    #[inline]
102    unsafe fn dec_ref(obj: NonNull<Self>) {
103        // SAFETY: The caller is giving up their refcount.
104        unsafe { bindings::mmput(obj.cast().as_ptr()) };
105    }
106}
107
108// Make all `Mm` methods available on `MmWithUser`.
109impl Deref for MmWithUser {
110    type Target = Mm;
111
112    #[inline]
113    fn deref(&self) -> &Mm {
114        &self.mm
115    }
116}
117
118// These methods are safe to call even if `mm_users` is zero.
119impl Mm {
120    /// Returns a raw pointer to the inner `mm_struct`.
121    #[inline]
122    pub fn as_raw(&self) -> *mut bindings::mm_struct {
123        self.mm.get()
124    }
125
126    /// Obtain a reference from a raw pointer.
127    ///
128    /// # Safety
129    ///
130    /// The caller must ensure that `ptr` points at an `mm_struct`, and that it is not deallocated
131    /// during the lifetime 'a.
132    #[inline]
133    pub unsafe fn from_raw<'a>(ptr: *const bindings::mm_struct) -> &'a Mm {
134        // SAFETY: Caller promises that the pointer is valid for 'a. Layouts are compatible due to
135        // repr(transparent).
136        unsafe { &*ptr.cast() }
137    }
138
139    /// Calls `mmget_not_zero` and returns a handle if it succeeds.
140    #[inline]
141    pub fn mmget_not_zero(&self) -> Option<ARef<MmWithUser>> {
142        // SAFETY: The pointer is valid since self is a reference.
143        let success = unsafe { bindings::mmget_not_zero(self.as_raw()) };
144
145        if success {
146            // SAFETY: We just created an `mmget` refcount.
147            Some(unsafe { ARef::from_raw(NonNull::new_unchecked(self.as_raw().cast())) })
148        } else {
149            None
150        }
151    }
152}
153
154// These methods require `mm_users` to be non-zero.
155impl MmWithUser {
156    /// Obtain a reference from a raw pointer.
157    ///
158    /// # Safety
159    ///
160    /// The caller must ensure that `ptr` points at an `mm_struct`, and that `mm_users` remains
161    /// non-zero for the duration of the lifetime 'a.
162    #[inline]
163    pub unsafe fn from_raw<'a>(ptr: *const bindings::mm_struct) -> &'a MmWithUser {
164        // SAFETY: Caller promises that the pointer is valid for 'a. The layout is compatible due
165        // to repr(transparent).
166        unsafe { &*ptr.cast() }
167    }
168
169    /// Attempt to access a vma using the vma read lock.
170    ///
171    /// This is an optimistic trylock operation, so it may fail if there is contention. In that
172    /// case, you should fall back to taking the mmap read lock.
173    #[inline]
174    pub fn lock_vma_under_rcu(&self, vma_addr: usize) -> Option<VmaReadGuard<'_>> {
175        // SAFETY: Calling `bindings::lock_vma_under_rcu` is always okay given an mm where
176        // `mm_users` is non-zero.
177        let vma = unsafe { bindings::lock_vma_under_rcu(self.as_raw(), vma_addr) };
178        if vma.is_null() {
179            return None;
180        }
181        Some(VmaReadGuard {
182            // SAFETY: If `lock_vma_under_rcu` returns a non-null ptr, then it points at a
183            // valid vma. The vma is stable for as long as the vma read lock is held.
184            vma: unsafe { VmaRef::from_raw(vma) },
185            _nts: NotThreadSafe,
186        })
187    }
188
189    /// Find the VMA covering 'address' and read-lock it.
190    ///
191    /// The fast path does not take mmap_lock. Waits for writers to finish if the
192    /// VMA is being modified by taking mmap_lock.
193    /// Use when mmap_lock is not held, otherwise use vma_start_read_locked().
194    /// Nothing prevents VMAs being unmapped/mapped before or after the VMA is
195    /// looked up, if a stronger guarantee is required, take an mmap_lock.
196    ///
197    /// Return: If a VMA exists which spans @address, return that VMA, read-locked.
198    /// If no VMA is mapped there or, very unlikely, a reference count overflow
199    /// occurred, return NULL.
200    #[inline]
201    pub fn vma_start_read_unlocked(&self, vma_addr: usize) -> Option<VmaReadGuard<'_>> {
202        // SAFETY: We may invoke `vma_start_read_unlocked` because we know this `mm` has non-zero
203        // `mm_users`.
204        let vma = unsafe { bindings::vma_start_read_unlocked(self.as_raw(), vma_addr) };
205        if vma.is_null() {
206            return None;
207        }
208        // INVARIANT: We just acquired the VMA read lock.
209        Some(VmaReadGuard {
210            // SAFETY: If `vma_start_read_unlocked` returns a non-null ptr, then it points at a
211            // valid vma. The vma is stable for as long as the vma read lock is held.
212            vma: unsafe { VmaRef::from_raw(vma) },
213            _nts: NotThreadSafe,
214        })
215    }
216
217    /// Lock the mmap read lock.
218    #[inline]
219    pub fn mmap_read_lock(&self) -> MmapReadGuard<'_> {
220        // SAFETY: The pointer is valid since self is a reference.
221        unsafe { bindings::mmap_read_lock(self.as_raw()) };
222
223        // INVARIANT: We just acquired the read lock.
224        MmapReadGuard {
225            mm: self,
226            _nts: NotThreadSafe,
227        }
228    }
229
230    /// Try to lock the mmap read lock.
231    #[inline]
232    pub fn mmap_read_trylock(&self) -> Option<MmapReadGuard<'_>> {
233        // SAFETY: The pointer is valid since self is a reference.
234        let success = unsafe { bindings::mmap_read_trylock(self.as_raw()) };
235
236        if success {
237            // INVARIANT: We just acquired the read lock.
238            Some(MmapReadGuard {
239                mm: self,
240                _nts: NotThreadSafe,
241            })
242        } else {
243            None
244        }
245    }
246}
247
248/// A guard for the mmap read lock.
249///
250/// # Invariants
251///
252/// This `MmapReadGuard` guard owns the mmap read lock.
253pub struct MmapReadGuard<'a> {
254    mm: &'a MmWithUser,
255    // `mmap_read_lock` and `mmap_read_unlock` must be called on the same thread
256    _nts: NotThreadSafe,
257}
258
259impl<'a> MmapReadGuard<'a> {
260    /// Look up a vma at the given address.
261    #[inline]
262    pub fn vma_lookup(&self, vma_addr: usize) -> Option<&virt::VmaRef> {
263        // SAFETY: By the type invariants we hold the mmap read guard, so we can safely call this
264        // method. Any value is okay for `vma_addr`.
265        let vma = unsafe { bindings::vma_lookup(self.mm.as_raw(), vma_addr) };
266
267        if vma.is_null() {
268            None
269        } else {
270            // SAFETY: We just checked that a vma was found, so the pointer references a valid vma.
271            //
272            // Furthermore, the returned vma is still under the protection of the read lock guard
273            // and can be used while the mmap read lock is still held. That the vma is not used
274            // after the MmapReadGuard gets dropped is enforced by the borrow-checker.
275            unsafe { Some(virt::VmaRef::from_raw(vma)) }
276        }
277    }
278}
279
280impl Drop for MmapReadGuard<'_> {
281    #[inline]
282    fn drop(&mut self) {
283        // SAFETY: We hold the read lock by the type invariants.
284        unsafe { bindings::mmap_read_unlock(self.mm.as_raw()) };
285    }
286}
287
288/// A guard for the vma read lock.
289///
290/// # Invariants
291///
292/// This `VmaReadGuard` guard owns the vma read lock.
293pub struct VmaReadGuard<'a> {
294    vma: &'a VmaRef,
295    // `vma_end_read` must be called on the same thread as where the lock was taken
296    _nts: NotThreadSafe,
297}
298
299// Make all `VmaRef` methods available on `VmaReadGuard`.
300impl Deref for VmaReadGuard<'_> {
301    type Target = VmaRef;
302
303    #[inline]
304    fn deref(&self) -> &VmaRef {
305        self.vma
306    }
307}
308
309impl Drop for VmaReadGuard<'_> {
310    #[inline]
311    fn drop(&mut self) {
312        // SAFETY: We hold the read lock by the type invariants.
313        unsafe { bindings::vma_end_read(self.vma.as_ptr()) };
314    }
315}