Re: [WIP RFC v2 01/35] WIP: rust/drm: Add fourcc bindings

From: Daniel Almeida
Date: Tue Jan 14 2025 - 13:55:44 EST


Hi Lyude,

>>>
>>> +impl FormatInfo {
>>> + // SAFETY: `ptr` must point to a valid instance of a `bindings::drm_format_info`
>>> + pub(super) unsafe fn from_raw<'a>(ptr: *const bindings::drm_format_info) -> &'a Self {
>>
>> I think FormatInfoRef would be more appropriate, since you seem to be creating a reference type (IIUC)
>> for a type that can also be owned.
>>
>> This would be more in line with the GEM [1] patch, for example.
>>
>> In other words, using `Ref` here will allow for both an owned `FormatInfo` and a `FormatInfoRef<‘_>`.
>>
>> I am not sure about the role of lifetime ‘a here. If you wanted to tie the lifetime of &Self to that of the pointer,
>> this does not do it, specially considering that pointers do not have lifetimes associated with them.
>>
>>> + // SAFETY: Our data layout is identical
>>> + unsafe { &*ptr.cast() }
>>
>> It’s hard to know what is going on with both the reborrow and the cast in the same statement.
>>
>> I am assuming that cast() is transforming to *Self, and the reborrow to &Self.
>>
>> To be honest, I dislike this approach. My suggestion here is to rework it to be similar to, e.g., what
>> Alice did here for `ShrinkControl` [2].
>
> Interesting. I did understand this wouldn't be tying the reference to any
> lifetime more specific then "is alive for the duration of the function this
> was called in" - which in pretty much all the cases we would be using this
> function in would be good enough to ensure safety.
>
> I guess though I'm curious what precisely is the point of having another type
> instead of a reference would be? It seems like if we were to add a function in
> the future for something that needed a reference to a `FormatInfo`, that
> having to cast from `FormatInfo` to `FormatInfoRef` would be a bit confusing
> when you now have both `&FormatInfo` and `FormatInfoRef`.

I’ve realized since then that there’s more code using the same pattern as you did,
so it appears that it’s found acceptance in the rest of the community. Thus,
I retract what I said earlier.

The `unsafe { &*ptr.cast() }` construct seems to be widely used too, so that is also
not a problem for me anymore

>
>>
>> +/// This struct is used to pass information from page reclaim to the shrinkers.
>> +///
>> +/// # Invariants
>> +///
>> +/// `ptr` has exclusive access to a valid `struct shrink_control`.
>> +pub struct ShrinkControl<'a> {
>> + ptr: NonNull<bindings::shrink_control>,
>> + _phantom: PhantomData<&'a bindings::shrink_control>,
>> +}
>> +
>> +impl<'a> ShrinkControl<'a> {
>> + /// Create a `ShrinkControl` from a raw pointer.
>> + ///
>> + /// # Safety
>> + ///
>> + /// The pointer should point at a valid `shrink_control` for the duration of 'a.
>> + pub unsafe fn from_raw(ptr: *mut bindings::shrink_control) -> Self {
>> + Self {
>> + // SAFETY: Caller promises that this pointer is valid.
>> + ptr: unsafe { NonNull::new_unchecked(ptr) },
>> + _phantom: PhantomData,
>> + }
>> + }
>>
>> Notice the use of PhantomData in her patch.

Some people have complained about introducing arbitrary smart pointers like
I suggested, so let’s drop this idea.

>>
>> By the way, Alice, I wonder if we can just use Opaque here?
>
> FWIW: I think the reason I didn't use Opaque is because it didn't really seem
> necessary. AFAICT the lifetime of drm_format_info follows rust's data aliasing
> rules: it's only ever mutated before pointers to it are stored elsewhere, thus
> holding a plain reference to it should be perfectly safe.

Do use Opaque though, it’s repr(transparent) and will make your code more similar
to what we already have upstream.

— Daniel