From nobody Sat Feb 7 15:12:40 2026 Received: from mail-pg1-f201.google.com (mail-pg1-f201.google.com [209.85.215.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A84DE259C9B for ; Tue, 29 Apr 2025 23:15:59 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745968561; cv=none; b=lhiDUWFSZ2XdyhRjVtYQDcI6M3Ye+BYxYPMp+wlFD8hUQn0w+gAhYT+4twOQLWaXL9Gr2ErxEr1iG+A7PIHJECoWX2FWP6KMMpTXVjk4pqgLxAeAxhAdBHjvIXlNiidwM5dmQWqusb3+JcU2D82SI4762DBKkWpLzCFqJL0yEno= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745968561; c=relaxed/simple; bh=5x0e5QBv1Z4ozrUpH5qQ8gzEs1i//XcfEzkGBpTPNY0=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=O+ZUyJtypT8YWjHZDKhBGZMj3rmMnIwNFxVvTH7uPuj7fW+Uy1PtQJCXxxAkGgnlMcVtueAlxbBk61cksaXVPbsTu93kBIFgghhYqdXKNbuiGiH7kOpIgSlE6n5ZKL9eiRn6lrCSY21eMpwp19sbgeoXSkBdL4thokwEYIeb3dE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--mmaurer.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=sCSqsRla; arc=none smtp.client-ip=209.85.215.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--mmaurer.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="sCSqsRla" Received: by mail-pg1-f201.google.com with SMTP id 41be03b00d2f7-af59547f55bso3606767a12.0 for ; Tue, 29 Apr 2025 16:15:59 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1745968559; x=1746573359; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=0NTGxWn82aDeVJrvCw0EHsDFY/VYn1O9kb+DYv5wee8=; b=sCSqsRlaxonR2PUiMpKLqaBUz+iE6mYC5p2FKPaABzBMWdTN5ZDd7OX3OLnL6BcSko T59iOLfMrpGDr1pLY0vtX/anTTVOizwvF4evYwsMZ6D0+6qUWYZi/YFUtbBNUn+YfUQp 051hy/YcOgcoYiXZPD2/zIIr6Dhhr9BXMrhaMEW2Eo7oWopch71esVf0QkKomPq/ORnE EjkqImJqBCOYi8TLTMo+KPDabEKvTz27p3cLD9z8zooD9Ua5b7B28C6x71uTn5Z79dSZ AOy4ZtNWI0ICZSENpDbQkiPmssz6tu+v5Er+enYMwOhwiKC9Ls5VDDHfDiF7yQ8L9wmk jSsg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1745968559; x=1746573359; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=0NTGxWn82aDeVJrvCw0EHsDFY/VYn1O9kb+DYv5wee8=; b=ItnPmsrkxtBrK7CrJERYp18EpFutzBSCPHn2gL6xtNiTutygtXUZyJNKg9BGo2N3Ck 8P45DgaaW2oAOENptGQd6f2qNUbW1QAHRVKoKlXe5m11IM6tdFfnnPxhtVg9mB5ZfTZ9 fvQzOMqJfgsRZac7tWiyXV6Y+KSxmGO3ER14p1A/7ZeclCL2eqOfnQ6+mDCq6UlFh5Y1 vJb3X69kWcJVrEbwsIcd3mm/qfFR4aJ0qSUlIDZL4jtCaguCmhmI8w0rLplkcC8OkjTq 21+PGwI0McEzq1AUNZN9oXZRkVLRFuEaTgyEespg2mb7qpB4Y2AOEMCdvIsLKdivPta+ YEoQ== X-Gm-Message-State: AOJu0YxjbmI/pj0d/y+hQtaeK59pqpTcxTPIBO0FQQb09W/TaiZI18xO l4+ppFKn7OMcSbAY4d1nh00AQmkKqvr0MMjA0gbpsWD3cLid5JDiBnHKKF0CmDjbJBVEoDrO5AF ypLbRig== X-Google-Smtp-Source: AGHT+IEbMTQYfSqEHs3EurYngEiO9J68LRQDBTFBMc7unXnAgKve3i6odjKua0/2N/5RRPFOwqIOiWCULDg1 X-Received: from pgbcr13.prod.google.com ([2002:a05:6a02:410d:b0:af2:681:e27a]) (user=mmaurer job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a21:3297:b0:1f3:41d5:65f6 with SMTP id adf61e73a8af0-20aa4381202mr626913637.32.1745968558968; Tue, 29 Apr 2025 16:15:58 -0700 (PDT) Date: Tue, 29 Apr 2025 23:15:55 +0000 In-Reply-To: <20250429-debugfs-rust-v1-0-6b6e7cb7929f@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250429-debugfs-rust-v1-0-6b6e7cb7929f@google.com> X-Developer-Key: i=mmaurer@google.com; a=ed25519; pk=2Ezhl7+fEjTOMVFpplDeak2AdQ8cjJieLRVJdNzrW+E= X-Developer-Signature: v=1; a=ed25519-sha256; t=1745968555; l=6559; i=mmaurer@google.com; s=20250429; h=from:subject:message-id; bh=5x0e5QBv1Z4ozrUpH5qQ8gzEs1i//XcfEzkGBpTPNY0=; b=fSH2M0CgACUVXBOGPZE6ztg7TYQ2YvdGv3AyPgLdSDgn6pLTo9IvUJsnOVmc6noh4sMoCzL2b ZpQwJrK32YRCspRwdgxI+Ux8QIPfbPMSilygjC5ZeYH2PU0hMTPFzTl X-Mailer: b4 0.14.2 Message-ID: <20250429-debugfs-rust-v1-1-6b6e7cb7929f@google.com> Subject: [PATCH 1/8] rust: debugfs: Bind DebugFS directory creation From: Matthew Maurer To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Greg Kroah-Hartman , "Rafael J. Wysocki" , Sami Tolvanen Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, Matthew Maurer Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable The basic API relies on `dput` to prevent leaks. Use of `debugfs_remove` is delayed until the more full-featured API, because we need to avoid the user having an reference to a dir that is recursively removed. Signed-off-by: Matthew Maurer --- MAINTAINERS | 1 + rust/bindings/bindings_helper.h | 1 + rust/helpers/dcache.c | 12 +++++ rust/helpers/helpers.c | 1 + rust/kernel/debugfs.rs | 100 ++++++++++++++++++++++++++++++++++++= ++++ rust/kernel/lib.rs | 1 + 6 files changed, 116 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 906881b6c5cb6ff743e13b251873b89138c69a1c..a3b835e427b083a4ddd690d9e77= 39851f0af47ae 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7271,6 +7271,7 @@ F: include/linux/kobj* F: include/linux/property.h F: include/linux/sysfs.h F: lib/kobj* +F: rust/kernel/debugfs.rs F: rust/kernel/device.rs F: rust/kernel/device_id.rs F: rust/kernel/devres.rs diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 8a2add69e5d66d1c2ebed9d2c950380e61c48842..787f928467faabd02a7f3cf0413= 78fac856c4f89 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/helpers/dcache.c b/rust/helpers/dcache.c new file mode 100644 index 0000000000000000000000000000000000000000..2396cdaa89a95a2be69fd84ec20= 5e0f5f1b63f0c --- /dev/null +++ b/rust/helpers/dcache.c @@ -0,0 +1,12 @@ +// SPDX-License-Identifier: GPL-2.0 + +/* + * Copyright (C) 2025 Google LLC. + */ + +#include + +struct dentry *rust_helper_dget(struct dentry *d) +{ + return dget(d); +} diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c index f34320e6d1f2fb56cc151ee2ffe5d331713fd36a..95f486c1175191483297b7140b9= 9f1aa364c081c 100644 --- a/rust/helpers/helpers.c +++ b/rust/helpers/helpers.c @@ -15,6 +15,7 @@ #include "cpumask.c" #include "cred.c" #include "device.c" +#include "dcache.c" #include "dma.c" #include "err.c" #include "fs.c" diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs new file mode 100644 index 0000000000000000000000000000000000000000..4d06cce7099607f95b684bad329= f791a815d3e86 --- /dev/null +++ b/rust/kernel/debugfs.rs @@ -0,0 +1,100 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +//! DebugFS Abstraction +//! +//! C header: [`include/linux/debugfs.h`](srctree/include/linux/debugfs.h) + +use crate::error::{from_err_ptr, Result}; +use crate::str::CStr; +use crate::types::{ARef, AlwaysRefCounted, Opaque}; +use core::ptr::NonNull; + +/// Handle to a DebugFS directory. +pub struct Dir { + inner: Opaque, +} + +// SAFETY: Dir is just a `dentry` under the hood, which the API promises c= an be transferred +// between threads. +unsafe impl Send for Dir {} + +// SAFETY: All the native functions we re-export use interior locking, and= the contents of the +// struct are opaque to Rust. +unsafe impl Sync for Dir {} + +// SAFETY: Dir is actually `dentry`, and dget/dput are the reference count= ing functions +// for it. +unsafe impl AlwaysRefCounted for Dir { + #[inline] + fn inc_ref(&self) { + // SAFETY: Since we have a reference to the directory, + // it's live, so it's safe to call dget on it. + unsafe { + kernel::bindings::dget(self.as_ptr()); + } + } + #[inline] + unsafe fn dec_ref(obj: NonNull) { + // SAFETY: By the caller precondition on the trait, we know that t= he caller has a reference + // count to the object. + unsafe { + kernel::bindings::dput(obj.cast().as_ptr()); + } + } +} + +impl Dir { + /// Create a new directory in DebugFS. If `parent` is [`None`], it wil= l be created at the root. + /// + /// # Examples + /// + /// ``` + /// # use kernel::c_str; + /// # use kernel::debugfs::Dir; + /// { + /// let dir =3D Dir::new(c_str!("my_debug_dir"), None)?; + /// // The directory will exist in DebugFS here. + /// } + /// // The directory will no longer exist in DebugFS here. + /// # Ok::<(), Error>(()) + /// ``` + /// + /// ``` + /// # use kernel::c_str; + /// # use kernel::debugfs::Dir; + /// let parent =3D Dir::new(c_str!("parent"), None)?; + /// let child =3D Dir::new(c_str!("child"), Some(&parent))?; + /// // parent/child exists in DebugFS here. + /// drop(parent); + /// // The child dentry is still valid here, but DebugFS will have nei= ther directory. + /// # Ok::<(), Error>(()) + /// ``` + pub fn new(name: &CStr, parent: Option<&Self>) -> Result> { + let parent_ptr =3D match parent { + Some(parent) =3D> parent.as_ptr(), + None =3D> core::ptr::null_mut(), + }; + // SAFETY: + // * name argument points to a null terminated string that lives a= cross the call, by + // invariants of &CStr + // * If parent is None, parent accepts null pointers to mean creat= e at root + // * If parent is Some, parent accepts live dentry debugfs pointers + // * `debugfs_create_dir` either returns an error code or a legal = `dentry` pointer, + // so we can call `NonNull::new_unchecked`. + let dir =3D unsafe { + NonNull::new_unchecked(from_err_ptr(kernel::bindings::debugfs_= create_dir( + name.as_char_ptr(), + parent_ptr, + ))?) + }; + // SAFETY: Dir is a transparent wrapper for an Opaque, and= we received a live + // owning dentry from `debugfs_create_dir`, so we can wrap it in a= n ARef + Ok(unsafe { ARef::from_raw(dir.cast()) }) + } + + fn as_ptr(&self) -> *mut bindings::dentry { + self.inner.get() + } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index c3762e80b314316b4b0cee3bfd9442f8f0510b91..86f6055b828d5f711578293d891= 6a517f2436977 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -45,6 +45,7 @@ #[doc(hidden)] pub mod build_assert; pub mod cred; +pub mod debugfs; pub mod device; pub mod device_id; pub mod devres; --=20 2.49.0.901.g37484f566f-goog From nobody Sat Feb 7 15:12:40 2026 Received: from mail-pf1-f201.google.com (mail-pf1-f201.google.com [209.85.210.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 079FA2DCB42 for ; Tue, 29 Apr 2025 23:16:00 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745968563; cv=none; b=gmiW30s6fgzbCLHNb8E4Yd0XAP/0A5XpTz0X1VQ1HxYm/eC1EJVbuBaY2Cbm5rU9nT96Mmyc8w+NfhiRvrb3XxmFJkbdrMSS7f7pFtGmjhh+Ykp5l7KOdgqtQ+4W5v+tK7VfG6qTVU52Tyl4LQc3aKL9aANYencISXmMrvWuiDw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745968563; c=relaxed/simple; bh=ue0hOorN/lBrLGmWDge6K1btfvMk7UJK9JMIiMBYIK8=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=V7LLIhBqhMOeGIWfzydlXNreKtUu4UfwGx3GhbQRvOYlaU35n3fEtnpSRvEpX2kr5FDMVJ1t5xUUiPiGKs2RVl8CyKswrbu4Qk28SUeQ2A25EVWZbZzZFYro7w4DKO3Q2NplODbpEeZ7YvW9vqeN8tbmxsYO21wpzxVFK6hxxT8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--mmaurer.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=NbimgP2p; arc=none smtp.client-ip=209.85.210.201 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--mmaurer.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="NbimgP2p" Received: by mail-pf1-f201.google.com with SMTP id d2e1a72fcca58-736c0306242so8696742b3a.1 for ; Tue, 29 Apr 2025 16:16:00 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1745968560; x=1746573360; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=HpFfzO6TkqksuGg6acaZEinI1XWu5p2UJLgjV+ZSwZg=; b=NbimgP2piuBJQoQLHN50X8Zn1ImSjH4VKL1gOWWRRTfoSGT4ISa4pH6paC7/u56gDj MFWWrmxoS4LJ+xa1SzakiERijEfdQPISzVyW6opOf4fkLqLLP2xuwXBuC2u9Syhh1La5 xHAePPZPF6dOfE/dbAqiX6UTRIMYfgwFasanrhxKYQS0pcE+ExRJD5TV/+5aTuC4tjAy dSc4VVBf+oZPKAHRKI5zwPOhd0XQPDnzjo3Dpou3dzHQJIxqC1ip7w9nqhW4BQJbWAX5 PAvHqY3DPFjDV1tdEYCVRGJ3IMfiSE44ivjcBqW8At3jsef4p7h+szA7QKq0b/N2gxJb tp6Q== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1745968560; x=1746573360; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=HpFfzO6TkqksuGg6acaZEinI1XWu5p2UJLgjV+ZSwZg=; b=dnr/vvA0BNQsEiHQIcRAclo099lEv2zU5HCZYw59D4nWO6557RpB1Y2Oe5nF7hRbzg 7JVS/I4X2gSjFCbOjVpyuEjtN7oVLytDrWDwDGcKA1Dyc6IXcV6XqvLVR7X9E0FO12ZA k/pNJJ9d3m5nSLvxd17svO5LM8NUqE4WAQzFaqHsTYH+kInrhJJX1atdZtPn/28aXAHV OugjI60XpRLxmEy6LDadSOLGTWWyBOAuDHh1Sdw8hu8GobXj21nRNxppluZdiGK4nF9P yL/clhNx+q6yRpggHCLp+h9phThf3Re7/Fx8UeHdnmRjfqpNs5JlcR7j7Ss4ZHD3mLyJ iQBQ== X-Gm-Message-State: AOJu0YynnY8eOQIqjESRD2l/1Yk3XupQHt+sHM9SghXFw9H6oLx8jtK6 fvwlPhlYFj24i22NVP5ie5H5kzIG6RdknebG89VwHhWJ2G2TKSsRst7D16SoY2FjgY+011m0yqK Z0gbPiA== X-Google-Smtp-Source: AGHT+IHfHu0YEkExrKPxqPuNXPBGg3USm3tiUXWoyqewu1bJ4vyzOuz0sLtHIKC3mRAcazOTNmkCmVL3RpZP X-Received: from pffn17.prod.google.com ([2002:a62:e511:0:b0:73e:655:5bee]) (user=mmaurer job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:3924:b0:736:34a2:8a18 with SMTP id d2e1a72fcca58-7403a836556mr619744b3a.24.1745968560313; Tue, 29 Apr 2025 16:16:00 -0700 (PDT) Date: Tue, 29 Apr 2025 23:15:56 +0000 In-Reply-To: <20250429-debugfs-rust-v1-0-6b6e7cb7929f@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250429-debugfs-rust-v1-0-6b6e7cb7929f@google.com> X-Developer-Key: i=mmaurer@google.com; a=ed25519; pk=2Ezhl7+fEjTOMVFpplDeak2AdQ8cjJieLRVJdNzrW+E= X-Developer-Signature: v=1; a=ed25519-sha256; t=1745968555; l=5607; i=mmaurer@google.com; s=20250429; h=from:subject:message-id; bh=ue0hOorN/lBrLGmWDge6K1btfvMk7UJK9JMIiMBYIK8=; b=atZwyn2XsJyagBMkk9xDo3PNR4E2kNEq+cy4bu1OnFWo92rLAFQhRddioEiv/A7OKbrHAg1Ep Kj0EOw7qw4qDRXKhIrSyRZJaPzBktZie0FtGjch7XNMHC+4MAyT/zFl X-Mailer: b4 0.14.2 Message-ID: <20250429-debugfs-rust-v1-2-6b6e7cb7929f@google.com> Subject: [PATCH 2/8] rust: debugfs: Bind file creation for long-lived Display From: Matthew Maurer To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Greg Kroah-Hartman , "Rafael J. Wysocki" , Sami Tolvanen Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, Matthew Maurer Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Allows creation of files for references that live forever and lack metadata through the `Display` implementation. The reference must live forever because the corresponding file is reference counted, so there's no way to say the lifetime outlives it otherwise. This restriction will be relaxed later in the series through use of `debugfs_remove`. The `Display` implementation is used because `seq_printf` needs to route through `%pA`, which in turn routes through Arguments. A more generic API is provided later in the series. Signed-off-by: Matthew Maurer --- rust/kernel/debugfs.rs | 94 ++++++++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 94 insertions(+) diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs index 4d06cce7099607f95b684bad329f791a815d3e86..b20df5fce692b3047c804f7ad5a= f90fc4248979b 100644 --- a/rust/kernel/debugfs.rs +++ b/rust/kernel/debugfs.rs @@ -7,8 +7,11 @@ //! C header: [`include/linux/debugfs.h`](srctree/include/linux/debugfs.h) =20 use crate::error::{from_err_ptr, Result}; +use crate::seq_file::SeqFile; +use crate::seq_print; use crate::str::CStr; use crate::types::{ARef, AlwaysRefCounted, Opaque}; +use core::fmt::Display; use core::ptr::NonNull; =20 /// Handle to a DebugFS directory. @@ -97,4 +100,95 @@ pub fn new(name: &CStr, parent: Option<&Self>) -> Resul= t> { fn as_ptr(&self) -> *mut bindings::dentry { self.inner.get() } + + /// Create a file in a DebugFS directory with the provided name, and c= ontents from invoking + /// [`Display::fmt`] on the provided reference. + /// + /// # Example + /// + /// ``` + /// # use kernel::c_str; + /// # use kernel::debugfs::Dir; + /// let dir =3D Dir::new(c_str!("my_debugfs_dir"), None)?; + /// let file =3D dir.display_file(c_str!("foo"), &200)?; + /// # Ok::<(), Error>(()) + /// ``` + pub fn display_file( + &self, + name: &CStr, + data: &'static T, + ) -> Result> { + // SAFETY: + // * `name` is a NUL-terminated C string, living across the call, = by CStr invariant + // * `parent` is a live dentry since we have a reference to it + // * `vtable` is all stock `seq_file` implementations except for `= open`. + // `open`'s only requirement beyond what is provided to all open= functions is that the + // inode's data pointer must point to a `T` that will outlive it= , which we know because + // we have a static reference. + // * debugfs_create_file_full either returns an error code or a le= gal dentry pointer, so + // `NonNull::new_unchecked` is safe here. + let ptr =3D unsafe { + NonNull::new_unchecked(from_err_ptr(kernel::bindings::debugfs_= create_file_full( + name.as_char_ptr(), + 0444, + self.as_ptr(), + data as *const _ as *mut _, + core::ptr::null(), + &::VTABLE, + ))?) + }; + // SAFETY: Dir is a transparent wrapper for an Opaque, and= we received a live + // owning dentry from debugfs_create_dir, so we can wrap it in an = ARef + Ok(unsafe { ARef::from_raw(ptr.cast()) }) + } +} + +/// Implements `open` for `file_operations` via `single_open` to fill out = a `seq_file` +/// +/// # Safety +/// * inode's private pointer must point to a value of type T which will o= utlive the inode and will +/// not be mutated during this call +/// * file must point to a live, not-yet-initialized file object +unsafe extern "C" fn display_open( + inode: *mut kernel::bindings::inode, + file: *mut kernel::bindings::file, +) -> i32 { + // SAFETY: + // * file is acceptable by caller precondition + // * print_act will be called on a seq_file with private data set to t= he third argument, so we + // meet its safety requirements + // * The data pointer passed in the third argument is a valid T pointe= r that outlives this call + // by caller preconditions + unsafe { kernel::bindings::single_open(file, Some(display_act::), (= *inode).i_private) } } + +/// Prints private data stashed in a seq_file to that seq file +// # Safety +// * seq must point to a live seq_file whose private data is a live pointe= r to a T which is not +// being mutated. +unsafe extern "C" fn display_act( + seq: *mut kernel::bindings::seq_file, + _: *mut core::ffi::c_void, +) -> i32 { + // SAFETY: By caller precondition, this pointer is live, points to a v= alue of type T, and is + // not being mutated. + let data =3D unsafe { &*((*seq).private as *mut T) }; + // SAFETY: By caller precondition, seq_file points to a live seq_file,= so we can lift it + let seq_file =3D unsafe { SeqFile::from_raw(seq) }; + seq_print!(seq_file, "{}", data); + 0 +} + +// Work around lack of generic const items +trait DisplayFile: Display + Sized { + const VTABLE: kernel::bindings::file_operations =3D kernel::bindings::= file_operations { + read: Some(kernel::bindings::seq_read), + llseek: Some(kernel::bindings::seq_lseek), + release: Some(kernel::bindings::single_release), + open: Some(display_open:: as _), + // SAFETY: file_operations supports zeroes in all fields + ..unsafe { core::mem::zeroed() } + }; +} + +impl DisplayFile for T {} --=20 2.49.0.901.g37484f566f-goog From nobody Sat Feb 7 15:12:40 2026 Received: from mail-pl1-f202.google.com (mail-pl1-f202.google.com [209.85.214.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BBFCE2DCB65 for ; Tue, 29 Apr 2025 23:16:02 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.214.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745968564; cv=none; b=qG0H0uiNlUiLOXwu8+q8ADHzdb38gF2tMaSkaeq23B1xf2hXxaDodxLpvmmaqhwdDDF15GJq1B+io0xP8BqPS/1Z66dh9p9w9bBEOBrLKQzVQ/j0ATCmRKKvIDXzkLbeiEQQnM7EcfJzwqpmO6jxUZ3qXVhvEXJltp8E5j2COtk= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745968564; c=relaxed/simple; bh=H0R9xHVE5gD9DZFvSrwWRzIrE3Yf2OJnI5T8aKnv0sk=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Tc28scg80u7Ct2u8xMWQVWnzxhwL/llpsgrUIBzdX6ZW9iwKDHV++LhXuXCNIDShfIebg3CvwWUtqHtbp47vRNuDKW5/wJtDb5GL7N6w/GbbVH3Febmy5Hppeu753OlDtLAiSvsqsVQL/g5MAcVcfjmwjl9cvu5QYVxCIo1q5hg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--mmaurer.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=I9HLDrCs; arc=none smtp.client-ip=209.85.214.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--mmaurer.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="I9HLDrCs" Received: by mail-pl1-f202.google.com with SMTP id d9443c01a7336-2254bdd4982so91284545ad.1 for ; Tue, 29 Apr 2025 16:16:02 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1745968562; x=1746573362; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=X5VRlHQlSmC4CwxYYUA0ffbYeWW2fuMVuSEdC5ZxOIA=; b=I9HLDrCsPN2/cQHz6PuEj4zcSjGlVXHgAtsV6HvSbw/RLuMINCuDkbpFKKKcXp2EQG 77MaTaUyYHpLxb5+D7zrPlwlVL3xKm338ZFsrTlG1k3LCAv0JIvKBTugNsKulBbgDPwZ cIRtSoUU6X/IK6uXc51fLqM8J6Wg4kj7Y5/NnDBJbP2w7xmU3953Eoj2sVWuoirnFaG8 +tEr0HWbdjDLCzwi00FbOW+BVMRRqT5yTsWh0Q1pMrKh+9eut8iCEpKVZvNDsNa5UFFs Hn0oGKvQG/UEFIZoupCYEtjIKqXQKTGYoFkBHQqLrbDJWHQ2qsGtw6/mqBf5b43tpQ4Y tz8g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1745968562; x=1746573362; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=X5VRlHQlSmC4CwxYYUA0ffbYeWW2fuMVuSEdC5ZxOIA=; b=j60Da+pmLi5XwV6ti2P5V8IH1L7w8UtpvRsWoAEKzkwtZB0IAbeF+nMPW7aNySu5a2 tOXLKWUKKKYF/JrddgC+GdCL9f0eOnWq9bGPn67p7GAHhu4HVWtgK8eDlwh196ZqVl8p 9LB9qaRuT5YxX8XJNKN/1dp5o7COT3f4go2+u1+fvwRI/q2FF3b47nqgfQGTn3U/cjdh Ar4sS+csYXzcYKayga++OA6AGnr3RqUrNwP+6mmNnrWQNkXZyALcf/47JsdpWSicP6bb Nzi23uTZJRfdTt7Y+xlJSaL6ZAxhzxT5IuSkVykNwKGE25LqoaOOMg9Evsq0akedC1y+ XdWQ== X-Gm-Message-State: AOJu0YwmuemWPLUCtHQglKCoWmBuVt1pv0LDH4MpHBPyFtCe1EuG2kvJ wvM5CsDfjIMqXdSXBNs1Bo6uiw09G6fFhU6+yvnNxcx+wHN7YXsznjzO/yH9BOIS2HEaz+pt6Nt cnKMMcg== X-Google-Smtp-Source: AGHT+IFxxc0wQTCm2CgU9b9O3RucwHFoW4xkdzab40kcTUqv90QWwXPAjjdzUErLc9VjQdew+JyvUwT0cKV+ X-Received: from pjbpb12.prod.google.com ([2002:a17:90b:3c0c:b0:2ff:5df6:7e03]) (user=mmaurer job=prod-delivery.src-stubby-dispatcher) by 2002:a17:903:2285:b0:216:3d72:1712 with SMTP id d9443c01a7336-22df35d361bmr17507905ad.48.1745968562045; Tue, 29 Apr 2025 16:16:02 -0700 (PDT) Date: Tue, 29 Apr 2025 23:15:57 +0000 In-Reply-To: <20250429-debugfs-rust-v1-0-6b6e7cb7929f@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250429-debugfs-rust-v1-0-6b6e7cb7929f@google.com> X-Developer-Key: i=mmaurer@google.com; a=ed25519; pk=2Ezhl7+fEjTOMVFpplDeak2AdQ8cjJieLRVJdNzrW+E= X-Developer-Signature: v=1; a=ed25519-sha256; t=1745968555; l=7881; i=mmaurer@google.com; s=20250429; h=from:subject:message-id; bh=H0R9xHVE5gD9DZFvSrwWRzIrE3Yf2OJnI5T8aKnv0sk=; b=46P5hVkwKySULaTTK9ZmqOkS0tS5e3gKnWvAkWPppSF7Z0wJXRN4QbwOsM7SlrLfcCqQBZbrU 0dNHOqzSpvhBmyRuWNtGvgngAxE24d4gCV/5CZfBJKTCIUki4sJQTNY X-Mailer: b4 0.14.2 Message-ID: <20250429-debugfs-rust-v1-3-6b6e7cb7929f@google.com> Subject: [PATCH 3/8] rust: debugfs: Add scoped builder interface From: Matthew Maurer To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Greg Kroah-Hartman , "Rafael J. Wysocki" , Sami Tolvanen Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, Matthew Maurer Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable This adds an interface which allows access to references which may not live indefinitely by forcing them to live at least as long as the DebugFS directory itself. Signed-off-by: Matthew Maurer --- rust/kernel/debugfs.rs | 163 +++++++++++++++++++++++++++++++++++++++++++++= ++++ 1 file changed, 163 insertions(+) diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs index b20df5fce692b3047c804f7ad5af90fc4248979b..f6240fd056f8598d5ef06bdaf61= c5c33eab5b734 100644 --- a/rust/kernel/debugfs.rs +++ b/rust/kernel/debugfs.rs @@ -12,7 +12,12 @@ use crate::str::CStr; use crate::types::{ARef, AlwaysRefCounted, Opaque}; use core::fmt::Display; +use core::marker::{PhantomData, PhantomPinned}; +use core::mem::ManuallyDrop; +use core::ops::Deref; +use core::pin::Pin; use core::ptr::NonNull; +use pin_init::{pin_data, pinned_drop, PinInit}; =20 /// Handle to a DebugFS directory. pub struct Dir { @@ -117,6 +122,22 @@ pub fn display_file( &self, name: &CStr, data: &'static T, + ) -> Result> { + // SAFETY: As `data` lives for the static lifetime, it outlives th= e file. + unsafe { self.display_file_raw(name, data) } + } + + /// Creates a DebugFS file backed by the display implementation of the= provided pointer. + /// + /// # Safety + /// The pointee of `data` must outlive the accessibility of the `Dir` = returned by this function. + /// This means that before `data` may become invalid, either: + /// * The refcount must go to zero + /// * The file must be rendered inaccessible, e.g. via `debugfs_remove` + unsafe fn display_file_raw( + &self, + name: &CStr, + data: *const T, ) -> Result> { // SAFETY: // * `name` is a NUL-terminated C string, living across the call, = by CStr invariant @@ -192,3 +213,145 @@ trait DisplayFile: Display + Sized { } =20 impl DisplayFile for T {} + +#[pin_data(PinnedDrop)] +/// A DebugFS directory combined with a backing store for data to implemen= t it +pub struct Values { + #[pin] + backing: T, + // Calling `debugfs_remove`, as we will do in our `Drop` impl, will co= nsume the refcount we + // hold after cleaning up all the child directories. + dir: ManuallyDrop>, + // Since the files present under our directory may point into backing,= we are !Unpin + #[pin] + _pin: PhantomPinned, +} + +impl Deref for Values { + type Target =3D T; + fn deref(&self) -> &T { + &self.backing + } +} + +impl Values { + /// Attach backing data to a DebugFS directory. When the resulting obj= ect is destroyed, the + /// DebugFS directory will be recursively removed as well. + /// + /// # Example + /// + /// ``` + /// # use kernel::c_str; + /// # use kernel::debugfs::{Dir, Values}; + /// let dir =3D Dir::new(c_str!("foo"), None)?; + /// let _foo =3D KBox::pin_init(Values::attach(0, dir), GFP_KERNEL)?; + /// // foo can now be used with `Values::build` to allow access to the= attached value when + /// // printing + /// # Ok::<(), Error>(()) + /// ``` + pub fn attach(backing: impl PinInit, dir: ARef) -> impl PinIni= t { + pin_init::pin_init! { Self { + backing <- backing, + dir: ManuallyDrop::new(dir), + _pin: PhantomPinned, + } } + } + + /// Runs a closure which has access to the backing data and a builder = that will allow you to + /// build a DebugFS structure off the backing data using its methods. + /// + /// # Example + /// + /// ``` + /// # use kernel::c_str; + /// # use kernel::debugfs::{Dir, Values}; + /// let dir =3D Dir::new(c_str!("foo"), None)?; + /// let foo =3D KBox::pin_init(Values::attach(0, dir), GFP_KERNEL)?; + /// foo.as_ref().build(|_value, _builder| { + /// // Construct debugfs with access to the attached value here + /// }); + /// # Ok::<(), Error>(()) + /// ``` + pub fn build FnOnce(&'a T, Builder<'a>) -> U>(self: Pin<= &Self>, f: F) -> U { + // SAFETY: The Builder produced here is technically at the lifetim= e of self, but is + // being used only in a universal context, so that information is = immediately erased and + // replaced with the universally quantified 'a. By taking a Pin<&S= elf>, we enforce that + // self.backing remains alive for any 'a less than the lifetime of= the struct. By not + // providing any mutable access to self.backing, we ensure that it= 's always safe to + // materialize a read-only reference to &self.backing for any 'a l= ess than the lifetime of + // the struct. + f(&self.backing, unsafe { Builder::new(&self.dir) }) + } +} + +#[pinned_drop] +impl PinnedDrop for Values { + fn drop(self: Pin<&mut Self>) { + // SAFETY: Our internal dir holds its own reference count, so it's= always valid. + unsafe { kernel::bindings::debugfs_remove(self.dir.as_ptr()) } + } +} + +/// A Dir, scoped to the lifetime for which it will exist. Unlike `&'a Dir= `, this is equivariant, +/// preventing the shortening of the lifetime. +/// +/// # Invariants +/// Builder will only ever be used with 'static or a universally quantifie= d lifetime that is +/// unified only with the lifetime of data structures guaranteed to outliv= e it and not have mutable +/// references taken. +#[repr(transparent)] +#[derive(Copy, Clone)] +pub struct Builder<'a> { + inner: &'a Dir, + _equivariant: PhantomData &'a ()>, +} + +impl<'a> Builder<'a> { + /// # Safety + /// Caller must promise to use this function at static lifetime or onl= y expose it to + /// universally quantified functions, unified only with lifetimes guar= anteed to extend beyond + /// when the directory will be rendered inaccessible. + unsafe fn new(inner: &'a Dir) -> Self { + Self { + inner, + _equivariant: PhantomData, + } + } + + /// Create a file in a DebugFS directory with the provided name, and c= ontents from invoking + /// [`Display::fmt`] on the provided reference. + /// + /// # Example + /// + /// ``` + /// # use kernel::{try_pin_init, c_str}; + /// # use pin_init::stack_try_pin_init; + /// # use kernel::debugfs::{Dir, Values}; + /// let dir =3D Dir::new(c_str!("foo"), None)?; + /// stack_try_pin_init!(let foo =3D? Values::attach((1, 2), dir)); + /// foo.as_ref().build(|value, builder| { + /// builder.display_file(c_str!("bar"), &value.0)?; + /// builder.display_file(c_str!("baz"), &value.1) + /// })?; + /// # Ok::<(), Error>(()) + /// ``` + pub fn display_file(&self, name: &CStr, data: &'a = T) -> Result<()> { + // We forget the reference because its reference count is implicit= ly "owned" by the root + // builder, which we know will use `debugfs_remove` to clean this = up. If we release the + // file here, it will be immediately deleted. + // SAFETY: + // Because `Builder`'s invariant says that our lifetime is how lon= g the directory will + // be available, and is equivariant, `'a` will outlive the base di= rectory, which will be + // torn down by `debugfs_remove` to prevent access even if an extr= a refcount is held + // somewhere. + core::mem::forget(unsafe { self.inner.display_file_raw(name, data)= ? }); + Ok(()) + } +} + +impl<'a> Deref for Builder<'a> { + type Target =3D Dir; + fn deref(&self) -> &Self::Target { + &self.inner + } +} --=20 2.49.0.901.g37484f566f-goog From nobody Sat Feb 7 15:12:40 2026 Received: from mail-pj1-f74.google.com (mail-pj1-f74.google.com [209.85.216.74]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 467612DCB7B for ; Tue, 29 Apr 2025 23:16:03 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.74 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745968566; cv=none; b=SKUiqMFablkSj54ugnTXK6vnhJi4D2KPVgs8oUTrHng/B/uqUOSO0mY2xv5IBGrUf5EPxnFpsGkUwRSC/8TGh2vtoyz+e7Q+ziQsqtc873umHrtGpl9mB2BiBJU4DtcolQoHK7aYOZ7Dk+denWXZ6lrtUuTH/G2sFPUDG2GY54I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745968566; c=relaxed/simple; bh=wiNWmXPA7aef+JSBJpG6giuwlkFHfN/reJPM9/DLlAE=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=QiHUxyK5N1LCqOEgM1MiapscgILCuI9Ac5yMnPKmNclFOVjaOEUqxq8pz3CM43TCnnY0HilwrMP7FVVpnSfnBwQshbAf038O87t3qaD4Li7iURlGPH72h/I4iy2uxd4uqFBBE5U39bJ8DLVcrpnW4SYyVQZYN+eJ4LD3TwTi1Hk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--mmaurer.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Q+6BCJjH; arc=none smtp.client-ip=209.85.216.74 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--mmaurer.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Q+6BCJjH" Received: by mail-pj1-f74.google.com with SMTP id 98e67ed59e1d1-2ff6167e9ccso7407715a91.1 for ; Tue, 29 Apr 2025 16:16:03 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1745968563; x=1746573363; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=jQeoPXxTZfB2IN32zOvdZjxaMXLUF1ehMnqMdv2YL/k=; b=Q+6BCJjHAF6nfuIzp1vzbs1xRXq0KixV7svAGN00gqrMO/PsSHLpq5dHXtyzc9UPAD HkhxEtyz3u18av8keX/7EYMv8jqrpxsdu7Db3qHSDyBoxVwxxK1l21hFVcpn84shY6Tg lEZaOckGM+D7Mx1WJe9pflqLQ+H3lziHsPLnk+mcmt4jsh2bqp7MyNlh8BgNbiLEadra nZmq4dJ/n8i/fXuT9yzgAll+k0YLhrwjrKL+mqDp+1nS2Q9qeLWaSvJbCYEfFwyyQaWA uv/gL0Ch0W98gtrATe7BPlTfzVMskLAAvNcjqqkjPbVtj0UJ0Uh4ltBgwO1/p7KSiT6t Kcig== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1745968563; x=1746573363; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=jQeoPXxTZfB2IN32zOvdZjxaMXLUF1ehMnqMdv2YL/k=; b=o5dtJnHEle2zOlbTlmnakTEV5qTYIBA/7KrnM7COx4AWYpU/Y3TyrCVi5gwyGQktL0 0EkoLBeAHQrA3oM5LcWo2lmcD4iHCKoRLoddtopkaS+Tr+QpToKB02LioSAp8KqECbnt b498XiOmPNl8wqi+S379/ef9T48Lt6wdqLF4D82BjbwjP81Ic8zVD+tOtRqRIiM1oJp6 rnbG3bRqwBD+bWHu5cI37UKDXej2PsXbFszzxvnze8BrG6YR2cjWkCzfTrfpyf/BtGSI 80sCtSLDyjqztfS5fwSx4VxJ65PeZ973YALQOVQ7Q14h7lkT5qmMc13MnTXHl07HReCR wdBA== X-Gm-Message-State: AOJu0YxVOoqgzHnzT5aPXyPjOdxYfyVdZkUSaaf2RgIjqyZrZGmQdhYO kqO+4tzFWr2NN66kxgcy/Wb4YaGqhWeakU++gvBlKpP//6EexsDn8z6ViwzckHVh3AvTzWBa/sW Rlv/n3Q== X-Google-Smtp-Source: AGHT+IHTtYh9lbg+u5+jXBsfaH1Ys7l7UGl6HzShzue0DXxB86FYRsgTXilfdtRn2zg9B2OgYy1E0dvKCTYP X-Received: from pjbos16.prod.google.com ([2002:a17:90b:1cd0:b0:2fc:ccfe:368]) (user=mmaurer job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:2c8d:b0:2ff:62f3:5b31 with SMTP id 98e67ed59e1d1-30a33365069mr1129213a91.29.1745968563550; Tue, 29 Apr 2025 16:16:03 -0700 (PDT) Date: Tue, 29 Apr 2025 23:15:58 +0000 In-Reply-To: <20250429-debugfs-rust-v1-0-6b6e7cb7929f@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250429-debugfs-rust-v1-0-6b6e7cb7929f@google.com> X-Developer-Key: i=mmaurer@google.com; a=ed25519; pk=2Ezhl7+fEjTOMVFpplDeak2AdQ8cjJieLRVJdNzrW+E= X-Developer-Signature: v=1; a=ed25519-sha256; t=1745968555; l=1931; i=mmaurer@google.com; s=20250429; h=from:subject:message-id; bh=wiNWmXPA7aef+JSBJpG6giuwlkFHfN/reJPM9/DLlAE=; b=49fow0XU7368/YDxnB7l8fFmldxw9zBseHKG6Pwt7nnmuDMgMzP42Ls51CV9+KFxW/2E0ZdvU 5jqQOzsMzh0DIGPOWbgCyd18ypepSBuZbgm7JszQeMZC9Tbcvn8KJJk X-Mailer: b4 0.14.2 Message-ID: <20250429-debugfs-rust-v1-4-6b6e7cb7929f@google.com> Subject: [PATCH 4/8] rust: debugfs: Allow subdir creation in builder interface From: Matthew Maurer To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Greg Kroah-Hartman , "Rafael J. Wysocki" , Sami Tolvanen Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, Matthew Maurer Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Allows creating subdirectories in the builder intended to be cleaned up by `debugfs_remove` at the same time as the root. Signed-off-by: Matthew Maurer --- rust/kernel/debugfs.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs index f6240fd056f8598d5ef06bdaf61c5c33eab5b734..6c7cf7e97741b98d2c0654d01fc= a3de0d8047e97 100644 --- a/rust/kernel/debugfs.rs +++ b/rust/kernel/debugfs.rs @@ -347,6 +347,32 @@ pub fn display_file(&self, name: &= CStr, data: &'a T) -> Resu core::mem::forget(unsafe { self.inner.display_file_raw(name, data)= ? }); Ok(()) } + + /// Creates a nested directory that may live as long as its parent + /// + /// # Example + /// + /// ``` + /// # use kernel::c_str; + /// # use kernel::debugfs::{Dir, Values}; + /// let dir =3D Dir::new(c_str!("foo"), None)?; + /// let foo =3D KBox::pin_init(Values::attach(0, dir), GFP_KERNEL)?; + /// foo.as_ref().build(|_value, builder| { + /// builder.dir(c_str!("bar"))?; + /// Ok::<(), Error>(()) + /// })?; + /// // foo/bar will still exist at this point in DebugFS + /// # Ok::<(), Error>(()) + /// ``` + pub fn dir(&self, name: &CStr) -> Result> { + let dir =3D Dir::new(name, Some(self))?; + // SAFETY: We're suppressing the drop of the ARef we received, so = we know it will live + // until its parent is `debugfs_remove`'d. The lifetime of the par= ent is 'a, so we can + // convert it to a similarly lived reference. + let dir: &'a Dir =3D unsafe { ARef::into_raw(dir).as_ref() }; + // SAFETY: Since 'a is a builder lifetime, we can propagate our in= variants + Ok(unsafe { Builder::new(dir) }) + } } =20 impl<'a> Deref for Builder<'a> { --=20 2.49.0.901.g37484f566f-goog From nobody Sat Feb 7 15:12:40 2026 Received: from mail-pg1-f202.google.com (mail-pg1-f202.google.com [209.85.215.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id AFF322DDCF9 for ; Tue, 29 Apr 2025 23:16:05 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745968567; cv=none; b=RosLknHrgGRxWhFJRF1xK8fPS7vfUMW/qwwmWcNhTT33k03x0SHFxfIxM1b6bS7TsIUJU6yCBFNmbILNsC96fD7v6ooNQ5Cm1jvNcdvTAs7m+0wODAus3wQV6KjYTBEdPKTGhtDSNksk5CrRBd6Qev5ZLj4LIDZwKnEn9Y707X0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745968567; c=relaxed/simple; bh=x4XZw/uTNiFUFZkmeUpFkUNuBS3nSzEJUNzJJbd28To=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=jMY4pi4QsmSBpnckES1pgq1WONSRo6sjKrCIjQ/pMvhS2PxXM7HWLCowdqg2HVaA7lwVCsbGuoGBoFrJQw6XTXES6XxnXSxWZgM6+OfTyfinCjkWMc+x+x4ZuUZRV10esTc+NsTf6oFyZ8oq+EUWj9smd1zHebV4Ekrhqr0JNFk= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--mmaurer.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=JhQQeZn+; arc=none smtp.client-ip=209.85.215.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--mmaurer.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="JhQQeZn+" Received: by mail-pg1-f202.google.com with SMTP id 41be03b00d2f7-b115fb801bcso7211044a12.3 for ; Tue, 29 Apr 2025 16:16:05 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1745968565; x=1746573365; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=Nj0VSHlz8BjkzXgQvs/OfvhGS6FJ+3Bdr3wHl5UDFLg=; b=JhQQeZn+3yq5XXiE4txIMnBTrR9XqumXfCqZJ4+U+TtH3sVUHjNzE1xjkML+sRbhow SIMHiflDcdpxtw7exPxpMmVYkP+2JikPMSoLItaFAkrVHI47BB+fa6SLk6JeumDppoxT u3DpwC8mnPTArkW7ZXNreW3bRDti7dTfQ5dDWTCw19uLU2EwmRBKxHkIa5BcVEdtcpqs IefA3LVnBbzLj98lwl/YIuqzLx9RP1nKWlocxnlvCI05+wba1hSROXSr6xE0Z3TlGPds dW523gGkn9cRkQ+PI/C3XTiqsGSI9uyjscVhfiz845kN/pcZVxkxOD1wj5a9Tz+QBCup /aog== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1745968565; x=1746573365; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=Nj0VSHlz8BjkzXgQvs/OfvhGS6FJ+3Bdr3wHl5UDFLg=; b=SUkIPrAtC3QQwt59YqhkjRk71KvWy3xoVAwcfuq1Cqz7VyMgUS9ajtrNqVEObeDnT7 oEnbXky7P48v8Mixv5E/XL130gsrCk/erw+M/eihk/sLjR836z9L+/K9ZkgRkmk1aBZr CNedmFcdjmLu0kX18EFaZYBVGlT//4XUIVFmAnPeitwuiRhnf9nYASyznLNHm5BvnuOH UwFnYlYVgcN6TaotJxQSodjhBeLPAZrfHmqfuz2eMfOG0W2AM6VMePKzS6unBtFc1A6y 6Hoqr1MrX57oTlMmpj97892qV0kf4sDTpb8AK+V3uNynThIIkERtM0s4DqgGMqMgNr5w yI3w== X-Gm-Message-State: AOJu0Yypuy5WnvbQlHt0TuRAjC8LnWo4OzKaAKHWOf0+T2J5X6S/FYWb FiVXxOGHcsbGbav2ixKz8xa1snHpAi6uIvAQE3p0keP4jgf9oeP/RJ1yepZ4uHnvVU6JBfDs0I+ m4F0DKQ== X-Google-Smtp-Source: AGHT+IFT32I5q1oA2JLaQdeDAqcxKTZkmZkXJgAh4y6hiXwQQLMuZzFKwV9VD5ZJmQj5jS5uSTIZORke0qFU X-Received: from pjh13.prod.google.com ([2002:a17:90b:3f8d:b0:301:b354:8d63]) (user=mmaurer job=prod-delivery.src-stubby-dispatcher) by 2002:a17:90b:5825:b0:308:65d4:9dda with SMTP id 98e67ed59e1d1-30a332ff7b4mr1377756a91.16.1745968565127; Tue, 29 Apr 2025 16:16:05 -0700 (PDT) Date: Tue, 29 Apr 2025 23:15:59 +0000 In-Reply-To: <20250429-debugfs-rust-v1-0-6b6e7cb7929f@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250429-debugfs-rust-v1-0-6b6e7cb7929f@google.com> X-Developer-Key: i=mmaurer@google.com; a=ed25519; pk=2Ezhl7+fEjTOMVFpplDeak2AdQ8cjJieLRVJdNzrW+E= X-Developer-Signature: v=1; a=ed25519-sha256; t=1745968555; l=7024; i=mmaurer@google.com; s=20250429; h=from:subject:message-id; bh=x4XZw/uTNiFUFZkmeUpFkUNuBS3nSzEJUNzJJbd28To=; b=dVctqUrYDf8t/2h5pL9lo8+x2qaU1YgRWyK2F0Bad8DxKr7DpUupHRiM58GxUNZaTIcJDIZcH CAiKlRsMXk5D97OU4P9nZarLci6d0pP5nhFhJr/VP/Ej97DYgRW01P8 X-Mailer: b4 0.14.2 Message-ID: <20250429-debugfs-rust-v1-5-6b6e7cb7929f@google.com> Subject: [PATCH 5/8] rust: debugfs: Support format hooks From: Matthew Maurer To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Greg Kroah-Hartman , "Rafael J. Wysocki" , Sami Tolvanen Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, Matthew Maurer Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Rather than always using Display, allow hooking arbitrary functions to arbitrary files. Display technically has the expressiveness to do this, but requires a new type be declared for every different way to render things, which can be very clumsy. Signed-off-by: Matthew Maurer --- rust/kernel/debugfs.rs | 125 +++++++++++++++++++++++++++++++++++++++++++++= +++- 1 file changed, 124 insertions(+), 1 deletion(-) diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs index 6c7cf7e97741b98d2c0654d01fca3de0d8047e97..2faa59d2dae44ab708cb8fca0d2= 3f06f73a95a3a 100644 --- a/rust/kernel/debugfs.rs +++ b/rust/kernel/debugfs.rs @@ -11,7 +11,8 @@ use crate::seq_print; use crate::str::CStr; use crate::types::{ARef, AlwaysRefCounted, Opaque}; -use core::fmt::Display; +use core::fmt; +use core::fmt::{Display, Formatter}; use core::marker::{PhantomData, PhantomPinned}; use core::mem::ManuallyDrop; use core::ops::Deref; @@ -127,6 +128,35 @@ pub fn display_file( unsafe { self.display_file_raw(name, data) } } =20 + /// Create a file in a DebugFS directory with the provided name, and c= ontents from invoking `f` + /// on the provided reference. `f` must be a function item or a non-ca= pturing closure, or this + /// will fail to compile. + /// + /// # Example + /// + /// ``` + /// # use core::sync::atomic::{AtomicU32, Ordering}; + /// # use kernel::c_str; + /// # use kernel::debugfs::Dir; + /// let dir =3D Dir::new(c_str!("foo"), None)?; + /// static MY_ATOMIC: AtomicU32 =3D AtomicU32::new(3); + /// let file =3D dir.fmt_file(c_str!("bar"), &MY_ATOMIC, &|val, f| { + /// let out =3D val.load(Ordering::Relaxed); + /// write!(f, "{out:#010x}\n") + /// })?; + /// MY_ATOMIC.store(10, Ordering::Relaxed); + /// # Ok::<(), Error>(()) + /// ``` + pub fn fmt_file) -> fmt::Result>( + &self, + name: &CStr, + data: &'static T, + f: &'static F, + ) -> Result> { + // SAFETY: As `data` lives for the static lifetime, it outlives th= e file + unsafe { self.fmt_file_raw(name, data, f) } + } + /// Creates a DebugFS file backed by the display implementation of the= provided pointer. /// /// # Safety @@ -162,6 +192,24 @@ unsafe fn display_file_raw( // owning dentry from debugfs_create_dir, so we can wrap it in an = ARef Ok(unsafe { ARef::from_raw(ptr.cast()) }) } + + /// Create a file in a DebugFS directory with the provided name, and c= ontents from invoking the + /// fomatter on the attached data. The attached function must be a ZST= , and will cause a + /// compilation error if it is not. + /// + /// # Safety + /// + /// `data` must outlive the resulting file's accessibility + unsafe fn fmt_file_raw) -> fmt::R= esult>( + &self, + name: &CStr, + data: &T, + f: &'static F, + ) -> Result> { + let data_adapted =3D FormatAdapter::new(data, f); + // SAFETY: data outlives the file's accessibility, so data_adapted= does too + unsafe { self.display_file_raw(name, data_adapted) } + } } =20 /// Implements `open` for `file_operations` via `single_open` to fill out = a `seq_file` @@ -373,6 +421,43 @@ pub fn dir(&self, name: &CStr) -> Result> { // SAFETY: Since 'a is a builder lifetime, we can propagate our in= variants Ok(unsafe { Builder::new(dir) }) } + + /// Create a file in a DebugFS directory with the provided name, and c= ontents from invoking `f` + /// on the provided reference. `f` must be a function item or a non-ca= pturing closure, or this + /// will fail to compile. + /// + /// # Example + /// + /// ``` + /// # use kernel::{c_str, new_mutex}; + /// # use kernel::debugfs::{Dir, Values}; + /// let dir =3D Dir::new(c_str!("foo"), None)?; + /// let foo =3D KBox::pin_init(Values::attach(new_mutex!(0), dir), GFP= _KERNEL)?; + /// foo.as_ref().build(|value, builder| { + /// builder.fmt_file(c_str!("bar"), value, &|val, f| { + /// write!(f, "Mutex read: {}", *val.lock()) + /// }) + /// })?; + /// *foo.lock() =3D 23; + /// # Ok::<(), Error>(()) + /// ``` + pub fn fmt_file) -> fmt::Result>( + &self, + name: &CStr, + data: &'a T, + f: &'static F, + ) -> Result<()> { + // We forget the reference because its reference count is implicit= ly "owned" by the root + // builder, which we know will use `debugfs_remove` to clean this = up. If we release the + // file here, it will be immediately deleted. + // SAFETY: + // Because `Builder`'s invariant says that our lifetime is how lon= g the directory will + // be available, and is equivariant, `'a` will outlive the base di= rectory, which will be + // torn down by `debugfs_remove` to prevent access even if an extr= a refcount is held + // somewhere. + core::mem::forget(unsafe { self.fmt_file_raw(name, data, f) }?); + Ok(()) + } } =20 impl<'a> Deref for Builder<'a> { @@ -381,3 +466,41 @@ fn deref(&self) -> &Self::Target { &self.inner } } + +// INVARIANT: F is inhabited +#[repr(transparent)] +struct FormatAdapter { + inner: T, + _formatter: PhantomData, +} + +impl FormatAdapter { + fn new<'a>(inner: &'a T, _f: &'static F) -> &'a Self { + // SAFETY: FormatAdapater is a repr(transparent) wrapper around T,= so + // casting a reference is legal + // INVARIANT: We were passed a reference to F, so it is inhabited. + unsafe { core::mem::transmute(inner) } + } +} + +impl) -> fmt::Result + 'static> Display fo= r FormatAdapter { + fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { + // SAFETY: FormatAdapter<_, F> can only be constructed if F is inh= abited + let f: &F =3D unsafe { materialize_zst_fmt() }; + f(&self.inner, fmt) + } +} + +/// # Safety +/// The caller asserts that F is inhabited +unsafe fn materialize_zst_fmt() -> &'static F { + // We don't have generic_const_exprs, and const items inside the funct= ion get promoted out and + // lose type variables, so we need to do the old-style assert to check= for ZSTness + [(); 1][core::mem::size_of::()]; + let zst_dangle: NonNull =3D NonNull::dangling(); + // SAFETY: + // While the pointer is dangling, it is a dangling pointer to a ZST, b= ased on the array + // assertion above. The type is also inhabited, by the caller's assert= ion. This means + // we can materialize it. + unsafe { zst_dangle.as_ref() } +} --=20 2.49.0.901.g37484f566f-goog From nobody Sat Feb 7 15:12:40 2026 Received: from mail-pf1-f202.google.com (mail-pf1-f202.google.com [209.85.210.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 697DB2DDD1C for ; Tue, 29 Apr 2025 23:16:07 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.210.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745968568; cv=none; b=IScDM0T4WXWssbj9YdkoL11+Ika7nEokH4z/Eu21JPOprdxI4p9Au7yTM354CJ9RMPcqmPrbSq+4ipmguz9f0dRh/T5hloPhIxj1OQFhiitwyfXv4v5r42wGZ07HsymjoD6pOJ/Q1RVPqx/CIGwXo8z8D/sBJfzhYfUkjQIG4wg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745968568; c=relaxed/simple; bh=jDFfce/aYAONbVLfkZooVl/9tCKFiXYK/iIQZ8BPTh4=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Jd4f05duH0ieDrpOXXCVNpaiQKZaXYm/XLZEyrlfybj48Ezeuij+oSqIjS1zX+vZvOSTX99HxYYeMWwH7+9HlcnNZjofpCSfb8y8i5hPwxmef76BAoo4PTSd60FIDOfz4YwzbszWsaxLepMesQ6Ecwck2Bd49QWqE3kDZf0fa5E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--mmaurer.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=Bqa9WAVo; arc=none smtp.client-ip=209.85.210.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--mmaurer.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="Bqa9WAVo" Received: by mail-pf1-f202.google.com with SMTP id d2e1a72fcca58-7394792f83cso4826968b3a.3 for ; Tue, 29 Apr 2025 16:16:07 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1745968567; x=1746573367; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=k3FMAy/FRG8pC4dy6gwKrSSJ8zPsmrSC5WffLcum+zI=; b=Bqa9WAVoTOwwHfy6tIXilrYAj83iC45tTNMgOmK+nca3E+mZYmkHH3mj1tkw8rGsVp 0V8ARbd/Yc6i9Hx2JD4wnr0AOK4EIKYOopdFhd3foM9xUx2Nhg7+T6U35SEPHE76bAar Ylt/gJEdvkAFfUDQO7oOUQwLM4hRp39lsQvhD0LnfhBcHWtPKjf1/MM9ik+MSgzwe9vL wO9LlyG/M26XcG5nIuEmpq1A1BY7l+bI644ffAJMQrOkQjTI7fopj9eCdWs8OiMKWzo/ FZ3mIBjnKMOKcbtKq4fZLS1BcqnfrSsNl4nOiowuVFSa7a15uNXFgi4v0pgTpy9Q+A64 TRAA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1745968567; x=1746573367; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=k3FMAy/FRG8pC4dy6gwKrSSJ8zPsmrSC5WffLcum+zI=; b=f6NBRaB6IYZbPkjm0jslR0zGxi1+sU7BlLMkYhY58+OwMwJe6+B3xycWD53euED0pg IfLtL3ssLSDZEq0ASCpSPGfzfehY412Xkey+LvGfaCEHuREpSXtAwguu4JMgo61sSUw4 qMMY38xwFqjykCFwZ1XWd1EiJaByRAbROUst4rPOTQfUf3xJG7mBZKIxUKdUJyiQcOXP e2P/4+uDI3ie5FrX3Ev+VmRu6siKMXraX2m37QUE9qGm3Tj6IqsSR50J7D+GLrTEqVKA 3ds2wNhOHYifIJ2FtSE8T9beJwuNzTbWvOXqyHbcQF4/A/zNtsDJZWN1pSORPSSAtpZj VhtA== X-Gm-Message-State: AOJu0YxbgY+1LP82IFhsP7Bfk849jYcHCqpE3mFThcRL+gzp1T9y42Jd bHj9AJye01Lw4Ou5ViTj3qqiQjhPbiTuEvvVacNULPIqJXs/K6vV1oSUdJ4A5aIyZAtyGCZw/hL E3mxj1w== X-Google-Smtp-Source: AGHT+IEKHsMjgQbX0xL5oHPDv7g0/Jga2HzMD62d9lUDbD1bZSA6aPDdFszQmEX4C9qLEPkZIOYrZWj3bhsB X-Received: from pfbei14.prod.google.com ([2002:a05:6a00:80ce:b0:739:8cd6:c16c]) (user=mmaurer job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:4fc4:b0:736:5544:7ad7 with SMTP id d2e1a72fcca58-740389c7565mr1415868b3a.14.1745968566698; Tue, 29 Apr 2025 16:16:06 -0700 (PDT) Date: Tue, 29 Apr 2025 23:16:00 +0000 In-Reply-To: <20250429-debugfs-rust-v1-0-6b6e7cb7929f@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250429-debugfs-rust-v1-0-6b6e7cb7929f@google.com> X-Developer-Key: i=mmaurer@google.com; a=ed25519; pk=2Ezhl7+fEjTOMVFpplDeak2AdQ8cjJieLRVJdNzrW+E= X-Developer-Signature: v=1; a=ed25519-sha256; t=1745968555; l=2919; i=mmaurer@google.com; s=20250429; h=from:subject:message-id; bh=jDFfce/aYAONbVLfkZooVl/9tCKFiXYK/iIQZ8BPTh4=; b=99NOQV1gabyc6/DqvOs21yTHQraG+0GFG+dlf248szD3TAv+PdOSOlz7Ap7pz3dvuE9+nfm4j vVLsOm1sScdCvn+yYgDYxj/jyqImRIL4vhyiZbVUy7YtawNtkm8cWvU X-Mailer: b4 0.14.2 Message-ID: <20250429-debugfs-rust-v1-6-6b6e7cb7929f@google.com> Subject: [PATCH 6/8] rust: debugfs: Implement display_file in terms of fmt_file From: Matthew Maurer To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Greg Kroah-Hartman , "Rafael J. Wysocki" , Sami Tolvanen Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, Matthew Maurer Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable fmt_file is fundamentally more flexible, this reduces the number of unsafe blocks, and allows us to append a newline for display_file which is a good default. Previous display_file did not append a newline to ensure that all output strings, including those without trailing newlines, were an option. Signed-off-by: Matthew Maurer --- rust/kernel/debugfs.rs | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs index 2faa59d2dae44ab708cb8fca0d23f06f73a95a3a..835df2b5d7311f278d1d15fc8d6= 88809d0ca363f 100644 --- a/rust/kernel/debugfs.rs +++ b/rust/kernel/debugfs.rs @@ -108,7 +108,7 @@ fn as_ptr(&self) -> *mut bindings::dentry { } =20 /// Create a file in a DebugFS directory with the provided name, and c= ontents from invoking - /// [`Display::fmt`] on the provided reference. + /// [`Display::fmt`] on the provided reference with a trailing newline. /// /// # Example /// @@ -124,8 +124,7 @@ pub fn display_file( name: &CStr, data: &'static T, ) -> Result> { - // SAFETY: As `data` lives for the static lifetime, it outlives th= e file. - unsafe { self.display_file_raw(name, data) } + self.fmt_file(name, data, &|val, f| write!(f, "{val}\n")) } =20 /// Create a file in a DebugFS directory with the provided name, and c= ontents from invoking `f` @@ -367,7 +366,7 @@ unsafe fn new(inner: &'a Dir) -> Self { } =20 /// Create a file in a DebugFS directory with the provided name, and c= ontents from invoking - /// [`Display::fmt`] on the provided reference. + /// [`Display::fmt`] on the provided reference with a trailing newline. /// /// # Example /// @@ -384,16 +383,7 @@ unsafe fn new(inner: &'a Dir) -> Self { /// # Ok::<(), Error>(()) /// ``` pub fn display_file(&self, name: &CStr, data: &'a = T) -> Result<()> { - // We forget the reference because its reference count is implicit= ly "owned" by the root - // builder, which we know will use `debugfs_remove` to clean this = up. If we release the - // file here, it will be immediately deleted. - // SAFETY: - // Because `Builder`'s invariant says that our lifetime is how lon= g the directory will - // be available, and is equivariant, `'a` will outlive the base di= rectory, which will be - // torn down by `debugfs_remove` to prevent access even if an extr= a refcount is held - // somewhere. - core::mem::forget(unsafe { self.inner.display_file_raw(name, data)= ? }); - Ok(()) + self.fmt_file(name, data, &|val, f| write!(f, "{val}\n")) } =20 /// Creates a nested directory that may live as long as its parent --=20 2.49.0.901.g37484f566f-goog From nobody Sat Feb 7 15:12:40 2026 Received: from mail-pg1-f202.google.com (mail-pg1-f202.google.com [209.85.215.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 143542DCB65 for ; Tue, 29 Apr 2025 23:16:08 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745968570; cv=none; b=ZIQSOLbJQF0jkHLsd24ldwB1qcdIdOaKGdwTyvOCAtSlyAlr7PaCQ0YAXRpyyEDEOClX/nCRYroEn6uRFrhyckA2Knm58Ev9V72U0NNcHHPI2PZ4wmPN3v3ouRgE0UFBbnTvK6rel3sWbwCbBAQhmb2yleQQoLkzxdO1Xjwo7pQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745968570; c=relaxed/simple; bh=xXexSYkiF+xc8497WmxTstUfnLfJhJHySbr1mw5kEMY=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=KzIsSgz/UITFfuJGRYeWgg/za8DLI1FCqhCV55h/a1kTyuEZ5T4NwexgcrTt6ZRw9HmkkAP0DWEhJAhYAWpD/HrGwaWa6jBL3lsDNcHNZvwoTixRoJ5P99uSEwPEl2revW9Mxoh3t4oLTGU+NcVylOL692tkQesZiqjKF4gTpgE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--mmaurer.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=RdVivedl; arc=none smtp.client-ip=209.85.215.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--mmaurer.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="RdVivedl" Received: by mail-pg1-f202.google.com with SMTP id 41be03b00d2f7-b0b2de67d6aso6537115a12.1 for ; Tue, 29 Apr 2025 16:16:08 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1745968568; x=1746573368; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=PD5cfpgRQLloOpPgFL2g+9oCBHx7RurASuZ91+rQhoM=; b=RdVivedlaJI657KoQWsIARoNwmyd54g96iveqVd3L4VG1NyaGp5JFrn8zD4mvBu6mY STrSrNDbfm5cOxZO9c7uLV/YdyW4HAOSxOmuICUSdubI5MIOfUdSZfb/juHMMTJhCnwv YrTbPbchSeQdZRP7acRAxYBWgaoAAbNSyhWelj1wt8XeEvg+GnAi6orycW/1J3RExDiH 0o4OT596m/CfL12r6iVnwNhFco3p0R02vLLTnOqQMz6+P5hMdou0cyEzXKAUCSvrOJTz SDazLzrlNuQG0ZM8GjwxbiAMUn1n1chtI7RhnJsBgjh5LWIfziUn1fXgdYlQ5S8XDnEd lWQg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1745968568; x=1746573368; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=PD5cfpgRQLloOpPgFL2g+9oCBHx7RurASuZ91+rQhoM=; b=VLlOy/3xs7jmXu2jjEbBoQ2529GHRCQl+yO2HXoxZ5FYhndZNmOTGCez+ctOgn9xlC HJyEa0IO602KeGP9nE4jgt/OmttbYuIczLkGbpzYt6Ut4HedsXuEHGnse/kj77qPVbFV kmrC9prXr9L7oedciFW1uFpO7veIATD0n3v0xoihAIoru52tEGv2JSXZYcNcZ2NP/r3q GBXjyJGV7uhNQSWXfJ8FSiTnSrmQPBkDbZn7qKYfSOTHk521SCI1UGmU+W+iBElVjkse HLiOFAFclEUBk73L2opCz9fGJzZCic191dhivr5mBl55/NaU2ClGgj4vg0gKcBtjSZrC Uy7g== X-Gm-Message-State: AOJu0YxJQHzzKTa9AJx46bxVPZWLKeM28xKjiZQJQbuWYPTgxfy2k3BC K+M8PvN4s9f9ek/vHwJOolvPINLXBLYOYzEX9K45Jy02vKP+retngQ5zCQ56SKL9StJ+iYnFiGr d7tN5Fg== X-Google-Smtp-Source: AGHT+IFhqMU7HcZrsLCHA1y4faH9LHObOnl08AX3PwgnJaNDFkUFrpblJwLZ0zdt/VtLoCwQZBwjjfz85EX+ X-Received: from pgg19.prod.google.com ([2002:a05:6a02:4d93:b0:b0b:2032:ef98]) (user=mmaurer job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a20:2d2a:b0:1f5:70d8:6a98 with SMTP id adf61e73a8af0-20a8499baedmr1035776637.0.1745968568359; Tue, 29 Apr 2025 16:16:08 -0700 (PDT) Date: Tue, 29 Apr 2025 23:16:01 +0000 In-Reply-To: <20250429-debugfs-rust-v1-0-6b6e7cb7929f@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250429-debugfs-rust-v1-0-6b6e7cb7929f@google.com> X-Developer-Key: i=mmaurer@google.com; a=ed25519; pk=2Ezhl7+fEjTOMVFpplDeak2AdQ8cjJieLRVJdNzrW+E= X-Developer-Signature: v=1; a=ed25519-sha256; t=1745968555; l=2455; i=mmaurer@google.com; s=20250429; h=from:subject:message-id; bh=xXexSYkiF+xc8497WmxTstUfnLfJhJHySbr1mw5kEMY=; b=bcVWeoLnL4CEsh9LxPMGw2mltHgE8e6mF/mnRQTkIsfElcQ9i0wpqurDrXhh0gTfFS/vCaRqF g9pYvALCqrQDl3CsdFH3bDdmyt7s3luA0i2g2NIAk+nuttsorUqH3vZ X-Mailer: b4 0.14.2 Message-ID: <20250429-debugfs-rust-v1-7-6b6e7cb7929f@google.com> Subject: [PATCH 7/8] rust: debugfs: Helper macro for common case implementations From: Matthew Maurer To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Greg Kroah-Hartman , "Rafael J. Wysocki" , Sami Tolvanen Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, Matthew Maurer Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable The most likely thing someone needs a custom hook for is a simple wrapper function around `write!`. This macro lets them just specify the format string directly rather than the fully expanded closure. Signed-off-by: Matthew Maurer --- rust/kernel/debugfs.rs | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs index 835df2b5d7311f278d1d15fc8d688809d0ca363f..edc6dd4cc5aedd4d3f1abc1a379= 3b39fce110d7b 100644 --- a/rust/kernel/debugfs.rs +++ b/rust/kernel/debugfs.rs @@ -8,9 +8,9 @@ =20 use crate::error::{from_err_ptr, Result}; use crate::seq_file::SeqFile; -use crate::seq_print; use crate::str::CStr; use crate::types::{ARef, AlwaysRefCounted, Opaque}; +use crate::{debugfs_fmt_file, seq_print}; use core::fmt; use core::fmt::{Display, Formatter}; use core::marker::{PhantomData, PhantomPinned}; @@ -124,7 +124,7 @@ pub fn display_file( name: &CStr, data: &'static T, ) -> Result> { - self.fmt_file(name, data, &|val, f| write!(f, "{val}\n")) + debugfs_fmt_file!(self, name, data, "{}\n") } =20 /// Create a file in a DebugFS directory with the provided name, and c= ontents from invoking `f` @@ -383,7 +383,7 @@ unsafe fn new(inner: &'a Dir) -> Self { /// # Ok::<(), Error>(()) /// ``` pub fn display_file(&self, name: &CStr, data: &'a = T) -> Result<()> { - self.fmt_file(name, data, &|val, f| write!(f, "{val}\n")) + debugfs_fmt_file!(self, name, data, "{}\n") } =20 /// Creates a nested directory that may live as long as its parent @@ -494,3 +494,21 @@ unsafe fn materialize_zst_fmt() -> &'static F { // we can materialize it. unsafe { zst_dangle.as_ref() } } + +#[macro_export] +/// Allows defining a debugfs file with a format string directly +/// +/// # Example +/// +/// ``` +/// # use kernel::debugfs::Dir; +/// # use kernel::{c_str, debugfs_fmt_file}; +/// let dir =3D Dir::new(c_str!("foo"), None)?; +/// debugfs_fmt_file!(dir, c_str!("bar"), &3, "bar=3D{}")?; +/// # Ok::<(), Error>(()) +/// ``` +macro_rules! debugfs_fmt_file { + ($dir:expr, $name:expr, $data:expr, $($arg:tt),*) =3D> { + $dir.fmt_file($name, $data, &|binding, fmt| write!(fmt, $($arg),*,= binding)) + } +} --=20 2.49.0.901.g37484f566f-goog From nobody Sat Feb 7 15:12:40 2026 Received: from mail-pg1-f202.google.com (mail-pg1-f202.google.com [209.85.215.202]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A4E412DEBBC for ; Tue, 29 Apr 2025 23:16:10 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.202 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745968572; cv=none; b=eNFVBsul7JaKWe0haWy4IqnDiLE8TjMvSF27f290nWqCS+Fzc5q/n0ryfzypyaOeQVbXKvH1xjHGL0CgU1YrsQrj4kD5kmEw91VNmIWdwWaz94zD41oe0DJMZDw4IV3GvT8glt2ToHevaVqMB87jXeVSCb6x6imRiXT+P0ml5Y8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1745968572; c=relaxed/simple; bh=YUqCqi7aUTwdF3KpHEUhIFercRLeKzLAnJ50JHhUVFI=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=oqLfMb1qGzuxMnxt4z1QEglTXg4wpmQzd+rE05Q1eUEzFe0sdYypE4Y5JkhRITozlYhEUsaViOSe80+LfrkdfiXUHf/DXRsHFF+d2EgMn11XgR0jKaEoZ+hCATu4kHISUsUJ6fWyBjO2RmGDLkwVKT4Gxr3yRPhiTiz6f9CPaRg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com; spf=pass smtp.mailfrom=flex--mmaurer.bounces.google.com; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b=x4o5Graz; arc=none smtp.client-ip=209.85.215.202 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=reject dis=none) header.from=google.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=flex--mmaurer.bounces.google.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=google.com header.i=@google.com header.b="x4o5Graz" Received: by mail-pg1-f202.google.com with SMTP id 41be03b00d2f7-b0e5f28841dso3961048a12.2 for ; Tue, 29 Apr 2025 16:16:10 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1745968570; x=1746573370; darn=vger.kernel.org; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:from:to:cc:subject:date:message-id:reply-to; bh=oRMAHF+KfmYzUz/9PJ/MZYytTgEPSKOAlccvFnnMFBU=; b=x4o5Grazv9lxKJ0SV8g4FlY0Hy3BHluvLr8xxRjTxUi4GXxTiXuc+cUsW8iEPMYyGl b0Db0VtH3FvX1o5n4B0ieTvpZFvi4DQR96x8o489VHL6IyNJjoUvWLXVtMvAlomOwsYM ve2LJ9qPRxnynTAB8izHUOoSqlNhQEppoMzMqssVI5meIIj9xsllNmnNHDdmJF7lgPjR NgWlr5yqhqTqK6AAlSP2mfJLdmjk2/o2idYsZHXjO0Qu7LUFgeZ9E1hQ+eBVAsZggGTp X0lfQxiqRTWax7cqbUYK14YDCZRGgrOfMXpI6vXMzxW8GLwzCobXJkDesDMGFAv6WXhQ 5ULg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1745968570; x=1746573370; h=cc:to:from:subject:message-id:references:mime-version:in-reply-to :date:x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=oRMAHF+KfmYzUz/9PJ/MZYytTgEPSKOAlccvFnnMFBU=; b=fmgzzMHkH8w1PPMdJqrk4Q32fCFJaVc5F1JHeMo063TsEGWVbbtE46MrESB5HTvr9U K1WY6CmTa+lBxTXaToq3W+1HgK+UuuHE+X+5ZzNeLtF6vF2gh4GEHoulW4qYUFcbbAEw eNWRwW/tyDlI79eraKY9J6qqxUOGAFGczCJEvsK7mZh+vXvvwm8howKyQJebZUjBzOmU UkmX2LSf9Yk7BpKWwqv3bHpyBF+7BDVwrjodT55S2o6HzNdCNjc0uSNOTm+j0VCXiiCi rCze+VFkPS24h0tWisYSi37BK1KZg5eP0Mn0XQkFB9hNZLgOLwF5FifItNCdLpM/+XPl xWvw== X-Gm-Message-State: AOJu0Yy1/9saJzmp7W5FGMK3vtMucCWQkNSqtHP93+lXqNffF9WZA2TW f5U0OUkgDGoaZ6dwqHUMAus96QUOhonTXDg2ofD5wzGtaKbQ/zPUroFQRqXojQPGox8Cg2auIVk UsXFHLg== X-Google-Smtp-Source: AGHT+IG74B+k9PFA7uUny3+Nk6P70J9+F71Nfzr4e6zW198ufm+tlhfRnWenZ2slERkmS+au8VqvGQvRx69k X-Received: from plrr18.prod.google.com ([2002:a17:902:c612:b0:223:690d:fd84]) (user=mmaurer job=prod-delivery.src-stubby-dispatcher) by 2002:a17:903:24d:b0:220:e63c:5aff with SMTP id d9443c01a7336-22df3588029mr16244025ad.47.1745968569964; Tue, 29 Apr 2025 16:16:09 -0700 (PDT) Date: Tue, 29 Apr 2025 23:16:02 +0000 In-Reply-To: <20250429-debugfs-rust-v1-0-6b6e7cb7929f@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250429-debugfs-rust-v1-0-6b6e7cb7929f@google.com> X-Developer-Key: i=mmaurer@google.com; a=ed25519; pk=2Ezhl7+fEjTOMVFpplDeak2AdQ8cjJieLRVJdNzrW+E= X-Developer-Signature: v=1; a=ed25519-sha256; t=1745968555; l=5886; i=mmaurer@google.com; s=20250429; h=from:subject:message-id; bh=YUqCqi7aUTwdF3KpHEUhIFercRLeKzLAnJ50JHhUVFI=; b=6ZRnSFlqqOhhDiugHVgaWWE07+Gw7dJ+BcYOX25vri87/MCWT//orKgD3tLWG3pahtTme7r2I pYqmVjLfUjCDItq1KEMRdtqfcJmlWLSyTROy2/mlt+qjwYgASzDkwQ+ X-Mailer: b4 0.14.2 Message-ID: <20250429-debugfs-rust-v1-8-6b6e7cb7929f@google.com> Subject: [PATCH 8/8] rust: samples: Add debugfs sample From: Matthew Maurer To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Greg Kroah-Hartman , "Rafael J. Wysocki" , Sami Tolvanen Cc: linux-kernel@vger.kernel.org, rust-for-linux@vger.kernel.org, Matthew Maurer Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Provides an example of using the Rust DebugFS bindings. Signed-off-by: Matthew Maurer --- MAINTAINERS | 1 + samples/rust/Kconfig | 11 ++++ samples/rust/Makefile | 1 + samples/rust/rust_debugfs.rs | 120 +++++++++++++++++++++++++++++++++++++++= ++++ 4 files changed, 133 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index a3b835e427b083a4ddd690d9e7739851f0af47ae..426bcdac025134e20911de8e2cf= 5c9efb0591814 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7278,6 +7278,7 @@ F: rust/kernel/devres.rs F: rust/kernel/driver.rs F: rust/kernel/faux.rs F: rust/kernel/platform.rs +F: samples/rust/rust_debugfs.rs F: samples/rust/rust_driver_platform.rs F: samples/rust/rust_driver_faux.rs =20 diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig index 43cb72d72631bb2d6e06185e1d88778edff6ee13..6c42ed73f842cda26256039e691= 7bb443738d3f1 100644 --- a/samples/rust/Kconfig +++ b/samples/rust/Kconfig @@ -51,6 +51,17 @@ config SAMPLE_RUST_DMA =20 If unsure, say N. =20 +config SAMPLE_RUST_DEBUGFS + tristate "DebugFS Test Driver" + depends on DEBUG_FS + help + This option builds the Rust DebugFS Test driver sample. + + To compile this as a module, choose M here: + the module will be called rust_debugfs. + + If unsure, say N. + config SAMPLE_RUST_DRIVER_PCI tristate "PCI Driver" depends on PCI diff --git a/samples/rust/Makefile b/samples/rust/Makefile index 6a466afd2a21eba84a3b7b2be29f25dce44e9053..b1fc4677ed53fcf7d0f5a3dbf32= 2f65851bc1784 100644 --- a/samples/rust/Makefile +++ b/samples/rust/Makefile @@ -4,6 +4,7 @@ ccflags-y +=3D -I$(src) # needed for trace events 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 +obj-$(CONFIG_SAMPLE_RUST_DEBUGFS) +=3D rust_debugfs.o obj-$(CONFIG_SAMPLE_RUST_DMA) +=3D rust_dma.o obj-$(CONFIG_SAMPLE_RUST_DRIVER_PCI) +=3D rust_driver_pci.o obj-$(CONFIG_SAMPLE_RUST_DRIVER_PLATFORM) +=3D rust_driver_platform.o diff --git a/samples/rust/rust_debugfs.rs b/samples/rust/rust_debugfs.rs new file mode 100644 index 0000000000000000000000000000000000000000..3fd25848f2d096b03fa70679103= bd725d0e42fcf --- /dev/null +++ b/samples/rust/rust_debugfs.rs @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +//! Sample DebugFS exporting module + +use core::fmt; +use core::fmt::{Display, Formatter}; +use core::sync::atomic::{AtomicU32, Ordering}; +use kernel::c_str; +use kernel::debugfs::{Builder, Dir, Values}; +use kernel::debugfs_fmt_file; +use kernel::new_mutex; +use kernel::prelude::*; +use kernel::sync::{Arc, Mutex}; + +module! { + type: RustDebugFs, + name: "rust_debugfs", + authors: ["Matthew Maurer"], + description: "Rust DebugFS usage sample", + license: "GPL", +} + +struct RustDebugFs { + _debugfs: Pin>>, +} + +struct Composite { + major: u32, + minor: u32, +} + +impl Display for Composite { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + write!(f, "{}.{}", self.major, self.minor) + } +} + +struct Record { + name: &'static CStr, + size: usize, + stride: usize, +} + +struct Backing { + simple: u32, + composite: Composite, + custom: u32, + many: KVec, + atomic: AtomicU32, + locked: Arc>, +} + +impl Backing { + fn new() -> Result { + let mut many =3D KVec::new(); + many.push( + Record { + name: c_str!("foo"), + size: 1, + stride: 2, + }, + GFP_KERNEL, + )?; + many.push( + Record { + name: c_str!("bar"), + size: 3, + stride: 4, + }, + GFP_KERNEL, + )?; + Ok(Self { + simple: 10, + composite: Composite { major: 1, minor: 2 }, + custom: 37, + many, + atomic: AtomicU32::new(7), + locked: Arc::pin_init(new_mutex!(0), GFP_KERNEL)?, + }) + } + fn build<'a>(&'a self, builder: Builder<'a>) -> Result<()> { + builder.display_file(c_str!("simple"), &self.simple)?; + builder.display_file(c_str!("composite"), &self.composite)?; + debugfs_fmt_file!( + builder, + c_str!("custom"), + &self.custom, + "Foo! {:#010x} Bar!\n" + )?; + for record in self.many.iter() { + let dir =3D builder.dir(record.name)?; + dir.display_file(c_str!("size"), &record.size)?; + dir.display_file(c_str!("stride"), &record.stride)?; + } + builder.fmt_file(c_str!("atomic"), &self.atomic, &|atomic, f| { + write!(f, "{}\n", atomic.load(Ordering::Relaxed)) + })?; + builder.fmt_file(c_str!("locked"), &self.locked, &|locked, f| { + write!(f, "{}\n", *locked.lock()) + })?; + Ok(()) + } +} + +impl kernel::Module for RustDebugFs { + fn init(_this: &'static ThisModule) -> Result { + let dir =3D Dir::new(c_str!("sample_debugfs"), None)?; + let backing =3D Backing::new()?; + let locked =3D backing.locked.clone(); + let debugfs =3D KBox::pin_init(Values::attach(backing, dir), GFP_K= ERNEL)?; + debugfs.as_ref().build(Backing::build)?; + // These mutations could occur at any time in the future, and woul= d remain visible through + // debugfs. + debugfs.as_ref().atomic.store(8, Ordering::Relaxed); + *locked.lock() =3D 42; + Ok(Self { _debugfs: debugfs }) + } +} --=20 2.49.0.901.g37484f566f-goog