lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <CAH5fLghNpbwteZMo7Lb81rg3yoxFs9ZbykSwgnnJZnpBuddCNA@mail.gmail.com>
Date: Thu, 21 Nov 2024 15:35:45 +0100
From: Alice Ryhl <aliceryhl@...gle.com>
To: Lorenzo Stoakes <lorenzo.stoakes@...cle.com>
Cc: Miguel Ojeda <ojeda@...nel.org>, Matthew Wilcox <willy@...radead.org>, 
	Vlastimil Babka <vbabka@...e.cz>, John Hubbard <jhubbard@...dia.com>, 
	"Liam R. Howlett" <Liam.Howlett@...cle.com>, Andrew Morton <akpm@...ux-foundation.org>, 
	Greg Kroah-Hartman <gregkh@...uxfoundation.org>, Arnd Bergmann <arnd@...db.de>, 
	Christian Brauner <brauner@...nel.org>, Alex Gaynor <alex.gaynor@...il.com>, 
	Boqun Feng <boqun.feng@...il.com>, Gary Guo <gary@...yguo.net>, 
	Björn Roy Baron <bjorn3_gh@...tonmail.com>, 
	Benno Lossin <benno.lossin@...ton.me>, linux-kernel@...r.kernel.org, linux-mm@...ck.org, 
	rust-for-linux@...r.kernel.org, Andreas Hindborg <a.hindborg@...nel.org>
Subject: Re: [PATCH v8 1/7] mm: rust: add abstraction for struct mm_struct

On Thu, Nov 21, 2024 at 1:37 PM Lorenzo Stoakes
<lorenzo.stoakes@...cle.com> wrote:
>
> I'm generally fine with this patch (other than rust specifics which I leave
> to the rust experts), however I'm a little concerned about us taking
> reference counts when we don't need to so this is something I'd like to see
> addressed for v9 or, at least to be confident we're not doing this in the
> binder code unnecessarily.
>
> Thanks!

The refcount increment is *not* unnecessary in Binder. For the C
equivalent, see the implementation of `binder_alloc_init`. It's used
because Binder will access the mm of the recipient from the sender's
scope, so it must hold on to an mm_struct reference.

> > > > +/// [`mmget_not_zero`]: Mm::mmget_not_zero
> > > > +#[repr(transparent)]
> > > > +pub struct Mm {
> > > > +    mm: Opaque<bindings::mm_struct>,
> > > > +}
> > >
> > > Does this tie this type to the C struct mm_struct type?
> > >
> > > Does 'Opaque' mean it is a pointer to a type which is 'opaque' in the sense
> > > that rust can't see into its internals?
> >
> > This declaration defines a Rust type called Mm which has the same
> > size, alignment, and contents as `struct mm_struct`. The purpose of
> > Opaque is to tell Rust that it can't assume anything about the
> > contents at all; we do that to leave it up to C.
> >
> > For example, normally if you have an immutable reference &i32, then
> > Rust is going to assume that the contents behind the reference are in
> > fact immutable. Opaque turns that off, meaning that an `&Opaque<i32>`
> > is allowed to reference an integer as it gets modified. It makes all
> > access to the contents unsafe, though.
> >
> > Note that Opaque is *not* a pointer type. We're going to be dealing
> > with types like &Mm or ARef<Mm> where &_ and ARef<_> are two different
> > kinds of pointers.
>
> OK so when you reference Mm.mm that is in effect referencing the struct
> mm_struct object rather than a pointer to a struct mm_struct? and

Yes.

> > > > +// 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()) };
> > > > +    }
> > > > +}
> > >
> > > Under what circumstances would these be taken? Same question for MmWthUser.
> >
> > This makes `Mm` compatible with the pointer type called ARef<_>. This
> > pointer type is used to represent ownership of a refcount. So whenever
> > a variable of type ARef<_> goes out of scope, the refcount is
> > decremented, and whenever an ARef<_> is cloned, the refcount is
> > incremented.
> >
> > The way this works is that ARef<_> is implemented to use the
> > AlwaysRefCounted trait to understand how to manipulate the count. Only
> > types that implement the trait with an impl block like above can be
> > used with ARef<_>.
>
> OK so when you first instantiate an ARef<_> you don't increment the
> reference count, only if it is cloned from there on in?

Well it depends on which ARef constructor you are using. But the uses
of ARef::from_raw do not increment the count.

> > > > +// 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
> > > > +        };
> > >
> > > I don't see an equivalent means of obtaining mm from current for
> > > MmWithUser, is that intentional, would there be another means of obtaining
> > > an mm? (perhaps via vma->vm_mm I guess?)
> > >
> > > An aside -->
> > >
> > > If we're grabbing from current, and this is non-NULL (i.e. not a kernel
> > > thread), this is kinda MmWithUser to _start out_ with, but I guess if
> > > you're grabbing the current one you might not expect it.
> > >
> > > I guess one thing I want to point out (maybe here is wrong place) is that
> > > the usual way of interacting with current->mm is that we do _not_ increment
> > > mm->mm_count, mm->mm_users or any refernce count, as while we are in the
> > > kernel portion of the task, we are guaranteed the mm and the backing
> > > virtual address space will stick around.
> > >
> > > With reference to MmWithUser, in fact, if you look up users of
> > > mmget()/mmput() it is pretty rare to do that.
> > >
> > > So ideally we'd avoid doing this if we could (though having the semantics
> > > of grabbing a reference if we were to copy the object somehow again or hold
> > > its state or something would be nice).
> > >
> > > I guess this might actually be tricky in rust, because we'd probably need
> > > to somehow express the current task's lifetime and tie this to that
> > > and... yeah.
> > >
> > > <-- aside
> >
> > Ah, yeah, I guess this API is incomplete. We could have an API that
> > lets you obtain an &MmWithUser instead. Then, if the user wants to
> > increment the refcount, they can manually convert that into an
> > ARef<Mm> or ARef<MmWithUser>.
> >
> > It's true that it's slightly tricky to express in Rust, but it's
> > possible. We already have a way to get a &Task pointing at current.
>
> Yeah, but I think we should do this incrementally as I want this initial
> series to merge first, after which we can tweak things.

Rest assured that the API can be written to not automatically
increment the refcount when accessing current. That's just binder's
case.

> > > > +        unsafe { &*ptr.cast() }
> > > > +    }
> > > > +
> > > > +    /// Calls `mmget_not_zero` and returns a handle if it succeeds.
> > > > +    #[inline]
> > > > +    pub fn mmget_not_zero(&self) -> Option<ARef<MmWithUser>> {
> > >
> > > I actually kinda love that this takes an mm and guarantees that you get an
> > > MmWithUser out of it which is implied by the fact this succeeds.
> > >
> > > However as to the point above, I'm concerned that this might be seen as
> > > 'the way' to access an mm, i.e. mm.mmgrab_current().mmget_not_zero() or
> > > something.
> > >
> > > Whereas, the usual way of referencing current->mm is to not increment any
> > > reference counts at all (assuming what you are doing resides in the same
> > > lifetime as the task).
> > >
> > > Obviously if you step outside of that lifetime, then you _do_ have to pin
> > > the mm (nearly always you want to grab rather than get though in that
> > > circumstance).
> >
> > I can add a way to obtain an &MmWithUser from current without
> > incrementing the refcount.
>
> Yeah, I feel like we definitely need this.
>
> However we'd need to _not_ drop the refcount when it goes out of scope too
> in this case.
>
> I'm not sure how you'd express that, however.

The way you express that is by giving the user a &Mm or &MmWithUser
instead of giving the user an ARef<Mm> or ARef<MmWithUser>. Using a
normal reference implies that you don't have ownership over the
refcount, and the reference has no destructor when it goes out of
scope. The only slightly tricky piece is tying the lifetime of that
reference to the scope of the current task, but this is a problem with
a known solution.

For more on this, see the discussion on the various versions of
Christian's PidNamespace series:
https://lore.kernel.org/rust-for-linux/20241002-brauner-rust-pid_namespace-v5-1-a90e70d44fde@kernel.org/

Alice

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ