From: Alice Ryhl <[email protected]> Rust Binder currently uses PollCondVar, but it calls synchronize_rcu() in the destructor, which we would like to avoid. Add a variation of PollCondVar that kfree_rcu() instead.
One could avoid the `rcu` field and allocate the rcu_head on drop using a fallback to synchronize_rcu() on ENOMEM. However, I'd prefer to avoid the potential for synchronize_rcu(), and Binder will only use this for a small fraction of processes, so even if it changes which kmalloc bucket it falls into, the extra memory is not a problem. Signed-off-by: Alice Ryhl <[email protected]> [boqun: Use RcuFreeSafe] Signed-off-by: Boqun Feng <[email protected]> --- rust/kernel/sync/poll.rs | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/rust/kernel/sync/poll.rs b/rust/kernel/sync/poll.rs index 5aa0ce9ba01b..830a4763a5c1 100644 --- a/rust/kernel/sync/poll.rs +++ b/rust/kernel/sync/poll.rs @@ -9,12 +9,19 @@ fs::File, prelude::*, sync::{ - rcu::synchronize_rcu, + rcu::{ + synchronize_rcu, // + RcuFreeSafe, + }, CondVar, LockClassKey, // }, // }; -use core::{marker::PhantomData, ops::Deref}; + +use core::{ + marker::PhantomData, + ops::Deref, // +}; /// Creates a [`PollCondVar`] initialiser with the given name and a newly-created lock class. #[macro_export] @@ -70,6 +77,7 @@ pub fn register_wait(&self, file: &File, cv: &PollCondVar) { /// /// [`CondVar`]: crate::sync::CondVar #[pin_data(PinnedDrop)] +#[repr(transparent)] pub struct PollCondVar { #[pin] inner: CondVar, @@ -97,12 +105,20 @@ fn deref(&self) -> &CondVar { impl PinnedDrop for PollCondVar { #[inline] fn drop(self: Pin<&mut Self>) { + self.drop_before_gp(); + + // Wait for epoll items to be properly removed. + synchronize_rcu(); + } +} + +// SAFETY: __wake_up_pollfree() guarantees all the epoll items on the wait list will be gone after +// one grace period. +unsafe impl RcuFreeSafe for PollCondVar { + fn drop_before_gp(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()) }; - - // Wait for epoll items to be properly removed. - synchronize_rcu(); } } -- 2.50.1 (Apple Git-155)

