From nobody Wed Dec 17 07:05:51 2025 Received: from mail-qt1-f181.google.com (mail-qt1-f181.google.com [209.85.160.181]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E091A1AAA1A; Wed, 23 Apr 2025 13:54:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.181 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745416486; cv=none; b=rtWCQvGb4fWInn3TSx1Y68aVFoTAdaoFP2/rSqrYym291Gu9BaqshIOaIgzJx40z8OJAcIOVZMmHw7ifl9VZ6uE56OnbTjC19+StX2594pN9olkz3HSkhaGRAoiCSom2oshz2Y2tkWcH/GmIHhNBZTwwGL76K3cuB5COXxQTpuo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745416486; c=relaxed/simple; bh=AMTM4qZdVSX9qdAs1aNQ2SNVc1SJP5H7BhlwiU9J9zk=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=RQcqLne8hVns6NA9XFslSdUXC9JkKcCjnsTM8rTZWFbkTdH/A6XMVCU48hOZ7iZ9KFxByBeylCLWfzol4WNQzdgaykmT7uP8vhtoQyDuSRu6Vh/v6+SRcaEps7Oi0cf6v8JLntzmg65+zSmnsdfh+AU29vFmRgBzFf+6OgpKEuI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=Lk7JPWQd; arc=none smtp.client-ip=209.85.160.181 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="Lk7JPWQd" Received: by mail-qt1-f181.google.com with SMTP id d75a77b69052e-4769f3e19a9so44027281cf.0; Wed, 23 Apr 2025 06:54:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1745416482; x=1746021282; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=4AmSNur/UL24mftigbhQbeOIeLWMBjX1lRgQ75bgFcc=; b=Lk7JPWQd9HzP0i1fhTDOA2XV9Ra9Cuz7F08vYKpF5uhZEdV84tmDULI2usbWGlB0Nc 9Ons+nzU8IMKtvhg8hq+QW/cQa76cPtzCwd4z0XEqlmCg6AQ2ociJGm4X4PEx/sY7Y/A ksI7PkDH7t541+MbdJiQkKZpfXHdd/5o9Sw7CpSBKedUJjy2nq4siAYvGc439T0oYSRQ CSa0byCMldFEKlscEFMWRwe9nRDkiaMYMrw4VAbRV4KTRgh/gpW/7WK2SzcQWH/a1SGn XoGWaq02evgoqPHzzd2c64B0O2bmIioBJzlAW6L7g1PMqJn+WrTr/FfiAS4vMBcSwLa2 B+Yw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1745416482; x=1746021282; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=4AmSNur/UL24mftigbhQbeOIeLWMBjX1lRgQ75bgFcc=; b=hRXIVfc6EIn10l+RMM2aFWs0WBYNpyPc1YQQOXrFEgSREXajgixABjejxfLJeCwBmT 9xraPbY0RWWgrnsDGPtlwtDF/uYSMuROvGZCJXnbbgFL/SM6EFQtFakqk2aKpx5QQkfS IZ6Z9XDA2pyIFnUvuFNpVqj86dd+Hd70dwdmNfEKNs/h2CEyhNikwkbOUMxKzRL8DaRH uwVZYeemeqhMYsqN6NjVmDACL8VnPuA16NtPtLi/qTkPW1vx5joz11/tS2MPwozG7nBv H/lbhRJLxo7JG36R89t/Fq1wAwfhSMluMhh+DskjcTahEPiLPv6XnJkWaEDjR7cVkpSK UfoA== X-Forwarded-Encrypted: i=1; AJvYcCV5/TmthHHkqh5mZQD/ny364rmO8gjz3Zv2xxMg5Q4tQm23zlQon3/hnI3a0SGGsXszFSaEXIMYWNSk684yPgQ=@vger.kernel.org, AJvYcCW0XtJDGkAyzYWNDVbhn1qVAtDhXzzoCQ2hr70HnVa5dVIV/mJXveNkUy8EA72O+hQVTWP37J6eGW1l@vger.kernel.org, AJvYcCWAAZxIe8bmf47R3F51ialhgLSFNLn3FW+7Vem0hpkEu/t03l1OuBx0MfaSndia+AZBrGimq/6CU+NCqvED@vger.kernel.org, AJvYcCWnRResTjK70eooxqo4dQO8ta11G0/wgWouGpOVJGPNzSGYixw9NlWxpw8gYYRaNnqSHzpLQ9Cp8ShwyJNc@vger.kernel.org X-Gm-Message-State: AOJu0YxN+PaHTo19EjZm9Fpnpnof4FWVIZfmeCN39bq1XK1t2rLmZfWu 751vCYXDPUW4pczEHlJi5rOSc75l8ba6ljWMcu0uNur5ybH9oCRK X-Gm-Gg: ASbGncsaeyCrrTaovd8HRdTggV8CphiLScHPc/7kW9v5rlZE6+BqeMHqtrhNqwFATpR xABbLVCn9sjxE9eIApiIctagEAA4X9uu68YGN+7a2IHan7qUqQzroY1ka791ayImbd7uHRayNIl nFn/WAVJI/0s8cqDK+VnDNZYT9HNnKH04B2DC+QY5pn0B4I0MBo4xlcpthUPZSLGwFNinVYAKrr j9H5aOeyY4PxyyPvauyay80i0N0VyExrbcfVdqGQiBxMfKJdojosWNANlVt+nytRFbl9hG7QSYF jEL0SWRNfDoPm/8nNwQfsk2UxppHctXEvNUBk6VViGXx37Ne0MaM5H4+CR6RAhePsaS5c4Glgzt VxTsp0ZIFpisPptD2aXOMwZ56M52zrV9rxX4MQ1WNtsHhUc848Q== X-Google-Smtp-Source: AGHT+IE1y1QPyvGpmyb3lIJTBSCxfBsc6daYJBUZFuovod4HdUmjRrXqjjdo2BNdS2IOcHkLeprrNQ== X-Received: by 2002:a05:622a:24f:b0:476:b764:e315 with SMTP id d75a77b69052e-47aec4dd531mr308911601cf.52.1745416481279; Wed, 23 Apr 2025 06:54:41 -0700 (PDT) Received: from 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa ([2620:10d:c091:600::1:e2b6]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-47ae9cf9f7dsm68135461cf.74.2025.04.23.06.54.39 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 23 Apr 2025 06:54:40 -0700 (PDT) From: Tamir Duberstein Date: Wed, 23 Apr 2025 09:54:37 -0400 Subject: [PATCH v19 1/3] rust: types: add `ForeignOwnable::PointedTo` Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250423-rust-xarray-bindings-v19-1-83cdcf11c114@gmail.com> References: <20250423-rust-xarray-bindings-v19-0-83cdcf11c114@gmail.com> In-Reply-To: <20250423-rust-xarray-bindings-v19-0-83cdcf11c114@gmail.com> To: Danilo Krummrich , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Matthew Wilcox , Bjorn Helgaas , Greg Kroah-Hartman , "Rafael J. Wysocki" , Tamir Duberstein , FUJITA Tomonori , "Rob Herring (Arm)" Cc: =?utf-8?q?Ma=C3=ADra_Canal?= , Asahi Lina , rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org X-Mailer: b4 0.15-dev Allow implementors to specify the foreign pointer type; this exposes information about the pointed-to type such as its alignment. This requires the trait to be `unsafe` since it is now possible for implementors to break soundness by returning a misaligned pointer. Encoding the pointer type in the trait (and avoiding pointer casts) allows the compiler to check that implementors return the correct pointer type. This is preferable to directly encoding the alignment in the trait using a constant as the compiler would be unable to check it. Acked-by: Danilo Krummrich Signed-off-by: Tamir Duberstein --- rust/kernel/alloc/kbox.rs | 38 ++++++++++++++++++++------------------ rust/kernel/miscdevice.rs | 10 +++++----- rust/kernel/pci.rs | 2 +- rust/kernel/platform.rs | 2 +- rust/kernel/sync/arc.rs | 21 ++++++++++++--------- rust/kernel/types.rs | 46 +++++++++++++++++++++++++++++++------------= --- 6 files changed, 70 insertions(+), 49 deletions(-) diff --git a/rust/kernel/alloc/kbox.rs b/rust/kernel/alloc/kbox.rs index b77d32f3a58b..6aa88b01e84d 100644 --- a/rust/kernel/alloc/kbox.rs +++ b/rust/kernel/alloc/kbox.rs @@ -360,68 +360,70 @@ fn try_init(init: impl Init, flags: Flags) -= > Result } } =20 -impl ForeignOwnable for Box +// SAFETY: The `into_foreign` function returns a pointer that is well-alig= ned. +unsafe impl ForeignOwnable for Box where A: Allocator, { + type PointedTo =3D T; type Borrowed<'a> =3D &'a T; type BorrowedMut<'a> =3D &'a mut T; =20 - fn into_foreign(self) -> *mut crate::ffi::c_void { - Box::into_raw(self).cast() + fn into_foreign(self) -> *mut Self::PointedTo { + Box::into_raw(self) } =20 - unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self { + unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self { // SAFETY: The safety requirements of this function ensure that `p= tr` comes from a previous // call to `Self::into_foreign`. - unsafe { Box::from_raw(ptr.cast()) } + unsafe { Box::from_raw(ptr) } } =20 - unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> &'a T { + unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> &'a T { // SAFETY: The safety requirements of this method ensure that the = object remains alive and // immutable for the duration of 'a. - unsafe { &*ptr.cast() } + unsafe { &*ptr } } =20 - unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> &'a mut T { - let ptr =3D ptr.cast(); + unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> &'a mut T { // SAFETY: The safety requirements of this method ensure that the = pointer is valid and that // nothing else will access the value for the duration of 'a. unsafe { &mut *ptr } } } =20 -impl ForeignOwnable for Pin> +// SAFETY: The `into_foreign` function returns a pointer that is well-alig= ned. +unsafe impl ForeignOwnable for Pin> where A: Allocator, { + type PointedTo =3D T; type Borrowed<'a> =3D Pin<&'a T>; type BorrowedMut<'a> =3D Pin<&'a mut T>; =20 - fn into_foreign(self) -> *mut crate::ffi::c_void { + fn into_foreign(self) -> *mut Self::PointedTo { // SAFETY: We are still treating the box as pinned. - Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }).cast() + Box::into_raw(unsafe { Pin::into_inner_unchecked(self) }) } =20 - unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self { + unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self { // SAFETY: The safety requirements of this function ensure that `p= tr` comes from a previous // call to `Self::into_foreign`. - unsafe { Pin::new_unchecked(Box::from_raw(ptr.cast())) } + unsafe { Pin::new_unchecked(Box::from_raw(ptr)) } } =20 - unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> Pin<&'a T> { + unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> Pin<&'a T> { // SAFETY: The safety requirements for this function ensure that t= he object is still alive, // so it is safe to dereference the raw pointer. // The safety requirements of `from_foreign` also ensure that the = object remains alive for // the lifetime of the returned value. - let r =3D unsafe { &*ptr.cast() }; + let r =3D unsafe { &*ptr }; =20 // SAFETY: This pointer originates from a `Pin>`. unsafe { Pin::new_unchecked(r) } } =20 - unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> Pin<&'a mut = T> { - let ptr =3D ptr.cast(); + unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> Pin<&'a mut T> { // SAFETY: The safety requirements for this function ensure that t= he object is still alive, // so it is safe to dereference the raw pointer. // The safety requirements of `from_foreign` also ensure that the = object remains alive for diff --git a/rust/kernel/miscdevice.rs b/rust/kernel/miscdevice.rs index fa9ecc42602a..b4c5f74de23d 100644 --- a/rust/kernel/miscdevice.rs +++ b/rust/kernel/miscdevice.rs @@ -200,7 +200,7 @@ impl MiscdeviceVTable { // type. // // SAFETY: The open call of a file can access the private data. - unsafe { (*raw_file).private_data =3D ptr.into_foreign() }; + unsafe { (*raw_file).private_data =3D ptr.into_foreign().cast() }; =20 0 } @@ -211,7 +211,7 @@ impl MiscdeviceVTable { /// must be associated with a `MiscDeviceRegistration`. unsafe extern "C" fn release(_inode: *mut bindings::inode, file: *mut = bindings::file) -> c_int { // SAFETY: The release call of a file owns the private data. - let private =3D unsafe { (*file).private_data }; + let private =3D unsafe { (*file).private_data }.cast(); // SAFETY: The release call of a file owns the private data. let ptr =3D unsafe { ::from_foreign(priv= ate) }; =20 @@ -228,7 +228,7 @@ impl MiscdeviceVTable { /// `file` must be a valid file that is associated with a `MiscDeviceR= egistration`. unsafe extern "C" fn ioctl(file: *mut bindings::file, cmd: c_uint, arg= : c_ulong) -> c_long { // SAFETY: The ioctl call of a file can access the private data. - let private =3D unsafe { (*file).private_data }; + let private =3D unsafe { (*file).private_data }.cast(); // SAFETY: Ioctl calls can borrow the private data of the file. let device =3D unsafe { ::borrow(private= ) }; =20 @@ -253,7 +253,7 @@ impl MiscdeviceVTable { arg: c_ulong, ) -> c_long { // SAFETY: The compat ioctl call of a file can access the private = data. - let private =3D unsafe { (*file).private_data }; + let private =3D unsafe { (*file).private_data }.cast(); // SAFETY: Ioctl calls can borrow the private data of the file. let device =3D unsafe { ::borrow(private= ) }; =20 @@ -274,7 +274,7 @@ impl MiscdeviceVTable { /// - `seq_file` must be a valid `struct seq_file` that we can write t= o. unsafe extern "C" fn show_fdinfo(seq_file: *mut bindings::seq_file, fi= le: *mut bindings::file) { // SAFETY: The release call of a file owns the private data. - let private =3D unsafe { (*file).private_data }; + let private =3D unsafe { (*file).private_data }.cast(); // SAFETY: Ioctl calls can borrow the private data of the file. let device =3D unsafe { ::borrow(private= ) }; // SAFETY: diff --git a/rust/kernel/pci.rs b/rust/kernel/pci.rs index c97d6d470b28..3aeb1250c27f 100644 --- a/rust/kernel/pci.rs +++ b/rust/kernel/pci.rs @@ -89,7 +89,7 @@ extern "C" fn probe_callback( extern "C" fn remove_callback(pdev: *mut bindings::pci_dev) { // SAFETY: The PCI bus only ever calls the remove callback with a = valid pointer to a // `struct pci_dev`. - let ptr =3D unsafe { bindings::pci_get_drvdata(pdev) }; + let ptr =3D unsafe { bindings::pci_get_drvdata(pdev) }.cast(); =20 // SAFETY: `remove_callback` is only ever called after a successfu= l call to // `probe_callback`, hence it's guaranteed that `ptr` points to a = valid and initialized diff --git a/rust/kernel/platform.rs b/rust/kernel/platform.rs index 4917cb34e2fe..fd4a494f30e8 100644 --- a/rust/kernel/platform.rs +++ b/rust/kernel/platform.rs @@ -80,7 +80,7 @@ extern "C" fn probe_callback(pdev: *mut bindings::platfor= m_device) -> kernel::ff =20 extern "C" fn remove_callback(pdev: *mut bindings::platform_device) { // SAFETY: `pdev` is a valid pointer to a `struct platform_device`. - let ptr =3D unsafe { bindings::platform_get_drvdata(pdev) }; + let ptr =3D unsafe { bindings::platform_get_drvdata(pdev) }.cast(); =20 // SAFETY: `remove_callback` is only ever called after a successfu= l call to // `probe_callback`, hence it's guaranteed that `ptr` points to a = valid and initialized diff --git a/rust/kernel/sync/arc.rs b/rust/kernel/sync/arc.rs index 8484c814609a..a42c164e577a 100644 --- a/rust/kernel/sync/arc.rs +++ b/rust/kernel/sync/arc.rs @@ -140,9 +140,10 @@ pub struct Arc { _p: PhantomData>, } =20 +#[doc(hidden)] #[pin_data] #[repr(C)] -struct ArcInner { +pub struct ArcInner { refcount: Opaque, data: T, } @@ -371,18 +372,20 @@ pub fn into_unique_or_drop(self) -> Option>> { } } =20 -impl ForeignOwnable for Arc { +// SAFETY: The `into_foreign` function returns a pointer that is well-alig= ned. +unsafe impl ForeignOwnable for Arc { + type PointedTo =3D ArcInner; type Borrowed<'a> =3D ArcBorrow<'a, T>; type BorrowedMut<'a> =3D Self::Borrowed<'a>; =20 - fn into_foreign(self) -> *mut crate::ffi::c_void { - ManuallyDrop::new(self).ptr.as_ptr().cast() + fn into_foreign(self) -> *mut Self::PointedTo { + ManuallyDrop::new(self).ptr.as_ptr() } =20 - unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self { + unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self { // SAFETY: The safety requirements of this function ensure that `p= tr` comes from a previous // call to `Self::into_foreign`. - let inner =3D unsafe { NonNull::new_unchecked(ptr.cast::>()) }; + let inner =3D unsafe { NonNull::new_unchecked(ptr) }; =20 // SAFETY: By the safety requirement of this function, we know tha= t `ptr` came from // a previous call to `Arc::into_foreign`, which guarantees that `= ptr` is valid and @@ -390,17 +393,17 @@ unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) = -> Self { unsafe { Self::from_inner(inner) } } =20 - unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> ArcBorrow<'a, T>= { + unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> ArcBorrow<'a, T> { // SAFETY: The safety requirements of this function ensure that `p= tr` comes from a previous // call to `Self::into_foreign`. - let inner =3D unsafe { NonNull::new_unchecked(ptr.cast::>()) }; + let inner =3D unsafe { NonNull::new_unchecked(ptr) }; =20 // SAFETY: The safety requirements of `from_foreign` ensure that t= he object remains alive // for the lifetime of the returned value. unsafe { ArcBorrow::new(inner) } } =20 - unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> ArcBorrow<'a= , T> { + unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> ArcBorrow<'a, T= > { // SAFETY: The safety requirements for `borrow_mut` are a superset= of the safety // requirements for `borrow`. unsafe { Self::borrow(ptr) } diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs index 9d0471afc964..86562e738eac 100644 --- a/rust/kernel/types.rs +++ b/rust/kernel/types.rs @@ -18,7 +18,19 @@ /// /// This trait is meant to be used in cases when Rust objects are stored i= n C objects and /// eventually "freed" back to Rust. -pub trait ForeignOwnable: Sized { +/// +/// # Safety +/// +/// Implementers must ensure that [`into_foreign`] returns a pointer which= meets the alignment +/// requirements of [`PointedTo`]. +/// +/// [`into_foreign`]: Self::into_foreign +/// [`PointedTo`]: Self::PointedTo +pub unsafe trait ForeignOwnable: Sized { + /// Type used when the value is foreign-owned. In practical terms only= defines the alignment of + /// the pointer. + type PointedTo; + /// Type used to immutably borrow a value that is currently foreign-ow= ned. type Borrowed<'a>; =20 @@ -27,16 +39,18 @@ pub trait ForeignOwnable: Sized { =20 /// Converts a Rust-owned object to a foreign-owned one. /// - /// The foreign representation is a pointer to void. There are no guar= antees for this pointer. - /// For example, it might be invalid, dangling or pointing to uninitia= lized memory. Using it in - /// any way except for [`from_foreign`], [`try_from_foreign`], [`borro= w`], or [`borrow_mut`] can - /// result in undefined behavior. + /// # Guarantees + /// + /// The return value is guaranteed to be well-aligned, but there are n= o other guarantees for + /// this pointer. For example, it might be null, dangling, or point to= uninitialized memory. + /// Using it in any way except for [`ForeignOwnable::from_foreign`], [= `ForeignOwnable::borrow`], + /// [`ForeignOwnable::try_from_foreign`] can result in undefined behav= ior. /// /// [`from_foreign`]: Self::from_foreign /// [`try_from_foreign`]: Self::try_from_foreign /// [`borrow`]: Self::borrow /// [`borrow_mut`]: Self::borrow_mut - fn into_foreign(self) -> *mut crate::ffi::c_void; + fn into_foreign(self) -> *mut Self::PointedTo; =20 /// Converts a foreign-owned object back to a Rust-owned one. /// @@ -46,7 +60,7 @@ pub trait ForeignOwnable: Sized { /// must not be passed to `from_foreign` more than once. /// /// [`into_foreign`]: Self::into_foreign - unsafe fn from_foreign(ptr: *mut crate::ffi::c_void) -> Self; + unsafe fn from_foreign(ptr: *mut Self::PointedTo) -> Self; =20 /// Tries to convert a foreign-owned object back to a Rust-owned one. /// @@ -58,7 +72,7 @@ pub trait ForeignOwnable: Sized { /// `ptr` must either be null or satisfy the safety requirements for [= `from_foreign`]. /// /// [`from_foreign`]: Self::from_foreign - unsafe fn try_from_foreign(ptr: *mut crate::ffi::c_void) -> Option { + unsafe fn try_from_foreign(ptr: *mut Self::PointedTo) -> Option { if ptr.is_null() { None } else { @@ -81,7 +95,7 @@ unsafe fn try_from_foreign(ptr: *mut crate::ffi::c_void) = -> Option { /// /// [`into_foreign`]: Self::into_foreign /// [`from_foreign`]: Self::from_foreign - unsafe fn borrow<'a>(ptr: *mut crate::ffi::c_void) -> Self::Borrowed<'= a>; + unsafe fn borrow<'a>(ptr: *mut Self::PointedTo) -> Self::Borrowed<'a>; =20 /// Borrows a foreign-owned object mutably. /// @@ -109,21 +123,23 @@ unsafe fn try_from_foreign(ptr: *mut crate::ffi::c_vo= id) -> Option { /// [`from_foreign`]: Self::from_foreign /// [`borrow`]: Self::borrow /// [`Arc`]: crate::sync::Arc - unsafe fn borrow_mut<'a>(ptr: *mut crate::ffi::c_void) -> Self::Borrow= edMut<'a>; + unsafe fn borrow_mut<'a>(ptr: *mut Self::PointedTo) -> Self::BorrowedM= ut<'a>; } =20 -impl ForeignOwnable for () { +// SAFETY: The `into_foreign` function returns a pointer that is dangling,= but well-aligned. +unsafe impl ForeignOwnable for () { + type PointedTo =3D (); type Borrowed<'a> =3D (); type BorrowedMut<'a> =3D (); =20 - fn into_foreign(self) -> *mut crate::ffi::c_void { + fn into_foreign(self) -> *mut Self::PointedTo { core::ptr::NonNull::dangling().as_ptr() } =20 - unsafe fn from_foreign(_: *mut crate::ffi::c_void) -> Self {} + unsafe fn from_foreign(_: *mut Self::PointedTo) -> Self {} =20 - unsafe fn borrow<'a>(_: *mut crate::ffi::c_void) -> Self::Borrowed<'a>= {} - unsafe fn borrow_mut<'a>(_: *mut crate::ffi::c_void) -> Self::Borrowed= Mut<'a> {} + unsafe fn borrow<'a>(_: *mut Self::PointedTo) -> Self::Borrowed<'a> {} + unsafe fn borrow_mut<'a>(_: *mut Self::PointedTo) -> Self::BorrowedMut= <'a> {} } =20 /// Runs a cleanup function/closure when dropped. --=20 2.49.0 From nobody Wed Dec 17 07:05:51 2025 Received: from mail-qt1-f173.google.com (mail-qt1-f173.google.com [209.85.160.173]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C48081B040B; Wed, 23 Apr 2025 13:54:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.173 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745416487; cv=none; b=c0T3qMhMXxXk2VDwvOWjrqGuPceo37X3UociIp5OkiJFoTlGn0DcB62J1Zjh1QOsvn7Xux9lYxeAbcMHCs2Nf7FNv+bgisCBSOx1wplT/0+YDyWrJzlWY2YfvcAASILsJyFaSpdPc0Jw7HW+Vl/EOVvP0P3fx2rZfs+FnwXrWVY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745416487; c=relaxed/simple; bh=jlRN/tTw7Zp0eIq9osGcJ+spoV2f70e/V57vy6It0uw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=jzw+AxwsSyZVnC5uLQdRBumij07zNQ+Qb7+DsUuH8Pi3myJp21rxxOS/s7gc3mFDxne4vJs/yimJA16HsadSE4IP07XA7YK5bHH8IDpoizU+avud5T9t8yhoA6cx6H7gVrMJjsJWCwN5X4nuNo4+iUwSX0r/P/l8J/LP2zroXds= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=AGkerWM4; arc=none smtp.client-ip=209.85.160.173 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="AGkerWM4" Received: by mail-qt1-f173.google.com with SMTP id d75a77b69052e-47691d82bfbso121821671cf.0; Wed, 23 Apr 2025 06:54:44 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1745416483; x=1746021283; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=MEvzGSgrG49q0bEAP8Rox67ehlzYDpSBzxCxazKaPJQ=; b=AGkerWM442lpijwXtWCkWnx0viCxXl6+fk/K/mQVPGp26MhHYg67pNw6mi6/o1nmfb QbMBa2s2Uo2Ws3xYR50YgnvEK/EF+sSwpooAYSMdxEREguSiAxNUlE/b6Hod40lUjiXt NeUzQRVXdAkgfVhTybWzbhgNcEQ2gsXTbaFfAR7nnym7wbFx50muQxSgsM4NvMDmwl3K fE6SlD3tVMyARC2FeNnjmErDUWEsdSJPBKWmKJy0evsBQPZj4vUDmfcBMiu+ZIkW5cN7 YpGoBvP6bZXP7xiCsiap7wOIN0Ty2OTK9liOZNEsYvY7J04Z7pTMnKH5+PPMvDAh1LIA 7u7g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1745416483; x=1746021283; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=MEvzGSgrG49q0bEAP8Rox67ehlzYDpSBzxCxazKaPJQ=; b=fNjXH4EJPwh6+srKAAEegvF5ZbORoivbPc7SRnMt61W8sD5waHjDZWl5XXiKUICGVn 5s4MW2vWLWYfEhDDESbJMrBcY7Dy9HcsLayGq1dBjyen6BSCJ7AVULZNaaJTXlez5IaI oe34jYF4R8KZbzK40OcJAs0AUvNI6Mboti122Qj/22GDW+cC9NrcF0XhAj2q8rLj8D7s L8Tck3h48/xGDkrUq6cuEtvPeLo2VYKeAtf/b3wGOwxZwVbCqMoFtOUkeFD55HXq0I5r xfJtPhQKWqWnor3iES4hWYeipvXqihYFiGzJX+p7+0q/YPjic2YAlEwZhkGIh6AW+tQi BBzw== X-Forwarded-Encrypted: i=1; AJvYcCUfby6n3cbjaebCSVp54zGfdu3zW4pcukln1aF7cbj5DVe47i7oZddY677YJwPbaptbdVVWfJ42L4iX@vger.kernel.org, AJvYcCWcFB0QLKbd6gqYzZaPCKh5gyFpZ/UUv1sfUlbxLIXSPSu2Gx2k63Kb6yQCrsTSuJj+UtRSWCwBWaXbXW5/pJo=@vger.kernel.org, AJvYcCWwITy6hDqydIX9wbJJMSRzHTLAM1nf7kGIXTNWWoiVd3XEH4tdFACqxIU/OyiF0/Y3UwGkItOzgCh+hco6@vger.kernel.org, AJvYcCXxdFJNxbjRdZ2etARU8PHOntvSYW0Y7Kchg3s1cjxGDI5GXi6K4xY3dHHr0jRQ/VIPCr6jYhE1bvDxw/nR@vger.kernel.org X-Gm-Message-State: AOJu0YwLTqAyho2jpPpQ5ZgvDkav7HfGeD7WswzGNft7lqDpdtGKNUCV 5OSrMv359iTR9g5MfRQPLcSpsKnuDgNYoFcnlnNiC2MVLy1wS4PJWyTWCxXXtHQ= X-Gm-Gg: ASbGncv/FAwyJgQGE5aELXxCbpuC3w3BoU4UdcPLrwHoiHQGpIYik4bidMui4sLm+O3 4vK+mKlEWg8NVfJ/dJDJK+v1vX5IvEOx/fvpeE7c5id/RKuprAC52qTaWHJhSqrhhBjH1eIOQoJ 07O9hdFH2Xsdxd2DV4yanwrYHFzJCWNhNxCv1nDew+i4JEMsOXr502PG/SyMqyAFFwsu7oGmDAh vPpuRIvDzneacitQ9XFtotTIfqeR8rXy2Dhx2Aa12N6uByomQsuEy0X8CV89FbOGvQr0/rsJSqC i4t1hdwu+j1JUBoT4q0x4/kiJaBcJ2/sW6Dkg2P2Ruch0rew7/GaBwq2N/2zViwzaL2LJtxmrXC obvgsj4h/67bBgh93twp1LrP22w+ifZYqVqTNkIiICAhn8cBLww== X-Google-Smtp-Source: AGHT+IGlo13KlW/fEd4g5vPuYiTrdtt3LqipoGa/r/MhFsBhq+5EbrRbxxmfpvgrkzFV8RU2tB9Hsg== X-Received: by 2002:ac8:57ce:0:b0:477:64dd:5765 with SMTP id d75a77b69052e-47aec4c359amr374309841cf.44.1745416483440; Wed, 23 Apr 2025 06:54:43 -0700 (PDT) Received: from 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa ([2620:10d:c091:600::1:e2b6]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-47ae9cf9f7dsm68135461cf.74.2025.04.23.06.54.41 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 23 Apr 2025 06:54:42 -0700 (PDT) From: Tamir Duberstein Date: Wed, 23 Apr 2025 09:54:38 -0400 Subject: [PATCH v19 2/3] rust: xarray: Add an abstraction for XArray Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250423-rust-xarray-bindings-v19-2-83cdcf11c114@gmail.com> References: <20250423-rust-xarray-bindings-v19-0-83cdcf11c114@gmail.com> In-Reply-To: <20250423-rust-xarray-bindings-v19-0-83cdcf11c114@gmail.com> To: Danilo Krummrich , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Matthew Wilcox , Bjorn Helgaas , Greg Kroah-Hartman , "Rafael J. Wysocki" , Tamir Duberstein , FUJITA Tomonori , "Rob Herring (Arm)" Cc: =?utf-8?q?Ma=C3=ADra_Canal?= , Asahi Lina , rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org X-Mailer: b4 0.15-dev `XArray` is an efficient sparse array of pointers. Add a Rust abstraction for this type. This implementation bounds the element type on `ForeignOwnable` and requires explicit locking for all operations. Future work may leverage RCU to enable lockless operation. Inspired-by: Ma=C3=ADra Canal Inspired-by: Asahi Lina Reviewed-by: Andreas Hindborg Reviewed-by: Alice Ryhl Signed-off-by: Tamir Duberstein --- rust/bindings/bindings_helper.h | 6 + rust/helpers/helpers.c | 1 + rust/helpers/xarray.c | 28 ++++ rust/kernel/lib.rs | 1 + rust/kernel/xarray.rs | 275 ++++++++++++++++++++++++++++++++++++= ++++ 5 files changed, 311 insertions(+) diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index ab37e1d35c70..e0bcd130b494 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -37,6 +37,7 @@ #include #include #include +#include #include =20 #if defined(CONFIG_DRM_PANIC_SCREEN_QR_CODE) @@ -55,3 +56,8 @@ const gfp_t RUST_CONST_HELPER___GFP_ZERO =3D __GFP_ZERO; const gfp_t RUST_CONST_HELPER___GFP_HIGHMEM =3D ___GFP_HIGHMEM; const gfp_t RUST_CONST_HELPER___GFP_NOWARN =3D ___GFP_NOWARN; const blk_features_t RUST_CONST_HELPER_BLK_FEAT_ROTATIONAL =3D BLK_FEAT_RO= TATIONAL; + +const xa_mark_t RUST_CONST_HELPER_XA_PRESENT =3D XA_PRESENT; + +const gfp_t RUST_CONST_HELPER_XA_FLAGS_ALLOC =3D XA_FLAGS_ALLOC; +const gfp_t RUST_CONST_HELPER_XA_FLAGS_ALLOC1 =3D XA_FLAGS_ALLOC1; diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 1e7c84df7252..80785b1e7a63 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -38,3 +38,4 @@ #include "vmalloc.c" #include "wait.c" #include "workqueue.c" +#include "xarray.c" diff --git a/rust/helpers/xarray.c b/rust/helpers/xarray.c new file mode 100644 index 000000000000..60b299f11451 --- /dev/null +++ b/rust/helpers/xarray.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +int rust_helper_xa_err(void *entry) +{ + return xa_err(entry); +} + +void rust_helper_xa_init_flags(struct xarray *xa, gfp_t flags) +{ + return xa_init_flags(xa, flags); +} + +int rust_helper_xa_trylock(struct xarray *xa) +{ + return xa_trylock(xa); +} + +void rust_helper_xa_lock(struct xarray *xa) +{ + return xa_lock(xa); +} + +void rust_helper_xa_unlock(struct xarray *xa) +{ + return xa_unlock(xa); +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index de07aadd1ff5..715fab6b1345 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -88,6 +88,7 @@ pub mod types; pub mod uaccess; pub mod workqueue; +pub mod xarray; =20 #[doc(hidden)] pub use bindings; diff --git a/rust/kernel/xarray.rs b/rust/kernel/xarray.rs new file mode 100644 index 000000000000..75719e7bb491 --- /dev/null +++ b/rust/kernel/xarray.rs @@ -0,0 +1,275 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! XArray abstraction. +//! +//! C header: [`include/linux/xarray.h`](srctree/include/linux/xarray.h) + +use crate::{ + alloc, bindings, build_assert, + error::{Error, Result}, + types::{ForeignOwnable, NotThreadSafe, Opaque}, +}; +use core::{iter, marker::PhantomData, mem, pin::Pin, ptr::NonNull}; +use pin_init::{pin_data, pin_init, pinned_drop, PinInit}; + +/// An array which efficiently maps sparse integer indices to owned object= s. +/// +/// This is similar to a [`crate::alloc::kvec::Vec>`], but more = efficient when there are +/// holes in the index space, and can be efficiently grown. +/// +/// # Invariants +/// +/// `self.xa` is always an initialized and valid [`bindings::xarray`] whos= e entries are either +/// `XA_ZERO_ENTRY` or came from `T::into_foreign`. +/// +/// # Examples +/// +/// ```rust +/// use kernel::alloc::KBox; +/// use kernel::xarray::{AllocKind, XArray}; +/// +/// let xa =3D KBox::pin_init(XArray::new(AllocKind::Alloc1), GFP_KERNEL)?; +/// +/// let dead =3D KBox::new(0xdead, GFP_KERNEL)?; +/// let beef =3D KBox::new(0xbeef, GFP_KERNEL)?; +/// +/// let mut guard =3D xa.lock(); +/// +/// assert_eq!(guard.get(0), None); +/// +/// assert_eq!(guard.store(0, dead, GFP_KERNEL)?.as_deref(), None); +/// assert_eq!(guard.get(0).copied(), Some(0xdead)); +/// +/// *guard.get_mut(0).unwrap() =3D 0xffff; +/// assert_eq!(guard.get(0).copied(), Some(0xffff)); +/// +/// assert_eq!(guard.store(0, beef, GFP_KERNEL)?.as_deref().copied(), Some= (0xffff)); +/// assert_eq!(guard.get(0).copied(), Some(0xbeef)); +/// +/// guard.remove(0); +/// assert_eq!(guard.get(0), None); +/// +/// # Ok::<(), Error>(()) +/// ``` +#[pin_data(PinnedDrop)] +pub struct XArray { + #[pin] + xa: Opaque, + _p: PhantomData, +} + +#[pinned_drop] +impl PinnedDrop for XArray { + fn drop(self: Pin<&mut Self>) { + self.iter().for_each(|ptr| { + let ptr =3D ptr.as_ptr(); + // SAFETY: `ptr` came from `T::into_foreign`. + // + // INVARIANT: we own the only reference to the array which is = being dropped so the + // broken invariant is not observable on function exit. + drop(unsafe { T::from_foreign(ptr) }) + }); + + // SAFETY: `self.xa` is always valid by the type invariant. + unsafe { bindings::xa_destroy(self.xa.get()) }; + } +} + +/// Flags passed to [`XArray::new`] to configure the array's allocation tr= acking behavior. +pub enum AllocKind { + /// Consider the first element to be at index 0. + Alloc, + /// Consider the first element to be at index 1. + Alloc1, +} + +impl XArray { + /// Creates a new initializer for this type. + pub fn new(kind: AllocKind) -> impl PinInit { + let flags =3D match kind { + AllocKind::Alloc =3D> bindings::XA_FLAGS_ALLOC, + AllocKind::Alloc1 =3D> bindings::XA_FLAGS_ALLOC1, + }; + pin_init!(Self { + // SAFETY: `xa` is valid while the closure is called. + // + // INVARIANT: `xa` is initialized here to an empty, valid [`bi= ndings::xarray`]. + xa <- Opaque::ffi_init(|xa| unsafe { + bindings::xa_init_flags(xa, flags) + }), + _p: PhantomData, + }) + } + + fn iter(&self) -> impl Iterator> + '_ { + let mut index =3D 0; + + // SAFETY: `self.xa` is always valid by the type invariant. + iter::once(unsafe { + bindings::xa_find(self.xa.get(), &mut index, usize::MAX, bindi= ngs::XA_PRESENT) + }) + .chain(iter::from_fn(move || { + // SAFETY: `self.xa` is always valid by the type invariant. + Some(unsafe { + bindings::xa_find_after(self.xa.get(), &mut index, usize::= MAX, bindings::XA_PRESENT) + }) + })) + .map_while(|ptr| NonNull::new(ptr.cast())) + } + + /// Attempts to lock the [`XArray`] for exclusive access. + pub fn try_lock(&self) -> Option> { + // SAFETY: `self.xa` is always valid by the type invariant. + if (unsafe { bindings::xa_trylock(self.xa.get()) } !=3D 0) { + Some(Guard { + xa: self, + _not_send: NotThreadSafe, + }) + } else { + None + } + } + + /// Locks the [`XArray`] for exclusive access. + pub fn lock(&self) -> Guard<'_, T> { + // SAFETY: `self.xa` is always valid by the type invariant. + unsafe { bindings::xa_lock(self.xa.get()) }; + + Guard { + xa: self, + _not_send: NotThreadSafe, + } + } +} + +/// A lock guard. +/// +/// The lock is unlocked when the guard goes out of scope. +#[must_use =3D "the lock unlocks immediately when the guard is unused"] +pub struct Guard<'a, T: ForeignOwnable> { + xa: &'a XArray, + _not_send: NotThreadSafe, +} + +impl Drop for Guard<'_, T> { + fn drop(&mut self) { + // SAFETY: + // - `self.xa.xa` is always valid by the type invariant. + // - The caller holds the lock, so it is safe to unlock it. + unsafe { bindings::xa_unlock(self.xa.xa.get()) }; + } +} + +/// The error returned by [`store`](Guard::store). +/// +/// Contains the underlying error and the value that was not stored. +pub struct StoreError { + /// The error that occurred. + pub error: Error, + /// The value that was not stored. + pub value: T, +} + +impl From> for Error { + fn from(value: StoreError) -> Self { + value.error + } +} + +impl<'a, T: ForeignOwnable> Guard<'a, T> { + fn load(&self, index: usize, f: F) -> Option + where + F: FnOnce(NonNull) -> U, + { + // SAFETY: `self.xa.xa` is always valid by the type invariant. + let ptr =3D unsafe { bindings::xa_load(self.xa.xa.get(), index) }; + let ptr =3D NonNull::new(ptr.cast())?; + Some(f(ptr)) + } + + /// Provides a reference to the element at the given index. + pub fn get(&self, index: usize) -> Option> { + self.load(index, |ptr| { + // SAFETY: `ptr` came from `T::into_foreign`. + unsafe { T::borrow(ptr.as_ptr()) } + }) + } + + /// Provides a mutable reference to the element at the given index. + pub fn get_mut(&mut self, index: usize) -> Option> { + self.load(index, |ptr| { + // SAFETY: `ptr` came from `T::into_foreign`. + unsafe { T::borrow_mut(ptr.as_ptr()) } + }) + } + + /// Removes and returns the element at the given index. + pub fn remove(&mut self, index: usize) -> Option { + // SAFETY: + // - `self.xa.xa` is always valid by the type invariant. + // - The caller holds the lock. + let ptr =3D unsafe { bindings::__xa_erase(self.xa.xa.get(), index)= }.cast(); + // SAFETY: + // - `ptr` is either NULL or came from `T::into_foreign`. + // - `&mut self` guarantees that the lifetimes of [`T::Borrowed`] = and [`T::BorrowedMut`] + // borrowed from `self` have ended. + unsafe { T::try_from_foreign(ptr) } + } + + /// Stores an element at the given index. + /// + /// May drop the lock if needed to allocate memory, and then reacquire= it afterwards. + /// + /// On success, returns the element which was previously at the given = index. + /// + /// On failure, returns the element which was attempted to be stored. + pub fn store( + &mut self, + index: usize, + value: T, + gfp: alloc::Flags, + ) -> Result, StoreError> { + build_assert!( + mem::align_of::() >=3D 4, + "pointers stored in XArray must be 4-byte aligned" + ); + let new =3D value.into_foreign(); + + let old =3D { + let new =3D new.cast(); + // SAFETY: + // - `self.xa.xa` is always valid by the type invariant. + // - The caller holds the lock. + // + // INVARIANT: `new` came from `T::into_foreign`. + unsafe { bindings::__xa_store(self.xa.xa.get(), index, new, gf= p.as_raw()) } + }; + + // SAFETY: `__xa_store` returns the old entry at this index on suc= cess or `xa_err` if an + // error happened. + let errno =3D unsafe { bindings::xa_err(old) }; + if errno !=3D 0 { + // SAFETY: `new` came from `T::into_foreign` and `__xa_store` = does not take + // ownership of the value on error. + let value =3D unsafe { T::from_foreign(new) }; + Err(StoreError { + value, + error: Error::from_errno(errno), + }) + } else { + let old =3D old.cast(); + // SAFETY: `ptr` is either NULL or came from `T::into_foreign`. + // + // NB: `XA_ZERO_ENTRY` is never returned by functions belongin= g to the Normal XArray + // API; such entries present as `NULL`. + Ok(unsafe { T::try_from_foreign(old) }) + } + } +} + +// SAFETY: `XArray` has no shared mutable state so it is `Send` iff `T`= is `Send`. +unsafe impl Send for XArray {} + +// SAFETY: `XArray` serialises the interior mutability it provides so i= t is `Sync` iff `T` is +// `Send`. +unsafe impl Sync for XArray {} --=20 2.49.0 From nobody Wed Dec 17 07:05:51 2025 Received: from mail-qt1-f169.google.com (mail-qt1-f169.google.com [209.85.160.169]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BB8C31AF0B5; Wed, 23 Apr 2025 13:54:47 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.160.169 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745416489; cv=none; b=fHKA60g0ae7evhRatWgg3pCXYqm2PUJkn5GFw1urT2TrrmRSWUKMvQYRgY3qgQWHGsy0dHbSnW2qgb2ChAoD/Ii1ahE/ge8BlpcDU4tcBfl+BdOAb8fPLAK8YUtd4lE1ZzjAaeajQPp39do4r+2T0Tj8Rjs1jRdL4Kyx0xszLrU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745416489; c=relaxed/simple; bh=OTgMdZaw+c5NGr/9Til4thtTT36TGX8yCwq4TYTPiks=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=Xx67uYPsVtoFsqfbEpb+jml3yik7IRaowWDycgXr5ltAeqryMhIEYypr0O3Y7CotgSZGJuyfPiXlwhXLw2FqFhxaH/b5ZCo/wDrl1Dg54avPiid6gNeEafT52qji86IHUux2ecWW8XeyrgmzZ58wBtOgrLSqy0wdAk+JGqfQYkM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=bsj9dmlI; arc=none smtp.client-ip=209.85.160.169 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="bsj9dmlI" Received: by mail-qt1-f169.google.com with SMTP id d75a77b69052e-476977848c4so72577681cf.1; Wed, 23 Apr 2025 06:54:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1745416486; x=1746021286; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=CuqgNpQtYEXMZS1DrSHgUIFvXUKBF5Ic3ONpr4JBBA0=; b=bsj9dmlI/y+qVwuPI8z5UWasVIqaUpV5q2DST2q7hyvF4+w8TRgf1FlNq6YddEkW3N 5/LrQdeCNE0p3ElzNCBf3HzI9ixCZW29Nj05MT7KhBeAcAgMr1YHivhaFwwf3h81vfIx bYS+kMIGxrxrqxs4xlT2AS5HLoI/F6B7g/VJ6C/CShJ5Aazf2jMyF0POrxDF3htPWawu zoA40ZWInPIfe7Hg3N64Lo19P1pNC/ZqyFDGtkbrgek6d7Nbmx2o1OAx/QATc2Fgiaaf d2zjw5o45RgHe/W66l5QbO82HG8QMuwUv/NrBjkzDkEtlbD+yuyYcuAEivOohJnL7rib 5LAQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1745416486; x=1746021286; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=CuqgNpQtYEXMZS1DrSHgUIFvXUKBF5Ic3ONpr4JBBA0=; b=WkeF8EmP46PtUhHi+0nykwtH7B1oP18MKy1dEYaCynXW8bjQxxx+BbSm5eoPxFpQJ6 ToFm/yE1pPHd8rC91eZDjoWebqo9mTJWr2S/dt3f2ZQ3w/3Aj8Uc20fCoaFmBrANkNtF lxXLhhElzjg71GyxCQpVBlRGwm55OT6a+2puJkivKps8x2NNdmCwxvb4Ry4YnKBsKs32 LXYKAiOwwHIyVyANVMA8rZX452ia/LYxKxDeRRbQeY1N1bj+Fh332PKYKAZmpOHQZDbQ MBk8K3KFyM6d4/nv2lUPWdlJPSTE7LBSu5WC45a5nOrySmfpxw5C1ve34MaluHLckLbC LS0w== X-Forwarded-Encrypted: i=1; AJvYcCUFdOSgHAjBXjjbyy/0EqFJ09XHGC244viMaaOg+5p6XgnuhsW1pLawnKu4eUDLNJHtyYLrZN/guIbs28CU@vger.kernel.org, AJvYcCUZYderfpL79wXZeaQqfhd7ZOJ4X2n1gantCzRQJ8tcb0+GNSaJeSyDrSUZzHLeWrWe6d7/i1d35OdJAnyr@vger.kernel.org, AJvYcCWO1L9JPp75OVmy/Ljm5qJLLdE7uvVlydwPVtHBkTl8idQbtLSChi7oGMxJXjptdcN3KVB1Al4k3d1O@vger.kernel.org, AJvYcCWXwhC/d5VFvQeCc7q0Qx3+KXaxxHbAu2VMZlBivfSUT1VNCF1wvo7uXuDibrpQDJVqWZtCHjaBzZlfthObzwk=@vger.kernel.org X-Gm-Message-State: AOJu0YwgW1uuisN84477ie/eBYrm3URdIcAtm/6lNOOd0evyMTVzZkw1 bzOAFitybbCbkRFbiSfYOoMtB+2mClsya1HoyPAGlJ6ZJHOJ4nSw X-Gm-Gg: ASbGncuFp4O1qhuaWyX2oTgFFA907CBHvGycdecpfF1eAzVwy+xR2RCj6Im8lrWjoxQ 6t1J7tfp4G/VLSbc6RFOc6EJx3jiXmAEe0mfjjL0E8pcmCN9zg1hHbBE05bLjZZIsTXG/EEcUOx ddKdG3bJwCb2rYnusd7eWP9sNjLvLP8hLC5OB5LYyDwReiJ2QWFLNxrf+RhHVKqAY7FC2JXACFc ri35CwisfJz/bLhiRWqAK93SP09uz2iP+bljIAWXRrFCkdmt/ELNFc4LGVfCdJBGNEVoQNep78h sdOu5SislPEf0dSi+g6M8jKwp5LB4ySE2RkE648D/1uXv731ILOoSjC/aFfds+q/2xc0ykzEicZ 1ioFYJ39PtCAWhvtY7Vr4/ydZaMUiWsmqPiH6INRe6sm+x5MrAvjEghr8UUnn X-Google-Smtp-Source: AGHT+IGeEjYsFDhltXcZCq9irwEbKANOyTBHg4Za/JkGXn9YfvMrHB2vnBRdejBXniq5yhRW3lC/Ww== X-Received: by 2002:a05:622a:28d:b0:478:f03c:b3dc with SMTP id d75a77b69052e-47aec491329mr332173931cf.41.1745416486510; Wed, 23 Apr 2025 06:54:46 -0700 (PDT) Received: from 1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa ([2620:10d:c091:600::1:e2b6]) by smtp.gmail.com with ESMTPSA id d75a77b69052e-47ae9cf9f7dsm68135461cf.74.2025.04.23.06.54.45 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 23 Apr 2025 06:54:46 -0700 (PDT) From: Tamir Duberstein Date: Wed, 23 Apr 2025 09:54:39 -0400 Subject: [PATCH v19 3/3] MAINTAINERS: add entry for Rust XArray API Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Message-Id: <20250423-rust-xarray-bindings-v19-3-83cdcf11c114@gmail.com> References: <20250423-rust-xarray-bindings-v19-0-83cdcf11c114@gmail.com> In-Reply-To: <20250423-rust-xarray-bindings-v19-0-83cdcf11c114@gmail.com> To: Danilo Krummrich , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Matthew Wilcox , Bjorn Helgaas , Greg Kroah-Hartman , "Rafael J. Wysocki" , Tamir Duberstein , FUJITA Tomonori , "Rob Herring (Arm)" Cc: =?utf-8?q?Ma=C3=ADra_Canal?= , Asahi Lina , rust-for-linux@vger.kernel.org, linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org, linux-pci@vger.kernel.org X-Mailer: b4 0.15-dev Add an entry for the Rust xarray abstractions. Acked-by: Andreas Hindborg Signed-off-by: Tamir Duberstein --- MAINTAINERS | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index fa1e04e87d1d..925d64be9dd6 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -26310,6 +26310,17 @@ F: lib/test_xarray.c F: lib/xarray.c F: tools/testing/radix-tree =20 +XARRAY API [RUST] +M: Tamir Duberstein +M: Andreas Hindborg +L: rust-for-linux@vger.kernel.org +S: Supported +W: https://rust-for-linux.com +B: https://github.com/Rust-for-Linux/linux/issues +C: https://rust-for-linux.zulipchat.com +T: git https://github.com/Rust-for-Linux/linux.git rust-next +F: rust/kernel/xarray.rs + XBOX DVD IR REMOTE M: Benjamin Valentin S: Maintained --=20 2.49.0