From nobody Sun Feb 8 07:08:34 2026 Received: from CH4PR04CU002.outbound.protection.outlook.com (mail-northcentralusazon11013023.outbound.protection.outlook.com [40.107.201.23]) (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 820D7374AA5; Thu, 30 Oct 2025 19:06:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.201.23 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761851197; cv=fail; b=K/Kbtb00xoZCBjDGYpYyza4QuwKba8If9J6ooVVWgwCIAGfslvmKQiERjZvvcdKSfrnw6LieNSf9U38k/CyNrfzXNsgXWTS1lohPpB9+QynJuyDockQOxwyXd9hOMOciulpxvHJ3hZZtJMEO8XJLnH7ZaNPofcfyDSFKjz6TqRI= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761851197; c=relaxed/simple; bh=Rn/zrv40JgkoC0DbcwyexEaM2lveFTZSMhArBubXN8M=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=lgkqIa06qvo/Jpz9O1B6BoPVaDcG5HC/jZVdZV+ZBeMltFE/ZdinN9gdXzogSol+/wVucRW5wOs5wz9ogMr66f4Zr3GMjrYXDwiMf3qBuS5wGvAvlPAZe7S86wLn6WFZv4DBIkor7PjaLhj5nL8/eGYgKymvEWq8ifBgYi+sZ8A= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=P8A3s7eF; arc=fail smtp.client-ip=40.107.201.23 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="P8A3s7eF" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=hji1yRKfflvoFTWM50j6ajfn5hS10VmiMMglf5pn1qGoDlWEV5bJjFDkdtdUNv0qyUqBBYjUM54rexLj6UWtD/yQqDphKSqRJ2IaEVEMFMi6rUdCoH0cy52v1FYjGP2flTMx8EFjC3LDZaXJQ/TptXRbdrwYAvUNWiLLULs6ykL2yaeALj/zlQ6amrH4PLfacy3Lym+wbwN2y9rZOIp4QVqiXNDJBTKnVcLOB+1NsQYf2fbwv3hWo5gHiqxScAf7B4dDkvtn4wJGJy63CKruzK3WnnbW/ITzLNKhVcuvdJDH1N9uGUqcS6sHNgR8f7H0igEfEFVs4TvX90xDNYNdjQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=M20FBJnvcmSsWDiO/hP1LroGcCpoKGyXqgZEe7BZYxs=; b=lybtddx6XGafwfm4j8ACD43RemXpDvkS6WOHUDuiEAJ4nCEt4mBU6MsqnNY7ABWbrdH+sgucVIDC+e0p+FpX1fpiOgslB3O2WtvtjplrGNLSezuxjaZ4jucOmxolKJZOV6Sa8yzKhcXFRdYqq4aOwMf8wNWqkviSQD+9zuXxs+q1QdB+qtdSuaHDSP1BkkEkken26ZrHrXX2FrIw9fO4DOvLpixiepsOxsqeWBbNtP7YYnDHH6q0Pm0oV3O9JsfTdfhrx+19XQJq/RyfApGsm2GuGv/1mFcRZHf+W3TyuuN59ayTjw2JjzvbUrqAtNexOfZzg3FxljQC6git8P5tDw== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=M20FBJnvcmSsWDiO/hP1LroGcCpoKGyXqgZEe7BZYxs=; b=P8A3s7eFB3URrESuv8OkGfJ9aqpzGwWUPL5H5f3l5+22kONPcsAxwJt1JAL49Pe0KaB2xPt5YEL/8/uqbudQyHjcu9tcy5McigVQUmYAN9Z9MBDyuoK29tRMEgnt1CJORlp4dHLZggVlfxMlUZMxXlvRTjtfuw875X/N6SH3FelrXISL+y/tGSKZ8tQgFM6a99MAAfmFGKXSTlb+GbUtt4Fpuwt/5BUxahG1ZpIe//9ZKtfEL9JMOhoCEsUP8x+FX/lIVv6MmTUzDTk8F3cdZMexbs+gXA5gfjGdl9+Awm44Fgrpaku2d8qyRh2b9pYn+tfQ+WA0vNE7fCZLAt7lqA== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from SN7PR12MB8059.namprd12.prod.outlook.com (2603:10b6:806:32b::7) by DS5PPFBABE93B01.namprd12.prod.outlook.com (2603:10b6:f:fc00::65f) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9275.14; Thu, 30 Oct 2025 19:06:27 +0000 Received: from SN7PR12MB8059.namprd12.prod.outlook.com ([fe80::4ee2:654e:1fe8:4b91]) by SN7PR12MB8059.namprd12.prod.outlook.com ([fe80::4ee2:654e:1fe8:4b91%2]) with mapi id 15.20.9228.015; Thu, 30 Oct 2025 19:06:25 +0000 From: Joel Fernandes To: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, dri-devel@lists.freedesktop.org, dakr@kernel.org, David Airlie Cc: acourbot@nvidia.com, Alistair Popple , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , bjorn3_gh@protonmail.com, Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , John Hubbard , Joel Fernandes , Timur Tabi , joel@joelfernandes.org, Elle Rhumsaa , Daniel Almeida , Andrea Righi , Philipp Stanner , nouveau@lists.freedesktop.org Subject: [PATCH RFC 1/4] rust: clist: Add abstraction for iterating over C linked lists Date: Thu, 30 Oct 2025 15:06:10 -0400 Message-Id: <20251030190613.1224287-2-joelagnelf@nvidia.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20251030190613.1224287-1-joelagnelf@nvidia.com> References: <20251030190613.1224287-1-joelagnelf@nvidia.com> Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BN9PR03CA0600.namprd03.prod.outlook.com (2603:10b6:408:10d::35) To SN7PR12MB8059.namprd12.prod.outlook.com (2603:10b6:806:32b::7) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SN7PR12MB8059:EE_|DS5PPFBABE93B01:EE_ X-MS-Office365-Filtering-Correlation-Id: 5af55669-329c-4741-e0c1-08de17e76c61 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|7416014|1800799024|376014|366016; X-Microsoft-Antispam-Message-Info: =?us-ascii?Q?islQ4wSWQ/VkZaGKxWqYAdyTP/Z7csUJsCLSSJbhL2JSexkkmRrkw1lJZFHm?= =?us-ascii?Q?VyLy05Nb8hmyPqBuVNYGL1tnV1ACTLmPFm+jgbGNUEzTafhzcGjg6xZRUdij?= =?us-ascii?Q?8e5koBdFEuqV+kINKVpnuYItCdB+nh0D0Akynk5gLRwncj26ix1gyBPWHoAR?= =?us-ascii?Q?cxNTaeoNN4fi6Etn6HsgNUNlu+BTZI7zeWCM02H74NPSDVb6AmfmJvYHJLgj?= =?us-ascii?Q?K+a9gHGHE/clJ/DlcOxH5xy5BqKY1yxCaakiVMtJtdKJJheiesjIycsppUTo?= =?us-ascii?Q?l00oiZgmt7rFQugxXtq96dVnDZHmsyKvDwQVeYoPeagG+aT7GaJSMfGlB9qI?= =?us-ascii?Q?oLjCmecqFpX38CCvYw3DQYLM/uab1cmognzb32hdA3W0DyJycvxyS0fiLTfb?= =?us-ascii?Q?B1T3YUsfDO8VazIi0Xm/eMMZ5+jK1oskgOO0KlUk8wNi0bGT+VLRg02opUdK?= =?us-ascii?Q?fIGvFyH4siTPkFGoDF5ZqMhkOJSxSMcnnCLM4x+FJNvGVlyepVdzUj7RhGKm?= =?us-ascii?Q?co9BwYFnsjbBXN0OdPxfNuM8jSkS2OABDpnBkEc9CS+AFOFTLJ60PxIAJ0Zc?= =?us-ascii?Q?oA0TVBHsliRilQJLYBxl2KG22/OV/gvpiiRBCeT8u1eMCo+rTsWNeQCUhb8V?= =?us-ascii?Q?5rgGA6HtPUmTUJJl6k//QDih6tg1WICgjEStL8R5YO8DSEUhUuCKF46wKfOS?= =?us-ascii?Q?mB66ijF4ofZsIqqmdx+9bxowu5XLrjnYOEc7A8zgE92ksTHDZDNzkvVnYF1N?= =?us-ascii?Q?sX4SrC7n4HHBQtzeZBzuNrvGMxxErnrhqG/t3Awu50Jhz/YgAg2A79u5VWVP?= =?us-ascii?Q?tHAIYcx98/LeLS0xghehfBCxLp1k7Lc9NdCEirC3m8npslkgYW1ro48c+3E1?= =?us-ascii?Q?iLgnC60hZb631/qczKpxjaxjq108iDYbqLCn+A8gO1KNnaX0Xb9NCcAeWfz1?= =?us-ascii?Q?OjvG6LCjpL6SR4qbw7VwbHOcvqzb3ZcW5sdHzsLYStyUfwfLp1bMg3zrN5Ms?= =?us-ascii?Q?k1G1JWjCbVPueES4u5jicJa8qAugvH0g7krQF6eKUFAulDFHIxCgovpGVCMf?= =?us-ascii?Q?y/c8PEo7WHEJGqL7N5MZm9bMIJH7O7cYGO84o5dJMGD9VlG8TRQXbtl9eFfL?= =?us-ascii?Q?Thq7Q+OHRSqWwONf/7mCQ2hLhpN+LA9b85nGTxnwHjuol2KdR9QOnnG/NKGE?= =?us-ascii?Q?KGg7i6bqghIfT2TQ2fOGIryEy1YvWadzbPOfBiG+3f63aXqvB9VW4og+/ek2?= =?us-ascii?Q?0vKrPeblB2M18bezq7dAnZFWer4IC/3BmAj1e1lSMSKCwCflF0bIK6izsEaO?= =?us-ascii?Q?IGvEm8Y9skbPXkpROdhjWu4dd+2FNPExSen00en5Vzk4eL+hVK7mlrVeCMIJ?= =?us-ascii?Q?bDL+VS58Bg6/ZBSLUpBHxNsPXlItbAN0QKUwP/7YN4tWo3ySpsUvPj0cJzDz?= =?us-ascii?Q?kDPQhgNXIdkjxF6r6cEN0cg5hwS8yvH6?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:SN7PR12MB8059.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(7416014)(1800799024)(376014)(366016);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?4ahRjXoVKhbhGcq/DWNfJuzXGNipFOw2mKtRPG7nGFX+Pw7ybKJDi+UyY5gr?= =?us-ascii?Q?VGnoQVhE/eneHCHpuLx8ae32QZDfJlltHDG7iopBnf+OWOlXmK5XuW5qRoox?= =?us-ascii?Q?wIbELnTJx5x2he/zdHn8Y9nvrFTAwY2F9R6ORsXCwA0i1qvMqo3VpVPeqhXw?= =?us-ascii?Q?rBh2aIucKzf/BKr/5D/yCfGUJhgjgapq0GKKhsgirpQLjmp7k+adrU8ZGXbD?= =?us-ascii?Q?Ryz3xj0XW0n8HAq3P74E1DYq9tIjwmTOYm/7deagdrItojXt2LwBUq/L+UHW?= =?us-ascii?Q?25/7JlqQqhEP6NDk8gxElhb/0R9i4WDZtHpal4Bqp3H2cX6Zvu//KFcIt0va?= =?us-ascii?Q?pPcvFQ/LZO8uoz6LkuwrobxX2YE6o7YOdtQpyFoSioSgG7XSWe70nYMz3y5r?= =?us-ascii?Q?ZL6EZN7KdlAWylSAqdTDzms8X085jeVuyTc+nwsnERBwU8Hbe9ypwvtYymBI?= =?us-ascii?Q?W0///kF8yRzjIDqzStR+Yz9qVxzZIkKbw5VvnAAhuvCzGBThRH4Xb96adEYz?= =?us-ascii?Q?s2/mVWXzszqASF7PHshYmYXIBJjBVcXNJqn7+SsqWk3c+HJ8TcweZsqHpsoc?= =?us-ascii?Q?axziANQ2dB8LV/QSWadCTgst8APxopZzPVdp7CJB9Vz5U59PM0UbhidYb+yc?= =?us-ascii?Q?F+q6wAQIzn+S5M5DIUrtAbsNcvf2vlGcE1004TwPj86q3CgrfZZhAb//QXHz?= =?us-ascii?Q?z/Nfb1OyMU9O9YbArtF9FAELEPI3OVxwrqpd/1TIZWz5dqTz+5BBpGV8c1Ne?= =?us-ascii?Q?zsPaFYW4Nd+0r14DK4EFAqacaef/GQDVn1hPydjBG+J5M/HV6lfS8/V7oi5Y?= =?us-ascii?Q?sbNo02xBq8kQVIC1KApZGLoKFoVOl9JEXHo4w+9cKqYGzuHLALWsP75wEYAs?= =?us-ascii?Q?CKmCNOfLUBJCrXzCx1NLnya4uOl1Hiy/UjR+ysqppfTv+kjMFy8uKyOhHRiL?= =?us-ascii?Q?BjLX9IL8efb0lsBGKjLMPUAxs2WfnSA0Q0yF6jdDNNSHFDUNy0Ua/etQNxHc?= =?us-ascii?Q?THGP7FVA4o3FHm9MXsYPqnu4EZOj1D5mA1LXLQYNP4SUxKZJqCvoqzm1za/A?= =?us-ascii?Q?dMUgFwFVKwHgU4TEBbm/1q5voUGvcO0zkeJKQ8Y3odeRRb3Wn6BGuVG/1t1u?= =?us-ascii?Q?60zXs5Lwpt2fHCTLSXr4ePzr5KBLqrAxxTwXSw5bwOvF0fMJ/zYIet6KnEtJ?= =?us-ascii?Q?ho4xPC3ObBFDiTcX5YQsPzPPRcd07rjrdCxp3lqhns2HzKaRLE4Z1MpONTCT?= =?us-ascii?Q?kxENXfFxwgKmG/R1PuQHaR12m3b9FqCZEuAVPpOas72UGYNmCNTvwQGfY9ov?= =?us-ascii?Q?CHgGMDKyeDGFzB5Dc/MR4THavBPHAyrEFKq/VXqRfWi/5Cothjd1DBUUAkaA?= =?us-ascii?Q?PFknG7vTvi9/eka99mIzcz4tjnrUXLdo3N7Sgnh5gL0wpAPJdN9k1aTugnTm?= =?us-ascii?Q?KaiqUGb85G4zmYlIJp+slAZ1+SI8k7VxEAsutgTqM7J+lqMeerMUtKlUA8iv?= =?us-ascii?Q?3rsd5TLDtxE5EB6eE2kprzRwRyw8AHmO/8QCCkZPlVAvwLffpwcBySs14CUK?= =?us-ascii?Q?ZMDUhks7z7Msl9/ea5Xa28dt4ryu2IdxQJxrov0s?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 5af55669-329c-4741-e0c1-08de17e76c61 X-MS-Exchange-CrossTenant-AuthSource: SN7PR12MB8059.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Oct 2025 19:06:25.8170 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: SWrhZROS1/TsOTyUKQK2jIvDJFHF8VZsjgDdJu23yO4EzpHMwWN+TIxfApXPEN4eiFvYyNMy7/rn1iFRBZhMDA== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DS5PPFBABE93B01 Content-Type: text/plain; charset="utf-8" Provides a safe interface for iterating over C's intrusive linked lists (`list_head` structures). At the moment, supports only read-only iteration. DRM Buddy bindings will use this to iterate over DRM buddy blocks allocated in a linked list. Signed-off-by: Joel Fernandes --- rust/helpers/helpers.c | 1 + rust/helpers/list.c | 28 ++++ rust/kernel/clist.rs | 296 +++++++++++++++++++++++++++++++++++++++++ rust/kernel/lib.rs | 1 + 4 files changed, 326 insertions(+) create mode 100644 rust/helpers/list.c create mode 100644 rust/kernel/clist.rs diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index 79c72762ad9c..634fa2386bbb 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -32,6 +32,7 @@ #include "io.c" #include "jump_label.c" #include "kunit.c" +#include "list.c" #include "maple_tree.c" #include "mm.c" #include "mutex.c" diff --git a/rust/helpers/list.c b/rust/helpers/list.c new file mode 100644 index 000000000000..74e8f40b7141 --- /dev/null +++ b/rust/helpers/list.c @@ -0,0 +1,28 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include + +bool rust_helper_list_empty(const struct list_head *head) +{ + return list_empty(head); +} + +void rust_helper_list_del(struct list_head *entry) +{ + list_del(entry); +} + +void rust_helper_INIT_LIST_HEAD(struct list_head *list) +{ + INIT_LIST_HEAD(list); +} + +void rust_helper_list_add(struct list_head *new, struct list_head *head) +{ + list_add(new, head); +} + +void rust_helper_list_add_tail(struct list_head *new, struct list_head *he= ad) +{ + list_add_tail(new, head); +} diff --git a/rust/kernel/clist.rs b/rust/kernel/clist.rs new file mode 100644 index 000000000000..e6a46974b1ba --- /dev/null +++ b/rust/kernel/clist.rs @@ -0,0 +1,296 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! List processing module for C list_head linked lists. +//! +//! C header: [`include/linux/list.h`](srctree/include/linux/list.h) +//! +//! Provides a safe interface for iterating over C's intrusive `list_head`= structures. +//! At the moment, supports only read-only iteration. +//! +//! # Examples +//! +//! ```ignore +//! use core::ptr::NonNull; +//! use kernel::{ +//! bindings, +//! clist, +//! container_of, +//! prelude::*, // +//! }; +//! +//! // Example C-side struct (typically from C bindings): +//! // struct c_item { +//! // u64 offset; +//! // struct list_head link; +//! // /* ... other fields ... */ +//! // }; +//! +//! // Rust-side struct to hold pointer to C-side struct. +//! struct Item { +//! ptr: NonNull, +//! } +//! +//! impl clist::FromListHead for Item { +//! unsafe fn from_list_head(link: *const bindings::list_head) -> Self= { +//! let item_ptr =3D container_of!(link, bindings::c_item, link) a= s *mut _; +//! Item { ptr: NonNull::new_unchecked(item_ptr) } +//! } +//! } +//! +//! impl Item { +//! fn offset(&self) -> u64 { +//! unsafe { (*self.ptr.as_ptr()).offset } +//! } +//! } +//! +//! // Get the list head from C code. +//! let c_list_head =3D unsafe { bindings::get_item_list() }; +//! +//! // Rust wraps and iterates over the list. +//! let list =3D unsafe { clist::Clist::::new(c_list_head) }; +//! +//! // Check if empty. +//! if list.is_empty() { +//! pr_info!("List is empty\n"); +//! } +//! +//! // Iterate over items. +//! for item in list.iter() { +//! pr_info!("Item offset: {}\n", item.offset()); +//! } +//! ``` + +use crate::bindings; +use core::marker::PhantomData; + +/// Trait for types that can be constructed from a C list_head pointer. +/// +/// This typically encapsulates `container_of` logic, allowing iterators to +/// work with high-level types without knowing about C struct layout detai= ls. +/// +/// # Safety +/// +/// Implementors must ensure that `from_list_head` correctly converts the +/// `list_head` pointer to the containing struct pointer using proper offs= et +/// calculations (typically via container_of! macro). +/// +/// # Examples +/// +/// ```ignore +/// impl FromListHead for MyItem { +/// unsafe fn from_list_head(link: *const bindings::list_head) -> Self= { +/// let item_ptr =3D container_of!(link, bindings::my_c_struct, li= nk_field) as *mut _; +/// MyItem { ptr: NonNull::new_unchecked(item_ptr) } +/// } +/// } +/// ``` +pub trait FromListHead: Sized { + /// Create instance from list_head pointer embedded in containing stru= ct. + /// + /// # Safety + /// + /// Caller must ensure `link` points to a valid list_head embedded in = the + /// containing struct, and that the containing struct is valid for the + /// lifetime of the returned instance. + unsafe fn from_list_head(link: *const bindings::list_head) -> Self; +} + +/// Iterator over C list items. +/// +/// Uses the [`FromListHead`] trait to convert list_head pointers to +/// Rust types and iterate over them. +/// +/// # Invariants +/// - `head` points to a valid, initialized list_head. +/// - `current` points to a valid node in the list. +/// - The list is not modified during iteration. +/// +/// # Examples +/// +/// ```ignore +/// // Iterate over blocks in a C list_head +/// for block in clist::iter_list_head::(&list_head) { +/// // Process block +/// } +/// ``` +pub struct ClistIter<'a, T: FromListHead> { + current: *const bindings::list_head, + head: *const bindings::list_head, + _phantom: PhantomData<&'a T>, +} + +// SAFETY: Safe to send iterator if T is Send. +unsafe impl<'a, T: FromListHead + Send> Send for ClistIter<'a, T> {} + +impl<'a, T: FromListHead> Iterator for ClistIter<'a, T> { + type Item =3D T; + + fn next(&mut self) -> Option { + // SAFETY: Pointers are valid per the type's invariants. The list + // structure is valid and we traverse according to kernel list sem= antics. + unsafe { + self.current =3D (*self.current).next; + + if self.current =3D=3D self.head { + return None; + } + + // Use the trait to convert list_head to T. + Some(T::from_list_head(self.current)) + } + } +} + +/// Create a read-only iterator over a C list_head. +/// +/// This is a convenience function for creating iterators directly +/// from a list_head reference. +/// +/// # Safety +/// +/// Caller must ensure: +/// - `head` is a valid, initialized list_head. +/// - All items in the list are valid instances that can be converted via = [`FromListHead`]. +/// - The list is not modified during iteration. +/// +/// # Examples +/// +/// ```ignore +/// // Iterate over items in a C list. +/// for item in clist::iter_list_head::(&c_list_head) { +/// // Process item +/// } +/// ``` +pub fn iter_list_head<'a, T: FromListHead>(head: &'a bindings::list_head) = -> ClistIter<'a, T> { + ClistIter { + current: head as *const _, + head: head as *const _, + _phantom: PhantomData, + } +} + +/// Check if a C list is empty. +/// +/// # Safety +/// +/// Caller must ensure `head` points to a valid, initialized list_head. +#[inline] +pub unsafe fn list_empty(head: *const bindings::list_head) -> bool { + // SAFETY: Caller ensures head is valid and initialized. + unsafe { bindings::list_empty(head) } +} + +/// Initialize a C list_head to an empty list. +/// +/// # Safety +/// +/// Caller must ensure `head` points to valid memory for a list_head. +#[inline] +pub unsafe fn init_list_head(head: *mut bindings::list_head) { + // SAFETY: Caller ensures head points to valid memory for a list_head. + unsafe { bindings::INIT_LIST_HEAD(head) } +} + +/// An interface to C list_head structures. +/// +/// This provides an iterator-based interface for traversing C's intrusive +/// linked lists. Items must implement the [`FromListHead`] trait. +/// +/// Designed for iterating over lists created and managed by C code (e.g., +/// drm_buddy block lists). [`Clist`] does not own the `list_head` or the = items. +/// It's a non-owning view for iteration. +/// +/// # Invariants +/// - `head` points to a valid, initialized list_head. +/// - All items in the list are valid instances of `T`. +/// - The list is not modified while iterating. +/// +/// # Thread Safety +/// [`Clist`] can have its ownership transferred between threads ([`Send`]= ) if `T: Send`. +/// But its never [`Sync`] - concurrent Rust threads with `&Clist` could c= all C FFI unsafely. +/// For concurrent access, wrap in a `Mutex` or other synchronization prim= itive. +/// +/// # Examples +/// +/// ```ignore +/// use kernel::clist::Clist; +/// +/// // C code provides the populated list_head. +/// let list =3D unsafe { Clist::::new(c_list_head) }; +/// +/// // Iterate over items. +/// for item in list.iter() { +/// // Process item. +/// } +/// ``` +pub struct Clist { + head: *mut bindings::list_head, + _phantom: PhantomData, +} + +// SAFETY: Safe to send Clist if T is Send (pointer moves, C data stays in= place). +unsafe impl Send for Clist {} + +impl Clist { + /// Wrap an existing C list_head pointer without taking ownership. + /// + /// # Safety + /// + /// Caller must ensure: + /// - `head` points to a valid, initialized list_head. + /// - `head` remains valid for the lifetime of the returned [`Clist`]. + /// - The list is not modified by C code while [`Clist`] exists. Calle= r must + /// implement mutual exclusion algorithms if required, to coordinate= with C. + /// - Caller is responsible for requesting or working with C to free `= head` if needed. + pub unsafe fn new(head: *mut bindings::list_head) -> Self { + // SAFETY: Caller ensures head is valid and initialized + Self { + head, + _phantom: PhantomData, + } + } + + /// Check if the list is empty. + /// + /// # Examples + /// + /// ```ignore + /// let list =3D Clist::::new()?; + /// assert!(list.is_empty()); + /// ``` + #[inline] + pub fn is_empty(&self) -> bool { + // SAFETY: self.head points to valid list_head per invariant. + unsafe { list_empty(self.head) } + } + + /// Iterate over items in the list. + /// + /// # Examples + /// + /// ```ignore + /// for item in list.iter() { + /// // Process item + /// } + /// ``` + pub fn iter(&self) -> ClistIter<'_, T> { + // SAFETY: self.head points to valid list_head per invariant. + unsafe { iter_list_head::(&*self.head) } + } + + /// Get the raw list_head pointer. + /// + /// This is useful when interfacing with C APIs that need the list_hea= d pointer. + pub fn as_raw(&self) -> *mut bindings::list_head { + self.head + } +} + +impl<'a, T: FromListHead> IntoIterator for &'a Clist { + type Item =3D T; + type IntoIter =3D ClistIter<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index c2eea9a2a345..b69cc5ed3b59 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -72,6 +72,7 @@ pub mod bug; #[doc(hidden)] pub mod build_assert; +pub mod clist; pub mod clk; #[cfg(CONFIG_CONFIGFS_FS)] pub mod configfs; --=20 2.34.1 From nobody Sun Feb 8 07:08:34 2026 Received: from CH4PR04CU002.outbound.protection.outlook.com (mail-northcentralusazon11013023.outbound.protection.outlook.com [40.107.201.23]) (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 CBEC836CE0E; Thu, 30 Oct 2025 19:06:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.201.23 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761851199; cv=fail; b=OP554+8TEvF2UfBfFFGAGuREqd2ADfmUpy9djq6DT7NgMqOYzg7NZPJ6pTHMU+IgBy5oAgCcxFdr92bw51gHr6MsqdjsRStcFxtgiEUgdPx5nPIn8gTnTe984iPn6Cly3+gM2YqpMZheRgYFQ8dxuxKqBL0ceM+6ry3c1e9nw0Q= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761851199; c=relaxed/simple; bh=YTrTIo4KvW8oFBf+lgY+EF3ETHMmOw3oFNKw0pMp/F4=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=icJHyxB+Bo0Xsj0WgE8wBl5ZnV34DvlNcmj+UF1i9bL8k3jCgeUbVtX1sLKBs1LaOkspnmycNJevd+RXhQvnbDgcvoEOh1FJGT+SX+RJacby4PTJK203ZTSi+v5MbgiNlqTaUrkvPpoj8wuMmpLoLU8UtZCzTFOgtZrEysOFEi0= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=EwZjMJTK; arc=fail smtp.client-ip=40.107.201.23 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="EwZjMJTK" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=lqxGd783p4DM1d7vwm5ZhiuGdoZmzOn8qg5sCiFT9QxD33bXUswjmCJTTSfgpSqK3FlvYbvHD5C+2Ml98JKIy2ct1jyTrTwFmTdxpUfKDjFT7yNdTWeMS6B0GX+x7mtu3r+NgsEgZpdf/JEVuE6avK3kzo2e5Y27hdvZFZ0/gTTCVH3NS4WdeVSdTsbOUOuHeSVwXX4HJJzXPxDTPDzRQj/gt0FlZMDv6nW/el/QDQSf/2KIY7pctf9lTCrBxdaxA+WbGPu27QoOufPf2DRYmr6BxnZ6IhfKu3rLUr2efEarwkkgVp4D2GSKI7RmS94N6jFnlSPx1iudKQuEHaqIZQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=etJbbMeqdAuZRh/HJvZ2cLD+tgdVu/ko2JD1/SlDlII=; b=hdj6t9nfK43nU/+8Yp/ZfzY3jMVxzCjDCAAR/RDvLbdFZQwRaAlzvktIx0QHpUjOKJU5ghk27PI27cnef7QgE/V+JKNu9vcnQ2CT3l2KGs6B5zxS8dpcRuYcU81R2Af7Zp4yjfsgTBODAqP6ymNCzqTNjlp6MhxLVPPNfrFxQcxW6BzMVOK1tDclkb7cs4ertbwhCVlwLh/7M/VNNVYK1uZQeRSBhmH8XxgtgX7/IgM5slAXLt7j8xy41xUFhSnoHajhGlLqHYmAD1h7mQsKp+YinYWj8TMsxB7e1TLptf6qi2uYzskUTVLnU8tOhzqI70IahtmLaA4M63UHiDc0FA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=etJbbMeqdAuZRh/HJvZ2cLD+tgdVu/ko2JD1/SlDlII=; b=EwZjMJTKp8HeAkXV1VbWZRf01/0dTiVQuSJImA9yKN29MHjsMa6mom1clEVrXXz9GQbhIoEFByjjFkp2o5pixvmF5XhAGhT8Gch1oZIBzYH5mKaPezpntpWgA2+/KLvQ93SpRSDq7OgB7RHISWF1hHE4DdAN7WrklfTsUkRUgUf/yIqMGsE3oXlTVBPgGw4ccD88igd83So4912ryuHKWYL2F5ZPg3PLX8xba3S7UwNhJ0b0wR9I/Rjj45SYtEicpmHEShlU8jEQFIS5Xkn9odXkSKabd0SdARhIZfB0XAVLOFuOLAybAzS7kKop0cFMcxBlqHsODT9jPsckLbjeIQ== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from SN7PR12MB8059.namprd12.prod.outlook.com (2603:10b6:806:32b::7) by DS5PPFBABE93B01.namprd12.prod.outlook.com (2603:10b6:f:fc00::65f) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9275.14; Thu, 30 Oct 2025 19:06:31 +0000 Received: from SN7PR12MB8059.namprd12.prod.outlook.com ([fe80::4ee2:654e:1fe8:4b91]) by SN7PR12MB8059.namprd12.prod.outlook.com ([fe80::4ee2:654e:1fe8:4b91%2]) with mapi id 15.20.9228.015; Thu, 30 Oct 2025 19:06:30 +0000 From: Joel Fernandes To: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, dri-devel@lists.freedesktop.org, dakr@kernel.org, David Airlie Cc: acourbot@nvidia.com, Alistair Popple , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , bjorn3_gh@protonmail.com, Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , John Hubbard , Joel Fernandes , Timur Tabi , joel@joelfernandes.org, Elle Rhumsaa , Daniel Almeida , Andrea Righi , Philipp Stanner , nouveau@lists.freedesktop.org Subject: [PATCH RFC 2/4] samples: rust: Add sample demonstrating C linked list iteration Date: Thu, 30 Oct 2025 15:06:11 -0400 Message-Id: <20251030190613.1224287-3-joelagnelf@nvidia.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20251030190613.1224287-1-joelagnelf@nvidia.com> References: <20251030190613.1224287-1-joelagnelf@nvidia.com> Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BN9PR03CA0579.namprd03.prod.outlook.com (2603:10b6:408:10d::14) To SN7PR12MB8059.namprd12.prod.outlook.com (2603:10b6:806:32b::7) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SN7PR12MB8059:EE_|DS5PPFBABE93B01:EE_ X-MS-Office365-Filtering-Correlation-Id: dc53d27f-b101-487b-2e9a-08de17e76d5c X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|7416014|1800799024|376014|366016; X-Microsoft-Antispam-Message-Info: =?us-ascii?Q?YBqd2stBHY53LF/ZcGtKDnTixWwBbVdsa8mhDpPLa3gGxZRH8Ev5zxtCjeNO?= =?us-ascii?Q?dVHyipdS++ztJh15rFE0dYB8OEfrzK/1xe1GtBuPiyRykUKcWZjyv12DglM3?= =?us-ascii?Q?WqNBE5sM/OQrV/2Jc62WVM5Qq6uUNWJS1v484QTYacH9wRjMAhZqFreAzjJ/?= =?us-ascii?Q?cDKOtuuLXrER/eSEIJiPU0RBPDaW+bEiIsA/2dvEO/6lTtNT0DQDAeP8SNsV?= =?us-ascii?Q?wTzGcjwTziUF/7j303PThsIJzCOFao3qyIdPTsKn/DHCLfsSfPr1w+4rWpiV?= =?us-ascii?Q?Scj2VehNoCyZpCwmwtWam6M1CmQG1NocebPoJ2EKXy0omprPl0aipqm4SXtG?= =?us-ascii?Q?VOBmywUERDUNObgxbuTmEvZzZPWVfMUaf6SjouHlEmhRvYEUmZ5Ggorr2rEf?= =?us-ascii?Q?t8+BHcAX6zOuvpUMpGMN8+TCB8o/zbxpYU/R/08ccdRkMPar3iGfgsZsE3Rd?= =?us-ascii?Q?jmD8cH4Blfzkp/lYkMHUddkq/Kd7O+0E9Y3wreolIpR0LS0u0WhQs1CNMxie?= =?us-ascii?Q?8asbolwhe4xdXaLBhjqhJbl/68pd/eiSj6R07v6j0pAgUFDCyaaMmOhB3Pqd?= =?us-ascii?Q?dKtA+xiJCf0Oz37X8JVCbEwXT46d65a9F5nn+K9BR94hg8ivbCYuCkd0h1X0?= =?us-ascii?Q?vyyE1hZ1llKCw3zbouUCmi45d8kfrIGXz9AwNfEef3cbddZ0KykdAweh1Dwu?= =?us-ascii?Q?dFHE/sdVJ9KZDKst0dIoXfnzGP6ADvnYcGrLXueu7oMb5ZCwDEK47iFQda8+?= =?us-ascii?Q?6TAomRrf/ma/Zo8TT2fZLx4i1L2WHFdBXVlr5riQ7ufszp0JSdMJycEEHHbm?= =?us-ascii?Q?123+Sx7CbpLmSLYhj83uIYSvFuBKNSIxkjDYaTUURQxIbmAxtoyIRRqV2Je5?= =?us-ascii?Q?9Vev3iQ6D4gKIwFZZ0KGWDnyoyqBwo32V8fI2Db+AtZ8pdEr6CLMEaDkyBLY?= =?us-ascii?Q?7sd0YFV0hBEizj71wA8c0yCGVNdkdEUbJkzJ8GA2B84oi2E4CfoMknserCjt?= =?us-ascii?Q?aHZzE1B4hiIwNzNzdfQIemSn29ZmkASNXMkI23RQztDYPt+WJqq+JirdolcW?= =?us-ascii?Q?IKUjDlbqoNyyjnLQILJwcpRD/ZhCbYYm4E/i0/Qa29WNS21HWC9zx2Lxslzu?= =?us-ascii?Q?o0LYKcGWDK5JD6u/hkUczcrFAf1p8le6xbIFjjSM+xKoesGtTti5GMUil6WY?= =?us-ascii?Q?Rzb0ZSoack6uXIU/tls20KltM6Bvu94o5i9s6dFRyBleR7ZftQVHJi/1BAbQ?= =?us-ascii?Q?nk0SXBdV++/MZNfJgDW+QhT0NHGhYmvDALjHl3dyW7Dl95jM4VZyw/mmEhpB?= =?us-ascii?Q?OPcCN+g4pl57Asb5FyK3tvaApLYa+6Z3F6D+jEKrZN5IJKQgSTfUQMpqmKfN?= =?us-ascii?Q?0d++b9S1Gs+iUXci1ed+xmAzEsBA2KllyJMpZoyZakRwmMv7HBHR29lF8WBY?= =?us-ascii?Q?cRvA+dnwRMiisIfETB3rv9zQ3XHpF7fY?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:SN7PR12MB8059.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(7416014)(1800799024)(376014)(366016);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?RsO2V4nPUA0OmFOcXsM/bosUsDyMJpgs6jvvQDQx4ebr8afg6BlPOdoScOI2?= =?us-ascii?Q?5yhAVrM35Bt/VzyQ7XmXdpTaVXLyQPVo8BE7FsV5w/Dqd8ufwTMliZoNRIV+?= =?us-ascii?Q?xkWSd9YbJbDUvX2rngoQI/xxtWZC+IWBK18t3YjR1ZdaeQf7YwKxzXmq9LYP?= =?us-ascii?Q?hONtdNJBzxhkdZStZ9bCMOHa1L9ynXZg0Q98h7PElaIbCvVXGXSOTudUqGDd?= =?us-ascii?Q?87UmJ/0qIXXM+qpjbFcwkvrO/wqaIGe1ngXJA8MKaV87FXIyjhkb9MsARma2?= =?us-ascii?Q?envQSQs7duU9oY2qiLlbE4jM4qE0UBNv3xukUt4XBkUoCeNcl+93ebq3CLSr?= =?us-ascii?Q?WfkAipEAgFDcF9GpIKwv5+WyVXWb/cg4ZJF/PFdkSxPhm7a+sfyKJyexNMM4?= =?us-ascii?Q?/e4DF/kaFQjcl9fbAcxBEEYYcCOGlJp2OjjQpMF+/wgSj1pxVM+Jt1R1xhxx?= =?us-ascii?Q?eN1v4AyJW7/2o7ROu/CTn7HYXDUaMw32cjaNmqLws+Bab7BmfLRYaNI/pXt+?= =?us-ascii?Q?3Oyg/QfZ+NdYYPulAffsD5p5sukaoT4eWarmnNy07Gmp8GVRKU7CXZqrSyCK?= =?us-ascii?Q?6NxeMLT9HQsJoRAYq7Sx2bnZlUc14fqZRO5uFK3m1gIqDxYreL92EHmnanDh?= =?us-ascii?Q?JQuiaVngSGoE67Bw+c1P2Z2GlALbVETuFawXEYgD9kZMlXKIYT25JIY94SFG?= =?us-ascii?Q?dX8DUB/REMTPLPqYfGavrHIPD+yZHZSWe04JTIaq58VeUgKUUPqW9gRFey4+?= =?us-ascii?Q?womrgANqoJiV1m/8ckDRvkWU0Uw78P9TpmWmaMiCWEd5seEB4tLYAqnljmPy?= =?us-ascii?Q?iybvKwfCdUmEDm5KA5h3kF8WoAik34JhX86t6aZsc/SnR4mAnZM0GTn3xqHO?= =?us-ascii?Q?dsS9/jnnK+6HnruBf5Y9zg8qaKGIiteOnP4KPbc0ucZ3jGLn/EKT74ZbRdqZ?= =?us-ascii?Q?YKvQ8nG0iXe0k0O0mzA7awl1w7G4ZjK4v9LbVW5rXsrkej99UcFhrTL0jGYc?= =?us-ascii?Q?/X0dvG1k1MqmOSsCj+WARRUc1083ByWiVQOf4qpSkbL63q3gqsTsGpwchqbA?= =?us-ascii?Q?1/gF22NKRvfyJ/dOmrGWphZoQbrBoR2q3riWh7okWoY8c3j9xjmTiP/Fqfii?= =?us-ascii?Q?ajVX3Ujn8HRGFoklSwKk7R1cYcXGs+aUAWJxTJq7QaSS04/0SFcLUm8rGyVb?= =?us-ascii?Q?kU+LY+vnvha1XWEZaSPlEJW2yD2y9IwguqYfpZCN+5G7uWzWuB26Mn+K1TfA?= =?us-ascii?Q?SkQOcJ4z/OuJYA8X97sTVeitTjaatW5+TQ3b7pZSx8GpUKSj+cXKzDoVSVLd?= =?us-ascii?Q?qJwPOvAkAs5gb0WdvM89h2ms4z3BZ1Az8IXVpZ7ciLABQzCCBLYUssaogW7h?= =?us-ascii?Q?3nkUPE2UTDkHbBSBV5iekKoMBLahxTJaeLAZczUmWsnOq0PRWsk2wPiOZY6w?= =?us-ascii?Q?/k1dOEgyMKg8ZS7nEpLCbn2qAftaxvgYCiRHcvuNtW5lYkzeT2tOTbI49bu8?= =?us-ascii?Q?s4OytqAGmgCsN9t4wCV5v5aYBC2cgtK681NwulPUw74RuvKx0QiUcDVEuMKU?= =?us-ascii?Q?+dKgrALP/jDGU8VebhaBhwRmxn44RPlrb2FoR0I/?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: dc53d27f-b101-487b-2e9a-08de17e76d5c X-MS-Exchange-CrossTenant-AuthSource: SN7PR12MB8059.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Oct 2025 19:06:27.6498 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: dbfHFnTF7M4Afqlanf9AIDHlz55Y4vJnNUc5x5BqOevX7x7SRoE3yMwQhu3sJUk0ZBp1kt6+rM+Cm+Ev2xDvOg== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DS5PPFBABE93B01 Content-Type: text/plain; charset="utf-8" Demonstrates usage of the clist module for iterating over C-managed linked lists. C code creates and populates the list, Rust code performs safe iteration using the clist abstraction. Signed-off-by: Joel Fernandes --- samples/rust/Kconfig | 11 +++ samples/rust/Makefile | 2 + samples/rust/rust_clist_c.c | 54 +++++++++++++ samples/rust/rust_clist_main.rs | 138 ++++++++++++++++++++++++++++++++ 4 files changed, 205 insertions(+) create mode 100644 samples/rust/rust_clist_c.c create mode 100644 samples/rust/rust_clist_main.rs diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig index c1cc787a9add..b45631e2593c 100644 --- a/samples/rust/Kconfig +++ b/samples/rust/Kconfig @@ -10,6 +10,17 @@ menuconfig SAMPLES_RUST =20 if SAMPLES_RUST =20 +config SAMPLE_RUST_CLIST + tristate "C Linked List sample" + help + This option builds the Rust CList sample demonstrating + the clist module for working with C list_head structures. + + To compile this as a module, choose M here: + the module will be called rust_clist. + + If unsure, say N. + config SAMPLE_RUST_CONFIGFS tristate "Configfs sample" depends on CONFIGFS_FS diff --git a/samples/rust/Makefile b/samples/rust/Makefile index cf8422f8f219..f8899c0df762 100644 --- a/samples/rust/Makefile +++ b/samples/rust/Makefile @@ -1,6 +1,7 @@ # SPDX-License-Identifier: GPL-2.0 ccflags-y +=3D -I$(src) # needed for trace events =20 +obj-$(CONFIG_SAMPLE_RUST_CLIST) +=3D rust_clist.o obj-$(CONFIG_SAMPLE_RUST_MINIMAL) +=3D rust_minimal.o obj-$(CONFIG_SAMPLE_RUST_MISC_DEVICE) +=3D rust_misc_device.o obj-$(CONFIG_SAMPLE_RUST_PRINT) +=3D rust_print.o @@ -14,6 +15,7 @@ obj-$(CONFIG_SAMPLE_RUST_DRIVER_FAUX) +=3D rust_driver_f= aux.o obj-$(CONFIG_SAMPLE_RUST_DRIVER_AUXILIARY) +=3D rust_driver_auxiliary.o obj-$(CONFIG_SAMPLE_RUST_CONFIGFS) +=3D rust_configfs.o =20 +rust_clist-y :=3D rust_clist_main.o rust_clist_c.o rust_print-y :=3D rust_print_main.o rust_print_events.o =20 subdir-$(CONFIG_SAMPLE_RUST_HOSTPROGS) +=3D hostprogs diff --git a/samples/rust/rust_clist_c.c b/samples/rust/rust_clist_c.c new file mode 100644 index 000000000000..7a8f5e6c642a --- /dev/null +++ b/samples/rust/rust_clist_c.c @@ -0,0 +1,54 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include + +/* Sample item with embedded C list_head */ +struct sample_item_c { + int value; + struct list_head link; +}; + +/* Create a list_head and populate it with items */ +struct list_head *clist_sample_create(int count) +{ + struct list_head *head; + int i; + + head =3D kmalloc(sizeof(*head), GFP_KERNEL); + if (!head) + return NULL; + + INIT_LIST_HEAD(head); + + /* Populate with items */ + for (i =3D 0; i < count; i++) { + struct sample_item_c *item =3D kmalloc(sizeof(*item), GFP_KERNEL); + + if (!item) + continue; + + item->value =3D i * 10; + INIT_LIST_HEAD(&item->link); + list_add_tail(&item->link, head); + } + + return head; +} + +/* Free the list_head and all items */ +void clist_sample_free(struct list_head *head) +{ + struct sample_item_c *item, *tmp; + + if (!head) + return; + + /* Free all items in the list */ + list_for_each_entry_safe(item, tmp, head, link) { + list_del(&item->link); + kfree(item); + } + + kfree(head); +} diff --git a/samples/rust/rust_clist_main.rs b/samples/rust/rust_clist_main= .rs new file mode 100644 index 000000000000..6600b0c79558 --- /dev/null +++ b/samples/rust/rust_clist_main.rs @@ -0,0 +1,138 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Sample for Rust code interfacing with C linked lists (list_head). +//! +//! This sample demonstrates iteration of a C-managed linked list using th= e [`clist`] module. +//! C code creates and populates the list, Rust code performs iteration. + +use core::ptr::NonNull; +use kernel::{ + bindings, + clist, + container_of, + prelude::*, // +}; + +module! { + type: RustClistModule, + name: "rust_clist", + authors: ["Joel Fernandes"], + description: "Rust Clist sample", + license: "GPL", +} + +// FFI declarations for C functions +extern "C" { + fn clist_sample_create(count: i32) -> *mut bindings::list_head; + fn clist_sample_free(head: *mut bindings::list_head); +} + +/// Sample item with embedded C list_head (This would typically be a C str= uct). +#[repr(C)] +struct SampleItemC { + value: i32, + link: bindings::list_head, +} + +/// Rust wrapper for SampleItemC object pointer allocated on the C side. +/// +/// # Invariants +/// +/// `ptr` points to a valid [`SampleItemC`] with an initialized embedded `= list_head`. +struct SampleItem { + ptr: NonNull, +} + +impl clist::FromListHead for SampleItem { + unsafe fn from_list_head(link: *const bindings::list_head) -> Self { + // SAFETY: Caller ensures link points to a valid, initialized list= _head. + unsafe { + let item_ptr =3D container_of!(link, SampleItemC, link) as *mu= t _; + SampleItem { + ptr: NonNull::new_unchecked(item_ptr), + } + } + } +} + +impl SampleItem { + /// Get the value from the sample item. + fn value(&self) -> i32 { + // SAFETY: self.ptr is valid as per the SampleItem invariants. + unsafe { (*self.ptr.as_ptr()).value } + } +} + +/// Clist struct - holds the C list_head and manages its lifecycle. +#[repr(C)] +struct RustClist { + list_head: NonNull, +} + +// SAFETY: RustClist can be sent between threads since it only holds a poi= nter +// which can be accessed from any thread with proper synchronization. +unsafe impl Send for RustClist {} + +impl RustClist { + /// Create a container for a pointer to a C-allocated list_head. + fn new(list_head: *mut bindings::list_head) -> Self { + // SAFETY: Caller ensures list_head is a valid, non-null pointer. + Self { + list_head: unsafe { NonNull::new_unchecked(list_head) }, + } + } + + /// Demonstrate iteration over the list. + fn do_iteration(&self) { + // Wrap the C list_head with a Rust [`Clist`]. + // SAFETY: list_head is a valid, initialized, populated list_head. + let list =3D unsafe { clist::Clist::::new(self.list_he= ad.as_ptr()) }; + pr_info!("Created C list with items, is_empty: {}\n", list.is_empt= y()); + + // Iterate over the list. + pr_info!("Iterating over C list from Rust:\n"); + for item in list.iter() { + pr_info!(" Item value: {}\n", item.value()); + } + + pr_info!("Iteration complete\n"); + } +} + +impl Drop for RustClist { + fn drop(&mut self) { + // Free the list and all items using C FFI. + // SAFETY: list_head was allocated by clist_sample_create. + // C side handles freeing both the list_head and all items. + unsafe { + clist_sample_free(self.list_head.as_ptr()); + } + } +} + +struct RustClistModule; + +impl kernel::Module for RustClistModule { + fn init(_module: &'static ThisModule) -> Result { + pr_info!("Rust Clist sample (init)\n"); + + // C creates and populates a list_head with items. + // SAFETY: clist_sample_create allocates, initializes, and populat= es a list. + let c_list_head =3D unsafe { clist_sample_create(6) }; + if c_list_head.is_null() { + pr_err!("Failed to create and populate C list\n"); + return Err(ENOMEM); + } + + // Create the list container (separate from module). + let rust_clist =3D RustClist::new(c_list_head); + + // Demonstrate list operations. + rust_clist.do_iteration(); + + // rust_clist is dropped here, which frees the C list via Drop imp= l. + pr_info!("Rust Clist sample (exit)\n"); + + Ok(RustClistModule {}) + } +} --=20 2.34.1 From nobody Sun Feb 8 07:08:34 2026 Received: from CH4PR04CU002.outbound.protection.outlook.com (mail-northcentralusazon11013023.outbound.protection.outlook.com [40.107.201.23]) (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 CAD4C374ACF; Thu, 30 Oct 2025 19:06:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.201.23 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761851203; cv=fail; b=Lz6AMD4rKN82FP5/6I+wcZZllLaxQo7QEbYbrzkPFoG2EMJ0BSjxS3tN2qlsRkxRR85aQWab9YJVSlm/SCbQBUDtZZiEaRQ0EWjdie+jBtT1vnQjrU+mfi1/389nZwaVXmimtarc0BbHziNcK8n1wK8WyITTCad4oifyuL73Qjo= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761851203; c=relaxed/simple; bh=BUXilFqNHTNTFnCgDMMv66qaq/ob8h6SRTNj0Zjr/Ks=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=BN87hfwgap00RaAOprPZK2YwDoXvdeY5dtDHSvsyF08Ret/CrRyDyyVMQGznu+tq3UWOJOlgTBxDuoNpZkh9ZG7HQHx45xswS1MvmvAG2akmJ1WZzLXSbSz9Zzkdv3YVWu8Sl6wn0TDBPhYVeiePqe7YcjkJj386c72iDHytbME= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=UcYqluqF; arc=fail smtp.client-ip=40.107.201.23 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="UcYqluqF" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=x+mKagy0F1P3WHk0RVYJ3X2r3tVYDTs/BeGchchP2O7uutog/uvCnx1TCRwFUdCWcOXAJwg57Yf9eq+2KstekiWiB3qxQYz0yqFW/exLxwPCDU27lJmlDyxURn1WoNqSWIQvoHLvbg2QYM2fQgTNc25JOKJ5tu70gTnQVluZEcIh3NpHQXUWt3iAq0lttOzV5wE/D781vSQHSesycf4r/uo4JJlHhBFm5A42xTZKQTogSn2aM2hqhUp00esaQu4rW+/6NMdASj/5WpJo29JdwvXGpyBvx8PssD0nTI+3csiv5vPMFI/eBBU4Od+gi6UpOgAhqBdvpbjVm/Q0WOfCTg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=yiVTJHiNiDjnr2NxwkAK6VVz42WDCXEUP9b3e+gcK3Y=; b=Ne0Zhw6MmfSONywTmO2JzLBY2vWCY0oMZSKToze7xRgv7I2XlprRjJMVixY5mVJjYELmHd8bnvRDRQSTnn/ZmJp2b8vcojW149rc/eNlwmMq7bgbxgPB364HIlGYR8aVGWicI5U385CIyockXLziWvcFtj1T7b8ALt0eB61LTa0VOq1tH6XSiaBNTJsl41L02AEDzBVEGSLqeECGrKRePrC4lTx8zZPyDYSpKfrqZWfwA/zVRveDrCijutKWbl+BE5h4XpexBasB52AZM/jI4P7eJmuZeRJpSO7nkTTmtJPU+OY7m7IRsqZI+0LKAWEMjNCmC+bM7V+MspA42u1RFA== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=yiVTJHiNiDjnr2NxwkAK6VVz42WDCXEUP9b3e+gcK3Y=; b=UcYqluqFz3we8cmtBMNRU9sqKbXUtSdxvQjSzdn9OMTlV30UCGpTwRCcWn7SJz2UjqP/0YIuXfdwE9gms2QzIB0R03QBNqab4j38on44pE5Wrs4yxN8iuT+AMUbE5ziwnYs7K2QHgZIFr3uWuAlS+ztCgQOC9CdgDqIwIodHKI+buFVvnga3gD/+asuCxLY9WQ3AKiJPJUSjXpqI9vhET+Pi44CRgbi+rbHF7GyJQymdhS2IRRglED6TDQ9Qe77bMscG4UudCIwRuGS87Vj+oIewS5xqDWSQGURZjLoMsNjNAhy6wKQ/UY7R2uYZYf1oAjHN/kUlb7IUc+CXrZ4yGA== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from SN7PR12MB8059.namprd12.prod.outlook.com (2603:10b6:806:32b::7) by DS5PPFBABE93B01.namprd12.prod.outlook.com (2603:10b6:f:fc00::65f) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9275.14; Thu, 30 Oct 2025 19:06:32 +0000 Received: from SN7PR12MB8059.namprd12.prod.outlook.com ([fe80::4ee2:654e:1fe8:4b91]) by SN7PR12MB8059.namprd12.prod.outlook.com ([fe80::4ee2:654e:1fe8:4b91%2]) with mapi id 15.20.9228.015; Thu, 30 Oct 2025 19:06:32 +0000 From: Joel Fernandes To: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, dri-devel@lists.freedesktop.org, dakr@kernel.org, David Airlie Cc: acourbot@nvidia.com, Alistair Popple , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , bjorn3_gh@protonmail.com, Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , John Hubbard , Joel Fernandes , Timur Tabi , joel@joelfernandes.org, Elle Rhumsaa , Daniel Almeida , Andrea Righi , Philipp Stanner , nouveau@lists.freedesktop.org Subject: [PATCH RFC 3/4] rust: drm: Add DRM buddy allocator bindings Date: Thu, 30 Oct 2025 15:06:12 -0400 Message-Id: <20251030190613.1224287-4-joelagnelf@nvidia.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20251030190613.1224287-1-joelagnelf@nvidia.com> References: <20251030190613.1224287-1-joelagnelf@nvidia.com> Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BL1PR13CA0133.namprd13.prod.outlook.com (2603:10b6:208:2bb::18) To SN7PR12MB8059.namprd12.prod.outlook.com (2603:10b6:806:32b::7) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SN7PR12MB8059:EE_|DS5PPFBABE93B01:EE_ X-MS-Office365-Filtering-Correlation-Id: 7abe587f-a4e9-45b3-d345-08de17e76e5d X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|7416014|1800799024|376014|366016; X-Microsoft-Antispam-Message-Info: =?us-ascii?Q?ZWf7Y/9J/IMP+lnG/YeGMgPKRQ76ncUvuSszILzNtqAqI7xtQu0SS3aYMNj3?= =?us-ascii?Q?YIunZgzjyrPybOUDzBfeY4ZSB39WcvwgUOHDXDmNhxVe7xhuPXiVTH88hVnq?= =?us-ascii?Q?IYBXLOF6uH46vGYkQl47RgLzTbQgcxtpIxBQzEBN0Pm5RbYJtGcY7iiIphUG?= =?us-ascii?Q?zayUnOUA3Fspba7LyslyMaaUtZzubQAW0pYnsRc+CXrw0wBzAb7RVD3qFDW6?= =?us-ascii?Q?JfmFo4IyhckVmHj7dzGzLFoyASKXBuErcQ8mYePGvuAHfULpQBCSspUcYaCw?= =?us-ascii?Q?b0f/QY/z+yjfo7cQLoW58AOiiojWU7IzzxJR3SHifjmGnXHKBDpf1JOb4467?= =?us-ascii?Q?ilVMuK0uln0DJc/qfvzPmMja/a2+uoXxRJV70bikXY5Uj8OqTlhuKsvH9NcB?= =?us-ascii?Q?aMx8HagUnWL2ApLmEQ4wFW5ior+FXdNDxcR4EcaVvgONjSnj/oNOcDX3kEWh?= =?us-ascii?Q?Rv26AfTTxvjc5CfurIbYQnCf4k8k2ZMo3a3E7TAere+y+KeaDXnkoXzoK7gJ?= =?us-ascii?Q?m1fu9ua+aAUFl9nf3xTLjTlU9b3I3h2Fa1vNlLCu0Xy9NcmheVdsCtc7ZCMv?= =?us-ascii?Q?hOSVYYJZy12CpsCwpPvoUspVIO4maocKR736+1r2XHeOJVcys6dzmLdDe8Yt?= =?us-ascii?Q?sGmP6/xecbxd+S40UGwFM3eJqdqXSgVU3HjJgl7U8kRaO9bTXzzzgknYT6tE?= =?us-ascii?Q?ffgb2tzVM+rgN4iuLrNOzIrznxuUTHglCywJyTvoDcCdMSxUSLezQ0cvvs+E?= =?us-ascii?Q?ZlSjMQxbus72dRJPHJHlLI+4KXWK5Ujst34deenPabNrMRNPcVXxlNQnP+t/?= =?us-ascii?Q?27mFhrDG8qDP1npCSyRxfNjZqmMHJzgAQd4m2nQPrgncVmDT9Y1PmT5rpGZ5?= =?us-ascii?Q?DtdtW8VqNERAYb75+KxuQQW2a1IwMTwzoAJF9HX+9j/eCuff8Oc2KQyELM4f?= =?us-ascii?Q?XoNWACVGuWhS/g6XZ0+4TUSFcVESpwgPnv8J8V/Z9YkM4J6nC+mshf1E3Cgp?= =?us-ascii?Q?v600MUmK1COeLli78JG3rLX7JLUhGkoQlbZ+pxXz6HfHRPQuRXglUFooOIZn?= =?us-ascii?Q?a46CvVZ/MYAHTVdVhVk0hlHe6Vcqr5R6Ojo4hsskW5BamNLPibAmtdIJKI+J?= =?us-ascii?Q?yXSRRFLoVm0OWC+px6AUjJ0Hsb+TuLRnWk/RaR7X2OVwGSteCaU5rO7AKIbq?= =?us-ascii?Q?OB2+sD8P4UH0aWY53jnio7wR7tScJKwGPFFw0lk5QMG13H9gJ3k0jK10jyGM?= =?us-ascii?Q?tf/uZ7teeyLAvz8MvUTOSPeLYoWgbUb2KT31fkhcM5bQnooy+i+of5jtbmb+?= =?us-ascii?Q?4spp+PNbdVDrY+zLBIwCTQvL6NbzaR5zVpFKhW7jAuIKxU6iQCNDWSOj7mTf?= =?us-ascii?Q?I65wanQF6nAYf79S2UNpRhy53Nba3BUGCTVRqXwwl42KQvj+cfLyY4Bsyr4e?= =?us-ascii?Q?MvXv4E8PKUBmE5BOvyMtHI94CnS2fkF4?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:SN7PR12MB8059.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(7416014)(1800799024)(376014)(366016);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?dSgbk1r+jRbzAFp0uxlXmlO2CxHsGN341O7YMnKABRbT+rrwnzD0h2W7Q0TJ?= =?us-ascii?Q?J8VrsYPPEWXm6iNliM5+G1sSfkpl2Jf4YfqPwPb5A7CJD2ZuCA3tQCnKBmxx?= =?us-ascii?Q?zFJfGj2uWl5AiHQZz8PVgBkTRuMKDTMW5hWzDu69/JAmIDz7g7rZQFBTf7Jm?= =?us-ascii?Q?s+a9K/LqPGKsrC4ovUnySwYle7KkVe5q7WBj3puCTEP/rMO4a2Ga3fv0CG1P?= =?us-ascii?Q?Fh0boCDWMyftmW4dT6xz+uJ5L2+HbY9JoPyAAxYL69IIBT5xPLMQC+S7n7XT?= =?us-ascii?Q?PyjyaOM1g5Mrx1XFY8Hw2njQHGxA2Uqc7ijvGxHsKG37qZHTPg/jdIkE7fpn?= =?us-ascii?Q?r04j+jWVYKQHomCiit0FqdOE3PhEGs0lOSFEQyWP8YpFPin2I9fxOjUoWVwV?= =?us-ascii?Q?pd3JBWMK79a1iaP2BjMxIUIm1MNc+LGayN+Ss/N372BQj1AW+O/8nWQxvrpr?= =?us-ascii?Q?h/vORXp8Obdj+9zXnfXoFijd3CRwGCYwMfIzfreR8RN8oeoDtIGRG/xxJD2G?= =?us-ascii?Q?avGapw8zJYDp0rGajQSH91opY3bDTITh2bUT/ASQhBT8Qht2mqIuPsoGmrRy?= =?us-ascii?Q?eZwuPIjI6fGuy2grHG1FUTm4W7ZOeYJ6uSoysJCg89kRp3KFNRofl83hhT2/?= =?us-ascii?Q?Y22O3NolJHA/ZqU6ez4Cn6anhb7MaxCfxzd5KUMfWOf1RCPb+VMFEG49Md37?= =?us-ascii?Q?C+64OoWvSTS8OgCA4WET6BoMhteAYUBV82Qmb1pelaU4F4Wz1J12tWPYUnkw?= =?us-ascii?Q?OlTstiUyxzTEYBlZ5wY8aSvk3yWwBwGGrcpPLCHU0JR4E4LkwHgTJABUIYI/?= =?us-ascii?Q?hx7AAn5+YxYzQnZt4b6RhXEK3NFrKkloZg8CEG+Yfvqy0sFZARZ1U/wuSNEe?= =?us-ascii?Q?btAR4hdykjqjQ8sWNEDJqWnyv7UtHApo+nOt2DDFd37pkRDrmXCbFWNMj06Z?= =?us-ascii?Q?MvKKuWnLx0TA7Y8S+t9MkwgJNNGmx72syEEUkkrVdMKMUdhRMjY8aorLa67j?= =?us-ascii?Q?/zi6JCW4HRJ1R6PK6Tcpxyc8H7vAqLEXvkUjIXJhxaI+LLrER/P92r2lPpu0?= =?us-ascii?Q?a4U4/odk+74bdB7DxiNJV82ZDez93H1PoUP6+/jTcOaX8pNvmiCC3UQkVSsn?= =?us-ascii?Q?A6qdraq2xVEgJ6lMcEzRfl0BvUlV8rtvbWzk78G4Ww9lK0UNGafm7Cvxm7wR?= =?us-ascii?Q?tvBZmPzBBsAlR1WqnKa+U6h5Mb+6gG2HnGAtT7BYIGTJ0bPU0ySQtFah14dY?= =?us-ascii?Q?2OfY3tB4xcMXUCcUmcfyA4y03SIA4tcxeEeaJ7mt9eiAFiAfk/Typ7cATYwY?= =?us-ascii?Q?eg6Y3Yda5gVcnfQ+QpykZ/+0ri16m4YvXEMxexj8Si48sUE1BMmOrazUE5WZ?= =?us-ascii?Q?4DbQ3qclas6AWfcIGdxJFqlbPqEcXNwvfeeVmHxysug3Tng3c5Usdr1L0Rkf?= =?us-ascii?Q?sFCjhw+pzauh3j+WkHcltG6jRAZ+TW0PjlSk7AJ0PoEabK34ZkPkPGA9qV8j?= =?us-ascii?Q?0wbCuXoTNDtIjXBmsIj1LbmCsyxeR25RL85qRZMnvxMgcisdjsIevklbSVrT?= =?us-ascii?Q?i26ptVzCSoWKv/u5eJSTDkPg1XqojoI4GuUtS+MU?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 7abe587f-a4e9-45b3-d345-08de17e76e5d X-MS-Exchange-CrossTenant-AuthSource: SN7PR12MB8059.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Oct 2025 19:06:29.1549 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: P+6/SMIOOprH8FvHwK0XM9s2gqJ8Cb9VHE7PasktjYN9fycRXp2+qw1pBiGzT9u/aySt5+Xde+7Ewfh/zxP+Nw== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DS5PPFBABE93B01 Content-Type: text/plain; charset="utf-8" Add safe Rust abstractions over the Linux kernel's DRM buddy allocator for physical memory management. The DRM buddy allocator implements a binary buddy system for useful for GPU physical memory allocation. nova-core will use it for physical memory allocation. Signed-off-by: Joel Fernandes --- rust/bindings/bindings_helper.h | 11 + rust/helpers/drm.c | 23 +- rust/kernel/drm/buddy.rs | 357 ++++++++++++++++++++++++++++++++ rust/kernel/drm/mod.rs | 1 + 4 files changed, 391 insertions(+), 1 deletion(-) create mode 100644 rust/kernel/drm/buddy.rs diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 6b973589a546..747d4c7ef935 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -29,6 +29,7 @@ #include =20 #include +#include #include #include #include @@ -112,6 +113,16 @@ const gfp_t RUST_CONST_HELPER_XA_FLAGS_ALLOC =3D XA_FL= AGS_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; =20 +#if IS_ENABLED(CONFIG_DRM_BUDDY) +const unsigned long RUST_CONST_HELPER_DRM_BUDDY_RANGE_ALLOCATION =3D DRM_B= UDDY_RANGE_ALLOCATION; +const unsigned long RUST_CONST_HELPER_DRM_BUDDY_TOPDOWN_ALLOCATION =3D DRM= _BUDDY_TOPDOWN_ALLOCATION; +const unsigned long RUST_CONST_HELPER_DRM_BUDDY_CONTIGUOUS_ALLOCATION =3D + DRM_BUDDY_CONTIGUOUS_ALLOCATION; +const unsigned long RUST_CONST_HELPER_DRM_BUDDY_CLEAR_ALLOCATION =3D DRM_B= UDDY_CLEAR_ALLOCATION; +const unsigned long RUST_CONST_HELPER_DRM_BUDDY_CLEARED =3D DRM_BUDDY_CLEA= RED; +const unsigned long RUST_CONST_HELPER_DRM_BUDDY_TRIM_DISABLE =3D DRM_BUDDY= _TRIM_DISABLE; +#endif + #if IS_ENABLED(CONFIG_ANDROID_BINDER_IPC_RUST) #include "../../drivers/android/binder/rust_binder.h" #include "../../drivers/android/binder/rust_binder_events.h" diff --git a/rust/helpers/drm.c b/rust/helpers/drm.c index 450b406c6f27..bd8748ade3f5 100644 --- a/rust/helpers/drm.c +++ b/rust/helpers/drm.c @@ -1,5 +1,6 @@ // SPDX-License-Identifier: GPL-2.0 =20 +#include #include #include =20 @@ -20,4 +21,24 @@ __u64 rust_helper_drm_vma_node_offset_addr(struct drm_vm= a_offset_node *node) return drm_vma_node_offset_addr(node); } =20 -#endif +#ifdef CONFIG_DRM_BUDDY + +u64 rust_helper_drm_buddy_block_offset(const struct drm_buddy_block *block) +{ + return drm_buddy_block_offset(block); +} + +unsigned int rust_helper_drm_buddy_block_order(struct drm_buddy_block *blo= ck) +{ + return drm_buddy_block_order(block); +} + +u64 rust_helper_drm_buddy_block_size(struct drm_buddy *mm, + struct drm_buddy_block *block) +{ + return drm_buddy_block_size(mm, block); +} + +#endif /* CONFIG_DRM_BUDDY */ + +#endif /* CONFIG_DRM */ diff --git a/rust/kernel/drm/buddy.rs b/rust/kernel/drm/buddy.rs new file mode 100644 index 000000000000..b1cd23f81838 --- /dev/null +++ b/rust/kernel/drm/buddy.rs @@ -0,0 +1,357 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! DRM buddy allocator bindings. +//! +//! C header: [`include/drm/drm_buddy.h`](srctree/include/drm/drm_buddy.h) +//! +//! This module provides Rust abstractions over the Linux kernel's DRM bud= dy +//! allocator, which implements a binary buddy memory allocation system. +//! +//! The buddy allocator manages a contiguous address space and allocates b= locks +//! in power-of-two sizes. It's commonly used for physical memory manageme= nt. +//! +//! # Examples +//! +//! ```ignore +//! use kernel::{ +//! drm::buddy::{BuddyFlags, DrmBuddy}, +//! prelude::*, +//! sizes::*, // +//! }; +//! +//! let buddy =3D DrmBuddy::new(SZ_1G, SZ_4K)?; +//! let allocated =3D buddy.alloc_blocks( +//! 0, 0, SZ_16M, SZ_4K, +//! BuddyFlags::RANGE_ALLOCATION, +//! GFP_KERNEL, +//! )?; +//! +//! for block in &allocated { +//! // Use block. +//! } +//! // Blocks are automatically freed when `allocated` goes out of scope. +//! ``` + +use crate::{ + alloc::Flags, + bindings, + clist, + container_of, + error::{ + to_result, + Result, // + }, + prelude::KBox, + types::Opaque, // +}; +use core::ptr::NonNull; + +/// Flags for DRM buddy allocator operations. +/// +/// These flags control the allocation behavior of the buddy allocator. +#[derive(Clone, Copy, PartialEq)] +pub struct BuddyFlags(u64); + +impl BuddyFlags { + /// Range-based allocation from start to end addresses. + pub const RANGE_ALLOCATION: BuddyFlags =3D + BuddyFlags(bindings::DRM_BUDDY_RANGE_ALLOCATION as u64); + + /// Allocate from top of address space downward. + pub const TOPDOWN_ALLOCATION: BuddyFlags =3D + BuddyFlags(bindings::DRM_BUDDY_TOPDOWN_ALLOCATION as u64); + + /// Allocate physically contiguous blocks. + pub const CONTIGUOUS_ALLOCATION: BuddyFlags =3D + BuddyFlags(bindings::DRM_BUDDY_CONTIGUOUS_ALLOCATION as u64); + + /// Clear allocated blocks (zero them). + pub const CLEAR_ALLOCATION: BuddyFlags =3D + BuddyFlags(bindings::DRM_BUDDY_CLEAR_ALLOCATION as u64); + + /// Block has been cleared - internal flag. + pub const CLEARED: BuddyFlags =3D BuddyFlags(bindings::DRM_BUDDY_CLEAR= ED as u64); + + /// Disable trimming of partially used blocks. + pub const TRIM_DISABLE: BuddyFlags =3D BuddyFlags(bindings::DRM_BUDDY_= TRIM_DISABLE as u64); + + /// Get raw value for FFI. + pub(crate) fn as_raw(self) -> u64 { + self.0 + } +} + +impl core::ops::BitOr for BuddyFlags { + type Output =3D Self; + + fn bitor(self, rhs: Self) -> Self::Output { + Self(self.0 | rhs.0) + } +} + +/// DRM buddy allocator instance. +/// +/// This structure wraps the C `drm_buddy` allocator. +/// +/// # Safety +/// +/// Not thread-safe. Concurrent alloc/free operations require external +/// synchronization (e.g., wrapping in `Arc>`). +/// +/// # Invariants +/// +/// - `mm` is initialized via `drm_buddy_init()` and remains valid until D= rop. +pub struct DrmBuddy { + mm: Opaque, +} + +impl DrmBuddy { + /// Create a new buddy allocator. + /// + /// Creates a buddy allocator that manages a contiguous address space = of the given + /// size, with the specified minimum allocation unit (chunk_size must = be at least 4KB). + /// + /// # Examples + /// + /// See the complete example in the documentation comments for [`Alloc= atedBlocks`]. + pub fn new(size: usize, chunk_size: usize) -> Result { + // Create buddy allocator with zeroed memory. + let buddy =3D Self { + mm: Opaque::zeroed(), + }; + + // Initialize the C buddy structure. + // SAFETY: buddy.mm points to valid, zeroed memory. + unsafe { + to_result(bindings::drm_buddy_init( + buddy.mm.get(), + size as u64, + chunk_size as u64, + ))?; + } + + Ok(buddy) + } + + /// Get a raw pointer to the underlying C drm_buddy structure. + /// + /// # Safety + /// + /// Caller must ensure the returned pointer is not used after this + /// structure is dropped. + pub unsafe fn as_raw(&self) -> *mut bindings::drm_buddy { + self.mm.get() + } + + /// Get the chunk size (minimum allocation unit). + pub fn chunk_size(&self) -> u64 { + // SAFETY: mm is initialized and valid per struct invariant. + unsafe { (*self.as_raw()).chunk_size } + } + + /// Get the total managed size. + pub fn size(&self) -> u64 { + // SAFETY: mm is initialized and valid per struct invariant. + unsafe { (*self.as_raw()).size } + } + + /// Get the available (free) memory. + pub fn avail(&self) -> u64 { + // SAFETY: mm is initialized and valid per struct invariant. + unsafe { (*self.as_raw()).avail } + } + + /// Allocate blocks from the buddy allocator. + /// + /// Returns an [`AllocatedBlocks`] structure that owns the allocated b= locks and automatically + /// frees them when dropped. Allocation of `list_head` uses the `gfp` = flags passed. + pub fn alloc_blocks( + &self, + start: usize, + end: usize, + size: usize, + min_block_size: usize, + flags: BuddyFlags, + gfp: Flags, + ) -> Result> { + // Allocate list_head on the heap. + let mut list_head =3D KBox::new(bindings::list_head::default(), gf= p)?; + + // SAFETY: list_head is valid and heap-allocated. + unsafe { + bindings::INIT_LIST_HEAD(&mut *list_head as *mut _); + } + + // SAFETY: mm is a valid DrmBuddy object per the type's invariants. + unsafe { + to_result(bindings::drm_buddy_alloc_blocks( + self.as_raw(), + start as u64, + end as u64, + size as u64, + min_block_size as u64, + &mut *list_head as *mut _, + flags.as_raw() as usize, + ))?; + } + + // `list_head` is now the head of a list that contains allocated b= locks + // from C code. The allocated blocks will be automatically freed w= hen + // `AllocatedBlocks` is dropped. + Ok(AllocatedBlocks { + list_head, + buddy: self, + }) + } +} + +impl Drop for DrmBuddy { + fn drop(&mut self) { + // SAFETY: self.mm is initialized and valid. drm_buddy_fini proper= ly + // cleans up all resources. This is called exactly once during Dro= p. + unsafe { + bindings::drm_buddy_fini(self.as_raw()); + } + } +} + +// SAFETY: DrmBuddy can be sent between threads. Caller is responsible for +// ensuring thread-safe access if needed (e.g., via Mutex). +unsafe impl Send for DrmBuddy {} + +/// Allocated blocks from the buddy allocator with automatic cleanup. +/// +/// This structure owns a list of allocated blocks and ensures they are +/// automatically freed when dropped. Blocks may be iterated over and are +/// read-only after allocation (iteration via [`IntoIterator`] and +/// automatic cleanup via [`Drop`] only). To share across threads, wrap +/// in `Arc`. Rust owns the head list head of the +/// allocated blocks; C allocates blocks and links them to the head +/// list head. Clean up of the allocated blocks is handled by C code. +/// +/// # Invariants +/// +/// - `list_head` is an owned, valid, initialized list_head. +/// - `buddy` points to a valid, initialized [`DrmBuddy`]. +pub struct AllocatedBlocks<'a> { + list_head: KBox, + buddy: &'a DrmBuddy, +} + +impl Drop for AllocatedBlocks<'_> { + fn drop(&mut self) { + // Free all blocks automatically when dropped. + // SAFETY: list_head is a valid list of blocks per the type's inva= riants. + unsafe { + bindings::drm_buddy_free_list(self.buddy.as_raw(), &mut *self.= list_head as *mut _, 0); + } + } +} + +impl<'a> AllocatedBlocks<'a> { + /// Check if the block list is empty. + pub fn is_empty(&self) -> bool { + // SAFETY: list_head is a valid list of blocks per the type's inva= riants. + unsafe { clist::list_empty(&*self.list_head as *const _) } + } + + /// Iterate over allocated blocks. + pub fn iter(&self) -> clist::ClistIter<'_, Block> { + // SAFETY: list_head is a valid list of blocks per the type's inva= riants. + clist::iter_list_head::(&*self.list_head) + } +} + +/// Iteration support for allocated blocks. +/// +/// # Examples +/// +/// ```ignore +/// for block in &allocated_blocks { +/// // Use block. +/// } +/// ``` +impl<'a> IntoIterator for &'a AllocatedBlocks<'_> { + type Item =3D Block; + type IntoIter =3D clist::ClistIter<'a, Block>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +/// A DRM buddy block. +/// +/// Wraps a pointer to a C `drm_buddy_block` structure. This is returned +/// from allocation operations and used to free blocks. +/// +/// # Invariants +/// +/// `drm_buddy_block_ptr` points to a valid `drm_buddy_block` managed by t= he buddy allocator. +pub struct Block { + drm_buddy_block_ptr: NonNull, +} + +impl Block { + /// Get the block's offset in the address space. + pub fn offset(&self) -> u64 { + // SAFETY: drm_buddy_block_ptr is valid per the type's invariants. + unsafe { bindings::drm_buddy_block_offset(self.drm_buddy_block_ptr= .as_ptr()) } + } + + /// Get the block order (size =3D chunk_size << order). + pub fn order(&self) -> u32 { + // SAFETY: drm_buddy_block_ptr is valid per the type's invariants. + unsafe { bindings::drm_buddy_block_order(self.drm_buddy_block_ptr.= as_ptr()) } + } + + /// Get the block's size in bytes. + /// + /// Requires the buddy allocator to calculate size from order. + pub fn size(&self, buddy: &DrmBuddy) -> u64 { + // SAFETY: Both pointers are valid per the type's invariants. + unsafe { bindings::drm_buddy_block_size(buddy.as_raw(), self.drm_b= uddy_block_ptr.as_ptr()) } + } + + /// Get a raw pointer to the underlying C block. + /// + /// # Safety + /// + /// Caller must ensure the pointer is not used after the block is free= d. + pub unsafe fn as_ptr(&self) -> *mut bindings::drm_buddy_block { + self.drm_buddy_block_ptr.as_ptr() + } +} + +impl clist::FromListHead for Block { + unsafe fn from_list_head(link: *const bindings::list_head) -> Self { + // SAFETY: link points to a valid list_head embedded in drm_buddy_= block. + // The container_of macro calculates the containing struct pointer. + // We need to account for the union field __bindgen_anon_1.link. + // + // The link is embedded in a union within drm_buddy_block: + // struct drm_buddy_block { + // [...] + // union { + // struct rb_node rb; + // struct list_head link; + // }; + // } + // + // This is why we perform a double container_of calculation: first= to get + // to the union, then to get to the containing drm_buddy_block. + unsafe { + // First get to the union. + let union_ptr =3D container_of!(link, bindings::drm_buddy_bloc= k__bindgen_ty_1, link); + // Then get to the containing drm_buddy_block. + let block_ptr =3D + container_of!(union_ptr, bindings::drm_buddy_block, __bind= gen_anon_1) as *mut _; + Block { + drm_buddy_block_ptr: NonNull::new_unchecked(block_ptr), + } + } + } +} + +// SAFETY: Block is just a pointer wrapper and can be safely sent between = threads. +unsafe impl Send for Block {} diff --git a/rust/kernel/drm/mod.rs b/rust/kernel/drm/mod.rs index 1b82b6945edf..ee173729eac5 100644 --- a/rust/kernel/drm/mod.rs +++ b/rust/kernel/drm/mod.rs @@ -2,6 +2,7 @@ =20 //! DRM subsystem abstractions. =20 +pub mod buddy; pub mod device; pub mod driver; pub mod file; --=20 2.34.1 From nobody Sun Feb 8 07:08:34 2026 Received: from CH4PR04CU002.outbound.protection.outlook.com (mail-northcentralusazon11013023.outbound.protection.outlook.com [40.107.201.23]) (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 0E176374ABD; Thu, 30 Oct 2025 19:06:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=fail smtp.client-ip=40.107.201.23 ARC-Seal: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761851201; cv=fail; b=dIueb1MKN/tNewAHlQHLbSbbMENawZvfKSuoDkDZNGMW1piNw1GU5hhKUWwACmG2LbZWcs2BseNgB9ex3MXBWhH/GjQoKoxx45MUaksofdtwcWhL8rIeWYo+ecIh7dTBQGs7oNtgmuOFEm5KKSeQYFKm7PCPNLB2vQT0i4tCxDA= ARC-Message-Signature: i=2; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1761851201; c=relaxed/simple; bh=fshyvVT/ITkFKpz3DU+UpvD2/P84EaEdYSH72L3DpqE=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: Content-Type:MIME-Version; b=u8k3V2kefmYLmoOqmdoQK8aNHV8gn0jbGXmDvFWM9JumE2dChdDky3CmKboWva0woZqp9isCGwylQ32Cy93L2gQrp+5f+kAkrghL2VWJK1g6nu+pEBsyJHmLDOjGKvqT3/SCFqS7b0gr+aTDZwdbw2pFCOOAiX2deKwIDddlujs= ARC-Authentication-Results: i=2; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com; spf=fail smtp.mailfrom=nvidia.com; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b=s85n3Gbb; arc=fail smtp.client-ip=40.107.201.23 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=nvidia.com Authentication-Results: smtp.subspace.kernel.org; spf=fail smtp.mailfrom=nvidia.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=Nvidia.com header.i=@Nvidia.com header.b="s85n3Gbb" ARC-Seal: i=1; a=rsa-sha256; s=arcselector10001; d=microsoft.com; cv=none; b=ohzp7t+3h/o/bCC/Uk0WTNNDH5H5/3+Dk8NvZ4yDqM8UxvjhVWkNlxIZuYbflLpgVB5QD0lYrbAAt67tyKL2f+M1Ys7m/xmCGNKCEY9Ej4Btt8sanG20QADCRDwxoLUwqqLiyPTn0OQld2Wi6YImPK5AX+S/IeugaAzXltNV4QZwrXzGQSm5RJVsR+LcZXtxkF5Mx1siv+5R4iM5RN9o7bZcbu27EfE/5GBuoGdTW5TScFOLCoxmLzrjmjDkPnELyJjT8MMVDOI7Sxbe593UBMi1kvZq3Dzl+l5uEJLqqgIRaZd4v5Rm9ml8B/iegbwovSWikk6fBO54hbFwrG8MCQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector10001; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=QKodteNH7w/qQblXa9jTro7UQUGCsxy1AI+CLyMuW4A=; b=pl3RqkK3qLIZELZ+KQGLNFmHPaYGoKm+3En+i4BkDTWRf2+7iKAu0rmrcGuZRIN9kJcnyri9QA+Yz7ar9NklcMirHq6x6p6QH727WDjQiyI6RH1jzY8Etu7OG1Uygz+Vk+66MfNVFHYRX59fLzJUzS9vlLGYU1xURVIHDHjpC1hztpCyyNqwzrlWx4g8vy790pj4q7YMCdxklKqVd8FxNl1eNr61sM29rL2kq6I3gS2JqTyRL2QuwQUeH8I1E5H2G/n8qNXUK/6JGLsqT1lP3VJV+osOmFUNVOEQvZN8YfKDeoFkQIXIRrEA/WlUBPPzG35iK0bkgfq9kEgW6LmeIg== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=nvidia.com; dmarc=pass action=none header.from=nvidia.com; dkim=pass header.d=nvidia.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=Nvidia.com; s=selector2; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=QKodteNH7w/qQblXa9jTro7UQUGCsxy1AI+CLyMuW4A=; b=s85n3GbbtetQbxGQHY8fSiBVIrr+YdPVIYHI71p997othE7L1ma8rbsceUKQuxWD5+YllHwhFakj3j+jQk6yXggKh/T0x6A6DcnIEnpQhrtOUEmcnEZL2qk0GEBHUkg6BbnTWuOASMbPZxTz2LVSiSq2SnQz3VeaDOiKbeRwzkUVpYXbDq39CDXgGLfNR/hzSHGcmdNiANkWGILRYAlfDSoQQOOVFCkXt6dnqHce9K6bh3vUT8qhLpUBj7dqr4E0xcXzvLITqFryN/gA1L3kEh+j953qtSkgs9yaUeU0taudhQICrQ1vCN45RNLT7Ih/CYs+cY6h2ygs0wDY4doXEQ== Authentication-Results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=nvidia.com; Received: from SN7PR12MB8059.namprd12.prod.outlook.com (2603:10b6:806:32b::7) by DS5PPFBABE93B01.namprd12.prod.outlook.com (2603:10b6:f:fc00::65f) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.9275.14; Thu, 30 Oct 2025 19:06:33 +0000 Received: from SN7PR12MB8059.namprd12.prod.outlook.com ([fe80::4ee2:654e:1fe8:4b91]) by SN7PR12MB8059.namprd12.prod.outlook.com ([fe80::4ee2:654e:1fe8:4b91%2]) with mapi id 15.20.9228.015; Thu, 30 Oct 2025 19:06:32 +0000 From: Joel Fernandes To: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, dri-devel@lists.freedesktop.org, dakr@kernel.org, David Airlie Cc: acourbot@nvidia.com, Alistair Popple , Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , bjorn3_gh@protonmail.com, Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Simona Vetter , Maarten Lankhorst , Maxime Ripard , Thomas Zimmermann , John Hubbard , Joel Fernandes , Timur Tabi , joel@joelfernandes.org, Elle Rhumsaa , Daniel Almeida , Andrea Righi , Philipp Stanner , nouveau@lists.freedesktop.org Subject: [PATCH RFC 4/4] samples: rust: Add sample demonstrating DRM buddy allocator Date: Thu, 30 Oct 2025 15:06:13 -0400 Message-Id: <20251030190613.1224287-5-joelagnelf@nvidia.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20251030190613.1224287-1-joelagnelf@nvidia.com> References: <20251030190613.1224287-1-joelagnelf@nvidia.com> Content-Transfer-Encoding: quoted-printable X-ClientProxiedBy: BN0PR02CA0047.namprd02.prod.outlook.com (2603:10b6:408:e5::22) To SN7PR12MB8059.namprd12.prod.outlook.com (2603:10b6:806:32b::7) Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-MS-PublicTrafficType: Email X-MS-TrafficTypeDiagnostic: SN7PR12MB8059:EE_|DS5PPFBABE93B01:EE_ X-MS-Office365-Filtering-Correlation-Id: 78faeea4-686e-448a-277a-08de17e76f57 X-MS-Exchange-SenderADCheck: 1 X-MS-Exchange-AntiSpam-Relay: 0 X-Microsoft-Antispam: BCL:0;ARA:13230040|7416014|1800799024|376014|366016; X-Microsoft-Antispam-Message-Info: =?us-ascii?Q?PYYsZ7fTwjKGwT8lrXONnM3BF3YAmSpYZlZbM0ZsA39W/YkJtPm7tuvARelb?= =?us-ascii?Q?+cz+uEd6FiUHVE8vTE8VVhjAmpqNqzmS52MdyFi2g9pvVQqEyEYSGfm64eXe?= =?us-ascii?Q?Po3Uw9RpJy785cghCFNtad1mKn/VGRkmxTHUx60v6laYm+FRE02930cayOjT?= =?us-ascii?Q?GYDC1EpqlEf668vqk1+pvZE2ZYgFrZDIMaLqImshprSk+8ABpULD4vWygGL9?= =?us-ascii?Q?8giakSQSLcr/fOnQ9jS9Uib7yDkqMXLs5qwhJh7dGHfaDkDrAVNor73Aw9nu?= =?us-ascii?Q?6x+4ajrtv91nu/qhHsWT4S86j9/VZ9jOkZTu+H9P0ksy1AV3uIvDRtF6AQva?= =?us-ascii?Q?7P7gCZhYt//hmHMr0egvOSRmAkTOxBA3o8xDu2WHXb6EFVBlEmtRUpKyllxK?= =?us-ascii?Q?iUShaZs30yGLJW56FyExPhRZeEs9c1AYn/bIkrWxbmB1Nt9N8Np3yWF9/vGA?= =?us-ascii?Q?34hW5yYrB8G/jmJRgyWdResKbOrdX8nX4NRTTOQ78bK5MTPNsogODAZUxZHi?= =?us-ascii?Q?S1y4vlLGaeVw/JqZ3LMuCDz9Gx2LjFjLfUUXFEz07EvxGDTl/wKDBj8Qk8D9?= =?us-ascii?Q?ckED9+yLGMK+/tKjYRIwy2r9ygSkl+cDrXm73fjaWHVqsO9DGjfV/qocdTvZ?= =?us-ascii?Q?MvMPpu+8GBjKze7o+uBUOMUNv8baEkSf/ltS4xg2IWG15PnF2hNGbfpfFV47?= =?us-ascii?Q?uxQaO18i2XXdOtqNi4mI8PoYxmbfU3mQNiuroLIwjAguPzsiNakOY2fr6563?= =?us-ascii?Q?AV3gsFDx1LH5HXJtHYbJOT/A7z3bHVG+s86p6tuvqOp9vR1FCjuNPN+zgk4C?= =?us-ascii?Q?pyx+2Sj6tyzPSB6p9WU51XvCfYAmWYeQJNIzfHngQIl4wWnPE/4IXAUMum6P?= =?us-ascii?Q?o4BlbPSpqilZbWdM13xtVksFgj5uVbixaoCQi0EkQMbuDxj+3dtox8T3pvLp?= =?us-ascii?Q?mBsa4yeGVnpWwoXC4eHllIWXaep1QKzdsWOzh6Rkirr7VYedGtrkgOreoRR4?= =?us-ascii?Q?wWO9Ccng1hgSOOSYJjj0cwtiokGBd8hCjRW2onLYDEzY97fjTRPTtZOY5hOE?= =?us-ascii?Q?NhjAaRJe5L3Sbo5frFv25J/vMb+pvr8oiaoAvrVV46mG+MxYi6Bp9ASrAgxt?= =?us-ascii?Q?wFJsrAxYbg8ef03sUIy6SyTtbhYjjzAoazzaX9/OT21MD0P9rmTyrcwf+94O?= =?us-ascii?Q?248grmliLei8DBYhSXl9X4Ey8Ee+5FsoCyjiW5OQ+TfzLKyIz3nhKNOmcuti?= =?us-ascii?Q?pMO+IPyTo3C5vNUjverhlKqqwwe8wJfAXFglzsj2vsm5TL++NyAHCQOA/Ugk?= =?us-ascii?Q?LuOt2EqRfhv+56CAFBnuFP2gseMizHdGbzCyN0ThktzI7hiArS1mrMPz9l7M?= =?us-ascii?Q?VA1kj/m+ciIvjuiGWudVQCPPRqzyNkuB8lbnZ4xU2PARNagXFc89rYUxk3R+?= =?us-ascii?Q?4eBLOoXIsgTADWNXtNvQS60tDR/kLip8?= X-Forefront-Antispam-Report: CIP:255.255.255.255;CTRY:;LANG:en;SCL:1;SRV:;IPV:NLI;SFV:NSPM;H:SN7PR12MB8059.namprd12.prod.outlook.com;PTR:;CAT:NONE;SFS:(13230040)(7416014)(1800799024)(376014)(366016);DIR:OUT;SFP:1101; X-MS-Exchange-AntiSpam-MessageData-ChunkCount: 1 X-MS-Exchange-AntiSpam-MessageData-0: =?us-ascii?Q?dmhqgWBt3sv4J2opAbZmw0SxZW9N7J/u6E3JpzneX0fDgZa1yYh6Xxjj2lK4?= =?us-ascii?Q?GSpYLC3HrD43C1oxzr+S7UOkPSPKRZmjC2UOgwIRG/YWOoqS7gjqb7Mx+3cH?= =?us-ascii?Q?aKr7D3ufApMVrYemWVKAcmGcrbVcH4HEOaDn0K4hRXXnpsFXv1YrBQw41jN5?= =?us-ascii?Q?XBEXDS1xb+VbQjrDhuasNmmYqu9o/Iu4ZL7ucIAY8AqVKECfmp9eQqCwR37A?= =?us-ascii?Q?N5/6zwrudZI9kz6ctonLDNjQWQt6/oghpDTLADAhHe5t6Ke75M6TqCQYxBkq?= =?us-ascii?Q?yd2c48et3iG74edPe2oAePVotWqb3xKekm8ACZUIYLwCZpWqEXiOYMOfnhF6?= =?us-ascii?Q?r4sX/8s9opIL8aiPSlyJq4F34V91eB6+VX7eTeUJGwUs2e68RYK3orJwY8PD?= =?us-ascii?Q?ZDeZgUUilu18RwM93jYzcNirlVY+AvBxO9uOG6V/P017V7g8wJMjpBsX6ZA9?= =?us-ascii?Q?hpP6bwQcJGgvYqFmNtuRbdKSo27fWxl63HLJmDprie2XWywFI02N5R7fKnDB?= =?us-ascii?Q?7JaRwxOefTtrc9yHyTVjwEKhcXAVAF8sPS6QOdhcT8I3mpKZnEUVPcifOaIZ?= =?us-ascii?Q?indSire/qRnUIHGiHIKrGKfluOa13iQ/oDB39B6GxG+27HBO4Qy+XNFjuAvX?= =?us-ascii?Q?QbbAFSeEINTOdk6BN1jHY8KZ1AL14krvvrLMnEQmZs2ane+zTsfViSfPPZFM?= =?us-ascii?Q?/AUBkGPGfgzScOpn5gY1KFAolX1zV08iZ0XOb0C2Jvu5s2gXbtcusvzZhrGV?= =?us-ascii?Q?sQKgdpoc1Fg4osO0W1LHSmlMvUgsJ0ckxa3vznYmaVXoqzlrhZcLTJr9w/eP?= =?us-ascii?Q?upxDoRXnGCPd7p0khISSEKdhpqPYqwFJmM16G6ZSKqhYcTniN+Umf+hTBUvc?= =?us-ascii?Q?C/6GmWyg4GORy6yG2odEGnbVrWiBoCms4hS4+OfrnFvpLmRMxME3cKd2KXLF?= =?us-ascii?Q?b0MRv6A549OB55rsazZPikN40wfSNFKrqz/n/z+VJpq647xAqt2iF+FPPrXd?= =?us-ascii?Q?64/bUdoIROVVtKvZAOgHAWoNgm+jjoneZwCtxe9MLhPjrFhZpYdUO6GVeGx1?= =?us-ascii?Q?MWSg7Q+CcZsRlc6VRrefadzhpkxy7gUUhj1SugQylvOCGHQIQYWC+xwsRRqW?= =?us-ascii?Q?mwgANVSqfAHClqpUQKfq9IiVgCPsHq62AJyX+ZgXvYKjpeU2NmoyEOsT1bSK?= =?us-ascii?Q?IvdkuMdGqB4Hhp6Hgqphahvk7Wa2axSJDHB0xP9NKGuUpMDq9Fr+AzYOiQk8?= =?us-ascii?Q?tSnFd26CBgv1jruUHI8OPaHS7mLF0c8WAMhBWv56gw14ccv/ilMXnsw7YU+0?= =?us-ascii?Q?4gc/NAnYTIzGwd3wudEBN5S9vGtVnUwRPGkhCQvjXrwQjuhD3/6PsYzqHnal?= =?us-ascii?Q?XmGRPVnBi4E4SmruH5N+L1p+fHpVP9uIRdw6AhVczShPEDlRyWkBEwLv+F8C?= =?us-ascii?Q?U4GK3KR2MCuJN15xvoOTHvPG4kepdmuuD8jt/pROTPGknsObTXQIDHcunU+u?= =?us-ascii?Q?UD2MrHrXFNaJuMllpk1GOvti7++ICJCl9zHY2GrTXUJPkw5rLnjLwygX2hRF?= =?us-ascii?Q?prIIES/xzKDynrZSM4XcYFuxfOWmSBWXsFfezOf8?= X-OriginatorOrg: Nvidia.com X-MS-Exchange-CrossTenant-Network-Message-Id: 78faeea4-686e-448a-277a-08de17e76f57 X-MS-Exchange-CrossTenant-AuthSource: SN7PR12MB8059.namprd12.prod.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Internal X-MS-Exchange-CrossTenant-OriginalArrivalTime: 30 Oct 2025 19:06:30.7459 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 43083d15-7273-40c1-b7db-39efd9ccc17a X-MS-Exchange-CrossTenant-MailboxType: HOSTED X-MS-Exchange-CrossTenant-UserPrincipalName: MW9jvN3H4NQVG2pNCQpjtP+d5n9qr/jeXQwZD68kk1PthwdKqxoXvYUiqz5YKFx1kAygaRc0aShJovayWIfP8w== X-MS-Exchange-Transport-CrossTenantHeadersStamped: DS5PPFBABE93B01 Content-Type: text/plain; charset="utf-8" Demonstrates usage of the DRM buddy allocator bindings through a simple test module that initializes the allocator, performs allocations, and prints information about the allocated blocks. Signed-off-by: Joel Fernandes --- samples/rust/Kconfig | 14 +++++ samples/rust/Makefile | 1 + samples/rust/rust_drm_buddy.rs | 106 +++++++++++++++++++++++++++++++++ 3 files changed, 121 insertions(+) create mode 100644 samples/rust/rust_drm_buddy.rs diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig index b45631e2593c..8ccb4064ba91 100644 --- a/samples/rust/Kconfig +++ b/samples/rust/Kconfig @@ -21,6 +21,20 @@ config SAMPLE_RUST_CLIST =20 If unsure, say N. =20 +config SAMPLE_RUST_DRM_BUDDY + tristate "DRM buddy allocator sample" + depends on DRM_BUDDY + help + This option builds the Rust DRM buddy allocator sample. + + The sample demonstrates using the DRM buddy allocator bindings + to allocate and free memory blocks. + + To compile this as a module, choose M here: + the module will be called rust_drm_buddy. + + If unsure, say N. + config SAMPLE_RUST_CONFIGFS tristate "Configfs sample" depends on CONFIGFS_FS diff --git a/samples/rust/Makefile b/samples/rust/Makefile index f8899c0df762..a56204ee4e96 100644 --- a/samples/rust/Makefile +++ b/samples/rust/Makefile @@ -2,6 +2,7 @@ ccflags-y +=3D -I$(src) # needed for trace events =20 obj-$(CONFIG_SAMPLE_RUST_CLIST) +=3D rust_clist.o +obj-$(CONFIG_SAMPLE_RUST_DRM_BUDDY) +=3D rust_drm_buddy.o obj-$(CONFIG_SAMPLE_RUST_MINIMAL) +=3D rust_minimal.o obj-$(CONFIG_SAMPLE_RUST_MISC_DEVICE) +=3D rust_misc_device.o obj-$(CONFIG_SAMPLE_RUST_PRINT) +=3D rust_print.o diff --git a/samples/rust/rust_drm_buddy.rs b/samples/rust/rust_drm_buddy.rs new file mode 100644 index 000000000000..96907bc19243 --- /dev/null +++ b/samples/rust/rust_drm_buddy.rs @@ -0,0 +1,106 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Rust DRM buddy allocator sample. +//! +//! This sample demonstrates using the DRM buddy allocator from Rust. + +use kernel::{ + drm::buddy::{ + BuddyFlags, + DrmBuddy, // + }, + prelude::*, + sizes::*, // +}; + +module! { + type: RustDrmBuddySample, + name: "rust_drm_buddy", + authors: ["Joel Fernandes"], + description: "DRM buddy allocator sample", + license: "GPL", +} + +struct RustDrmBuddySample; + +impl kernel::Module for RustDrmBuddySample { + fn init(_module: &'static ThisModule) -> Result { + // Create a buddy allocator managing 1GB with 4KB chunks. + let buddy =3D DrmBuddy::new(SZ_1G, SZ_4K)?; + + pr_info!("=3D=3D=3D Test 1: Single 16MB block =3D=3D=3D\n"); + let allocated =3D buddy.alloc_blocks( + 0, + 0, + SZ_16M, + SZ_4K, + BuddyFlags::RANGE_ALLOCATION, + GFP_KERNEL, + )?; + + let mut count =3D 0; + for block in &allocated { + pr_info!( + " Block {}: offset=3D0x{:x}, order=3D{}, size=3D{}\n", + count, + block.offset(), + block.order(), + block.size(&buddy) + ); + count +=3D 1; + } + pr_info!(" Total: {} blocks\n", count); + drop(allocated); + + pr_info!("=3D=3D=3D Test 2: Three 4MB blocks =3D=3D=3D\n"); + let allocated =3D buddy.alloc_blocks( + 0, + 0, + SZ_4M * 3, + SZ_4K, + BuddyFlags::RANGE_ALLOCATION, + GFP_KERNEL, + )?; + + count =3D 0; + for block in &allocated { + pr_info!( + " Block {}: offset=3D0x{:x}, order=3D{}, size=3D{}\n", + count, + block.offset(), + block.order(), + block.size(&buddy) + ); + count +=3D 1; + } + pr_info!(" Total: {} blocks\n", count); + drop(allocated); + + pr_info!("=3D=3D=3D Test 3: Two 8MB blocks =3D=3D=3D\n"); + let allocated =3D buddy.alloc_blocks( + 0, + 0, + SZ_8M * 2, + SZ_4K, + BuddyFlags::RANGE_ALLOCATION, + GFP_KERNEL, + )?; + + count =3D 0; + for block in &allocated { + pr_info!( + " Block {}: offset=3D0x{:x}, order=3D{}, size=3D{}\n", + count, + block.offset(), + block.order(), + block.size(&buddy) + ); + count +=3D 1; + } + pr_info!(" Total: {} blocks\n", count); + + pr_info!("=3D=3D=3D All tests passed! =3D=3D=3D\n"); + + Ok(RustDrmBuddySample {}) + } +} --=20 2.34.1