From: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
To: Alice Ryhl <aliceryhl@google.com>
Cc: "Miguel Ojeda" <ojeda@kernel.org>,
"Matthew Wilcox" <willy@infradead.org>,
"Vlastimil Babka" <vbabka@suse.cz>,
"John Hubbard" <jhubbard@nvidia.com>,
"Liam R. Howlett" <Liam.Howlett@oracle.com>,
"Andrew Morton" <akpm@linux-foundation.org>,
"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
"Arnd Bergmann" <arnd@arndb.de>,
"Christian Brauner" <brauner@kernel.org>,
"Jann Horn" <jannh@google.com>,
"Suren Baghdasaryan" <surenb@google.com>,
"Alex Gaynor" <alex.gaynor@gmail.com>,
"Boqun Feng" <boqun.feng@gmail.com>,
"Gary Guo" <gary@garyguo.net>,
"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
"Benno Lossin" <benno.lossin@proton.me>,
linux-kernel@vger.kernel.org, linux-mm@kvack.org,
rust-for-linux@vger.kernel.org,
"Andreas Hindborg" <a.hindborg@kernel.org>
Subject: Re: [PATCH v9 8/8] task: rust: rework how current is accessed
Date: Fri, 22 Nov 2024 17:54:52 +0000 [thread overview]
Message-ID: <44ef7154-0f38-46c0-b87d-e598b146f4a4@lucifer.local> (raw)
In-Reply-To: <20241122-vma-v9-8-7127bfcdd54e@google.com>
On Fri, Nov 22, 2024 at 03:40:33PM +0000, Alice Ryhl wrote:
> Introduce a new type called `CurrentTask` that lets you perform various
> operations that are only safe on the `current` task. Use the new type to
> provide a way to access the current mm without incrementing its
> refcount.
Nice!
>
> With this change, you can write stuff such as
>
> let vma = current!().mm().lock_vma_under_rcu(addr);
>
> without incrementing any refcounts.
>
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
On assumption that the problem you reference with the rust imports is
corrected in v10, and that what you are doing with current_raw() is
sensible, then:
Acked-by: Lorenzo Stoakes <lorenzo.stoakes@oracle.com>
Thanks!
> ---
> Reviewers: Does accessing task->mm on a non-current task require rcu
> protection?
Hm I am not actually sure, but it seems like you probably do, and I would say
you need the task lock right?
Looking at find_lock_task_mm() as used by the oomk for instance suggests as much.
>
> Christian: If you submit the PidNamespace abstractions this cycle, I'll
> update this to also apply to PidNamespace.
> ---
> rust/kernel/mm.rs | 22 ------------------
> rust/kernel/task.rs | 64 ++++++++++++++++++++++++++++++++++++++++++-----------
> 2 files changed, 51 insertions(+), 35 deletions(-)
>
> diff --git a/rust/kernel/mm.rs b/rust/kernel/mm.rs
> index 50f4861ae4b9..f7d1079391ef 100644
> --- a/rust/kernel/mm.rs
> +++ b/rust/kernel/mm.rs
> @@ -142,28 +142,6 @@ fn deref(&self) -> &MmWithUser {
>
> // 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
> - };
> -
> - if mm.is_null() {
> - return None;
> - }
> -
> - // SAFETY: The value of `current->mm` is guaranteed to be null or a valid `mm_struct`. We
> - // just checked that it's not null. Furthermore, the returned `&Mm` is valid only for the
> - // duration of this function, and `current->mm` will stay valid for that long.
> - let mm = unsafe { Mm::from_raw(mm) };
> -
> - // This increments the refcount using `mmgrab`.
> - Some(ARef::from(mm))
> - }
> -
It's nice to drop this to discourage the unusual thing of grabbing current's mm
and incrementing reference count.
> /// Returns a raw pointer to the inner `mm_struct`.
> #[inline]
> pub fn as_raw(&self) -> *mut bindings::mm_struct {
> diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs
> index 9e59d86da42d..103d235eb844 100644
> --- a/rust/kernel/task.rs
> +++ b/rust/kernel/task.rs
> @@ -94,6 +94,26 @@ unsafe impl Send for Task {}
> // synchronised by C code (e.g., `signal_pending`).
> unsafe impl Sync for Task {}
>
> +/// Represents a [`Task`] obtained from 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
> +///
> +/// Must be equal to `current` of some thread that is currently running somewhere.
> +pub struct CurrentTask(Task);
Nice, I do like the ability to express abstractions like this...
> +
> +// Make all `Task` methods available on `CurrentTask`.
> +impl Deref for CurrentTask {
> + type Target = Task;
> + #[inline]
> + fn deref(&self) -> &Task {
> + &self.0
> + }
> +}
> +
It's nice to be able to 'alias' types like this too (ok I'm sure that's not
quite the write way of describing but you know what I mean), so you can abstract
something, then very simply create variants that have the same methods but
different attributes otherwise.
> /// The type of process identifiers (PIDs).
> type Pid = bindings::pid_t;
>
> @@ -121,27 +141,25 @@ pub fn current_raw() -> *mut bindings::task_struct {
> /// # Safety
> ///
> /// Callers must ensure that the returned object doesn't outlive the current task/thread.
> - pub unsafe fn current() -> impl Deref<Target = Task> {
> - struct TaskRef<'a> {
> - task: &'a Task,
> - _not_send: NotThreadSafe,
> + pub unsafe fn current() -> impl Deref<Target = CurrentTask> {
> + struct TaskRef {
> + task: *const CurrentTask,
> }
Why do we drop the NotThreadSafe bit here? And it seems like the 'a lifetime
stuff has gone too?
I'm guessing the lifetime stuff is because of the SAFETY comment below about
assumptions about lifetime?
>
> - impl Deref for TaskRef<'_> {
> - type Target = Task;
> + impl Deref for TaskRef {
> + type Target = CurrentTask;
>
> fn deref(&self) -> &Self::Target {
> - self.task
> + // 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 }
> }
> }
>
> - let current = Task::current_raw();
> TaskRef {
> - // 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,
> + task: Task::current_raw().cast(),
> }
I guess these changes align with the changes above?
> }
>
> @@ -203,6 +221,26 @@ pub fn wake_up(&self) {
> }
> }
>
> +impl CurrentTask {
> + /// Access the address space of this task.
> + ///
> + /// To increment the refcount of the referenced `mm`, you can use `ARef::from`.
> + #[inline]
> + pub fn mm(&self) -> Option<&MmWithUser> {
> + let mm = unsafe { (*self.as_ptr()).mm };
> +
> + if mm.is_null() {
> + None
> + } else {
> + // SAFETY: If `current->mm` is non-null, then it references a valid mm with a non-zero
> + // value of `mm_users`. The returned `&MmWithUser` borrows from `CurrentTask`, so the
> + // `&MmWithUser` cannot escape the current task, meaning `mm_users` can't reach zero
> + // while the reference is still live.
> + Some(unsafe { MmWithUser::from_raw(mm) })
> + }
> + }
> +}
Nice!
> +
> // SAFETY: The type invariants guarantee that `Task` is always refcounted.
> unsafe impl crate::types::AlwaysRefCounted for Task {
> fn inc_ref(&self) {
>
> --
> 2.47.0.371.ga323438b13-goog
>
next prev parent reply other threads:[~2024-11-22 17:55 UTC|newest]
Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-11-22 15:40 [PATCH v9 0/8] Rust support for mm_struct, vm_area_struct, and mmap Alice Ryhl
2024-11-22 15:40 ` [PATCH v9 1/8] mm: rust: add abstraction for struct mm_struct Alice Ryhl
2024-11-22 17:27 ` Lorenzo Stoakes
2024-11-22 15:40 ` [PATCH v9 2/8] mm: rust: add vm_area_struct methods that require read access Alice Ryhl
2024-11-26 22:09 ` Jann Horn
2024-11-27 12:01 ` Alice Ryhl
2024-11-27 15:40 ` Jann Horn
2024-11-27 15:45 ` Alice Ryhl
2024-11-27 16:16 ` Jann Horn
2024-11-29 11:44 ` Alice Ryhl
2024-11-29 11:58 ` Lorenzo Stoakes
2024-11-22 15:40 ` [PATCH v9 3/8] mm: rust: add vm_insert_page Alice Ryhl
2024-11-22 15:40 ` [PATCH v9 4/8] mm: rust: add lock_vma_under_rcu Alice Ryhl
2024-11-26 21:50 ` Jann Horn
2024-11-22 15:40 ` [PATCH v9 5/8] mm: rust: add mmput_async support Alice Ryhl
2024-11-22 15:40 ` [PATCH v9 6/8] mm: rust: add VmAreaNew for f_ops->mmap() Alice Ryhl
2024-11-22 17:33 ` Lorenzo Stoakes
2024-11-26 21:29 ` Jann Horn
2024-11-27 12:38 ` Alice Ryhl
2024-11-27 16:19 ` Jann Horn
2024-11-22 15:40 ` [PATCH v9 7/8] rust: miscdevice: add mmap support Alice Ryhl
2024-11-22 15:40 ` [PATCH v9 8/8] task: rust: rework how current is accessed Alice Ryhl
2024-11-22 15:53 ` Alice Ryhl
2024-11-22 17:34 ` Lorenzo Stoakes
2024-11-22 17:54 ` Lorenzo Stoakes [this message]
2024-11-22 18:51 ` Alice Ryhl
2024-11-22 18:03 ` Boqun Feng
2024-11-22 18:48 ` Alice Ryhl
2024-11-22 19:17 ` Boqun Feng
2024-11-22 19:30 ` Matthew Wilcox
2024-11-22 19:43 ` Alice Ryhl
2024-11-22 19:54 ` Matthew Wilcox
2024-11-22 20:16 ` Alice Ryhl
2024-11-26 17:14 ` Jann Horn
2024-11-27 12:35 ` Alice Ryhl
2024-11-27 15:52 ` Jann Horn
2024-11-27 15:57 ` Alice Ryhl
2024-11-27 16:18 ` Jann Horn
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=44ef7154-0f38-46c0-b87d-e598b146f4a4@lucifer.local \
--to=lorenzo.stoakes@oracle.com \
--cc=Liam.Howlett@oracle.com \
--cc=a.hindborg@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=arnd@arndb.de \
--cc=benno.lossin@proton.me \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=brauner@kernel.org \
--cc=gary@garyguo.net \
--cc=gregkh@linuxfoundation.org \
--cc=jannh@google.com \
--cc=jhubbard@nvidia.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=surenb@google.com \
--cc=vbabka@suse.cz \
--cc=willy@infradead.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox