Commit 42415d16 authored by Benno Lossin's avatar Benno Lossin
Browse files

rust: pin-init: add references to previously initialized fields



After initializing a field in an initializer macro, create a variable
holding a reference that points at that field. The type is either
`Pin<&mut T>` or `&mut T` depending on the field's structural pinning
kind.

[ Applied fixes to devres and rust_driver_pci sample - Benno]
Reviewed-by: default avatarDanilo Krummrich <dakr@kernel.org>
Signed-off-by: default avatarBenno Lossin <lossin@kernel.org>
parent 1fa51679
Loading
Loading
Loading
Loading
+2 −4
Original line number Diff line number Diff line
@@ -134,11 +134,9 @@ pub fn new<'a, E>(
        T: 'a,
        Error: From<E>,
    {
        let callback = Self::devres_callback;

        try_pin_init!(&this in Self {
            dev: dev.into(),
            callback,
            callback: Self::devres_callback,
            // INVARIANT: `inner` is properly initialized.
            inner <- {
                // SAFETY: `this` is a valid pointer to uninitialized memory.
@@ -151,7 +149,7 @@ pub fn new<'a, E>(
                //    properly initialized, because we require `dev` (i.e. the *bound* device) to
                //    live at least as long as the returned `impl PinInit<Self, Error>`.
                to_result(unsafe {
                    bindings::devm_add_action(dev.as_raw(), Some(callback), inner.cast())
                    bindings::devm_add_action(dev.as_raw(), Some(*callback), inner.cast())
                })?;

                Opaque::pin_init(try_pin_init!(Inner {
+115 −34
Original line number Diff line number Diff line
@@ -1049,6 +1049,7 @@ impl<$($impl_generics)*> $name<$($ty_generics)*>
        @pinned($($(#[$($p_attr:tt)*])* $pvis:vis $p_field:ident : $p_type:ty),* $(,)?),
        @not_pinned($($(#[$($attr:tt)*])* $fvis:vis $field:ident : $type:ty),* $(,)?),
    ) => {
        $crate::macros::paste! {
            // For every field, we create a projection function according to its projection type. If a
            // field is structurally pinned, then it must be initialized via `PinInit`, if it is not
            // structurally pinned, then it can be initialized via `Init`.
@@ -1069,6 +1070,14 @@ impl<$($impl_generics)*> $pin_data<$($ty_generics)*>
                        // SAFETY: TODO.
                        unsafe { $crate::PinInit::__pinned_init(init, slot) }
                    }

                    $(#[$($p_attr)*])*
                    $pvis unsafe fn [<__project_ $p_field>]<'__slot>(
                        self,
                        slot: &'__slot mut $p_type,
                    ) -> ::core::pin::Pin<&'__slot mut $p_type> {
                        ::core::pin::Pin::new_unchecked(slot)
                    }
                )*
                $(
                    $(#[$($attr)*])*
@@ -1080,8 +1089,17 @@ impl<$($impl_generics)*> $pin_data<$($ty_generics)*>
                        // SAFETY: TODO.
                        unsafe { $crate::Init::__init(init, slot) }
                    }

                    $(#[$($attr)*])*
                    $fvis unsafe fn [<__project_ $field>]<'__slot>(
                        self,
                        slot: &'__slot mut $type,
                    ) -> &'__slot mut $type {
                        slot
                    }
                )*
            }
        }
    };
}

@@ -1292,6 +1310,13 @@ fn assert_zeroable<T: $crate::Zeroable>(_: *mut T) {}
        // return when an error/panic occurs.
        // We also use the `data` to require the correct trait (`Init` or `PinInit`) for `$field`.
        unsafe { $data.$field(::core::ptr::addr_of_mut!((*$slot).$field), init)? };
        // SAFETY:
        // - the project function does the correct field projection,
        // - the field has been initialized,
        // - the reference is only valid until the end of the initializer.
        #[allow(unused_variables)]
        let $field = $crate::macros::paste!(unsafe { $data.[< __project_ $field >](&mut (*$slot).$field) });

        // Create the drop guard:
        //
        // We rely on macro hygiene to make it impossible for users to access this local variable.
@@ -1323,6 +1348,14 @@ fn assert_zeroable<T: $crate::Zeroable>(_: *mut T) {}
        // SAFETY: `slot` is valid, because we are inside of an initializer closure, we
        // return when an error/panic occurs.
        unsafe { $crate::Init::__init(init, ::core::ptr::addr_of_mut!((*$slot).$field))? };

        // SAFETY:
        // - the field is not structurally pinned, since the line above must compile,
        // - the field has been initialized,
        // - the reference is only valid until the end of the initializer.
        #[allow(unused_variables)]
        let $field = unsafe { &mut (*$slot).$field };

        // Create the drop guard:
        //
        // We rely on macro hygiene to make it impossible for users to access this local variable.
@@ -1341,7 +1374,7 @@ fn assert_zeroable<T: $crate::Zeroable>(_: *mut T) {}
            );
        }
    };
    (init_slot($($use_data:ident)?):
    (init_slot(): // No `use_data`, so all fields are not structurally pinned
        @data($data:ident),
        @slot($slot:ident),
        @guards($($guards:ident,)*),
@@ -1355,6 +1388,15 @@ fn assert_zeroable<T: $crate::Zeroable>(_: *mut T) {}
            // SAFETY: The memory at `slot` is uninitialized.
            unsafe { ::core::ptr::write(::core::ptr::addr_of_mut!((*$slot).$field), $field) };
        }

        #[allow(unused_variables)]
        // SAFETY:
        // - the field is not structurally pinned, since no `use_data` was required to create this
        //   initializer,
        // - the field has been initialized,
        // - the reference is only valid until the end of the initializer.
        let $field = unsafe { &mut (*$slot).$field };

        // Create the drop guard:
        //
        // We rely on macro hygiene to make it impossible for users to access this local variable.
@@ -1365,7 +1407,46 @@ fn assert_zeroable<T: $crate::Zeroable>(_: *mut T) {}
                $crate::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field))
            };

            $crate::__init_internal!(init_slot($($use_data)?):
            $crate::__init_internal!(init_slot():
                @data($data),
                @slot($slot),
                @guards([< __ $field _guard >], $($guards,)*),
                @munch_fields($($rest)*),
            );
        }
    };
    (init_slot($use_data:ident):
        @data($data:ident),
        @slot($slot:ident),
        @guards($($guards:ident,)*),
        // Init by-value.
        @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*),
    ) => {
        {
            $(let $field = $val;)?
            // Initialize the field.
            //
            // SAFETY: The memory at `slot` is uninitialized.
            unsafe { ::core::ptr::write(::core::ptr::addr_of_mut!((*$slot).$field), $field) };
        }
        // SAFETY:
        // - the project function does the correct field projection,
        // - the field has been initialized,
        // - the reference is only valid until the end of the initializer.
        #[allow(unused_variables)]
        let $field = $crate::macros::paste!(unsafe { $data.[< __project_ $field >](&mut (*$slot).$field) });

        // Create the drop guard:
        //
        // We rely on macro hygiene to make it impossible for users to access this local variable.
        // We use `paste!` to create new hygiene for `$field`.
        $crate::macros::paste! {
            // SAFETY: We forget the guard later when initialization has succeeded.
            let [< __ $field _guard >] = unsafe {
                $crate::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field))
            };

            $crate::__init_internal!(init_slot($use_data):
                @data($data),
                @slot($slot),
                @guards([< __ $field _guard >], $($guards,)*),
+1 −1
Original line number Diff line number Diff line
@@ -78,8 +78,8 @@ fn probe(pdev: &pci::Device<Core>, info: &Self::IdInfo) -> Result<Pin<KBox<Self>

        let drvdata = KBox::pin_init(
            try_pin_init!(Self {
                pdev: pdev.into(),
                bar <- pdev.iomap_region_sized::<{ Regs::END }>(0, c_str!("rust_driver_pci")),
                pdev: pdev.into(),
                index: *info,
            }),
            GFP_KERNEL,