From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mail-lj1-f177.google.com (mail-lj1-f177.google.com [209.85.208.177]) (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 401D825C6F9 for ; Thu, 1 Jan 2026 05:21:52 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.208.177 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767244916; cv=none; b=aUqoOy5EltAvaIRIK0rXQgzPRynPk4PSGQ2zmKzBUDsCc5i7vHhdtkO0jNpV6JP51F7god+du/gvMEfbMAl+XJARozpHHupATdPN9WNkXGE1Up/0JBYCTTmKBvw4VRoVj+sjE80BttK5ozfcwJbAxKgGAC8/hldM6xBMUCbqACQ= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1767244916; c=relaxed/simple; bh=7rhNZKoiKt69rXYOx/nPj8NyhjOaV5my4mHPW2W+MJo=; h=From:Date:Subject:MIME-Version:Content-Type:Message-Id:References: In-Reply-To:To:Cc; b=X8V+cj0cjeKOUoNSBu3f9A+KMM+F3pxcIulOEThIr67U9YhflbwDbkBB02SXRwkj/x50j7ejw5dTn8E8o++hw61PedZBn3/rCABSEfrZhhMEwurJWJE+mmemN7aFLCjTD5GyqyvJNgLdALOR7apWLG+69EbNljXACYzYXPt/Fog= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=lr2pmb9f; arc=none smtp.client-ip=209.85.208.177 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="lr2pmb9f" Received: by mail-lj1-f177.google.com with SMTP id 38308e7fff4ca-37b495ce059so85597291fa.0 for ; Wed, 31 Dec 2025 21:21:52 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1767244911; x=1767849711; darn=vger.kernel.org; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:from:to:cc:subject:date:message-id :reply-to; bh=ZnWuhRewCBtlepNlYLvDYAkJsMsIyPpraMiTNGgUITs=; b=lr2pmb9fBA3ugs/QR3Y2DjR/7jhhFex3Bml0m8fWx3JIlEE/Naj4CCVxWlbFOY5qSf 4xsINTZRn4KBLoC6EWlnV/FJdu+6fNEbdvkPPpwPMYWa+LKygDQK2iWWV9FVWg+RQgtx 2bWp5goviPCxIL9+m2T6KC4zxzmvi6kIQGreyl3kD2kDWjHEjZr1+TBU6rjBaCmU4Zrk oFkxvaaooR7/DOjrZmPFHWEmow+5xJLqXjQT9NHsMWdAX34K8fiMfI2AO6n6yoWLVNsD DVMi360hK39YLVb8Oo88j+nlXyvZh3yeOlQtuUsmBFfd7ubmHBvukKn/QdrbVxT7VunQ 5fdA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1767244911; x=1767849711; h=cc:to:in-reply-to:references:message-id:content-transfer-encoding :mime-version:subject:date:from:x-gm-gg:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=ZnWuhRewCBtlepNlYLvDYAkJsMsIyPpraMiTNGgUITs=; b=can+4A6fXdV4KiqlvZU3W51O6McQe8urFproCbLycovL7D0deuQaHmieWdRXkEmUyl ocmlWKUO0Pe3vMDMyGOCDlV7tw5z+DBSaM4pt9LxtDLLMIyehQMiEfSFebM4P2nAzZW0 BO3QGxLiTievnf17MRAgArTWhTEyfjqP9mgRPIS93sKM2MeBcDbSyGLmzlOaFe3zmzL/ COLP3CrTythMlwMVaHDTX0a8B+EE5xFciUl99ps711nyoEy+djE2esF7uipNA9qtpqAG xpT6TuSnOlzr6AusZ/XhUJXMlCTw+cszxHciFs9KSpAeawpDO2FuijMHWXRbVVY9663W lryA== X-Forwarded-Encrypted: i=1; AJvYcCWcJbUgKj/OUekNE7qgB9tarkamiKYj1MgPUtCYFCOOVu4XdfyXRZzJ4yyA81+kDByRtmdw/snHkA23MZFtcQ==@vger.kernel.org X-Gm-Message-State: AOJu0YxHnMtyZa8QLXVf32NemZoJAA1PoU/I1yqHSFzloY4e5n8h58LF 2Y6VJ2iuUX5KZE6M04gaO2ZOtogoL91wdYSbVBy/vz243Br3IZl9Izxp X-Gm-Gg: AY/fxX5QV3pMgkJOXwUpJ/qe/1yuxN6NVGCX/54rdF/G6B/4pV6mSrl8PAkgW2ek5JF f9ORvoupzLOBdydApxj91wm6lUj2TZj21q4e94o69IuYFIjWEiW+DCN7B74E6UeUIXKyZQmXBIK Waz54JzyjldG1dk9L7an0d1cI9PcjrbJ1ZGtsQfUL4qNxFkSbRGaBFyqkP3lgJ+QRkN8rm8XG40 k9D2OVpj8+9nv6KK3Ehvx4L16gsf05xrVytOEV0MUA5okmPkNmSuioxNflR24ZK7OOYHULSkVB/ Upwjpe2MJAepMwOxPyrPoklLQeN1ROF0aRb6xwbOmlZZ3/bXpu7dbvmmaQWH0C+iPQA0iIDVvYr QJlCVvVEHRQq0uqUzcNkSUzvdDBR1idZ++27TFj/0vuxNLPBzdqOcNGr6XMlylXztX9aFSk4CPc q2ljZ8uq5EyzDQGET8vNa+PpCiGki7DZ3HeZmqdU1NeUPhy3W41IhciX+5dd54ahIQTYD82Cm5F 9YsD7lvUA3YcVIL X-Google-Smtp-Source: AGHT+IGWnxKTzBFDRvVhBJLkPNrg5zCvovKVt3Iq5ajcHW0NwDfpLyHHuTaAQOvw6Ai3P24W4z2g9Q== X-Received: by 2002:a05:651c:1443:b0:382:4d6b:993b with SMTP id 38308e7fff4ca-3824d6b9c18mr83313231fa.35.1767244910574; Wed, 31 Dec 2025 21:21:50 -0800 (PST) Received: from LT-5CG5341NQ4.nordic.imtech.com (84-253-216-54.bb.dnainternet.fi. [84.253.216.54]) by smtp.gmail.com with ESMTPSA id 38308e7fff4ca-382861ef4ccsm37064921fa.23.2025.12.31.21.21.46 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Wed, 31 Dec 2025 21:21:48 -0800 (PST) From: Kari Argillander Date: Thu, 01 Jan 2026 07:20:49 +0200 Subject: [PATCH RFC 5/6] rust: debugfs: WIP: Use owner for file_operations Precedence: bulk X-Mailing-List: rust-for-linux@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: 7bit Message-Id: <20260101-this_module_fix-v1-5-46ae3e5605a0@gmail.com> References: <20260101-this_module_fix-v1-0-46ae3e5605a0@gmail.com> In-Reply-To: <20260101-this_module_fix-v1-0-46ae3e5605a0@gmail.com> To: Miguel Ojeda , Boqun Feng , Gary Guo , =?utf-8?q?Bj=C3=B6rn_Roy_Baron?= , Benno Lossin , Andreas Hindborg , Alice Ryhl , Trevor Gross , Danilo Krummrich , Alexandre Courbot Cc: Greg Kroah-Hartman , rust-for-linux@vger.kernel.org, linux-kernel@vger.kernel.org, linux-modules@vger.kernel.org, Luis Chamberlain , Petr Pavlu , Daniel Gomez , Sami Tolvanen , Aaron Tomlin , Jens Axboe , Kari Argillander , Andreas Hindborg X-Mailer: b4 0.14.3 X-Developer-Signature: v=1; a=ed25519-sha256; t=1767244881; l=16426; i=kari.argillander@gmail.com; s=20251219; h=from:subject:message-id; bh=7rhNZKoiKt69rXYOx/nPj8NyhjOaV5my4mHPW2W+MJo=; b=/FHxPndxLye7RpOlj19HW54w3416yImg7K+iPDUzBUCprQvFxJNDtczJD3uQwfT7CmWNxIUe6 6iglF8d4oCDCqSX4wSpusPl5a2PMwxaVFMFe5smUbzFzPC75Rg8FCPo X-Developer-Key: i=kari.argillander@gmail.com; a=ed25519; pk=RwSxyhTpE3z4sywdDbIkC3q33ZQLNyhYWxT44iTY6r4= --- rust/kernel/debugfs.rs | 79 ++++++++++++++++++++++------------------- rust/kernel/debugfs/file_ops.rs | 50 +++++++++++++++++++------- samples/rust/rust_debugfs.rs | 6 ++-- 3 files changed, 83 insertions(+), 52 deletions(-) diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs index facad81e8290..03e22b1cfa2b 100644 --- a/rust/kernel/debugfs.rs +++ b/rust/kernel/debugfs.rs @@ -6,7 +6,8 @@ //! C header: [`include/linux/debugfs.h`](srctree/include/linux/debugfs.h) // When DebugFS is disabled, many parameters are dead. Linting for this isn't helpful. -#![cfg_attr(not(CONFIG_DEBUG_FS), allow(unused_variables))] +// #![cfg_attr(not(CONFIG_DEBUG_FS), allow(unused_variables))] +#![allow(unused_variables)] use crate::fmt; use crate::prelude::*; @@ -46,27 +47,31 @@ // able to refer to us. In this case, we need to silently fail. All future child directories/files // will silently fail as well. #[derive(Clone)] -pub struct Dir(#[cfg(CONFIG_DEBUG_FS)] Option>>); +pub struct Dir( + #[cfg(CONFIG_DEBUG_FS)] Option>>, + PhantomData, +); -impl Dir { +impl Dir { /// Create a new directory in DebugFS. If `parent` is [`None`], it will be created at the root. - fn create(name: &CStr, parent: Option<&Dir>) -> Self { + fn create(name: &CStr, parent: Option<&Self>) -> Self { #[cfg(CONFIG_DEBUG_FS)] { let parent_entry = match parent { // If the parent couldn't be allocated, just early-return - Some(Dir(None)) => return Self(None), - Some(Dir(Some(entry))) => Some(entry.clone()), + Some(Self(None, _)) => return Self(None, PhantomData), + Some(Self(Some(entry), _)) => Some(entry.clone()), None => None, }; Self( // If Arc creation fails, the `Entry` will be dropped, so the directory will be // cleaned up. Arc::new(Entry::dynamic_dir(name, parent_entry), GFP_KERNEL).ok(), + PhantomData, ) } #[cfg(not(CONFIG_DEBUG_FS))] - Self() + Self(PhantomData) } /// Creates a DebugFS file which will own the data produced by the initializer provided in @@ -107,7 +112,7 @@ fn create_file<'a, T, E: 'a>( /// let debugfs = Dir::new(c_str!("parent")); /// ``` pub fn new(name: &CStr) -> Self { - Dir::create(name, None) + Self::create(name, None) } /// Creates a subdirectory within this directory. @@ -121,7 +126,7 @@ pub fn new(name: &CStr) -> Self { /// let child = parent.subdir(c_str!("child")); /// ``` pub fn subdir(&self, name: &CStr) -> Self { - Dir::create(name, Some(self)) + Self::create(name, Some(self)) } /// Creates a read-only file in this directory. @@ -149,7 +154,7 @@ pub fn read_only_file<'a, T, E: 'a>( where T: Writer + Send + Sync + 'static, { - let file_ops = &>::FILE_OPS; + let file_ops = &>::FILE_OPS; self.create_file(name, data, file_ops) } @@ -176,7 +181,7 @@ pub fn read_binary_file<'a, T, E: 'a>( where T: BinaryWriter + Send + Sync + 'static, { - self.create_file(name, data, &T::FILE_OPS) + self.create_file(name, data, &>::FILE_OPS) } /// Creates a read-only file in this directory, with contents from a callback. @@ -215,7 +220,7 @@ pub fn read_callback_file<'a, T, E: 'a, F>( T: Send + Sync + 'static, F: Fn(&T, &mut fmt::Formatter<'_>) -> fmt::Result + Send + Sync, { - let file_ops = >::FILE_OPS.adapt(); + let file_ops = as ReadFile>>::FILE_OPS.adapt(); self.create_file(name, data, file_ops) } @@ -231,7 +236,7 @@ pub fn read_write_file<'a, T, E: 'a>( where T: Writer + Reader + Send + Sync + 'static, { - let file_ops = &>::FILE_OPS; + let file_ops = &>::FILE_OPS; self.create_file(name, data, file_ops) } @@ -247,7 +252,7 @@ pub fn read_write_binary_file<'a, T, E: 'a>( where T: BinaryWriter + BinaryReader + Send + Sync + 'static, { - let file_ops = &>::FILE_OPS; + let file_ops = &>::FILE_OPS; self.create_file(name, data, file_ops) } @@ -270,7 +275,7 @@ pub fn read_write_callback_file<'a, T, E: 'a, F, W>( W: Fn(&T, &mut UserSliceReader) -> Result + Send + Sync, { let file_ops = - , W> as file_ops::ReadWriteFile<_>>::FILE_OPS + , W> as file_ops::ReadWriteFile>::FILE_OPS .adapt() .adapt(); self.create_file(name, data, file_ops) @@ -290,7 +295,7 @@ pub fn write_only_file<'a, T, E: 'a>( where T: Reader + Send + Sync + 'static, { - self.create_file(name, data, &T::FILE_OPS) + self.create_file(name, data, &>::FILE_OPS) } /// Creates a write-only binary file in this directory. @@ -307,7 +312,7 @@ pub fn write_binary_file<'a, T, E: 'a>( where T: BinaryReader + Send + Sync + 'static, { - self.create_file(name, data, &T::FILE_OPS) + self.create_file(name, data, &>::FILE_OPS) } /// Creates a write-only file in this directory, with write logic from a callback. @@ -324,7 +329,7 @@ pub fn write_callback_file<'a, T, E: 'a, W>( T: Send + Sync + 'static, W: Fn(&T, &mut UserSliceReader) -> Result + Send + Sync, { - let file_ops = , W> as WriteFile<_>>::FILE_OPS + let file_ops = , W> as WriteFile>::FILE_OPS .adapt() .adapt(); self.create_file(name, data, file_ops) @@ -527,7 +532,7 @@ fn create_file(&self, name: &CStr, data: &'data T, vtable: &'static Fil /// file is removed when the [`Scope`] that this directory belongs /// to is dropped. pub fn read_only_file(&self, name: &CStr, data: &'data T) { - self.create_file(name, data, &T::FILE_OPS) + // self.create_file(name, data, &>::FILE_OPS) } /// Creates a read-only binary file in this directory. @@ -541,7 +546,7 @@ pub fn read_binary_file( name: &CStr, data: &'data T, ) { - self.create_file(name, data, &T::FILE_OPS) + // self.create_file(name, data, &>::FILE_OPS) } /// Creates a read-only file in this directory, with contents from a callback. @@ -560,8 +565,8 @@ pub fn read_callback_file(&self, name: &CStr, data: &'data T, _f: &'static T: Send + Sync + 'static, F: Fn(&T, &mut fmt::Formatter<'_>) -> fmt::Result + Send + Sync, { - let vtable = as ReadFile<_>>::FILE_OPS.adapt(); - self.create_file(name, data, vtable) + // let vtable = as ReadFile>::FILE_OPS.adapt(); + // self.create_file(name, data, vtable) } /// Creates a read-write file in this directory. @@ -577,8 +582,8 @@ pub fn read_write_file( name: &CStr, data: &'data T, ) { - let vtable = &>::FILE_OPS; - self.create_file(name, data, vtable) + // let vtable = &>::FILE_OPS; + // self.create_file(name, data, vtable) } /// Creates a read-write binary file in this directory. @@ -593,8 +598,8 @@ pub fn read_write_binary_file>::FILE_OPS; - self.create_file(name, data, vtable) + // let vtable = &>::FILE_OPS; + // self.create_file(name, data, vtable) } /// Creates a read-write file in this directory, with logic from callbacks. @@ -618,10 +623,10 @@ pub fn read_write_callback_file( F: Fn(&T, &mut fmt::Formatter<'_>) -> fmt::Result + Send + Sync, W: Fn(&T, &mut UserSliceReader) -> Result + Send + Sync, { - let vtable = , W> as ReadWriteFile<_>>::FILE_OPS - .adapt() - .adapt(); - self.create_file(name, data, vtable) + // let vtable = , W> as ReadWriteFile<_>>::FILE_OPS + // .adapt() + // .adapt(); + // self.create_file(name, data, vtable) } /// Creates a write-only file in this directory. @@ -632,8 +637,8 @@ pub fn read_write_callback_file( /// file is removed when the [`Scope`] that this directory belongs /// to is dropped. pub fn write_only_file(&self, name: &CStr, data: &'data T) { - let vtable = &>::FILE_OPS; - self.create_file(name, data, vtable) + // let vtable = &>::FILE_OPS; + // self.create_file(name, data, vtable) } /// Creates a write-only binary file in this directory. @@ -647,7 +652,7 @@ pub fn write_binary_file( name: &CStr, data: &'data T, ) { - self.create_file(name, data, &T::FILE_OPS) + // self.create_file(name, data, &>::FILE_OPS) } /// Creates a write-only file in this directory, with write logic from a callback. @@ -665,10 +670,10 @@ pub fn write_only_callback_file(&self, name: &CStr, data: &'data T, _w: &' T: Send + Sync + 'static, W: Fn(&T, &mut UserSliceReader) -> Result + Send + Sync, { - let vtable = &, W> as WriteFile<_>>::FILE_OPS - .adapt() - .adapt(); - self.create_file(name, data, vtable) + // let vtable = &, W> as WriteFile<_>>::FILE_OPS + // .adapt() + // .adapt(); + // self.create_file(name, data, vtable) } fn empty() -> Self { diff --git a/rust/kernel/debugfs/file_ops.rs b/rust/kernel/debugfs/file_ops.rs index 8a0442d6dd7a..0e5059c044af 100644 --- a/rust/kernel/debugfs/file_ops.rs +++ b/rust/kernel/debugfs/file_ops.rs @@ -115,13 +115,14 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { } // Work around lack of generic const items. -pub(crate) trait ReadFile { +pub(crate) trait ReadFile { const FILE_OPS: FileOps; } -impl ReadFile for T { +impl ReadFile for T { const FILE_OPS: FileOps = { let operations = bindings::file_operations { + owner: M::OWNER.as_ptr(), read: Some(bindings::seq_read), llseek: Some(bindings::seq_lseek), release: Some(bindings::single_release), @@ -167,13 +168,18 @@ fn read(data: &T, buf: *const c_char, count: usize) -> isize { } // A trait to get the file operations for a type. -pub(crate) trait ReadWriteFile { +pub(crate) trait ReadWriteFile { const FILE_OPS: FileOps; } -impl ReadWriteFile for T { +impl ReadWriteFile for T +where + M: ThisModule, + T: Writer + Reader + Sync, +{ const FILE_OPS: FileOps = { let operations = bindings::file_operations { + owner: M::OWNER.as_ptr(), open: Some(writer_open::), read: Some(bindings::seq_read), write: Some(write::), @@ -225,13 +231,18 @@ impl ReadWriteFile for T { read(data, buf, count) } -pub(crate) trait WriteFile { +pub(crate) trait WriteFile { const FILE_OPS: FileOps; } -impl WriteFile for T { +impl WriteFile for T +where + M: ThisModule, + T: Reader + Sync, +{ const FILE_OPS: FileOps = { let operations = bindings::file_operations { + owner: M::OWNER.as_ptr(), open: Some(write_only_open), write: Some(write_only_write::), llseek: Some(bindings::noop_llseek), @@ -278,13 +289,18 @@ extern "C" fn blob_read( } /// Representation of [`FileOps`] for read only binary files. -pub(crate) trait BinaryReadFile { +pub(crate) trait BinaryReadFile { const FILE_OPS: FileOps; } -impl BinaryReadFile for T { +impl BinaryReadFile for T +where + M: ThisModule, + T: BinaryWriter + Sync, +{ const FILE_OPS: FileOps = { let operations = bindings::file_operations { + owner: M::OWNER.as_ptr(), read: Some(blob_read::), llseek: Some(bindings::default_llseek), open: Some(bindings::simple_open), @@ -333,13 +349,18 @@ extern "C" fn blob_write( } /// Representation of [`FileOps`] for write only binary files. -pub(crate) trait BinaryWriteFile { +pub(crate) trait BinaryWriteFile { const FILE_OPS: FileOps; } -impl BinaryWriteFile for T { +impl BinaryWriteFile for T +where + M: ThisModule, + T: BinaryReader + Sync, +{ const FILE_OPS: FileOps = { let operations = bindings::file_operations { + owner: M::OWNER.as_ptr(), write: Some(blob_write::), llseek: Some(bindings::default_llseek), open: Some(bindings::simple_open), @@ -358,13 +379,18 @@ impl BinaryWriteFile for T { } /// Representation of [`FileOps`] for read/write binary files. -pub(crate) trait BinaryReadWriteFile { +pub(crate) trait BinaryReadWriteFile { const FILE_OPS: FileOps; } -impl BinaryReadWriteFile for T { +impl BinaryReadWriteFile for T +where + M: ThisModule, + T: BinaryWriter + BinaryReader + Sync, +{ const FILE_OPS: FileOps = { let operations = bindings::file_operations { + owner: M::OWNER.as_ptr(), read: Some(blob_read::), write: Some(blob_write::), llseek: Some(bindings::default_llseek), diff --git a/samples/rust/rust_debugfs.rs b/samples/rust/rust_debugfs.rs index 025e8f9d12de..85c3f93159fd 100644 --- a/samples/rust/rust_debugfs.rs +++ b/samples/rust/rust_debugfs.rs @@ -54,7 +54,7 @@ struct RustDebugFs { pdev: ARef, // As we only hold these for drop effect (to remove the directory/files) we have a leading // underscore to indicate to the compiler that we don't expect to use this field directly. - _debugfs: Dir, + _debugfs: Dir, #[pin] _compatible: File, #[pin] @@ -124,11 +124,11 @@ fn probe( } impl RustDebugFs { - fn build_counter(dir: &Dir) -> impl PinInit>> + '_ { + fn build_counter(dir: &Dir) -> impl PinInit>> + '_ { dir.read_write_file(c_str!("counter"), Atomic::::new(0)) } - fn build_inner(dir: &Dir) -> impl PinInit>> + '_ { + fn build_inner(dir: &Dir) -> impl PinInit>> + '_ { dir.read_write_file(c_str!("pair"), new_mutex!(Inner { x: 3, y: 10 })) } -- 2.43.0