From patchwork Mon Aug 14 08:46:26 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 135249 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b824:0:b0:3f2:4152:657d with SMTP id z4csp2622446vqi; Mon, 14 Aug 2023 02:27:48 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGmqLi2o0W36C081kcCM53ldSqGbgXxRzwdkl5F4yT4snBO6wd6l7QtJ+YLL6lSlJUEVx/S X-Received: by 2002:a17:906:2009:b0:99c:e1f4:2720 with SMTP id 9-20020a170906200900b0099ce1f42720mr6668522ejo.30.1692005268476; Mon, 14 Aug 2023 02:27:48 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1692005268; cv=none; d=google.com; s=arc-20160816; b=oTUIHTRZ63ZcisTogUXe6SMuBmi9yrhZu8yKTaEu28iw86zqk2TpVIbghZ6y9FYJUX lZxCq1RbR3du/4axSXYcS6on9ZjvAR1qa7e6PutkAzkzJvWMjmAonzRa3H4L0HbM0AwC H4T3fsVqyeliV7H9tZbm1pt2ehjkdr+kjCiTBYApG5EAyv+a+fuQJ5D/mbzGtt3jL72f YzIf7EtkBEAD3Q7Io7233QJfTrxUhlaXrOfUvIk46ayv4HDwGSDdlRheV51z+jqRyfkl xcAHiJ9OqU7duJmdCt0IxgE4H9Rd40E8rP0T3HpQ0q0onAY8YJiuqtDC4COF/kn1G4kk VzKw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=8LcCKWr3ysRBu6jMqsm8nlz+BJEf48RXqJ1abrUpglc=; fh=TE4onW3Du2FQ1EsedDK8TzgRHOYndfJXYpOtlseWrM0=; b=RRQ5Md2Ji7/VjxDeI1nluGq5cgNGeLWqU/0u+bfbkJkLaqtZndw491DrqSLZ3Pp7by OZjYRikEgMRlE9hvSs7tQpahPW9HwlHMaWHNdmQrHSUt0yJWNOEG/vjLrIWX3wB8EjKF lEgBOxJApRv4uEghI45kYfyGx5XseCcYDz8EchAmsmUhMCzH6hQbP+sM4LSQvqM1fz7K YM1f43UCTfsTXRRsDZWHROua049xzruJFpWOOF+IXnctqXg1O+rzpXP0yRreXxqjbzLl AJkcZXCYTNPS8BNxBR1YC782dbKtyiMJBlMzx/6W8I6ukVPkLVWCvRlFdVCnSWZh5+uz 59Bg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=hyLGgOBI; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id f16-20020a170906139000b0099381745ba7si8036114ejc.878.2023.08.14.02.27.24; Mon, 14 Aug 2023 02:27:48 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=hyLGgOBI; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234939AbjHNIqn (ORCPT + 99 others); Mon, 14 Aug 2023 04:46:43 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33916 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234370AbjHNIqf (ORCPT ); Mon, 14 Aug 2023 04:46:35 -0400 Received: from mail-40134.protonmail.ch (mail-40134.protonmail.ch [185.70.40.134]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id B09F110B for ; Mon, 14 Aug 2023 01:46:32 -0700 (PDT) Date: Mon, 14 Aug 2023 08:46:26 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1692002790; x=1692261990; bh=8LcCKWr3ysRBu6jMqsm8nlz+BJEf48RXqJ1abrUpglc=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=hyLGgOBIBDVfL6VunfIeaigW2KFtEQYHVDQnd6yMyScHbItpxBtZF+pSpUzZt7nmw 7dcQwqIKbUKvgJaUzSYo846Q3Svv8EpEJvEB//qJtjVXoUTLR56pVl8zA0aSZIG31v YmVYUawdp0s/Zm2M6ifkBB/dqaZpfUXzt3qQOT4IJ+1CyIpGU0ih0jxvng7l02oBOl R2ItcbzojUjOhn/kFy0zzGtMwhl2ckstmeRa+CHCq28YTayA1XdzzMjQkdnELiQ0/B YmTRuOgXm9qcQon+QJtePEmDAx27hIoMYCsS7KC4NlAKXHWMQlNs/2eEP8bhyhfb1F tA4GgQpY+oYXA== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, patches@lists.linux.dev, Martin Rodriguez Reboredo Subject: [PATCH v4 01/13] rust: init: consolidate init macros Message-ID: <20230814084602.25699-2-benno.lossin@proton.me> In-Reply-To: <20230814084602.25699-1-benno.lossin@proton.me> References: <20230814084602.25699-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, RCVD_IN_MSPIKE_H5,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1774196116370466673 X-GMAIL-MSGID: 1774196116370466673 Merges the implementations of `try_init!` and `try_pin_init!`. These two macros are very similar, but use different traits. The new macro `__init_internal!` that is now the implementation for both takes these traits as parameters. This change does not affect any users, as no public API has been changed, but it should simplify maintaining the init macros. Reviewed-by: Björn Roy Baron Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Alice Ryhl Signed-off-by: Benno Lossin --- v3 -> v4: No changes. v2 -> v3: - added Reviewed-by's from Martin and Alice. v1 -> v2: - added Reviewed-by from Björn. rust/kernel/init.rs | 388 +++---------------------------------- rust/kernel/init/macros.rs | 237 +++++++++++++++++++++- 2 files changed, 259 insertions(+), 366 deletions(-) diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index e05563aad2ed..d431d0b153a2 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -548,11 +548,14 @@ macro_rules! pin_init { ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { $($fields:tt)* }) => { - $crate::try_pin_init!( + $crate::__init_internal!( @this($($this)?), @typ($t $(::<$($generics),*>)?), @fields($($fields)*), @error(::core::convert::Infallible), + @data(PinData, use_data), + @has_data(HasPinData, __pin_data), + @construct_closure(pin_init_from_closure), ) }; } @@ -601,205 +604,29 @@ macro_rules! try_pin_init { ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { $($fields:tt)* }) => { - $crate::try_pin_init!( + $crate::__init_internal!( @this($($this)?), @typ($t $(::<$($generics),*>)? ), @fields($($fields)*), @error($crate::error::Error), + @data(PinData, use_data), + @has_data(HasPinData, __pin_data), + @construct_closure(pin_init_from_closure), ) }; ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { $($fields:tt)* }? $err:ty) => { - $crate::try_pin_init!( + $crate::__init_internal!( @this($($this)?), @typ($t $(::<$($generics),*>)? ), @fields($($fields)*), @error($err), + @data(PinData, use_data), + @has_data(HasPinData, __pin_data), + @construct_closure(pin_init_from_closure), ) }; - ( - @this($($this:ident)?), - @typ($t:ident $(::<$($generics:ty),*>)?), - @fields($($fields:tt)*), - @error($err:ty), - ) => {{ - // We do not want to allow arbitrary returns, so we declare this type as the `Ok` return - // type and shadow it later when we insert the arbitrary user code. That way there will be - // no possibility of returning without `unsafe`. - struct __InitOk; - // Get the pin data from the supplied type. - let data = unsafe { - use $crate::init::__internal::HasPinData; - $t$(::<$($generics),*>)?::__pin_data() - }; - // Ensure that `data` really is of type `PinData` and help with type inference: - let init = $crate::init::__internal::PinData::make_closure::<_, __InitOk, $err>( - data, - move |slot| { - { - // Shadow the structure so it cannot be used to return early. - struct __InitOk; - // Create the `this` so it can be referenced by the user inside of the - // expressions creating the individual fields. - $(let $this = unsafe { ::core::ptr::NonNull::new_unchecked(slot) };)? - // Initialize every field. - $crate::try_pin_init!(init_slot: - @data(data), - @slot(slot), - @munch_fields($($fields)*,), - ); - // We use unreachable code to ensure that all fields have been mentioned exactly - // once, this struct initializer will still be type-checked and complain with a - // very natural error message if a field is forgotten/mentioned more than once. - #[allow(unreachable_code, clippy::diverging_sub_expression)] - if false { - $crate::try_pin_init!(make_initializer: - @slot(slot), - @type_name($t), - @munch_fields($($fields)*,), - @acc(), - ); - } - // Forget all guards, since initialization was a success. - $crate::try_pin_init!(forget_guards: - @munch_fields($($fields)*,), - ); - } - Ok(__InitOk) - } - ); - let init = move |slot| -> ::core::result::Result<(), $err> { - init(slot).map(|__InitOk| ()) - }; - let init = unsafe { $crate::init::pin_init_from_closure::<_, $err>(init) }; - init - }}; - (init_slot: - @data($data:ident), - @slot($slot:ident), - @munch_fields($(,)?), - ) => { - // Endpoint of munching, no fields are left. - }; - (init_slot: - @data($data:ident), - @slot($slot:ident), - // In-place initialization syntax. - @munch_fields($field:ident <- $val:expr, $($rest:tt)*), - ) => { - let $field = $val; - // Call the initializer. - // - // SAFETY: `slot` is valid, because we are inside of an initializer closure, we - // 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), $field)? }; - // Create the drop guard. - // - // We only give access to `&DropGuard`, so it cannot be forgotten via safe code. - // - // SAFETY: We forget the guard later when initialization has succeeded. - let $field = &unsafe { - $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field)) - }; - - $crate::try_pin_init!(init_slot: - @data($data), - @slot($slot), - @munch_fields($($rest)*), - ); - }; - (init_slot: - @data($data:ident), - @slot($slot:ident), - // Direct value init, this is safe for every field. - @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) }; - // Create the drop guard: - // - // We only give access to `&DropGuard`, so it cannot be accidentally forgotten. - // - // SAFETY: We forget the guard later when initialization has succeeded. - let $field = &unsafe { - $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field)) - }; - - $crate::try_pin_init!(init_slot: - @data($data), - @slot($slot), - @munch_fields($($rest)*), - ); - }; - (make_initializer: - @slot($slot:ident), - @type_name($t:ident), - @munch_fields($(,)?), - @acc($($acc:tt)*), - ) => { - // Endpoint, nothing more to munch, create the initializer. - // Since we are in the `if false` branch, this will never get executed. We abuse `slot` to - // get the correct type inference here: - unsafe { - ::core::ptr::write($slot, $t { - $($acc)* - }); - } - }; - (make_initializer: - @slot($slot:ident), - @type_name($t:ident), - @munch_fields($field:ident <- $val:expr, $($rest:tt)*), - @acc($($acc:tt)*), - ) => { - $crate::try_pin_init!(make_initializer: - @slot($slot), - @type_name($t), - @munch_fields($($rest)*), - @acc($($acc)* $field: ::core::panic!(),), - ); - }; - (make_initializer: - @slot($slot:ident), - @type_name($t:ident), - @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), - @acc($($acc:tt)*), - ) => { - $crate::try_pin_init!(make_initializer: - @slot($slot), - @type_name($t), - @munch_fields($($rest)*), - @acc($($acc)* $field: ::core::panic!(),), - ); - }; - (forget_guards: - @munch_fields($(,)?), - ) => { - // Munching finished. - }; - (forget_guards: - @munch_fields($field:ident <- $val:expr, $($rest:tt)*), - ) => { - unsafe { $crate::init::__internal::DropGuard::forget($field) }; - - $crate::try_pin_init!(forget_guards: - @munch_fields($($rest)*), - ); - }; - (forget_guards: - @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), - ) => { - unsafe { $crate::init::__internal::DropGuard::forget($field) }; - - $crate::try_pin_init!(forget_guards: - @munch_fields($($rest)*), - ); - }; } /// Construct an in-place initializer for `struct`s. @@ -824,11 +651,14 @@ macro_rules! init { ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { $($fields:tt)* }) => { - $crate::try_init!( + $crate::__init_internal!( @this($($this)?), @typ($t $(::<$($generics),*>)?), @fields($($fields)*), @error(::core::convert::Infallible), + @data(InitData, /*no use_data*/), + @has_data(HasInitData, __init_data), + @construct_closure(init_from_closure), ) } } @@ -871,199 +701,29 @@ macro_rules! try_init { ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { $($fields:tt)* }) => { - $crate::try_init!( + $crate::__init_internal!( @this($($this)?), @typ($t $(::<$($generics),*>)?), @fields($($fields)*), @error($crate::error::Error), + @data(InitData, /*no use_data*/), + @has_data(HasInitData, __init_data), + @construct_closure(init_from_closure), ) }; ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { $($fields:tt)* }? $err:ty) => { - $crate::try_init!( + $crate::__init_internal!( @this($($this)?), @typ($t $(::<$($generics),*>)?), @fields($($fields)*), @error($err), + @data(InitData, /*no use_data*/), + @has_data(HasInitData, __init_data), + @construct_closure(init_from_closure), ) }; - ( - @this($($this:ident)?), - @typ($t:ident $(::<$($generics:ty),*>)?), - @fields($($fields:tt)*), - @error($err:ty), - ) => {{ - // We do not want to allow arbitrary returns, so we declare this type as the `Ok` return - // type and shadow it later when we insert the arbitrary user code. That way there will be - // no possibility of returning without `unsafe`. - struct __InitOk; - // Get the init data from the supplied type. - let data = unsafe { - use $crate::init::__internal::HasInitData; - $t$(::<$($generics),*>)?::__init_data() - }; - // Ensure that `data` really is of type `InitData` and help with type inference: - let init = $crate::init::__internal::InitData::make_closure::<_, __InitOk, $err>( - data, - move |slot| { - { - // Shadow the structure so it cannot be used to return early. - struct __InitOk; - // Create the `this` so it can be referenced by the user inside of the - // expressions creating the individual fields. - $(let $this = unsafe { ::core::ptr::NonNull::new_unchecked(slot) };)? - // Initialize every field. - $crate::try_init!(init_slot: - @slot(slot), - @munch_fields($($fields)*,), - ); - // We use unreachable code to ensure that all fields have been mentioned exactly - // once, this struct initializer will still be type-checked and complain with a - // very natural error message if a field is forgotten/mentioned more than once. - #[allow(unreachable_code, clippy::diverging_sub_expression)] - if false { - $crate::try_init!(make_initializer: - @slot(slot), - @type_name($t), - @munch_fields($($fields)*,), - @acc(), - ); - } - // Forget all guards, since initialization was a success. - $crate::try_init!(forget_guards: - @munch_fields($($fields)*,), - ); - } - Ok(__InitOk) - } - ); - let init = move |slot| -> ::core::result::Result<(), $err> { - init(slot).map(|__InitOk| ()) - }; - let init = unsafe { $crate::init::init_from_closure::<_, $err>(init) }; - init - }}; - (init_slot: - @slot($slot:ident), - @munch_fields( $(,)?), - ) => { - // Endpoint of munching, no fields are left. - }; - (init_slot: - @slot($slot:ident), - @munch_fields($field:ident <- $val:expr, $($rest:tt)*), - ) => { - let $field = $val; - // Call the initializer. - // - // SAFETY: `slot` is valid, because we are inside of an initializer closure, we - // return when an error/panic occurs. - unsafe { - $crate::init::Init::__init($field, ::core::ptr::addr_of_mut!((*$slot).$field))?; - } - // Create the drop guard. - // - // We only give access to `&DropGuard`, so it cannot be accidentally forgotten. - // - // SAFETY: We forget the guard later when initialization has succeeded. - let $field = &unsafe { - $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field)) - }; - - $crate::try_init!(init_slot: - @slot($slot), - @munch_fields($($rest)*), - ); - }; - (init_slot: - @slot($slot:ident), - // Direct value init. - @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), - ) => { - $(let $field = $val;)? - // Call the initializer. - // - // SAFETY: The memory at `slot` is uninitialized. - unsafe { ::core::ptr::write(::core::ptr::addr_of_mut!((*$slot).$field), $field) }; - // Create the drop guard. - // - // We only give access to `&DropGuard`, so it cannot be accidentally forgotten. - // - // SAFETY: We forget the guard later when initialization has succeeded. - let $field = &unsafe { - $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field)) - }; - - $crate::try_init!(init_slot: - @slot($slot), - @munch_fields($($rest)*), - ); - }; - (make_initializer: - @slot($slot:ident), - @type_name($t:ident), - @munch_fields( $(,)?), - @acc($($acc:tt)*), - ) => { - // Endpoint, nothing more to munch, create the initializer. - // Since we are in the `if false` branch, this will never get executed. We abuse `slot` to - // get the correct type inference here: - unsafe { - ::core::ptr::write($slot, $t { - $($acc)* - }); - } - }; - (make_initializer: - @slot($slot:ident), - @type_name($t:ident), - @munch_fields($field:ident <- $val:expr, $($rest:tt)*), - @acc($($acc:tt)*), - ) => { - $crate::try_init!(make_initializer: - @slot($slot), - @type_name($t), - @munch_fields($($rest)*), - @acc($($acc)*$field: ::core::panic!(),), - ); - }; - (make_initializer: - @slot($slot:ident), - @type_name($t:ident), - @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), - @acc($($acc:tt)*), - ) => { - $crate::try_init!(make_initializer: - @slot($slot), - @type_name($t), - @munch_fields($($rest)*), - @acc($($acc)*$field: ::core::panic!(),), - ); - }; - (forget_guards: - @munch_fields($(,)?), - ) => { - // Munching finished. - }; - (forget_guards: - @munch_fields($field:ident <- $val:expr, $($rest:tt)*), - ) => { - unsafe { $crate::init::__internal::DropGuard::forget($field) }; - - $crate::try_init!(forget_guards: - @munch_fields($($rest)*), - ); - }; - (forget_guards: - @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), - ) => { - unsafe { $crate::init::__internal::DropGuard::forget($field) }; - - $crate::try_init!(forget_guards: - @munch_fields($($rest)*), - ); - }; } /// A pin-initializer for the type `T`. diff --git a/rust/kernel/init/macros.rs b/rust/kernel/init/macros.rs index 00aa4e956c0a..fbaebd34f218 100644 --- a/rust/kernel/init/macros.rs +++ b/rust/kernel/init/macros.rs @@ -1,10 +1,12 @@ // SPDX-License-Identifier: Apache-2.0 OR MIT //! This module provides the macros that actually implement the proc-macros `pin_data` and -//! `pinned_drop`. +//! `pinned_drop`. It also contains `__init_internal` the implementation of the `{try_}{pin_}init!` +//! macros. //! //! These macros should never be called directly, since they expect their input to be -//! in a certain format which is internal. Use the proc-macros instead. +//! in a certain format which is internal. If used incorrectly, these macros can lead to UB even in +//! safe code! Use the public facing macros instead. //! //! This architecture has been chosen because the kernel does not yet have access to `syn` which //! would make matters a lot easier for implementing these as proc-macros. @@ -980,3 +982,234 @@ impl<$($impl_generics)*> $pin_data<$($ty_generics)*> } }; } + +/// The internal init macro. Do not call manually! +/// +/// This is called by the `{try_}{pin_}init!` macros with various inputs. +/// +/// This macro has multiple internal call configurations, these are always the very first ident: +/// - nothing: this is the base case and called by the `{try_}{pin_}init!` macros. +/// - `init_slot`: recursively creates the code that initializes all fields in `slot`. +/// - `make_initializer`: recursively create the struct initializer that guarantees that every +/// field has been initialized exactly once. +/// - `forget_guards`: recursively forget the drop guards for every field. +#[doc(hidden)] +#[macro_export] +macro_rules! __init_internal { + ( + @this($($this:ident)?), + @typ($t:ident $(::<$($generics:ty),*>)?), + @fields($($fields:tt)*), + @error($err:ty), + // Either `PinData` or `InitData`, `$use_data` should only be present in the `PinData` + // case. + @data($data:ident, $($use_data:ident)?), + // `HasPinData` or `HasInitData`. + @has_data($has_data:ident, $get_data:ident), + // `pin_init_from_closure` or `init_from_closure`. + @construct_closure($construct_closure:ident), + ) => {{ + // We do not want to allow arbitrary returns, so we declare this type as the `Ok` return + // type and shadow it later when we insert the arbitrary user code. That way there will be + // no possibility of returning without `unsafe`. + struct __InitOk; + // Get the data about fields from the supplied type. + let data = unsafe { + use $crate::init::__internal::$has_data; + $t$(::<$($generics),*>)?::$get_data() + }; + // Ensure that `data` really is of type `$data` and help with type inference: + let init = $crate::init::__internal::$data::make_closure::<_, __InitOk, $err>( + data, + move |slot| { + { + // Shadow the structure so it cannot be used to return early. + struct __InitOk; + // Create the `this` so it can be referenced by the user inside of the + // expressions creating the individual fields. + $(let $this = unsafe { ::core::ptr::NonNull::new_unchecked(slot) };)? + // Initialize every field. + $crate::__init_internal!(init_slot($($use_data)?): + @data(data), + @slot(slot), + @munch_fields($($fields)*,), + ); + // We use unreachable code to ensure that all fields have been mentioned exactly + // once, this struct initializer will still be type-checked and complain with a + // very natural error message if a field is forgotten/mentioned more than once. + #[allow(unreachable_code, clippy::diverging_sub_expression)] + if false { + $crate::__init_internal!(make_initializer: + @slot(slot), + @type_name($t), + @munch_fields($($fields)*,), + @acc(), + ); + } + // Forget all guards, since initialization was a success. + $crate::__init_internal!(forget_guards: + @munch_fields($($fields)*,), + ); + } + Ok(__InitOk) + } + ); + let init = move |slot| -> ::core::result::Result<(), $err> { + init(slot).map(|__InitOk| ()) + }; + let init = unsafe { $crate::init::$construct_closure::<_, $err>(init) }; + init + }}; + (init_slot($($use_data:ident)?): + @data($data:ident), + @slot($slot:ident), + @munch_fields($(,)?), + ) => { + // Endpoint of munching, no fields are left. + }; + (init_slot($use_data:ident): // use_data is present, so we use the `data` to init fields. + @data($data:ident), + @slot($slot:ident), + // In-place initialization syntax. + @munch_fields($field:ident <- $val:expr, $($rest:tt)*), + ) => { + let $field = $val; + // Call the initializer. + // + // SAFETY: `slot` is valid, because we are inside of an initializer closure, we + // 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), $field)? }; + // Create the drop guard. + // + // We only give access to `&DropGuard`, so it cannot be forgotten via safe code. + // + // SAFETY: We forget the guard later when initialization has succeeded. + let $field = &unsafe { + $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field)) + }; + + $crate::__init_internal!(init_slot($use_data): + @data($data), + @slot($slot), + @munch_fields($($rest)*), + ); + }; + (init_slot(): // no use_data, so we use `Init::__init` directly. + @data($data:ident), + @slot($slot:ident), + // In-place initialization syntax. + @munch_fields($field:ident <- $val:expr, $($rest:tt)*), + ) => { + let $field = $val; + // Call the initializer. + // + // SAFETY: `slot` is valid, because we are inside of an initializer closure, we + // return when an error/panic occurs. + unsafe { $crate::init::Init::__init($field, ::core::ptr::addr_of_mut!((*$slot).$field))? }; + // Create the drop guard. + // + // We only give access to `&DropGuard`, so it cannot be forgotten via safe code. + // + // SAFETY: We forget the guard later when initialization has succeeded. + let $field = &unsafe { + $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field)) + }; + + $crate::__init_internal!(init_slot(): + @data($data), + @slot($slot), + @munch_fields($($rest)*), + ); + }; + (init_slot($($use_data:ident)?): + @data($data:ident), + @slot($slot: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) }; + // Create the drop guard: + // + // We only give access to `&DropGuard`, so it cannot be accidentally forgotten. + // + // SAFETY: We forget the guard later when initialization has succeeded. + let $field = &unsafe { + $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field)) + }; + + $crate::__init_internal!(init_slot($($use_data)?): + @data($data), + @slot($slot), + @munch_fields($($rest)*), + ); + }; + (make_initializer: + @slot($slot:ident), + @type_name($t:ident), + @munch_fields($(,)?), + @acc($($acc:tt)*), + ) => { + // Endpoint, nothing more to munch, create the initializer. + // Since we are in the `if false` branch, this will never get executed. We abuse `slot` to + // get the correct type inference here: + unsafe { + ::core::ptr::write($slot, $t { + $($acc)* + }); + } + }; + (make_initializer: + @slot($slot:ident), + @type_name($t:ident), + @munch_fields($field:ident <- $val:expr, $($rest:tt)*), + @acc($($acc:tt)*), + ) => { + $crate::__init_internal!(make_initializer: + @slot($slot), + @type_name($t), + @munch_fields($($rest)*), + @acc($($acc)* $field: ::core::panic!(),), + ); + }; + (make_initializer: + @slot($slot:ident), + @type_name($t:ident), + @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), + @acc($($acc:tt)*), + ) => { + $crate::__init_internal!(make_initializer: + @slot($slot), + @type_name($t), + @munch_fields($($rest)*), + @acc($($acc)* $field: ::core::panic!(),), + ); + }; + (forget_guards: + @munch_fields($(,)?), + ) => { + // Munching finished. + }; + (forget_guards: + @munch_fields($field:ident <- $val:expr, $($rest:tt)*), + ) => { + unsafe { $crate::init::__internal::DropGuard::forget($field) }; + + $crate::__init_internal!(forget_guards: + @munch_fields($($rest)*), + ); + }; + (forget_guards: + @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), + ) => { + unsafe { $crate::init::__internal::DropGuard::forget($field) }; + + $crate::__init_internal!(forget_guards: + @munch_fields($($rest)*), + ); + }; +} From patchwork Mon Aug 14 08:46:31 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 135347 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b824:0:b0:3f2:4152:657d with SMTP id z4csp2666683vqi; Mon, 14 Aug 2023 04:09:21 -0700 (PDT) X-Google-Smtp-Source: AGHT+IG6I2UxXn3F6LSFPueHpggTsW+eyS/SS4f53rXjm5OYtWGQx4Pbg+/WxLC6Onm/rTMDfIJO X-Received: by 2002:a17:906:518a:b0:99d:9ca9:8c19 with SMTP id y10-20020a170906518a00b0099d9ca98c19mr3251436ejk.74.1692011361604; Mon, 14 Aug 2023 04:09:21 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1692011361; cv=none; d=google.com; s=arc-20160816; b=WeyBdBvqXahZdzQRPEAtWpkSVktmzA+63R4UYcooLVUTlCu9b9d7UOlis07epvSP8q X6Ysi31leNyZsoFP9CGu6+nlQbR7neZ4YxzeSwqh1wqa9Pf31zOLCKZDAPCimCch/kQL TBVtUxVQ/Uq09YJgm5VIPs5VNhZmIlG0KbuUJ54/wLNXvC0bF5dHCJex0CQ7OHFZy+Qa YCA2vreOjxKx4FZXi9tkaW8Ep+C6hYA4BVc7h7quUzr7CWsyjta2bCE7pF6N5e9wRYrm AHM87iy+PKwm8fY+HoWqkMcVSyYwLASCLTgjZNI3UlgrVjzJW+SqeYtoTWBTOca7d0jB d1xg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=cCm8wW9vNkKH2FZUy3jRZYJZ3dWJlVZH7ASGRvlZaKY=; fh=TE4onW3Du2FQ1EsedDK8TzgRHOYndfJXYpOtlseWrM0=; b=v3tLtUsxDNhDvsT5C8el3hOL3HbNXs/d3UXR4tVomf4FMn8a9U9xbxFTFXtDpYDY68 op59XzId7Jme1nmaUbw0ObUjg7PTk3vk0DHniIr+zHokMtVgTR8XWHsOoUxN3/xG++VD /l+64+cItkIlPzB3OMDXM+wZYN7clampKGkYBKRqeyW1WfPiIIKZNL5AYnJo2H5GDLgJ hJ10k8occEOSSTVszRL9GCvuKLtab9QltyitB+oZXalGA5AXRHw825M1o0LNcaGwmFEP Y4oJ5l1tqVrQvWLp5/1HyW3lyFNdaDG6Jgg96jvwhGebY8Gu+McEL/H2S8OlTkoNM2WG eiww== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=f6gK19pW; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id jw26-20020a17090776ba00b0099bd39dcec3si7483248ejc.95.2023.08.14.04.08.55; Mon, 14 Aug 2023 04:09:21 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=f6gK19pW; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234697AbjHNIrN (ORCPT + 99 others); Mon, 14 Aug 2023 04:47:13 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41216 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234958AbjHNIqq (ORCPT ); Mon, 14 Aug 2023 04:46:46 -0400 Received: from mail-4316.protonmail.ch (mail-4316.protonmail.ch [185.70.43.16]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 7299F12D; Mon, 14 Aug 2023 01:46:45 -0700 (PDT) Date: Mon, 14 Aug 2023 08:46:31 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1692002803; x=1692262003; bh=cCm8wW9vNkKH2FZUy3jRZYJZ3dWJlVZH7ASGRvlZaKY=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=f6gK19pWOkyU7bTj7Kg/FMG1ckvi7PYfOhAi1ncpXLPafgl5r3cYDtO/VzAzitHFA UCvdyD/gVxVDnRmgn7xGwopgP4ygYk7EBfd7NZTwxM+/AtaVkyobCrTsAvsw96nCTF kAob29TUS63xuJuUbLIVGGtzq0tSOcPMvklbF/9Z0GV+3HWNbs/aFPUvP8u8/OKSEJ 05yGRoWkw072+33b/wg1rt8IhtxIyeszCk5nDZtFjWAmNrtrxHROIQT0T2xq+u+0N8 uXi/Y5ldaxdaEYRZ0egRZBQLrLIIRZ05OvckVmROJn5TMwqHPgBDK0RFiu1Ey8/CrM qNK6obLjqQT8A== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, patches@lists.linux.dev, Martin Rodriguez Reboredo Subject: [PATCH v4 02/13] rust: init: make `#[pin_data]` compatible with conditional compilation of fields Message-ID: <20230814084602.25699-3-benno.lossin@proton.me> In-Reply-To: <20230814084602.25699-1-benno.lossin@proton.me> References: <20230814084602.25699-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1774202505173250724 X-GMAIL-MSGID: 1774202505173250724 This patch allows one to write ``` #[pin_data] pub struct Foo { #[cfg(CONFIG_BAR)] a: Bar, #[cfg(not(CONFIG_BAR))] a: Baz, } ``` Before, this would result in a compile error, because `#[pin_data]` would generate two functions named `a` for both fields unconditionally. Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Gary Guo Reviewed-by: Alice Ryhl Signed-off-by: Benno Lossin --- v3 -> v4: - added Reviewed-by's from Gary, Alice and Martin. rust/kernel/init/macros.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rust/kernel/init/macros.rs b/rust/kernel/init/macros.rs index fbaebd34f218..9182fdf99e7e 100644 --- a/rust/kernel/init/macros.rs +++ b/rust/kernel/init/macros.rs @@ -962,6 +962,7 @@ impl<$($impl_generics)*> $pin_data<$($ty_generics)*> where $($whr)* { $( + $(#[$($p_attr)*])* $pvis unsafe fn $p_field( self, slot: *mut $p_type, @@ -971,6 +972,7 @@ impl<$($impl_generics)*> $pin_data<$($ty_generics)*> } )* $( + $(#[$($attr)*])* $fvis unsafe fn $field( self, slot: *mut $type, From patchwork Mon Aug 14 08:46:41 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 135287 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b824:0:b0:3f2:4152:657d with SMTP id z4csp2629311vqi; Mon, 14 Aug 2023 02:46:05 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFjVBwCMFr3oh9uegyef+agtHnjXGP056l6sdTnZJr8H9o7QzcI3LyHPmetjI+sAQTlJONY X-Received: by 2002:aa7:c30f:0:b0:523:6c47:56f8 with SMTP id l15-20020aa7c30f000000b005236c4756f8mr7107294edq.18.1692006365258; Mon, 14 Aug 2023 02:46:05 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1692006365; cv=none; d=google.com; s=arc-20160816; b=K+uPe4xUl9wTGGzTBJgm3VeiYgnofZ/gjNacLouGQDVBej9ZWXrtsQqbKbAJlqRIRe 5PM9Ijczv9B5c9CDrZ1pc20B162DLIRhKOLS4fxkXHv1YByeUg6yFpWSRuUi7GjvU95n /KRSrxva0wZVUMokXHxT5BNdTuTWupfkX5lax0Td3BRjfXAKw0x5ZFrFAZ4gAmUNQ4L4 1FVRjSYBbgwQBO4lKabHoFZ3fM5GZYOOLdYZt92TPBMPy91ZmAp7bGlSdT175Umf9OkN BGch7Z8KTzC3sjaYEnTbGwLX5IFW7RJM9y8bP9naTP0gHTwxKqJ8OhexntiV/iO4shTB ft0Q== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=bMYBy/yxUzYNLePNMMjA4ZSmmlU+epSTw1cc5ylrenA=; fh=9qAu1mhYFxYeaElldShNhIt7ezwLosaXPSwpT1P2JOg=; b=xJgnNT6XWD2KrKfKAjt9pjLdBNRq6/GvhcKTKB5SRXWitfeBjJpezuopd9vNNth6ba GkyC4ErBaA3yt5uggQTkH/wR7GqdFTVitnbl8D7382xydpaM1lNylUvK8rsGTwRovkXS HsoBZ7YQq5v/j0VNqvMCMgKyjIpOdFipq/cXgadmfQhAzUPMY47k8YPV3487fR/1Amtr rRu4moLFV9qYnJ4YIFsY+/NhfsUTnlnIr6Cyh3qy2g2C5jKfRyA4aRnx3RdXEDpKlSNC qj9rbkmLY78CZHZIy+LsPiJR62fNz9GlStIt4AHOcLY8Fm0kW6lNm/D5zXqz0aiuI/j4 y6LA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=rayheo6bwfb25jkb4mklfbwy2m.protonmail header.b=MzE73qw+; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id v14-20020aa7d80e000000b005234f302c99si7364488edq.499.2023.08.14.02.45.42; Mon, 14 Aug 2023 02:46:05 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=rayheo6bwfb25jkb4mklfbwy2m.protonmail header.b=MzE73qw+; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234950AbjHNIrQ (ORCPT + 99 others); Mon, 14 Aug 2023 04:47:16 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41186 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234997AbjHNIqs (ORCPT ); Mon, 14 Aug 2023 04:46:48 -0400 Received: from mail-4316.protonmail.ch (mail-4316.protonmail.ch [185.70.43.16]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9E36510C1 for ; Mon, 14 Aug 2023 01:46:46 -0700 (PDT) Date: Mon, 14 Aug 2023 08:46:41 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=rayheo6bwfb25jkb4mklfbwy2m.protonmail; t=1692002804; x=1692262004; bh=bMYBy/yxUzYNLePNMMjA4ZSmmlU+epSTw1cc5ylrenA=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=MzE73qw+hMEoBUfH8OMzukx5yOplVWu6U1j0jSdZwHWnYoYdMjonRcqbiPMbfyYGZ zDW0DsdwwGuzMoZNDdrhjAZrQmhGZdX3TuakGyGiPA941Fp3z5hxbwL8q750+NgZUb kOHVd+VGE9BYn7FRXYQN2GIhihuzHiNRX9vQoWp3uipYnecmX473MkCOcw/nvEKDoj +Y5jRB5IWEOYnBAEAR7jHIJyXRVrBFO4BDK23G2fz1GhG/WgvW0You56RSMffk4FRu +OD4OajI5bv+phpUTRIA2/rYNtTzgyb8PPrm7/M3kOkcuP/FnjlfwPiT5/2meTHQd7 ewTgdvID3CYeA== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, patches@lists.linux.dev, Asahi Lina Subject: [PATCH v4 03/13] rust: add derive macro for `Zeroable` Message-ID: <20230814084602.25699-4-benno.lossin@proton.me> In-Reply-To: <20230814084602.25699-1-benno.lossin@proton.me> References: <20230814084602.25699-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1774197266563031740 X-GMAIL-MSGID: 1774197266563031740 Add a derive proc-macro for the `Zeroable` trait. The macro supports structs where every field implements the `Zeroable` trait. This way `unsafe` implementations can be avoided. The macro is split into two parts: - a proc-macro to parse generics into impl and ty generics, - a declarative macro that expands to the impl block. Suggested-by: Asahi Lina Signed-off-by: Benno Lossin --- v3 -> v4: - add support for `+` in `quote!`. v2 -> v3: - change derive behavior, instead of adding `Zeroable` bounds for every field, add them only for generic type parameters, - still check that every field implements `Zeroable`, - removed Reviewed-by's due to changes. v1 -> v2: - fix Zeroable path, - add Reviewed-by from Gary and Björn. rust/kernel/init/macros.rs | 35 ++++++++++++++++++ rust/kernel/prelude.rs | 2 +- rust/macros/lib.rs | 20 +++++++++++ rust/macros/quote.rs | 12 +++++++ rust/macros/zeroable.rs | 72 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 140 insertions(+), 1 deletion(-) create mode 100644 rust/macros/zeroable.rs diff --git a/rust/kernel/init/macros.rs b/rust/kernel/init/macros.rs index 9182fdf99e7e..78091756dec0 100644 --- a/rust/kernel/init/macros.rs +++ b/rust/kernel/init/macros.rs @@ -1215,3 +1215,38 @@ macro_rules! __init_internal { ); }; } + +#[doc(hidden)] +#[macro_export] +macro_rules! __derive_zeroable { + (parse_input: + @sig( + $(#[$($struct_attr:tt)*])* + $vis:vis struct $name:ident + $(where $($whr:tt)*)? + ), + @impl_generics($($impl_generics:tt)*), + @ty_generics($($ty_generics:tt)*), + @body({ + $( + $(#[$($field_attr:tt)*])* + $field:ident : $field_ty:ty + ),* $(,)? + }), + ) => { + // SAFETY: every field type implements `Zeroable` and padding bytes may be zero. + #[automatically_derived] + unsafe impl<$($impl_generics)*> $crate::init::Zeroable for $name<$($ty_generics)*> + where + $($($whr)*)? + {} + const _: () = { + fn assert_zeroable() {} + fn ensure_zeroable<$($impl_generics)*>() + where $($($whr)*)? + { + $(assert_zeroable::<$field_ty>();)* + } + }; + }; +} diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs index c28587d68ebc..ae21600970b3 100644 --- a/rust/kernel/prelude.rs +++ b/rust/kernel/prelude.rs @@ -18,7 +18,7 @@ pub use alloc::{boxed::Box, vec::Vec}; #[doc(no_inline)] -pub use macros::{module, pin_data, pinned_drop, vtable}; +pub use macros::{module, pin_data, pinned_drop, vtable, Zeroable}; pub use super::build_assert; diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs index b4bc44c27bd4..fd7a815e68a8 100644 --- a/rust/macros/lib.rs +++ b/rust/macros/lib.rs @@ -11,6 +11,7 @@ mod pin_data; mod pinned_drop; mod vtable; +mod zeroable; use proc_macro::TokenStream; @@ -343,3 +344,22 @@ pub fn paste(input: TokenStream) -> TokenStream { paste::expand(&mut tokens); tokens.into_iter().collect() } + +/// Derives the [`Zeroable`] trait for the given struct. +/// +/// This can only be used for structs where every field implements the [`Zeroable`] trait. +/// +/// # Examples +/// +/// ```rust +/// #[derive(Zeroable)] +/// pub struct DriverData { +/// id: i64, +/// buf_ptr: *mut u8, +/// len: usize, +/// } +/// ``` +#[proc_macro_derive(Zeroable)] +pub fn derive_zeroable(input: TokenStream) -> TokenStream { + zeroable::derive(input) +} diff --git a/rust/macros/quote.rs b/rust/macros/quote.rs index dddbb4e6f4cb..33a199e4f176 100644 --- a/rust/macros/quote.rs +++ b/rust/macros/quote.rs @@ -124,6 +124,18 @@ macro_rules! quote_spanned { )); quote_spanned!(@proc $v $span $($tt)*); }; + (@proc $v:ident $span:ident ; $($tt:tt)*) => { + $v.push(::proc_macro::TokenTree::Punct( + ::proc_macro::Punct::new(';', ::proc_macro::Spacing::Alone) + )); + quote_spanned!(@proc $v $span $($tt)*); + }; + (@proc $v:ident $span:ident + $($tt:tt)*) => { + $v.push(::proc_macro::TokenTree::Punct( + ::proc_macro::Punct::new('+', ::proc_macro::Spacing::Alone) + )); + quote_spanned!(@proc $v $span $($tt)*); + }; (@proc $v:ident $span:ident $id:ident $($tt:tt)*) => { $v.push(::proc_macro::TokenTree::Ident(::proc_macro::Ident::new(stringify!($id), $span))); quote_spanned!(@proc $v $span $($tt)*); diff --git a/rust/macros/zeroable.rs b/rust/macros/zeroable.rs new file mode 100644 index 000000000000..0d605c46ab3b --- /dev/null +++ b/rust/macros/zeroable.rs @@ -0,0 +1,72 @@ +// SPDX-License-Identifier: GPL-2.0 + +use crate::helpers::{parse_generics, Generics}; +use proc_macro::{TokenStream, TokenTree}; + +pub(crate) fn derive(input: TokenStream) -> TokenStream { + let ( + Generics { + impl_generics, + ty_generics, + }, + mut rest, + ) = parse_generics(input); + // This should be the body of the struct `{...}`. + let last = rest.pop(); + // Now we insert `Zeroable` as a bound for every generic parameter in `impl_generics`. + let mut new_impl_generics = Vec::with_capacity(impl_generics.len()); + // Are we inside of a generic where we want to add `Zeroable`? + let mut in_generic = !impl_generics.is_empty(); + // Have we already inserted `Zeroable`? + let mut inserted = false; + // Level of `<>` nestings. + let mut nested = 0; + for tt in impl_generics { + match &tt { + // If we find a `,`, then we have finished a generic/constant/lifetime parameter. + TokenTree::Punct(p) if nested == 0 && p.as_char() == ',' => { + if in_generic && !inserted { + new_impl_generics.extend(quote! { : ::kernel::init::Zeroable }); + } + in_generic = true; + inserted = false; + new_impl_generics.push(tt); + } + // If we find `'`, then we are entering a lifetime. + TokenTree::Punct(p) if nested == 0 && p.as_char() == '\'' => { + in_generic = false; + new_impl_generics.push(tt); + } + TokenTree::Punct(p) if nested == 0 && p.as_char() == ':' => { + new_impl_generics.push(tt); + if in_generic { + new_impl_generics.extend(quote! { ::kernel::init::Zeroable + }); + inserted = true; + } + } + TokenTree::Punct(p) if p.as_char() == '<' => { + nested += 1; + new_impl_generics.push(tt); + } + TokenTree::Punct(p) if p.as_char() == '>' => { + assert!(nested > 0); + nested -= 1; + new_impl_generics.push(tt); + } + _ => new_impl_generics.push(tt), + } + } + assert_eq!(nested, 0); + if in_generic && !inserted { + new_impl_generics.extend(quote! { : ::kernel::init::Zeroable }); + } + quote! { + ::kernel::__derive_zeroable!( + parse_input: + @sig(#(#rest)*), + @impl_generics(#(#new_impl_generics)*), + @ty_generics(#(#ty_generics)*), + @body(#last), + ); + } +} From patchwork Mon Aug 14 08:46:48 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 135251 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b824:0:b0:3f2:4152:657d with SMTP id z4csp2623180vqi; Mon, 14 Aug 2023 02:30:00 -0700 (PDT) X-Google-Smtp-Source: AGHT+IE4Mf9pJCdaEPg0p6bPL4M4rbTzNf/WkvhuSTAjBDvQ4YWVKc8ynvmkdB9ZhaI6u+pBgGEb X-Received: by 2002:a17:906:7489:b0:993:e752:1a71 with SMTP id e9-20020a170906748900b00993e7521a71mr7396528ejl.9.1692005400573; Mon, 14 Aug 2023 02:30:00 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1692005400; cv=none; d=google.com; s=arc-20160816; b=FTr/DhCPOVfsuaBHp5NMJWbfEkBKjJcMFYBE+6Oda85ujhqZKUFQvzCu25Wmxj/gG2 t3wTGaYkRZy76M3xMuwIXOo/m6ixJeUgueOw9w1ei1L8Dl0lHZgEKibIJAylETqxmvrc C+c3UwSiIs+jSXzsV4tBOwJmts6bSIv2RYFMajWo8jyGnPiRJYjHtdtpEEi/vWay9qNz Gp8wka5uoUx7dy24245s7AI39Ykbhwpu1JXis2IfC3O4tF1e7313RgXamz10wHrojbkF SSYyXqSOzyGbqVacZ/n94wI7UQGmzsi34zweJce6Q+4kZ3idwNZN9UHMcYg6vXS5p9ui IMRA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=r0rCJDgexbLd/PbKtXjKQNdC/yi+joahEDdPpIvT9F4=; fh=h3KS08NeBaYH5bCiXUF1yMk4NKDs2FHNIfHsq8atlgQ=; b=jMUiIaR2GorBN1nuSLRwhUUGocRkHk3AstG15HWy2KHGBUfKcc02USsCAIchqIDZKA fZQkZfMj9xPclNYmS8sgBkkTaEn+4t5Pvn6jZfVziTsm7JCountzrx++Ga/JN69ynF6b 3rgRBsUd4ffkGws+p/ZgwDQ/qceezpX3bElIkksO1V2LuGIQIL9s3oEjeoM+jlGWjq6v KzLSZ0FW0ug7SbB8zY8GpncQG4jAE2y1FlLNGEt4+A18q7VVKMjYg134oG+C5woPPHXy 6XVW4Ut/rgRtGSUDJ1uQcGMaxviKCI45XJY4EvME/dfC1n4KXcfIuxbfju0V3olTAEgF ikOA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=f4tuk7d6b5g5pm4hzkdqaeyym4.protonmail header.b=GuGi73VP; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id sd19-20020a170906ce3300b0098dafe075ccsi6696509ejb.97.2023.08.14.02.29.36; Mon, 14 Aug 2023 02:30:00 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=f4tuk7d6b5g5pm4hzkdqaeyym4.protonmail header.b=GuGi73VP; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234994AbjHNIrU (ORCPT + 99 others); Mon, 14 Aug 2023 04:47:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38586 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235047AbjHNIrA (ORCPT ); Mon, 14 Aug 2023 04:47:00 -0400 Received: from mail-40134.protonmail.ch (mail-40134.protonmail.ch [185.70.40.134]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 76F3210C for ; Mon, 14 Aug 2023 01:46:57 -0700 (PDT) Date: Mon, 14 Aug 2023 08:46:48 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=f4tuk7d6b5g5pm4hzkdqaeyym4.protonmail; t=1692002815; x=1692262015; bh=r0rCJDgexbLd/PbKtXjKQNdC/yi+joahEDdPpIvT9F4=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=GuGi73VPFHhqfKtnd2Cfr3GJXEI+uRjuLLuP+OCvBYdtmAKFphi6mgeHtuUzb0/AK 7l4crUPRsVWA07vpIUIvoRVtKOq1A8WSSB2xFCTM8TOZ0JXNuNNn2p5MmUZbaszlBk dGXhyLmYiCbFVMcXUEBDypGnu71XiZpW1igYvTI0hT+8N+DfBcscR+IrHM/hpLTiwZ TRGJjLWvaFcVZdSSjmoi9GzBXzQpCvM39LTUBnZMvq7/BYnvlNee63baGNUoFBD0N5 gGFNrW1SWNeBii3vqNRloCa1RSWqRUz/9QZMXppzmd3uoJnERAa91dEuOsY/TWeFog dD8PYFWqjSoBg== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, patches@lists.linux.dev, Asahi Lina , Martin Rodriguez Reboredo Subject: [PATCH v4 04/13] rust: init: make guards in the init macros hygienic Message-ID: <20230814084602.25699-5-benno.lossin@proton.me> In-Reply-To: <20230814084602.25699-1-benno.lossin@proton.me> References: <20230814084602.25699-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, RCVD_IN_MSPIKE_H5,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS autolearn=unavailable autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1774196254908341589 X-GMAIL-MSGID: 1774196254908341589 Use hygienic identifiers for the guards instead of the field names. This makes the init macros feel more like normal struct initializers, since assigning identifiers with the name of a field does not create conflicts. Also change the internals of the guards, no need to make the `forget` function `unsafe`, since users cannot access the guards anyways. Now the guards are carried directly on the stack and have no extra `Cell` field that marks if they have been forgotten or not, instead they are just forgotten via `mem::forget`. Suggested-by: Asahi Lina Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Alice Ryhl Reviewed-by: Gary Guo Signed-off-by: Benno Lossin --- v3 -> v4: - added Reviewed-by from Gary. v2 -> v3: - added Reviewed-by's from Martin and Alice. v1 -> v2: - use Gary's `paste!` macro to create the guard hygiene. rust/kernel/init.rs | 1 - rust/kernel/init/__internal.rs | 25 ++----- rust/kernel/init/macros.rs | 116 +++++++++++++++------------------ 3 files changed, 56 insertions(+), 86 deletions(-) diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index d431d0b153a2..0120674b451e 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -216,7 +216,6 @@ use alloc::boxed::Box; use core::{ alloc::AllocError, - cell::Cell, convert::Infallible, marker::PhantomData, mem::MaybeUninit, diff --git a/rust/kernel/init/__internal.rs b/rust/kernel/init/__internal.rs index 44751fb62b51..7abd1fb65e41 100644 --- a/rust/kernel/init/__internal.rs +++ b/rust/kernel/init/__internal.rs @@ -174,7 +174,6 @@ pub fn init(self: Pin<&mut Self>, init: impl PinInit) -> Result { ptr: *mut T, - do_drop: Cell, } impl DropGuard { @@ -190,32 +189,16 @@ impl DropGuard { /// - will not be dropped by any other means. #[inline] pub unsafe fn new(ptr: *mut T) -> Self { - Self { - ptr, - do_drop: Cell::new(true), - } - } - - /// Prevents this guard from dropping the supplied pointer. - /// - /// # Safety - /// - /// This function is unsafe in order to prevent safe code from forgetting this guard. It should - /// only be called by the macros in this module. - #[inline] - pub unsafe fn forget(&self) { - self.do_drop.set(false); + Self { ptr } } } impl Drop for DropGuard { #[inline] fn drop(&mut self) { - if self.do_drop.get() { - // SAFETY: A `DropGuard` can only be constructed using the unsafe `new` function - // ensuring that this operation is safe. - unsafe { ptr::drop_in_place(self.ptr) } - } + // SAFETY: A `DropGuard` can only be constructed using the unsafe `new` function + // ensuring that this operation is safe. + unsafe { ptr::drop_in_place(self.ptr) } } } diff --git a/rust/kernel/init/macros.rs b/rust/kernel/init/macros.rs index 78091756dec0..454f31b8c614 100644 --- a/rust/kernel/init/macros.rs +++ b/rust/kernel/init/macros.rs @@ -994,7 +994,6 @@ impl<$($impl_generics)*> $pin_data<$($ty_generics)*> /// - `init_slot`: recursively creates the code that initializes all fields in `slot`. /// - `make_initializer`: recursively create the struct initializer that guarantees that every /// field has been initialized exactly once. -/// - `forget_guards`: recursively forget the drop guards for every field. #[doc(hidden)] #[macro_export] macro_rules! __init_internal { @@ -1034,6 +1033,7 @@ macro_rules! __init_internal { $crate::__init_internal!(init_slot($($use_data)?): @data(data), @slot(slot), + @guards(), @munch_fields($($fields)*,), ); // We use unreachable code to ensure that all fields have been mentioned exactly @@ -1048,10 +1048,6 @@ macro_rules! __init_internal { @acc(), ); } - // Forget all guards, since initialization was a success. - $crate::__init_internal!(forget_guards: - @munch_fields($($fields)*,), - ); } Ok(__InitOk) } @@ -1065,13 +1061,17 @@ macro_rules! __init_internal { (init_slot($($use_data:ident)?): @data($data:ident), @slot($slot:ident), + @guards($($guards:ident,)*), @munch_fields($(,)?), ) => { - // Endpoint of munching, no fields are left. + // Endpoint of munching, no fields are left. If execution reaches this point, all fields + // have been initialized. Therefore we can now dismiss the guards by forgetting them. + $(::core::mem::forget($guards);)* }; (init_slot($use_data:ident): // use_data is present, so we use the `data` to init fields. @data($data:ident), @slot($slot:ident), + @guards($($guards:ident,)*), // In-place initialization syntax. @munch_fields($field:ident <- $val:expr, $($rest:tt)*), ) => { @@ -1082,24 +1082,28 @@ macro_rules! __init_internal { // 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), $field)? }; - // Create the drop guard. - // - // We only give access to `&DropGuard`, so it cannot be forgotten via safe code. + // Create the drop guard: // - // SAFETY: We forget the guard later when initialization has succeeded. - let $field = &unsafe { - $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field)) - }; + // 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. + ::kernel::macros::paste! { + // SAFETY: We forget the guard later when initialization has succeeded. + let [<$field>] = unsafe { + $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field)) + }; - $crate::__init_internal!(init_slot($use_data): - @data($data), - @slot($slot), - @munch_fields($($rest)*), - ); + $crate::__init_internal!(init_slot($use_data): + @data($data), + @slot($slot), + @guards([<$field>], $($guards,)*), + @munch_fields($($rest)*), + ); + } }; (init_slot(): // no use_data, so we use `Init::__init` directly. @data($data:ident), @slot($slot:ident), + @guards($($guards:ident,)*), // In-place initialization syntax. @munch_fields($field:ident <- $val:expr, $($rest:tt)*), ) => { @@ -1109,24 +1113,28 @@ macro_rules! __init_internal { // SAFETY: `slot` is valid, because we are inside of an initializer closure, we // return when an error/panic occurs. unsafe { $crate::init::Init::__init($field, ::core::ptr::addr_of_mut!((*$slot).$field))? }; - // Create the drop guard. - // - // We only give access to `&DropGuard`, so it cannot be forgotten via safe code. + // Create the drop guard: // - // SAFETY: We forget the guard later when initialization has succeeded. - let $field = &unsafe { - $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field)) - }; + // 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. + ::kernel::macros::paste! { + // SAFETY: We forget the guard later when initialization has succeeded. + let [<$field>] = unsafe { + $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field)) + }; - $crate::__init_internal!(init_slot(): - @data($data), - @slot($slot), - @munch_fields($($rest)*), - ); + $crate::__init_internal!(init_slot(): + @data($data), + @slot($slot), + @guards([<$field>], $($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)*), ) => { @@ -1137,18 +1145,21 @@ macro_rules! __init_internal { unsafe { ::core::ptr::write(::core::ptr::addr_of_mut!((*$slot).$field), $field) }; // Create the drop guard: // - // We only give access to `&DropGuard`, so it cannot be accidentally forgotten. - // - // SAFETY: We forget the guard later when initialization has succeeded. - let $field = &unsafe { - $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field)) - }; + // 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. + ::kernel::macros::paste! { + // SAFETY: We forget the guard later when initialization has succeeded. + let [<$field>] = unsafe { + $crate::init::__internal::DropGuard::new(::core::ptr::addr_of_mut!((*$slot).$field)) + }; - $crate::__init_internal!(init_slot($($use_data)?): - @data($data), - @slot($slot), - @munch_fields($($rest)*), - ); + $crate::__init_internal!(init_slot($($use_data)?): + @data($data), + @slot($slot), + @guards([<$field>], $($guards,)*), + @munch_fields($($rest)*), + ); + } }; (make_initializer: @slot($slot:ident), @@ -1191,29 +1202,6 @@ macro_rules! __init_internal { @acc($($acc)* $field: ::core::panic!(),), ); }; - (forget_guards: - @munch_fields($(,)?), - ) => { - // Munching finished. - }; - (forget_guards: - @munch_fields($field:ident <- $val:expr, $($rest:tt)*), - ) => { - unsafe { $crate::init::__internal::DropGuard::forget($field) }; - - $crate::__init_internal!(forget_guards: - @munch_fields($($rest)*), - ); - }; - (forget_guards: - @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), - ) => { - unsafe { $crate::init::__internal::DropGuard::forget($field) }; - - $crate::__init_internal!(forget_guards: - @munch_fields($($rest)*), - ); - }; } #[doc(hidden)] From patchwork Mon Aug 14 08:46:55 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 135324 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b824:0:b0:3f2:4152:657d with SMTP id z4csp2651496vqi; Mon, 14 Aug 2023 03:37:56 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGVrJ9W2XCuhJsSFplHP5MExGZ6ypxzsLeYHTSo41JvPABy7tmE0KN7YEfB/CwmpoGcehvM X-Received: by 2002:aca:100b:0:b0:3a7:8e6:c946 with SMTP id 11-20020aca100b000000b003a708e6c946mr8825669oiq.41.1692009476469; Mon, 14 Aug 2023 03:37:56 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1692009476; cv=none; d=google.com; s=arc-20160816; b=ByC8gEqJ1v7U8uTBb3RsaCp9SLMATZewuu3FuYhIu7xJLlNiVWHiuehaPWOfNJkd5c NCt9tiPzUINTqhFitgYmGCGNA8hGfgBB6/Y/TJWWKUPuxh8oMoYDVVdFCHDNcPz10ZNr 6RdbesfmMirjvTN5RnW1kle8AL37yPQPeJ3+yy1pLNVgpeIOpMgQ9lmhfBKlXDeTeEEN AJ5bSfM5YyqvwtHxd6LQAQYG+rpOwFGSib30GEHa0bXPqpcRaoXJGO4MQUva/Y32Qfe9 qnFnNVkeieQF10T+8mzQ3gpr8vOVQBRfFK0rPe49VCIPSrPQnUm+08Mto11/N9itb0DZ jeZQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=+y/4hwjE9xTPBuUzHSo6g+e55bg8L+V4bqZtkGtraCM=; fh=TE4onW3Du2FQ1EsedDK8TzgRHOYndfJXYpOtlseWrM0=; b=Knbsy/rr7tHDprIWFv99mOmXyPFhMn6e33CnDFsdZ1lcDKNW3TwUHgtxZVOQ6j6vpA FRr/H0SNDOgq/lyo3MBTbmNg6/33dceD6SMv7buUp9znYtTZHgCSN6V5TB3837LIcp8w beLyQAl6Xq+Pwe2+7f8mPxwR5dhpFZ6por1L4eQ6JxG7lQJH0h3ilvjd5tfrkxYX4aAq j+ZtYRn0u96I1NPHI3CVLLzL3FTI86xHuJd8ap//YPkvv6pCtB1gkmC0isaX5brj5HjB NUuYCJEg7OPbCscRgfN4LUD45xEWWF3KF2BWYx+2HjEEzzEDD2LIhj/ICTeNipJCBlyu zhPg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=6tf7jz7u4rgs3bvq3n5hlsdnem.protonmail header.b=VBx8s9iE; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id 132-20020a63028a000000b0055798b90375si8208444pgc.709.2023.08.14.03.37.41; Mon, 14 Aug 2023 03:37:56 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=6tf7jz7u4rgs3bvq3n5hlsdnem.protonmail header.b=VBx8s9iE; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235049AbjHNIrZ (ORCPT + 99 others); Mon, 14 Aug 2023 04:47:25 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:38722 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235064AbjHNIrG (ORCPT ); Mon, 14 Aug 2023 04:47:06 -0400 Received: from mail-4316.protonmail.ch (mail-4316.protonmail.ch [185.70.43.16]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D702010C for ; Mon, 14 Aug 2023 01:47:05 -0700 (PDT) Date: Mon, 14 Aug 2023 08:46:55 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=6tf7jz7u4rgs3bvq3n5hlsdnem.protonmail; t=1692002824; x=1692262024; bh=+y/4hwjE9xTPBuUzHSo6g+e55bg8L+V4bqZtkGtraCM=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=VBx8s9iEtWxkKgrYspZcruM+PDspV9IubBxy3NR9+IXX26WLTxFQ2GyudmdxCRqP6 gQjLu1hc6mE244ph3QYqkgfBY+rC00A1VjSkfQ0gSOF0a1q5FtrRl1FRDsVYVb2QRI 79cryyyphfK4zDylndAV50fVdxY6XjACv9AU3B5puoVz7kMyZBITZOBIUuocYrR6px CLJ3JO6HMpcGxlmmV09Uo0+vB5uRk1AIqz1WTS/6eGPiKCwZEmq+hMBf24CKTznQ/I gpcTdxefkHMfli3MCLsN9b8QkFtF9Ng+B1WRAFnWD+SBQbsqxGqUMD3orQbHwAFSJq W60adFkHjvzow== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, patches@lists.linux.dev, Martin Rodriguez Reboredo Subject: [PATCH v4 05/13] rust: init: wrap type checking struct initializers in a closure Message-ID: <20230814084602.25699-6-benno.lossin@proton.me> In-Reply-To: <20230814084602.25699-1-benno.lossin@proton.me> References: <20230814084602.25699-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1774200528570582712 X-GMAIL-MSGID: 1774200528570582712 In the implementation of the init macros there is a `if false` statement that type checks the initializer to ensure every field is initialized. Since the next patch has a stack variable to store the struct, the function might allocate too much memory on debug builds. Putting the struct into a closure that is never executed ensures that even in debug builds no stack overflow error is caused. In release builds this was not a problem since the code was optimized away due to the `if false`. Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Alice Ryhl Reviewed-by: Gary Guo Signed-off-by: Benno Lossin --- v3 -> v4: - added Reviewed-by from Gary. v2 -> v3: - added Reviewed-by's from Martin and Alice. v1 -> v2: - do not call the created closure. rust/kernel/init/macros.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/kernel/init/macros.rs b/rust/kernel/init/macros.rs index 454f31b8c614..2bad086cda0a 100644 --- a/rust/kernel/init/macros.rs +++ b/rust/kernel/init/macros.rs @@ -1040,14 +1040,14 @@ macro_rules! __init_internal { // once, this struct initializer will still be type-checked and complain with a // very natural error message if a field is forgotten/mentioned more than once. #[allow(unreachable_code, clippy::diverging_sub_expression)] - if false { + let _ = || { $crate::__init_internal!(make_initializer: @slot(slot), @type_name($t), @munch_fields($($fields)*,), @acc(), ); - } + }; } Ok(__InitOk) } @@ -1168,8 +1168,8 @@ macro_rules! __init_internal { @acc($($acc:tt)*), ) => { // Endpoint, nothing more to munch, create the initializer. - // Since we are in the `if false` branch, this will never get executed. We abuse `slot` to - // get the correct type inference here: + // Since we are in the closure that is never called, this will never get executed. + // We abuse `slot` to get the correct type inference here: unsafe { ::core::ptr::write($slot, $t { $($acc)* From patchwork Mon Aug 14 08:47:03 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 135270 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b824:0:b0:3f2:4152:657d with SMTP id z4csp2626265vqi; Mon, 14 Aug 2023 02:37:27 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFwYeNWw57YYumFdLLQF2z+MPYMh/edN3ttadPyPAnfhhgVaX5lcEo3lWd4KoyPtoQafpcv X-Received: by 2002:a05:6a20:96c6:b0:132:d029:ed3d with SMTP id hq6-20020a056a2096c600b00132d029ed3dmr7064307pzc.29.1692005847257; Mon, 14 Aug 2023 02:37:27 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1692005847; cv=none; d=google.com; s=arc-20160816; b=HCm3vV/0QVKOSbSao7jR93cBuoUXBcUYfJYKUXHmkNuMWN0quCTz28ZznadLGqKF53 WA6Y3hsuWkBESHUC1gV9+F4GNthQqTUgo8gjBJ6QjSd8sBjqXrI4AvCtS7SOZqLxN02r Shw3XCvXlnVYdc681yBFCHMkW4edupOFqeYL7Kq56kyQmH9ZVzyaNawEd3U3VVApVs/g TykvB2vPPl01VSd82vcNzQaqtDH3UqYIsGAw7J6C+n8kcWuDwTPMoIswnHQpNfzN0uBx 1+MF9y/1dWVyzKORi6KBMKn+BPrtKackTPCh7Mz5spPFUmWcZw03OUT1LA+YLCjKdg0g capg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=BM+ndpgoaIa28MW959xE4f6HCZcpfHae5spTLfBk2Ho=; fh=TE4onW3Du2FQ1EsedDK8TzgRHOYndfJXYpOtlseWrM0=; b=KcpFWdz8KUY6RjnzU+0U0GKKX7sCJS5MpDkIxV3qXpaqVrLtTwrhrXBKHlDCFUvoNR HeFEV3Bo1vxuWzXxYCzRsq8BAKYEcjMmwEZtAdvKgtLpmsKH8u6MFrAzbg5KF5eS9sBE zXMDlktiLTigWuqgDaxV+///RcihS/ijS8/l4Tn0ZNKSkptOIVyGr7snKtMkfnSQCuZj 7nPaZFu5Orycfeu+rfAeC1jThYBUrdLQ5po9bH5+jh+Y5EtS+V+YKjFgrSpRXv5Y+7Lk Kngv9YA6nrPfGn+nnePpmoJdGI0KMhdrt2BHd3CPZugVYzP5f4q0Foo/JK3oRjFoEe/P lDzA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=pxdyxhsc5zgjrepj7b2v2ltcyq.protonmail header.b=EZ4YpFZj; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id e14-20020a17090301ce00b001b8c6f80ddbsi7943021plh.105.2023.08.14.02.37.14; Mon, 14 Aug 2023 02:37:27 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=pxdyxhsc5zgjrepj7b2v2ltcyq.protonmail header.b=EZ4YpFZj; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234952AbjHNIrs (ORCPT + 99 others); Mon, 14 Aug 2023 04:47:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55658 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235065AbjHNIr1 (ORCPT ); Mon, 14 Aug 2023 04:47:27 -0400 Received: from mail-4322.protonmail.ch (mail-4322.protonmail.ch [185.70.43.22]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 41AA210E5; Mon, 14 Aug 2023 01:47:23 -0700 (PDT) Date: Mon, 14 Aug 2023 08:47:03 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=pxdyxhsc5zgjrepj7b2v2ltcyq.protonmail; t=1692002841; x=1692262041; bh=BM+ndpgoaIa28MW959xE4f6HCZcpfHae5spTLfBk2Ho=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=EZ4YpFZjH4dQ/P5XmIh0QjJWVL2O+OOOGrpHpVy1dZ7Tz4co9qn7Om0WECgCOcAzJ qRO9RgUIu1B+3VSgLzyCHaDSGputiYoY3zXVzTI1REi2yRnI0YbzTi2x7xp8oYq+9T d1Qi3RGgR2nhb0uEoRdrAhSN3FFiENW0UhYSeh9IBQcSXMR6fq+eTSmuP/XBg5U5dg mNKdGKovn5QZcSeEboo8SxC4peZLAdEX/jKOhhN6Rqfz0siuEYwciwGY/+wvnKPxbJ tuAsWeskPSu0sLjC1jYBptDReJAgYWrxOyz8FVhjGnmHGrI0+nA14JREu6HfkczFT3 PtAsPqPX+w+PA== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, patches@lists.linux.dev, Martin Rodriguez Reboredo Subject: [PATCH v4 06/13] rust: init: make initializer values inaccessible after initializing Message-ID: <20230814084602.25699-7-benno.lossin@proton.me> In-Reply-To: <20230814084602.25699-1-benno.lossin@proton.me> References: <20230814084602.25699-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, RCVD_IN_MSPIKE_H5,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1774196723300784587 X-GMAIL-MSGID: 1774196723300784587 Previously the init macros would create a local variable with the name and hygiene of the field that is being initialized to store the value of the field. This would override any user defined variables. For example: ``` struct Foo { a: usize, b: usize, } let a = 10; let foo = init!(Foo{ a: a + 1, // This creates a local variable named `a`. b: a, // This refers to that variable! }); let foo = Box::init!(foo)?; assert_eq!(foo.a, 11); assert_eq!(foo.b, 11); ``` This patch changes this behavior, so the above code would panic at the last assertion, since `b` would have value 10. Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Alice Ryhl Reviewed-by: Gary Guo Signed-off-by: Benno Lossin --- v3 -> v4: - added Reviewed-by from Gary. v2 -> v3: - added Reviewed-by's from Martin and Alice. rust/kernel/init/macros.rs | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/rust/kernel/init/macros.rs b/rust/kernel/init/macros.rs index 2bad086cda0a..cfeacc4b3f7d 100644 --- a/rust/kernel/init/macros.rs +++ b/rust/kernel/init/macros.rs @@ -1075,13 +1075,13 @@ macro_rules! __init_internal { // In-place initialization syntax. @munch_fields($field:ident <- $val:expr, $($rest:tt)*), ) => { - let $field = $val; + let init = $val; // Call the initializer. // // SAFETY: `slot` is valid, because we are inside of an initializer closure, we // 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), $field)? }; + unsafe { $data.$field(::core::ptr::addr_of_mut!((*$slot).$field), init)? }; // Create the drop guard: // // We rely on macro hygiene to make it impossible for users to access this local variable. @@ -1107,12 +1107,12 @@ macro_rules! __init_internal { // In-place initialization syntax. @munch_fields($field:ident <- $val:expr, $($rest:tt)*), ) => { - let $field = $val; + let init = $val; // Call the initializer. // // SAFETY: `slot` is valid, because we are inside of an initializer closure, we // return when an error/panic occurs. - unsafe { $crate::init::Init::__init($field, ::core::ptr::addr_of_mut!((*$slot).$field))? }; + unsafe { $crate::init::Init::__init(init, ::core::ptr::addr_of_mut!((*$slot).$field))? }; // Create the drop guard: // // We rely on macro hygiene to make it impossible for users to access this local variable. @@ -1138,11 +1138,13 @@ macro_rules! __init_internal { // 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) }; + { + $(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) }; + } // Create the drop guard: // // We rely on macro hygiene to make it impossible for users to access this local variable. From patchwork Mon Aug 14 08:47:10 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 135250 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b824:0:b0:3f2:4152:657d with SMTP id z4csp2622605vqi; Mon, 14 Aug 2023 02:28:16 -0700 (PDT) X-Google-Smtp-Source: AGHT+IHEZRvKdPN1XI+LCHVruooO17yOByNOWdD2PcVp/hM6G3M4rzm6akcjln1EqttrPmVSIuC0 X-Received: by 2002:a17:906:257:b0:991:b292:699 with SMTP id 23-20020a170906025700b00991b2920699mr6462536ejl.5.1692005296159; Mon, 14 Aug 2023 02:28:16 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1692005296; cv=none; d=google.com; s=arc-20160816; b=YckL/6Bn9B/krzVpxJLGeZ8KeCf1uVcezSAxJ5V7S+/K/M0KdiXjFin2QCTGkeHplP eQ43/GLIxDDv1LT+dToneTheIyx/UQGroxmnlvWbDj0jRIXGi0dLheIqhOpDCmgBRKmJ npFuEf+JVBL+twN1DY8LP+5gns0gZcKGfeJV8lBq6mIexAHzlXGivoeQZ6JscVSNAVP3 Kgga6kCDcvx1GaxUbmktI0Ye31GUYhHnOGyZ3M0Ls1viv5EnglnI2DCwXyDXPHLUNJRz wK00xgHefCIpJlnnOTBL1aXjtAxDSfD52H+xJk/z9wLejCRtb9XjjReM86Bvr3YLAimJ olFw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=DOUsrR9hesPZ+QVUGZPbd/KrHB27w86EX9+a/GhU1bE=; fh=h3KS08NeBaYH5bCiXUF1yMk4NKDs2FHNIfHsq8atlgQ=; b=z0E03T883Ya9w9G/yp9K93bKQqXFePWT+sKMQ0+xli92lNugP1mO3clMkzLDUeoRb4 BjsV5cv1opQC+twibubIalAS8BVUlecNug/jk8HgeJAsTaXIdRimu5rOs0ivBRnUF25T bwPMgXi9yPGXPoJVwY2o1n6GGv0o67Oghi/6iWMsNMXghCfiJohHaKVT5H/qxsxfgYtb fv3VPBK21NdZyanJWT/Mu7XUS+a1ToNxuvXOzY1zAjpcH7NHKRDaHRDAXfyojnAkhj1M d5FyxwxqFCchezmJeMBGw5k9VPCHOyR+9u4rvY3+sr6cgWuItypvKc6WkZBRR44rwHQV f9NQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=IUB74zJW; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id pg22-20020a170907205600b00997c25decfcsi7799328ejb.187.2023.08.14.02.27.52; Mon, 14 Aug 2023 02:28:16 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=IUB74zJW; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234173AbjHNIrp (ORCPT + 99 others); Mon, 14 Aug 2023 04:47:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55622 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235003AbjHNIrV (ORCPT ); Mon, 14 Aug 2023 04:47:21 -0400 Received: from mail-4316.protonmail.ch (mail-4316.protonmail.ch [185.70.43.16]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 2B2E01700; Mon, 14 Aug 2023 01:47:18 -0700 (PDT) Date: Mon, 14 Aug 2023 08:47:10 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1692002836; x=1692262036; bh=DOUsrR9hesPZ+QVUGZPbd/KrHB27w86EX9+a/GhU1bE=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=IUB74zJW3K7iw8YYsQQQIm3nIjvaw1/4UxWkBsHubVAnsKfdJMnWyyfBndiODsXse V6MHojc/w9ryltKzL0YkUdos0DS+oY3qWUeNnSIZVJyf/9649VBfcnT6A22MHXsCMe aL5KOVq9vEpYXLb9aUuslyANmoE1L4qUDdmZMxNQCPX2hEmyo1GvxizvdLoiDQVGyW f7w0CraQ+eqTTAY1miygsq3uEk7NB2KssTfyucgPcNfIohqeBLApyLNx5Qxhk2G6J2 VmpSYup1MhZBoKox/vH3cyv8eFLod2cRfO9hjx3kdy7wAkw8scC8gyBM6W4ZB/2Eks JA0Zu8ktGklLA== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, patches@lists.linux.dev, Asahi Lina , Martin Rodriguez Reboredo Subject: [PATCH v4 07/13] rust: init: add `..Zeroable::zeroed()` syntax for zeroing all missing fields Message-ID: <20230814084602.25699-8-benno.lossin@proton.me> In-Reply-To: <20230814084602.25699-1-benno.lossin@proton.me> References: <20230814084602.25699-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1774196145616263243 X-GMAIL-MSGID: 1774196145616263243 Add the struct update syntax to the init macros, but only for `..Zeroable::zeroed()`. Adding this at the end of the struct initializer allows one to omit fields from the initializer, these fields will be initialized with 0x00 set to every byte. Only types that implement the `Zeroable` trait can utilize this. Suggested-by: Asahi Lina Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Alice Ryhl Reviewed-by: Gary Guo Signed-off-by: Benno Lossin --- v3 -> v4: - added Reviewed-by from Gary. v2 -> v3: - changed `if false` argument to use `never executed closure`, - added Reviewed-by's from Martin and Alice. v1 -> v2: - fix doctest imports, - fix doctest examples, - fix `Zeroable` path in the `__init_internal` macro, - rename `is_zeroable` -> `assert_zeroable`, - add missing `{}` to the case when `..Zeroable::zeroed()` is present, - add `allow(unused_assignments)` in the type-checked struct initializer. rust/kernel/init.rs | 16 +++++- rust/kernel/init/macros.rs | 115 ++++++++++++++++++++++++++++++++++++- 2 files changed, 129 insertions(+), 2 deletions(-) diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index 0120674b451e..460f808ebf84 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -517,13 +517,17 @@ macro_rules! stack_try_pin_init { /// - Fields that you want to initialize in-place have to use `<-` instead of `:`. /// - In front of the initializer you can write `&this in` to have access to a [`NonNull`] /// pointer named `this` inside of the initializer. +/// - Using struct update syntax one can place `..Zeroable::zeroed()` at the very end of the +/// struct, this initializes every field with 0 and then runs all initializers specified in the +/// body. This can only be done if [`Zeroable`] is implemented for the struct. /// /// For instance: /// /// ```rust -/// # use kernel::{macros::pin_data, pin_init}; +/// # use kernel::{macros::{Zeroable, pin_data}, pin_init}; /// # use core::{ptr::addr_of_mut, marker::PhantomPinned}; /// #[pin_data] +/// #[derive(Zeroable)] /// struct Buf { /// // `ptr` points into `buf`. /// ptr: *mut u8, @@ -536,6 +540,10 @@ macro_rules! stack_try_pin_init { /// ptr: unsafe { addr_of_mut!((*this.as_ptr()).buf).cast() }, /// pin: PhantomPinned, /// }); +/// pin_init!(Buf { +/// buf: [1; 64], +/// ..Zeroable::zeroed() +/// }); /// ``` /// /// [`try_pin_init!`]: kernel::try_pin_init @@ -555,6 +563,7 @@ macro_rules! pin_init { @data(PinData, use_data), @has_data(HasPinData, __pin_data), @construct_closure(pin_init_from_closure), + @munch_fields($($fields)*), ) }; } @@ -611,6 +620,7 @@ macro_rules! try_pin_init { @data(PinData, use_data), @has_data(HasPinData, __pin_data), @construct_closure(pin_init_from_closure), + @munch_fields($($fields)*), ) }; ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { @@ -624,6 +634,7 @@ macro_rules! try_pin_init { @data(PinData, use_data), @has_data(HasPinData, __pin_data), @construct_closure(pin_init_from_closure), + @munch_fields($($fields)*), ) }; } @@ -658,6 +669,7 @@ macro_rules! init { @data(InitData, /*no use_data*/), @has_data(HasInitData, __init_data), @construct_closure(init_from_closure), + @munch_fields($($fields)*), ) } } @@ -708,6 +720,7 @@ macro_rules! try_init { @data(InitData, /*no use_data*/), @has_data(HasInitData, __init_data), @construct_closure(init_from_closure), + @munch_fields($($fields)*), ) }; ($(&$this:ident in)? $t:ident $(::<$($generics:ty),* $(,)?>)? { @@ -721,6 +734,7 @@ macro_rules! try_init { @data(InitData, /*no use_data*/), @has_data(HasInitData, __init_data), @construct_closure(init_from_closure), + @munch_fields($($fields)*), ) }; } diff --git a/rust/kernel/init/macros.rs b/rust/kernel/init/macros.rs index cfeacc4b3f7d..4c86281301d8 100644 --- a/rust/kernel/init/macros.rs +++ b/rust/kernel/init/macros.rs @@ -991,6 +991,7 @@ impl<$($impl_generics)*> $pin_data<$($ty_generics)*> /// /// This macro has multiple internal call configurations, these are always the very first ident: /// - nothing: this is the base case and called by the `{try_}{pin_}init!` macros. +/// - `with_update_parsed`: when the `..Zeroable::zeroed()` syntax has been handled. /// - `init_slot`: recursively creates the code that initializes all fields in `slot`. /// - `make_initializer`: recursively create the struct initializer that guarantees that every /// field has been initialized exactly once. @@ -1009,6 +1010,82 @@ macro_rules! __init_internal { @has_data($has_data:ident, $get_data:ident), // `pin_init_from_closure` or `init_from_closure`. @construct_closure($construct_closure:ident), + @munch_fields(), + ) => { + $crate::__init_internal!(with_update_parsed: + @this($($this)?), + @typ($t $(::<$($generics),*>)? ), + @fields($($fields)*), + @error($err), + @data($data, $($use_data)?), + @has_data($has_data, $get_data), + @construct_closure($construct_closure), + @zeroed(), // nothing means default behavior. + ) + }; + ( + @this($($this:ident)?), + @typ($t:ident $(::<$($generics:ty),*>)?), + @fields($($fields:tt)*), + @error($err:ty), + // Either `PinData` or `InitData`, `$use_data` should only be present in the `PinData` + // case. + @data($data:ident, $($use_data:ident)?), + // `HasPinData` or `HasInitData`. + @has_data($has_data:ident, $get_data:ident), + // `pin_init_from_closure` or `init_from_closure`. + @construct_closure($construct_closure:ident), + @munch_fields(..Zeroable::zeroed()), + ) => { + $crate::__init_internal!(with_update_parsed: + @this($($this)?), + @typ($t $(::<$($generics),*>)? ), + @fields($($fields)*), + @error($err), + @data($data, $($use_data)?), + @has_data($has_data, $get_data), + @construct_closure($construct_closure), + @zeroed(()), // `()` means zero all fields not mentioned. + ) + }; + ( + @this($($this:ident)?), + @typ($t:ident $(::<$($generics:ty),*>)?), + @fields($($fields:tt)*), + @error($err:ty), + // Either `PinData` or `InitData`, `$use_data` should only be present in the `PinData` + // case. + @data($data:ident, $($use_data:ident)?), + // `HasPinData` or `HasInitData`. + @has_data($has_data:ident, $get_data:ident), + // `pin_init_from_closure` or `init_from_closure`. + @construct_closure($construct_closure:ident), + @munch_fields($ignore:tt $($rest:tt)*), + ) => { + $crate::__init_internal!( + @this($($this)?), + @typ($t $(::<$($generics),*>)? ), + @fields($($fields)*), + @error($err), + @data($data, $($use_data)?), + @has_data($has_data, $get_data), + @construct_closure($construct_closure), + @munch_fields($($rest)*), + ) + }; + (with_update_parsed: + @this($($this:ident)?), + @typ($t:ident $(::<$($generics:ty),*>)?), + @fields($($fields:tt)*), + @error($err:ty), + // Either `PinData` or `InitData`, `$use_data` should only be present in the `PinData` + // case. + @data($data:ident, $($use_data:ident)?), + // `HasPinData` or `HasInitData`. + @has_data($has_data:ident, $get_data:ident), + // `pin_init_from_closure` or `init_from_closure`. + @construct_closure($construct_closure:ident), + @zeroed($($init_zeroed:expr)?), ) => {{ // We do not want to allow arbitrary returns, so we declare this type as the `Ok` return // type and shadow it later when we insert the arbitrary user code. That way there will be @@ -1026,6 +1103,17 @@ macro_rules! __init_internal { { // Shadow the structure so it cannot be used to return early. struct __InitOk; + // If `$init_zeroed` is present we should zero the slot now and not emit an + // error when fields are missing (since they will be zeroed). We also have to + // check that the type actually implements `Zeroable`. + $({ + fn assert_zeroable(_: *mut T) {} + // Ensure that the struct is indeed `Zeroable`. + assert_zeroable(slot); + // SAFETY: The type implements `Zeroable` by the check above. + unsafe { ::core::ptr::write_bytes(slot, 0, 1) }; + $init_zeroed // this will be `()` if set. + })? // Create the `this` so it can be referenced by the user inside of the // expressions creating the individual fields. $(let $this = unsafe { ::core::ptr::NonNull::new_unchecked(slot) };)? @@ -1062,7 +1150,7 @@ macro_rules! __init_internal { @data($data:ident), @slot($slot:ident), @guards($($guards:ident,)*), - @munch_fields($(,)?), + @munch_fields($(..Zeroable::zeroed())? $(,)?), ) => { // Endpoint of munching, no fields are left. If execution reaches this point, all fields // have been initialized. Therefore we can now dismiss the guards by forgetting them. @@ -1163,6 +1251,31 @@ macro_rules! __init_internal { ); } }; + (make_initializer: + @slot($slot:ident), + @type_name($t:ident), + @munch_fields(..Zeroable::zeroed() $(,)?), + @acc($($acc:tt)*), + ) => { + // Endpoint, nothing more to munch, create the initializer. Since the users specified + // `..Zeroable::zeroed()`, the slot will already have been zeroed and all field that have + // not been overwritten are thus zero and initialized. We still check that all fields are + // actually accessible by using the struct update syntax ourselves. + // We are inside of a closure that is never executed and thus we can abuse `slot` to + // get the correct type inference here: + #[allow(unused_assignments)] + unsafe { + let mut zeroed = ::core::mem::zeroed(); + // We have to use type inference here to make zeroed have the correct type. This does + // not get executed, so it has no effect. + ::core::ptr::write($slot, zeroed); + zeroed = ::core::mem::zeroed(); + ::core::ptr::write($slot, $t { + $($acc)* + ..zeroed + }); + } + }; (make_initializer: @slot($slot:ident), @type_name($t:ident), From patchwork Mon Aug 14 08:47:15 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 135320 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b824:0:b0:3f2:4152:657d with SMTP id z4csp2647051vqi; Mon, 14 Aug 2023 03:28:00 -0700 (PDT) X-Google-Smtp-Source: AGHT+IH1tpzcZgT1pY04sDhrjPmykcrkaXtu8RjErU/7f/Vx95l7367cP7grK51/PNXOIa/vWff6 X-Received: by 2002:a05:6a20:8e1f:b0:142:8731:bed1 with SMTP id y31-20020a056a208e1f00b001428731bed1mr9952819pzj.41.1692008879952; Mon, 14 Aug 2023 03:27:59 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1692008879; cv=none; d=google.com; s=arc-20160816; b=hxIAKc9RTWiyp5QLY0bPrznWUJ/PyDng7cJbFZ1kBxPmaUFSx4my6p3FMUuMtmKfg+ lcR3jnXHM20QhOMc8rSF71iKY9uCy1O6rs51KFEFeJys/ynMtg+9GhALDiLdYoMhplut KGHe4AV/Ymh86q7hSksBkAVClXPIcYs29EERXsPA2j5qgLahksJV7WaNJ02yKwBeSuZH r1YIjO658K/vW55TDSZ1VnDP0wncWRwb3fp3uboND41JaPnKbQxr6DUyPQipz2c7BZyw IHpmaVStwpAoGsZ1RoDSZCyRp/mt2j/YDPcUmKLwj6HMC6s47YlN3NJGmpDgTrDmH8/e eAhA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=FtpwglMZkGsk6Cq7uG4CBizP3n1NDqFHuFg1fsdOfrA=; fh=h3KS08NeBaYH5bCiXUF1yMk4NKDs2FHNIfHsq8atlgQ=; b=eb1cX9GLGwFbI3AEebE+VcS6sOck076ll5lzeSizcc2I01tDe/5XEN4sfSzrz7MKj6 IXhgi+Q4RNS7VcceOC7KRIHZbdwDpf6neTtpbWkM/61gqdsB/F9HGOWsL6HO1XTEGjJi 11LB+8G5DorjIM7qtDebgP+MHtclSaam1hGhVHRpA3G80PBdRLJt6FgetXxnWCGdx6uH F1OBLIT1of0vZqCY04Ia+MlQA0fSv2HPZHLzEtXi6nH6C6hs4w0wzib5eelDswBs2nse it28XVdoJmqQmwE+vH0TXL60IFCzscHbkiNbDv4lcLE3rUASUMnJsAnmi+juo+1RWhsT dd2g== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=c3ehzphaojh3tmfhfoidalwfii.protonmail header.b=Xa+gIRKh; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id ch11-20020a056a00288b00b006872db70705si7995143pfb.375.2023.08.14.03.27.46; Mon, 14 Aug 2023 03:27:59 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=c3ehzphaojh3tmfhfoidalwfii.protonmail header.b=Xa+gIRKh; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231730AbjHNIrx (ORCPT + 99 others); Mon, 14 Aug 2023 04:47:53 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:55684 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235105AbjHNIrc (ORCPT ); Mon, 14 Aug 2023 04:47:32 -0400 Received: from mail-4316.protonmail.ch (mail-4316.protonmail.ch [185.70.43.16]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1FEAD1BD for ; Mon, 14 Aug 2023 01:47:26 -0700 (PDT) Date: Mon, 14 Aug 2023 08:47:15 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=c3ehzphaojh3tmfhfoidalwfii.protonmail; t=1692002844; x=1692262044; bh=FtpwglMZkGsk6Cq7uG4CBizP3n1NDqFHuFg1fsdOfrA=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=Xa+gIRKh6q1Oa69K6I+pgABGtdkERf9oJ46KJRMnqaWH019BrDoZVQBvsJC1XsvlY cL/6BtfO3agfXPu+r9+v5wI+z6vETwK2ju/+PstvuGMGXpI/eiMdHIdSrOj/mFto+I sTzCCOyfyurQh3tniudsoZmGTyvpp32kHxZ7/Xf8ocuovOZw4cYkzkUoXP4PEs9sgd nq1uWTOjzcCxxLr4x5+LBDT7BwJfTVRwJfDFoXHHJ3jpof1FfWgQuk2j3Zw7Fis8Am qD1AYbBUR/QOJtqHCST/Qjydszw18rkHua7oYoKE7RM1tNaYTG/6qFV9v5eEo4RygI WtBV8gm9Ywzjw== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, patches@lists.linux.dev, Asahi Lina , Martin Rodriguez Reboredo Subject: [PATCH v4 08/13] rust: init: Add functions to create array initializers Message-ID: <20230814084602.25699-9-benno.lossin@proton.me> In-Reply-To: <20230814084602.25699-1-benno.lossin@proton.me> References: <20230814084602.25699-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1774199903446353902 X-GMAIL-MSGID: 1774199903446353902 Add two functions `pin_init_array_from_fn` and `init_array_from_fn` that take a function that generates initializers for `T` from usize, the added functions then return an initializer for `[T; N]` where every element is initialized by an element returned from the generator function. Suggested-by: Asahi Lina Reviewed-by: Björn Roy Baron Reviewed-by: Alice Ryhl Reviewed-by: Martin Rodriguez Reboredo Signed-off-by: Benno Lossin --- v3 -> v4: - changed example size from 1_000_000_000 to 1_000, - made functions unwind-safe by using a ScopeGuard, - added Reviewed-by from Martin. v2 -> v3: - changed doctest: instead of printing the array, assert the length, - added Reviewed-by's from Alice. v1 -> v2: - fix warnings and errors in doctests, - replace dropping loop with `drop_in_place` and `slice_from_raw_parts_mut` inside of `{pin_}init_array_from_fn` functions. rust/kernel/init.rs | 88 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index 460f808ebf84..b54f32017d00 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -212,6 +212,7 @@ use crate::{ error::{self, Error}, sync::UniqueArc, + types::ScopeGuard, }; use alloc::boxed::Box; use core::{ @@ -875,6 +876,93 @@ pub fn uninit() -> impl Init, E> { unsafe { init_from_closure(|_| Ok(())) } } +/// Initializes an array by initializing each element via the provided initializer. +/// +/// # Examples +/// +/// ```rust +/// use kernel::{error::Error, init::init_array_from_fn}; +/// let array: Box<[usize; 1_000]>= Box::init::(init_array_from_fn(|i| i)).unwrap(); +/// assert_eq!(array.len(), 1_000); +/// ``` +pub fn init_array_from_fn( + mut make_init: impl FnMut(usize) -> I, +) -> impl Init<[T; N], E> +where + I: Init, +{ + let init = move |slot: *mut [T; N]| { + let slot = slot.cast::(); + // Counts the number of initialized elements and when dropped drops that many elements from + // `slot`. + let mut init_count = ScopeGuard::new_with_data(0, |i| { + // We now free every element that has been initialized before: + // SAFETY: The loop initialized exactly the values from 0..i and since we + // return `Err` below, the caller will consider the memory at `slot` as + // uninitialized. + unsafe { ptr::drop_in_place(ptr::slice_from_raw_parts_mut(slot, i)) }; + }); + for i in 0..N { + let init = make_init(i); + // SAFETY: since 0 <= `i` < N, it is still in bounds of `[T; N]`. + let ptr = unsafe { slot.add(i) }; + // SAFETY: The pointer is derived from `slot` and thus satisfies the `__init` + // requirements. + unsafe { init.__init(ptr) }?; + *init_count += 1; + } + init_count.dismiss(); + Ok(()) + }; + // SAFETY: The initializer above initializes every element of the array. On failure it drops + // any initialized elements and returns `Err`. + unsafe { init_from_closure(init) } +} + +/// Initializes an array by initializing each element via the provided initializer. +/// +/// # Examples +/// +/// ```rust +/// use kernel::{sync::{Arc, Mutex}, init::pin_init_array_from_fn, new_mutex}; +/// let array: Arc<[Mutex; 1_000]>= +/// Arc::pin_init(pin_init_array_from_fn(|i| new_mutex!(i))).unwrap(); +/// assert_eq!(array.len(), 1_000); +/// ``` +pub fn pin_init_array_from_fn( + mut make_init: impl FnMut(usize) -> I, +) -> impl PinInit<[T; N], E> +where + I: PinInit, +{ + let init = move |slot: *mut [T; N]| { + let slot = slot.cast::(); + // Counts the number of initialized elements and when dropped drops that many elements from + // `slot`. + let mut init_count = ScopeGuard::new_with_data(0, |i| { + // We now free every element that has been initialized before: + // SAFETY: The loop initialized exactly the values from 0..i and since we + // return `Err` below, the caller will consider the memory at `slot` as + // uninitialized. + unsafe { ptr::drop_in_place(ptr::slice_from_raw_parts_mut(slot, i)) }; + }); + for i in 0..N { + let init = make_init(i); + // SAFETY: since 0 <= `i` < N, it is still in bounds of `[T; N]`. + let ptr = unsafe { slot.add(i) }; + // SAFETY: The pointer is derived from `slot` and thus satisfies the `__init` + // requirements. + unsafe { init.__pinned_init(ptr) }?; + *init_count += 1; + } + init_count.dismiss(); + Ok(()) + }; + // SAFETY: The initializer above initializes every element of the array. On failure it drops + // any initialized elements and returns `Err`. + unsafe { pin_init_from_closure(init) } +} + // SAFETY: Every type can be initialized by-value. unsafe impl Init for T { unsafe fn __init(self, slot: *mut T) -> Result<(), E> { From patchwork Mon Aug 14 08:47:28 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 135281 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b824:0:b0:3f2:4152:657d with SMTP id z4csp2627944vqi; Mon, 14 Aug 2023 02:41:37 -0700 (PDT) X-Google-Smtp-Source: AGHT+IFY7+SvkoetXAqrSrHosY0a5ywvhcic7on5iw4h+tY/EaNMRiq5Penouc4ElVkYzQNf/XWm X-Received: by 2002:a05:6512:2349:b0:4f8:64f5:f591 with SMTP id p9-20020a056512234900b004f864f5f591mr6600996lfu.12.1692006097101; Mon, 14 Aug 2023 02:41:37 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1692006097; cv=none; d=google.com; s=arc-20160816; b=CicqW3Wj9b4tDIzzaz8080wI3ZRknLp0/L+ymCX6HNRgep0luY90Nuf/TPIPwffmAP mBIy2XFRrJhyyY5jaS8mGFikV3Zg0XLKwhgZedkcBnFg+4Xf93EkFS1C3fowX0Dxu32h nZvfWvK2JXkBZMMy0xPbxdG7M4B98J0GopP/eC+QBhJKLCeJ6fyKUjaNu5HJCagkea5E O1Pa6xnJUt9JhUkxSwx88d6p3ttB6bhJyktLDU+tFa1qz67hyTxAOB8+5BXGGFyHH1vS v8Hfw2qDZBeA1w4u266i8Beb6t1dH4F59O2h3MZDUceUYALN+Ek322G7gBu/DWaSxKQC Uzlw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=yxj7d+etZ8Z/JcONAl0pO5uOZe+qoxHzlb+NGmYO3PA=; fh=h3KS08NeBaYH5bCiXUF1yMk4NKDs2FHNIfHsq8atlgQ=; b=aVhPBva7SPDGDFJcVzBq0XQiM4mQrCR9nSISHU7vJYtgyn2jKhtAJ2KXj5aKeK4cEo aoMplW0Erq56MAT8qP6GWG2GJZeyAq0Mh/9KuIfCYsT37+aQ0eDUIP/oLE3m28kpJk7B xPpnzLleKksWR7CjplQMGEbTttyN3sdjSmtb7cDaG8Q0UkZ/3G+3zpSrv1PF0vpPezg1 YkBD1o8cxhy4n7IMivmiXBSikNRKOll1OBdT8hkmGZzUJTWmTQ6wyahZrEcQnuOcz/To ys4sL+BImuhlHgI/KrAiP4DgMsAmszqp80c6EkZ+aTgaNgJvBvihF5ZaeVzFeU8CWnK+ wdVw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=InAkLBj8; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id e1-20020aa7d7c1000000b005221fc03d28si7597561eds.233.2023.08.14.02.41.12; Mon, 14 Aug 2023 02:41:37 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=InAkLBj8; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233565AbjHNIsV (ORCPT + 99 others); Mon, 14 Aug 2023 04:48:21 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:54218 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S233319AbjHNIro (ORCPT ); Mon, 14 Aug 2023 04:47:44 -0400 Received: from mail-40133.protonmail.ch (mail-40133.protonmail.ch [185.70.40.133]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 84DA510D for ; Mon, 14 Aug 2023 01:47:43 -0700 (PDT) Date: Mon, 14 Aug 2023 08:47:28 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1692002861; x=1692262061; bh=yxj7d+etZ8Z/JcONAl0pO5uOZe+qoxHzlb+NGmYO3PA=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=InAkLBj8A6dnh7fwLDAjeDxjHKwTOKRay1IRrR8wUqc3zQK5WPrv1rqpD6mmil2Mj 1pn5X7ziU3o530tv+lcuSWDu3zw73oU+yOJMatKRHkT18951HHkAWqRPG3CX71gpRm kwtUMTzuSqW5VW+hxEZnWwRdpuycHzxq3IDh+RcANdtjIsJ8j3ZutHWep1ed3h/hU8 47bMQ+Co7RkynsifoGQy/0FLHxYtST7JZdb0w0z0OKINsPa8rlx6lZdDS5/O/2NfL7 d/LOikf98dgQYkxHH9VxV+uvCfGo3uZe70K1nt+s+2ROA3XOQRzn4GusBohSOIRdip KSwX0+0Jt6k3w== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, patches@lists.linux.dev, Asahi Lina , Martin Rodriguez Reboredo Subject: [PATCH v4 09/13] rust: init: add support for arbitrary paths in init macros Message-ID: <20230814084602.25699-10-benno.lossin@proton.me> In-Reply-To: <20230814084602.25699-1-benno.lossin@proton.me> References: <20230814084602.25699-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, RCVD_IN_MSPIKE_H5,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1774196985106786111 X-GMAIL-MSGID: 1774196985106786111 Previously only `ident` and generic types were supported in the `{try_}{pin_}init!` macros. This patch allows arbitrary path fragments, so for example `Foo::Bar` but also very complex paths such as `::Bar::<0, i32>`. Internally this is accomplished by using `path` fragments. Due to some peculiar declarative macro limitations, we have to "forget" certain additional parsing information in the token trees. This is achieved by using the `paste!` proc macro. It does not actually modify the input, since no `[< >]` will be present in the input, so it just strips the information held by declarative macros. For example, if a declarative macro takes `$t:path` as its input, it cannot sensibly propagate this to a macro that takes `$($p:tt)*` as its input, since the `$t` token will only be considered one `tt` token for the second macro. If we first pipe the tokens through `paste!`, then it parses as expected. Suggested-by: Asahi Lina Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Alice Ryhl Reviewed-by: Gary Guo Signed-off-by: Benno Lossin --- v3 -> v4: - added Reviewed-by from Gary. v2 -> v3: - added Reviewed-by's from Martin and Alice. v1 -> v2: - use Gary's `paste!` macro instead of `retokenize`, - remove the retokenize macro. rust/kernel/init/macros.rs | 54 ++++++++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 19 deletions(-) diff --git a/rust/kernel/init/macros.rs b/rust/kernel/init/macros.rs index 4c86281301d8..d54243cd3c82 100644 --- a/rust/kernel/init/macros.rs +++ b/rust/kernel/init/macros.rs @@ -1000,7 +1000,7 @@ impl<$($impl_generics)*> $pin_data<$($ty_generics)*> macro_rules! __init_internal { ( @this($($this:ident)?), - @typ($t:ident $(::<$($generics:ty),*>)?), + @typ($t:path), @fields($($fields:tt)*), @error($err:ty), // Either `PinData` or `InitData`, `$use_data` should only be present in the `PinData` @@ -1014,7 +1014,7 @@ macro_rules! __init_internal { ) => { $crate::__init_internal!(with_update_parsed: @this($($this)?), - @typ($t $(::<$($generics),*>)? ), + @typ($t), @fields($($fields)*), @error($err), @data($data, $($use_data)?), @@ -1025,7 +1025,7 @@ macro_rules! __init_internal { }; ( @this($($this:ident)?), - @typ($t:ident $(::<$($generics:ty),*>)?), + @typ($t:path), @fields($($fields:tt)*), @error($err:ty), // Either `PinData` or `InitData`, `$use_data` should only be present in the `PinData` @@ -1039,7 +1039,7 @@ macro_rules! __init_internal { ) => { $crate::__init_internal!(with_update_parsed: @this($($this)?), - @typ($t $(::<$($generics),*>)? ), + @typ($t), @fields($($fields)*), @error($err), @data($data, $($use_data)?), @@ -1050,7 +1050,7 @@ macro_rules! __init_internal { }; ( @this($($this:ident)?), - @typ($t:ident $(::<$($generics:ty),*>)?), + @typ($t:path), @fields($($fields:tt)*), @error($err:ty), // Either `PinData` or `InitData`, `$use_data` should only be present in the `PinData` @@ -1064,7 +1064,7 @@ macro_rules! __init_internal { ) => { $crate::__init_internal!( @this($($this)?), - @typ($t $(::<$($generics),*>)? ), + @typ($t), @fields($($fields)*), @error($err), @data($data, $($use_data)?), @@ -1075,7 +1075,7 @@ macro_rules! __init_internal { }; (with_update_parsed: @this($($this:ident)?), - @typ($t:ident $(::<$($generics:ty),*>)?), + @typ($t:path), @fields($($fields:tt)*), @error($err:ty), // Either `PinData` or `InitData`, `$use_data` should only be present in the `PinData` @@ -1094,7 +1094,11 @@ macro_rules! __init_internal { // Get the data about fields from the supplied type. let data = unsafe { use $crate::init::__internal::$has_data; - $t$(::<$($generics),*>)?::$get_data() + // Here we abuse `paste!` to retokenize `$t`. Declarative macros have some internal + // information that is associated to already parsed fragments, so a path fragment + // cannot be used in this position. Doing the retokenization results in valid rust + // code. + ::kernel::macros::paste!($t::$get_data()) }; // Ensure that `data` really is of type `$data` and help with type inference: let init = $crate::init::__internal::$data::make_closure::<_, __InitOk, $err>( @@ -1253,7 +1257,7 @@ fn assert_zeroable(_: *mut T) {} }; (make_initializer: @slot($slot:ident), - @type_name($t:ident), + @type_name($t:path), @munch_fields(..Zeroable::zeroed() $(,)?), @acc($($acc:tt)*), ) => { @@ -1270,15 +1274,21 @@ fn assert_zeroable(_: *mut T) {} // not get executed, so it has no effect. ::core::ptr::write($slot, zeroed); zeroed = ::core::mem::zeroed(); - ::core::ptr::write($slot, $t { - $($acc)* - ..zeroed - }); + // Here we abuse `paste!` to retokenize `$t`. Declarative macros have some internal + // information that is associated to already parsed fragments, so a path fragment + // cannot be used in this position. Doing the retokenization results in valid rust + // code. + ::kernel::macros::paste!( + ::core::ptr::write($slot, $t { + $($acc)* + ..zeroed + }); + ); } }; (make_initializer: @slot($slot:ident), - @type_name($t:ident), + @type_name($t:path), @munch_fields($(,)?), @acc($($acc:tt)*), ) => { @@ -1286,14 +1296,20 @@ fn assert_zeroable(_: *mut T) {} // Since we are in the closure that is never called, this will never get executed. // We abuse `slot` to get the correct type inference here: unsafe { - ::core::ptr::write($slot, $t { - $($acc)* - }); + // Here we abuse `paste!` to retokenize `$t`. Declarative macros have some internal + // information that is associated to already parsed fragments, so a path fragment + // cannot be used in this position. Doing the retokenization results in valid rust + // code. + ::kernel::macros::paste!( + ::core::ptr::write($slot, $t { + $($acc)* + }); + ); } }; (make_initializer: @slot($slot:ident), - @type_name($t:ident), + @type_name($t:path), @munch_fields($field:ident <- $val:expr, $($rest:tt)*), @acc($($acc:tt)*), ) => { @@ -1306,7 +1322,7 @@ fn assert_zeroable(_: *mut T) {} }; (make_initializer: @slot($slot:ident), - @type_name($t:ident), + @type_name($t:path), @munch_fields($field:ident $(: $val:expr)?, $($rest:tt)*), @acc($($acc:tt)*), ) => { From patchwork Mon Aug 14 08:47:32 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 135309 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b824:0:b0:3f2:4152:657d with SMTP id z4csp2642828vqi; Mon, 14 Aug 2023 03:17:47 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEMEzvqvkb9bnqsSFxLKzsHiHBzQCCaK0GvyDyOmVueok2PZg2c8iapG02uSs29rw+c/es+ X-Received: by 2002:a17:90a:94cc:b0:262:f8b8:dba2 with SMTP id j12-20020a17090a94cc00b00262f8b8dba2mr7236409pjw.35.1692008267071; Mon, 14 Aug 2023 03:17:47 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1692008267; cv=none; d=google.com; s=arc-20160816; b=EH3p++7HN4c2Ehb/t8Hnn22LhwfAjAbmNWpt84rbgGtUJsiZoj6OJHDQvZxZA2XiBN Kgcbk1F6FfFRWSC9JMv9OLpQH+nCBntFpeRg/LnXLCh+Gwijo1L5keowSpOrcwNGTCRV qXx878zQFNnKo0DaIfEMv4otgzTdKrOIYY6jxaYjLXzn9ZoKcXSy6y55gzSJnIozKG6T rxSYLHsCJ7EgwoQCH/4mTTm/bmFWraYzpdbrsA7ZGE3TWo1p/OgY5kD/EmnWz9PcBwqk yZ4+3ylXEJCwNFN7/SG5+domimgnm22fEXzPg1hrHLUUnkwVcSMcgDg2W3QnU6hAokD4 aWXw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=RmXK6p609GEJrLnFk9jfesnOhQMMA5F6nnV0NJXuXV4=; fh=TE4onW3Du2FQ1EsedDK8TzgRHOYndfJXYpOtlseWrM0=; b=SiPOK4gH6Qpkr1wAkem4RXem+rpndHnhAJ0BV1Jk/a0x763HFvcDh00gJHdvNFTydl czYcfZmtt39Agk3ZLhkP9darQFc0DvJxdjVOE/2/yQEx0uqmov5duy6kDSqevqebdyn+ nYYU9pGO+hyHb77xG//NOv2jO0T0ZlvkzvLc1EAx9keieY+42uZjWpDtGVy2LXRmwF57 00EBvP5u2f4ts7SFaHcu5/uWMx+oZZDN0TUURSBIIti4GGHP5TRQNEzg3rm3Q1ZCRygt M5UW4wavf9uPaEPUBQ3To9Br+ubBB9Uohx6f5b337HFu7OJ2wneMj0/UTd7rWWzUvKW6 adfw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=BtvXsbft; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id a6-20020a17090ad80600b0026823d86469si7654808pjv.24.2023.08.14.03.17.34; Mon, 14 Aug 2023 03:17:47 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=BtvXsbft; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235094AbjHNIse (ORCPT + 99 others); Mon, 14 Aug 2023 04:48:34 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60416 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235074AbjHNIr5 (ORCPT ); Mon, 14 Aug 2023 04:47:57 -0400 Received: from mail-4316.protonmail.ch (mail-4316.protonmail.ch [185.70.43.16]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D8C9E1737; Mon, 14 Aug 2023 01:47:51 -0700 (PDT) Date: Mon, 14 Aug 2023 08:47:32 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1692002870; x=1692262070; bh=RmXK6p609GEJrLnFk9jfesnOhQMMA5F6nnV0NJXuXV4=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=BtvXsbftFR8N1LTgE1UOZEG9t4qE9EuuVvtX+vYczOwYQTDCI6do7dB9Oe+P+mXvC vO0kWckuR+N7GqoP1Mg1O2VQ4DL2GP6nmCsdCdiprbCXpVa6Ye7ySV0wRp216IV3TK 5vr/VEITqjSoZSiuxuvzygMTNeH5nDNVpkS4dBuuRf15eGe+vpTcNi6iF1HvltYKBw Rdbq5L3pndnFSRvAsvD8gA0FYBfhXin9XUlaV2f8RfixAcdl2OXBrBrjWFRoCpSteq 3eKTzrZ/Nh+Ffvxz30ouhZQUijNWuR9lSNqnyvsKOPx5UF2g7jfF3/0EhabGZXN6E0 UzN7Us8ciVtTw== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, patches@lists.linux.dev, Martin Rodriguez Reboredo Subject: [PATCH v4 10/13] rust: init: implement `Zeroable` for `UnsafeCell` and `Opaque` Message-ID: <20230814084602.25699-11-benno.lossin@proton.me> In-Reply-To: <20230814084602.25699-1-benno.lossin@proton.me> References: <20230814084602.25699-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_MSPIKE_H5, RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1774199260627502364 X-GMAIL-MSGID: 1774199260627502364 `UnsafeCell` and `T` have the same layout so if `T` is `Zeroable` then so should `UnsafeCell` be. This allows using the derive macro for `Zeroable` on types that contain an `UnsafeCell`. Since `Opaque` contains a `MaybeUninit`, all bytes zero is a valid bit pattern for that type. Reviewed-by: Gary Guo Reviewed-by: Martin Rodriguez Reboredo Signed-off-by: Benno Lossin --- v3 -> v4: - added Reviewed-by's from Gary and Martin. v2 -> v3: - also implement Zeroable for `UnsafeCell` when `T: Zeroable`, - use `impl_zeroable!` instead of `derive(Zeroable)`. rust/kernel/init.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index b54f32017d00..f91ecd3b1edf 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -212,11 +212,12 @@ use crate::{ error::{self, Error}, sync::UniqueArc, - types::ScopeGuard, + types::{Opaque, ScopeGuard}, }; use alloc::boxed::Box; use core::{ alloc::AllocError, + cell::UnsafeCell, convert::Infallible, marker::PhantomData, mem::MaybeUninit, @@ -1159,6 +1160,11 @@ macro_rules! impl_zeroable { // SAFETY: Type is allowed to take any value, including all zeros. {} MaybeUninit, + // SAFETY: Type is allowed to take any value, including all zeros. + {} Opaque, + + // SAFETY: `T: Zeroable` and `UnsafeCell` is `repr(transparent)`. + {} UnsafeCell, // SAFETY: All zeros is equivalent to `None` (option layout optimization guarantee). Option, Option, Option, Option, From patchwork Mon Aug 14 08:47:40 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 135271 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b824:0:b0:3f2:4152:657d with SMTP id z4csp2626372vqi; Mon, 14 Aug 2023 02:37:45 -0700 (PDT) X-Google-Smtp-Source: AGHT+IGsUtGNDb/siDKapiEE7Sg87G4IEwOmubauXN8AqFh1d0uo11exR+BYF4q41qCkSbJyWisn X-Received: by 2002:a05:6a21:7890:b0:141:2cb:2954 with SMTP id bf16-20020a056a21789000b0014102cb2954mr12244612pzc.3.1692005865285; Mon, 14 Aug 2023 02:37:45 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1692005865; cv=none; d=google.com; s=arc-20160816; b=ClAfCrgVHqAqGgXos71pbC8DkuTNhWozkxCDmAGUHDIjmvtvtM3+EiMBJJn5Ien1EU aOOm8uheHxJhtcQW14jGoAZsplgIIRdcjkdGrQFNws7JDcvviN3UN5x+29HYWwFpJF9N LhytR+GhRpkDEUS+iLjueyUkOJuVeoC1RjFTzgFqZptZ8wSV4lKZeh3yKuqFsA/QXcqv Dxl329piZJL6t2Kaq4oaDRkjkvlzK2V4UNsucXs2IAr4qEkzHsET8kXz+JW6u1iKeAkq WRhEGnv5JGsN63oYjsO3FvsEtJ3TKNCE8kPf4UImEzf8R+sponqDrHyKhxKP741yP5xL YyxA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=kwnI5+l3SlcIXt3YVOWTO7NQq0uMh4+BFKhqIK/WWV4=; fh=TE4onW3Du2FQ1EsedDK8TzgRHOYndfJXYpOtlseWrM0=; b=Gg+r/tlpQdegJ240eCWXY/j9xaY+uIk2/JCQfEnLwMfPZYDGaIlR4KLPJoWO5fWCBd 4OUnGO9wrq/s5YR4TxznoG+woe0h7Wkco/vMS3RcK5cTwL+lD8cu7NjMmpt6CK1lIGRM iWDsIDTdvCXKl7pb29b/n3g+r/M3vvNzSdrFSWoOEF6teH+mpWbm9fd+SsvXo76CFvyB hxeTrT5/ZFgHS9Fb/gCgB38+GiOvSjzk6IzLZElvfeT/flKVj90g56j7PL/sfv1e+6+E xjM9MuOyXBvb+8ETG/L6wm64FTdNMgUPCFl0t6ZHkenaXAP0QMRyrvUwhmiW460wYxKr Y5LQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=WfvQxVkN; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id s1-20020a63dc01000000b00553ce421356si8108148pgg.56.2023.08.14.02.37.32; Mon, 14 Aug 2023 02:37:45 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=WfvQxVkN; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233319AbjHNIss (ORCPT + 99 others); Mon, 14 Aug 2023 04:48:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:60240 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231862AbjHNIsP (ORCPT ); Mon, 14 Aug 2023 04:48:15 -0400 Received: from mail-4322.protonmail.ch (mail-4322.protonmail.ch [185.70.43.22]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 55A66BB for ; Mon, 14 Aug 2023 01:48:00 -0700 (PDT) Date: Mon, 14 Aug 2023 08:47:40 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1692002878; x=1692262078; bh=kwnI5+l3SlcIXt3YVOWTO7NQq0uMh4+BFKhqIK/WWV4=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=WfvQxVkNyUpKJJPJeXtyGEsl3PEPcbjPmZ8VluT61s46kQCr3Xt9ftuIQDW/MExjb 7W1lqo3DojXVv/la0jVGx/X0G5OL0YcXLGQpEMEo0Qtyfy016ghhJBO6JRVMsoiIOY 9AIHL0zxiESNlq9BQdAQl0jmExBQagTMNNKIDeNl25iJBAWBEOMOwhforqTWTDGTnW TETwDZ+HLzwFDhjXMLi1sFvPyIOAyncw4v2zhqHoG1bwAHbGhSNiS+tqfe97UfFEFG /t4SZm36ff/LfJzsXk2Ud5KLsnDPJzp47y4sLgiv1RspkzIP42uDHRyNec4CfJ7ULv XkixB7uXama/A== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, patches@lists.linux.dev, Martin Rodriguez Reboredo Subject: [PATCH v4 11/13] rust: init: make `PinInit` a supertrait of `Init` Message-ID: <20230814084602.25699-12-benno.lossin@proton.me> In-Reply-To: <20230814084602.25699-1-benno.lossin@proton.me> References: <20230814084602.25699-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, RCVD_IN_MSPIKE_H5,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1774196742036906318 X-GMAIL-MSGID: 1774196742036906318 Remove the blanket implementation of `PinInit for I where I: Init`. This blanket implementation prevented custom types that implement `PinInit`. Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Alice Ryhl Reviewed-by: Gary Guo Signed-off-by: Benno Lossin --- v3 -> v4: - added Reviewed-by from Gary. v2 -> v3: - add blank missing line, - added Reviewed-by's from Martin and Alice. rust/kernel/init.rs | 21 ++++++++------------- rust/kernel/init/__internal.rs | 12 ++++++++++++ 2 files changed, 20 insertions(+), 13 deletions(-) diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index f91ecd3b1edf..a15fb5ddbc7d 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -807,7 +807,7 @@ pub unsafe trait PinInit: Sized { /// /// [`Arc`]: crate::sync::Arc #[must_use = "An initializer must be used in order to create its value."] -pub unsafe trait Init: Sized { +pub unsafe trait Init: PinInit { /// Initializes `slot`. /// /// # Safety @@ -818,18 +818,6 @@ pub unsafe trait Init: Sized { unsafe fn __init(self, slot: *mut T) -> Result<(), E>; } -// SAFETY: Every in-place initializer can also be used as a pin-initializer. -unsafe impl PinInit for I -where - I: Init, -{ - unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { - // SAFETY: `__init` meets the same requirements as `__pinned_init`, except that it does not - // require `slot` to not move after init. - unsafe { self.__init(slot) } - } -} - /// Creates a new [`PinInit`] from the given closure. /// /// # Safety @@ -972,6 +960,13 @@ unsafe fn __init(self, slot: *mut T) -> Result<(), E> { } } +// SAFETY: Every type can be initialized by-value. `__pinned_init` calls `__init`. +unsafe impl PinInit for T { + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { + unsafe { self.__init(slot) } + } +} + /// Smart pointer that can initialize memory in-place. pub trait InPlaceInit: Sized { /// Use the given pin-initializer to pin-initialize a `T` inside of a new smart pointer of this diff --git a/rust/kernel/init/__internal.rs b/rust/kernel/init/__internal.rs index 7abd1fb65e41..12e195061525 100644 --- a/rust/kernel/init/__internal.rs +++ b/rust/kernel/init/__internal.rs @@ -32,6 +32,18 @@ unsafe fn __init(self, slot: *mut T) -> Result<(), E> { } } +// SAFETY: While constructing the `InitClosure`, the user promised that it upholds the +// `__pinned_init` invariants. +unsafe impl PinInit for InitClosure +where + F: FnOnce(*mut T) -> Result<(), E>, +{ + #[inline] + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { + (self.0)(slot) + } +} + /// This trait is only implemented via the `#[pin_data]` proc-macro. It is used to facilitate /// the pin projections within the initializers. /// From patchwork Mon Aug 14 08:47:48 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 135341 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b824:0:b0:3f2:4152:657d with SMTP id z4csp2660312vqi; Mon, 14 Aug 2023 03:59:30 -0700 (PDT) X-Google-Smtp-Source: AGHT+IEUqJqz1eBfOjbSmIrlGOEBDacm7PFzcYmnMmc4H4GHEydGvVT1x0QOBDwJ06IiL/hjebUC X-Received: by 2002:a05:6a00:138b:b0:66c:6678:3776 with SMTP id t11-20020a056a00138b00b0066c66783776mr11540315pfg.7.1692010770195; Mon, 14 Aug 2023 03:59:30 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1692010770; cv=none; d=google.com; s=arc-20160816; b=vx0qIVq2FKExgT7/JtnGYDnbmGAJQHocwyOb+07wOumuuSLK8gIIlS0nLXAjY2IfAm eoJZQJfh7IT/YcGpG3cH0KFHLyOxFkfegY/Xnku78iJA159BMzjS1xAXnox51en7VPk7 k012QGTCJBP5m8Jv6QczmWI6KUXlDPfd2ydQ4z1n2Hf/+axfflTSLORzpqXECYTHaqf1 q4oyljI3mwYSOkMFa//Emzf6Eyr4Mg/8TnyKmPROOpDprKJrS1WRfNDUVBGkkvuV5iC3 jphwvSNv33YuO6J2WODPyUoXatD3vX2LA3ZCJupfVGoca+tYvG7zIsVZBJ28wUfhqH2K 4RQg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=hkVBT1/HhXlC0vpOSaCkYCiuk6RG/epKqCA50EBxt0s=; fh=h3KS08NeBaYH5bCiXUF1yMk4NKDs2FHNIfHsq8atlgQ=; b=ww+WbNAiuKYzlqKM86Gw3K7bzGhHOyrQNsmQr2TEPi/fwLLMGPJvcB10LLU2LjhKJV XzitNb4+0fqBdrWMup16HEUsmANF/1AMJ4QGAk9LI9kY/oixa325sgvUMkvuT52xGTBt R0nMNATrs5M0c3VeiF8W3nGSX6U3ijuyuiBOH8ikeNKHOj0tAfJv9ocWsq/2D+Niev8B sCKUDc20wFRZ/6t+Sq4aXQTG96jLawgFCkcqvY/vhB4vCYBBAPWiOp5OK4FL3vbMS6Z0 16w4sq6eBYXII5vZoE4V+huynhyrpKu8EYkc/pcDRs19aUWM5Ukit9G/TC8wVRzRPbsk KLbg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=H6TSHj0o; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id k6-20020a634b46000000b00557447d5721si7764010pgl.768.2023.08.14.03.59.16; Mon, 14 Aug 2023 03:59:30 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=H6TSHj0o; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231788AbjHNIsv (ORCPT + 99 others); Mon, 14 Aug 2023 04:48:51 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33586 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234977AbjHNIsW (ORCPT ); Mon, 14 Aug 2023 04:48:22 -0400 Received: from mail-40133.protonmail.ch (mail-40133.protonmail.ch [185.70.40.133]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 0DEDD170C; Mon, 14 Aug 2023 01:48:04 -0700 (PDT) Date: Mon, 14 Aug 2023 08:47:48 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1692002882; x=1692262082; bh=hkVBT1/HhXlC0vpOSaCkYCiuk6RG/epKqCA50EBxt0s=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=H6TSHj0ovbEmRBAYnTfOmitCd0goCXOvTFW1CiF7GfTonLxQXS+KR4Hig9ISdxZ71 8Xl4r130KWm4xNvRHnSgN5EBw3g9+GvpBJm6P00B7KlfSzcHunr4vFJaaltiNFCYT8 3d4Exm1EEHD6E+8Yh/5KQ9snDxMhEuiaQanEL6ScJaMhqchCq8qVwfiHSEuwGZL1a4 7fs3Fx6l1FxLd6LXZDflI33fFCG0aNngyVHynKZztdI0V4U2zESeTU4udaMT6gjk9y t0LWKvnFfuxOKeDdrTS7BOP6IHc65TIGuBk4koptQ+CJuwCrDrCVt6Etksq4KTpiUF aY0ci2xSPLhng== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, patches@lists.linux.dev, Asahi Lina , Martin Rodriguez Reboredo Subject: [PATCH v4 12/13] rust: init: add `{pin_}chain` functions to `{Pin}Init` Message-ID: <20230814084602.25699-13-benno.lossin@proton.me> In-Reply-To: <20230814084602.25699-1-benno.lossin@proton.me> References: <20230814084602.25699-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, RCVD_IN_MSPIKE_H5,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1774201885157071441 X-GMAIL-MSGID: 1774201885157071441 The `{pin_}chain` functions extend an initializer: it not only initializes the value, but also executes a closure taking a reference to the initialized value. This allows to do something with a value directly after initialization. Suggested-by: Asahi Lina Reviewed-by: Martin Rodriguez Reboredo Signed-off-by: Benno Lossin --- v3 -> v4: - added Reviewed-by from Martin. v2 -> v3: - clarify that if `f` errors, the already initialized value will be dropped in both functions. rust/kernel/init.rs | 142 +++++++++++++++++++++++++++++++++ rust/kernel/init/__internal.rs | 2 +- 2 files changed, 143 insertions(+), 1 deletion(-) diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index a15fb5ddbc7d..d75220c8b3f1 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -775,6 +775,79 @@ pub unsafe trait PinInit: Sized { /// deallocate. /// - `slot` will not move until it is dropped, i.e. it will be pinned. unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E>; + + /// First initializes the value using `self` then calls the function `f` with the initialized + /// value. + /// + /// If `f` returns an error the value is dropped and the initializer will forward the error. + /// + /// # Examples + /// + /// ```rust + /// # #![allow(clippy::disallowed_names)] + /// use kernel::{types::Opaque, init::pin_init_from_closure}; + /// #[repr(C)] + /// struct RawFoo([u8; 16]); + /// extern { + /// fn init_foo(_: *mut RawFoo); + /// } + /// + /// #[pin_data] + /// struct Foo { + /// #[pin] + /// raw: Opaque, + /// } + /// + /// impl Foo { + /// fn setup(self: Pin<&mut Self>) { + /// pr_info!("Setting up foo"); + /// } + /// } + /// + /// let foo = pin_init!(Foo { + /// raw <- unsafe { + /// Opaque::ffi_init(|s| { + /// init_foo(s); + /// }) + /// }, + /// }).pin_chain(|foo| { + /// foo.setup(); + /// Ok(()) + /// }); + /// ``` + fn pin_chain(self, f: F) -> ChainPinInit + where + F: FnOnce(Pin<&mut T>) -> Result<(), E>, + { + ChainPinInit(self, f, PhantomData) + } +} + +/// An initializer returned by [`PinInit::pin_chain`]. +pub struct ChainPinInit(I, F, __internal::Invariant<(E, Box)>); + +// SAFETY: the `__pinned_init` function is implemented such that it +// - returns `Ok(())` on successful initialization, +// - returns `Err(err)` on error and in this case `slot` will be dropped. +// - considers `slot` pinned. +unsafe impl PinInit for ChainPinInit +where + I: PinInit, + F: FnOnce(Pin<&mut T>) -> Result<(), E>, +{ + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { + // SAFETY: all requirements fulfilled since this function is `__pinned_init`. + unsafe { self.0.__pinned_init(slot)? }; + // SAFETY: The above call initialized `slot` and we still have unique access. + let val = unsafe { &mut *slot }; + // SAFETY: `slot` is considered pinned + let val = unsafe { Pin::new_unchecked(val) }; + (self.1)(val).map_err(|e| { + // SAFETY: `slot` was initialized above. + unsafe { core::ptr::drop_in_place(slot) }; + e + }) + } } /// An initializer for `T`. @@ -816,6 +889,75 @@ pub unsafe trait Init: PinInit { /// - the caller does not touch `slot` when `Err` is returned, they are only permitted to /// deallocate. unsafe fn __init(self, slot: *mut T) -> Result<(), E>; + + /// First initializes the value using `self` then calls the function `f` with the initialized + /// value. + /// + /// If `f` returns an error the value is dropped and the initializer will forward the error. + /// + /// # Examples + /// + /// ```rust + /// # #![allow(clippy::disallowed_names)] + /// use kernel::{types::Opaque, init::{self, init_from_closure}}; + /// struct Foo { + /// buf: [u8; 1_000_000], + /// } + /// + /// impl Foo { + /// fn setup(&mut self) { + /// pr_info!("Setting up foo"); + /// } + /// } + /// + /// let foo = init!(Foo { + /// buf <- init::zeroed() + /// }).chain(|foo| { + /// foo.setup(); + /// Ok(()) + /// }); + /// ``` + fn chain(self, f: F) -> ChainInit + where + F: FnOnce(&mut T) -> Result<(), E>, + { + ChainInit(self, f, PhantomData) + } +} + +/// An initializer returned by [`Init::chain`]. +pub struct ChainInit(I, F, __internal::Invariant<(E, Box)>); + +// SAFETY: the `__init` function is implemented such that it +// - returns `Ok(())` on successful initialization, +// - returns `Err(err)` on error and in this case `slot` will be dropped. +unsafe impl Init for ChainInit +where + I: Init, + F: FnOnce(&mut T) -> Result<(), E>, +{ + unsafe fn __init(self, slot: *mut T) -> Result<(), E> { + // SAFETY: all requirements fulfilled since this function is `__init`. + unsafe { self.0.__pinned_init(slot)? }; + // SAFETY: The above call initialized `slot` and we still have unique access. + (self.1)(unsafe { &mut *slot }).map_err(|e| { + // SAFETY: `slot` was initialized above. + unsafe { core::ptr::drop_in_place(slot) }; + e + }) + } +} + +// SAFETY: `__pinned_init` behaves exactly the same as `__init`. +unsafe impl PinInit for ChainInit +where + I: Init, + F: FnOnce(&mut T) -> Result<(), E>, +{ + unsafe fn __pinned_init(self, slot: *mut T) -> Result<(), E> { + // SAFETY: `__init` has less strict requirements compared to `__pinned_init`. + unsafe { self.__init(slot) } + } } /// Creates a new [`PinInit`] from the given closure. diff --git a/rust/kernel/init/__internal.rs b/rust/kernel/init/__internal.rs index 12e195061525..db3372619ecd 100644 --- a/rust/kernel/init/__internal.rs +++ b/rust/kernel/init/__internal.rs @@ -13,7 +13,7 @@ /// /// [nomicon]: https://doc.rust-lang.org/nomicon/subtyping.html /// [this table]: https://doc.rust-lang.org/nomicon/phantom-data.html#table-of-phantomdata-patterns -type Invariant = PhantomData *mut T>; +pub(super) type Invariant = PhantomData *mut T>; /// This is the module-internal type implementing `PinInit` and `Init`. It is unsafe to create this /// type, since the closure needs to fulfill the same safety requirement as the From patchwork Mon Aug 14 08:47:54 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 135259 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b824:0:b0:3f2:4152:657d with SMTP id z4csp2624285vqi; Mon, 14 Aug 2023 02:32:25 -0700 (PDT) X-Google-Smtp-Source: AGHT+IE2S6Ct4BC0gzDWcaDlfLqLiiDE3C3opTiutnWg2lhxM0sURehwIMgCSATxPkpoUTiW9c5f X-Received: by 2002:a05:6808:188f:b0:39c:93ba:cb92 with SMTP id bi15-20020a056808188f00b0039c93bacb92mr11266605oib.8.1692005545469; Mon, 14 Aug 2023 02:32:25 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1692005545; cv=none; d=google.com; s=arc-20160816; b=m80OQCLwvrwdniqNZa3BhUQ5ENfs6k8QIxFrLp8lUfDBKmMe//gqTzTFsopTz5p8Vi WHfwoDVgw+PjKO+ASF9bkS90OLi/YKy1GtgDTEq9x5gQ9pn8E+3U/jNOgXO5JDeL4Vkc n8M9ADcuuqdOTB4luGl28KAquh8n9hN20gfb1wpH7QQ4DVrz/a35S0hv1je36yWROl6l ApfjHndU3MH8MrKgXb1njvnyYwcZrwy/Dbgi3MzYE08+950thObJvDA7EFZX3WKwdyHt cmFa2Mm+a3eWw14Qh1HbYc0goqnHhZule0QpYd8c0XT/22+oeA83IVErLcwuMhjCad7n Gjgg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:content-transfer-encoding:mime-version :feedback-id:references:in-reply-to:message-id:subject:cc:from:to :dkim-signature:date; bh=OzxRk04kug+IJRfrdZ4RG1rImHgGnATYUlRMhZsCbwM=; fh=TE4onW3Du2FQ1EsedDK8TzgRHOYndfJXYpOtlseWrM0=; b=VgviWJQ/6uv8mHGsCGQjVD4/bVRiCfahWsYsbqBXiS2kqpPIWhOUQfAiCQmk7aCEty ljqOmUKiqGlfGgOAeLLv6IXgBcncetP0j+RS0cXwbWzUaeXVwhVVDLond4LZGhKbKOkk 9Aj0+0m+FGe8pK8TtWz6RI/G1Zt96knyq9yRGMW4xKd0+E0KxViA6rxR8vrOOpRIMAiI 2QBlJentqvRhmFFa4LMNxZuFZO/Zpeys6BO6zW8Jgr8vQ2ybbqUMa/9znN5ZFbVKPZqs gkDl1UTav9G6Xx83ytLyeHT8vXwmS0J/1lOFP9zPnkSnF3KEmebm8CcwStPZQczsOyeN xRfg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=bo4g63vkczak7fgpnjhlhxuidy.protonmail header.b=adOP9C1Y; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id w67-20020a636246000000b00563adcaab61si8109841pgb.865.2023.08.14.02.32.12; Mon, 14 Aug 2023 02:32:25 -0700 (PDT) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) client-ip=2620:137:e000::1:20; Authentication-Results: mx.google.com; dkim=pass header.i=@proton.me header.s=bo4g63vkczak7fgpnjhlhxuidy.protonmail header.b=adOP9C1Y; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 2620:137:e000::1:20 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=proton.me Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S233081AbjHNItU (ORCPT + 99 others); Mon, 14 Aug 2023 04:49:20 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:33660 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235014AbjHNIs1 (ORCPT ); Mon, 14 Aug 2023 04:48:27 -0400 Received: from mail-40131.protonmail.ch (mail-40131.protonmail.ch [185.70.40.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id E599A129 for ; Mon, 14 Aug 2023 01:48:10 -0700 (PDT) Date: Mon, 14 Aug 2023 08:47:54 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=bo4g63vkczak7fgpnjhlhxuidy.protonmail; t=1692002889; x=1692262089; bh=OzxRk04kug+IJRfrdZ4RG1rImHgGnATYUlRMhZsCbwM=; h=Date:To:From:Cc:Subject:Message-ID:In-Reply-To:References: Feedback-ID:From:To:Cc:Date:Subject:Reply-To:Feedback-ID: Message-ID:BIMI-Selector; b=adOP9C1YTvn8M30AMLGzIRm+gphZgiEIRlaXXyyFcXWSLiB7LephdMV2rjPC+9PbN Yk0RbqjI9j/I4yf8CwUxh8tGA1mDACVsjc5VqEAsWkqEpj1c5nAbO5hJ5EPZavYJAP Np1owH85fWpYFWeRwh32HbRNTLg7Uhl8kYDJqZpUikR+LRD+Y75E8TMMYoxPPdJLyq oo1kj63I/SfwyniZC9HkWktw23LMenkVQYqSg74RTUp3xopZoRmgmPGyQDqNBvTV/8 ZeAYPKqS+vSWTDnm4J/e1JRSmzenAWItm33JYSYZG97+B0Am9erprq/bDLyX9Pow+F OlZLcZhMAkCVQ== To: Miguel Ojeda , Wedson Almeida Filho , Alex Gaynor From: Benno Lossin Cc: Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Andreas Hindborg , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, patches@lists.linux.dev, Martin Rodriguez Reboredo Subject: [PATCH v4 13/13] rust: init: update expanded macro explanation Message-ID: <20230814084602.25699-14-benno.lossin@proton.me> In-Reply-To: <20230814084602.25699-1-benno.lossin@proton.me> References: <20230814084602.25699-1-benno.lossin@proton.me> Feedback-ID: 71780778:user:proton MIME-Version: 1.0 X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_BLOCKED, RCVD_IN_MSPIKE_H5,RCVD_IN_MSPIKE_WL,SPF_HELO_PASS,SPF_PASS autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on lindbergh.monkeyblade.net Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: INBOX X-GMAIL-THRID: 1774196406822826224 X-GMAIL-MSGID: 1774196406822826224 The previous patches changed the internals of the macros resulting in the example expanded code being outdated. This patch updates the example and only changes documentation. Reviewed-by: Martin Rodriguez Reboredo Signed-off-by: Benno Lossin --- v3 -> v4: No changes. v2 -> v3: - added Reviewed-by's from Martin. rust/kernel/init/macros.rs | 126 ++++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 57 deletions(-) diff --git a/rust/kernel/init/macros.rs b/rust/kernel/init/macros.rs index d54243cd3c82..bee172e8599e 100644 --- a/rust/kernel/init/macros.rs +++ b/rust/kernel/init/macros.rs @@ -45,7 +45,7 @@ //! #[pinned_drop] //! impl PinnedDrop for Foo { //! fn drop(self: Pin<&mut Self>) { -//! println!("{self:p} is getting dropped."); +//! pr_info!("{self:p} is getting dropped."); //! } //! } //! @@ -170,8 +170,10 @@ //! t: T, //! } //! #[doc(hidden)] -//! impl<'__pin, T> -//! ::core::marker::Unpin for Bar where __Unpin<'__pin, T>: ::core::marker::Unpin {} +//! impl<'__pin, T> ::core::marker::Unpin for Bar +//! where +//! __Unpin<'__pin, T>: ::core::marker::Unpin, +//! {} //! // Now we need to ensure that `Bar` does not implement `Drop`, since that would give users //! // access to `&mut self` inside of `drop` even if the struct was pinned. This could lead to //! // UB with only safe code, so we disallow this by giving a trait implementation error using @@ -188,8 +190,9 @@ //! // for safety, but a good sanity check, since no normal code calls `PinnedDrop::drop`. //! #[allow(non_camel_case_types)] //! trait UselessPinnedDropImpl_you_need_to_specify_PinnedDrop {} -//! impl -//! UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for T {} +//! impl< +//! T: ::kernel::init::PinnedDrop, +//! > UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for T {} //! impl UselessPinnedDropImpl_you_need_to_specify_PinnedDrop for Bar {} //! }; //! ``` @@ -219,7 +222,7 @@ //! // return type and shadow it later when we insert the arbitrary user code. That way //! // there will be no possibility of returning without `unsafe`. //! struct __InitOk; -//! // Get the pin-data type from the initialized type. +//! // Get the data about fields from the supplied type. //! // - the function is unsafe, hence the unsafe block //! // - we `use` the `HasPinData` trait in the block, it is only available in that //! // scope. @@ -227,8 +230,7 @@ //! use ::kernel::init::__internal::HasPinData; //! Self::__pin_data() //! }; -//! // Use `data` to help with type inference, the closure supplied will have the type -//! // `FnOnce(*mut Self) -> Result<__InitOk, Infallible>`. +//! // Ensure that `data` really is of type `PinData` and help with type inference: //! let init = ::kernel::init::__internal::PinData::make_closure::< //! _, //! __InitOk, @@ -236,71 +238,75 @@ //! >(data, move |slot| { //! { //! // Shadow the structure so it cannot be used to return early. If a user -//! // tries to write `return Ok(__InitOk)`, then they get a type error, since -//! // that will refer to this struct instead of the one defined above. +//! // tries to write `return Ok(__InitOk)`, then they get a type error, +//! // since that will refer to this struct instead of the one defined +//! // above. //! struct __InitOk; //! // This is the expansion of `t,`, which is syntactic sugar for `t: t,`. -//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).t), t) }; -//! // Since initialization could fail later (not in this case, since the error -//! // type is `Infallible`) we will need to drop this field if there is an -//! // error later. This `DropGuard` will drop the field when it gets dropped -//! // and has not yet been forgotten. We make a reference to it, so users -//! // cannot `mem::forget` it from the initializer, since the name is the same -//! // as the field (including hygiene). -//! let t = &unsafe { -//! ::kernel::init::__internal::DropGuard::new( -//! ::core::addr_of_mut!((*slot).t), -//! ) +//! { +//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).t), t) }; +//! } +//! // Since initialization could fail later (not in this case, since the +//! // error type is `Infallible`) we will need to drop this field if there +//! // is an error later. This `DropGuard` will drop the field when it gets +//! // dropped and has not yet been forgotten. +//! let t = unsafe { +//! ::pinned_init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).t)) //! }; //! // Expansion of `x: 0,`: -//! // Since this can be an arbitrary expression we cannot place it inside of -//! // the `unsafe` block, so we bind it here. -//! let x = 0; -//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).x), x) }; +//! // Since this can be an arbitrary expression we cannot place it inside +//! // of the `unsafe` block, so we bind it here. +//! { +//! let x = 0; +//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).x), x) }; +//! } //! // We again create a `DropGuard`. -//! let x = &unsafe { -//! ::kernel::init::__internal::DropGuard::new( -//! ::core::addr_of_mut!((*slot).x), -//! ) +//! let x = unsafe { +//! ::kernel::init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).x)) //! }; -//! +//! // Since initialization has successfully completed, we can now forget +//! // the guards. This is not `mem::forget`, since we only have +//! // `&DropGuard`. +//! ::core::mem::forget(x); +//! ::core::mem::forget(t); //! // Here we use the type checker to ensure that every field has been //! // initialized exactly once, since this is `if false` it will never get //! // executed, but still type-checked. -//! // Additionally we abuse `slot` to automatically infer the correct type for -//! // the struct. This is also another check that every field is accessible -//! // from this scope. +//! // Additionally we abuse `slot` to automatically infer the correct type +//! // for the struct. This is also another check that every field is +//! // accessible from this scope. //! #[allow(unreachable_code, clippy::diverging_sub_expression)] -//! if false { +//! let _ = || { //! unsafe { //! ::core::ptr::write( //! slot, //! Self { -//! // We only care about typecheck finding every field here, -//! // the expression does not matter, just conjure one using -//! // `panic!()`: +//! // We only care about typecheck finding every field +//! // here, the expression does not matter, just conjure +//! // one using `panic!()`: //! t: ::core::panic!(), //! x: ::core::panic!(), //! }, //! ); //! }; -//! } -//! // Since initialization has successfully completed, we can now forget the -//! // guards. This is not `mem::forget`, since we only have `&DropGuard`. -//! unsafe { ::kernel::init::__internal::DropGuard::forget(t) }; -//! unsafe { ::kernel::init::__internal::DropGuard::forget(x) }; +//! }; //! } //! // We leave the scope above and gain access to the previously shadowed //! // `__InitOk` that we need to return. //! Ok(__InitOk) //! }); //! // Change the return type from `__InitOk` to `()`. -//! let init = move |slot| -> ::core::result::Result<(), ::core::convert::Infallible> { +//! let init = move | +//! slot, +//! | -> ::core::result::Result<(), ::core::convert::Infallible> { //! init(slot).map(|__InitOk| ()) //! }; //! // Construct the initializer. //! let init = unsafe { -//! ::kernel::init::pin_init_from_closure::<_, ::core::convert::Infallible>(init) +//! ::kernel::init::pin_init_from_closure::< +//! _, +//! ::core::convert::Infallible, +//! >(init) //! }; //! init //! } @@ -374,7 +380,10 @@ //! b: Bar, //! } //! #[doc(hidden)] -//! impl<'__pin> ::core::marker::Unpin for Foo where __Unpin<'__pin>: ::core::marker::Unpin {} +//! impl<'__pin> ::core::marker::Unpin for Foo +//! where +//! __Unpin<'__pin>: ::core::marker::Unpin, +//! {} //! // Since we specified `PinnedDrop` as the argument to `#[pin_data]`, we expect `Foo` to //! // implement `PinnedDrop`. Thus we do not need to prevent `Drop` implementations like //! // before, instead we implement `Drop` here and delegate to `PinnedDrop`. @@ -403,7 +412,7 @@ //! #[pinned_drop] //! impl PinnedDrop for Foo { //! fn drop(self: Pin<&mut Self>) { -//! println!("{self:p} is getting dropped."); +//! pr_info!("{self:p} is getting dropped."); //! } //! } //! ``` @@ -414,7 +423,7 @@ //! // `unsafe`, full path and the token parameter are added, everything else stays the same. //! unsafe impl ::kernel::init::PinnedDrop for Foo { //! fn drop(self: Pin<&mut Self>, _: ::kernel::init::__internal::OnlyCallFromDrop) { -//! println!("{self:p} is getting dropped."); +//! pr_info!("{self:p} is getting dropped."); //! } //! } //! ``` @@ -449,18 +458,21 @@ //! >(data, move |slot| { //! { //! struct __InitOk; -//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).a), a) }; -//! let a = &unsafe { +//! { +//! unsafe { ::core::ptr::write(::core::addr_of_mut!((*slot).a), a) }; +//! } +//! let a = unsafe { //! ::kernel::init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).a)) //! }; -//! let b = Bar::new(36); +//! let init = Bar::new(36); //! unsafe { data.b(::core::addr_of_mut!((*slot).b), b)? }; -//! let b = &unsafe { +//! let b = unsafe { //! ::kernel::init::__internal::DropGuard::new(::core::addr_of_mut!((*slot).b)) //! }; -//! +//! ::core::mem::forget(b); +//! ::core::mem::forget(a); //! #[allow(unreachable_code, clippy::diverging_sub_expression)] -//! if false { +//! let _ = || { //! unsafe { //! ::core::ptr::write( //! slot, @@ -470,13 +482,13 @@ //! }, //! ); //! }; -//! } -//! unsafe { ::kernel::init::__internal::DropGuard::forget(a) }; -//! unsafe { ::kernel::init::__internal::DropGuard::forget(b) }; +//! }; //! } //! Ok(__InitOk) //! }); -//! let init = move |slot| -> ::core::result::Result<(), ::core::convert::Infallible> { +//! let init = move | +//! slot, +//! | -> ::core::result::Result<(), ::core::convert::Infallible> { //! init(slot).map(|__InitOk| ()) //! }; //! let init = unsafe {