Message ID | 20230517203119.3160435-4-aliceryhl@google.com |
---|---|
State | New |
Headers |
Return-Path: <linux-kernel-owner@vger.kernel.org> Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:b0ea:0:b0:3b6:4342:cba0 with SMTP id b10csp38883vqo; Wed, 17 May 2023 13:37:55 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ7osEJUWcq/AgIKrMNSvK40T6SYmImVwdhxTeU7AfsPZbiPPLWgY07AsjM7F5hmPfhyYC6a X-Received: by 2002:a05:6a00:a05:b0:64c:c5f9:152a with SMTP id p5-20020a056a000a0500b0064cc5f9152amr1392166pfh.23.1684355875052; Wed, 17 May 2023 13:37:55 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1684355875; cv=none; d=google.com; s=arc-20160816; b=XLYZImySQ4bvFhvh3C4KEpUukiSxNd/4StSnFb3FlqnjrY+EDm6Z33f50bsoJfr7x4 4fxViR9cf+Uau3ejf9o4WZwau4WsGoBqJ1GS8IooDAp2opdAIthfIDeCN3O9frchmicc GUEUoI+UxDB0sHlcyvBh2lmKiDv/T0+teGW+hjngo6Px2Et10r8IZlv+/Hsfz2t74JwM jSUVQGGk4pfQDHYKLKfCxMKRZx/QRmiJ0Fk4uBXE2GnvUIK1tM4h0bd6GUvvup7D+tb7 26OA8Hytp7AM6Z9VOaurhJOqJsZ/LlVCIiP07Ma4noXLmcG9rcOf2i5V9L2lwi3Gej06 GSTA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:message-id:references :mime-version:in-reply-to:date:dkim-signature; bh=1m2NIZThmeCBayz0liS/tGETC/9gj7ELeSxPKaC6Yh8=; b=ZMixPLuyRSuvpd/ZybEl3FivnVpiMLUkMQaB90UB6x23pEOY/E1QJFoDx+nlH3etmi AGwG/m7mjZo5utjJQkGZfrJrqk7FdV3fP0S9ceor/SPlmYuH1jyA5Y5L7mbUi9GMNKt/ 7c4Dm4W1gweuayYihg/ofWrSxmPspih/KomG0NQi79wW4PhcZkrIiWQCbGrOehRnFedb j+PsICfN9TAIMmB8jQwvko7eOwg72z5yD04mfe150JRlZxz4kAe7hhJDXNmpIHGdUwec W9mEa0sR5O6a7HWd0cGezrE19NDzIe+/INPMxxdzFj9FOm7FZOTK1Ky5xkPZ+ElsKYC0 j3Rg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20221208 header.b="BnGU93/l"; 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=REJECT sp=REJECT dis=NONE) header.from=google.com Received: from out1.vger.email (out1.vger.email. [2620:137:e000::1:20]) by mx.google.com with ESMTP id m12-20020a633f0c000000b00528a60ab393si21662381pga.314.2023.05.17.13.37.14; Wed, 17 May 2023 13:37: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=@google.com header.s=20221208 header.b="BnGU93/l"; 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=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229785AbjEQUbl (ORCPT <rfc822;abdi.embedded@gmail.com> + 99 others); Wed, 17 May 2023 16:31:41 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:56204 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229514AbjEQUbc (ORCPT <rfc822;linux-kernel@vger.kernel.org>); Wed, 17 May 2023 16:31:32 -0400 Received: from mail-ej1-x64a.google.com (mail-ej1-x64a.google.com [IPv6:2a00:1450:4864:20::64a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4203F30DE for <linux-kernel@vger.kernel.org>; Wed, 17 May 2023 13:31:30 -0700 (PDT) Received: by mail-ej1-x64a.google.com with SMTP id a640c23a62f3a-969f24626fbso68332766b.0 for <linux-kernel@vger.kernel.org>; Wed, 17 May 2023 13:31:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20221208; t=1684355489; x=1686947489; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=1m2NIZThmeCBayz0liS/tGETC/9gj7ELeSxPKaC6Yh8=; b=BnGU93/l6zgPX74n1BWhPYto1+DmrAaRJmje1ktjtxvvMVe5/ufxtkwfhHuGWoWdhk sTD0ze0cB+pBIMUh0eC20QGkHMtXngl1qheah8sXtY3xJUm4p2C/jy+3agGa/nXWMaBI cjXQYFgEMFGWjq0AK5WF2hb3rxsDq2qWXzEhoziYVq2kaalDDx9UX4nj4NQFwlvAumU+ X8d+B3yeLFzGBO3Z8qQeVsV6ID5+4q96aaX8eg1fnDPAsOkB3kNDdNSo2o+kmZH4J8aw 91bpLwB4E7EfRot8PStAuoblk4n4X2GSjicq/7i8QVuKgUhHDcQKGNJycsRIbr49laKs oJ7g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1684355489; x=1686947489; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=1m2NIZThmeCBayz0liS/tGETC/9gj7ELeSxPKaC6Yh8=; b=Zl71juEiWgWapMieElwxyxvVlTgo7rZXGmSnDEl5iVUZUtXdGaJ0J8wium9eKnvjJG l8WIx8E+Y3+NYHhEDMO/JVB66nrlztT+q48BR5WxYF/2jh0RQPfYVSZBdZmLSWZEr5Nc pww5aVjUiac5OGx9EIs5vG0djJ6WUaIzm95Kku7G5cLi0mZ3Tc7kWQpD3n1G7eoO3RcE Yq85DoQVOkz7yNTdIxOtrByHjwC19OxQH3R24ApRTq4wHMfPbSLtNfHBJndSpW9HH1JG 7JwVs8neLGmiMSNeO38kZX3p/DbCGdZTg5uRF7VmjyIp0WNgg1OCeovMfmWeu6/KArk3 TYhA== X-Gm-Message-State: AC+VfDwxCnQWukm2fhCOSsmlU2PCqGADf9kO6U3gMSsIpj9DlMBSx9Pp /RyHxkWmBGaeM5NCnG9a8zaXCFsgoOFsjTU= X-Received: from aliceryhl.c.googlers.com ([fda3:e722:ac3:cc00:31:98fb:c0a8:6c8]) (user=aliceryhl job=sendgmr) by 2002:a17:907:2bf5:b0:94e:dcd5:2429 with SMTP id gv53-20020a1709072bf500b0094edcd52429mr1413196ejc.3.1684355488912; Wed, 17 May 2023 13:31:28 -0700 (PDT) Date: Wed, 17 May 2023 20:31:15 +0000 In-Reply-To: <20230517203119.3160435-1-aliceryhl@google.com> Mime-Version: 1.0 References: <20230517203119.3160435-1-aliceryhl@google.com> X-Mailer: git-send-email 2.40.1.606.ga4b1b128d6-goog Message-ID: <20230517203119.3160435-4-aliceryhl@google.com> Subject: [PATCH v1 3/7] rust: sync: add `Arc::{from_raw, into_raw}` From: Alice Ryhl <aliceryhl@google.com> To: rust-for-linux@vger.kernel.org Cc: Miguel Ojeda <ojeda@kernel.org>, Wedson Almeida Filho <wedsonaf@gmail.com>, Tejun Heo <tj@kernel.org>, Lai Jiangshan <jiangshanlai@gmail.com>, Alex Gaynor <alex.gaynor@gmail.com>, Boqun Feng <boqun.feng@gmail.com>, Gary Guo <gary@garyguo.net>, " =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= " <bjorn3_gh@protonmail.com>, Benno Lossin <benno.lossin@proton.me>, Alice Ryhl <aliceryhl@google.com>, linux-kernel@vger.kernel.org, patches@lists.linux.dev Content-Type: text/plain; charset="UTF-8" X-Spam-Status: No, score=-9.6 required=5.0 tests=BAYES_00,DKIMWL_WL_MED, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,RCVD_IN_DNSWL_NONE, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE,URIBL_BLOCKED, USER_IN_DEF_DKIM_WL 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: <linux-kernel.vger.kernel.org> X-Mailing-List: linux-kernel@vger.kernel.org X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1766175146251007014?= X-GMAIL-MSGID: =?utf-8?q?1766175146251007014?= |
Series |
Bindings for the workqueue
|
|
Commit Message
Alice Ryhl
May 17, 2023, 8:31 p.m. UTC
From: Wedson Almeida Filho <walmeida@microsoft.com> These methods can be used to turn an `Arc` into a raw pointer and back, in a way that preserves the metadata for fat pointers. This is done using the unstable ptr_metadata feature [1]. However, it could also be done using the unstable pointer_byte_offsets feature [2], which is likely to have a shorter path to stabilization than ptr_metadata. Link: https://github.com/rust-lang/rust/issues/81513 [1] Link: https://github.com/rust-lang/rust/issues/96283 [2] Signed-off-by: Wedson Almeida Filho <walmeida@microsoft.com> Co-developed-by: Alice Ryhl <aliceryhl@google.com> Signed-off-by: Alice Ryhl <aliceryhl@google.com> --- rust/kernel/lib.rs | 1 + rust/kernel/sync/arc.rs | 44 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+)
Comments
On 5/17/23 17:31, Alice Ryhl wrote: > From: Wedson Almeida Filho <walmeida@microsoft.com> > > These methods can be used to turn an `Arc` into a raw pointer and back, > in a way that preserves the metadata for fat pointers. > > This is done using the unstable ptr_metadata feature [1]. However, it > could also be done using the unstable pointer_byte_offsets feature [2], > which is likely to have a shorter path to stabilization than > ptr_metadata. > > Link: https://github.com/rust-lang/rust/issues/81513 [1] > Link: https://github.com/rust-lang/rust/issues/96283 [2] > Signed-off-by: Wedson Almeida Filho <walmeida@microsoft.com> > Co-developed-by: Alice Ryhl <aliceryhl@google.com> > Signed-off-by: Alice Ryhl <aliceryhl@google.com> > --- > [...] Reviewed-by: Martin Rodriguez Reboredo <yakoyoku@gmail.com>
On Wed, 17 May 2023 20:31:15 +0000 Alice Ryhl <aliceryhl@google.com> wrote: > From: Wedson Almeida Filho <walmeida@microsoft.com> > > These methods can be used to turn an `Arc` into a raw pointer and back, > in a way that preserves the metadata for fat pointers. > > This is done using the unstable ptr_metadata feature [1]. However, it > could also be done using the unstable pointer_byte_offsets feature [2], > which is likely to have a shorter path to stabilization than > ptr_metadata. > > Link: https://github.com/rust-lang/rust/issues/81513 [1] > Link: https://github.com/rust-lang/rust/issues/96283 [2] > Signed-off-by: Wedson Almeida Filho <walmeida@microsoft.com> > Co-developed-by: Alice Ryhl <aliceryhl@google.com> > Signed-off-by: Alice Ryhl <aliceryhl@google.com> > --- > rust/kernel/lib.rs | 1 + > rust/kernel/sync/arc.rs | 44 +++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 45 insertions(+) > > diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs > index cdf9fe999328..82854c86e65d 100644 > --- a/rust/kernel/lib.rs > +++ b/rust/kernel/lib.rs > @@ -22,6 +22,7 @@ > #![feature(generic_associated_types)] > #![feature(new_uninit)] > #![feature(pin_macro)] > +#![feature(ptr_metadata)] > #![feature(receiver_trait)] > #![feature(unsize)] > > diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs > index e6d206242465..7c55a9178dfb 100644 > --- a/rust/kernel/sync/arc.rs > +++ b/rust/kernel/sync/arc.rs > @@ -210,6 +210,50 @@ impl<T: ?Sized> Arc<T> { > } > } > > + /// Convert the [`Arc`] into a raw pointer. > + /// > + /// The raw pointer has ownership of the refcount that this Arc object owned. > + pub fn into_raw(self) -> *const T { > + let ptr = self.ptr.as_ptr(); > + core::mem::forget(self); > + // SAFETY: The pointer is valid. > + unsafe { core::ptr::addr_of!((*ptr).data) } > + } > + > + /// Recreates an [`Arc`] instance previously deconstructed via [`Arc::into_raw`]. > + /// > + /// This code relies on the `repr(C)` layout of structs as described in > + /// <https://doc.rust-lang.org/reference/type-layout.html#reprc-structs>. > + /// > + /// # Safety > + /// > + /// `ptr` must have been returned by a previous call to [`Arc::into_raw`]. Additionally, it > + /// can only be called once for each previous call to [`Arc::into_raw`]. > + pub unsafe fn from_raw(ptr: *const T) -> Self { > + // SAFETY: The safety requirement ensures that the pointer is valid. > + let val_align = core::mem::align_of_val(unsafe { &*ptr }); > + let refcount_size = core::mem::size_of::<Opaque<bindings::refcount_t>>(); > + > + // Use the `repr(C)` algorithm to compute the offset of `data` in `ArcInner`. > + // > + // Pseudo-code for the `#[repr(C)]` algorithm can be found here: > + // <https://doc.rust-lang.org/reference/type-layout.html#reprc-structs> > + let mut val_offset = refcount_size; > + let val_misalign = val_offset % val_align; > + if val_misalign > 0 { > + val_offset += val_align - val_misalign; > + } Given the layout of the whole ArcInner can be calculated as Layout::new::<bindings::refcount_t>().extend(Layout::for_value(&*ptr)).unwrap_unchecked().0.pad_to_align() The offset of `data` could be more intuitively calculated by Layout::new::<bindings::refcount_t>().extend(Layout::for_value(&*ptr)).unwrap_unchecked().1 or Layout::new::<bindings::refcount_t>().align_to(val_align).unwrap_unchecked().pad_to_align().size() Best, Gary
Alice Ryhl <aliceryhl@google.com> writes: > From: Wedson Almeida Filho <walmeida@microsoft.com> > > These methods can be used to turn an `Arc` into a raw pointer and back, > in a way that preserves the metadata for fat pointers. > > This is done using the unstable ptr_metadata feature [1]. However, it > could also be done using the unstable pointer_byte_offsets feature [2], > which is likely to have a shorter path to stabilization than > ptr_metadata. > > Link: https://github.com/rust-lang/rust/issues/81513 [1] > Link: https://github.com/rust-lang/rust/issues/96283 [2] > Signed-off-by: Wedson Almeida Filho <walmeida@microsoft.com> > Co-developed-by: Alice Ryhl <aliceryhl@google.com> > Signed-off-by: Alice Ryhl <aliceryhl@google.com> > --- > rust/kernel/lib.rs | 1 + > rust/kernel/sync/arc.rs | 44 +++++++++++++++++++++++++++++++++++++++++ > 2 files changed, 45 insertions(+) > > diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs > index cdf9fe999328..82854c86e65d 100644 > --- a/rust/kernel/lib.rs > +++ b/rust/kernel/lib.rs > @@ -22,6 +22,7 @@ > #![feature(generic_associated_types)] > #![feature(new_uninit)] > #![feature(pin_macro)] > +#![feature(ptr_metadata)] > #![feature(receiver_trait)] > #![feature(unsize)] > > diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs > index e6d206242465..7c55a9178dfb 100644 > --- a/rust/kernel/sync/arc.rs > +++ b/rust/kernel/sync/arc.rs > @@ -210,6 +210,50 @@ impl<T: ?Sized> Arc<T> { > } > } > > + /// Convert the [`Arc`] into a raw pointer. > + /// > + /// The raw pointer has ownership of the refcount that this Arc object owned. > + pub fn into_raw(self) -> *const T { > + let ptr = self.ptr.as_ptr(); > + core::mem::forget(self); > + // SAFETY: The pointer is valid. > + unsafe { core::ptr::addr_of!((*ptr).data) } > + } > + > + /// Recreates an [`Arc`] instance previously deconstructed via [`Arc::into_raw`]. > + /// > + /// This code relies on the `repr(C)` layout of structs as described in > + /// <https://doc.rust-lang.org/reference/type-layout.html#reprc-structs>. > + /// > + /// # Safety > + /// > + /// `ptr` must have been returned by a previous call to [`Arc::into_raw`]. Additionally, it > + /// can only be called once for each previous call to [`Arc::into_raw`]. > + pub unsafe fn from_raw(ptr: *const T) -> Self { > + // SAFETY: The safety requirement ensures that the pointer is valid. > + let val_align = core::mem::align_of_val(unsafe { &*ptr }); > + let refcount_size = core::mem::size_of::<Opaque<bindings::refcount_t>>(); > + > + // Use the `repr(C)` algorithm to compute the offset of `data` in `ArcInner`. > + // > + // Pseudo-code for the `#[repr(C)]` algorithm can be found here: > + // <https://doc.rust-lang.org/reference/type-layout.html#reprc-structs> > + let mut val_offset = refcount_size; > + let val_misalign = val_offset % val_align; > + if val_misalign > 0 { > + val_offset += val_align - val_misalign; > + } > + > + // This preserves the metadata in the pointer, if any. > + let metadata = core::ptr::metadata(ptr as *const ArcInner<T>); I can't follow this. How does this work? `ptr` was for field `inner.data: T`, but we are casting to `ArcInner<T>`. > + let ptr = (ptr as *mut u8).wrapping_sub(val_offset) as *mut (); > + let ptr = core::ptr::from_raw_parts_mut(ptr, metadata); Metadata was obtained from a pointer pointing to `inner.data`, we then move it back to beginning of `ArcInner<T>` and then reconstruct the potentially fat pointer with metadata from the pointer to `T`? How can this be right? BR Andreas > + > + // SAFETY: By the safety requirements we know that `ptr` came from `Arc::into_raw`, so the > + // reference count held then will be owned by the new `Arc` object. > + unsafe { Self::from_inner(NonNull::new_unchecked(ptr)) } > + } > + > /// Returns an [`ArcBorrow`] from the given [`Arc`]. > /// > /// This is useful when the argument of a function call is an [`ArcBorrow`] (e.g., in a method
Andreas Hindborg <nmi@metaspace.dk> writes: > Alice Ryhl <aliceryhl@google.com> writes: >> + // This preserves the metadata in the pointer, if any. >> + let metadata = core::ptr::metadata(ptr as *const ArcInner<T>); > > I can't follow this. How does this work? `ptr` was for field > `inner.data: T`, but we are casting to `ArcInner<T>`. > >> + let ptr = (ptr as *mut u8).wrapping_sub(val_offset) as *mut (); >> + let ptr = core::ptr::from_raw_parts_mut(ptr, metadata); > > Metadata was obtained from a pointer pointing to `inner.data`, we then > move it back to beginning of `ArcInner<T>` and then reconstruct the > potentially fat pointer with metadata from the pointer to `T`? How can > this be right? The metadata of a struct is always the metadata of its last field, so both `*mut T` and `*mut ArcInner<T>` have the same metadata. Because of that, moving the metadata over from one type to the other is ok. The reason that I cast to an `ArcInner<T>` pointer before calling `metadata` is because I get a type mismatch otherwise for the metadata, since the compiler doesn't unify the metadata types when the type is generic. Alice
Gary Guo <gary@garyguo.net> writes: > On Wed, 17 May 2023 20:31:15 +0000 > Alice Ryhl <aliceryhl@google.com> wrote: >> + /// Recreates an [`Arc`] instance previously deconstructed via [`Arc::into_raw`]. >> + /// >> + /// This code relies on the `repr(C)` layout of structs as described in >> + /// <https://doc.rust-lang.org/reference/type-layout.html#reprc-structs>. >> + /// >> + /// # Safety >> + /// >> + /// `ptr` must have been returned by a previous call to [`Arc::into_raw`]. Additionally, it >> + /// can only be called once for each previous call to [`Arc::into_raw`]. >> + pub unsafe fn from_raw(ptr: *const T) -> Self { >> + // SAFETY: The safety requirement ensures that the pointer is valid. >> + let val_align = core::mem::align_of_val(unsafe { &*ptr }); >> + let refcount_size = core::mem::size_of::<Opaque<bindings::refcount_t>>(); >> + >> + // Use the `repr(C)` algorithm to compute the offset of `data` in `ArcInner`. >> + // >> + // Pseudo-code for the `#[repr(C)]` algorithm can be found here: >> + // <https://doc.rust-lang.org/reference/type-layout.html#reprc-structs> >> + let mut val_offset = refcount_size; >> + let val_misalign = val_offset % val_align; >> + if val_misalign > 0 { >> + val_offset += val_align - val_misalign; >> + } > > Given the layout of the whole ArcInner can be calculated as > > Layout::new::<bindings::refcount_t>().extend(Layout::for_value(&*ptr)).unwrap_unchecked().0.pad_to_align() > > The offset of `data` could be more intuitively calculated by > > Layout::new::<bindings::refcount_t>().extend(Layout::for_value(&*ptr)).unwrap_unchecked().1 > > or > > Layout::new::<bindings::refcount_t>().align_to(val_align).unwrap_unchecked().pad_to_align().size() I'm not a big fan of the `pad_to_align` version (which is also what the rust branch uses), but I like the version you posted with `extend`, and I agree that it is clear and intuitive. I will use that in the next version of the patchset. Thanks for the suggestion. Alice
Alice Ryhl <aliceryhl@google.com> writes: > Andreas Hindborg <nmi@metaspace.dk> writes: >> Alice Ryhl <aliceryhl@google.com> writes: >>> + // This preserves the metadata in the pointer, if any. >>> + let metadata = core::ptr::metadata(ptr as *const ArcInner<T>); >> >> I can't follow this. How does this work? `ptr` was for field >> `inner.data: T`, but we are casting to `ArcInner<T>`. >> >>> + let ptr = (ptr as *mut u8).wrapping_sub(val_offset) as *mut (); >>> + let ptr = core::ptr::from_raw_parts_mut(ptr, metadata); >> >> Metadata was obtained from a pointer pointing to `inner.data`, we then >> move it back to beginning of `ArcInner<T>` and then reconstruct the >> potentially fat pointer with metadata from the pointer to `T`? How can >> this be right? > > The metadata of a struct is always the metadata of its last field, so > both `*mut T` and `*mut ArcInner<T>` have the same metadata. Because of > that, moving the metadata over from one type to the other is ok. > > The reason that I cast to an `ArcInner<T>` pointer before calling > `metadata` is because I get a type mismatch otherwise for the metadata, > since the compiler doesn't unify the metadata types when the type is > generic. OK, cool. In that case, since this is common knowledge (is it?), could you maybe include a link to the relevant documentation, or a comment indicating why this is OK? BR Andreas
On Thu, 25 May 2023 09:45:29 +0200 Andreas Hindborg <nmi@metaspace.dk> wrote: > Alice Ryhl <aliceryhl@google.com> writes: > > > Andreas Hindborg <nmi@metaspace.dk> writes: > >> Alice Ryhl <aliceryhl@google.com> writes: > >>> + // This preserves the metadata in the pointer, if any. > >>> + let metadata = core::ptr::metadata(ptr as *const ArcInner<T>); > >> > >> I can't follow this. How does this work? `ptr` was for field > >> `inner.data: T`, but we are casting to `ArcInner<T>`. > >> > >>> + let ptr = (ptr as *mut u8).wrapping_sub(val_offset) as *mut (); > >>> + let ptr = core::ptr::from_raw_parts_mut(ptr, metadata); > >> > >> Metadata was obtained from a pointer pointing to `inner.data`, we then > >> move it back to beginning of `ArcInner<T>` and then reconstruct the > >> potentially fat pointer with metadata from the pointer to `T`? How can > >> this be right? > > > > The metadata of a struct is always the metadata of its last field, so > > both `*mut T` and `*mut ArcInner<T>` have the same metadata. Because of > > that, moving the metadata over from one type to the other is ok. > > > > The reason that I cast to an `ArcInner<T>` pointer before calling > > `metadata` is because I get a type mismatch otherwise for the metadata, > > since the compiler doesn't unify the metadata types when the type is > > generic. > > OK, cool. In that case, since this is common knowledge (is it?), > could you maybe include a link to the relevant documentation, or a > comment indicating why this is OK? > > BR Andreas This is documented in the doc of Pointee trait: https://doc.rust-lang.org/std/ptr/trait.Pointee.html > For structs whose last field is a DST, metadata is the metadata for the last field Best, Gary
Gary Guo <gary@garyguo.net> writes: > On Thu, 25 May 2023 09:45:29 +0200 > Andreas Hindborg <nmi@metaspace.dk> wrote: > >> Alice Ryhl <aliceryhl@google.com> writes: >> >> > Andreas Hindborg <nmi@metaspace.dk> writes: >> >> Alice Ryhl <aliceryhl@google.com> writes: >> >>> + // This preserves the metadata in the pointer, if any. >> >>> + let metadata = core::ptr::metadata(ptr as *const ArcInner<T>); >> >> >> >> I can't follow this. How does this work? `ptr` was for field >> >> `inner.data: T`, but we are casting to `ArcInner<T>`. >> >> >> >>> + let ptr = (ptr as *mut u8).wrapping_sub(val_offset) as *mut (); >> >>> + let ptr = core::ptr::from_raw_parts_mut(ptr, metadata); >> >> >> >> Metadata was obtained from a pointer pointing to `inner.data`, we then >> >> move it back to beginning of `ArcInner<T>` and then reconstruct the >> >> potentially fat pointer with metadata from the pointer to `T`? How can >> >> this be right? >> > >> > The metadata of a struct is always the metadata of its last field, so >> > both `*mut T` and `*mut ArcInner<T>` have the same metadata. Because of >> > that, moving the metadata over from one type to the other is ok. >> > >> > The reason that I cast to an `ArcInner<T>` pointer before calling >> > `metadata` is because I get a type mismatch otherwise for the metadata, >> > since the compiler doesn't unify the metadata types when the type is >> > generic. >> >> OK, cool. In that case, since this is common knowledge (is it?), >> could you maybe include a link to the relevant documentation, or a >> comment indicating why this is OK? >> >> BR Andreas > > This is documented in the doc of Pointee trait: > > https://doc.rust-lang.org/std/ptr/trait.Pointee.html Nice. I think I forgot a _not_ in my last message. I think it would be nice to add a comment with a link to this documentation and perhaps a note as to why this works. BR Andreas
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index cdf9fe999328..82854c86e65d 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -22,6 +22,7 @@ #![feature(generic_associated_types)] #![feature(new_uninit)] #![feature(pin_macro)] +#![feature(ptr_metadata)] #![feature(receiver_trait)] #![feature(unsize)] diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index e6d206242465..7c55a9178dfb 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -210,6 +210,50 @@ impl<T: ?Sized> Arc<T> { } } + /// Convert the [`Arc`] into a raw pointer. + /// + /// The raw pointer has ownership of the refcount that this Arc object owned. + pub fn into_raw(self) -> *const T { + let ptr = self.ptr.as_ptr(); + core::mem::forget(self); + // SAFETY: The pointer is valid. + unsafe { core::ptr::addr_of!((*ptr).data) } + } + + /// Recreates an [`Arc`] instance previously deconstructed via [`Arc::into_raw`]. + /// + /// This code relies on the `repr(C)` layout of structs as described in + /// <https://doc.rust-lang.org/reference/type-layout.html#reprc-structs>. + /// + /// # Safety + /// + /// `ptr` must have been returned by a previous call to [`Arc::into_raw`]. Additionally, it + /// can only be called once for each previous call to [`Arc::into_raw`]. + pub unsafe fn from_raw(ptr: *const T) -> Self { + // SAFETY: The safety requirement ensures that the pointer is valid. + let val_align = core::mem::align_of_val(unsafe { &*ptr }); + let refcount_size = core::mem::size_of::<Opaque<bindings::refcount_t>>(); + + // Use the `repr(C)` algorithm to compute the offset of `data` in `ArcInner`. + // + // Pseudo-code for the `#[repr(C)]` algorithm can be found here: + // <https://doc.rust-lang.org/reference/type-layout.html#reprc-structs> + let mut val_offset = refcount_size; + let val_misalign = val_offset % val_align; + if val_misalign > 0 { + val_offset += val_align - val_misalign; + } + + // This preserves the metadata in the pointer, if any. + let metadata = core::ptr::metadata(ptr as *const ArcInner<T>); + let ptr = (ptr as *mut u8).wrapping_sub(val_offset) as *mut (); + let ptr = core::ptr::from_raw_parts_mut(ptr, metadata); + + // SAFETY: By the safety requirements we know that `ptr` came from `Arc::into_raw`, so the + // reference count held then will be owned by the new `Arc` object. + unsafe { Self::from_inner(NonNull::new_unchecked(ptr)) } + } + /// Returns an [`ArcBorrow`] from the given [`Arc`]. /// /// This is useful when the argument of a function call is an [`ArcBorrow`] (e.g., in a method