All of lore.kernel.org
 help / color / mirror / Atom feed
From: Gary Guo <gary@garyguo.net>
To: Alice Ryhl <aliceryhl@google.com>
Cc: "Paul Moore" <paul@paul-moore.com>,
	"James Morris" <jmorris@namei.org>,
	"Serge E. Hallyn" <serge@hallyn.com>,
	"Miguel Ojeda" <ojeda@kernel.org>,
	"Christian Brauner" <brauner@kernel.org>,
	"Alex Gaynor" <alex.gaynor@gmail.com>,
	"Wedson Almeida Filho" <wedsonaf@gmail.com>,
	"Boqun Feng" <boqun.feng@gmail.com>,
	"Björn Roy Baron" <bjorn3_gh@protonmail.com>,
	"Benno Lossin" <benno.lossin@proton.me>,
	"Andreas Hindborg" <a.hindborg@samsung.com>,
	"Peter Zijlstra" <peterz@infradead.org>,
	"Alexander Viro" <viro@zeniv.linux.org.uk>,
	"Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
	"Arve Hjønnevåg" <arve@android.com>,
	"Todd Kjos" <tkjos@android.com>,
	"Martijn Coenen" <maco@android.com>,
	"Joel Fernandes" <joel@joelfernandes.org>,
	"Carlos Llamas" <cmllamas@google.com>,
	"Suren Baghdasaryan" <surenb@google.com>,
	"Dan Williams" <dan.j.williams@intel.com>,
	"Matthew Wilcox" <willy@infradead.org>,
	"Thomas Gleixner" <tglx@linutronix.de>,
	"Daniel Xu" <dxu@dxuuu.xyz>,
	"Martin Rodriguez Reboredo" <yakoyoku@gmail.com>,
	"Trevor Gross" <tmgross@umich.edu>,
	linux-kernel@vger.kernel.org,
	linux-security-module@vger.kernel.org,
	rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org,
	"Kees Cook" <kees@kernel.org>
Subject: Re: [PATCH v10 8/8] rust: file: add abstraction for `poll_table`
Date: Sun, 15 Sep 2024 23:24:03 +0100	[thread overview]
Message-ID: <20240915232403.58466ba7.gary@garyguo.net> (raw)
In-Reply-To: <20240915-alice-file-v10-8-88484f7a3dcf@google.com>

On Sun, 15 Sep 2024 14:31:34 +0000
Alice Ryhl <aliceryhl@google.com> wrote:

> The existing `CondVar` abstraction is a wrapper around
> `wait_queue_head`, but it does not support all use-cases of the C
> `wait_queue_head` type. To be specific, a `CondVar` cannot be registered
> with a `struct poll_table`. This limitation has the advantage that you
> do not need to call `synchronize_rcu` when destroying a `CondVar`.
> 
> However, we need the ability to register a `poll_table` with a
> `wait_queue_head` in Rust Binder. To enable this, introduce a type
> called `PollCondVar`, which is like `CondVar` except that you can
> register a `poll_table`. We also introduce `PollTable`, which is a safe
> wrapper around `poll_table` that is intended to be used with
> `PollCondVar`.
> 
> The destructor of `PollCondVar` unconditionally calls `synchronize_rcu`
> to ensure that the removal of epoll waiters has fully completed before
> the `wait_queue_head` is destroyed.
> 
> That said, `synchronize_rcu` is rather expensive and is not needed in
> all cases: If we have never registered a `poll_table` with the
> `wait_queue_head`, then we don't need to call `synchronize_rcu`. (And
> this is a common case in Binder - not all processes use Binder with
> epoll.) The current implementation does not account for this, but if we
> find that it is necessary to improve this, a future patch could store a
> boolean next to the `wait_queue_head` to keep track of whether a
> `poll_table` has ever been registered.
> 
> Reviewed-by: Benno Lossin <benno.lossin@proton.me>
> Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com>
> Reviewed-by: Trevor Gross <tmgross@umich.edu>
> Signed-off-by: Alice Ryhl <aliceryhl@google.com>
> ---
>  rust/bindings/bindings_helper.h |   1 +
>  rust/kernel/sync.rs             |   1 +
>  rust/kernel/sync/poll.rs        | 121 ++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 123 insertions(+)
> 
> diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
> index e854ccddecee..ca13659ded4c 100644
> --- a/rust/bindings/bindings_helper.h
> +++ b/rust/bindings/bindings_helper.h
> @@ -20,6 +20,7 @@
>  #include <linux/mdio.h>
>  #include <linux/phy.h>
>  #include <linux/pid_namespace.h>
> +#include <linux/poll.h>
>  #include <linux/refcount.h>
>  #include <linux/sched.h>
>  #include <linux/security.h>
> diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs
> index 0ab20975a3b5..bae4a5179c72 100644
> --- a/rust/kernel/sync.rs
> +++ b/rust/kernel/sync.rs
> @@ -11,6 +11,7 @@
>  mod condvar;
>  pub mod lock;
>  mod locked_by;
> +pub mod poll;
>  
>  pub use arc::{Arc, ArcBorrow, UniqueArc};
>  pub use condvar::{new_condvar, CondVar, CondVarTimeoutResult};
> diff --git a/rust/kernel/sync/poll.rs b/rust/kernel/sync/poll.rs
> new file mode 100644
> index 000000000000..d5f17153b424
> --- /dev/null
> +++ b/rust/kernel/sync/poll.rs
> @@ -0,0 +1,121 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +// Copyright (C) 2024 Google LLC.
> +
> +//! Utilities for working with `struct poll_table`.
> +
> +use crate::{
> +    bindings,
> +    fs::File,
> +    prelude::*,
> +    sync::{CondVar, LockClassKey},
> +    types::Opaque,
> +};
> +use core::ops::Deref;
> +
> +/// Creates a [`PollCondVar`] initialiser with the given name and a newly-created lock class.
> +#[macro_export]
> +macro_rules! new_poll_condvar {
> +    ($($name:literal)?) => {
> +        $crate::sync::poll::PollCondVar::new(
> +            $crate::optional_name!($($name)?), $crate::static_lock_class!()
> +        )
> +    };
> +}
> +
> +/// Wraps the kernel's `struct poll_table`.
> +///
> +/// # Invariants
> +///
> +/// This struct contains a valid `struct poll_table`.
> +///
> +/// For a `struct poll_table` to be valid, its `_qproc` function must follow the safety
> +/// requirements of `_qproc` functions:
> +///
> +/// * The `_qproc` function is given permission to enqueue a waiter to the provided `poll_table`
> +///   during the call. Once the waiter is removed and an rcu grace period has passed, it must no
> +///   longer access the `wait_queue_head`.
> +#[repr(transparent)]
> +pub struct PollTable(Opaque<bindings::poll_table>);
> +
> +impl PollTable {
> +    /// Creates a reference to a [`PollTable`] from a valid pointer.
> +    ///
> +    /// # Safety
> +    ///
> +    /// The caller must ensure that for the duration of 'a, the pointer will point at a valid poll
> +    /// table (as defined in the type invariants).
> +    ///
> +    /// The caller must also ensure that the `poll_table` is only accessed via the returned
> +    /// reference for the duration of 'a.
> +    pub unsafe fn from_ptr<'a>(ptr: *mut bindings::poll_table) -> &'a mut PollTable {
> +        // SAFETY: The safety requirements guarantee the validity of the dereference, while the
> +        // `PollTable` type being transparent makes the cast ok.
> +        unsafe { &mut *ptr.cast() }
> +    }
> +
> +    fn get_qproc(&self) -> bindings::poll_queue_proc {
> +        let ptr = self.0.get();
> +        // SAFETY: The `ptr` is valid because it originates from a reference, and the `_qproc`
> +        // field is not modified concurrently with this call since we have an immutable reference.
> +        unsafe { (*ptr)._qproc }
> +    }
> +
> +    /// Register this [`PollTable`] with the provided [`PollCondVar`], so that it can be notified
> +    /// using the condition variable.
> +    pub fn register_wait(&mut self, file: &File, cv: &PollCondVar) {
> +        if let Some(qproc) = self.get_qproc() {
> +            // SAFETY: The pointers to `file` and `self` need to be valid for the duration of this
> +            // call to `qproc`, which they are because they are references.
> +            //
> +            // The `cv.wait_queue_head` pointer must be valid until an rcu grace period after the
> +            // waiter is removed. The `PollCondVar` is pinned, so before `cv.wait_queue_head` can
> +            // be destroyed, the destructor must run. That destructor first removes all waiters,
> +            // and then waits for an rcu grace period. Therefore, `cv.wait_queue_head` is valid for
> +            // long enough.
> +            unsafe { qproc(file.as_ptr() as _, cv.wait_queue_head.get(), self.0.get()) };
> +        }

Should this be calling `poll_wait` instead?

> +    }
> +}
> +
> +/// A wrapper around [`CondVar`] that makes it usable with [`PollTable`].
> +///
> +/// [`CondVar`]: crate::sync::CondVar
> +#[pin_data(PinnedDrop)]
> +pub struct PollCondVar {
> +    #[pin]
> +    inner: CondVar,
> +}
> +
> +impl PollCondVar {
> +    /// Constructs a new condvar initialiser.
> +    pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> {
> +        pin_init!(Self {
> +            inner <- CondVar::new(name, key),
> +        })
> +    }
> +}
> +
> +// Make the `CondVar` methods callable on `PollCondVar`.
> +impl Deref for PollCondVar {
> +    type Target = CondVar;
> +
> +    fn deref(&self) -> &CondVar {
> +        &self.inner
> +    }
> +}
> +
> +#[pinned_drop]
> +impl PinnedDrop for PollCondVar {
> +    fn drop(self: Pin<&mut Self>) {
> +        // Clear anything registered using `register_wait`.
> +        //
> +        // SAFETY: The pointer points at a valid `wait_queue_head`.
> +        unsafe { bindings::__wake_up_pollfree(self.inner.wait_queue_head.get()) };

Should this use `wake_up_pollfree` (without the leading __)?

> +
> +        // Wait for epoll items to be properly removed.
> +        //
> +        // SAFETY: Just an FFI call.
> +        unsafe { bindings::synchronize_rcu() };
> +    }
> +}
> 


  reply	other threads:[~2024-09-15 22:24 UTC|newest]

Thread overview: 52+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-09-15 14:31 [PATCH v10 0/8] File abstractions needed by Rust Binder Alice Ryhl
2024-09-15 14:31 ` [PATCH v10 1/8] rust: types: add `NotThreadSafe` Alice Ryhl
2024-09-15 15:38   ` Gary Guo
2024-09-27 11:21     ` Miguel Ojeda
2024-09-24 19:45   ` Serge E. Hallyn
2024-09-25 11:06     ` Alice Ryhl
2024-09-25 13:59       ` Serge E. Hallyn
2024-09-27 10:20         ` Gary Guo
2024-09-15 14:31 ` [PATCH v10 2/8] rust: task: add `Task::current_raw` Alice Ryhl
2024-09-15 14:31 ` [PATCH v10 3/8] rust: file: add Rust abstraction for `struct file` Alice Ryhl
2024-09-15 21:51   ` Gary Guo
2024-09-15 14:31 ` [PATCH v10 4/8] rust: cred: add Rust abstraction for `struct cred` Alice Ryhl
2024-09-15 20:24   ` Kees Cook
2024-09-15 20:55     ` Alice Ryhl
2024-09-19  7:57   ` Paul Moore
2024-09-15 14:31 ` [PATCH v10 5/8] rust: security: add abstraction for secctx Alice Ryhl
2024-09-15 20:58   ` Kees Cook
2024-09-15 21:07     ` Alice Ryhl
2024-09-16 15:40       ` Casey Schaufler
2024-09-17 13:18         ` Paul Moore
2024-09-22 15:01           ` Alice Ryhl
2024-09-22 15:08         ` Alice Ryhl
2024-09-22 16:50           ` Casey Schaufler
2024-09-22 17:04             ` Alice Ryhl
2024-09-19  7:56   ` Paul Moore
2024-09-15 14:31 ` [PATCH v10 6/8] rust: file: add `FileDescriptorReservation` Alice Ryhl
2024-09-15 18:39   ` Al Viro
2024-09-15 19:34     ` Al Viro
2024-09-16  4:18       ` Al Viro
2024-09-15 20:13     ` Alice Ryhl
2024-09-15 22:01       ` Al Viro
2024-09-15 22:05         ` Al Viro
2024-09-15 14:31 ` [PATCH v10 7/8] rust: file: add `Kuid` wrapper Alice Ryhl
2024-09-15 22:02   ` Gary Guo
2024-09-23  9:13     ` Alice Ryhl
2024-09-26 16:33       ` Christian Brauner
2024-09-26 16:35         ` [PATCH] [RFC] rust: add PidNamespace wrapper Christian Brauner
2024-09-27 12:04           ` Alice Ryhl
2024-09-27 14:21             ` Christian Brauner
2024-09-27 14:58               ` Alice Ryhl
2024-10-01  9:43           ` [PATCH v2] rust: add PidNamespace Christian Brauner
2024-10-01 10:26             ` Alice Ryhl
2024-10-01 14:17               ` Christian Brauner
2024-10-01 15:45                 ` Miguel Ojeda
2024-10-02 10:14                   ` Christian Brauner
2024-10-02 11:08                     ` Miguel Ojeda
2024-10-01 19:10             ` Gary Guo
2024-10-02 11:05               ` Christian Brauner
2024-09-15 14:31 ` [PATCH v10 8/8] rust: file: add abstraction for `poll_table` Alice Ryhl
2024-09-15 22:24   ` Gary Guo [this message]
2024-09-23  9:10     ` Alice Ryhl
2024-09-27  9:28 ` [PATCH v10 0/8] File abstractions needed by Rust Binder Christian Brauner

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=20240915232403.58466ba7.gary@garyguo.net \
    --to=gary@garyguo.net \
    --cc=a.hindborg@samsung.com \
    --cc=alex.gaynor@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=arve@android.com \
    --cc=benno.lossin@proton.me \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun.feng@gmail.com \
    --cc=brauner@kernel.org \
    --cc=cmllamas@google.com \
    --cc=dan.j.williams@intel.com \
    --cc=dxu@dxuuu.xyz \
    --cc=gregkh@linuxfoundation.org \
    --cc=jmorris@namei.org \
    --cc=joel@joelfernandes.org \
    --cc=kees@kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=maco@android.com \
    --cc=ojeda@kernel.org \
    --cc=paul@paul-moore.com \
    --cc=peterz@infradead.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=serge@hallyn.com \
    --cc=surenb@google.com \
    --cc=tglx@linutronix.de \
    --cc=tkjos@android.com \
    --cc=tmgross@umich.edu \
    --cc=viro@zeniv.linux.org.uk \
    --cc=wedsonaf@gmail.com \
    --cc=willy@infradead.org \
    --cc=yakoyoku@gmail.com \
    /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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.