mirror of https://github.com/torvalds/linux.git
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: Danilo Krummrich <dakr@kernel.org> Signed-off-by: Benno Lossin <lossin@kernel.org>
This commit is contained in:
parent
1fa516794f
commit
42415d163e
|
|
@ -134,11 +134,9 @@ pub fn new<'a, E>(
|
||||||
T: 'a,
|
T: 'a,
|
||||||
Error: From<E>,
|
Error: From<E>,
|
||||||
{
|
{
|
||||||
let callback = Self::devres_callback;
|
|
||||||
|
|
||||||
try_pin_init!(&this in Self {
|
try_pin_init!(&this in Self {
|
||||||
dev: dev.into(),
|
dev: dev.into(),
|
||||||
callback,
|
callback: Self::devres_callback,
|
||||||
// INVARIANT: `inner` is properly initialized.
|
// INVARIANT: `inner` is properly initialized.
|
||||||
inner <- {
|
inner <- {
|
||||||
// SAFETY: `this` is a valid pointer to uninitialized memory.
|
// 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
|
// properly initialized, because we require `dev` (i.e. the *bound* device) to
|
||||||
// live at least as long as the returned `impl PinInit<Self, Error>`.
|
// live at least as long as the returned `impl PinInit<Self, Error>`.
|
||||||
to_result(unsafe {
|
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 {
|
Opaque::pin_init(try_pin_init!(Inner {
|
||||||
|
|
|
||||||
|
|
@ -1049,38 +1049,56 @@ impl<$($impl_generics)*> $name<$($ty_generics)*>
|
||||||
@pinned($($(#[$($p_attr:tt)*])* $pvis:vis $p_field:ident : $p_type:ty),* $(,)?),
|
@pinned($($(#[$($p_attr:tt)*])* $pvis:vis $p_field:ident : $p_type:ty),* $(,)?),
|
||||||
@not_pinned($($(#[$($attr:tt)*])* $fvis:vis $field:ident : $type:ty),* $(,)?),
|
@not_pinned($($(#[$($attr:tt)*])* $fvis:vis $field:ident : $type:ty),* $(,)?),
|
||||||
) => {
|
) => {
|
||||||
// For every field, we create a projection function according to its projection type. If a
|
$crate::macros::paste! {
|
||||||
// field is structurally pinned, then it must be initialized via `PinInit`, if it is not
|
// For every field, we create a projection function according to its projection type. If a
|
||||||
// structurally pinned, then it can be initialized via `Init`.
|
// field is structurally pinned, then it must be initialized via `PinInit`, if it is not
|
||||||
//
|
// structurally pinned, then it can be initialized via `Init`.
|
||||||
// The functions are `unsafe` to prevent accidentally calling them.
|
//
|
||||||
#[allow(dead_code)]
|
// The functions are `unsafe` to prevent accidentally calling them.
|
||||||
#[expect(clippy::missing_safety_doc)]
|
#[allow(dead_code)]
|
||||||
impl<$($impl_generics)*> $pin_data<$($ty_generics)*>
|
#[expect(clippy::missing_safety_doc)]
|
||||||
where $($whr)*
|
impl<$($impl_generics)*> $pin_data<$($ty_generics)*>
|
||||||
{
|
where $($whr)*
|
||||||
$(
|
{
|
||||||
$(#[$($p_attr)*])*
|
$(
|
||||||
$pvis unsafe fn $p_field<E>(
|
$(#[$($p_attr)*])*
|
||||||
self,
|
$pvis unsafe fn $p_field<E>(
|
||||||
slot: *mut $p_type,
|
self,
|
||||||
init: impl $crate::PinInit<$p_type, E>,
|
slot: *mut $p_type,
|
||||||
) -> ::core::result::Result<(), E> {
|
init: impl $crate::PinInit<$p_type, E>,
|
||||||
// SAFETY: TODO.
|
) -> ::core::result::Result<(), E> {
|
||||||
unsafe { $crate::PinInit::__pinned_init(init, slot) }
|
// SAFETY: TODO.
|
||||||
}
|
unsafe { $crate::PinInit::__pinned_init(init, slot) }
|
||||||
)*
|
}
|
||||||
$(
|
|
||||||
$(#[$($attr)*])*
|
$(#[$($p_attr)*])*
|
||||||
$fvis unsafe fn $field<E>(
|
$pvis unsafe fn [<__project_ $p_field>]<'__slot>(
|
||||||
self,
|
self,
|
||||||
slot: *mut $type,
|
slot: &'__slot mut $p_type,
|
||||||
init: impl $crate::Init<$type, E>,
|
) -> ::core::pin::Pin<&'__slot mut $p_type> {
|
||||||
) -> ::core::result::Result<(), E> {
|
::core::pin::Pin::new_unchecked(slot)
|
||||||
// SAFETY: TODO.
|
}
|
||||||
unsafe { $crate::Init::__init(init, slot) }
|
)*
|
||||||
}
|
$(
|
||||||
)*
|
$(#[$($attr)*])*
|
||||||
|
$fvis unsafe fn $field<E>(
|
||||||
|
self,
|
||||||
|
slot: *mut $type,
|
||||||
|
init: impl $crate::Init<$type, E>,
|
||||||
|
) -> ::core::result::Result<(), E> {
|
||||||
|
// 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.
|
// return when an error/panic occurs.
|
||||||
// We also use the `data` to require the correct trait (`Init` or `PinInit`) for `$field`.
|
// 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)? };
|
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:
|
// Create the drop guard:
|
||||||
//
|
//
|
||||||
// We rely on macro hygiene to make it impossible for users to access this local variable.
|
// 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
|
// SAFETY: `slot` is valid, because we are inside of an initializer closure, we
|
||||||
// return when an error/panic occurs.
|
// return when an error/panic occurs.
|
||||||
unsafe { $crate::Init::__init(init, ::core::ptr::addr_of_mut!((*$slot).$field))? };
|
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:
|
// Create the drop guard:
|
||||||
//
|
//
|
||||||
// We rely on macro hygiene to make it impossible for users to access this local variable.
|
// 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),
|
@data($data:ident),
|
||||||
@slot($slot:ident),
|
@slot($slot:ident),
|
||||||
@guards($($guards:ident,)*),
|
@guards($($guards:ident,)*),
|
||||||
|
|
@ -1355,6 +1388,15 @@ fn assert_zeroable<T: $crate::Zeroable>(_: *mut T) {}
|
||||||
// SAFETY: The memory at `slot` is uninitialized.
|
// SAFETY: The memory at `slot` is uninitialized.
|
||||||
unsafe { ::core::ptr::write(::core::ptr::addr_of_mut!((*$slot).$field), $field) };
|
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:
|
// Create the drop guard:
|
||||||
//
|
//
|
||||||
// We rely on macro hygiene to make it impossible for users to access this local variable.
|
// 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::__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),
|
@data($data),
|
||||||
@slot($slot),
|
@slot($slot),
|
||||||
@guards([< __ $field _guard >], $($guards,)*),
|
@guards([< __ $field _guard >], $($guards,)*),
|
||||||
|
|
|
||||||
|
|
@ -78,8 +78,8 @@ fn probe(pdev: &pci::Device<Core>, info: &Self::IdInfo) -> Result<Pin<KBox<Self>
|
||||||
|
|
||||||
let drvdata = KBox::pin_init(
|
let drvdata = KBox::pin_init(
|
||||||
try_pin_init!(Self {
|
try_pin_init!(Self {
|
||||||
pdev: pdev.into(),
|
|
||||||
bar <- pdev.iomap_region_sized::<{ Regs::END }>(0, c_str!("rust_driver_pci")),
|
bar <- pdev.iomap_region_sized::<{ Regs::END }>(0, c_str!("rust_driver_pci")),
|
||||||
|
pdev: pdev.into(),
|
||||||
index: *info,
|
index: *info,
|
||||||
}),
|
}),
|
||||||
GFP_KERNEL,
|
GFP_KERNEL,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue