WIP Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index 22d9ea6..b7f4aa6 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs
@@ -527,6 +527,16 @@ unsafe fn drop_rcu_ptr(ptr: *mut ffi::c_void) { unsafe { KBox::from_raw(ptr) }.drop_rcu(); } } + + type RcuBorrowed<'a> = &'a T; + + unsafe fn rcu_borrow<'a>(ptr: *mut c_void) -> Self::RcuBorrowed<'a> { + // CAST: `ptr` should points the `ArcInner<T>` per implementation of `ForeignOwnable`. + let ptr = ptr.cast::<ArcInner<T>>(); + + // SAFETY: RCU guarantees the returned reference is valid for one grace period. + unsafe { &(*ptr).data } + } } impl<T: ?Sized> From<UniqueArc<T>> for Arc<T> {
diff --git a/rust/kernel/sync/rcu.rs b/rust/kernel/sync/rcu.rs index 1210569..6083380 100644 --- a/rust/kernel/sync/rcu.rs +++ b/rust/kernel/sync/rcu.rs
@@ -140,6 +140,16 @@ fn drop_rcu(self) { // SAFETY: `self.into_foreign()` is used immediately. unsafe { Self::drop_rcu_ptr(self.into_foreign()) }; } + + /// TODO + type RcuBorrowed<'a>; + + /// TODO + /// + /// # Safety + /// + /// TODO + unsafe fn rcu_borrow<'a>(ptr: *mut c_void) -> Self::RcuBorrowed<'a>; } /// Drop and free the object in a rcu callback. @@ -200,6 +210,13 @@ unsafe fn drop_rcu_ptr(ptr: *mut c_void) { } } } + + type RcuBorrowed<'a> = &'a T; + + unsafe fn rcu_borrow<'a>(ptr: *mut c_void) -> Self::RcuBorrowed<'a> { + // SAFETY: TODO + unsafe { <Self as ForeignOwnable>::borrow(ptr) } + } } /// A wrapper that uses the `drop_rcu()` instead of normal `drop()` of `T`. @@ -247,12 +264,10 @@ pub fn new(t: T) -> Self { } /// Accesses the value while RCU read lock is held. - pub fn with_rcu<'rcu>(&self, _guard: &'rcu Guard) -> <T as ForeignOwnable>::Borrowed<'rcu> { + pub fn with_rcu<'rcu>(&self, _guard: &'rcu Guard) -> <T as DropRcu>::RcuBorrowed<'rcu> { // SAFETY: The function signature guarantees that the object outlives the returned // reference since the `RcuDrop::drop()` waits for a grace period. - // - // TODO: Use rcu_borrow? - unsafe { T::borrow(self.0) } + unsafe { T::rcu_borrow(self.0) } } } @@ -285,3 +300,39 @@ unsafe fn borrow_mut<'a>(ptr: *mut c_void) -> Self::BorrowedMut<'a> { unsafe { T::borrow_mut(ptr) } } } + +/// `RcuDrop<T>` impl `Clone` if `T: Clone`. +/// +/// # Examples +/// +/// ``` +/// use kernel::sync::{Arc, rcu::{DropRcu, RcuDrop, RcuHead, read_lock, WithRcuHead}}; +/// use core::ops::Deref; +/// +/// let rcu_drop = RcuDrop::new(Arc::new(WithRcuHead::<i32>::new(42), GFP_KERNEL)?); +/// let cloned = rcu_drop.clone(); +/// +/// let g = read_lock(); +/// let w = cloned.with_rcu(&g).deref(); +/// +/// drop(cloned); +/// drop(rcu_drop); // <- kfree_rcu() +/// +/// assert_eq!(*w, 42); +/// +/// # Ok::<(), Error>(()) +/// ``` +impl<T: DropRcu + Clone> Clone for RcuDrop<T> { + fn clone(&self) -> Self { + let ptr = self.0; + + // SAFETY: Normally it's unsafe but here we keep it in a `ManuallyDrop` as if the + // `from_foreign()` has not been called. + let temp = ManuallyDrop::new(unsafe { <T as ForeignOwnable>::from_foreign(ptr) }); + + let new = temp.deref().clone(); + + // INVARIANTS: Trivial. + Self(new.into_foreign(), PhantomData) + } +}