From nobody Fri Dec 19 19:23:38 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7BF042E6106; Wed, 3 Dec 2025 22:28:04 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764800887; cv=none; b=kNhY3TLvbIClO+FiFyTZEMNnpZmfNEMSR4SkC7Vdr4SN+mnTmeDsnF4DiR2VyuYVnpQvl21McLJrmuipw+MZ7WzOTKck10AbSbg3ReqCnzdJWl+92G5j9XV+lIgg6LPUCd+N2fgw7nQpEe7K1V3y99YxPrTP6majzMeLipiq3MQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764800887; c=relaxed/simple; bh=FiVEAF/tWJvB6+o0z58DaKdND505fxL1cM+NJxp039c=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=pmceqtGZtFa/+lrYzBGemYKvsmA6dadXvS8uSEKaeiFLYmL2WQGjARNR+uFYWdhrfrgBerjndP3aWqD5Qs/MAFHSG2HkVC+HuFI1g1fC0sUihUSErEuOkQw+x46hxJDU/YJxrc45f+8Hceui0Jbt3xk0yhc0BwLndPQdV4jftPI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=DtAD2I/A; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="DtAD2I/A" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A7D86C4CEF5; Wed, 3 Dec 2025 22:28:00 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1764800883; bh=FiVEAF/tWJvB6+o0z58DaKdND505fxL1cM+NJxp039c=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=DtAD2I/A1S7nSAuVdd5a+6uv3vWMDq+Z1dLNAB0mfeRX7Ik8ri2M49CNcybOLl84m admqzifAnI5b/qMnyjbQPmjwHhBRMnqseEG8aQ4eBk/3gLPSfsa+5OC2QrNoU0MwSA fmVirfpHqVDQlZpMOLqc/cYf2FJTiWxZcC/CS2sRNfbEBK9+QJV4KUARcpjyAgABLg 8191xgQMaXpO9tuNzDlfk5UuTPsnx+R3CpD2KhX0hmfEHOUFQ8guNd8DtaEXz0ZbE1 yRyykncA9SVVqJGNCRJKHZs2jjaGlPDUMTn0seqpTh6zuWk9MRqVqUuk0Qm7x6ejEY DSiFRFIDDTWUQ== From: Andreas Hindborg Date: Wed, 03 Dec 2025 23:26:31 +0100 Subject: [PATCH 01/10] rust: xarray: minor formatting fixes 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: <20251203-xarray-entry-send-v1-1-9e5ffd5e3cf0@kernel.org> References: <20251203-xarray-entry-send-v1-0-9e5ffd5e3cf0@kernel.org> In-Reply-To: <20251203-xarray-entry-send-v1-0-9e5ffd5e3cf0@kernel.org> To: Tamir Duberstein , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Danilo Krummrich Cc: Daniel Gomez , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Andreas Hindborg X-Mailer: b4 0.15-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=2022; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=FiVEAF/tWJvB6+o0z58DaKdND505fxL1cM+NJxp039c=; b=owEBbQKS/ZANAwAKAeG4Gj55KGN3AcsmYgBpMLkqh9Qpuw/Hh7FSu8B885HJUpBKwpyq25WAy 2o4r3+P5Z+JAjMEAAEKAB0WIQQSwflHVr98KhXWwBLhuBo+eShjdwUCaTC5KgAKCRDhuBo+eShj d46kD/wJ74iqA5i0KeniV0//o+V0vmg9FJr47Y8djZL5Zrcq9XsI0wtjuD+BwLVTka9+xGmyN0K jK342I5LUI1+rpTO37rl1migYscEg7Tv3XEwkx8UB2JjPWrP98LjlrohtiwGNF5CEaawSo4Q+US gYlw5/eJ5J6xH+40dxIo0j+XCLZGs5jq7Ab2OLXqwKSsNNGa+W1UROuWSF9J+eceWvN/dsRZ3fx wrgMU1GYtOcdi1YeLmF2mkYbnjqPHKd2J7mXqRhdJ1NPyXg9Vlu6dr1u36ku8oKI3cUPzJVXS0Y CBIKs73qcnIh+TNupyL/wVKKQjSxSkMJwNdNgDBrnd2ZzqlyAnnGoDniQI7bMBkejDdnHRUERpD rP/3exluW3cmXGltiS3PM5PSRecFrECCnIBr7PmnVJshtLLNPY+tMGh9pbcmuUjZvOuitOy8bof mN5Ju+qOHp7vhjjDrzG+TqYYLoLfwAXNh4QbC3Qu9DAJX6hLXk3VDuyXM+8skYGlkXU2USrCfWT IGup8frhlLbJ9WP0JmmnOeKum5VsY+marOXGfjIRyT1FxBvmn5SRRAkwHwS5NlK2boWjjY26AAL DfwJbo+N4ZCd/Mg71oBfh7qj/5BhE0akp8mBOGQFiRLj0MhAUHDOcW/BO1M6lnrjOVEYNlmRKFm Ckt6iWVPF6BW3Zg== X-Developer-Key: i=a.hindborg@kernel.org; a=openpgp; fpr=3108C10F46872E248D1FB221376EB100563EF7A7 Fix formatting in xarray module to comply with kernel coding guidelines: - Update use clauses to use vertical layout with each import on its own line. - Add trailing empty comments to preserve formatting and prevent rustfmt from collapsing imports. - Break long assert_eq! statement in documentation across multiple lines for better readability. Signed-off-by: Andreas Hindborg --- rust/kernel/xarray.rs | 36 +++++++++++++++++++++++++++++------- 1 file changed, 29 insertions(+), 7 deletions(-) diff --git a/rust/kernel/xarray.rs b/rust/kernel/xarray.rs index a49d6db288458..88625c9abf4ef 100644 --- a/rust/kernel/xarray.rs +++ b/rust/kernel/xarray.rs @@ -4,14 +4,33 @@ //! //! C header: [`include/linux/xarray.h`](srctree/include/linux/xarray.h) =20 -use crate::{ - alloc, bindings, build_assert, - error::{Error, Result}, +use core::{ + iter, + marker::PhantomData, + pin::Pin, + ptr::NonNull, // +}; +use kernel::{ + alloc, + bindings, + build_assert, // + error::{ + Error, + Result, // + }, ffi::c_void, - types::{ForeignOwnable, NotThreadSafe, Opaque}, + types::{ + ForeignOwnable, + NotThreadSafe, + Opaque, // + }, +}; +use pin_init::{ + pin_data, + pin_init, + pinned_drop, + PinInit, // }; -use core::{iter, marker::PhantomData, pin::Pin, ptr::NonNull}; -use pin_init::{pin_data, pin_init, pinned_drop, PinInit}; =20 /// An array which efficiently maps sparse integer indices to owned object= s. /// @@ -44,7 +63,10 @@ /// *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.store(0, beef, GFP_KERNEL)?.as_deref().copied(), +/// Some(0xffff) +/// ); /// assert_eq!(guard.get(0).copied(), Some(0xbeef)); /// /// guard.remove(0); --=20 2.51.2 From nobody Fri Dec 19 19:23:38 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 7D7A8257423; Wed, 3 Dec 2025 22:27:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764800850; cv=none; b=mAMXwThMJ9NuAu8XstFCsSuCQcHRiWO+JdgC5PTMrzCMijwCNOOuzPDS7n4WLkoiz1vgKO4r0JKOxVNQAWRuWOTIZzeA1se+qtw4sn1rjXsRmF6de0fYXKXYRFTQszY/1UrFsMmr2M4md/Ex11Y7C179c6RITJUUINQoRGBosbE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764800850; c=relaxed/simple; bh=hBStdRM9X9Jt48Srj4ZInprCU4w1LOwO5wapy+gyHPI=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=mCv6ZLKZySxH1K2woSnQpikPrPmGlV+uuN8AzkaGJluJewYS09SXdogctC4AAbB/VcLvimwJPCjGURTJvyh3gCO9DWiI0MP53LNBL6IhgyW71O4c6FtVza59jhLmdFtLYYL25FJ9i2Ry00HMIMikKhzutfVd+VXmZQ7u5acLPUg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=imjqwTyz; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="imjqwTyz" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0DC6CC4CEFB; Wed, 3 Dec 2025 22:27:26 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1764800850; bh=hBStdRM9X9Jt48Srj4ZInprCU4w1LOwO5wapy+gyHPI=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=imjqwTyzZv9TOsS9aY7U8iYCdE59jqOhIZeuuIyFp1BaBQX2/qxh/3ocW9X6DuGm2 mWmN66FFQvM/klLPlTW3f4nxt17I+PR3V86I/9se7C/x4Y+J7XLXhZDU4tBhiCDW5a 4t4nQjtsynw+tELiqwZAabTscay0OgyBAHxg3CfOW4AMp4rNUl1sVGsfcmiKwNTuf9 SSxE/mD8z5ticF253cGG5BUvrIHXOQAfp/OxkIl8uueiYTW7VBOdjHAWzawW73eb3L Ct17IDmB5XOUzGrXNY5EgAjyuMGzmzWzSGLTOXhgvBYJW3FKVIhzPYu91WbLdBexdO blPufEVTLFQ7g== From: Andreas Hindborg Date: Wed, 03 Dec 2025 23:26:32 +0100 Subject: [PATCH 02/10] rust: xarray: add debug format for `StoreError` 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: <20251203-xarray-entry-send-v1-2-9e5ffd5e3cf0@kernel.org> References: <20251203-xarray-entry-send-v1-0-9e5ffd5e3cf0@kernel.org> In-Reply-To: <20251203-xarray-entry-send-v1-0-9e5ffd5e3cf0@kernel.org> To: Tamir Duberstein , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Danilo Krummrich Cc: Daniel Gomez , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Andreas Hindborg X-Mailer: b4 0.15-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=958; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=hBStdRM9X9Jt48Srj4ZInprCU4w1LOwO5wapy+gyHPI=; b=owEBbQKS/ZANAwAKAeG4Gj55KGN3AcsmYgBpMLkrrnqqd5Sd6Ic5e5aBvn1txrqQChgkKEEUi PsZvWjtnViJAjMEAAEKAB0WIQQSwflHVr98KhXWwBLhuBo+eShjdwUCaTC5KwAKCRDhuBo+eShj d/AhEACJOCDpykNiDw9nMM6tndOzrPQvnjYsL9QG1CmukuDpRHL/kI9RXcEN9tTwqmXK7u9AjQj StEDhnOmntUzWSt0nw8pmWLE9rTCj47lir8e+N1PV0DBt1d/vJrFENfWQ/l/JUb3DsmHZa9rSIc 1xXydxKjWQ0ldahuTB5SrjeG5GPNWfN3MzPvhHmBOPC5vu0IDfXrk/OJlh5gAtiZIGeATqtZyU4 OokAQ36zOd+qSf0J7D52YefDJmsNNlyK+gvJWu7ejCtjghF7GDQEul42PwO2B2qyWR7DJea2icr OrSSk/jDNSSHFcZjxFEiDplTF6dgffikA9cZuqVQwLW12SkZ5RR9rCMQBkFOzEItefOBI0d2Lhj kcqNHWGsGhSSifIQ1dvKNi/OGYC9wb+Jo/I+9APTHwUCi1YYTTBdkoSpZ0NAQhIpoaMh3K0Vz1k YQm+tWQccbc7l3/483/mv0FJpWxEEL914a/GdOLB/c0CMZ0AjSgSQ95XJIdk7Y60yXtS29BcqC6 P41j3f6DjGaNwpzgAqBAjQhtu9YDwsF4GTmSNuRrlF28MLItDAZPryGD024NsEH0t4/NlnE1ag8 4rfu9OPMgvYl+0BlKai4WgFsDmrKFgcCWzTo0DB68qdsqSpPq3c8RgDpaGnST+KZZLAkruRPk1K eCdz1QsCl6bhZRg== X-Developer-Key: i=a.hindborg@kernel.org; a=openpgp; fpr=3108C10F46872E248D1FB221376EB100563EF7A7 Add a `Debug` implementation for `StoreError` to enable better error reporting and debugging. The implementation only displays the `error` field and omits the `value` field, as `T` may not implement `Debug`. Signed-off-by: Andreas Hindborg --- rust/kernel/xarray.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/rust/kernel/xarray.rs b/rust/kernel/xarray.rs index 88625c9abf4ef..d9762c6bef19c 100644 --- a/rust/kernel/xarray.rs +++ b/rust/kernel/xarray.rs @@ -193,6 +193,14 @@ pub struct StoreError { pub value: T, } =20 +impl core::fmt::Debug for StoreError { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.debug_struct("StoreError") + .field("error", &self.error) + .finish() + } +} + impl From> for Error { fn from(value: StoreError) -> Self { value.error --=20 2.51.2 From nobody Fri Dec 19 19:23:38 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DF16E2E2F0E; Wed, 3 Dec 2025 22:27:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764800873; cv=none; b=i/8KjgYnwU0IyTHvGuArHm6CfJk6DMpVx4YTVGN4B1UO2UptCIV5Idwq6u/sHkicTtD0ggIqix7m+FBnrQzw5VAezLg9u249WwR+QL1HTUxGmf1ADdP9PKZfZnsUnpQ6h4vTIYMMAmcwmF6mgEAc+T5XNxF8GZsws/dTgE2/eEY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764800873; c=relaxed/simple; bh=PrcApbk7BCNSPsQwnef2I6IdaZ2i07Y2ln8fzlwV9sQ=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=mq578Jee8mPr3qbakykzYkf9U9yGVYBXrhmjpquYRq0E7SIvt93iufjWwQlM8sJELft+ccU8BsTUo37GNmBUbpy4KCtH2su1N+syRHTNlengV9RIim7/df1B8/wJRDJqbBjvIvnTK9C6N8kjAkNn79HWmaqX1BdpIePaiHEaaME= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=m0jP/Ud0; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="m0jP/Ud0" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AD64DC4CEFB; Wed, 3 Dec 2025 22:27:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1764800872; bh=PrcApbk7BCNSPsQwnef2I6IdaZ2i07Y2ln8fzlwV9sQ=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=m0jP/Ud0yOa10gIlxWprE9/j4xwsLyPG4pp22VYwn3LR9gbwlytJlZWvZ7/XHTZJT 5XQGVla9xE7q+Ug1Lo8oLaocWIfC4OOjZLDJuRhr5+wTLEw7X2WivNgZTmUjWhqNX/ QZZF9So8QuldZOau1jhj/tid0JtrIjF/ebVq28vG0bLc8KvGZwzTznNadD9JpEyUwR rFzKB+hwrJV84gID6ajzUQZCt/Pwpq4gOgKE+20x62Iy3e3ZH9oYn5Jt/C5f5Xx8iD dkLqy83j6Q+qlili/Cfm1BrKltw4kAOowq+AM0QbORrEkPjkBEKz3LRAs9m/ehf02h RtwuNtKsI7MyQ== From: Andreas Hindborg Date: Wed, 03 Dec 2025 23:26:33 +0100 Subject: [PATCH 03/10] rust: xarray: add `contains_index` method 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: <20251203-xarray-entry-send-v1-3-9e5ffd5e3cf0@kernel.org> References: <20251203-xarray-entry-send-v1-0-9e5ffd5e3cf0@kernel.org> In-Reply-To: <20251203-xarray-entry-send-v1-0-9e5ffd5e3cf0@kernel.org> To: Tamir Duberstein , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Danilo Krummrich Cc: Daniel Gomez , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Andreas Hindborg X-Mailer: b4 0.15-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=1538; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=PrcApbk7BCNSPsQwnef2I6IdaZ2i07Y2ln8fzlwV9sQ=; b=owEBbQKS/ZANAwAKAeG4Gj55KGN3AcsmYgBpMLkstUvW7+YPAChWwj2PNQcLbewxGouH19f/x ZM8ruj3xGSJAjMEAAEKAB0WIQQSwflHVr98KhXWwBLhuBo+eShjdwUCaTC5LAAKCRDhuBo+eShj d5sGD/9g3byBD9oFAUj6QRSDtU1XnB2ifRdbJ/bCAiFS1M+C/K9xEDjhpCpi8kfWMpl4xpAtUSZ Lp5nFt6y6h0TYfUkuKKjuo8ONYHFh6TFrScqjpAWParm5hc69KAuAWDs5ZUs7pDO+taJSsVhWnG mZzk0wj5DltOSfE7kvek01rU4CcRW/q8FXNEorxC5VZ4Qo8qWtKGLQ6w1ADL7otDa/b2mkYdvMa ZEfEZ4vX4oUsomz6Hv55j6I9JR6HyQ4BKN2nmhwpjzO/zJkpywbcoBxt2mGF1RilEym+EtbTiP5 o5UuY5MsFvX6T24QcgUPgOdSy4vpGQ8Mm2Tv6XHQOpan4Js3sxftjoI238TCzc3B9X03MaEft4G qSV4mOJW1v+J4q9Xee+uGEWcvCsFlvLBSlzRMQO28wk52p4yTKapAgfianXpSeAsHmHCzePalm2 eF/hWIUIbt9RiaQxbxjH/CkrHxINK9ynesAaLli2ODcvuclepJfn1jFcxMeRETXVsWPKFXzNOWc CMBqV2lLXZkz8L75TBWaCbWyHXOwCO5LvtfIfH4IiJhbXnJqbnFbNb2x19RralZSet1QlM5Dqb7 zCaaMAMqztcR6cvBowZkTsXqfQJUwobUIt49gQpMmWgNKiwW2Z7M5OFgtQdka3tuAVLl1K5MkD8 xMmnQgeGSBafjng== X-Developer-Key: i=a.hindborg@kernel.org; a=openpgp; fpr=3108C10F46872E248D1FB221376EB100563EF7A7 Add a convenience method `contains_index` to check whether an element exists at a given index in the XArray. This method provides a more ergonomic API compared to calling `get` and checking for `Some`. Signed-off-by: Andreas Hindborg --- rust/kernel/xarray.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/rust/kernel/xarray.rs b/rust/kernel/xarray.rs index d9762c6bef19c..ede48b5e1dba3 100644 --- a/rust/kernel/xarray.rs +++ b/rust/kernel/xarray.rs @@ -218,6 +218,27 @@ fn load(&self, index: usize, f: F) -> Option Some(f(ptr)) } =20 + /// Checks if the XArray contains an element at the specified index. + /// + /// # Examples + /// + /// ``` + /// # use kernel::{alloc::{flags::GFP_KERNEL, kbox::KBox}, xarray::{Al= locKind, XArray}}; + /// let xa =3D KBox::pin_init(XArray::new(AllocKind::Alloc), GFP_KERNE= L)?; + /// + /// let mut guard =3D xa.lock(); + /// assert_eq!(guard.contains_index(42), false); + /// + /// guard.store(42, KBox::new(0u32, GFP_KERNEL)?, GFP_KERNEL)?; + /// + /// assert_eq!(guard.contains_index(42), true); + /// + /// # Ok::<(), kernel::error::Error>(()) + /// ``` + pub fn contains_index(&self, index: usize) -> bool { + self.get(index).is_some() + } + /// Provides a reference to the element at the given index. pub fn get(&self, index: usize) -> Option> { self.load(index, |ptr| { --=20 2.51.2 From nobody Fri Dec 19 19:23:38 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 637B22E3AEA; Wed, 3 Dec 2025 22:27:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764800865; cv=none; b=pjgDp6wfsR9Q4cvUk1uEaL2Z7Es+1TkBXlvQ2gRELIxZQR9GOEg65N8eNrU7O5JskF0Czv2ufKKVW8g7lvPfuK3dmRJkotdg+kcNnuQn9pBDIfB6g+swRymJHZ0S0eAv2/0+wLDNor3UBi76yNhNYrlSGlSh0uWSD95hJXB0bnE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764800865; c=relaxed/simple; bh=6AoK80zUJhrQ3fbZgad6VdXkWCk/JukGAqPmhDOpdmE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=au+eAOzsrlGyT+uFafQ0/F5z6IXBEwuq2roLVKiSeIR6bMIQgnlYJxO7czW6gdIB84MOaNC8pe46GqIxTCiL9GkW2grIY8/WttjzNNQywo7PFsmNJ6ILVs/s36ZbYKIe8bNw8eclDCdXH6xzGDx34MeJbgbJkpJAvvnONpNV+wE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=dpOpyTk1; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="dpOpyTk1" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 7CC52C116B1; Wed, 3 Dec 2025 22:27:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1764800864; bh=6AoK80zUJhrQ3fbZgad6VdXkWCk/JukGAqPmhDOpdmE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=dpOpyTk1dpBHVEPrey51Z3G/4xVbNzdP8SEOrD+Q3j6wU+fNn+l5K3VvdmPo4M5nn +q+fKmLF4Z+TFJlV+yLa5hly7BYFr1WabB4+gzMHoPgd3o9jWPg/wWZgv7OOr7ToZK A/GC2CYEF/hWYldqyd6KIkrJO7zCrVGcY7qPO3rW8j8fQDYFaSJdIVWgvr2Uw/CBU6 qC4yE16pPaTBnsvExyORwFuC8dg7zciSAEeU/sTsjwZ+7+JIguvSv/0bZdv5FhClRz PMRPRr7N0Hk6E9zH77d1rmIMu784xQI9R2s0O8wos62w7E+82NtfxXmos5Zx1hPejM ihkpDksGbUBjA== From: Andreas Hindborg Date: Wed, 03 Dec 2025 23:26:34 +0100 Subject: [PATCH 04/10] rust: xarray: add `XArrayState` 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: <20251203-xarray-entry-send-v1-4-9e5ffd5e3cf0@kernel.org> References: <20251203-xarray-entry-send-v1-0-9e5ffd5e3cf0@kernel.org> In-Reply-To: <20251203-xarray-entry-send-v1-0-9e5ffd5e3cf0@kernel.org> To: Tamir Duberstein , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Danilo Krummrich Cc: Daniel Gomez , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Andreas Hindborg X-Mailer: b4 0.15-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=3170; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=6AoK80zUJhrQ3fbZgad6VdXkWCk/JukGAqPmhDOpdmE=; b=owEBbQKS/ZANAwAKAeG4Gj55KGN3AcsmYgBpMLktFKvciv9Nl8Br57MpZsQcuCiW62bkACaG3 r8Q99WMoC+JAjMEAAEKAB0WIQQSwflHVr98KhXWwBLhuBo+eShjdwUCaTC5LQAKCRDhuBo+eShj d8A0D/9ykjfxH+r2py6dhev34wNp/GG5691VAzY2B3j5DHf1wtbrzfT04mQk926p1XtA5VwIRxN wigud3to1pMXXvKTJSXjiaXV1XdufDZGsmOtdC58Fracucgs8CbCpL7SHtG+tIEXjEt8alHAi7c xRL6gP9PTTcpqcFnrLOA+LaFQ7ZxFayeFhWN+WsV6kNnyLrll60jGSgbdAdxLM9nVQgXHPxwN6M NTBw4LGZ8VhJNsk+K2yIXJkAttxxCbZitkWgH/1r+C2SJTk1N3RHG1aQS0oiUeLwDTrBBYWA1Cf PLUYfY+VZh5dCmhDkceF13aVnqVdq3JUo8JocvPJaGgK6PIthrItKqlksAQRveeGRVaPhmDpdh3 IDt8FZCPTaIhbvgJBRmkTbODUoF8P4Q3TVMe4k4uP1TA869rdmxrx2r0wqfRlMMGkEc1/KfmXla +tniPonhiu8B1d4l0c2J69xA4o1FdR4KmCwGbElJgwjXkjCxRNixFQ6+qpgryRyBb8sleZJm/xM MvWZ0IwnxXJDvgSJJQHwoFxnpHFF1TLjyAZ38V1pfvxpOa5Bo8OmBqd/ypwELyqYWjbMMHmX4Xp PWhQUiw9McVNvrbzI8YxORIJM4VLG73ty17LKhIqEjYSjcQDIgsthKBru3VaBVmWSuZokRwFLl/ 6CRksU53EuDhfKw== X-Developer-Key: i=a.hindborg@kernel.org; a=openpgp; fpr=3108C10F46872E248D1FB221376EB100563EF7A7 Add `XArrayState` as internal state for XArray iteration and entry operations. This struct wraps the C `xa_state` structure and holds a reference to a `Guard` to ensure exclusive access to the XArray for the lifetime of the state object. The `XAS_RESTART` constant is also exposed through the bindings helper to properly initialize the `xa_node` field. The struct and its constructor are marked with `#[expect(dead_code)]` as there are no users yet. We will remove this annotation in a later patch. Signed-off-by: Andreas Hindborg --- rust/bindings/bindings_helper.h | 1 + rust/kernel/xarray.rs | 41 +++++++++++++++++++++++++++++++++++++= +++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 2e43c66635a2c..86bca946faff0 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -109,6 +109,7 @@ const xa_mark_t RUST_CONST_HELPER_XA_PRESENT =3D XA_PRE= SENT; 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; const vm_flags_t RUST_CONST_HELPER_VM_MERGEABLE =3D VM_MERGEABLE; +const size_t RUST_CONST_HELPER_XAS_RESTART =3D (size_t)XAS_RESTART; =20 #if IS_ENABLED(CONFIG_ANDROID_BINDER_IPC_RUST) #include "../../drivers/android/binder/rust_binder.h" diff --git a/rust/kernel/xarray.rs b/rust/kernel/xarray.rs index ede48b5e1dba3..f6e610b059625 100644 --- a/rust/kernel/xarray.rs +++ b/rust/kernel/xarray.rs @@ -8,7 +8,10 @@ iter, marker::PhantomData, pin::Pin, - ptr::NonNull, // + ptr::{ + null_mut, + NonNull, // + }, }; use kernel::{ alloc, @@ -319,6 +322,42 @@ pub fn store( } } =20 +/// Internal state for XArray iteration and entry operations. +/// +/// # Invariants +/// +/// - `state` is always a valid `bindings::xa_state`. +#[expect(dead_code)] +pub(crate) struct XArrayState<'a, 'b, T: ForeignOwnable> { + /// Holds a reference to the lock guard to ensure the lock is not drop= ped + /// while `Self` is live. + _access: &'b Guard<'a, T>, + state: bindings::xa_state, +} + +impl<'a, 'b, T: ForeignOwnable> XArrayState<'a, 'b, T> { + #[expect(dead_code)] + fn new(access: &'b Guard<'a, T>, index: usize) -> Self { + let ptr =3D access.xa.xa.get(); + // INVARIANT: We initialize `self.state` to a valid value below. + Self { + _access: access, + state: bindings::xa_state { + xa: ptr, + xa_index: index, + xa_shift: 0, + xa_sibs: 0, + xa_offset: 0, + xa_pad: 0, + xa_node: bindings::XAS_RESTART as *mut bindings::xa_node, + xa_alloc: null_mut(), + xa_update: None, + xa_lru: null_mut(), + }, + } + } +} + // SAFETY: `XArray` has no shared mutable state so it is `Send` iff `T`= is `Send`. unsafe impl Send for XArray {} =20 --=20 2.51.2 From nobody Fri Dec 19 19:23:38 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id ECC342E3387; Wed, 3 Dec 2025 22:27:56 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764800877; cv=none; b=XuXtnbRWQ/xB73uZV4yN38Cr4GahP11kaTL0PgpCVxvF5gcF/IPEWEnD7L2jC5rzszw2ZXzjyeXvT2EFh5mcVA5GoAbpjGzgj7FmAP0yS9y21RuXIy5Hbsu3KwcId2RzdSqN76l7T955+3teQkV8zfcpP6t8k+mQOWgpmlqI5C0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764800877; c=relaxed/simple; bh=r8fjJ/0sJNZXN0VhQA4fesjTQ4dU92nbou+EK9lKlUs=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=lGfNYN4aq2+nmj1NzLc0VPIlj5F7Z41a6asIOjWDURWfUHLTIiYUBIa/A6TL+aS7ztJbPyz+p78IZyyj2SmaTmCd7bd2xjOORWjqe0ZVmqxEFVmcx6fIzT9SK4tljVZvDRoVnZG/aXa6PWZXpwcfzhSc7FOlok5R6hMXccPvIWU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=n2IruBOq; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="n2IruBOq" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6D9A2C4CEF5; Wed, 3 Dec 2025 22:27:53 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1764800876; bh=r8fjJ/0sJNZXN0VhQA4fesjTQ4dU92nbou+EK9lKlUs=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=n2IruBOqnajoVd/lykfvDi4LKv7kv7WvRDzlkoz+u29dSGsqFaOhnZcnXsRN8+SXB XPoRHqahlQ1ySBQBG6huGLB/V+4tR821BpoKBmp6RqNiizRsE2lk3vQmHciWI2/MEt bIzXDiv0BwbNbN6VRiESRIZdXyOwquxdWDXiBQ8mlWeSkjuJAqlZCbhpm7iXD0we5r LG6Ydph/sAaQ+zWeezSwLePe/orUydUpekWvWWMA8Frqn64lxfPybmlk9p12uih9dw SQpuyW3+Im9f0VdjgKVVsRzOUOiwXTzgb0xI79L7kSOAS4Oo1GyghQy1uF3qeR4nwl zKZysuQ/4Wa6A== From: Andreas Hindborg Date: Wed, 03 Dec 2025 23:26:35 +0100 Subject: [PATCH 05/10] rust: xarray: use `xas_load` instead of `xa_load` in `Guard::load` 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: <20251203-xarray-entry-send-v1-5-9e5ffd5e3cf0@kernel.org> References: <20251203-xarray-entry-send-v1-0-9e5ffd5e3cf0@kernel.org> In-Reply-To: <20251203-xarray-entry-send-v1-0-9e5ffd5e3cf0@kernel.org> To: Tamir Duberstein , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Danilo Krummrich Cc: Daniel Gomez , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Andreas Hindborg X-Mailer: b4 0.15-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=2065; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=r8fjJ/0sJNZXN0VhQA4fesjTQ4dU92nbou+EK9lKlUs=; b=owEBbQKS/ZANAwAKAeG4Gj55KGN3AcsmYgBpMLkuKU3p0iqxIBnW8ULt0GY0mbkZX6Zf2liSI OQaLf7gLhKJAjMEAAEKAB0WIQQSwflHVr98KhXWwBLhuBo+eShjdwUCaTC5LgAKCRDhuBo+eShj d2egEACF9HiF/fncSnF3nAlEcDK8KdpoXEoYTRiUW5GNVtYCSEKjGOnXhsUe9f6dUuP4jhi2nyu aKxtVRmF7kJVvsCTrj7OnZmPUNps2Oes4Qph9ViKQxPTl8ykBoxGAme0apwOIJ32zRkx6xlNNk6 bnn7oRoykBokq9OoQFEl8Qm0X99Guqt6v4RH9VAp3MXAlDY2qwW6EHtBAWoSb3Xvdf2NM7yf2C/ UFeYu4Zj1vzIzXOo1gJ5acsgN64oqcSq34vqZXDZlP9LkYqiY8RxWMnAUtiXZR8p0F1bd7UepaJ /jvzaOLy0dpDalzFavn+9pQDLGHXa5F5qwzVWHbL2cpabP92I6CsPYL9AT9XzZSK87fkjRXOoco fwdaTqmPlvVaYZlysBwxTt2CNq3t7Zz9w4LnNmZDxk7OaeUwHj2zsgpT8+JsgeslGCrJfpYGJ3T iN58SN35VqM8mAK5oMs3oFmFXKr/sVxnGfTApulbEwKTzMK+nPdUV1Npomb6hbSn6AusK7K5LzP EB/zCQLRuCSWytP75d1YTk1FofpDl/bdWFv0t5C/NIaYRXlRCJEcVaZPJIjUqef7Asde+T0z0qB 3uyEVmZnOFmtK9oD6p0Kf4W21EEEVQZWe+ii0F1vz8TLn5hjiQlA9N7dDdiR0s7cjlb4SQZA7vr WuXUJ0ryoue4/jw== X-Developer-Key: i=a.hindborg@kernel.org; a=openpgp; fpr=3108C10F46872E248D1FB221376EB100563EF7A7 Replace the call to `xa_load` with `xas_load` in `Guard::load`. The `xa_load` function takes the XArray lock internally, which would cause a double lock since the `Guard` already holds the lock. The `xas_load` function operates on XArray state and assumes the lock is already held, which is the correct API to use when holding a `Guard`. This change also removes the `#[expect(dead_code)]` annotation from `XArrayState` and its constructor, as they are now in use. Signed-off-by: Andreas Hindborg --- rust/kernel/xarray.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/rust/kernel/xarray.rs b/rust/kernel/xarray.rs index f6e610b059625..0f69a523b72bf 100644 --- a/rust/kernel/xarray.rs +++ b/rust/kernel/xarray.rs @@ -215,8 +215,10 @@ 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 mut state =3D XArrayState::new(self, index); + // SAFETY: `state.state` is always valid by the type invariant of + // `XArrayState`. + let ptr =3D unsafe { bindings::xas_load(&raw mut state.state) }; let ptr =3D NonNull::new(ptr.cast())?; Some(f(ptr)) } @@ -327,7 +329,6 @@ pub fn store( /// # Invariants /// /// - `state` is always a valid `bindings::xa_state`. -#[expect(dead_code)] pub(crate) struct XArrayState<'a, 'b, T: ForeignOwnable> { /// Holds a reference to the lock guard to ensure the lock is not drop= ped /// while `Self` is live. @@ -336,7 +337,6 @@ pub(crate) struct XArrayState<'a, 'b, T: ForeignOwnable= > { } =20 impl<'a, 'b, T: ForeignOwnable> XArrayState<'a, 'b, T> { - #[expect(dead_code)] fn new(access: &'b Guard<'a, T>, index: usize) -> Self { let ptr =3D access.xa.xa.get(); // INVARIANT: We initialize `self.state` to a valid value below. --=20 2.51.2 From nobody Fri Dec 19 19:23:38 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 5AE152E2F0E; Wed, 3 Dec 2025 22:27:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764800861; cv=none; b=hMYNIsBtJ+heJmlW9XQmLmAbJsiN1ZOmqDYXqhW5sba4nMEe4EUC+pna57MZvyCI5W2zgZZX6v9hCXHSmetUkEgYR91eObsoyEPsxmBy5GaFp6eZGVoYorypIkTh3l6ug6bkbImwPKrNTJZghKk+IqWARStL/Xfpe9cBAfGUQxc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764800861; c=relaxed/simple; bh=Vhypvds1yvFWGBDtAQE1W2d/uxGhxuDAxur/sfhCxJw=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=SVa+j+C+CB+3uHg55ThuWM7GrxW29FwTmKM+e/yDDyRotHdvQJxFmdtIRoFfPXbhwn9NuEXTsX7BCv0p78Z5+fN+xHhiD+1gwDCzqETKK+3A+hZmE1cVVJF9WfgpLw53dImXoZLIXTQPlzoULRonTTMIL5INToO+Xvd25INVS88= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=g+rkN+5+; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="g+rkN+5+" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C5AF4C4CEF5; Wed, 3 Dec 2025 22:27:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1764800860; bh=Vhypvds1yvFWGBDtAQE1W2d/uxGhxuDAxur/sfhCxJw=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=g+rkN+5+9Zj6Kklsa6v2qJZZw0diJ7Zi5Lr0vTPz66NIVh/1kbZMCt9TGbtwZDO6S hH5a6DeHSHbcvAUzL8ty25q8YWyN+4M3F7JZsrb0uo88ooah2JymnvMMLyU9Bpwjkn L8K7h3wfYtlRzAPmg7PhOyPaHR0RGC+ypPc/dvpH1hImXS7i/E3O1h6CPKCTt0EWhM hiY3zmugsm8a2F8ttmeKjYvHDiGufc6dxzxb54nSZME5tHy6ObSv6uy01KJ7OYcJ/i 3v1PgERI3rmUeJY2hda9N4jrmci/HFbcyxZ44v4/RXG6p5uJ9hQBKVT1RQZw4Kl9xc m3lA/yjl9Ty0w== From: Andreas Hindborg Date: Wed, 03 Dec 2025 23:26:36 +0100 Subject: [PATCH 06/10] rust: xarray: simplify `Guard::load` 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: <20251203-xarray-entry-send-v1-6-9e5ffd5e3cf0@kernel.org> References: <20251203-xarray-entry-send-v1-0-9e5ffd5e3cf0@kernel.org> In-Reply-To: <20251203-xarray-entry-send-v1-0-9e5ffd5e3cf0@kernel.org> To: Tamir Duberstein , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Danilo Krummrich Cc: Daniel Gomez , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Andreas Hindborg X-Mailer: b4 0.15-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=2272; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=Vhypvds1yvFWGBDtAQE1W2d/uxGhxuDAxur/sfhCxJw=; b=owEBbQKS/ZANAwAKAeG4Gj55KGN3AcsmYgBpMLkvXrKRMLN78CDUJHyCaRMTTddgQYNbRMGd0 KZXNmMzjLGJAjMEAAEKAB0WIQQSwflHVr98KhXWwBLhuBo+eShjdwUCaTC5LwAKCRDhuBo+eShj d7w7EACPMTAQjYEq5yx49FDr0w4PU7trnOWIUvIYXb7K3otLjk3ln3v4WsZfd8ORz74k9/sIf/Q Vi3PMpSn3mp9fNYAgH4P0CtPz9I6lyOEvVX6rHZS9ciiMkzNEJ4A7HrG+Mmcm+NC79+V7nH5f96 nI0xHyKuqf+HW9auDVUUud1AEfxzpI3KLgjF8uuxvB/Wm/PmqMz+BYrAOkLs53OXMMP7nsPhwLu huJoRPH3NCmE2jOLwuT3ZaMf3mRsLvIivYGP5Mn7eumia58Hny6ll753ERNjXwC8zAcWfGrnn6Y 98CjoWZa8wdq32rMci2Yk/QUGiWL7Uga3TjaHcvkPiS/eS7HQPHgBtG3Ao6k/u/Nu25/HOkAVw+ GR1+F3D2LxBhEJo4IFT6sfQGQhjVqRq6wofY4CgcPWWU5dWcNRsCJyMI50yOL2YctbO+q2c8gPb yLvBHxmMJRgkQZXxY1AzRewGt4EoVfTmjrXf7iexgpxdKOVvxZvb+pphDT5pQHVuQSyr3LyBtgF HomR8budjqf5aqDUL5YmP5aOEiTpVbQUG9jTykRsApPfmtbz8MRELf1Eeb49dGamYm04V+W1TqH ONFbHO5P5FyPlbvIFd1gqwVNG40wo3csre23XabZmZGZkyP80kY0puFvKQ8NYm/Kw7ArP8fqyNF w/sODRxQDmRKrtQ== X-Developer-Key: i=a.hindborg@kernel.org; a=openpgp; fpr=3108C10F46872E248D1FB221376EB100563EF7A7 Simplify the implementation by removing the closure-based API from `Guard::load` in favor of returning `Option>` directly. Signed-off-by: Andreas Hindborg --- rust/kernel/xarray.rs | 23 +++++++++-------------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/rust/kernel/xarray.rs b/rust/kernel/xarray.rs index 0f69a523b72bf..ca97134ba2bd0 100644 --- a/rust/kernel/xarray.rs +++ b/rust/kernel/xarray.rs @@ -211,16 +211,12 @@ fn from(value: StoreError) -> Self { } =20 impl<'a, T: ForeignOwnable> Guard<'a, T> { - fn load(&self, index: usize, f: F) -> Option - where - F: FnOnce(NonNull) -> U, - { + fn load(&self, index: usize) -> Option> { let mut state =3D XArrayState::new(self, index); // SAFETY: `state.state` is always valid by the type invariant of // `XArrayState`. let ptr =3D unsafe { bindings::xas_load(&raw mut state.state) }; - let ptr =3D NonNull::new(ptr.cast())?; - Some(f(ptr)) + NonNull::new(ptr) } =20 /// Checks if the XArray contains an element at the specified index. @@ -246,18 +242,17 @@ pub fn contains_index(&self, index: usize) -> bool { =20 /// 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()) } - }) + let ptr =3D self.load(index)?; + // SAFETY: `ptr` came from `T::into_foreign`. + Some(unsafe { T::borrow(ptr.as_ptr()) }) } =20 /// 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()) } - }) + let ptr =3D self.load(index)?; + + // SAFETY: `ptr` came from `T::into_foreign`. + Some(unsafe { T::borrow_mut(ptr.as_ptr()) }) } =20 /// Removes and returns the element at the given index. --=20 2.51.2 From nobody Fri Dec 19 19:23:38 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 10F9F2E427C; Wed, 3 Dec 2025 22:27:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764800854; cv=none; b=AkXWHaytZ9Ork16TOhjmWCmsHOlcRLC0NFagogP3L6vtXQlGFIzpLCcuM1ulU5umEbvVnfr/kKtJtfrnNARINhei0fSgu/vuFbttanaC8VrXRPOHIFiAhq3Ay+lHGUXuYFQOgbBe6189pUDmfSnNTm+zYR6e8V3UBh031F5QpbI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764800854; c=relaxed/simple; bh=JtquLCjmJCuOLZ5pIgrOtNma6TGBWjwHhBofiD5p46Q=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=PIAA4PbFpD7fTpI15FTjxzmqQyirqc4j4n8zUGuhy2QQ2dyxIhq/3ZIIyYqQ4pHHxFoG2KR+kDO7p5WumviBwD3rCkDyRe9uF4c4/YAD3AEhsuIbQYJtxKkqt3IGVjBhsqnuC/CgMVMtuRLhkpM8J+xlYU7488OGBfB6Lk3r0zM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=pUdHonvE; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="pUdHonvE" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C222AC4CEFB; Wed, 3 Dec 2025 22:27:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1764800853; bh=JtquLCjmJCuOLZ5pIgrOtNma6TGBWjwHhBofiD5p46Q=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=pUdHonvE+YMCbI6l3yJDdcjkmctf6h+J4q0taqTSvV47v0UpwfRKnSCiAvMn8jxnT cOtSUEa6YKwbZWQRKO/B9eyvyDJeixQmC1gZrPKO7DvbzHakWf0+hHbLf1w4Af3dhH 3dpK1RdMmllucn2DdQ6JqEzHt+nuw5tfssK1sFd4h7fpupn3nlTFX/1pYaXVdLwvSQ OGTZ2y1z1exEED1XReWKZ4TtuRLIPzrIP4Z6/m1kFyJD40N2ptwTgCsbouqS3GxBGN NBotXGg5tHaIHANoz9eC8yw57PTtFu/e0EtjlOitkgcXhiVIctLfU4nmaIyqcUT2oH 8rXvotjWweb3Q== From: Andreas Hindborg Date: Wed, 03 Dec 2025 23:26:37 +0100 Subject: [PATCH 07/10] rust: xarray: add `find_next` and `find_next_mut` 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: <20251203-xarray-entry-send-v1-7-9e5ffd5e3cf0@kernel.org> References: <20251203-xarray-entry-send-v1-0-9e5ffd5e3cf0@kernel.org> In-Reply-To: <20251203-xarray-entry-send-v1-0-9e5ffd5e3cf0@kernel.org> To: Tamir Duberstein , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Danilo Krummrich Cc: Daniel Gomez , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Andreas Hindborg X-Mailer: b4 0.15-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=3657; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=JtquLCjmJCuOLZ5pIgrOtNma6TGBWjwHhBofiD5p46Q=; b=owEBbQKS/ZANAwAKAeG4Gj55KGN3AcsmYgBpMLkwF6wqucvtQw8KN7aWnwLd/seNiLxWXNoa7 H9X6qyCrZiJAjMEAAEKAB0WIQQSwflHVr98KhXWwBLhuBo+eShjdwUCaTC5MAAKCRDhuBo+eShj d0VYD/4nYQu8gGFZVVXmNefrLXRzHop53P5YrC3I409ZWfdVq6bA8oCCljozO+9bO1vIJc26VT2 +lHWqOOSQcZf8HNimy6tzefm6eWysHuBqRqwatau/F7PelDfnUAfYaZl07eWDulrduM2kE3tiry 5QEQpnqTUL4u38f6pOyhy2S5E+sfSMRvmiQC8u168ZbHEOjZ034HusdrXu6ISAH5WFjG7ijy6Se m5jwx7RrEcFbsr7jzjd/LXk3jG8wyPK6HXy0q9QoAbPasdNmETuqCTxvnek81WefWyA6VtyT9Yk AyL2VA8biSCxFDjS7IPzYaPrMrcXmEdGgtcelb5nAC41sJZYClnOaBpjUF3K0u6n332ahNtNCqO 5nwVN31zaVbmQUhy7IxxHYhRrauyE3xbsapvi2BF26+0wwrDlvDm/4HJbYBZEH+PdQxjEV9o1Xd huN3RPUipQoKXly/wnwnBg3PtYVt8Kc3WHDUA42MS5TdeL+TE/6uRFta1mabKl++mU4I3PzjyrA PYULvv1Tdw6T+QusdfJpWyfTLjPLcw3g2WZyAEcdIZC3KUeUumlRuKeDq3GF383OJWFE9UL1Pvg oTOvSxgFjXGKE7KC5Bn1lfQ/yfERBZw6tDwRWqyVTF4sTFIg8Rp7PyIQMHFgS5SlG+JvHdQDJMf bnqY2GGl83I8v6w== X-Developer-Key: i=a.hindborg@kernel.org; a=openpgp; fpr=3108C10F46872E248D1FB221376EB100563EF7A7 Add methods to find the next element in an XArray starting from a given index. The methods return a tuple containing the index where the element was found and a reference to the element. The implementation uses the XArray state API via `xas_find` to avoid taking the xarray lock that is already held by `Guard`. Signed-off-by: Andreas Hindborg --- rust/kernel/xarray.rs | 65 +++++++++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 65 insertions(+) diff --git a/rust/kernel/xarray.rs b/rust/kernel/xarray.rs index ca97134ba2bd0..9d4589979fd1d 100644 --- a/rust/kernel/xarray.rs +++ b/rust/kernel/xarray.rs @@ -255,6 +255,71 @@ pub fn get_mut(&mut self, index: usize) -> Option> { Some(unsafe { T::borrow_mut(ptr.as_ptr()) }) } =20 + fn load_next(&self, index: usize) -> Option<(usize, NonNull)> { + let mut state =3D XArrayState::new(self, index); + // SAFETY: `state.state` is always valid by the type invariant of + // `XArrayState` and the caller holds the lock. + let ptr =3D unsafe { bindings::xas_find(&raw mut state.state, usiz= e::MAX) }; + NonNull::new(ptr).map(|ptr| (state.state.xa_index, ptr)) + } + + /// Finds the next element starting from the given index. + /// + /// # Examples + /// + /// ``` + /// # use kernel::{prelude::*, xarray::{AllocKind, XArray}}; + /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// let mut guard =3D xa.lock(); + /// + /// guard.store(10, KBox::new(10u32, GFP_KERNEL)?, GFP_KERNEL)?; + /// guard.store(20, KBox::new(20u32, GFP_KERNEL)?, GFP_KERNEL)?; + /// + /// if let Some((found_index, value)) =3D guard.find_next(11) { + /// assert_eq!(found_index, 20); + /// assert_eq!(*value, 20); + /// } + /// + /// if let Some((found_index, value)) =3D guard.find_next(5) { + /// assert_eq!(found_index, 10); + /// assert_eq!(*value, 10); + /// } + /// + /// # Ok::<(), kernel::error::Error>(()) + /// ``` + pub fn find_next(&self, index: usize) -> Option<(usize, T::Borrowed<'_= >)> { + self.load_next(index) + // SAFETY: `ptr` came from `T::into_foreign`. + .map(|(index, ptr)| (index, unsafe { T::borrow(ptr.as_ptr()) }= )) + } + + /// Finds the next element starting from the given index, returning a = mutable reference. + /// + /// # Examples + /// + /// ``` + /// # use kernel::{prelude::*, xarray::{AllocKind, XArray}}; + /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// let mut guard =3D xa.lock(); + /// + /// guard.store(10, KBox::new(10u32, GFP_KERNEL)?, GFP_KERNEL)?; + /// guard.store(20, KBox::new(20u32, GFP_KERNEL)?, GFP_KERNEL)?; + /// + /// if let Some((found_index, mut_value)) =3D guard.find_next_mut(5) { + /// assert_eq!(found_index, 10); + /// *mut_value =3D 0x99; + /// } + /// + /// assert_eq!(guard.get(10).copied(), Some(0x99)); + /// + /// # Ok::<(), kernel::error::Error>(()) + /// ``` + pub fn find_next_mut(&mut self, index: usize) -> Option<(usize, T::Bor= rowedMut<'_>)> { + self.load_next(index) + // SAFETY: `ptr` came from `T::into_foreign`. + .map(move |(index, ptr)| (index, 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: --=20 2.51.2 From nobody Fri Dec 19 19:23:38 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 53B7F2E542C; Wed, 3 Dec 2025 22:27:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764800857; cv=none; b=DP9/VPCgZFVVtYd49lPV3eLf7QrEjYXqMuTFtHeO3dC4ndyj2xN3S9hMcFWEBPk0VXEPCuqwTKIl7F5Ef2Itx7peuUPZMUcdpWElgOBbG2OZmmD2Q2wZlj594wTiOyF8zZz0ePMTbeRVFsYauc+FZOmi5xl4JUTbb1omElORTwA= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764800857; c=relaxed/simple; bh=1os19qZifO9cV0VPyklvVdll4arK3x5FIl8tZk47svo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=QWiUd7ffGArpXdcP1ONRsbIRMdDzLvwCNGUNF51g8iNdBFl0iORWEQ4ORD5dLuyRq7fBuiVzRcU0ypJNOXTjnhmy7vo11HZp1OmVzymjcwyxp5yRsWZpkv4TRn1dUVMq9IVGuy05OJjrnpCWZ53FPL0ltLVyxhKUGr74ruLu3h4= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=fab38MwM; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="fab38MwM" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 48E3EC116B1; Wed, 3 Dec 2025 22:27:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1764800857; bh=1os19qZifO9cV0VPyklvVdll4arK3x5FIl8tZk47svo=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=fab38MwMqZqm39NTaP1gwfdFXpg9rVGsfZVcizMc20IRtGyx3SwNnn3WDvyOaGuZG MwTjEGzT2/02b4hhg9SrO83NbjHhi4OC49gxPxOIvt3EvOkIceda9OYnEDXQAtOs1X txntuwBxnmR/TSZgLmUiQwWVBU2835VRNUBgJhxaxxBKxkwS5y/S1cZMdc//Aags+k 4T6QJ62Ad02LLmKsEGsdMMc9w9zrhtTSD+9xORKLt0POsFqHlBONGGMNSkm74OuvWY D81gVLwkFT1ja8wS/Ne4hXkBzfxHrGHWm3FpYJW2w2eDje1CVr4ueLE/zmFb6hG7bb jISCxCdN6LAYg== From: Andreas Hindborg Date: Wed, 03 Dec 2025 23:26:38 +0100 Subject: [PATCH 08/10] rust: xarray: add entry 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: <20251203-xarray-entry-send-v1-8-9e5ffd5e3cf0@kernel.org> References: <20251203-xarray-entry-send-v1-0-9e5ffd5e3cf0@kernel.org> In-Reply-To: <20251203-xarray-entry-send-v1-0-9e5ffd5e3cf0@kernel.org> To: Tamir Duberstein , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Danilo Krummrich Cc: Daniel Gomez , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Andreas Hindborg X-Mailer: b4 0.15-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=21122; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=1os19qZifO9cV0VPyklvVdll4arK3x5FIl8tZk47svo=; b=owEBbQKS/ZANAwAKAeG4Gj55KGN3AcsmYgBpMLkwL6qCDMaIACz5QYyXPhq4yybbBRt1F5yjb mIz+BLqHemJAjMEAAEKAB0WIQQSwflHVr98KhXWwBLhuBo+eShjdwUCaTC5MAAKCRDhuBo+eShj d94kD/94kr7Xivn3Kzj68xLGesxfFlvbb24bLYseNpUMVs8WDALi377xzYbyBdOtN+s1MFmuBNB xqjDibBco3noZttP0tyViXg/b4BqYMhBZmzt1XohhTt8dJzhODjXxPQlNSlxC2xxy4bhWpOlZpw j5tqGyDlri9Jv2m6+VRL40GcDnju+aS/KWfd9fhM5EM5x9RbQRaKO/33gJpRBn6OPsCfNfN8JC4 /zvQ1I9LWEhjrgRE7/P3QFhtT0w2nLnucw9eLIDaNat3N9WZwtclJajPTBVHhN2zt7VXriCFrlo KC0oxMio+BRI7RejNfAR3FaPBaWpsXuh4eQ0VH/z81NASbXmHWz4WV4J/ABykKMnrlS1IkhR+fp zVNPHHrJYDXMcsnNsn6tRp6HBXmJZbfFascQcETrKQUFZQO5DzpUOn3lpj18ygLfcqgOO+3E/9L QyX045BnlBXCk8yAd7IUxUIkid4VmTAC3eS/uYvIkm788heIscfEY6C6kSC9LbYyLciItlAMDju 7lkrCfZkEm5q3VPja+2PR9Lw7YckCtR4VbwcA6+87hdumE17Weab4OXQHNQpKuCkZuQFJ70oCks DRjdcNg+Ajv6xBKKZidZp7tm2jIobggSje37ZjxmABF5T30j0CCjvXGUgaw5IjjOFOwcLnwbbJd z5eUdYKc4EYEW4Q== X-Developer-Key: i=a.hindborg@kernel.org; a=openpgp; fpr=3108C10F46872E248D1FB221376EB100563EF7A7 Add an Entry API for XArray that provides ergonomic access to array slots that may be vacant or occupied. The API follows the pattern of Rust's standard library HashMap entry API, allowing efficient conditional insertion and modification of entries. The implementation uses the XArray state API (`xas_*` functions) for efficient operations without requiring multiple lookups. Helper functions are added to rust/helpers/xarray.c to wrap C macros that are not directly accessible from Rust. Also update MAINTAINERS to cover the new rust files. Signed-off-by: Andreas Hindborg --- MAINTAINERS | 1 + rust/helpers/xarray.c | 17 ++ rust/kernel/xarray.rs | 112 +++++++++++++ rust/kernel/xarray/entry.rs | 376 ++++++++++++++++++++++++++++++++++++++++= ++++ 4 files changed, 506 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index e8f06145fb54c..79d4c9c9b2b63 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -27909,6 +27909,7 @@ 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 xarray-next F: rust/kernel/xarray.rs +F: rust/kernel/xarray/ =20 XBOX DVD IR REMOTE M: Benjamin Valentin diff --git a/rust/helpers/xarray.c b/rust/helpers/xarray.c index 60b299f11451d..425a6cc494734 100644 --- a/rust/helpers/xarray.c +++ b/rust/helpers/xarray.c @@ -26,3 +26,20 @@ void rust_helper_xa_unlock(struct xarray *xa) { return xa_unlock(xa); } + +void *rust_helper_xas_result(struct xa_state *xas, void *curr) +{ + if (xa_err(xas->xa_node)) + curr =3D xas->xa_node; + return curr; +} + +void *rust_helper_xa_zero_to_null(void *entry) +{ + return xa_is_zero(entry) ? NULL : entry; +} + +int rust_helper_xas_error(const struct xa_state *xas) +{ + return xas_error(xas); +} diff --git a/rust/kernel/xarray.rs b/rust/kernel/xarray.rs index 9d4589979fd1d..2b8d56c81e36b 100644 --- a/rust/kernel/xarray.rs +++ b/rust/kernel/xarray.rs @@ -13,11 +13,17 @@ NonNull, // }, }; +pub use entry::{ + Entry, + OccupiedEntry, + VacantEntry, // +}; use kernel::{ alloc, bindings, build_assert, // error::{ + to_result, Error, Result, // }, @@ -255,6 +261,35 @@ pub fn get_mut(&mut self, index: usize) -> Option> { Some(unsafe { T::borrow_mut(ptr.as_ptr()) }) } =20 + /// Gets an entry for the specified index, which can be vacant or occu= pied. + /// + /// # Examples + /// + /// ``` + /// # use kernel::{prelude::*, xarray::{AllocKind, XArray, Entry}}; + /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// let mut guard =3D xa.lock(); + /// + /// assert_eq!(guard.contains_index(42), false); + /// + /// match guard.get_entry(42) { + /// Entry::Vacant(entry) =3D> { + /// entry.insert(KBox::new(0x1337u32, GFP_KERNEL)?)?; + /// } + /// Entry::Occupied(_) =3D> unreachable!("We did not insert an ent= ry yet"), + /// } + /// + /// assert_eq!(guard.get(42), Some(&0x1337)); + /// + /// # Ok::<(), kernel::error::Error>(()) + /// ``` + pub fn get_entry<'b>(&'b mut self, index: usize) -> Entry<'a, 'b, T> { + match self.load(index) { + None =3D> Entry::Vacant(VacantEntry::new(self, index)), + Some(ptr) =3D> Entry::Occupied(OccupiedEntry::new(self, index,= ptr)), + } + } + fn load_next(&self, index: usize) -> Option<(usize, NonNull)> { let mut state =3D XArrayState::new(self, index); // SAFETY: `state.state` is always valid by the type invariant of @@ -320,6 +355,76 @@ pub fn find_next_mut(&mut self, index: usize) -> Optio= n<(usize, T::BorrowedMut<' .map(move |(index, ptr)| (index, unsafe { T::borrow_mut(ptr.as= _ptr()) })) } =20 + /// Finds the next occupied entry starting from the given index. + /// + /// # Examples + /// + /// ``` + /// # use kernel::{prelude::*, xarray::{AllocKind, XArray}}; + /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// let mut guard =3D xa.lock(); + /// + /// guard.store(10, KBox::new(10u32, GFP_KERNEL)?, GFP_KERNEL)?; + /// guard.store(20, KBox::new(20u32, GFP_KERNEL)?, GFP_KERNEL)?; + /// + /// if let Some(entry) =3D guard.find_next_entry(5) { + /// assert_eq!(entry.index(), 10); + /// let value =3D entry.remove(); + /// assert_eq!(*value, 10); + /// } + /// + /// assert_eq!(guard.get(10), None); + /// + /// # Ok::<(), kernel::error::Error>(()) + /// ``` + pub fn find_next_entry<'b>(&'b mut self, index: usize) -> Option> { + let mut state =3D XArrayState::new(self, index); + + // SAFETY: `state.state` is properly initialized by XArrayState::n= ew and the caller holds + // the lock. + let ptr =3D NonNull::new(unsafe { bindings::xas_find(&mut state.st= ate, usize::MAX) })?; + + Some(OccupiedEntry { state, ptr }) + } + + /// Finds the next occupied entry starting at the given index, wrappin= g around. + /// + /// Searches for an entry starting at `index` up to the maximum index.= If no entry + /// is found, wraps around and searches from index 0 up to `index`. + /// + /// # Examples + /// + /// ``` + /// # use kernel::{prelude::*, xarray::{AllocKind, XArray}}; + /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// let mut guard =3D xa.lock(); + /// + /// guard.store(100, KBox::new(42u32, GFP_KERNEL)?, GFP_KERNEL)?; + /// let entry =3D guard.find_next_entry_circular(101); + /// assert_eq!(entry.map(|e| e.index()), Some(100)); + /// + /// # Ok::<(), kernel::error::Error>(()) + /// ``` + pub fn find_next_entry_circular<'b>( + &'b mut self, + index: usize, + ) -> Option> { + let mut state =3D XArrayState::new(self, index); + + // SAFETY: `state.state` is properly initialized by XArrayState::n= ew and the caller holds + // the lock. + let ptr =3D NonNull::new(unsafe { bindings::xas_find(&mut state.st= ate, usize::MAX) }) + .or_else(|| { + state.state.xa_node =3D bindings::XAS_RESTART as *mut bind= ings::xa_node; + state.state.xa_index =3D 0; + // SAFETY: `state.state` is properly initialized and by ty= pe invariant, we hold the + // xarray lock. + NonNull::new(unsafe { bindings::xas_find(&mut state.state,= index) }) + })?; + + Some(OccupiedEntry { state, ptr }) + } + /// Removes and returns the element at the given index. pub fn remove(&mut self, index: usize) -> Option { // SAFETY: @@ -416,8 +521,15 @@ fn new(access: &'b Guard<'a, T>, index: usize) -> Self= { }, } } + + fn status(&self) -> Result { + // SAFETY: `self.state` is properly initialized and valid. + to_result(unsafe { bindings::xas_error(&self.state) }) + } } =20 +mod entry; + // SAFETY: `XArray` has no shared mutable state so it is `Send` iff `T`= is `Send`. unsafe impl Send for XArray {} =20 diff --git a/rust/kernel/xarray/entry.rs b/rust/kernel/xarray/entry.rs new file mode 100644 index 0000000000000..1268dc35bac58 --- /dev/null +++ b/rust/kernel/xarray/entry.rs @@ -0,0 +1,376 @@ +// SPDX-License-Identifier: GPL-2.0 + +use super::{ + Guard, + StoreError, + XArrayState, // +}; +use core::ptr::NonNull; +use kernel::{ + prelude::*, + types::ForeignOwnable, // +}; + +/// Represents either a vacant or occupied entry in an XArray. +pub enum Entry<'a, 'b, T: ForeignOwnable> { + /// A vacant entry that can have a value inserted. + Vacant(VacantEntry<'a, 'b, T>), + /// An occupied entry containing a value. + Occupied(OccupiedEntry<'a, 'b, T>), +} + +impl Entry<'_, '_, T> { + /// Returns true if this entry is occupied. + /// + /// # Examples + /// + /// ``` + /// # use kernel::{prelude::*, xarray::{AllocKind, XArray, Entry}}; + /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// let mut guard =3D xa.lock(); + /// + /// + /// let entry =3D guard.get_entry(42); + /// assert_eq!(entry.is_occupied(), false); + /// + /// guard.store(42, KBox::new(0x1337u32, GFP_KERNEL)?, GFP_KERNEL)?; + /// let entry =3D guard.get_entry(42); + /// assert_eq!(entry.is_occupied(), true); + /// + /// # Ok::<(), kernel::error::Error>(()) + /// ``` + pub fn is_occupied(&self) -> bool { + matches!(self, Entry::Occupied(_)) + } +} + +/// A view into a vacant entry in an XArray. +pub struct VacantEntry<'a, 'b, T: ForeignOwnable> { + state: XArrayState<'a, 'b, T>, +} + +impl<'a, 'b, T> VacantEntry<'a, 'b, T> +where + T: ForeignOwnable, +{ + pub(crate) fn new(guard: &'b mut Guard<'a, T>, index: usize) -> Self { + Self { + state: XArrayState::new(guard, index), + } + } + + fn insert_internal(&mut self, value: T) -> Result<*mut c_void, StoreEr= ror> { + let new =3D T::into_foreign(value).cast(); + + // SAFETY: `self.state.state` is properly initialized and `new` ca= me from `T::into_foreign`. + // We hold the xarray lock. + unsafe { bindings::xas_store(&mut self.state.state, new) }; + + self.state.status().map(|()| new).map_err(|error| { + // SAFETY: `new` came from `T::into_foreign` and `xas_store` d= oes not take ownership of + // the value on error. + let value =3D unsafe { T::from_foreign(new) }; + StoreError { value, error } + }) + } + + /// Inserts a value into this vacant entry. + /// + /// Returns a reference to the newly inserted value. + /// + /// - This method will fail if the nodes on the path to the index + /// represented by this entry are not present in the XArray. + /// - This method will not drop the XArray lock. + /// + /// + /// # Examples + /// + /// ``` + /// # use kernel::{prelude::*, xarray::{AllocKind, XArray, Entry}}; + /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// let mut guard =3D xa.lock(); + /// + /// assert_eq!(guard.get(42), None); + /// + /// if let Entry::Vacant(entry) =3D guard.get_entry(42) { + /// let value =3D KBox::new(0x1337u32, GFP_KERNEL)?; + /// let borrowed =3D entry.insert(value)?; + /// assert_eq!(*borrowed, 0x1337); + /// } + /// + /// assert_eq!(guard.get(42).copied(), Some(0x1337)); + /// + /// # Ok::<(), kernel::error::Error>(()) + /// ``` + pub fn insert(mut self, value: T) -> Result, StoreE= rror> { + let new =3D self.insert_internal(value)?; + + // SAFETY: `new` came from `T::into_foreign`. The entry has exclus= ive + // ownership of `new` as it holds a mutable reference to `Guard`. + Ok(unsafe { T::borrow_mut(new) }) + } + + /// Inserts a value and returns an occupied entry representing the new= ly inserted value. + /// + /// - This method will fail if the nodes on the path to the index + /// represented by this entry are not present in the XArray. + /// - This method will not drop the XArray lock. + /// + /// # Examples + /// + /// ``` + /// # use kernel::{prelude::*, xarray::{AllocKind, XArray, Entry}}; + /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// let mut guard =3D xa.lock(); + /// + /// assert_eq!(guard.get(42), None); + /// + /// if let Entry::Vacant(entry) =3D guard.get_entry(42) { + /// let value =3D KBox::new(0x1337u32, GFP_KERNEL)?; + /// let occupied =3D entry.insert_entry(value)?; + /// assert_eq!(occupied.index(), 42); + /// } + /// + /// assert_eq!(guard.get(42).copied(), Some(0x1337)); + /// + /// # Ok::<(), kernel::error::Error>(()) + /// ``` + pub fn insert_entry(mut self, value: T) -> Result, StoreError> { + let new =3D self.insert_internal(value)?; + + Ok(OccupiedEntry::<'a, 'b, T> { + state: self.state, + // SAFETY: `new` came from `T::into_foreign` and is guaranteed= non-null. + ptr: unsafe { core::ptr::NonNull::new_unchecked(new) }, + }) + } + + /// Returns the index of this vacant entry. + /// + /// # Examples + /// + /// ``` + /// # use kernel::{prelude::*, xarray::{AllocKind, XArray, Entry}}; + /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// let mut guard =3D xa.lock(); + /// + /// assert_eq!(guard.get(42), None); + /// + /// if let Entry::Vacant(entry) =3D guard.get_entry(42) { + /// assert_eq!(entry.index(), 42); + /// } + /// + /// # Ok::<(), kernel::error::Error>(()) + /// ``` + pub fn index(&self) -> usize { + self.state.state.xa_index + } +} + +/// A view into an occupied entry in an XArray. +pub struct OccupiedEntry<'a, 'b, T: ForeignOwnable> { + pub(crate) state: XArrayState<'a, 'b, T>, + pub(crate) ptr: NonNull, +} + +impl<'a, 'b, T> OccupiedEntry<'a, 'b, T> +where + T: ForeignOwnable, +{ + pub(crate) fn new(guard: &'b mut Guard<'a, T>, index: usize, ptr: NonN= ull) -> Self { + Self { + state: XArrayState::new(guard, index), + ptr, + } + } + + /// Removes the value from this occupied entry and returns it, consumi= ng the entry. + /// + /// # Examples + /// + /// ``` + /// # use kernel::{prelude::*, xarray::{AllocKind, XArray, Entry}}; + /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// let mut guard =3D xa.lock(); + /// + /// guard.store(42, KBox::new(0x1337u32, GFP_KERNEL)?, GFP_KERNEL)?; + /// assert_eq!(guard.get(42).copied(), Some(0x1337)); + /// + /// if let Entry::Occupied(entry) =3D guard.get_entry(42) { + /// let value =3D entry.remove(); + /// assert_eq!(*value, 0x1337); + /// } + /// + /// assert_eq!(guard.get(42), None); + /// + /// # Ok::<(), kernel::error::Error>(()) + /// ``` + pub fn remove(mut self) -> T { + // NOTE: Storing NULL to an occupied slot never fails. + // SAFETY: `self.state.state` is properly initialized and valid fo= r XAS operations. + let ptr =3D unsafe { + bindings::xas_result( + &mut self.state.state, + bindings::xa_zero_to_null(bindings::xas_store( + &mut self.state.state, + core::ptr::null_mut(), + )), + ) + }; + + // SAFETY: `ptr` is a valid return value from xas_result. + let errno =3D unsafe { bindings::xa_err(ptr) }; + debug_assert!(errno =3D=3D 0); + + // SAFETY: + // - `ptr` came from `T::into_foreign`. + // - As this method takes self by value, the lifetimes of any [`T:= :Borrowed`] and + // [`T::BorrowedMut`] we have created must have ended. + unsafe { T::from_foreign(ptr.cast()) } + } + + /// Returns the index of this occupied entry. + /// + /// # Examples + /// + /// ``` + /// # use kernel::{prelude::*, xarray::{AllocKind, XArray, Entry}}; + /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// let mut guard =3D xa.lock(); + /// + /// guard.store(42, KBox::new(0x1337u32, GFP_KERNEL)?, GFP_KERNEL)?; + /// + /// if let Entry::Occupied(entry) =3D guard.get_entry(42) { + /// assert_eq!(entry.index(), 42); + /// } + /// + /// # Ok::<(), kernel::error::Error>(()) + /// ``` + pub fn index(&self) -> usize { + self.state.state.xa_index + } + + /// Replaces the value in this occupied entry and returns the old valu= e. + /// + /// # Examples + /// + /// ``` + /// # use kernel::{prelude::*, xarray::{AllocKind, XArray, Entry}}; + /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// let mut guard =3D xa.lock(); + /// + /// guard.store(42, KBox::new(0x1337u32, GFP_KERNEL)?, GFP_KERNEL)?; + /// + /// if let Entry::Occupied(mut entry) =3D guard.get_entry(42) { + /// let new_value =3D KBox::new(0x9999u32, GFP_KERNEL)?; + /// let old_value =3D entry.insert(new_value); + /// assert_eq!(*old_value, 0x1337); + /// } + /// + /// assert_eq!(guard.get(42).copied(), Some(0x9999)); + /// + /// # Ok::<(), kernel::error::Error>(()) + /// ``` + pub fn insert(&mut self, value: T) -> T { + // NOTE: Storing to an occupied slot never fails. + let new =3D T::into_foreign(value).cast(); + // SAFETY: `new` came from `T::into_foreign` and is guaranteed non= -null. + self.ptr =3D unsafe { NonNull::new_unchecked(new) }; + + // SAFETY: `self.state.state` is properly initialized and valid fo= r XAS operations. + let old =3D unsafe { + bindings::xas_result( + &mut self.state.state, + bindings::xa_zero_to_null(bindings::xas_store(&mut self.st= ate.state, new)), + ) + }; + + // SAFETY: `old` is a valid return value from xas_result. + let errno =3D unsafe { bindings::xa_err(old) }; + debug_assert!(errno =3D=3D 0); + + // SAFETY: + // - `ptr` came from `T::into_foreign`. + // - As this method takes self by value, the lifetimes of any [`T:= :Borrowed`] and + // [`T::BorrowedMut`] we have created must have ended. + unsafe { T::from_foreign(old) } + } + + /// Converts this occupied entry into a mutable reference to the value= in the slot represented + /// by the entry. + /// + /// # Examples + /// + /// ``` + /// # use kernel::{prelude::*, xarray::{AllocKind, XArray, Entry}}; + /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// let mut guard =3D xa.lock(); + /// + /// guard.store(42, KBox::new(0x1337u32, GFP_KERNEL)?, GFP_KERNEL)?; + /// + /// if let Entry::Occupied(entry) =3D guard.get_entry(42) { + /// let value_ref =3D entry.into_mut(); + /// *value_ref =3D 0x9999; + /// } + /// + /// assert_eq!(guard.get(42).copied(), Some(0x9999)); + /// + /// # Ok::<(), kernel::error::Error>(()) + /// ``` + pub fn into_mut(self) -> T::BorrowedMut<'b> { + // SAFETY: `ptr` came from `T::into_foreign`. + unsafe { T::borrow_mut(self.ptr.as_ptr()) } + } + + /// Swaps the value in this entry with the provided value. + /// + /// Returns the old value that was in the entry. + /// + /// # Examples + /// + /// ``` + /// # use kernel::{prelude::*, xarray::{AllocKind, XArray, Entry}}; + /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// let mut guard =3D xa.lock(); + /// + /// guard.store(42, KBox::new(100u32, GFP_KERNEL)?, GFP_KERNEL)?; + /// + /// if let Entry::Occupied(mut entry) =3D guard.get_entry(42) { + /// let old_value =3D entry.swap(200u32); + /// assert_eq!(old_value, 100); + /// assert_eq!(*entry, 200); + /// } + /// + /// # Ok::<(), kernel::error::Error>(()) + /// ``` + pub fn swap(&mut self, mut other: U) -> U + where + T: for<'c> ForeignOwnable =3D &'c U, BorrowedMut<'c> = =3D &'c mut U>, + { + use core::ops::DerefMut; + core::mem::swap(self.deref_mut(), &mut other); + other + } +} + +impl core::ops::Deref for OccupiedEntry<'_, '_, T> +where + T: for<'a> ForeignOwnable =3D &'a U, BorrowedMut<'a> =3D = &'a mut U>, +{ + type Target =3D U; + + fn deref(&self) -> &Self::Target { + // SAFETY: `ptr` came from `T::into_foreign`. + unsafe { T::borrow(self.ptr.as_ptr()) } + } +} + +impl core::ops::DerefMut for OccupiedEntry<'_, '_, T> +where + T: for<'a> ForeignOwnable =3D &'a U, BorrowedMut<'a> =3D = &'a mut U>, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + // SAFETY: `ptr` came from `T::into_foreign`. + unsafe { T::borrow_mut(self.ptr.as_ptr()) } + } +} --=20 2.51.2 From nobody Fri Dec 19 19:23:38 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id EB1AA2E2840; Wed, 3 Dec 2025 22:27:26 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764800847; cv=none; b=gCRPOpnLXQbt7bGW2Sbvpe+3TNF8jJjXKWOmFbdQa0WrSGr05uuWBi+OazQa9nSA/atClQ8Lkjpy6LPkDwc1iIlWgUV5nhkN1qEgnaTI5UTm0B8NAx2tfg8Pe7513X5NEE81NkJvAUARSXVsCFxELkSabXIZoO1tvFOrA6z1iF8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764800847; c=relaxed/simple; bh=aQzhqyZ8EjeS0wr4dptsBSQSvp9w3IXPV4HbdoyC0IU=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=u4S9HAcLUl3S0bgrGBAV9v/YHDts/RZudQowcGjh2CBEDdfTh5dWL5xr2ubQ+1bNe0M8vQM68d9VidKb8EfRPrqcBgErKWiuDsTwUOlZguuhdrByiZulwNo1igeM7KaZsMLLKWgg7o0ibv2fwmGtbjlNMy2LamLGgGsRznOdvRo= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=OQYcr3wS; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="OQYcr3wS" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4C405C4CEF5; Wed, 3 Dec 2025 22:27:23 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1764800846; bh=aQzhqyZ8EjeS0wr4dptsBSQSvp9w3IXPV4HbdoyC0IU=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=OQYcr3wSXIzfc4sPaZo4TpqxUJ35szDgRW3OrV13ElJ8Rhlhc1pLx9dAjXBM+PRXe HBoSCD+TjHg3Xy9e3Yc5WdY5H880DdriDEo+uPOAd7ALbdAno6n/9fKrN3L4oi6JTE 8wv0TicoydgX1q8rbGhiNBfhSIGdLS86pMXXDI6X7XyAs1PQlyZ/QkSrijKj+0eLEa eXWutK1ERZTWVeX3zdVDN7v1BuWVQzuydfPNK5BRByjIN63nPYqp5rnhCW2NbAuJnt Uh6gn3COumhVpTOzkPZ4SQqRPhCalE9wRCqAffUodTiLy01fvpMnpIwgbWB9tivGFp YdU+rY3P5z8bQ== From: Andreas Hindborg Date: Wed, 03 Dec 2025 23:26:39 +0100 Subject: [PATCH 09/10] rust: xarray: add preload 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: <20251203-xarray-entry-send-v1-9-9e5ffd5e3cf0@kernel.org> References: <20251203-xarray-entry-send-v1-0-9e5ffd5e3cf0@kernel.org> In-Reply-To: <20251203-xarray-entry-send-v1-0-9e5ffd5e3cf0@kernel.org> To: Tamir Duberstein , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Danilo Krummrich Cc: Daniel Gomez , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Andreas Hindborg X-Mailer: b4 0.15-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=18702; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=aQzhqyZ8EjeS0wr4dptsBSQSvp9w3IXPV4HbdoyC0IU=; b=owEBbQKS/ZANAwAKAeG4Gj55KGN3AcsmYgBpMLkx+pU8KZErsEBjl6tiaEm9yPICvbYLjvKdC 1DVeQH4gKuJAjMEAAEKAB0WIQQSwflHVr98KhXWwBLhuBo+eShjdwUCaTC5MQAKCRDhuBo+eShj d4HrEAC/dxwKHs893rTuzE1B5cKORJNzjAPSkpvkT6wLdwAMjcJwraOAVW8PKYrQemGU5PWRaBf qTi6kH+KpRTHPUdtgbK05SRDN36tn2sEZQ3yj682Hh3S9JFzfXvFPZ92j89aVs8r9g0yu92ujiK vXuJh9/VWNafwqZhd2HIDy8pQMC6pwzTBzouiQld6MzUnkGoz7aWyK3oTYRuAaDGzVk3nEv/Wjk OnlE5hDnlN9qTxbZddWt1riuK8DgBSWXgCYB7qpGwqvG/4KndVyG/N5hu07l3RMUGYaATo+z0jT 5opM7oSqXjQW+vCemkINk1sKwpNlQNa0m++q9PDsgPR451Gzpnmy92g9BoVNegzo/bQL2oNVEJ6 IXWVXhRYF8XEaBc27Nkqz5mucyTluKZ5oGX1QnUMsSLDrbVsF4jfzLniozPhfMFsz/4GLRJ8tlI 91jF01lZOp3d4vqHUIpxhdjmLylG4W89aNeRzWv3kegrl4Vk0QX0/YFOU8TWMfryYHMFlpi4rIn swVH8Mr0Tb96DQ8axI9l01FvXnEImgdGID+ZoLlszZDPXEsCytlxqpdrONSOYeaUG5JZ2Ak10lb Nf31gvc+tIaFcNC+ram9FJmcxIgZjUAgeFmuMCdAtkb9q4IXSqgkXr3j1QcC9bgGLASdT+4x5Mq bRJ2j5tDhK9UQsQ== X-Developer-Key: i=a.hindborg@kernel.org; a=openpgp; fpr=3108C10F46872E248D1FB221376EB100563EF7A7 Add a preload API that allows preallocating memory for XArray insertions. This enables insertions to proceed without allocation failures in contexts where memory allocation is not desirable, such as in atomic contexts or where reliability is critical. The API includes: - `XArrayPreloadBuffer` for managing a pool of preallocated nodes. - `XArrayPreloadNode` representing a single preallocated node. - Integration with the entry API, allowing `VacantEntry::insert` and `VacantEntry::insert_entry` to accept an optional preload buffer. - A new `Guard::insert_entry` method for inserting with preload support. The implementation uses a circular buffer to efficiently manage preallocated nodes. When an insertion would fail due to ENOMEM, the XArray state API automatically consumes a preallocated node from the buffer if available. Signed-off-by: Andreas Hindborg --- rust/bindings/bindings_helper.h | 3 + rust/kernel/xarray.rs | 58 ++++++++++- rust/kernel/xarray/entry.rs | 64 +++++++++--- rust/kernel/xarray/preload.rs | 217 ++++++++++++++++++++++++++++++++++++= ++++ 4 files changed, 324 insertions(+), 18 deletions(-) diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 86bca946faff0..8e9f8762d5e6e 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -110,6 +110,9 @@ const gfp_t RUST_CONST_HELPER_XA_FLAGS_ALLOC =3D XA_FLA= GS_ALLOC; const gfp_t RUST_CONST_HELPER_XA_FLAGS_ALLOC1 =3D XA_FLAGS_ALLOC1; const vm_flags_t RUST_CONST_HELPER_VM_MERGEABLE =3D VM_MERGEABLE; const size_t RUST_CONST_HELPER_XAS_RESTART =3D (size_t)XAS_RESTART; +const size_t RUST_CONST_HELPER_XA_CHUNK_SHIFT =3D XA_CHUNK_SHIFT; +const size_t RUST_CONST_HELPER_XA_CHUNK_SIZE =3D XA_CHUNK_SIZE; +extern struct kmem_cache *radix_tree_node_cachep; =20 #if IS_ENABLED(CONFIG_ANDROID_BINDER_IPC_RUST) #include "../../drivers/android/binder/rust_binder.h" diff --git a/rust/kernel/xarray.rs b/rust/kernel/xarray.rs index 2b8d56c81e36b..a405f2b6fdcad 100644 --- a/rust/kernel/xarray.rs +++ b/rust/kernel/xarray.rs @@ -23,6 +23,7 @@ bindings, build_assert, // error::{ + code::*, to_result, Error, Result, // @@ -40,6 +41,12 @@ pinned_drop, PinInit, // }; +pub use preload::{ + XArrayPreloadBuffer, + XArrayPreloadNode, // +}; + +mod preload; =20 /// An array which efficiently maps sparse integer indices to owned object= s. /// @@ -166,7 +173,6 @@ pub fn try_lock(&self) -> Option> { 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, @@ -274,7 +280,7 @@ pub fn get_mut(&mut self, index: usize) -> Option> { /// /// match guard.get_entry(42) { /// Entry::Vacant(entry) =3D> { - /// entry.insert(KBox::new(0x1337u32, GFP_KERNEL)?)?; + /// entry.insert(KBox::new(0x1337u32, GFP_KERNEL)?, None)?; /// } /// Entry::Occupied(_) =3D> unreachable!("We did not insert an ent= ry yet"), /// } @@ -487,6 +493,45 @@ pub fn store( Ok(unsafe { T::try_from_foreign(old) }) } } + + /// Inserts a value and returns an occupied entry for further operatio= ns. + /// + /// If a value is already present, the operation fails. + /// + /// This method will not drop the XArray lock. If memory allocation is + /// required for the operation to succeed, the user should supply memo= ry + /// through the `preload` argument. + /// + /// # Examples + /// + /// ``` + /// # use kernel::{prelude::*, xarray::{AllocKind, XArray}}; + /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// let mut guard =3D xa.lock(); + /// + /// assert_eq!(guard.get(42), None); + /// + /// let value =3D KBox::new(0x1337u32, GFP_KERNEL)?; + /// let entry =3D guard.insert_entry(42, value, None)?; + /// let borrowed =3D entry.into_mut(); + /// assert_eq!(borrowed, &0x1337); + /// + /// # Ok::<(), kernel::error::Error>(()) + /// ``` + pub fn insert_entry<'b>( + &'b mut self, + index: usize, + value: T, + preload: Option<&mut XArrayPreloadBuffer>, + ) -> Result, StoreError> { + match self.get_entry(index) { + Entry::Vacant(entry) =3D> entry.insert_entry(value, preload), + Entry::Occupied(_) =3D> Err(StoreError { + error: EBUSY, + value, + }), + } + } } =20 /// Internal state for XArray iteration and entry operations. @@ -501,6 +546,15 @@ pub(crate) struct XArrayState<'a, 'b, T: ForeignOwnabl= e> { state: bindings::xa_state, } =20 +impl<'a, 'b, T: ForeignOwnable> Drop for XArrayState<'a, 'b, T> { + fn drop(&mut self) { + if !self.state.xa_alloc.is_null() { + // SAFETY: `xa_alloc` is a valid pointer to a preallocated nod= e when non-null. + drop(unsafe { XArrayPreloadNode::from_raw(self.state.xa_alloc)= }) + } + } +} + impl<'a, 'b, T: ForeignOwnable> XArrayState<'a, 'b, T> { fn new(access: &'b Guard<'a, T>, index: usize) -> Self { let ptr =3D access.xa.xa.get(); diff --git a/rust/kernel/xarray/entry.rs b/rust/kernel/xarray/entry.rs index 1268dc35bac58..2d6ef4781f47d 100644 --- a/rust/kernel/xarray/entry.rs +++ b/rust/kernel/xarray/entry.rs @@ -3,6 +3,7 @@ use super::{ Guard, StoreError, + XArrayPreloadBuffer, XArrayState, // }; use core::ptr::NonNull; @@ -29,9 +30,9 @@ impl Entry<'_, '_, T> { /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; /// let mut guard =3D xa.lock(); /// - /// /// let entry =3D guard.get_entry(42); /// assert_eq!(entry.is_occupied(), false); + /// drop(entry); /// /// guard.store(42, KBox::new(0x1337u32, GFP_KERNEL)?, GFP_KERNEL)?; /// let entry =3D guard.get_entry(42); @@ -59,16 +60,37 @@ pub(crate) fn new(guard: &'b mut Guard<'a, T>, index: u= size) -> Self { } } =20 - fn insert_internal(&mut self, value: T) -> Result<*mut c_void, StoreEr= ror> { + fn insert_internal( + &mut self, + value: T, + mut preload: Option<&mut XArrayPreloadBuffer>, + ) -> Result<*mut c_void, StoreError> { let new =3D T::into_foreign(value).cast(); =20 - // SAFETY: `self.state.state` is properly initialized and `new` ca= me from `T::into_foreign`. - // We hold the xarray lock. - unsafe { bindings::xas_store(&mut self.state.state, new) }; + loop { + // SAFETY: `self.state.state` is properly initialized and `new= ` came from + // `T::into_foreign`. We hold the xarray lock. + unsafe { bindings::xas_store(&mut self.state.state, new) }; + + match self.state.status() { + Ok(()) =3D> break Ok(new), + Err(ENOMEM) =3D> { + debug_assert!(self.state.state.xa_alloc.is_null()); + let node =3D match preload.as_mut().map(|node| node.ta= ke_one().ok_or(ENOMEM)) { + None =3D> break Err(ENOMEM), + Some(Err(e)) =3D> break Err(e), + Some(Ok(node)) =3D> node, + }; =20 - self.state.status().map(|()| new).map_err(|error| { - // SAFETY: `new` came from `T::into_foreign` and `xas_store` d= oes not take ownership of - // the value on error. + self.state.state.xa_alloc =3D node.into_raw(); + continue; + } + Err(e) =3D> break Err(e), + } + } + .map_err(|error| { + // SAFETY: `new` came from `T::into_foreign` and `xas_store` d= oes not take + // ownership of the value on error. let value =3D unsafe { T::from_foreign(new) }; StoreError { value, error } }) @@ -79,7 +101,8 @@ fn insert_internal(&mut self, value: T) -> Result<*mut c= _void, StoreError> { /// Returns a reference to the newly inserted value. /// /// - This method will fail if the nodes on the path to the index - /// represented by this entry are not present in the XArray. + /// represented by this entry are not present in the XArray and no m= emory + /// is available via the `preload` argument. /// - This method will not drop the XArray lock. /// /// @@ -94,7 +117,7 @@ fn insert_internal(&mut self, value: T) -> Result<*mut c= _void, StoreError> { /// /// if let Entry::Vacant(entry) =3D guard.get_entry(42) { /// let value =3D KBox::new(0x1337u32, GFP_KERNEL)?; - /// let borrowed =3D entry.insert(value)?; + /// let borrowed =3D entry.insert(value, None)?; /// assert_eq!(*borrowed, 0x1337); /// } /// @@ -102,8 +125,12 @@ fn insert_internal(&mut self, value: T) -> Result<*mut= c_void, StoreError> { /// /// # Ok::<(), kernel::error::Error>(()) /// ``` - pub fn insert(mut self, value: T) -> Result, StoreE= rror> { - let new =3D self.insert_internal(value)?; + pub fn insert( + mut self, + value: T, + preload: Option<&mut XArrayPreloadBuffer>, + ) -> Result, StoreError> { + let new =3D self.insert_internal(value, preload)?; =20 // SAFETY: `new` came from `T::into_foreign`. The entry has exclus= ive // ownership of `new` as it holds a mutable reference to `Guard`. @@ -113,7 +140,8 @@ pub fn insert(mut self, value: T) -> Result, StoreError> { /// Inserts a value and returns an occupied entry representing the new= ly inserted value. /// /// - This method will fail if the nodes on the path to the index - /// represented by this entry are not present in the XArray. + /// represented by this entry are not present in the XArray and no m= emory + /// is available via the `preload` argument. /// - This method will not drop the XArray lock. /// /// # Examples @@ -127,7 +155,7 @@ pub fn insert(mut self, value: T) -> Result, StoreError> { /// /// if let Entry::Vacant(entry) =3D guard.get_entry(42) { /// let value =3D KBox::new(0x1337u32, GFP_KERNEL)?; - /// let occupied =3D entry.insert_entry(value)?; + /// let occupied =3D entry.insert_entry(value, None)?; /// assert_eq!(occupied.index(), 42); /// } /// @@ -135,8 +163,12 @@ pub fn insert(mut self, value: T) -> Result, StoreError> { /// /// # Ok::<(), kernel::error::Error>(()) /// ``` - pub fn insert_entry(mut self, value: T) -> Result, StoreError> { - let new =3D self.insert_internal(value)?; + pub fn insert_entry( + mut self, + value: T, + preload: Option<&mut XArrayPreloadBuffer>, + ) -> Result, StoreError> { + let new =3D self.insert_internal(value, preload)?; =20 Ok(OccupiedEntry::<'a, 'b, T> { state: self.state, diff --git a/rust/kernel/xarray/preload.rs b/rust/kernel/xarray/preload.rs new file mode 100644 index 0000000000000..964b16a0e6199 --- /dev/null +++ b/rust/kernel/xarray/preload.rs @@ -0,0 +1,217 @@ +// SPDX-License-Identifier: GPL-2.0 + +use kernel::prelude::*; + +/// A buffer for preallocating XArray nodes. +/// +/// This structure allows preallocating memory for XArray insertions to av= oid +/// allocation failures during operations where allocation is not desirabl= e. +pub struct XArrayPreloadBuffer { + nodes: KVec<*mut bindings::xa_node>, + size: usize, + head: usize, + tail: usize, +} + +impl XArrayPreloadBuffer { + /// Creates a new preload buffer with capacity for the given number of= leaf values. + /// + /// Inserting a leaf value into an [`XArray`] may require allocating a + /// number of internal nodes. This buffer will calculate the upper lim= it of + /// required internal nodes for inserting `entry_count` leaf values an= d use + /// that to size the buffer. + /// + /// # Examples + /// + /// ``` + /// # use kernel::{prelude::*, xarray::XArrayPreloadBuffer}; + /// let buffer =3D XArrayPreloadBuffer::new(10)?; + /// # Ok::<(), kernel::error::Error>(()) + /// ``` + /// [`XArray`]: super::XArray + pub fn new(entry_count: usize) -> Result { + let node_count =3D entry_count + * ((usize::BITS as usize / bindings::XA_CHUNK_SHIFT) + + if (usize::BITS as usize % bindings::XA_CHUNK_SHIFT) =3D= =3D 0 { + 0 + } else { + 1 + }); + + let mut this =3D Self { + nodes: KVec::new(), + size: node_count + 1, + head: 0, + tail: 0, + }; + + for _ in 0..this.size { + this.nodes.push(core::ptr::null_mut(), GFP_KERNEL)?; + } + + Ok(this) + } + + /// Allocates internal nodes until the buffer is full. + pub fn preload(&mut self, flags: kernel::alloc::Flags) -> Result { + while !self.full() { + self.alloc(flags)? + } + Ok(()) + } + + /// Fills the buffer with preallocated nodes from the given vector. + /// + /// Nodes are moved from the vector into the buffer until the buffer i= s full + /// or the vector is empty. + /// + /// # Examples + /// + /// ``` + /// # use kernel::{prelude::*, xarray::{XArrayPreloadBuffer, XArrayPre= loadNode}}; + /// let mut buffer =3D XArrayPreloadBuffer::new(5)?; + /// let mut nodes =3D KVec::new(); + /// nodes.push(XArrayPreloadNode::new(GFP_KERNEL)?, GFP_KERNEL)?; + /// buffer.preload_with(&mut nodes)?; + /// # Ok::<(), kernel::error::Error>(()) + /// ``` + pub fn preload_with(&mut self, nodes: &mut KVec) ->= Result { + while !self.full() { + if let Some(node) =3D nodes.pop() { + self.push(node)? + } else { + break; + } + } + + Ok(()) + } + + /// Returns `true` if the buffer is full and cannot accept more nodes. + /// + /// # Examples + /// + /// ``` + /// # use kernel::{prelude::*, xarray::{XArrayPreloadBuffer, XArrayPre= loadNode}}; + /// let mut buffer =3D XArrayPreloadBuffer::new(1)?; + /// if !buffer.full() { + /// let count =3D buffer.free_count(); + /// let mut nodes =3D KVec::new(); + /// for _ in 0..count { + /// nodes.push(XArrayPreloadNode::new(GFP_KERNEL)?, GFP_KERNEL= )?; + /// } + /// buffer.preload_with(&mut nodes)?; + /// } + /// # Ok::<(), kernel::error::Error>(()) + /// ``` + pub fn full(&self) -> bool { + (self.head + 1) % self.size !=3D self.tail + } + + fn empty(&self) -> bool { + self.head =3D=3D self.tail + } + + /// Returns the number of available slots in the buffer. + pub fn free_count(&self) -> usize { + (if self.head >=3D self.tail { + self.size - (self.head - self.tail) + } else { + (self.size - self.tail) + self.head + } - 1) + } + + fn alloc(&mut self, flags: kernel::alloc::Flags) -> Result { + if self.full() { + return Err(ENOSPC); + } + + self.push(XArrayPreloadNode::new(flags)?)?; + + Ok(()) + } + + fn push(&mut self, node: XArrayPreloadNode) -> Result { + if self.full() { + return Err(ENOSPC); + } + + self.nodes[self.head] =3D node.into_raw(); + self.head =3D (self.head + 1) % self.size; + + Ok(()) + } + + /// Removes and returns one preallocated node from the buffer. + /// + /// Returns `None` if the buffer is empty. + pub(crate) fn take_one(&mut self) -> Option { + if self.empty() { + return None; + } + + let node =3D self.nodes[self.tail]; + self.tail =3D (self.tail + 1) % self.size; + + Some(XArrayPreloadNode(node)) + } +} + +impl Drop for XArrayPreloadBuffer { + fn drop(&mut self) { + while !self.empty() { + drop(self.take_one().expect("Not empty")); + } + } +} + +/// A preallocated XArray node. +/// +/// This represents a single preallocated internal node for an XArray. +/// Nodes can be stored in an [`XArrayPreloadBuffer`] for later use. +pub struct XArrayPreloadNode(*mut bindings::xa_node); + +impl XArrayPreloadNode { + /// Allocates a new XArray node. + /// + /// # Examples + /// + /// ``` + /// # use kernel::{prelude::*, xarray::XArrayPreloadNode}; + /// let node =3D XArrayPreloadNode::new(GFP_KERNEL)?; + /// # Ok::<(), kernel::error::Error>(()) + /// ``` + pub fn new(flags: kernel::alloc::Flags) -> Result { + // SAFETY: `radix_tree_node_cachep` is a valid kmem cache for XArr= ay nodes. + let ptr =3D unsafe { + bindings::kmem_cache_alloc_noprof(bindings::radix_tree_node_ca= chep, flags.as_raw()) + }; + + if ptr.is_null() { + return Err(ENOMEM); + } + + // SAFETY: `ptr` is non-null and was allocated from `radix_tree_no= de_cachep`. + Ok(unsafe { XArrayPreloadNode::from_raw(ptr.cast()) }) + } + + pub(crate) fn into_raw(self) -> *mut bindings::xa_node { + self.0 + } + + /// Creates an `XArrayPreloadNode` from a raw pointer. + /// + /// # Safety + /// + /// `ptr` must be a valid pointer to an XArray node allocated from `ra= dix_tree_node_cachep`. + pub(crate) unsafe fn from_raw(ptr: *mut bindings::xa_node) -> Self { + Self(ptr) + } +} + +impl Drop for XArrayPreloadNode { + fn drop(&mut self) { + // SAFETY: `self.0` is a valid pointer allocated from `radix_tree_= node_cachep`. + unsafe { bindings::kmem_cache_free(bindings::radix_tree_node_cache= p, self.0.cast()) } + } +} --=20 2.51.2 From nobody Fri Dec 19 19:23:38 2025 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 79CCD2E1C63; Wed, 3 Dec 2025 22:28:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764800881; cv=none; b=ewqrDjB3kZ7lL/z8w8xPN14uPLDG5S3HEzMW9Th3lBRdNw6EBW+FiltEvKuqUOcGZHrmbkoGKXpNuhdthJGfkocGZFiVagjk8KnYX1gUUZNNcLLsRqS1wkztKzUHkkDJ1G1c9qB5M8PrzUUNsMp43K9yDf6s/2eegDrsABeKyQ4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1764800881; c=relaxed/simple; bh=EgKnL1W+UwiuxsULarEIK2q/hy40ymVfLcMM6JgsJXE=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=HgzU+XeHCQNyZ6wLsoChldwvSND+EBykTH2IU3Zv0YP5+GvVIxDq52n2/98MS5wvYKA5jnpTQAyXeDY09u1mWEooX0kqgM5NrjapXhmZ1t/21O0KkpCpwVNeH0kXY2Vc+P21XkIXm50zYV0HKW6AMWaklWyC+ryIDQBkwQSOO7I= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=uxgpeGRO; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="uxgpeGRO" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2C5E1C4CEFB; Wed, 3 Dec 2025 22:27:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1764800880; bh=EgKnL1W+UwiuxsULarEIK2q/hy40ymVfLcMM6JgsJXE=; h=From:Date:Subject:References:In-Reply-To:To:Cc:From; b=uxgpeGRO0E35cads8Sb1C6LbTBq2beLVcZrJTepd1N/mfJQVkyX0y+ylVd7KGVo1m lxubBU4Pa2hJNr6ibK20oUK5OmggNdViFjSVgs2NFoe2lHCLIQSKc+vFUX2z7KTvCr aP80CSQ3D6M69e7M/Yv8zlDUzxe9oiir9Z/vpwe7xZd+qAw9uAaKL8i/PeBu6jor5z HOJzEkSIWY3znJqY0i5MBDjUyFmnAeqo4RwW84KXJI16vwnLHqgjqwdtTiLodfePmx 0LbFDywQYZSZ4nxHfHxg1Jmn7EHD52o6uHcDHJVi/BPA33lHl068MfFa8ciOg4zcum 3jP7FHgL0iOmQ== From: Andreas Hindborg Date: Wed, 03 Dec 2025 23:26:40 +0100 Subject: [PATCH 10/10] rust: xarray: fix false positive lockdep warnings 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: <20251203-xarray-entry-send-v1-10-9e5ffd5e3cf0@kernel.org> References: <20251203-xarray-entry-send-v1-0-9e5ffd5e3cf0@kernel.org> In-Reply-To: <20251203-xarray-entry-send-v1-0-9e5ffd5e3cf0@kernel.org> To: Tamir Duberstein , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Alice Ryhl , Trevor Gross , Danilo Krummrich Cc: Daniel Gomez , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, Andreas Hindborg X-Mailer: b4 0.15-dev X-Developer-Signature: v=1; a=openpgp-sha256; l=15347; i=a.hindborg@kernel.org; h=from:subject:message-id; bh=EgKnL1W+UwiuxsULarEIK2q/hy40ymVfLcMM6JgsJXE=; b=owEBbQKS/ZANAwAKAeG4Gj55KGN3AcsmYgBpMLkyFIRbHr52OBWfpO4IgzXeSFGVdYkVmVAlb 2P8o6N6ngaJAjMEAAEKAB0WIQQSwflHVr98KhXWwBLhuBo+eShjdwUCaTC5MgAKCRDhuBo+eShj dz4LD/95g/PnD/dBq6jT0ZkAoTWQOu1tFHso+LdoBa1k96yPrxDemjaq409dpcxCw5SCztIavcT ZjwdwJ+HbFBNIgcYglK5pmZf2ImmWn3Isex5b9wkXOJ3Alj5SGXCBohGhj1P2ygAkKX/OO3UGVT vSsuit3CDxrZVUMVsqKJbJopfaujihdp41RHjv/EEUjl/HjD1I5ICYFzAFNG9V9MGEWmVF1Jfmn 95zUhiaXmkb0dN2+8aH/NjVTlh+5IGgrREu4M5GfLCqx8hazQ8ju9D76ycC8Dbm47ZlJUzg0pdO Vs0GkYOkioRPuC8RgPhJJgzXzEeqL/H6QRoNoBvU+EROjqUJ75HyyIR2lxEvmgkX3taHqR3EL4O r0bguLdcnmtu632HCCl7ihzexs3ogd+hWk1JVeGz/pfDwAkoqUTIPMt+yTb0if/7+iBduDT7V3D rqE4cDftyzvBcxjTW62YCvEXMqQDMBKKbdrxD/W9wwsQ9uJ/3G7HHhgVgZ3kurrd5zj8E5swggz 99MsQFJnQ5uG87lk2tTxZG6zOQPsfkdLT+SctYBklCDzrBI75zbYhjYWfDSuP20qmcYc38YjGah 9i+a1MmXaIT+m8PuP9BpW0ou121Ng5j920mxZm6WiRDFt2kgvbf0eNPmyaCX63P4CaGaEZvlM4a HFAvRUrN1EEJGbg== X-Developer-Key: i=a.hindborg@kernel.org; a=openpgp; fpr=3108C10F46872E248D1FB221376EB100563EF7A7 Replace the `xa_init_flags` helper with direct initialization of XArray structures using `__spin_lock_init`. This allows each XArray to have its own lock class key for lockdep, preventing false positive warnings about lock ordering violations. Add a `new_xarray!` macro that automatically generates a unique lock class key for each XArray instantiation site. The macro accepts an optional name parameter and uses the `optional_name!` and `static_lock_class!` macros to generate appropriate names and lock classes. Update the `XArray::new` method signature to accept explicit name and lock class key parameters. This enables proper lockdep tracking while maintaining flexibility for advanced use cases. Remove `rust_helper_xa_init_flags` as it is now dead code. Signed-off-by: Andreas Hindborg --- rust/helpers/xarray.c | 5 --- rust/kernel/xarray.rs | 74 +++++++++++++++++++++++++++++++++--------= ---- rust/kernel/xarray/entry.rs | 55 ++++++++++++++++++--------------- 3 files changed, 86 insertions(+), 48 deletions(-) diff --git a/rust/helpers/xarray.c b/rust/helpers/xarray.c index 425a6cc494734..2852f63388eea 100644 --- a/rust/helpers/xarray.c +++ b/rust/helpers/xarray.c @@ -7,11 +7,6 @@ int rust_helper_xa_err(void *entry) return xa_err(entry); } =20 -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); diff --git a/rust/kernel/xarray.rs b/rust/kernel/xarray.rs index a405f2b6fdcad..c393d4c01af2a 100644 --- a/rust/kernel/xarray.rs +++ b/rust/kernel/xarray.rs @@ -29,6 +29,8 @@ Result, // }, ffi::c_void, + str::CStr, + sync::LockClassKey, types::{ ForeignOwnable, NotThreadSafe, @@ -48,6 +50,19 @@ =20 mod preload; =20 +/// Creates a [`XArray`] initialiser with the given name and a newly-creat= ed lock class. +/// +/// It uses the name if one is given, otherwise it generates one based on = the file name and line +/// number. +#[macro_export] +macro_rules! new_xarray { + ($kind:expr $(, $name:literal)? $(,)?) =3D> { + $crate::xarray::XArray::new( + $kind, $crate::optional_name!($($name)?), $crate::static_lock_= class!()) + }; +} +pub use new_xarray; + /// 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 @@ -62,9 +77,10 @@ /// /// ```rust /// use kernel::alloc::KBox; -/// use kernel::xarray::{AllocKind, XArray}; +/// use kernel::xarray::{new_xarray, AllocKind, XArray}; /// -/// let xa =3D KBox::pin_init(XArray::new(AllocKind::Alloc1), GFP_KERNEL)?; +/// let xa: Pin>>> =3D +/// KBox::pin_init(new_xarray!(AllocKind::Alloc1), GFP_KERNEL)?; /// /// let dead =3D KBox::new(0xdead, GFP_KERNEL)?; /// let beef =3D KBox::new(0xbeef, GFP_KERNEL)?; @@ -124,7 +140,11 @@ pub enum AllocKind { =20 impl XArray { /// Creates a new initializer for this type. - pub fn new(kind: AllocKind) -> impl PinInit { + pub fn new( + kind: AllocKind, + name: &'static CStr, + key: Pin<&'static LockClassKey>, + ) -> impl PinInit { let flags =3D match kind { AllocKind::Alloc =3D> bindings::XA_FLAGS_ALLOC, AllocKind::Alloc1 =3D> bindings::XA_FLAGS_ALLOC1, @@ -133,8 +153,14 @@ pub fn new(kind: AllocKind) -> impl PinInit { // 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) + xa <- Opaque::ffi_init(|xa: *mut bindings::xarray| unsafe { + bindings::__spin_lock_init( + &raw mut (*xa).xa_lock, + name.as_ptr().cast(), + key.as_ptr(), + ); + (*xa).xa_flags =3D flags; + (*xa).xa_head =3D null_mut(); }), _p: PhantomData, }) @@ -236,8 +262,12 @@ fn load(&self, index: usize) -> Option= > { /// # Examples /// /// ``` - /// # use kernel::{alloc::{flags::GFP_KERNEL, kbox::KBox}, xarray::{Al= locKind, XArray}}; - /// let xa =3D KBox::pin_init(XArray::new(AllocKind::Alloc), GFP_KERNE= L)?; + /// # use kernel::{ + /// # alloc::{flags::GFP_KERNEL, kbox::KBox}, + /// # xarray::{new_xarray, AllocKind, XArray}, + /// # }; + /// let xa: Pin>>> =3D + /// KBox::pin_init(new_xarray!(AllocKind::Alloc), GFP_KERNEL)?; /// /// let mut guard =3D xa.lock(); /// assert_eq!(guard.contains_index(42), false); @@ -272,8 +302,9 @@ pub fn get_mut(&mut self, index: usize) -> Option> { /// # Examples /// /// ``` - /// # use kernel::{prelude::*, xarray::{AllocKind, XArray, Entry}}; - /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// # use kernel::{prelude::*, xarray::{new_xarray, AllocKind, XArray,= Entry}}; + /// let mut xa: Pin>>> =3D + /// KBox::pin_init(new_xarray!(AllocKind::Alloc), GFP_KERNEL)?; /// let mut guard =3D xa.lock(); /// /// assert_eq!(guard.contains_index(42), false); @@ -309,8 +340,9 @@ fn load_next(&self, index: usize) -> Option<(usize, Non= Null)> { /// # Examples /// /// ``` - /// # use kernel::{prelude::*, xarray::{AllocKind, XArray}}; - /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// # use kernel::{prelude::*, xarray::{new_xarray, AllocKind, XArray}= }; + /// let mut xa: Pin>>> =3D + /// KBox::pin_init(new_xarray!(AllocKind::Alloc), GFP_KERNEL)?; /// let mut guard =3D xa.lock(); /// /// guard.store(10, KBox::new(10u32, GFP_KERNEL)?, GFP_KERNEL)?; @@ -339,8 +371,9 @@ pub fn find_next(&self, index: usize) -> Option<(usize,= T::Borrowed<'_>)> { /// # Examples /// /// ``` - /// # use kernel::{prelude::*, xarray::{AllocKind, XArray}}; - /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// # use kernel::{prelude::*, xarray::{new_xarray, AllocKind, XArray}= }; + /// let mut xa: Pin>>> =3D + /// KBox::pin_init(new_xarray!(AllocKind::Alloc), GFP_KERNEL)?; /// let mut guard =3D xa.lock(); /// /// guard.store(10, KBox::new(10u32, GFP_KERNEL)?, GFP_KERNEL)?; @@ -366,8 +399,9 @@ pub fn find_next_mut(&mut self, index: usize) -> Option= <(usize, T::BorrowedMut<' /// # Examples /// /// ``` - /// # use kernel::{prelude::*, xarray::{AllocKind, XArray}}; - /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// # use kernel::{prelude::*, xarray::{new_xarray, AllocKind, XArray}= }; + /// let mut xa: Pin>>> =3D + /// KBox::pin_init(new_xarray!(AllocKind::Alloc), GFP_KERNEL)?; /// let mut guard =3D xa.lock(); /// /// guard.store(10, KBox::new(10u32, GFP_KERNEL)?, GFP_KERNEL)?; @@ -401,8 +435,9 @@ pub fn find_next_entry<'b>(&'b mut self, index: usize) = -> Option>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// # use kernel::{prelude::*, xarray::{new_xarray, AllocKind, XArray}= }; + /// let mut xa: Pin>>> =3D + /// KBox::pin_init(new_xarray!(AllocKind::Alloc), GFP_KERNEL)?; /// let mut guard =3D xa.lock(); /// /// guard.store(100, KBox::new(42u32, GFP_KERNEL)?, GFP_KERNEL)?; @@ -505,8 +540,9 @@ pub fn store( /// # Examples /// /// ``` - /// # use kernel::{prelude::*, xarray::{AllocKind, XArray}}; - /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// # use kernel::{prelude::*, xarray::{new_xarray, AllocKind, XArray}= }; + /// let mut xa: Pin>>> =3D + /// KBox::pin_init(new_xarray!(AllocKind::Alloc), GFP_KERNEL)?; /// let mut guard =3D xa.lock(); /// /// assert_eq!(guard.get(42), None); diff --git a/rust/kernel/xarray/entry.rs b/rust/kernel/xarray/entry.rs index 2d6ef4781f47d..6e370252309fc 100644 --- a/rust/kernel/xarray/entry.rs +++ b/rust/kernel/xarray/entry.rs @@ -26,8 +26,9 @@ impl Entry<'_, '_, T> { /// # Examples /// /// ``` - /// # use kernel::{prelude::*, xarray::{AllocKind, XArray, Entry}}; - /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// # use kernel::{prelude::*, xarray::{new_xarray, AllocKind, XArray,= Entry}}; + /// let mut xa: Pin>>> =3D + /// KBox::pin_init(new_xarray!(AllocKind::Alloc), GFP_KERNEL)?; /// let mut guard =3D xa.lock(); /// /// let entry =3D guard.get_entry(42); @@ -100,17 +101,17 @@ fn insert_internal( /// /// Returns a reference to the newly inserted value. /// - /// - This method will fail if the nodes on the path to the index - /// represented by this entry are not present in the XArray and no m= emory - /// is available via the `preload` argument. + /// - This method will fail if the nodes on the path to the index repr= esented by this entry are + /// not present in the XArray and no memory is available via the `pr= eload` argument. /// - This method will not drop the XArray lock. /// /// /// # Examples /// /// ``` - /// # use kernel::{prelude::*, xarray::{AllocKind, XArray, Entry}}; - /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// # use kernel::{prelude::*, xarray::{new_xarray, AllocKind, XArray,= Entry}}; + /// let mut xa: Pin>>> =3D + /// KBox::pin_init(new_xarray!(AllocKind::Alloc), GFP_KERNEL)?; /// let mut guard =3D xa.lock(); /// /// assert_eq!(guard.get(42), None); @@ -139,16 +140,16 @@ pub fn insert( =20 /// Inserts a value and returns an occupied entry representing the new= ly inserted value. /// - /// - This method will fail if the nodes on the path to the index - /// represented by this entry are not present in the XArray and no m= emory - /// is available via the `preload` argument. + /// - This method will fail if the nodes on the path to the index repr= esented by this entry are + /// not present in the XArray and no memory is available via the `pr= eload` argument. /// - This method will not drop the XArray lock. /// /// # Examples /// /// ``` - /// # use kernel::{prelude::*, xarray::{AllocKind, XArray, Entry}}; - /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// # use kernel::{prelude::*, xarray::{new_xarray, AllocKind, XArray,= Entry}}; + /// let mut xa: Pin>>> =3D + /// KBox::pin_init(new_xarray!(AllocKind::Alloc), GFP_KERNEL)?; /// let mut guard =3D xa.lock(); /// /// assert_eq!(guard.get(42), None); @@ -182,8 +183,9 @@ pub fn insert_entry( /// # Examples /// /// ``` - /// # use kernel::{prelude::*, xarray::{AllocKind, XArray, Entry}}; - /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// # use kernel::{prelude::*, xarray::{new_xarray, AllocKind, XArray,= Entry}}; + /// let mut xa: Pin>>> =3D + /// KBox::pin_init(new_xarray!(AllocKind::Alloc), GFP_KERNEL)?; /// let mut guard =3D xa.lock(); /// /// assert_eq!(guard.get(42), None); @@ -221,8 +223,9 @@ pub(crate) fn new(guard: &'b mut Guard<'a, T>, index: u= size, ptr: NonNull>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// # use kernel::{prelude::*, xarray::{new_xarray, AllocKind, XArray,= Entry}}; + /// let mut xa: Pin>>> =3D + /// KBox::pin_init(new_xarray!(AllocKind::Alloc), GFP_KERNEL)?; /// let mut guard =3D xa.lock(); /// /// guard.store(42, KBox::new(0x1337u32, GFP_KERNEL)?, GFP_KERNEL)?; @@ -266,8 +269,9 @@ pub fn remove(mut self) -> T { /// # Examples /// /// ``` - /// # use kernel::{prelude::*, xarray::{AllocKind, XArray, Entry}}; - /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// # use kernel::{prelude::*, xarray::{new_xarray, AllocKind, XArray,= Entry}}; + /// let mut xa: Pin>>> =3D + /// KBox::pin_init(new_xarray!(AllocKind::Alloc), GFP_KERNEL)?; /// let mut guard =3D xa.lock(); /// /// guard.store(42, KBox::new(0x1337u32, GFP_KERNEL)?, GFP_KERNEL)?; @@ -287,8 +291,9 @@ pub fn index(&self) -> usize { /// # Examples /// /// ``` - /// # use kernel::{prelude::*, xarray::{AllocKind, XArray, Entry}}; - /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// # use kernel::{prelude::*, xarray::{new_xarray, AllocKind, XArray,= Entry}}; + /// let mut xa: Pin>>> =3D + /// KBox::pin_init(new_xarray!(AllocKind::Alloc), GFP_KERNEL)?; /// let mut guard =3D xa.lock(); /// /// guard.store(42, KBox::new(0x1337u32, GFP_KERNEL)?, GFP_KERNEL)?; @@ -334,8 +339,9 @@ pub fn insert(&mut self, value: T) -> T { /// # Examples /// /// ``` - /// # use kernel::{prelude::*, xarray::{AllocKind, XArray, Entry}}; - /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// # use kernel::{prelude::*, xarray::{new_xarray, AllocKind, XArray,= Entry}}; + /// let mut xa: Pin>>> =3D + /// KBox::pin_init(new_xarray!(AllocKind::Alloc), GFP_KERNEL)?; /// let mut guard =3D xa.lock(); /// /// guard.store(42, KBox::new(0x1337u32, GFP_KERNEL)?, GFP_KERNEL)?; @@ -361,8 +367,9 @@ pub fn into_mut(self) -> T::BorrowedMut<'b> { /// # Examples /// /// ``` - /// # use kernel::{prelude::*, xarray::{AllocKind, XArray, Entry}}; - /// let mut xa =3D KBox::pin_init(XArray::>::new(AllocKind::= Alloc), GFP_KERNEL)?; + /// # use kernel::{prelude::*, xarray::{new_xarray, AllocKind, XArray,= Entry}}; + /// let mut xa: Pin>>> =3D + /// KBox::pin_init(new_xarray!(AllocKind::Alloc), GFP_KERNEL)?; /// let mut guard =3D xa.lock(); /// /// guard.store(42, KBox::new(100u32, GFP_KERNEL)?, GFP_KERNEL)?; --=20 2.51.2