diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs index 7003e5bdacf4..50d43b639cea 100644 --- a/rust/kernel/task.rs +++ b/rust/kernel/task.rs @@ -7,7 +7,6 @@ use crate::{ bindings, ffi::{c_int, c_long, c_uint}, - mm::MmWithUser, types::{NotThreadSafe, Opaque}, }; use core::{ @@ -33,16 +32,8 @@ pub const TASK_NORMAL: c_uint = bindings::TASK_NORMAL as c_uint; #[macro_export] macro_rules! current { () => { - // SAFETY: This expression creates a temporary value that is dropped at the end of the - // caller's scope. The following mechanisms ensure that the resulting `&CurrentTask` cannot - // leave current task context: - // - // * To return to userspace, the caller must leave the current scope. - // * Operations such as `begin_new_exec()` are necessarily unsafe and the caller of - // `begin_new_exec()` is responsible for safety. - // * Rust abstractions for things such as a `kthread_use_mm()` scope must require the - // closure to be `Send`, so the `NotThreadSafe` field of `CurrentTask` ensures that the - // `&CurrentTask` cannot cross the scope in either direction. + // SAFETY: Deref + addr-of below create a temporary `TaskRef` that cannot outlive the + // caller. unsafe { &*$crate::task::Task::current() } }; } @@ -85,7 +76,7 @@ macro_rules! current { /// impl State { /// fn new() -> Self { /// Self { -/// creator: ARef::from(&**current!()), +/// creator: current!().into(), /// index: 0, /// } /// } @@ -105,44 +96,6 @@ unsafe impl Send for Task {} // synchronised by C code (e.g., `signal_pending`). unsafe impl Sync for Task {} -/// Represents the [`Task`] in the `current` global. -/// -/// This type exists to provide more efficient operations that are only valid on the current task. -/// For example, to retrieve the pid-namespace of a task, you must use rcu protection unless it is -/// the current task. -/// -/// # Invariants -/// -/// Each value of this type must only be accessed from the task context it was created within. -/// -/// Of course, every thread is in a different task context, but for the purposes of this invariant, -/// these operations also permanently leave the task context: -/// -/// * Returning to userspace from system call context. -/// * Calling `release_task()`. -/// * Calling `begin_new_exec()` in a binary format loader. -/// -/// Other operations temporarily create a new sub-context: -/// -/// * Calling `kthread_use_mm()` creates a new context, and `kthread_unuse_mm()` returns to the -/// old context. -/// -/// This means that a `CurrentTask` obtained before a `kthread_use_mm()` call may be used again -/// once `kthread_unuse_mm()` is called, but it must not be used between these two calls. -/// Conversely, a `CurrentTask` obtained between a `kthread_use_mm()`/`kthread_unuse_mm()` pair -/// must not be used after `kthread_unuse_mm()`. -#[repr(transparent)] -pub struct CurrentTask(Task, NotThreadSafe); - -// Make all `Task` methods available on `CurrentTask`. -impl Deref for CurrentTask { - type Target = Task; - #[inline] - fn deref(&self) -> &Task { - &self.0 - } -} - /// The type of process identifiers (PIDs). pub type Pid = bindings::pid_t; @@ -169,29 +122,28 @@ impl Task { /// /// # Safety /// - /// Callers must ensure that the returned object is only used to access a [`CurrentTask`] - /// within the task context that was active when this function was called. For more details, - /// see the invariants section for [`CurrentTask`]. - pub unsafe fn current() -> impl Deref { - struct TaskRef { - task: *const CurrentTask, + /// Callers must ensure that the returned object doesn't outlive the current task/thread. + pub unsafe fn current() -> impl Deref { + struct TaskRef<'a> { + task: &'a Task, + _not_send: NotThreadSafe, } - impl Deref for TaskRef { - type Target = CurrentTask; + impl Deref for TaskRef<'_> { + type Target = Task; fn deref(&self) -> &Self::Target { - // SAFETY: The returned reference borrows from this `TaskRef`, so it cannot outlive - // the `TaskRef`, which the caller of `Task::current()` has promised will not - // outlive the task/thread for which `self.task` is the `current` pointer. Thus, it - // is okay to return a `CurrentTask` reference here. - unsafe { &*self.task } + self.task } } + let current = Task::current_raw(); TaskRef { - // CAST: The layout of `struct task_struct` and `CurrentTask` is identical. - task: Task::current_raw().cast(), + // SAFETY: If the current thread is still running, the current task is valid. Given + // that `TaskRef` is not `Send`, we know it cannot be transferred to another thread + // (where it could potentially outlive the caller). + task: unsafe { &*current.cast() }, + _not_send: NotThreadSafe, } } @@ -317,38 +269,6 @@ impl Task { } } -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) }) - } -} - // SAFETY: The type invariants guarantee that `Task` is always refcounted. unsafe impl crate::types::AlwaysRefCounted for Task { fn inc_ref(&self) {