From nobody Tue Oct 7 12:28:20 2025 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 0C88923F41A for ; Wed, 9 Jul 2025 19:09:46 +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=1752088188; cv=none; b=KbETxJSvVt/SkxhCEVKBXxiwckX8k+r1b40/D6wMWn/5bchJ8Nspi08iWKcaL56yYTdBGH3Vjlq7TZVLT471HOzoJ4jNZfHWvgMaSCVVFqHbmcV97lzabfFaMak6KFTBRE2Gay063+KxCiD1tXWNm4OVjRWNVs/DohLjRNrTWS0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752088188; c=relaxed/simple; bh=2xMXvnwdehEJpRes29S5HTu29jmng1EgLMgZ0BcjSMY=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=XKlIqBcL4K3Z9DSZCauSK6oQS/O4AA2j65x1OQGoDr23jjAFWsmm51luS1toBWvCwD01eJeMIxjz1gUi/dqV2qgE1HRqqji6hWmGbmWsMlpu2+NHVp7wSd3udMy/O7y6jZmJWleuNoFDBa4D774AxxTlta3zLwQ4mTje/gyhTHE= 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=WCZHdGYe; 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="WCZHdGYe" Received: by mail-pf1-f202.google.com with SMTP id d2e1a72fcca58-74ad608d60aso121917b3a.1 for ; Wed, 09 Jul 2025 12:09:46 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1752088186; x=1752692986; 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=hYtB32NJTeIv/b7Je1focZ0Ga/KNiuYXzRHxWQcjtBg=; b=WCZHdGYe5J/XcM8zQa2QzQEfXsqGjIYBt91MgVdSDcKS9ptHzAX8lvqVeZi5xnHIf7 ky2qz+1b3wSzrLcnLlnVoz4jQwYQB26ZgbPFFQfmYiR9OkqiNgsloIeV/ftDNiVxSFw9 0tlZqjuoLNLMjz+CxkWhkUHmu/hA9TMkckzjgaN+Rdux0u+jg0Sl/pQaSBsIYoyhYeLe DD9y7D+FCk6PZD3A033yLut9G4kb9YFuWqUc+I95GK6ZdpRBVuxm0qd1XzFQZUcjj2Br knN2C3B+uY+C8bUEAV66Q35kT44jmmTFjPM5c0C4ObQyO+E2/xDDL/T6UWCgjvi3CIge E/AA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1752088186; x=1752692986; 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=hYtB32NJTeIv/b7Je1focZ0Ga/KNiuYXzRHxWQcjtBg=; b=CGD2OSlgSqoXefWMy1PusTEXyY3p/06BWQVbWQYazuoE0XmNGJ8OIu9wUc2OJ2GQ3B ZTldLxWkxDoixwutudgEt2WBOfXX1SBvhv94tvRyJc9dHClcJUJN7tOjNddkea0V8fbg hmC/I0O12RClZyLy9rW3uVboX0Q9G1X9LaNWdHQ8NYfq02LFU/wfZCjYarL0TAPkY3JX wpcXYVLe9vx67UZ+zAzXy75pIKtnpfVL+eCl22lNkfF0ixwDS7lwm+Lg4ymclVekMwf/ R951VDm0Fodgo2n1WRgdaHpkaLsgh5ryqjj3xq4BvrEUT1UoCQ87js1EnDARSgB2/Sb4 bgFQ== X-Gm-Message-State: AOJu0YwYbLOzZ2uwlAtAlDC3ABeZw4lb3UgPGvg6THcWBaUHPR/Is2lb uoQRA9BmnHGxPZLNmDVcu9h+4mU0CrphIOufsf86RvE7aT3qYmCT6vNO7m5qNE2NBNA+w5Yu5WC 5K/gaYjGW+A== X-Google-Smtp-Source: AGHT+IHYrt50dBP3H7XchHPpdCvmoQ39JsAAAzyP1dC7yMptJZ1AomsPrvE638XBJnJXU3RQgB2AS3d6HXdF X-Received: from pfoo19.prod.google.com ([2002:a05:6a00:1a13:b0:746:18ec:d11a]) (user=mmaurer job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a00:22d2:b0:748:e5a0:aa77 with SMTP id d2e1a72fcca58-74eb558ed64mr923038b3a.13.1752088186294; Wed, 09 Jul 2025 12:09:46 -0700 (PDT) Date: Wed, 09 Jul 2025 19:09:28 +0000 In-Reply-To: <20250709-debugfs-rust-v9-0-92b9eab5a951@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250709-debugfs-rust-v9-0-92b9eab5a951@google.com> X-Developer-Key: i=mmaurer@google.com; a=ed25519; pk=2Ezhl7+fEjTOMVFpplDeak2AdQ8cjJieLRVJdNzrW+E= X-Developer-Signature: v=1; a=ed25519-sha256; t=1752088183; l=7535; i=mmaurer@google.com; s=20250429; h=from:subject:message-id; bh=2xMXvnwdehEJpRes29S5HTu29jmng1EgLMgZ0BcjSMY=; b=yY0F+uYOTXb6bwaMkBLATUk5Sqhto4XeDcz5spLLWEaJ9LhewltVIunONhW6llm2YxaRsKPov VmhfQIaHKM6DpqkCXcMs+kzGLRfixVF9tshsSudXln3n68OtpmbbuEm X-Mailer: b4 0.14.2 Message-ID: <20250709-debugfs-rust-v9-1-92b9eab5a951@google.com> Subject: [PATCH v9 1/5] 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?=" , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Greg Kroah-Hartman , "Rafael J. Wysocki" , Sami Tolvanen , Timur Tabi , Benno Lossin 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 Support creating DebugFS directories and subdirectories. Similar to the original DebugFS API, errors are hidden. Directories persist until their handle and the handles of any child objects have been dropped. Signed-off-by: Matthew Maurer --- MAINTAINERS | 2 + rust/bindings/bindings_helper.h | 1 + rust/kernel/debugfs.rs | 90 +++++++++++++++++++++++++++++++++++++= ++++ rust/kernel/debugfs/entry.rs | 58 ++++++++++++++++++++++++++ rust/kernel/lib.rs | 1 + 5 files changed, 152 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 7f8ddeec3b177772caf6160de65ca9985912cac8..1427af9d9779b1f6463409f4392= e2900438bdc2a 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7367,6 +7367,8 @@ 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/debugfs/ F: rust/kernel/device.rs F: rust/kernel/device/ F: rust/kernel/device_id.rs diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 7e8f2285064797d5bbac5583990ff823b76c6bdc..8600b361bce3f3b613d5189b7ac= d1704326b6284 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -46,6 +46,7 @@ #include #include #include +#include #include #include #include diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs new file mode 100644 index 0000000000000000000000000000000000000000..2359bd11cd664fb9f7206f8fe38= f758dc43d2cb8 --- /dev/null +++ b/rust/kernel/debugfs.rs @@ -0,0 +1,90 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2025 Google LLC. + +//! DebugFS Abstraction +//! +//! C header: [`include/linux/debugfs.h`](srctree/include/linux/debugfs.h) + +#[cfg(CONFIG_DEBUG_FS)] +use crate::prelude::GFP_KERNEL; +use crate::str::CStr; +#[cfg(CONFIG_DEBUG_FS)] +use crate::sync::Arc; + +#[cfg(CONFIG_DEBUG_FS)] +mod entry; +#[cfg(CONFIG_DEBUG_FS)] +use entry::Entry; + +/// Owning handle to a DebugFS directory. +/// +/// This directory will be cleaned up when the handle and all child direct= ory/file handles have +/// been dropped. +// We hold a reference to our parent if it exists to prevent the dentry we= point to from being +// cleaned up when our parent is removed. +pub struct Dir(#[cfg(CONFIG_DEBUG_FS)] Option>); + +impl Dir { + /// Create a new directory in DebugFS. If `parent` is [`None`], it wil= l be created at the root. + #[cfg(CONFIG_DEBUG_FS)] + fn create(name: &CStr, parent: Option<&Dir>) -> Self { + let parent_ptr =3D match parent { + // If the parent couldn't be allocated, just early-return + Some(Dir(None)) =3D> return Self(None), + Some(Dir(Some(entry))) =3D> entry.as_ptr(), + None =3D> core::ptr::null_mut(), + }; + // SAFETY: + // * `name` argument points to a NUL-terminated string that lives = across the call, by + // invariants of `&CStr`. + // * If `parent` is `None`, `parent_ptr` is null to mean create at= root. + // * If `parent` is `Some`, `parent_ptr` is a live dentry debugfs = pointer. + let dir =3D unsafe { bindings::debugfs_create_dir(name.as_char_ptr= (), parent_ptr) }; + + Self( + // If Arc creation fails, the `Entry` will be dropped, so the = directory will be cleaned + // up. + Arc::new( + // SAFETY: `debugfs_create_dir` either returns an error co= de or a legal `dentry` + // pointer, and the parent is the same one passed to `debu= gfs_create_dir` + unsafe { Entry::new(dir, parent.and_then(|dir| dir.0.clone= ())) }, + GFP_KERNEL, + ) + .ok(), + ) + } + + #[cfg(not(CONFIG_DEBUG_FS))] + fn create(_name: &CStr, _parent: Option<&Dir>) -> Self { + Self() + } + + /// Create a DebugFS subdirectory. + /// + /// Subdirectory handles cannot outlive the directory handle they were= created from. + /// + /// # Examples + /// + /// ``` + /// # use kernel::c_str; + /// # use kernel::debugfs::Dir; + /// let parent =3D Dir::new(c_str!("parent")); + /// let child =3D parent.subdir(c_str!("child")); + /// ``` + pub fn subdir(&self, name: &CStr) -> Self { + Dir::create(name, Some(self)) + } + + /// Create a new directory in DebugFS at the root. + /// + /// # Examples + /// + /// ``` + /// # use kernel::c_str; + /// # use kernel::debugfs::Dir; + /// let debugfs =3D Dir::new(c_str!("parent")); + /// ``` + pub fn new(name: &CStr) -> Self { + Dir::create(name, None) + } +} diff --git a/rust/kernel/debugfs/entry.rs b/rust/kernel/debugfs/entry.rs new file mode 100644 index 0000000000000000000000000000000000000000..ae0e2c4e1d58e878ebb081a71e4= ac0f4a7d99b91 --- /dev/null +++ b/rust/kernel/debugfs/entry.rs @@ -0,0 +1,58 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2025 Google LLC. + +use crate::sync::Arc; + +/// Owning handle to a DebugFS entry. +/// +/// # Invariants +/// +/// The wrapped pointer will always be `NULL`, an error, or an owned Debug= FS `dentry`. +pub(crate) struct Entry { + entry: *mut bindings::dentry, + _parent: Option>, +} + +// SAFETY: [`Entry`] is just a `dentry` under the hood, which the API prom= ises can be transferred +// between threads. +unsafe impl Send for Entry {} + +// 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 Entry {} + +impl Entry { + /// Constructs a new DebugFS [`Entry`] from the underlying pointer. + /// + /// # Safety + /// + /// The pointer must either be an error code, `NULL`, or represent a t= ransfer of ownership of a + /// live DebugFS directory. If this is a child directory or file, `'a`= must be less than the + /// lifetime of the parent directory. + /// + /// If the dentry has a parent, it must be provided as the parent argu= ment. + pub(crate) unsafe fn new(entry: *mut bindings::dentry, parent: Option<= Arc>) -> Self { + Self { + entry, + _parent: parent, + } + } + + /// Returns the pointer representation of the DebugFS directory. + /// + /// # Guarantees + /// + /// Due to the type invariant, the value returned from this function w= ill always be an error + /// code, NULL, or a live DebugFS directory. + pub(crate) fn as_ptr(&self) -> *mut bindings::dentry { + self.entry + } +} + +impl Drop for Entry { + fn drop(&mut self) { + // SAFETY: `debugfs_remove` can take `NULL`, error values, and leg= al DebugFS dentries. + // `as_ptr` guarantees that the pointer is of this form. + unsafe { bindings::debugfs_remove(self.as_ptr()) } + } +} diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 5bbf3627212f0a26d34be0d6c160a370abf1e996..8b4d7c95bcc895cf15544d96889= 41f93f2780510 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -67,6 +67,7 @@ pub mod cpufreq; pub mod cpumask; pub mod cred; +pub mod debugfs; pub mod device; pub mod device_id; pub mod devres; --=20 2.50.0.727.gbf7dc18ff4-goog From nobody Tue Oct 7 12:28:20 2025 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 914982405E8 for ; Wed, 9 Jul 2025 19:09:48 +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=1752088190; cv=none; b=neMv1xj1oQuDylsFnFYjLQwc88EfjdLdKW9dY0eiu6MTkdmlGugTevhIEOBzLPw7k63iZDUwrHcT4QTUU9bVJKRgLxJVcpWS0S6AAsYWaX9Lk7S08b5/rmcKgEgvs3N2zbvuN+nVX2W/39EhNc0ZVGjl/YoCu1xzbCmZys1xN8g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752088190; c=relaxed/simple; bh=QRiqyW+DCxPHLC6LuzDOu/jPtN7jYe5i/M7V+NqpsBs=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=KrUwWKhXKjYMRywyr4MMqrRJUuwonUEu9Z/p7gg40QXvhw5PUgbblyTkHka47WZCZFXSzNyBidDy78bvggLPFWU55pw5W/wHl7BB1Pql5VS9sDU67tvhE/U+tsT1Gmh9hC5QzHUU4Ne4YHkhXzbWoyMb/89m1smDwFeHJTaiAgg= 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=OyPfKP61; 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="OyPfKP61" Received: by mail-pg1-f202.google.com with SMTP id 41be03b00d2f7-b38fc4d8dbaso262989a12.2 for ; Wed, 09 Jul 2025 12:09:48 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1752088188; x=1752692988; 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=zPooK67XTY1HlJ292G/Ieoo/IDz4butYV3iYjuxKXdc=; b=OyPfKP61gVJuUuOPRoVhjzYH26G+Hp3MTahWwHsOiX2hxb0OnKuD57mDNWR/OZi4uw 9FyMlzvVFodF9e1QHwbuC/Yof8j/1ACjZkLqN/ZYzhhtjTi8XsaYtOGrwe7n8GmHOcX3 sLWAg/2BrmucvcIoyUzWZSk76lDJXwUq/1eEgLzuB4ESTX0E9XwATFJ1x1DDBYxoCr9S dAudvwvQFVl06rE+ajtYxH+TFT6b831FD0PQzGnF5lltNuPPNaYTCHdBzN2JzsR1mfbc vVsR76XS4sljqEUDXea35Bh9heeTriri7tdqrvbExI14zZEHb34Yg5zxbg/R8dDSb7nU Lt3w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1752088188; x=1752692988; 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=zPooK67XTY1HlJ292G/Ieoo/IDz4butYV3iYjuxKXdc=; b=lvCyb/FmreqNWWhnJFGJO8RtmWiPCd8X6eEkYEk0GwhjHbcLzprUajqfrEZTH+hUHY UYHquX6o4K9RbCxyt/sY/ZSzKYE4h9mpWNtB6xD0veq/M4hVngvP1DV53WTWRsDqgHyC 9gYanSxJjKWAKwgPrlbPv4U2pzcwfFrv/h9IW/y5bZU5tyzr3VIlaHPvR94f/l4kAWkG AZkXFrvUJV205EZW5jv0iWk4cmKi9jq5sOaGoGxwxQnteSBLd/WMrbK7AfNmFC6CPG1a Fdtj6UtaTcHTkBV+twCEJov2tCjr54nmgK+wcLyfVJQhgQTC0w48M1kBZbMJxtjcR7Qm mLuw== X-Gm-Message-State: AOJu0YxgQoIsz2SBfqQLg/ow3eiljSEHH3gKqk+ZUS/g0DHJJLqWZBZg 9dhpuQ5nQ918eLzidIGHQyHg7rMoVlj1NMxt3fVNFQwrjEcWF/P6LDCzetl2+erTSwqcaiViIcy uDvWEHgsEyg== X-Google-Smtp-Source: AGHT+IHWVMlOwYW++LmgsC4IEAN7tHaGgbzJ2Rx0MyZHTNqRafNy1V/OS6L5f3GoMD0S3BUQJzzfV/fr6IU2 X-Received: from pldr21.prod.google.com ([2002:a17:903:4115:b0:231:c831:9520]) (user=mmaurer job=prod-delivery.src-stubby-dispatcher) by 2002:a17:903:32d1:b0:235:ea0d:ae10 with SMTP id d9443c01a7336-23ddb2e1591mr61894145ad.12.1752088187813; Wed, 09 Jul 2025 12:09:47 -0700 (PDT) Date: Wed, 09 Jul 2025 19:09:29 +0000 In-Reply-To: <20250709-debugfs-rust-v9-0-92b9eab5a951@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250709-debugfs-rust-v9-0-92b9eab5a951@google.com> X-Developer-Key: i=mmaurer@google.com; a=ed25519; pk=2Ezhl7+fEjTOMVFpplDeak2AdQ8cjJieLRVJdNzrW+E= X-Developer-Signature: v=1; a=ed25519-sha256; t=1752088183; l=7413; i=mmaurer@google.com; s=20250429; h=from:subject:message-id; bh=QRiqyW+DCxPHLC6LuzDOu/jPtN7jYe5i/M7V+NqpsBs=; b=95F2k3uRDz2giN1M1JsUFd8J114spRlVrjgEZENf15eRCoPuYsJQvfs2GfzLUhB+vdjkfrrZV OSVcIob+5HjBWAwbDtubPmhjXfemvA4MPHdyogp8A0cEjBZx/WmtX4d X-Mailer: b4 0.14.2 Message-ID: <20250709-debugfs-rust-v9-2-92b9eab5a951@google.com> Subject: [PATCH v9 2/5] 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?=" , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Greg Kroah-Hartman , "Rafael J. Wysocki" , Sami Tolvanen , Timur Tabi , Benno Lossin 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 `Display` implementation is used because `seq_printf` needs to route through `%pA`, which in turn routes through Arguments. Signed-off-by: Matthew Maurer --- rust/kernel/debugfs.rs | 62 +++++++++++++++++++++++++++++++++= +++ rust/kernel/debugfs/display_file.rs | 63 +++++++++++++++++++++++++++++++++= ++++ rust/kernel/debugfs/entry.rs | 8 +++++ 3 files changed, 133 insertions(+) diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs index 2359bd11cd664fb9f7206f8fe38f758dc43d2cb8..e5b6497d1deb67671d22ffd90cd= 5baa855bb9257 100644 --- a/rust/kernel/debugfs.rs +++ b/rust/kernel/debugfs.rs @@ -10,7 +10,10 @@ use crate::str::CStr; #[cfg(CONFIG_DEBUG_FS)] use crate::sync::Arc; +use core::fmt::Display; =20 +#[cfg(CONFIG_DEBUG_FS)] +mod display_file; #[cfg(CONFIG_DEBUG_FS)] mod entry; #[cfg(CONFIG_DEBUG_FS)] @@ -59,6 +62,43 @@ fn create(_name: &CStr, _parent: Option<&Dir>) -> Self { Self() } =20 + #[cfg(CONFIG_DEBUG_FS)] + fn create_file(&self, name: &CStr, data: &'= static T) -> File { + let Some(parent) =3D &self.0 else { + return File { + _entry: Entry::empty(), + }; + }; + // 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. + let ptr =3D unsafe { + bindings::debugfs_create_file_full( + name.as_char_ptr(), + 0o444, + parent.as_ptr(), + data as *const _ as *mut _, + core::ptr::null(), + &::VTABLE, + ) + }; + + // SAFETY: `debugfs_create_file_full` either returns an error code= or a legal + // dentry pointer, so `Entry::new` is safe to call here. + let entry =3D unsafe { Entry::new(ptr, Some(parent.clone())) }; + + File { _entry: entry } + } + + #[cfg(not(CONFIG_DEBUG_FS))] + fn create_file(&self, _name: &CStr, _data: = &'static T) -> File { + File {} + } + /// Create a DebugFS subdirectory. /// /// Subdirectory handles cannot outlive the directory handle they were= created from. @@ -75,6 +115,22 @@ pub fn subdir(&self, name: &CStr) -> Self { Dir::create(name, Some(self)) } =20 + /// Create a file in a DebugFS directory with the provided name, and c= ontents from invoking + /// [`Display::fmt`] on the provided reference. + /// + /// # Examples + /// + /// ``` + /// # use kernel::c_str; + /// # use kernel::debugfs::Dir; + /// let dir =3D Dir::new(c_str!("my_debugfs_dir")); + /// dir.display_file(c_str!("foo"), &200); + /// // "my_debugfs_dir/foo" now contains the number 200. + /// ``` + pub fn display_file(&self, name: &CStr, dat= a: &'static T) -> File { + self.create_file(name, data) + } + /// Create a new directory in DebugFS at the root. /// /// # Examples @@ -88,3 +144,9 @@ pub fn new(name: &CStr) -> Self { Dir::create(name, None) } } + +/// Handle to a DebugFS file. +pub struct File { + #[cfg(CONFIG_DEBUG_FS)] + _entry: Entry, +} diff --git a/rust/kernel/debugfs/display_file.rs b/rust/kernel/debugfs/disp= lay_file.rs new file mode 100644 index 0000000000000000000000000000000000000000..2a58ca2685258b050089e4cfd62= 188885f7f5f04 --- /dev/null +++ b/rust/kernel/debugfs/display_file.rs @@ -0,0 +1,63 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (C) 2025 Google LLC. + +use crate::prelude::*; +use crate::seq_file::SeqFile; +use crate::seq_print; +use core::fmt::Display; + +/// 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 wi= ll outlive the `inode` +/// and will not have any unique references alias it during the call. +/// * `file` must point to a live, not-yet-initialized file object. +pub(crate) unsafe extern "C" fn display_open( + inode: *mut bindings::inode, + file: *mut bindings::file, +) -> c_int { + // SAFETY: + // * `file` is acceptable by caller precondition. + // * `print_act` will be called on a `seq_file` with private data set = to the third argument, + // so we meet its safety requirements. + // * The `data` pointer passed in the third argument is a valid `T` po= inter that outlives + // this call by caller preconditions. + unsafe { 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 poi= nter to a `T` which may +/// not have any unique references alias it during the call. +pub(crate) unsafe extern "C" fn display_act( + seq: *mut bindings::seq_file, + _: *mut c_void, +) -> c_int { + // SAFETY: By caller precondition, this pointer is live, points to a v= alue of type `T`, and + // there are not and will not be any unique references until we are do= ne. + let data =3D unsafe { &*((*seq).private as *mut T) }; + // SAFETY: By caller precondition, `seq_file` points to a live `seq_fi= le`, 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. +pub(crate) trait DisplayFile { + const VTABLE: bindings::file_operations; +} + +impl DisplayFile for T { + const VTABLE: bindings::file_operations =3D bindings::file_operations { + read: Some(bindings::seq_read), + llseek: Some(bindings::seq_lseek), + release: Some(bindings::single_release), + open: Some(display_open::), + // SAFETY: `file_operations` supports zeroes in all fields. + ..unsafe { core::mem::zeroed() } + }; +} diff --git a/rust/kernel/debugfs/entry.rs b/rust/kernel/debugfs/entry.rs index ae0e2c4e1d58e878ebb081a71e4ac0f4a7d99b91..2baaf31c326c3071b92b5bc3755= 2907fa1102246 100644 --- a/rust/kernel/debugfs/entry.rs +++ b/rust/kernel/debugfs/entry.rs @@ -38,6 +38,14 @@ pub(crate) unsafe fn new(entry: *mut bindings::dentry, p= arent: Option } } =20 + /// Constructs a placeholder DebugFS [`Entry`]. + pub(crate) fn empty() -> Self { + Self { + entry: core::ptr::null_mut(), + _parent: None, + } + } + /// Returns the pointer representation of the DebugFS directory. /// /// # Guarantees --=20 2.50.0.727.gbf7dc18ff4-goog From nobody Tue Oct 7 12:28:20 2025 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 BED14241680 for ; Wed, 9 Jul 2025 19:09:49 +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=1752088191; cv=none; b=ehNa3qQ3cjrPCLZYs5UgMmheR4nxMKTaGp/H/Kcy4dfmN/cy8SDqsL615JeAfyEzu89qOpgY0geCal4jjmdoRGYw3g7oa0GOBdyfjRmPs0q3W0WTBT3kAXHmbltfMlRszouHsq0sxYlsKwmHSGt2C7ivLqjjSTGuQqtJ69oMil4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752088191; c=relaxed/simple; bh=vClZs7+279+u3JU+CtWnditzSs55LyVZNeYQ3AsRgAc=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=Bv07SHxFbYw1xj7XQTRcew+muwJL8DPCPzFsBSDP4MJ2y+Avf/5XEH0mw58c98GIZ24AU2cT/rEWTKfEXUjy7Wa7no6q0Me0fndFdTlYFPwsOToOVl+pmqrZ2C1OZy9c9YexpDDwnlI1sWK4/PJ4H0FQyWsrcOU9OqKvJ3sPkN8= 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=yUu+Uqsx; 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="yUu+Uqsx" Received: by mail-pf1-f201.google.com with SMTP id d2e1a72fcca58-748efefedb5so157449b3a.2 for ; Wed, 09 Jul 2025 12:09:49 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1752088189; x=1752692989; 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=fkSaEMZguJnYB6nAxHEBOerDOjVtrb6rn4T/EUgMkSU=; b=yUu+UqsxZNF0zqaLRfgfJwPcYz70T5sZYG9uYZ2+gc5HlVXfmJm1Cn1v0uAiT3y3UR KECRL32OV2WEr72wxHJH8DK0wpPxgIhCeYsxmi2yY7yZQ1NqjpLaGLgfls+vBsvygQ4/ lv2ozB/NxLEgaoO6+44LQpiZsgyc9QLkzGYZWEx9F3TLx8PBs9miAMPs+pdaFPM8IvLm Wjn9L7+6pRHMFbeDiUaZjryw4ASWoNPPjlV2/499EkZOJhegXOW8cAHz/Wgf3uFRY9a4 1abzxPZmexVHlVkfgsfLtPVKjnj/q9uADe2Hl5TEIVakgn/AE7es40WgGZLfITzrefNP 7OUg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1752088189; x=1752692989; 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=fkSaEMZguJnYB6nAxHEBOerDOjVtrb6rn4T/EUgMkSU=; b=lAbFPKwiJIWs69CFCAWgsa+XoMSenMjOjpSqek/ytRbkrSpBdK/5ii76icTr1rc/kV X6Kpbxm66jQO3Fzp6bRBOgOD6bKF3Mar2OurWdGUYXSJeIg/6vvpYg2uaOXx+pJ1pHIs yCTrJGVLbWrTj3l+/nS4DJXSiChf+Sx1acVIDzZb1CdAG6aRsogDtjM4HItgzGKB4nNX 64EjiuJKDY9x0jrI71wUc23+S26ynCaOJTwxOQnaq/GT9iTnyOJghCqpOqZNy7MFOjvb Hzdh7dJ5ANCSrOSX6WTTbZfQCV3BhLqlGgQro0CNa0g9zv5lHG+UcFCtMSOsl9rhsiXI aCYQ== X-Gm-Message-State: AOJu0YzOoLfi4jmTXrWT50BPv7zSyV7+/8ecq5YUixFj+AugBdhFZm80 hrG+G5iniD8XoUx3cYRXEDR1cYBgTcetMNbBXdY99gFB6hq+oyd6HLLWX8zWCq8oDh6SVsNi4fE NW75g4Zr8EA== X-Google-Smtp-Source: AGHT+IGPmy9r7ClYGJvVeQ9QKH+1IkCG0m923xuq+x2n6wWf1oi7t0yeUoZQBGMXnxRwXvAsNTPmk+wh0sLj X-Received: from pfjc12.prod.google.com ([2002:a05:6a00:8c:b0:747:a8ac:ca05]) (user=mmaurer job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a20:a10e:b0:224:a21:6b6f with SMTP id adf61e73a8af0-22cd7d94079mr5853974637.28.1752088189192; Wed, 09 Jul 2025 12:09:49 -0700 (PDT) Date: Wed, 09 Jul 2025 19:09:30 +0000 In-Reply-To: <20250709-debugfs-rust-v9-0-92b9eab5a951@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250709-debugfs-rust-v9-0-92b9eab5a951@google.com> X-Developer-Key: i=mmaurer@google.com; a=ed25519; pk=2Ezhl7+fEjTOMVFpplDeak2AdQ8cjJieLRVJdNzrW+E= X-Developer-Signature: v=1; a=ed25519-sha256; t=1752088183; l=7928; i=mmaurer@google.com; s=20250429; h=from:subject:message-id; bh=vClZs7+279+u3JU+CtWnditzSs55LyVZNeYQ3AsRgAc=; b=I2Dn/DK2EUuyTL5PD7d+3bnQH3KCuBsbJflss1ZAg+25tZVwIu6tH7LK96VD6q5JrA+78BoMn k2OnS8ZpRCHCoxHgZ/Wo/qCIsR3GPbSIu5ldDEHwVq6bqkyKAF5QADW X-Mailer: b4 0.14.2 Message-ID: <20250709-debugfs-rust-v9-3-92b9eab5a951@google.com> Subject: [PATCH v9 3/5] rust: debugfs: Support `PinInit` backing for `File`s. From: Matthew Maurer To: Miguel Ojeda , Alex Gaynor , Boqun Feng , Gary Guo , "=?utf-8?q?Bj=C3=B6rn_Roy_Baron?=" , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Greg Kroah-Hartman , "Rafael J. Wysocki" , Sami Tolvanen , Timur Tabi , Benno Lossin 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 allows `File`s to own their data, allowing DebugFS files to be managed in sync with the data that backs them. Because DebugFS files are intended to actually own data and provide access, `File`s still maintain the same lifecycle for provided data when `CONFIG_DEBUG_FS` is disabled. Signed-off-by: Matthew Maurer --- rust/kernel/debugfs.rs | 149 ++++++++++++++++++++++++++++++++++++++-------= ---- 1 file changed, 117 insertions(+), 32 deletions(-) diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs index e5b6497d1deb67671d22ffd90cd5baa855bb9257..a1a84dd309216f455ae8fe3d3c0= fd00f957f82a9 100644 --- a/rust/kernel/debugfs.rs +++ b/rust/kernel/debugfs.rs @@ -5,12 +5,13 @@ //! //! C header: [`include/linux/debugfs.h`](srctree/include/linux/debugfs.h) =20 -#[cfg(CONFIG_DEBUG_FS)] -use crate::prelude::GFP_KERNEL; +use crate::prelude::*; use crate::str::CStr; #[cfg(CONFIG_DEBUG_FS)] use crate::sync::Arc; use core::fmt::Display; +use core::marker::PhantomPinned; +use core::ops::Deref; =20 #[cfg(CONFIG_DEBUG_FS)] mod display_file; @@ -63,40 +64,78 @@ fn create(_name: &CStr, _parent: Option<&Dir>) -> Self { } =20 #[cfg(CONFIG_DEBUG_FS)] - fn create_file(&self, name: &CStr, data: &'= static T) -> File { - let Some(parent) =3D &self.0 else { - return File { + /// Creates a DebugFS file which will own the data produced by the ini= tializer provided in + /// `data`. + /// + /// # Safety + /// + /// The provided vtable must be appropriate for implementing a seq_fil= e if provided + /// with a private data pointer which provides shared access to a `T`. + unsafe fn create_file<'a, T: Sync, E, TI: PinInit>( + &self, + name: &'a CStr, + data: TI, + vtable: &'static bindings::file_operations, + ) -> impl PinInit, E> + use<'_, 'a, T, E, TI> { + try_pin_init! { + File { _entry: Entry::empty(), + data <- data, + _pin: PhantomPinned, + } ? E + } + .pin_chain(|file| { + let Some(parent) =3D &self.0 else { + return Ok(()); }; - }; - // 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. - let ptr =3D unsafe { - bindings::debugfs_create_file_full( - name.as_char_ptr(), - 0o444, - parent.as_ptr(), - data as *const _ as *mut _, - core::ptr::null(), - &::VTABLE, - ) - }; =20 - // SAFETY: `debugfs_create_file_full` either returns an error code= or a legal - // dentry pointer, so `Entry::new` is safe to call here. - let entry =3D unsafe { Entry::new(ptr, Some(parent.clone())) }; + // SAFETY: + // * `name` is a NUL-terminated C string, living across the ca= ll, by `CStr` invariant. + // * `parent` is a live `dentry` since we have a reference to = it. + // * Since the file owns the `T` and it is pinned, we can safe= ly assume the pointer + // lives and is valid as long as we are. + // * Since the `Entry` will live in the `File`, it will be dro= pped before the pointer + // is invalidated. Dropping the `Entry` will remove the Debu= gFS file and avoid + // further access. + let ptr =3D unsafe { + bindings::debugfs_create_file_full( + name.as_char_ptr(), + 0o444, + parent.as_ptr(), + &file.data as *const _ as *mut c_void, + core::ptr::null(), + vtable, + ) + }; + + // SAFETY: `debugfs_create_file_full` either returns an error = code or a legal + // dentry pointer, so `Entry::new` is safe to call here. + *file.entry_mut() =3D unsafe { Entry::new(ptr, Some(parent.clo= ne())) }; =20 - File { _entry: entry } + Ok(()) + }) } =20 #[cfg(not(CONFIG_DEBUG_FS))] - fn create_file(&self, _name: &CStr, _data: = &'static T) -> File { - File {} + /// Creates a DebugFS file which will own the data produced by the ini= tializer provided in + /// `data`. + /// + /// # Safety + /// + /// As DebugFS is disabled, this is actually entirely safe. It is mark= ed unsafe for code + /// compatibility with the DebugFS-enabled variant. + unsafe fn create_file<'a, T: Sync, E, TI: PinInit>( + &self, + _name: &'a CStr, + data: TI, + _vtable: (), + ) -> impl PinInit, E> + use<'_, 'a, T, E, TI> { + try_pin_init! { + File { + data <- data, + _pin: PhantomPinned, + } ? E + } } =20 /// Create a DebugFS subdirectory. @@ -127,8 +166,32 @@ pub fn subdir(&self, name: &CStr) -> Self { /// dir.display_file(c_str!("foo"), &200); /// // "my_debugfs_dir/foo" now contains the number 200. /// ``` - pub fn display_file(&self, name: &CStr, dat= a: &'static T) -> File { - self.create_file(name, data) + /// + /// ``` + /// # use kernel::c_str; + /// # use kernel::debugfs::Dir; + /// # use kernel::prelude::*; + /// let val =3D KBox::new(300, GFP_KERNEL)?; + /// let dir =3D Dir::new(c_str!("my_debugfs_dir")); + /// dir.display_file(c_str!("foo"), val); + /// // "my_debugfs_dir/foo" now contains the number 300. + /// # Ok::<(), Error>(()) + /// ``` + pub fn display_file<'b, T: Display + Send + Sync, E, TI: PinInit= >( + &self, + name: &'b CStr, + data: TI, + ) -> impl PinInit, E> + use<'_, 'b, T, E, TI> { + #[cfg(CONFIG_DEBUG_FS)] + let vtable =3D &::VTABLE; + #[cfg(not(CONFIG_DEBUG_FS))] + let vtable =3D (); + + // SAFETY: `vtable` is all stock `seq_file` implementations except= for `open`. + // `open`'s only requirement beyond what is provided to all open f= unctions is that the + // inode's data pointer must point to a `T` that will outlive it, = which is provided by + // `create_file`'s safety requirements. + unsafe { self.create_file(name, data, vtable) } } =20 /// Create a new directory in DebugFS at the root. @@ -146,7 +209,29 @@ pub fn new(name: &CStr) -> Self { } =20 /// Handle to a DebugFS file. -pub struct File { +#[pin_data] +pub struct File { + // This order is load-bearing for drops - `_entry` must be dropped bef= ore `data`. #[cfg(CONFIG_DEBUG_FS)] _entry: Entry, + #[pin] + data: T, + // Even if `T` is `Unpin`, we still can't allow it to be moved. + #[pin] + _pin: PhantomPinned, +} + +#[cfg(CONFIG_DEBUG_FS)] +impl File { + fn entry_mut(self: Pin<&mut Self>) -> &mut Entry { + // SAFETY: _entry is not structurally pinned + unsafe { &mut Pin::into_inner_unchecked(self)._entry } + } +} + +impl Deref for File { + type Target =3D T; + fn deref(&self) -> &T { + &self.data + } } --=20 2.50.0.727.gbf7dc18ff4-goog From nobody Tue Oct 7 12:28:20 2025 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 8E859242D72 for ; Wed, 9 Jul 2025 19:09:51 +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=1752088193; cv=none; b=tOSbTQT+vmsfAV7285KSF9JkLqSTzdElY8cR6X267OqVzXNzOvCRKwxj/dKEquN3IPf3iOrI7OaPDfV4nOY2U2HnIOBu/VPbZ/bCjsg71yEdcPN/Kq3Oa0pSfTRYQ/GLER8hy6Lz67qyNUd/2M8s5gZ0WIk0QL0g1w1oT6fzGLY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752088193; c=relaxed/simple; bh=7IK1O/5Amrl0R0bRmZpGVYtUpbVxV03RaAkvF58lBNU=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=ctg2+NSVfW1vP7QaGADLgfrqg6IEC+nx0l6C7N21dtpg2/Z/YoDfQQJCtjpChVGRNrTpcsEmbbYMN/7NRY/bHcRWMUJN+0go/GVlpBJn0G6iGt4i1GYNdKhKFleIn1uNJGjLI539kt4EKChsioVUBjmu8r4fSTbe7kdfJGOx0iw= 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=N6KpdJu1; 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="N6KpdJu1" Received: by mail-pf1-f202.google.com with SMTP id d2e1a72fcca58-748b4d5c045so165526b3a.1 for ; Wed, 09 Jul 2025 12:09:51 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1752088191; x=1752692991; 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=ZiRlWSeoLIb9HFDXbg9k1oMY9yJt9AprT6ImWGiZWHg=; b=N6KpdJu1Sexz/mGZOerqrCQhAOQvcWvDiY/KQYaU/qtwxEF7otqm77HyXjOiepeFER 1/+IXg8jagiWG3UJKKH7ia2Q7B0mi1E4uQKywRibQ8cCJxvCcUAnaHfAlaGdZNkqirFW bkTDwQ55hXVAztFmE0HG/m2hTKz8/9hMTzj8HpkPET4ai34v7Gz9axwsH05rHaFbiAnP UO2yA5yXuMghM6/U5/OCWciiF73OMeITq7UD2yOJf7d1a5716Oay8imDczVJPRe48Bsy TwFclI2i0RGFL/QDqRhuNTXkIrsFs1WQ61NgczvpJuKXce3CDogfpPNrKva7K0bjCFQD Tz2g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1752088191; x=1752692991; 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=ZiRlWSeoLIb9HFDXbg9k1oMY9yJt9AprT6ImWGiZWHg=; b=nv/4k8vDti9z8W3fYurM61cyVkaTw2lL9ixEkT3UMG4oKV9f7+CZeKWxDmY0PKxE2i cvraWLygn5HyM03RxH9w+mp5hKLkHPf73OCn0OQmuMHdSOjARXIVyITOQbuRE9YvEWGW B51HI2kwdS7c7qO1Pu7MddJg2a8ZIAFVpLe96VISIHwm3jO7dnr0D5pbkRb19DRXlxPt CpQAefaHcFme+ktAyoVxqCsqN1M47o9IDsxIAoTYki3GQgM8osH+pLfyj5i3g8pnlSr+ h+JK/q8VqSU1khkqg8cWaY9Bj+3eiYkb6jqKVhCWQbdsGoUjeCbmLIEHySoBB+jX/o1A sMUQ== X-Gm-Message-State: AOJu0YxXi7rgByhLd8RY8+9mdJxH31EzstgHLRtWSs7SBJ1o2xXUCJBA qPjDyik69eos9JK6zRBqH/SPS3Jgpa4v30BZbOnf+OYabNGoq1Cqyz56nDgb91MzIpwq/IK6kc0 ZZMoBWYgtAg== X-Google-Smtp-Source: AGHT+IHN503Rj0ScL/6cOTUeQyfURQT+PFW4aGADN27aj9y2O6RunrX4n4WS88uUHeWI5W6/G096auKfcXUC X-Received: from pfblg25.prod.google.com ([2002:a05:6a00:7099:b0:746:1a2e:b29b]) (user=mmaurer job=prod-delivery.src-stubby-dispatcher) by 2002:a05:6a21:38c:b0:220:7cd5:e803 with SMTP id adf61e73a8af0-22cd719e18fmr7010579637.21.1752088190867; Wed, 09 Jul 2025 12:09:50 -0700 (PDT) Date: Wed, 09 Jul 2025 19:09:31 +0000 In-Reply-To: <20250709-debugfs-rust-v9-0-92b9eab5a951@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250709-debugfs-rust-v9-0-92b9eab5a951@google.com> X-Developer-Key: i=mmaurer@google.com; a=ed25519; pk=2Ezhl7+fEjTOMVFpplDeak2AdQ8cjJieLRVJdNzrW+E= X-Developer-Signature: v=1; a=ed25519-sha256; t=1752088183; l=5318; i=mmaurer@google.com; s=20250429; h=from:subject:message-id; bh=7IK1O/5Amrl0R0bRmZpGVYtUpbVxV03RaAkvF58lBNU=; b=Fy5lHm34IqwAx0oHmpPsUdSbyjH0UOrinaos8hd+g3B54hPnNaWo4OoS6UR2Uko+JNlXpev5k SGD6I4+XQAGBxdcbgWWQJWMu58qMc1I/8DfcFJRnbpspzfp+N7eYGeK X-Mailer: b4 0.14.2 Message-ID: <20250709-debugfs-rust-v9-4-92b9eab5a951@google.com> Subject: [PATCH v9 4/5] 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?=" , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Greg Kroah-Hartman , "Rafael J. Wysocki" , Sami Tolvanen , Timur Tabi , Benno Lossin 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 | 49 +++++++++++++++++++++++++++++++++= ++++ rust/kernel/debugfs/display_file.rs | 39 ++++++++++++++++++++++++++++- 2 files changed, 87 insertions(+), 1 deletion(-) diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs index a1a84dd309216f455ae8fe3d3c0fd00f957f82a9..083c49007cd7ae5b3d7954bf859= c24b7eb62d557 100644 --- a/rust/kernel/debugfs.rs +++ b/rust/kernel/debugfs.rs @@ -9,6 +9,7 @@ use crate::str::CStr; #[cfg(CONFIG_DEBUG_FS)] use crate::sync::Arc; +use core::fmt; use core::fmt::Display; use core::marker::PhantomPinned; use core::ops::Deref; @@ -194,6 +195,54 @@ pub fn display_file<'b, T: Display + Send + Sync, E, T= I: PinInit>( unsafe { self.create_file(name, data, vtable) } } =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-capturing closure, or this wi= ll fail to compile. + /// + /// # Examples + /// + /// ``` + /// # use core::sync::atomic::{AtomicU32, Ordering}; + /// # use kernel::c_str; + /// # use kernel::debugfs::Dir; + /// let dir =3D Dir::new(c_str!("foo")); + /// 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); + /// writeln!(f, "{out:#010x}") + /// }); + /// MY_ATOMIC.store(10, Ordering::Relaxed); + /// ``` + pub fn fmt_file< + 'b, + T: Send + Sync, + E, + TI: PinInit, + F: Fn(&T, &mut fmt::Formatter<'_>) -> fmt::Result + Send + Sync, + >( + &self, + name: &'b CStr, + data: TI, + _f: &'static F, + ) -> impl PinInit, E> + use<'_, 'b, T, TI, E, F> { + #[cfg(CONFIG_DEBUG_FS)] + let vtable =3D & as display_file= ::DisplayFile>::VTABLE; + #[cfg(not(CONFIG_DEBUG_FS))] + let vtable =3D (); + + // SAFETY: `vtable` is all stock `seq_file` implementations except= for `open`. + // `open`'s only requirement beyond what is provided to all open f= unctions is that the + // inode's data pointer must point to a `FormatAdapter` that= will outlive it. + // `create_file`'s safety requirements provide the lifetime aspect= of this, but we are + // using a private `T` pointer. This is legal because: + // 1. `FormatAdapter` is a `#[repr(transparent)]` wrapper ar= ound `T`, so the + // implicit transmute is legal. + // 2. The invariant in `FormatAdapter` that `F` is inhabited is up= held because we have + // `_f`, so constructing a `FormatAdapter is legal. + unsafe { self.create_file(name, data, vtable) } + } + /// Create a new directory in DebugFS at the root. /// /// # Examples diff --git a/rust/kernel/debugfs/display_file.rs b/rust/kernel/debugfs/disp= lay_file.rs index 2a58ca2685258b050089e4cfd62188885f7f5f04..6275283b9dabd8dae84a9335c88= 32e7943707d56 100644 --- a/rust/kernel/debugfs/display_file.rs +++ b/rust/kernel/debugfs/display_file.rs @@ -4,7 +4,8 @@ use crate::prelude::*; use crate::seq_file::SeqFile; use crate::seq_print; -use core::fmt::Display; +use core::fmt::{Display, Formatter, Result}; +use core::marker::PhantomData; =20 /// Implements `open` for `file_operations` via `single_open` to fill out = a `seq_file`. /// @@ -61,3 +62,39 @@ impl DisplayFile for T { ..unsafe { core::mem::zeroed() } }; } + +/// Adapter to implement `Display` via a callback with the same representa= tion as `T`. +/// +/// # Invariants +/// +/// If an instance for `FormatAdapter<_, F>` is constructed, `F` is inhabi= ted. +#[repr(transparent)] +pub(crate) struct FormatAdapter { + inner: D, + _formatter: PhantomData, +} + +impl Display for FormatAdapter +where + F: Fn(&D, &mut Formatter<'_>) -> Result + 'static, +{ + fn fmt(&self, fmt: &mut Formatter<'_>) -> 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) + } +} + +/// For types with a unique value, produce a static reference to it. +/// +/// # Safety +/// +/// The caller asserts that F is inhabited +unsafe fn materialize_zst_fmt() -> &'static F { + const { assert!(core::mem::size_of::() =3D=3D 0) }; + let zst_dangle: core::ptr::NonNull =3D core::ptr::NonNull::dangling= (); + // SAFETY: While the pointer is dangling, it is a dangling pointer to = a ZST, based on the + // 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.50.0.727.gbf7dc18ff4-goog From nobody Tue Oct 7 12:28:20 2025 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 EEA0124336B for ; Wed, 9 Jul 2025 19:09:52 +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=1752088194; cv=none; b=Y9ZJI5z6EVQXwdOQXHmwzd4bn5tFRmrBnytqqnKC2CNU90uK6Cf9e/JcMMBsmYlWSTW3sAaPlfUUKzRBR02XTqJf10obad/Ezva5kmII5IjYIuxX5Ds9qrX8h2IGBzlaEWMOi1GnZYgnrNfevpCbuASddMiQiC9UftMMk0Y1XXo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1752088194; c=relaxed/simple; bh=AR0B3SprU80VUaI4tnKzWxLHs4hGBKduSVO4uwQ1dWg=; h=Date:In-Reply-To:Mime-Version:References:Message-ID:Subject:From: To:Cc:Content-Type; b=MlLt8eRrG/agZ59nu5MbEnYCY0hdruxPNdmo1y8tsfHNyUCKfk5fcsrtav+jaTwNvorlu+0N0pRO/097XT3poHFykHg0rUm8/kfOr2snJLNRtshk2x3KhhrQskdrLl2z5g4wMLd6Ad1Ex5MJdOstAOK+KLvBeVOqx57UveFaG9M= 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=EoinKLL/; 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="EoinKLL/" Received: by mail-pl1-f202.google.com with SMTP id d9443c01a7336-23dc7d3e708so963875ad.3 for ; Wed, 09 Jul 2025 12:09:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1752088192; x=1752692992; 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=vxBPqQEUhgd0jy+znq+ym2P4RbM+yShsSJqD7O7h4bQ=; b=EoinKLL/vxA525phTgQ00WlUkYQ6CENIze1roRMZSW9/V+Bjw8dMDuFYYHo1yWDz6R bECXYhH+wua7R4YVbIa1UpgcEIseBUHXL2LuROlqcyAzn1ucwCiialRiJ05c1J9UjG+R IzFrs4kuArvZfVtxOvb28+BCK/ZKkfBeIEO0bAeizfHDOgTeujO2FzUj8EYdyCtfKrp/ lGRGWDH9mbVl4pw4yxcYnuiYPIHL7YFVBLQMb0o28XvaE2VewPFtZbovKv8Bxi3l7r1s PRlZQ4hDpT5yl2zl1Uee9hI9FTaahwPcNyaU90RQ1XMsjKkvo9/fOZe1grjBozV8T5ie x+Ng== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1752088192; x=1752692992; 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=vxBPqQEUhgd0jy+znq+ym2P4RbM+yShsSJqD7O7h4bQ=; b=vL/Yp02KRm5MFYbOlaTUQ1iqTbE5S1a9bsxT1nINZPjUXvSRLh6gOiA26FHTv4fgD6 5o1yMSZeurUlmhXzt2N7mZ3yKl2qoZGH1jRJAOdVL+p5HIC80BCrzEku3yCejf9IlzOr za+1g4QM0NjaIyNSgfLC4syS9NehKfF3UfTIEvIwzelot2uUxxNnmAFGadG1g1pKJd5q Yq8lcOzvIkebM4300pdeVDql5/AKXhPVa7WkqIzsLuTbfpOsfrb0Cx4K1e8+nfSQltQa mB/RGKS3/ikDCMAAVSeWY6VLLp0+cD28gBnf6dmzTvE0bMGUGRT8xLFnR3OzThxoXgjo IoHA== X-Gm-Message-State: AOJu0YzNygqxzAsXMw8EQDvTpSdxNaxDFDg6sWLlsMlOYC9giegyMrYA ST7KT5XDg4lRmvAejrvQvCQmISnfEHucoAVxMz9DUATw+QI83IqcpqWv2V7cXjebob/KK8hvkQP trArD3KzCFw== X-Google-Smtp-Source: AGHT+IHyHsQrHTD6Qk6o6qOwYHWyJ1p0XxWiWzJNGaE5RYZ2PCyNLexaz4jFcSo4K6HpvzF2n/10ueZQwOY3 X-Received: from plblg14.prod.google.com ([2002:a17:902:fb8e:b0:235:f4e3:ba29]) (user=mmaurer job=prod-delivery.src-stubby-dispatcher) by 2002:a17:902:e885:b0:234:d399:f948 with SMTP id d9443c01a7336-23ddb2f1a47mr58637115ad.33.1752088192329; Wed, 09 Jul 2025 12:09:52 -0700 (PDT) Date: Wed, 09 Jul 2025 19:09:32 +0000 In-Reply-To: <20250709-debugfs-rust-v9-0-92b9eab5a951@google.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: Mime-Version: 1.0 References: <20250709-debugfs-rust-v9-0-92b9eab5a951@google.com> X-Developer-Key: i=mmaurer@google.com; a=ed25519; pk=2Ezhl7+fEjTOMVFpplDeak2AdQ8cjJieLRVJdNzrW+E= X-Developer-Signature: v=1; a=ed25519-sha256; t=1752088183; l=8478; i=mmaurer@google.com; s=20250429; h=from:subject:message-id; bh=AR0B3SprU80VUaI4tnKzWxLHs4hGBKduSVO4uwQ1dWg=; b=FGLdEjOdFMaYqdf9QqUzH0XSvY2yutpAM4KSEPX7j36Dz+KRnCFXzR4SFgHk3vkrvnXvz1Cu+ CMsWBia64ffBUR1mXfCNQYKEO6Rz0IdZKVMbh29I66TqftxEHi5w84p X-Mailer: b4 0.14.2 Message-ID: <20250709-debugfs-rust-v9-5-92b9eab5a951@google.com> Subject: [PATCH v9 5/5] 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?=" , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Greg Kroah-Hartman , "Rafael J. Wysocki" , Sami Tolvanen , Timur Tabi , Benno Lossin 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 | 182 +++++++++++++++++++++++++++++++++++++++= ++++ 4 files changed, 195 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index 1427af9d9779b1f6463409f4392e2900438bdc2a..0d9cb77b54b4608a0e1006ae457= 61ed7440495ba 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -7376,6 +7376,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 7f7371a004ee0a8f67dca99c836596709a70c4fa..01101db41ae31b08a86d048cdd2= 7da8ef9bb23a2 100644 --- a/samples/rust/Kconfig +++ b/samples/rust/Kconfig @@ -62,6 +62,17 @@ config SAMPLE_RUST_DMA =20 If unsure, say N. =20 +config SAMPLE_RUST_DEBUGFS + tristate "DebugFS Test Module" + depends on DEBUG_FS + help + This option builds the Rust DebugFS Test module 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 bd2faad63b4f3befe7d1ed5139fe25c7a8b6d7f6..61276222a99f8cc6d7f84c26d05= 33b30815ebadd 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..21fbf26f7ec07fabad782915046= da3cdf52b03b3 --- /dev/null +++ b/samples/rust/rust_debugfs.rs @@ -0,0 +1,182 @@ +// SPDX-License-Identifier: GPL-2.0 + +// Copyright (C) 2025 Google LLC. + +//! Sample DebugFS exporting platform driver +//! +//! To successfully probe this driver with ACPI, use an ssdt that looks li= ke +//! +//! ```dsl +//! DefinitionBlock ("", "SSDT", 2, "TEST", "VIRTACPI", 0x00000001) +//!{ +//! Scope (\_SB) +//! { +//! Device (T432) +//! { +//! Name (_HID, "LNUXDEBF") // ACPI hardware ID to match +//! Name (_UID, 1) +//! Name (_STA, 0x0F) // Device present, enabled +//! Name (_DSD, Package () { // Sample attribute +//! ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"), +//! Package() { +//! Package(2) {"compatible", "sample-debugfs"} +//! } +//! }) +//! Name (_CRS, ResourceTemplate () +//! { +//! Memory32Fixed (ReadWrite, 0xFED00000, 0x1000) +//! }) +//! } +//! } +//!} +//! ``` + +use core::sync::atomic::AtomicUsize; +use core::sync::atomic::Ordering; +use kernel::c_str; +use kernel::debugfs::{Dir, File}; +use kernel::new_mutex; +use kernel::prelude::*; +use kernel::sync::Mutex; + +use kernel::{acpi, device::Core, of, platform, str::CString, types::ARef}; + +kernel::module_platform_driver! { + type: Wrapper, + name: "rust_debugfs", + authors: ["Matthew Maurer"], + description: "Rust DebugFS usage sample", + license: "GPL", +} + +// This data structure would be unlikely to be there in a real driver - it= 's to hook up mutation +// that would normally be driven by whatever the driver was actually servi= cing and show how that +// would work. We're assuming here that those methods would have access to= a `&RustDebugFs`. +#[pin_data] +struct Wrapper { + _dir: Dir, + #[pin] + _wrapped: File>, +} + +#[pin_data] +struct RustDebugFs { + pdev: ARef, + // As we only hold these for drop effect (to remove the directory/file= s) we have a leading + // underscore to indicate to the compiler that we don't expect to use = this field directly. + _debugfs: Dir, + #[pin] + _compatible: File, + #[pin] + counter: File>, + #[pin] + inner: File>, +} + +#[derive(Debug)] +struct Inner { + x: u32, + y: u32, +} + +kernel::of_device_table!( + OF_TABLE, + MODULE_OF_TABLE, + ::IdInfo, + [(of::DeviceId::new(c_str!("test,rust-debugfs-device")), ())] +); + +kernel::acpi_device_table!( + ACPI_TABLE, + MODULE_ACPI_TABLE, + ::IdInfo, + [(acpi::DeviceId::new(c_str!("LNUXDEBF")), ())] +); + +impl platform::Driver for Wrapper { + type IdInfo =3D (); + const OF_ID_TABLE: Option> =3D Some(&OF_TABL= E); + const ACPI_ID_TABLE: Option> =3D Some(&ACP= I_TABLE); + + fn probe( + pdev: &platform::Device, + _info: Option<&Self::IdInfo>, + ) -> Result>> { + KBox::try_pin_init(Wrapper::new(RustDebugFs::new(pdev)), GFP_KERNE= L) + } +} + +impl Wrapper { + /// This builds two debugfs files that would be unusual to exist in th= e real world to emulate + /// actions taken servicing the device. They trigger their action when= the debugfs file is + /// opened. + fn build_control>( + dir: &Dir, + init: I, + ) -> impl PinInit>, Error> + use<'_, I> { + let swap =3D dir.fmt_file(c_str!("swap"), init, &|sample, fmt| { + let mut guard =3D sample.inner.lock(); + let x =3D guard.x; + guard.x =3D guard.y; + guard.y =3D x; + writeln!(fmt, "Swapped!") + }); + + dir.fmt_file(c_str!("add_counter"), swap, &|sample, fmt| { + let mut inner =3D sample.inner.lock(); + inner.x +=3D sample.counter.load(Ordering::Relaxed) as u32; + writeln!(fmt, "Counter added!") + }) + } + + fn new>(init: I) -> impl PinInit + use { + let dir =3D Dir::new(c_str!("sample_control")); + try_pin_init! { + Self { + _wrapped <- Wrapper::build_control(&dir, init), + _dir: dir, + } ? Error + } + } +} + +impl RustDebugFs { + fn build_counter(dir: &Dir) -> impl PinInit>> += use<'_> { + let counter =3D dir.fmt_file(c_str!("counter"), AtomicUsize::new(0= ), &|counter, fmt| { + writeln!(fmt, "{}", counter.load(Ordering::Relaxed)) + }); + dir.fmt_file(c_str!("inc_counter"), counter, &|counter, fmt| { + writeln!(fmt, "{}", counter.fetch_add(1, Ordering::Relaxed)) + }) + } + + fn build_inner(dir: &Dir) -> impl PinInit>> + use<'_= > { + dir.fmt_file( + c_str!("pair"), + new_mutex!(Inner { x: 3, y: 10 }), + &|i, fmt| writeln!(fmt, "{:?}", *i.lock()), + ) + } + + fn new(pdev: &platform::Device) -> impl PinInit + u= se<'_> { + let debugfs =3D Dir::new(c_str!("sample_debugfs")); + let dev =3D pdev.as_ref(); + + try_pin_init! { + Self { + _compatible <- debugfs.fmt_file( + c_str!("compatible"), + dev.fwnode() + .ok_or(ENOENT)? + .property_read::(c_str!("compatible")) + .required_by(dev)?, + &|cs, w| writeln!(w, "{cs:?}"), + ), + counter <- Self::build_counter(&debugfs), + inner <- Self::build_inner(&debugfs), + _debugfs: debugfs, + pdev: pdev.into(), + } + } + } +} --=20 2.50.0.727.gbf7dc18ff4-goog