Re: [PATCH 1/3] rust: revocable: implement Revocable::access()

Benno Lossin
2025-04-27T17:15:55Z

On Sun Apr 27, 2025 at 12:13 PM CEST, Danilo Krummrich wrote:
> On Sun, Apr 27, 2025 at 08:37:00AM +0000, Benno Lossin wrote:
>> On Sat Apr 26, 2025 at 11:18 PM CEST, Danilo Krummrich wrote:
>> > On Sat, Apr 26, 2025 at 08:24:14PM +0000, Benno Lossin wrote:
>> >> On Sat Apr 26, 2025 at 3:30 PM CEST, Danilo Krummrich wrote:
>> >> > Implement an unsafe direct accessor for the data stored within the
>> >> > Revocable.
>> >> >
>> >> > This is useful for cases where we can proof that the data stored within
>> >> > the Revocable is not and cannot be revoked for the duration of the
>> >> > lifetime of the returned reference.
>> >> >
>> >> > Signed-off-by: Danilo Krummrich <dakr@kernel.org>
>> >> > ---
>> >> > The explicit lifetimes in access() probably don't serve a practical
>> >> > purpose, but I found them to be useful for documentation purposes.
>> >> > ---
>> >> > rust/kernel/revocable.rs | 12 ++++++++++++
>> >> > 1 file changed, 12 insertions(+)
>> >> >
>> >> > diff --git a/rust/kernel/revocable.rs b/rust/kernel/revocable.rs
>> >> > index 971d0dc38d83..33535de141ce 100644
>> >> > --- a/rust/kernel/revocable.rs
>> >> > +++ b/rust/kernel/revocable.rs
>> >> > @@ -139,6 +139,18 @@ pub fn try_access_with<R, F: FnOnce(&T) -> R>(&self, f: F) -> Option<R> {
>> >> > self.try_access().map(|t| f(&*t))
>> >> > }
>> >> >
>> >> > + /// Directly access the revocable wrapped object.
>> >> > + ///
>> >> > + /// # Safety
>> >> > + ///
>> >> > + /// The caller must ensure this [`Revocable`] instance hasn't been revoked and won't be revoked
>> >> > + /// for the duration of `'a`.
>> >>
>> >> Ah I missed this in my other email, in case you want to directly refer
>> >> to the lifetime, you should keep it defined. I would still remove the
>> >> `'s` lifetime though.
>> >> > + pub unsafe fn access<'a, 's: 'a>(&'s self) -> &'a T {
>> >> > + // SAFETY: By the safety requirement of this function it is guaranteed that
>> >> > + // `self.data.get()` is a valid pointer to an instance of `T`.
>> >>
>> >> I don't see how the "not-being revoked" state makes the `data` ptr be
>> >> valid. Is that an invariant of `Revocable`? (it's not documented to have
>> >> any invariants)
>> >
>> > What else makes it valid?
>>
>> IMO an `# Invariants` section with the corresponding invariant that
>> `data` is valid when `is_available` is true.
>
> Yeah, I agree that the # Invariants section is indeed missing and should be
> fixed.
>
>> > AFAICS, try_access() and try_access_with_guard() argue the exact same way,
>> > except that the reason for not being revoked is the atomic check and the RCU
>> > read lock.
>>
>> Just because other code is doing the same mistake doesn't make it
>> correct. If I had reviewed the patch at that time I'm sure I would have
>> pointed this out.
>
> I would say that try_access() and try_access_with_guard() are wrong, they rely

Did you mean to write `wouldn't`? Otherwise the second part doesn't
match IMO.

> on the correct thing, we just missed documenting the corresponding invariant.

Yeah it's not a behavior error, but since you agree that something
should be fixed, there also is something that is 'wrong' :)

>> I opened an issue about this:
>>
>> https://github.com/Rust-for-Linux/linux/issues/1160
>
> Thanks for creating the issue!
>
> What do you suggest for this patch?

I don't mind if you take it with the lifetime changes, so

Reviewed-by: Benno Lossin <benno.lossin@proton.me>

But I'd like the invariant to be documented (maybe we should tag the
issue with good-first-issue -- I don't actually think it is one, but
maybe you disagree).

---
Cheers,
Benno