From patchwork Sat Jul 29 09:09:21 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 128095 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:918b:0:b0:3e4:2afc:c1 with SMTP id s11csp951772vqg; Sat, 29 Jul 2023 03:21:06 -0700 (PDT) X-Google-Smtp-Source: APBJJlHqa6Zhg387/r0bW/c1rxBoTLzpVrGc/jo3VGA34fmRVQK27vEaj6b0vsgrQVs2fxIHGwKu X-Received: by 2002:aa7:d507:0:b0:522:1e2f:fa36 with SMTP id y7-20020aa7d507000000b005221e2ffa36mr4069346edq.28.1690626066474; Sat, 29 Jul 2023 03:21:06 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1690626066; cv=none; d=google.com; s=arc-20160816; b=BgMLQP4nxd85hM11j3RQZToUOdrdeeJjt3iqeVC+YHRiWGnxv1wwqwMCZMfnzATJ7P NhwHCxf5WceFy/HSmbLQyGcBb/G/Rw6JvAfFuNlIPC+CGWcauICnISj5gV79E2S4fQ5I iJ01VmN1R8JTfhkDUhPpemSeP5sCeNiq2d8JVnEpXd99gSjwFIZXEGJL5aYKoXCFtn2w liQ76dqpEIvInZBrcHcJAxeeNLk3OXSDljbXTrWnVqX+83ugCFbP+pKPGejO/jyD7jz9 gTjM/GEDn2MW//mNulvxTzhIvW+qX9wK6Cyzo/WAS8bedgdNqQNqjz3MCN4eeJWfURUU ZG+Q== 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=N2s97cvlN6M1T9h5Ui3a9IQD6ITz5ZetU6axxlh+5uE=; fh=Kxkq5MAR/ee06c4zNa7/ow9QmWBIyeCoT7WYYnSSoIA=; b=MRihvVJFZzq3z3eS79qWTuG/IpHMU7qEmrTjhCs+gMkC9TB7D/DwRYK0p/G/Z3M0/R 5glm4reisfroRzi4m98eUdB/cSNv+uuwjoGWMBebT1XUplfq4PENPeh3lCsoVo8dCXkq 6ZcZcCWFoSzME61g91ZBIIuBd+47Vcne31aNZQGuvCKGc38VaTSsvPgPwQcOknlupt/a p4VGN+KpTGR20j6ReSjKlk5tkrlsNIHzkmJfl+9iFg6T+58c4drnvGIylGcGfgbUMb0W ZSsRALpdtQNPqUGwmARRnebEAjz84MBJ2rJaQ18HzT2f6ndWZXLE8tFFjfvQ6pPS0sIs /Sdg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=jltqtrdnircvvmdkhvakuegsw4.protonmail header.b="OCs/bcgj"; 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 m2-20020a50ef02000000b005222af123bfsi3948414eds.301.2023.07.29.03.20.43; Sat, 29 Jul 2023 03:21:06 -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=jltqtrdnircvvmdkhvakuegsw4.protonmail header.b="OCs/bcgj"; 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 S231536AbjG2JKB (ORCPT + 99 others); Sat, 29 Jul 2023 05:10:01 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40648 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231511AbjG2JJr (ORCPT ); Sat, 29 Jul 2023 05:09:47 -0400 Received: from mail-40131.protonmail.ch (mail-40131.protonmail.ch [185.70.40.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id A2C39B9 for ; Sat, 29 Jul 2023 02:09:37 -0700 (PDT) Date: Sat, 29 Jul 2023 09:09:21 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=jltqtrdnircvvmdkhvakuegsw4.protonmail; t=1690621775; x=1690880975; bh=N2s97cvlN6M1T9h5Ui3a9IQD6ITz5ZetU6axxlh+5uE=; 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=OCs/bcgjoXeLdj8REzxT9xMEah/Qih18kJETWFrnTRX8jUPPMRwo8VGHygNDvHVrj ZOoCGb8Ap2qKRVJqLn5RB8k1iode6XBYgmu8Q5Lj/sA6gVrFfO/61bNnb4BzAQilEG JeaCYlkwUHRFjyApYzkfwIXGgrzaoFIugYFO+kYEp0q0UekK3jMIrvfeTPTjc/E3C5 Ff5f1jxvYbDwXfue2rOmFVzjnraNO9u6y95mVuZAbeGJjwF1jFHRhh2/FBBpkSxmzN h8At/nQSL559fiH5BYBd5tZQPmWwDIsv/1ZS+vECP/aws5smHr3eahAaiXpMwpczY7 u8LLW+pn7RvEQ== 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, Martin Rodriguez Reboredo Subject: [PATCH v3 01/13] rust: init: consolidate init macros Message-ID: <20230729090838.225225-2-benno.lossin@proton.me> In-Reply-To: <20230729090838.225225-1-benno.lossin@proton.me> References: <20230729090838.225225-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,T_SCC_BODY_TEXT_LINE, URIBL_BLOCKED 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: 1772749918679518988 X-GMAIL-MSGID: 1772749918679518988 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 --- 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 Sat Jul 29 09:09:23 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 128081 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:918b:0:b0:3e4:2afc:c1 with SMTP id s11csp939186vqg; Sat, 29 Jul 2023 02:44:19 -0700 (PDT) X-Google-Smtp-Source: APBJJlH4UHxh3gI9N/7cfg+bBUKwCbEQjAVzN03gfw+I1lSFGuY9W3lTim9gltGWZP8Ol5I2Rt5P X-Received: by 2002:a17:902:a40d:b0:1bb:20ee:e29e with SMTP id p13-20020a170902a40d00b001bb20eee29emr3932450plq.1.1690623859257; Sat, 29 Jul 2023 02:44:19 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1690623859; cv=none; d=google.com; s=arc-20160816; b=hOUkrhLAXEzn5rXwb2r/OZzeaUL/LG6CSK5ymDu9bWSxhqMQ3J4lHZdaQz2WJ+Ex/x 2rTipggEg1E31BlyIPTiQ4vGXltk0MvHQ1jAuq+fl5wOAF6b236UqNo0sYEF2lkcXv8N If/2J0Cif3cQ7HOngJyrb2PpqHb3q0GfNzveK4Iev6ghZ8AG5IHZIG2SIuoUJ1tzeGPg AqATGfLzaA8yVzBNOfVN9TKeawOU3GbTvCD+Z4DnuQ12Yp5YtWndsNAPFF4LVHBCFYxn 7N95QzTa9scpOsnfFI/8hJ72cltfhrHdRHvgcivZB4DXyfplIl55JS9dAjDQf2c4viGV Gmdg== 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=uCozY+Pcnawd0I1oW4pKqllFOri6l5nBR5qs/jiAoEo=; fh=qm1bOEYzVYZKL4fg86TgWb8D+QJA9mGpUhKFp2A6Xio=; b=kIf+u51cSppYjpSjJSoXEBoG6YjtScb2PlNHPbcnut/0C9Nkhnz9+DeIwT9KFcXqDJ CrkWVXZfAwZWOb2VtjjSdJRQbsW+pAzHk958DL0crTP1QZbeFDNlNUcL2q20hKYHPsUZ 6Ttbp8uLfE+IMf66i78naLykSTkbWWp5vzpdosFNJW2hcbdep+aKI+hpMeLUbEm/n+T6 dxwktEOVdREODPrs4Xk0suWsMvirNNmJBjwDlOAiEG5vjGr+PIcJ1GySFWCNLR+Q64sf ocf+9SAsmw/3nEx55ST4ARLW1QvM6PHRo9aKgjA3kSbykPk/S/r57JQ2xRAg7CK9zK97 q0wQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=lKDPxnyF; 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 o5-20020a170902d4c500b001b7f4696a2csi4552615plg.347.2023.07.29.02.44.04; Sat, 29 Jul 2023 02:44:19 -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=lKDPxnyF; 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 S231573AbjG2JKD (ORCPT + 99 others); Sat, 29 Jul 2023 05:10:03 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40538 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231547AbjG2JJu (ORCPT ); Sat, 29 Jul 2023 05:09:50 -0400 Received: from mail-40131.protonmail.ch (mail-40131.protonmail.ch [185.70.40.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 738A849EA for ; Sat, 29 Jul 2023 02:09:39 -0700 (PDT) Date: Sat, 29 Jul 2023 09:09:23 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1690621777; x=1690880977; bh=uCozY+Pcnawd0I1oW4pKqllFOri6l5nBR5qs/jiAoEo=; 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=lKDPxnyFMYP6lsDUaojZFrgdIpXQuFcXehhvbFGFwtYfMVJJdCfW5fjrEI5WujI0f nWcuxjcz/5W2zriu2QFzV9LNl6aFYV+VGS2Kyu5UYjZ/r7myg3R69jwdzH8wTFSL3/ 5fcT5TAOiTzMpDobLg6KARjQhq2qOwiVuQ6u7jxTH5AzNIojixXcrQ/1rJSYgY1nf3 5ofLheTX0lz8SKwNMg4RUlc4vSx5LA1a0xZSgJ4cPdX0KRe7HFo2iZR3usR3ekeVnr +ztylJks1+CpoQFuiAAa7fnnQ0A0bZuFdmagIM5FTjPCvHlTjbJIq58ECc9rY0WUfS DYWrqz2d2kfcA== 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 Subject: [PATCH v3 02/13] rust: init: make `#[pin_data]` compatible with conditional compilation of fields Message-ID: <20230729090838.225225-3-benno.lossin@proton.me> In-Reply-To: <20230729090838.225225-1-benno.lossin@proton.me> References: <20230729090838.225225-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,T_SCC_BODY_TEXT_LINE, URIBL_BLOCKED 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: 1772747604167218635 X-GMAIL-MSGID: 1772747604167218635 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. Signed-off-by: Benno Lossin Reviewed-by: Alice Ryhl Reviewed-by: Gary Guo Reviewed-by: Martin Rodriguez Reboredo --- 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 Sat Jul 29 09:09:35 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 128107 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:918b:0:b0:3e4:2afc:c1 with SMTP id s11csp981760vqg; Sat, 29 Jul 2023 04:45:37 -0700 (PDT) X-Google-Smtp-Source: APBJJlG6iHtCPnS1h4Ys0YmB809cKIdDvqKK+FEUnCKntJ1Icxh+kHzre8eWNT7QSUzLWcmGvclf X-Received: by 2002:a05:6402:27d2:b0:522:b723:11bd with SMTP id c18-20020a05640227d200b00522b72311bdmr1293171ede.4.1690631136685; Sat, 29 Jul 2023 04:45:36 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1690631136; cv=none; d=google.com; s=arc-20160816; b=RBMaXo02e2DC0glGG5zyKwat3Tde8OVjLHctsOWOeXNdgzC/+qYfwh8ao5WegHTwt+ yIZl7J29NKKcK6ZqK9ZoP+12qO3wOcYPzahLW2HLG4lP0Er68ucqZvTx/UfOzY7XHYc2 2sPe0K7paHmBoxcy42Y80Mf43bROoVuwS3HFQoDNijSDg3N3zgvqcSy+1XQfHjeMl1zg 7Mp+OWUT1t71DlCgVLlCZntS08k58hBoI+X+FAdM2NvDKE1wSNRpyqXu8MWxbeL/LPM9 zobDYT78QyUfBUzBWi8l66ldV/rYv9tIgClhZHJq2weKeDRMa9WQaInXbn7oeeXZOZJX sUyg== 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=5p21LSp8SkS5yN9wOR7GKAHVdY3UPSeFZ4WX2mo9szk=; fh=ahHPrvxY+ty2HIuIPh5QXslVmwB1wHeJjzGZ+GeRryw=; b=v6vkhB0qbHih4ZOn44NAtpfwcT1IkBLJ4bqeE+a/NArNHORXLFSYN8xUeC01/JZypE lEF9MpaFd1Z6yxCrHYV/zNjScrwBSGxlhlH1Q2gbOkLHiEsOt7/6oGAtpa0efc3LbTuy /QPEjawcg/pBGBLcn/sPVl9MdTnTBFj5x4/tZnDnZi5OVL091FTJzqKeY+JCBQRtiOwX hXpM+HreyIaThDy4RRCaFI+O7pgAq1MxBjBd52vElvZmhXeFYSWCWtx3p2+TG9SA4LmZ qy19amdCOAB7t0jOCzua+3eDcH8ojrHC3RjAKlkD0kzu6jYS0NpOCf9YMuWMbTLmqSPK VqjQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=Wpo2YzAg; 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 p23-20020aa7d317000000b005218239ce10si4004456edq.206.2023.07.29.04.45.12; Sat, 29 Jul 2023 04:45:36 -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=Wpo2YzAg; 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 S231671AbjG2JKR (ORCPT + 99 others); Sat, 29 Jul 2023 05:10:17 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40728 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231518AbjG2JJx (ORCPT ); Sat, 29 Jul 2023 05:09:53 -0400 Received: from mail-4322.protonmail.ch (mail-4322.protonmail.ch [185.70.43.22]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 5CD1849F3; Sat, 29 Jul 2023 02:09:42 -0700 (PDT) Date: Sat, 29 Jul 2023 09:09:35 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1690621780; x=1690880980; bh=5p21LSp8SkS5yN9wOR7GKAHVdY3UPSeFZ4WX2mo9szk=; 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=Wpo2YzAgmnWK6GDRk4h3YYnaq5VmH0C+eWwuxr1vUVg/D4kYYRDJb6SNCTWCV2XJS Pz4Ps+byzYbaq8lsORt9nudLYbJt9R+xerWo1fe069NPHr33JMfjCIpYJczESvrGTg GF1yD5AmAkeGBJPOLyxsm2flp3e6+nR/Q7Yy8LVod/5ge/xFtNeQOqvDhtl9qb77x2 Dwa7GRNFxZPdoCYIPJt14M9VNLL7AxczvHVshQDXoHMeiO8ioHFe3n4RnTtW3Qhy5Y nKZK89T2ZStojT/CUq2UBBXQN69YMrritwq9mk9zd50HL9E6YRLg/uVHgEn6L1UxuW +6zunh6a7UfMA== 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, Asahi Lina Subject: [PATCH v3 03/13] rust: add derive macro for `Zeroable` Message-ID: <20230729090838.225225-4-benno.lossin@proton.me> In-Reply-To: <20230729090838.225225-1-benno.lossin@proton.me> References: <20230729090838.225225-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,T_SCC_BODY_TEXT_LINE, URIBL_BLOCKED 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: 1772755234848159978 X-GMAIL-MSGID: 1772755234848159978 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 --- 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 | 6 ++++ rust/macros/zeroable.rs | 72 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 134 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..b76c198a4ed5 100644 --- a/rust/macros/quote.rs +++ b/rust/macros/quote.rs @@ -124,6 +124,12 @@ 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 $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 Sat Jul 29 09:09: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: 128084 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:918b:0:b0:3e4:2afc:c1 with SMTP id s11csp940217vqg; Sat, 29 Jul 2023 02:48:23 -0700 (PDT) X-Google-Smtp-Source: APBJJlGRbSIwPgX34oNT4b9SZnJyClzHg/SBbRnb2hduy4WUfnJaMVorQIk2FHe707G/2h5HXil/ X-Received: by 2002:a17:902:c947:b0:1bb:ab0d:4f76 with SMTP id i7-20020a170902c94700b001bbab0d4f76mr5452929pla.58.1690624103191; Sat, 29 Jul 2023 02:48:23 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1690624103; cv=none; d=google.com; s=arc-20160816; b=xV31KGAIkDA1CJikX3ewIAt6La9+ywAxi1FsMwsxKWKroyW6Hpb0uhqsLadmMjRjDH sYr2J/doPP5c0nIKxeTh9vMi18mBoo/ymOp9khlwucIMdCP9RpzlUBjwejm+C2JLiPAC SIZFgoN7cSI+bNXqTXyPVrry+syR5cYpOWZGULcbBlMUUERspSsWNpvhFE0F7rZkjE7v faEnVmC+65MNXO8V0uKcHhiuJzn0uA3an9ppBCiXgn/RLHBipxKALJ72tYY71w+WB5jN NvRE8crtIPJ0OmJm082uMhwcdb+ua7YYBHlVTbcmvFBO5kwonqfwIDQU4oGqhrut/B/C B8+Q== 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=JsVvEmezg9Lvg6P1Vn7MyyhGkVZ8a0YG+MpLx2E1ZDo=; fh=MTk7MD/292FwJGz5jKS0PBOnpzkNxprDjhqM8t+E7nE=; b=lf1XgIHDMhvY4CmGA9muaMocThEidLDBpM6SuQJATpnkJ0g/bCv2NUI2CylbIDyJX0 oR6SujsP7OQaoER4ohq9ml1bXIKULc++3fneSKIKFykTq0iNWD7aNwA+xoK8btG6o72u RmgjjnXwIfm7OuvS60aXDctgQ03fvdXg1IR3mlgUB1raiEtljDhLobhPg/uJ2LBc3db2 dgWpUOPE855w3bP5H0nhST8ONl4akhjtfq2xxIM/ScpD2+qZRwcEvRclOuW7Xdj26J+C 5pp4IsgZN2LntmzmGQtH4VdJTBzxj1iGsyTfkStyCNmMYwxOhJFIjJgcYW98KyzzJyoc 7uFw== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=ktgpeM85; 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 h9-20020a170902680900b001badbe8e441si4198452plk.106.2023.07.29.02.48.09; Sat, 29 Jul 2023 02:48:23 -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=ktgpeM85; 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 S231535AbjG2JKj (ORCPT + 99 others); Sat, 29 Jul 2023 05:10:39 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40606 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230256AbjG2JKQ (ORCPT ); Sat, 29 Jul 2023 05:10:16 -0400 Received: from mail-40134.protonmail.ch (mail-40134.protonmail.ch [185.70.40.134]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 013544C21; Sat, 29 Jul 2023 02:09:52 -0700 (PDT) Date: Sat, 29 Jul 2023 09:09:40 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1690621791; x=1690880991; bh=JsVvEmezg9Lvg6P1Vn7MyyhGkVZ8a0YG+MpLx2E1ZDo=; 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=ktgpeM85JtomgKv0UbJJcMRTJ4ebcj2kBQTzrWH5PtFSUFJ9knKdd720lDuyILOus x5qrZG30Qt14nxd9V7nb1HBMHB1wpGMiVRXO0sVT8WeSI7DU+5E9oiiOdEROE9EqTH KfY2VFO4C3hc4+pyfx7DCxR0wCWjbySrokZCp8V4fL4UxjGNaqYb1sFzJUfh+tHi39 ArgBil7DzyHgtbofiYqTzh7/bLdPAXAHBqPLWhtEOg873xVA7Axy6rCOOvGW3GlEUb Ukjue2pAdpxUt5BGXJFZ7cxU+7fZXVmGdSqrLU9d/spokyfGJpq8ORFUvrGHbW086U Zr/5UdUIqcTRw== 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, Asahi Lina , Martin Rodriguez Reboredo Subject: [PATCH v3 04/13] rust: init: make guards in the init macros hygienic Message-ID: <20230729090838.225225-5-benno.lossin@proton.me> In-Reply-To: <20230729090838.225225-1-benno.lossin@proton.me> References: <20230729090838.225225-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,T_SCC_BODY_TEXT_LINE, URIBL_BLOCKED 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: 1772747859727816239 X-GMAIL-MSGID: 1772747859727816239 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 Signed-off-by: Benno Lossin Reviewed-by: Gary Guo --- 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 Sat Jul 29 09:09:46 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 128088 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:918b:0:b0:3e4:2afc:c1 with SMTP id s11csp944300vqg; Sat, 29 Jul 2023 03:01:38 -0700 (PDT) X-Google-Smtp-Source: APBJJlG3HJkGzgyBW9cxYva5i9JlOrbokeJrDw86/ZziN2Tj5wjpMa5CbVPqwHxmCoUJHNy+1+Nq X-Received: by 2002:a05:6a21:3b45:b0:11d:4c79:90ee with SMTP id zy5-20020a056a213b4500b0011d4c7990eemr4370714pzb.25.1690624897725; Sat, 29 Jul 2023 03:01:37 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1690624897; cv=none; d=google.com; s=arc-20160816; b=NVJbxLPi6HYWwVbuaO1pSq76PhtxeGNmwYOa8/F61W8YxG5U8fgXGpkmCpHZVtoU8f 7g3wcYkC2IctPvm3k/fDqncXAuoYSB1g/QIrEPmmZMUWweR2e5idC5VNHlHA48/n73Ev KtR9IMjpl91FImtHPGeywmQCrmQGjU/JKqa+KvZzs9yGHQjDiCSkpn4GSKr3aeVABl3l D/rI0mgn8hOkAmafDJ7+DxksoGWKH43TBwXwkoHzOB7yyxcSPYSwcOKLpr95fmmgVEXj toL7R0sRz3J9r5VZAPSRRQBPZBGp3W9z+xU+nSXjnFok6tsuo/1GQ+v7gwmbb8WkURiN VQaA== 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=pQx6ihcSvIvQbgV/BbP1F61LnlGypfrLDVQD2l3NnSY=; fh=Kxkq5MAR/ee06c4zNa7/ow9QmWBIyeCoT7WYYnSSoIA=; b=0flyQUiNRgmVoYLi6HAxe2gIB856u06gofLda4EYWF6qAGasIA/SXm7FuKrcgqLd7c BLDFDzF21X9u2OkwHFLaaW+cwTSk/CrBxqckuoh1cHWY5rTjIGwW+e1vKCHBCCfd66WS WbdxOjjoUTuZFujFGCSwXHajZgbjcDsO/ybysJZ1iqfdWi3fr3hMm2HU6ER1HVar/Let x4VIynn1lmDjEbW5GjcM1XQ/1VT14W3CfTOYfjqV7XtY6bCNxjTLtF2rnycK17DpTEhN Mm6S0C7tbc7hQGNqMBGfIsJmF5NU6tV9siruWKztSjsQ81HjQcvpjqWLTfm4TkSUcrIq K15A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=oeiw4vx7yna6jha6bjbqylksbe.protonmail header.b=DQjd3O6k; 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 cd5-20020a056a00420500b006870b0a14cfsi2763255pfb.134.2023.07.29.03.01.18; Sat, 29 Jul 2023 03:01: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=oeiw4vx7yna6jha6bjbqylksbe.protonmail header.b=DQjd3O6k; 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 S231699AbjG2JKp (ORCPT + 99 others); Sat, 29 Jul 2023 05:10:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41312 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231682AbjG2JKb (ORCPT ); Sat, 29 Jul 2023 05:10:31 -0400 Received: from mail-40134.protonmail.ch (mail-40134.protonmail.ch [185.70.40.134]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EC29D49DB for ; Sat, 29 Jul 2023 02:10:03 -0700 (PDT) Date: Sat, 29 Jul 2023 09:09:46 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=oeiw4vx7yna6jha6bjbqylksbe.protonmail; t=1690621802; x=1690881002; bh=pQx6ihcSvIvQbgV/BbP1F61LnlGypfrLDVQD2l3NnSY=; 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=DQjd3O6krWMb6w6+BBC7iqizJ08O0WXNNmNV7ZfY08l4HV8f5wScaDrARRhWDaXWm h/QFvAkYLcmRrc+FCNtwdwvxtg+uzZiFcXPxlktpHnK6eTiVpiGQbAvZyBRUy17lW0 ankNpi1N/xj4O/sdOeQHt3qQxHtWqKHaBCH6ayYy142AeHbnU5VqdO4fNjWfmoog4p KMFFwz9n0D8IhmPN5grUjre/ZkAS8dpzcfcErS0M2leEm2T2bGuXnk5NnsZLdyZysC exFdp21cSBNvFqq4JKGaapbuGq8OzcnZxgZW4d3EHFU8wq1hnCjw7vuOIAnTLxqNJ3 jHK6JTuG3Ehdg== 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, Martin Rodriguez Reboredo Subject: [PATCH v3 05/13] rust: init: wrap type checking struct initializers in a closure Message-ID: <20230729090838.225225-6-benno.lossin@proton.me> In-Reply-To: <20230729090838.225225-1-benno.lossin@proton.me> References: <20230729090838.225225-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,T_SCC_BODY_TEXT_LINE, URIBL_BLOCKED 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: 1772748692739263381 X-GMAIL-MSGID: 1772748692739263381 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 Signed-off-by: Benno Lossin Reviewed-by: Gary Guo --- 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 Sat Jul 29 09:09:53 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 128097 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:918b:0:b0:3e4:2afc:c1 with SMTP id s11csp953662vqg; Sat, 29 Jul 2023 03:27:04 -0700 (PDT) X-Google-Smtp-Source: APBJJlF8uf+Uz7irirRhpKQRcfo666gqhPgn1u0DXiSvXO+vnXCjFWmEXPNh9CfjIl5y8qp75sJK X-Received: by 2002:aa7:d616:0:b0:522:3081:ddb4 with SMTP id c22-20020aa7d616000000b005223081ddb4mr3877342edr.20.1690626424683; Sat, 29 Jul 2023 03:27:04 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1690626424; cv=none; d=google.com; s=arc-20160816; b=MaGv7EjdwL4XFnPG/QHNhQnsceQqHgHjZovTO9GJoPtFJsJiC4hwhqyYNSGxUx13Qe BYc+nATB0RP6kYdzzYnbmrwkAl67xlSDgOlsO+eZ9dZqgTCE79X8VD0VFZqZFKo6qRC4 Dgp0ZnA7VbKKrLKE5ao3U44OU4qymJSpKxMOqGKI4kBDV4nWUnngRSCZqi90tYLEGKDK vW1Cmi1IBwWhVLeK3x2OWCiVmup100iB5ivmAdH4S9AuWcXBraCHHsNw7pteoYKDA3pw o4QGr4MWhkA9oxw7oDy0McrV7WW1fGFdNjF0yEXRwEe1y+yj25FUV+drtJrJbQMAHicU M1gw== 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=rixSAlF8H68fR6m3THBV7cCNL7So1w86OXDiq2xYBjU=; fh=Kxkq5MAR/ee06c4zNa7/ow9QmWBIyeCoT7WYYnSSoIA=; b=rHAp7m6ABuBos5uezhgQzVCNnr3EQtcmyBymcNDMkr2dZBIpaO+YGv7ObZBN57KwLP phzt7e1xzWDWBxhBo9XzJifqVxQwvW3Fhn5EIntETsBqt0RRzJ4caAdVA3MYn3zlf2Hb eUUvW7P5XySUZ3PwmwQayHT/HOELdjITKPeLbIU3JxIECGqShCa4aYDOwwR3YAsMAJWX KHVEuOhmZ9evX1CxMgpXMCCe2KDxgl/DXb6jp0MxvSVHxiOaZpryZEMreymHoDYp2ipB z6ZeKeA4LJfOSLKtE/Dol33QqLAcR4QKwDWoVBQUBZKALZvT8w/2JXbSfHv45zv0Fm2E x48A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=fnB7DKQr; 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 m21-20020aa7d355000000b0051e065bbc3csi163243edr.8.2023.07.29.03.26.41; Sat, 29 Jul 2023 03:27:04 -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=fnB7DKQr; 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 S231590AbjG2JKl (ORCPT + 99 others); Sat, 29 Jul 2023 05:10:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:41310 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231527AbjG2JKb (ORCPT ); Sat, 29 Jul 2023 05:10:31 -0400 Received: from mail-4322.protonmail.ch (mail-4322.protonmail.ch [185.70.43.22]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EBD7449C4 for ; Sat, 29 Jul 2023 02:10:03 -0700 (PDT) Date: Sat, 29 Jul 2023 09:09:53 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1690621802; x=1690881002; bh=rixSAlF8H68fR6m3THBV7cCNL7So1w86OXDiq2xYBjU=; 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=fnB7DKQrA5Mk3rcM0qdH1bUwWWwZruoJbh//pq9ObBMiIuInGNNV8FSd6v4xXHd6Z eBJ8TiauGbt8+31hQ3QoQ4JHTlkaaW9jl4S7EYP6FyrdW2wF6YFPFlEN2cUxt82UP3 5qF43KJejvkdGm5PTJ/fF3eQsjH4LrYxXW3FYBTe9isFjDp/E3SuvmKGEPbIUkocf0 Q+Haw7xBMFQ8sy0zpMg+NIiVNOO+2IJ1plEaaZtZB8OEGBH+r+OdwO7EoV8EhsexrD UPZ7X097/SV6kA4GbIurWboVWrBdHSy36+FRBLCVOV/XPPOhsdeNGcyaSOCqnyQUGf RAEFQxJXWLkyg== 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, Martin Rodriguez Reboredo Subject: [PATCH v3 06/13] rust: init: make initializer values inaccessible after initializing Message-ID: <20230729090838.225225-7-benno.lossin@proton.me> In-Reply-To: <20230729090838.225225-1-benno.lossin@proton.me> References: <20230729090838.225225-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,T_SCC_BODY_TEXT_LINE, URIBL_BLOCKED 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: 1772750293729172836 X-GMAIL-MSGID: 1772750293729172836 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 Signed-off-by: Benno Lossin Reviewed-by: Gary Guo --- 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 Sat Jul 29 09:09:59 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 128103 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:918b:0:b0:3e4:2afc:c1 with SMTP id s11csp966178vqg; Sat, 29 Jul 2023 04:04:56 -0700 (PDT) X-Google-Smtp-Source: APBJJlHIAwFEQHu66yIiEJJBXZ09qFolzps8GKIoiN30UCnGLgZ9kDwVuaNABYoBxJ6h9TEi1R4j X-Received: by 2002:a17:906:5308:b0:994:54e7:1287 with SMTP id h8-20020a170906530800b0099454e71287mr1896015ejo.73.1690628695920; Sat, 29 Jul 2023 04:04:55 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1690628695; cv=none; d=google.com; s=arc-20160816; b=z7Of58iJt3PP/m5Fm+vDz3cD3c37k2L3ByIc02TS/oAUE1H79DxfMk7SKkTAeUN6hP X7Ms1Xs+5KxvM3yFHVxQKkInzjb1kr3Vuc30jJ/ismKkFKHZgaEWZrnwiIkym+/wNdi5 G7A0At7vFtiHKQAyCRyoiQ+jANev/kMHt9GmNv5uzIzaxgXokA+6NY57KjkBdMLGgLZz bIU5EaDYlt/yDT0lwbqYr5XmqjNaKdotsuGkP61+5GTW0rp3xO90Xvudpsb2gqSRcNyM r6BwsPR5R5G4ZAucqrQl8fZadEqFd5LDjqtwGwdZdH2Wa4DDl7onzKr+ypHBl/aGnJjW u6pw== 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=wUJmXpGAQw6uTpAiIBamzaLUH9+jLE3uymP2dlSTlCM=; fh=MTk7MD/292FwJGz5jKS0PBOnpzkNxprDjhqM8t+E7nE=; b=OJnsg5dW17r/MiQ3VTWJpmHW9rDy+NSK9AEjpUEbK+QBu2j5gAXO41IcQAunYTVN67 SeGNkQI/HfZhgMg6ZEa9Iw+HrBMcDJG9KbLvVj+58j8j4fnFlRmWo5/3UcVwV/HR1Xug L1bzCiEb2e0Rkpoo6Eeln+OzFwi/ZO1jb5volxJpZmaUhBeK9zdb2s3UiLs3H1QDQP3k ga4seerAMNc4UyqxctcBcvCDA3O2nyanZnCiMhsQ05Vff6jDLRe5MMUtUZHWziYzHPqk OE5hNrVwJM3rhr+daTp8Wsp+8q4VzdkL7aMltRWPCr0KN5R0DEjgjZcZzBhxH8Syk8pc iFEQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=ZvypZ5vy; 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 a12-20020a17090682cc00b0099b94cd668bsi658552ejy.298.2023.07.29.04.04.31; Sat, 29 Jul 2023 04:04:55 -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=ZvypZ5vy; 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 S231649AbjG2JKs (ORCPT + 99 others); Sat, 29 Jul 2023 05:10:48 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40778 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231630AbjG2JKg (ORCPT ); Sat, 29 Jul 2023 05:10:36 -0400 Received: from mail-4322.protonmail.ch (mail-4322.protonmail.ch [185.70.43.22]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C3CB34EF2; Sat, 29 Jul 2023 02:10:14 -0700 (PDT) Date: Sat, 29 Jul 2023 09:09:59 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1690621812; x=1690881012; bh=wUJmXpGAQw6uTpAiIBamzaLUH9+jLE3uymP2dlSTlCM=; 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=ZvypZ5vyF51EefJs9iZiX8+xFe3ZkE5wih9jStP6wLmAvu2APFV5SRwznH5rO67ou zupbWBWujM6Q20+dmJBfxtUyiJnvWFamOcKhZsogt0nksKINpkzPbGnUV7YlGdrQQC F70KhvIhk+Rfgxb661HDydCb/WhZ1N1ZdDdX9XD50J2Bk3qLuBtaker4PGq43lz3OL 3xZAqOp82qiRQuiB7FjE2qVcJfuU3FNq1mdsCyE3zbRTRA+OGF5ObZ0AYF1JoCJySk 6deHAs+CmwD1+TtjT/AsXuLtRe9MsjXPoHDSBkS6AAPt4aGWnBJnQ2iKNoFgFAWd0A u6xiY40RW9FmQ== 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, Asahi Lina , Martin Rodriguez Reboredo Subject: [PATCH v3 07/13] rust: init: add `..Zeroable::zeroed()` syntax for zeroing all missing fields Message-ID: <20230729090838.225225-8-benno.lossin@proton.me> In-Reply-To: <20230729090838.225225-1-benno.lossin@proton.me> References: <20230729090838.225225-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,T_SCC_BODY_TEXT_LINE, URIBL_BLOCKED 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: 1772752675574300214 X-GMAIL-MSGID: 1772752675574300214 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 Signed-off-by: Benno Lossin Reviewed-by: Gary Guo --- 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 Sat Jul 29 09:10:02 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 128098 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:918b:0:b0:3e4:2afc:c1 with SMTP id s11csp954743vqg; Sat, 29 Jul 2023 03:29:59 -0700 (PDT) X-Google-Smtp-Source: APBJJlFR/w8PhhNzxvsx0nrcVFmMiCcrFI7LEJfR9n43MlYuWB00exRrnfGWTl9yiGlZEsJW1sCZ X-Received: by 2002:a17:90a:c210:b0:267:f8f4:73ab with SMTP id e16-20020a17090ac21000b00267f8f473abmr5346241pjt.16.1690626598839; Sat, 29 Jul 2023 03:29:58 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1690626598; cv=none; d=google.com; s=arc-20160816; b=Oc7Edn4RT8y6JBnwFGEvJUXzASayK3pxtvIkuWpZ/5E9tDJ9HglW2bk1RPMjmOCcAP oR2NIaeS4WlPPxTvxrdPmp6xrtf3OevYCYTiS1bUhvkrxiYbKz/91+msgXF5MD5I4R46 ClHbJ/UR3hW6PiNQezi+rYmd6BjoagOObx277+4jyyIhMBC3UjmyRWR8l8Uz4Hop/cYp hTgkvzYgNafeW/PrHCpm9BapZ4Ztobb3YGJJX9lM/JF9OLZpg+cz0tmhIINBDtNEomFO 4o8RyOISw6c/eAZ7sL0b9ltUYReMRhKMBQM5j9rvIcyoQsTNtCSZdki3KQ85MtUAJ72s lRkw== 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=n0kp3TT0AEotHmbMlG5LKX11QJLhjQnwXfm8v2x0jbI=; fh=ahHPrvxY+ty2HIuIPh5QXslVmwB1wHeJjzGZ+GeRryw=; b=EDH+lOuzQ787hhifH5ZnWOqPANjHkb87FqBfSRi96NN1BcZlzxlY0NB/cnkpXoEUVu SyarNIR7TGhA/ibNNic3BLeHMMkJosV0ih3N0M/Ei1fuuu5rfLyQO6MhVwIZJiO/t6N4 OHd3sTAA5wQfGUH6i6ywTgo1bbYS+QlRFOlssAoOnZgBXyE99jLOQh55+1RirHsHBTGQ vH9mkii5DvjGqFgyDc/glWL4risit26+MYy9zGKU8cJsUhiLGFcIPoyIJ3DCe/tvszyc p9nVfpK3LJKSpNy0GMMS8B024n6lzeDTnAOvB6vi5seoOviab9WtABSe0PakRRw9dISZ bAug== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=STchfM9p; 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 nh10-20020a17090b364a00b00259b2afc651si5794164pjb.62.2023.07.29.03.29.44; Sat, 29 Jul 2023 03:29:58 -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=STchfM9p; 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 S231786AbjG2JK7 (ORCPT + 99 others); Sat, 29 Jul 2023 05:10:59 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40728 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231614AbjG2JKg (ORCPT ); Sat, 29 Jul 2023 05:10:36 -0400 Received: from mail-4322.protonmail.ch (mail-4322.protonmail.ch [185.70.43.22]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id F37844EE6 for ; Sat, 29 Jul 2023 02:10:12 -0700 (PDT) Date: Sat, 29 Jul 2023 09:10:02 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1690621810; x=1690881010; bh=n0kp3TT0AEotHmbMlG5LKX11QJLhjQnwXfm8v2x0jbI=; 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=STchfM9pMzNv1kegQLLu7D1J9AWizn4gPoirUYsWKhr3Jksyn56UM+e2jRaN6YvC3 OUy8eUIsZ0ynQuNAJ+G0dVniFI+6ZMOePtiwKjbvplgzrU1Lezy7lpc4TVh8k42GIh fYkEs2cUYit0vfMFa81Qz2hc6/GQx+eckF9Nt5pxFaqZgRVf8IwzXUarKWhy//6BLu 4IK2sSrlDTlxOKM+LE3mEwVsi5kQ1ZZNyln8cB5TxPJxt2bMgUpEyHmnirebwd48HG rAcHMsPiCJz1lea99+7BIWRW+ntM1qApbUpn9Kv3ACzn2XqSanlNZhafl5I3l8+5Ur ARZ2+sDGwVaYA== 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, Asahi Lina Subject: [PATCH v3 08/13] rust: init: Add functions to create array initializers Message-ID: <20230729090838.225225-9-benno.lossin@proton.me> In-Reply-To: <20230729090838.225225-1-benno.lossin@proton.me> References: <20230729090838.225225-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,T_SCC_BODY_TEXT_LINE, URIBL_BLOCKED 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: 1772750476559859385 X-GMAIL-MSGID: 1772750476559859385 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 Signed-off-by: Benno Lossin Reviewed-by: Martin Rodriguez Reboredo --- 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 | 86 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 86 insertions(+) diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index 460f808ebf84..af96d4acc26b 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -875,6 +875,92 @@ 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_000_000]>= Box::init::(init_array_from_fn(|i| i)).unwrap(); +/// assert_eq!(array.len(), 1_000_000_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::(); + 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. + match unsafe { init.__init(ptr) } { + Ok(()) => {} + Err(e) => { + // 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)) }; + return Err(e); + } + } + } + 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_000_000]>= +/// Arc::pin_init(pin_init_array_from_fn(|i| new_mutex!(i))).unwrap(); +/// assert_eq!(array.len(), 1_000_000_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::(); + 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 `__pinned_init` + // requirements. + match unsafe { init.__pinned_init(ptr) } { + Ok(()) => {} + Err(e) => { + // We now have to free every element that has been initialized before, since we + // have to abide by the drop guarantee. + // 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)) }; + return Err(e); + } + } + } + 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 Sat Jul 29 09:10:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 128092 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:918b:0:b0:3e4:2afc:c1 with SMTP id s11csp945933vqg; Sat, 29 Jul 2023 03:05:16 -0700 (PDT) X-Google-Smtp-Source: APBJJlELrPxLzrmlXwbws76jCK4hYi6MD3BzcycgwcNa63FA/4sAZVOB50hhKGiRuuh5+phTqXM3 X-Received: by 2002:a05:6a00:248b:b0:677:c5bf:dcc7 with SMTP id c11-20020a056a00248b00b00677c5bfdcc7mr6032617pfv.17.1690625116222; Sat, 29 Jul 2023 03:05:16 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1690625116; cv=none; d=google.com; s=arc-20160816; b=BUMhtvPx/2Txo4U8orlUjqvBX2ac2TLXX5poNW7n8aoPrHb/qtO77+vJM6JieLLYle 129VBYnUnVpPwn5A4B+Z2FmU/49PGCEs5Fno4wQ8rh1RI0VmRMHcp6zUYjFP6JmhnUx1 hx3MT8kMaa4EtY+aUzPswVVuvoDyiYagMeoTDe19XVgbgWOn5WfQtBNqL9kbNPISlZdh LKAJfPa0/d7hvdVNh5fSs8Dt0yor/IRhFcfe4553Fnc0TCvDQ6CJcDohN+NM+a8e2yNY 6tWOYttdw9ldGbkABGGndObF1yLiKyAI48d6E5pl4+xljelje7KOj3O8wMbDC09uNCx1 JkSg== 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=UwJBusNwPUw169oexSJli8hQ25g/5KFXHZuYaKqD2S8=; fh=MTk7MD/292FwJGz5jKS0PBOnpzkNxprDjhqM8t+E7nE=; b=hc68xqT7hwVfVRKQoyb4JzbUqvyZpld4KgH/bcnGYFKOx9K57WJIyS1NmUSkSfjHwe ij+RhAI3le3HCSPUtPFc6KiGuPniW7KWFgb/2F8Uc19IggpizW+iAShFSBYHFe6S1+mt CA7159345EzWHetgOjTBO/9kige0zrTygjMBts87EMyU2+AALf/NX2QtmjD/ahXEBy9B gJSU6wWgmQ+YvoCk0uUuU0a4wL2vU3hoAqJAcuzGaL9FoJ+Ck5i+VUmPZXw2BOJFL6XQ ivAeUrLwFxnlOYFQ1a3ir6ArgafgeS2UUabnOK7wQMsZzAifFNrOF8cfRC07s6/5ynLr n8+A== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=fuKNzDRX; 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 w11-20020a056a0014cb00b0066db06a5cf1si4697618pfu.43.2023.07.29.03.04.56; Sat, 29 Jul 2023 03:05: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=fuKNzDRX; 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 S231822AbjG2JLi (ORCPT + 99 others); Sat, 29 Jul 2023 05:11:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40938 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231527AbjG2JLS (ORCPT ); Sat, 29 Jul 2023 05:11:18 -0400 Received: from mail-4316.protonmail.ch (mail-4316.protonmail.ch [185.70.43.16]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 3B9E44C16; Sat, 29 Jul 2023 02:10:31 -0700 (PDT) Date: Sat, 29 Jul 2023 09:10:16 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1690621828; x=1690881028; bh=UwJBusNwPUw169oexSJli8hQ25g/5KFXHZuYaKqD2S8=; 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=fuKNzDRX36zsowd+EUph9dhtDnDJysdkESS1IJXuSmjveBiXsV9GIS8W43oLiWyU7 xFlXhDfDPs0wVGYIOY3g7ZJa4K/HOGEUs26DZQ1XHRSKEGzX15M7/hCprOzdTHUCOT 49O0DXRVorVyhmnSfj6GQ0x8/fNAUYYv6RjKiLNbYYCbeRxNzQaYZk7+wWK1hwH4oh X64VH9AL8qNQGVS744JUCgtU8lYnrjUidm1YLv5ZdKLTzuqyu3tHSj+95GvtghUozO XoyRLmBXrrYUeAEJkiCEbOv0z4QKptCptkAFxyuDWS1/+IG+74hb6TAfSifMPSG+Yz WMwSTaWMiuYcA== 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, Asahi Lina , Martin Rodriguez Reboredo Subject: [PATCH v3 09/13] rust: init: add support for arbitrary paths in init macros Message-ID: <20230729090838.225225-10-benno.lossin@proton.me> In-Reply-To: <20230729090838.225225-1-benno.lossin@proton.me> References: <20230729090838.225225-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,T_SCC_BODY_TEXT_LINE, URIBL_BLOCKED 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: 1772748921994213557 X-GMAIL-MSGID: 1772748921994213557 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 Signed-off-by: Benno Lossin Reviewed-by: Gary Guo --- 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 Sat Jul 29 09:10:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 128099 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:918b:0:b0:3e4:2afc:c1 with SMTP id s11csp959981vqg; Sat, 29 Jul 2023 03:47:03 -0700 (PDT) X-Google-Smtp-Source: APBJJlF727FPbjG6d0uiEHumAG+P3VwFsNYip2qT7n3MTOQAzspOpo7mnN6PPnQJzxXk0/MlXoIb X-Received: by 2002:a17:902:f7cb:b0:1b8:9b5e:6697 with SMTP id h11-20020a170902f7cb00b001b89b5e6697mr3615971plw.68.1690627622927; Sat, 29 Jul 2023 03:47:02 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1690627622; cv=none; d=google.com; s=arc-20160816; b=IWR/xXB5hsU4GfALjCylcV80QnG4EStSAf8gMbMtQyVrON1JsCAdg6MqM0om220Fh6 c4PJ2/VCYBabfzfcf20pedakGXT/VsRNSh8QWJpcC7hzyXpDmBtPHvRSzdJ+HVuxOegf xDQEsnk2ToPzX6k4TydGEDfuFZpLKgL6DM4/FLyWmFyiM4PA7OX5t7RDNDJjYi4Eeihi lHobhZN09QwQCAz0hgnE77RK9pKe+M+vutFqiImgSAoldzv4kYJEIfIiHcMDopa/2xUq itbuK6ODb9aOFFE5Q8BbUMZtAqU4AHC9ceCcIE/udTjoPWqAoyVgtdFUolh8Wan3sb/Y T6Hw== 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=3zNIMZmZNDCpyXxxyP7KXlpj+oRhkgVcL+Ru9AKEqMQ=; fh=qm1bOEYzVYZKL4fg86TgWb8D+QJA9mGpUhKFp2A6Xio=; b=HpEfwwsTQn0m667XS/4kY+RUCppi0IJZ9yS9PHInccJXnkWmMmYXyYtBXpnNvPQlrb rp1HeVzImCi61ofPhgHP9DwmxSxcmnj9Kv0g4OUH2VYaqWNrgSJHJLdCv/KLmzwDeJl+ QG+daxhWZru61jeVMu54yhrDk+ojG2sBEcKzGVnK0pD4MFpl7M2Zy6WqpUBlZOL7RiPn gMiw1veSx/9Bb9xRHTyOc8cYAr+6hffpVL9NZGqdPBWJG2iTw6KagYFW+xAM6Y+rKwfT OaILHBLxwQvDmEUwJJoDahAv8DAbt37CVygHPZTSPLFpCwVwyJ7UJN1DsU78byjyqyXI t4Zg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=chbVs6fH; 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 p4-20020a170902e74400b001b3d27ca12fsi4621920plf.207.2023.07.29.03.46.47; Sat, 29 Jul 2023 03:47:02 -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=chbVs6fH; 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 S231206AbjG2JLo (ORCPT + 99 others); Sat, 29 Jul 2023 05:11:44 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40728 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231693AbjG2JLU (ORCPT ); Sat, 29 Jul 2023 05:11:20 -0400 Received: from mail-4316.protonmail.ch (mail-4316.protonmail.ch [185.70.43.16]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D689B44BC for ; Sat, 29 Jul 2023 02:10:37 -0700 (PDT) Date: Sat, 29 Jul 2023 09:10:19 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1690621832; x=1690881032; bh=3zNIMZmZNDCpyXxxyP7KXlpj+oRhkgVcL+Ru9AKEqMQ=; 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=chbVs6fHFDVnXKLqa/IdGHFF5wg9kxo0llJBCweB/b7pRciP4kY9xe5QSS3DJ97WN uuwVujcl8aAnoN7sMarSEODG0XBsxPWGk9vkwzEf1TDMbgU3t0UkktB6ubMvudcaR3 BF98jn3lt4nCyIhWqxzhgqIWflFdHbSk1MQNDtq43mkoW3FgD+CFxTTmkmL/3nJqwZ 2dIBXYQJrjoe4V9Pv99c2YkGP75+1+LdHEUcsqT4XLwp18HuOtsubnoibAjy5VKiLb pZHaZwjcpy1ndewgQ6f1t361S+Hu83O7O2ERAQxw0mnZsFJnRg+CvcW2VwMXcrVKNE zzLMZTVZagUSQ== 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 Subject: [PATCH v3 10/13] rust: init: implement `Zeroable` for `UnsafeCell` and `Opaque` Message-ID: <20230729090838.225225-11-benno.lossin@proton.me> In-Reply-To: <20230729090838.225225-1-benno.lossin@proton.me> References: <20230729090838.225225-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,T_SCC_BODY_TEXT_LINE, URIBL_BLOCKED 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: 1772751549896776767 X-GMAIL-MSGID: 1772751549896776767 `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. Signed-off-by: Benno Lossin Reviewed-by: Martin Rodriguez Reboredo Reviewed-by: Gary Guo --- v2 -> v3: - also implement Zeroable for `UnsafeCell` when `T: Zeroable`, - use `impl_zeroable!` instead of `derive(Zeroable)`. rust/kernel/init.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs index af96d4acc26b..06ecab4901f2 100644 --- a/rust/kernel/init.rs +++ b/rust/kernel/init.rs @@ -212,10 +212,12 @@ use crate::{ error::{self, Error}, sync::UniqueArc, + types::Opaque, }; use alloc::boxed::Box; use core::{ alloc::AllocError, + cell::UnsafeCell, convert::Infallible, marker::PhantomData, mem::MaybeUninit, @@ -1157,6 +1159,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 Sat Jul 29 09:10:22 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 128083 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:918b:0:b0:3e4:2afc:c1 with SMTP id s11csp939942vqg; Sat, 29 Jul 2023 02:47:12 -0700 (PDT) X-Google-Smtp-Source: APBJJlESaQy8YR7SaeGtiEtmwW/gIS+EbQKH3QTehkKXyGIg1sNwSzAOml+BGoCAreyhHeVaSBrE X-Received: by 2002:a17:902:e892:b0:1bb:ab44:1957 with SMTP id w18-20020a170902e89200b001bbab441957mr5084617plg.28.1690624011698; Sat, 29 Jul 2023 02:46:51 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1690624011; cv=none; d=google.com; s=arc-20160816; b=R8Jpc6bvZT/syCuX3S4CGlafRQEpc8aX7Im/p4QRoXkxS2R6EYdn3hmyz6JZ26PXzi 8qvs1YQYsZ0RStML02cLqNhbhLBzVdY0Vdw1BANCSF/srLBnebuIV4d2gFbCq/PS7SJP 4v5tnTXdLrZ//EINRWjJucvVxchp6wZ1v+sTQtTLl6GbzJxzb98oYSP45lCUPrVEJR8m weOmRBuIryKY/CIpnK9ousrO6Gdt8DPwb03xFg4AsDP8nR+uqQrHyaEwVlo4NUU2pBKZ LhYxiZcGv8L9g69KXPeiyxlq/ajvL5UeqGYOVlON4b9nwzYsPWgHugRuoHTxW4zwFVes rmsQ== 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=AH0HIEGjoQqibf1kDSLrSuvQlmckx0/sN/Y3zMQ9l2E=; fh=Kxkq5MAR/ee06c4zNa7/ow9QmWBIyeCoT7WYYnSSoIA=; b=ssY3Qu5IwNpgStJQCK1u/DOA1qiyIwZlRg7K1QHhko8pLciypuCGaTYjuTvYLLmhxd aFimmG8PgRqOGWFjQEDN0fIV533Qxgg/EvJGD42ANWrd2G+/SQrcwlFpgKa+UJBBERhp IkORsv3CqiKSXIpo+/IjFsXYYf+o3BC56kr8gs5sK0n7QaQbo9J9ZqNH8MT00qV4YuoM 2jiOi+6TuYqIXELU6HMSRidWeRTF485yRZPNY96215G6E/z9UeZnA60f/yJMvjRcBspo 2WDDujXWQrgtk+WjlLzQEWT5suXCC4Oixbhe9rIWPG1viRFG+2MzmhPScTu+60jYaOgI 9Nzg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b="e6Ee/Ay2"; 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 h9-20020a170902680900b001badbe8e441si4198452plk.106.2023.07.29.02.46.38; Sat, 29 Jul 2023 02:46:51 -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="e6Ee/Ay2"; 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 S229871AbjG2JLw (ORCPT + 99 others); Sat, 29 Jul 2023 05:11:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40826 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231886AbjG2JLW (ORCPT ); Sat, 29 Jul 2023 05:11:22 -0400 Received: from mail-4322.protonmail.ch (mail-4322.protonmail.ch [185.70.43.22]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 1231249F3; Sat, 29 Jul 2023 02:10:44 -0700 (PDT) Date: Sat, 29 Jul 2023 09:10:22 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1690621836; x=1690881036; bh=AH0HIEGjoQqibf1kDSLrSuvQlmckx0/sN/Y3zMQ9l2E=; 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=e6Ee/Ay28m2aF8g71TkVLHYPgKrHIsI6ZnO0XItdUgFnAlfOZSA0C3ivHqZ7l19nR hbHmpw/U7YDSNwfQChTDKu2zRmAru/SNNYCkExVdJYg91XUqmdTL+Ioi8LoWSjVcLo r7PRiooEkosYRC95ou+HpyIJV+0Bk5JWKIYr2TR4Sv6lrPp851efgebomRNzFnWoEg e9BchDE0QgFYQJewCJ1Go702HyCVikozp1mDXtQ3LhGxmKlc2D22cQHjtjib7jR+Ky 0KetuWGDpxhVa3h6xC0QG9l7I6QmXKayDlv7WOVubrgXIRzgNhrEtHx//WiNnrTikG N+Hff4uUNhzjA== 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, Martin Rodriguez Reboredo Subject: [PATCH v3 11/13] rust: init: make `PinInit` a supertrait of `Init` Message-ID: <20230729090838.225225-12-benno.lossin@proton.me> In-Reply-To: <20230729090838.225225-1-benno.lossin@proton.me> References: <20230729090838.225225-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,T_SCC_BODY_TEXT_LINE, URIBL_BLOCKED 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: 1772747763602007417 X-GMAIL-MSGID: 1772747763602007417 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 Signed-off-by: Benno Lossin Reviewed-by: Gary Guo --- 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 06ecab4901f2..040dc9a5f9fd 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 @@ -971,6 +959,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 Sat Jul 29 09:10:35 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 128082 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:918b:0:b0:3e4:2afc:c1 with SMTP id s11csp939185vqg; Sat, 29 Jul 2023 02:44:19 -0700 (PDT) X-Google-Smtp-Source: APBJJlE4j1ZdGP7hHUTtP5HYNoSH/D4cP4lNY4MOx9+dYWulI+gpZDtP6G2oZfEJFTuaCuiM3Yke X-Received: by 2002:a17:903:22c1:b0:1b8:b2c6:7e8d with SMTP id y1-20020a17090322c100b001b8b2c67e8dmr5033490plg.66.1690623859259; Sat, 29 Jul 2023 02:44:19 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1690623859; cv=none; d=google.com; s=arc-20160816; b=fWxAoCG49uUv0q4LqHV21TGLONbAl+Oqul+lmmEkcYyXtkuBnVe0eyIuD8//LqupUS hlFzHbSOpr/bpCpwGFDigmD/wpqrta+Os6iNDsYGBV1pPDlq10DA3C37AiIyVMWnRm15 I+ioYD68xG1NSDO/t14Qg2FAncT+F/PYlgSwL0quvdgiDKJzVS4bDYFXFPQS0KZbODAk DLs0nRTiBttP6B0bY4C0METaqZ3zwCESlfIxIonZL5WZ1CKqoWDvkPFpVW8ERfR1vmsZ u4Aq37e50YVbHhjS8xtiLKTA73Y05kaDljdCabEthQM6FxkiLjI7bM/4a8v58aJgGk+e HU6w== 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=ir44Jd6eKvbhVWw3SrVOCnjRYoKyTsX6wUbiHNFNeuw=; fh=ahHPrvxY+ty2HIuIPh5QXslVmwB1wHeJjzGZ+GeRryw=; b=xKf6foGr8Vku9/TDvPgudb1o/n1CJQFbNquCvshkVR5aRdxw50ohEGtBrG1GWa+Xlu u2DRqRkFLcNjfkFBTmqiMumYwLW5Y9xAuMobyHfHu/UkFQzELZRoQQ9bfy5NyPIv8sub F0o2oDWdZhp/v7kiN5HpNu8bs8eTviSULMzsYk4uh7YN5v4krta9d0eDrtk/gsLUAGV4 Nv+qDjIZWRI2I/lpTNpacxz3NWM8Tx8MVSUHkd+modcoZhWffoaPJtk+5rKp3hAFJYD4 gRhwZu4uizdf92D0c8ttPKzD2Oy5EDicI61t1ogaXi1Oq9OrOnKp+6RG+J2Y5a8+u/eu MFFQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=protonmail header.b=QjdEGGh5; 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 g6-20020a1709026b4600b001a6ade4c8c2si4240927plt.142.2023.07.29.02.44.01; Sat, 29 Jul 2023 02:44:19 -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=QjdEGGh5; 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 S231728AbjG2JL4 (ORCPT + 99 others); Sat, 29 Jul 2023 05:11:56 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:40860 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231889AbjG2JLW (ORCPT ); Sat, 29 Jul 2023 05:11:22 -0400 Received: from mail-40131.protonmail.ch (mail-40131.protonmail.ch [185.70.40.131]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4CB8E49FA; Sat, 29 Jul 2023 02:10:45 -0700 (PDT) Date: Sat, 29 Jul 2023 09:10:35 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=protonmail; t=1690621839; x=1690881039; bh=ir44Jd6eKvbhVWw3SrVOCnjRYoKyTsX6wUbiHNFNeuw=; 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=QjdEGGh5iVrIYeObk69+J0k9U0sCzDsFr7ceKXxv2r9Wg9F5H7mEDwyhw2SK5qurt jmJZjDhWVdLGgHx8qvpKWo2qIaR2eAx+GVceWGoPN1wl+t6hdwdApda21/cWYfuNif sOhimMnwif9B/xSbrzKH9vG9pIr/WK+VHj84b4obztjCWEnER8AkAbMKorG+8Skp15 z/R53HOxat9HOzNJDXQKKye9CkYzyc4nJ2WHvMyn+y7Pide7esFKYLjtaP1FJznSgg JyfVx7EABTaA6ovrk9Z7QGHhdlGKh6dovJeqK7FIEksQ+v6U7p+0dh5PPemTjyWpbK yKkfjutqZGDRA== 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, Asahi Lina Subject: [PATCH v3 12/13] rust: init: add `{pin_}chain` functions to `{Pin}Init` Message-ID: <20230729090838.225225-13-benno.lossin@proton.me> In-Reply-To: <20230729090838.225225-1-benno.lossin@proton.me> References: <20230729090838.225225-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,T_SCC_BODY_TEXT_LINE, URIBL_BLOCKED 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: 1772747604140886922 X-GMAIL-MSGID: 1772747604140886922 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 Signed-off-by: Benno Lossin Reviewed-by: Martin Rodriguez Reboredo --- 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 040dc9a5f9fd..c1e70d150934 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 Sat Jul 29 09:10:39 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Benno Lossin X-Patchwork-Id: 128109 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:918b:0:b0:3e4:2afc:c1 with SMTP id s11csp982624vqg; Sat, 29 Jul 2023 04:48:05 -0700 (PDT) X-Google-Smtp-Source: APBJJlGRlK505BG4pkRfnfPKqTzBso+AyUlwtcOKtbFc3cROJYhMEn4yMsDEib04Lf5ZHdPAfr3r X-Received: by 2002:a17:906:530e:b0:988:f93:32e8 with SMTP id h14-20020a170906530e00b009880f9332e8mr1693312ejo.26.1690631284753; Sat, 29 Jul 2023 04:48:04 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1690631284; cv=none; d=google.com; s=arc-20160816; b=ZE35geLXaaXdQ6qeroOmwlCi4jeiLFEt0UFKitnM/ml8NQ4P8si0s73z8Vs6treN1r ScrBNGBjFIgdkCnDf0jyy8x57rOcjC9MANIlS/3POX9/kupWRA0UhAsCQdAHWE4VP0rI tk/XtqF9aUeuVvmh3MYQqKLsKFBPsZuLD8udIlOlyUxc6r6nDpdi+nifViFPjJ5ElslY EZFZpHNlXd5wsxeVBzvLP5LDC7nb4P6iA2iycyBUlZqmW2mqZ8RE8M7kkimVr9CRCJAG lWZAnwT6LU2hna93os9S6juw3dsLgRYyMH1IGhe1imyFCd95RzWnOyVLILoZouQg/ImO Zx/w== 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=NqVMCstXwFCJc3Zjw12hIZVzieormXCP1JejQiCIqQY=; fh=Kxkq5MAR/ee06c4zNa7/ow9QmWBIyeCoT7WYYnSSoIA=; b=q0Rt6SZbIgpUyWGXH2ywP1hhUnpZnn4hHdmxw5Hmq0wyLDlBu348yJIKx5dgcMG8qJ cVvq3mS3WydwEaR70l7XgZKG9rqsvHCvbY4NJjKpWAhr69WDLXEECtIKu8hhWqmqSVGj gOpEQZsaeq9OBdh+/wztQFYJEW1EvaQGcGzTyJaxLc4UxcJUfXa8SK4LkKO0vIH+KRZH Xnk6ErPlZR55RcDZAGi35fXlN9xLDhrYWSJ4EkICvunjJxlpkHWO7mCkBaSIPJed2h79 zxEaKY/GEFSMDIZPoLkslB/PJCagOLs+Twf3hlsloI01xKrk9+7ZGrE5PkGUYYZVMJY1 F2eA== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@proton.me header.s=h6xtbgrdufgatmda4763qs5g7i.protonmail header.b=CSgrr7X7; 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 q22-20020a17090622d600b0099bce8bd49bsi4523066eja.990.2023.07.29.04.47.38; Sat, 29 Jul 2023 04:48:04 -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=h6xtbgrdufgatmda4763qs5g7i.protonmail header.b=CSgrr7X7; 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 S231934AbjG2JMz (ORCPT + 99 others); Sat, 29 Jul 2023 05:12:55 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:42092 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229946AbjG2JMb (ORCPT ); Sat, 29 Jul 2023 05:12:31 -0400 Received: from mail-40134.protonmail.ch (mail-40134.protonmail.ch [185.70.40.134]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 71E3155AA for ; Sat, 29 Jul 2023 02:11:34 -0700 (PDT) Date: Sat, 29 Jul 2023 09:10:39 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=proton.me; s=h6xtbgrdufgatmda4763qs5g7i.protonmail; t=1690621850; x=1690881050; bh=NqVMCstXwFCJc3Zjw12hIZVzieormXCP1JejQiCIqQY=; 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=CSgrr7X7qKDx8kCzmGmznIJRnEFVnIoDRb7geMsB8UUD+Dz3jsVPHciqCnzNwGHfj VXejKX53cT3OwSEu8yXZ1hFbWUfSUdzjSaCTRIZPipFkR7so33LtdSPsxyUgZF1EJz t70bBoAP9UU2eU2NrwuCsyuS4OZgjDZWYxm5Pk9dT2qnxaZBNNg+zoEPYxmv953NMM iG++ms0jC6oZcxpIPz2rY3mwZUZKEKt3UV59cYoGtj8nwxN5sIZUMy3iH+1YSY0Ztx 84vC1YIIZLPgjG74o5lanRG1BSHRg/WIf4s9mc3CGP3QTyi+AVhPtCaBSNTkx00Zs9 wxtMjgpHOJJHg== 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, Martin Rodriguez Reboredo Subject: [PATCH v3 13/13] rust: init: update expanded macro explanation Message-ID: <20230729090838.225225-14-benno.lossin@proton.me> In-Reply-To: <20230729090838.225225-1-benno.lossin@proton.me> References: <20230729090838.225225-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,T_SCC_BODY_TEXT_LINE, URIBL_BLOCKED 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: 1772755389577055086 X-GMAIL-MSGID: 1772755389577055086 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 --- 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 {