From patchwork Mon Aug 5 15:19:27 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Danilo Krummrich X-Patchwork-Id: 13753717 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 1A340C3DA4A for ; Mon, 5 Aug 2024 15:21:05 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id A12E56B009D; Mon, 5 Aug 2024 11:21:04 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 9BFD36B009E; Mon, 5 Aug 2024 11:21:04 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 8395C6B009F; Mon, 5 Aug 2024 11:21:04 -0400 (EDT) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0014.hostedemail.com [216.40.44.14]) by kanga.kvack.org (Postfix) with ESMTP id 667E86B009D for ; Mon, 5 Aug 2024 11:21:04 -0400 (EDT) Received: from smtpin26.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay01.hostedemail.com (Postfix) with ESMTP id 0B8E71C565D for ; Mon, 5 Aug 2024 15:21:04 +0000 (UTC) X-FDA: 82418554848.26.016F20B Received: from sin.source.kernel.org (sin.source.kernel.org [145.40.73.55]) by imf24.hostedemail.com (Postfix) with ESMTP id 8C21318000D for ; Mon, 5 Aug 2024 15:21:01 +0000 (UTC) Authentication-Results: imf24.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b="cdxAs5b/"; spf=pass (imf24.hostedemail.com: domain of dakr@kernel.org designates 145.40.73.55 as permitted sender) smtp.mailfrom=dakr@kernel.org; dmarc=pass (policy=none) header.from=kernel.org ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1722871213; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=7PFvN6+7DtHc+JrqwPEjPxGffSm5k3GRSxPndbOvRG8=; b=dIeGt73VV0mgmyxPszMkQmsVRJnJOzb9N4WJp4EugYIQHc2/ivZVqFKDMLOwmreyELag1I spywH/GOJ2hDdIfS74yuyPUgZ5xINac2Hm+GqsXipnxaMDN6wMTrEzGaJMP/OEnTKJFn7Z PZuxo5FUEL2UcXjmzVU8fIVm1ML9WhI= ARC-Authentication-Results: i=1; imf24.hostedemail.com; dkim=pass header.d=kernel.org header.s=k20201202 header.b="cdxAs5b/"; spf=pass (imf24.hostedemail.com: domain of dakr@kernel.org designates 145.40.73.55 as permitted sender) smtp.mailfrom=dakr@kernel.org; dmarc=pass (policy=none) header.from=kernel.org ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1722871213; a=rsa-sha256; cv=none; b=wJjIt7kpe7bcZX4ZwLLVQpiVPOBYVYIzexCKFMRVmOn1te97hb6wHeeqdbLUhMVh7QLk+T ZKtDtxRFoqUSaODtR7gK8ZOILgs9/1m/4pEccQtjt0A/E3p/lsr6+LbuQdmk3m+hFc8jW9 sEe34pyTDl50KuO9oqjjSyHFfWT2SCc= Received: from smtp.kernel.org (transwarp.subspace.kernel.org [100.75.92.58]) by sin.source.kernel.org (Postfix) with ESMTP id 6E863CE0ACC; Mon, 5 Aug 2024 15:20:58 +0000 (UTC) Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9C595C32782; Mon, 5 Aug 2024 15:20:52 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1722871257; bh=rMcjDrrKtW/xMLE5lbZxePxiklFMyzPsbOBl2rb1EqA=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=cdxAs5b/1Fe6xH8UKlGLdCCUCLDyjtSIBAnMG1ZUwkJr+9PDvew0haUEFRz6oVaaY +YuEuWuCcXfnTBKs4xHAToRDnUf+9uqy7/Flc/5TavUzriCPgQ6cE8RHHYwNVHox5S 8pOVIj6lILYgorP6kthArTsoN8FhBOSaAEkHfEuifWjQ2cAP3jhSPE6FBgDOyBazpN EmuPcKnqbrOByXqFZeoLTp9fUbm58JnaZdJwXpoDJKzCESgWuoaMkd217KtrD6alyI zO1Qajazexhllns3D4lxkOtexDp13fjM7Xg13mYjgtox/2+d8j9qU9gFwVKnI9P7X2 sxe2H+a2IgvFw== From: Danilo Krummrich To: ojeda@kernel.org, alex.gaynor@gmail.com, wedsonaf@gmail.com, boqun.feng@gmail.com, gary@garyguo.net, bjorn3_gh@protonmail.com, benno.lossin@proton.me, a.hindborg@samsung.com, aliceryhl@google.com, akpm@linux-foundation.org Cc: daniel.almeida@collabora.com, faith.ekstrand@collabora.com, boris.brezillon@collabora.com, lina@asahilina.net, mcanal@igalia.com, zhiw@nvidia.com, acurrid@nvidia.com, cjia@nvidia.com, jhubbard@nvidia.com, airlied@redhat.com, ajanulgu@redhat.com, lyude@redhat.com, linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, linux-mm@kvack.org, Danilo Krummrich Subject: [PATCH v4 08/28] rust: types: implement `Unique` Date: Mon, 5 Aug 2024 17:19:27 +0200 Message-ID: <20240805152004.5039-9-dakr@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: <20240805152004.5039-1-dakr@kernel.org> References: <20240805152004.5039-1-dakr@kernel.org> MIME-Version: 1.0 X-Stat-Signature: 7abpf96hgta5wbir9qexag6hq1awq5qh X-Rspam-User: X-Rspamd-Queue-Id: 8C21318000D X-Rspamd-Server: rspam02 X-HE-Tag: 1722871261-377741 X-HE-Meta: U2FsdGVkX1+bBuOlerBbBXv8x9IZuQJCVpKrhqcTawctMlMXszptN9xKEdc4DxTIPyobEpPZfrgg985gxsmUzg8+aL4TLLcyQRgYqcMxqVbqZ+t9AqJewoPxJEKpfP1RpSCrucBuLH8ygZt7z6GOB6K8KLs8nEpfJ91evlVw0C+PxTOOD8y1OUZWTdLCc8UHJv8PaLS0spJoWNRakRZDam+7May6R888Kz9tX+gr/0UBT0DGxAx4krGlE+z2yKwDbVeFgW3yll9eiFEMCMOps3T6CZ8hcwQy8IqqLwOORzs1XfEWaS7QsT4qtEc49Ukie9DaDNW+Lg6zGJzzOXYJm7AN0TTxY7VNa1W/KXL19zKZTjSvW63M7LE2quFJcCLb5Om5soCZ747ICnZ9qMnebJrXq4w7MVYAHw/aiAbmxOkwMa+bQ2/Qtt03ne4U11ylJ1y+dnC+b5T8ow5RFrdkbDqJQ9BqTbzH/BK+FJFWZxE5oW82JdmAshma5mqVf4NifWZm5y0Kq2KmoUf8DBvq4Q8oSufa9Jl2diCqzCJLIEciuZSb6oFOdBTN0US/YX7BHKzjXT+Eet9LB1BmugWjGAHfM7fmQJvQiFbm9dytKh3BXUDeKNPfVbq6hX1Dqp0CbWvUOh+RxePoFds4PKRK5HwRe5e6YG8uoRxmR6HeWVrNqbNVHjzggje0fGWgimgOkm/lhLKIT/QSTmFbUoRyUznUsK5HMvztS4+4YXBNvUCZEclbem60BAfTySjZyFehF9YJYobuDGbtNHn3JQIQJQdXCFcP2dhRnfTWRt/cZ5PTOZh3km0ZOpNu0pj9+2o5R9RXFe4nripEN+U2RqktaBDf/9a15oD23j1/yKQlvC/UWHRbLz7qUGIj7R9iujvd1JeD/Tu8hSa8oAbc7GNu6wiAR1VDvJDfT6WzmUx+ZFcdxiXNm5Ps7hDB1WgXTcMlJY+7zbTNrC6w7VHkgZz 4FuGdxNL EgTQCJDYVbt9h5JvFA5z0jDaWvAdxUCkusGkXek7p4sve/QdE8FPvWIvgx2bilhKUQwHyP+TS2L4xDw1Z8SLK/2RNZKpTPfUXs04pGgEVJyd2Z2SZVo+R/OI0YOOoNotPw1ZnwrRgBKKBIRarhmA2r6sfLkQxH0sbqpdX3pMTLeo9cBvTA/HckgJx0uxdnlJ86wUDpVVcHq825rT5gshUusY3NZK1/w3PL4GaEK5pqcDlXmyyjJxLjwJaNkU1dFwP7hSKW7u1PS42+5jDCqKgSWY64V5ugJgzbdl6n1eangkqDpWZ98OXJ9hCJi+fnWt4yWhvA8BOiUyNzSKFTa4IFXcRiTpg9Camvxt/ X-Bogosity: Ham, tests=bogofilter, spamicity=0.007542, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: List-Subscribe: List-Unsubscribe: Implement the `Unique` type as a prerequisite for `Box` and `Vec` introduced in subsequent patches. `Unique` serves as wrapper around a `NonNull`, but indicates that the possessor of this wrapper owns the referent. This type already exists in Rust's core library, but, unfortunately, is exposed as unstable API and hence shouldn't be used in the kernel. This implementation of `Unique` is almost identical, but mostly stripped down to the functionality we need for `Box` and `Vec`. Additionally, all unstable features are removed and / or replaced by stable ones. Reviewed-by: Alice Ryhl Signed-off-by: Danilo Krummrich --- rust/kernel/types.rs | 183 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 183 insertions(+) diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index bd189d646adb..7cf89067b5fc 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -473,3 +473,186 @@ unsafe impl AsBytes for str {} // does not have any uninitialized portions either. unsafe impl AsBytes for [T] {} unsafe impl AsBytes for [T; N] {} + +/// A wrapper around a raw non-null `*mut T` that indicates that the possessor +/// of this wrapper owns the referent. Useful for building abstractions like +/// `Box`, `Vec`, `String`, and `HashMap`. +/// +/// Unlike `*mut T`, `Unique` behaves "as if" it were an instance of `T`. +/// It implements `Send`/`Sync` if `T` is `Send`/`Sync`. It also implies +/// the kind of strong aliasing guarantees an instance of `T` can expect: +/// the referent of the pointer should not be modified without a unique path to +/// its owning Unique. +/// +/// If you're uncertain of whether it's correct to use `Unique` for your purposes, +/// consider using `NonNull`, which has weaker semantics. +/// +/// Unlike `*mut T`, the pointer must always be non-null, even if the pointer +/// is never dereferenced. This is so that enums may use this forbidden value +/// as a discriminant -- `Option>` has the same size as `Unique`. +/// However the pointer may still dangle if it isn't dereferenced. +/// +/// Unlike `*mut T`, `Unique` is covariant over `T`. This should always be correct +/// for any type which upholds Unique's aliasing requirements. +#[repr(transparent)] +pub struct Unique { + pointer: NonNull, + // NOTE: this marker has no consequences for variance, but is necessary + // for dropck to understand that we logically own a `T`. + // + // For details, see: + // https://github.com/rust-lang/rfcs/blob/master/text/0769-sound-generic-drop.md#phantom-data + _marker: PhantomData, +} + +/// `Unique` pointers are `Send` if `T` is `Send` because the data they +/// reference is unaliased. Note that this aliasing invariant is +/// unenforced by the type system; the abstraction using the +/// `Unique` must enforce it. +unsafe impl Send for Unique {} + +/// `Unique` pointers are `Sync` if `T` is `Sync` because the data they +/// reference is unaliased. Note that this aliasing invariant is +/// unenforced by the type system; the abstraction using the +/// `Unique` must enforce it. +unsafe impl Sync for Unique {} + +impl Unique { + /// Creates a new `Unique` that is dangling, but well-aligned. + /// + /// This is useful for initializing types which lazily allocate, like + /// `Vec::new` does. + /// + /// Note that the pointer value may potentially represent a valid pointer to + /// a `T`, which means this must not be used as a "not yet initialized" + /// sentinel value. Types that lazily allocate must track initialization by + /// some other means. + #[must_use] + #[inline] + pub const fn dangling() -> Self { + Unique { + pointer: NonNull::dangling(), + _marker: PhantomData, + } + } +} + +impl Unique { + /// Creates a new `Unique`. + /// + /// # Safety + /// + /// `ptr` must be non-null. + #[inline] + pub const unsafe fn new_unchecked(ptr: *mut T) -> Self { + // SAFETY: the caller must guarantee that `ptr` is non-null. + unsafe { + Unique { + pointer: NonNull::new_unchecked(ptr), + _marker: PhantomData, + } + } + } + + /// Creates a new `Unique` if `ptr` is non-null. + #[allow(clippy::manual_map)] + #[inline] + pub fn new(ptr: *mut T) -> Option { + if let Some(pointer) = NonNull::new(ptr) { + Some(Unique { + pointer, + _marker: PhantomData, + }) + } else { + None + } + } + + /// Acquires the underlying `*mut` pointer. + #[must_use = "`self` will be dropped if the result is not used"] + #[inline] + pub const fn as_ptr(self) -> *mut T { + self.pointer.as_ptr() + } + + /// Dereferences the content. + /// + /// The resulting lifetime is bound to self so this behaves "as if" + /// it were actually an instance of T that is getting borrowed. If a longer + /// (unbound) lifetime is needed, use `&*my_ptr.as_ptr()`. + /// + /// # Safety + /// + /// Safety requirements for this function are inherited from [NonNull::as_ref]. + /// + #[must_use] + #[inline] + pub const unsafe fn as_ref(&self) -> &T { + // SAFETY: the caller must guarantee that `self` meets all the + // requirements for a reference. + unsafe { self.pointer.as_ref() } + } + + /// Mutably dereferences the content. + /// + /// The resulting lifetime is bound to self so this behaves "as if" + /// it were actually an instance of T that is getting borrowed. If a longer + /// (unbound) lifetime is needed, use `&mut *my_ptr.as_ptr()`. + /// + /// # Safety + /// + /// Safety requirements for this function are inherited from [NonNull::as_mut]. + #[must_use] + #[inline] + pub unsafe fn as_mut(&mut self) -> &mut T { + // SAFETY: the caller must guarantee that `self` meets all the + // requirements for a mutable reference. + unsafe { self.pointer.as_mut() } + } + + /// Casts to a pointer of another type. + #[must_use = "`self` will be dropped if the result is not used"] + #[inline] + pub fn cast(self) -> Unique { + Unique::from(self.pointer.cast()) + } + + /// Acquires the underlying `*mut` pointer. + #[must_use = "`self` will be dropped if the result is not used"] + #[inline] + pub const fn as_non_null(self) -> NonNull { + self.pointer + } +} + +impl Clone for Unique { + #[inline] + fn clone(&self) -> Self { + *self + } +} + +impl Copy for Unique {} + +impl From<&mut T> for Unique { + /// Converts a `&mut T` to a `Unique`. + /// + /// This conversion is infallible since references cannot be null. + #[inline] + fn from(reference: &mut T) -> Self { + Self::from(NonNull::from(reference)) + } +} + +impl From> for Unique { + /// Converts a `NonNull` to a `Unique`. + /// + /// This conversion is infallible since `NonNull` cannot be null. + #[inline] + fn from(pointer: NonNull) -> Self { + Unique { + pointer, + _marker: PhantomData, + } + } +}