From 22018a5a54a3d353bf0fee7364b2b8018ed4c5a6 Mon Sep 17 00:00:00 2001 From: Alice Ryhl Date: Tue, 1 Oct 2024 09:07:02 +0000 Subject: [PATCH] rust: add seqfile abstraction This adds a simple seq file abstraction that lets you print to a seq file using ordinary Rust printing syntax. An example user from Rust Binder: pub(crate) fn full_debug_print( &self, m: &SeqFile, owner_inner: &mut ProcessInner, ) -> Result<()> { let prio = self.node_prio(); let inner = self.inner.access_mut(owner_inner); seq_print!( m, " node {}: u{:016x} c{:016x} pri {}:{} hs {} hw {} cs {} cw {}", self.debug_id, self.ptr, self.cookie, prio.sched_policy, prio.prio, inner.strong.has_count, inner.weak.has_count, inner.strong.count, inner.weak.count, ); if !inner.refs.is_empty() { seq_print!(m, " proc"); for node_ref in &inner.refs { seq_print!(m, " {}", node_ref.process.task.pid()); } } seq_print!(m, "\n"); for t in &inner.oneway_todo { t.debug_print_inner(m, " pending async transaction "); } Ok(()) } The `SeqFile` type is marked not thread safe so that `call_printf` can be a `&self` method. The alternative is to use `self: Pin<&mut Self>` which is inconvenient, or to have `SeqFile` wrap a pointer instead of wrapping the C struct directly. Signed-off-by: Alice Ryhl Link: https://lore.kernel.org/r/20241001-seqfile-v1-1-dfcd0fc21e96@google.com Signed-off-by: Christian Brauner --- rust/kernel/lib.rs | 1 + rust/kernel/seq_file.rs | 52 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 rust/kernel/seq_file.rs diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 22785422ac8b..9843eedd4293 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -48,6 +48,7 @@ pub mod prelude; pub mod print; pub mod rbtree; pub mod security; +pub mod seq_file; pub mod sizes; mod static_assert; #[doc(hidden)] diff --git a/rust/kernel/seq_file.rs b/rust/kernel/seq_file.rs new file mode 100644 index 000000000000..6ca29d576d02 --- /dev/null +++ b/rust/kernel/seq_file.rs @@ -0,0 +1,52 @@ +// SPDX-License-Identifier: GPL-2.0 + +//! Seq file bindings. +//! +//! C header: [`include/linux/seq_file.h`](srctree/include/linux/seq_file.h) + +use crate::{bindings, c_str, types::NotThreadSafe, types::Opaque}; + +/// A utility for generating the contents of a seq file. +#[repr(transparent)] +pub struct SeqFile { + inner: Opaque, + _not_send: NotThreadSafe, +} + +impl SeqFile { + /// Creates a new [`SeqFile`] from a raw pointer. + /// + /// # Safety + /// + /// The caller must ensure that for the duration of 'a the following is satisfied: + /// * The pointer points at a valid `struct seq_file`. + /// * The `struct seq_file` is not accessed from any other thread. + pub unsafe fn from_raw<'a>(ptr: *mut bindings::seq_file) -> &'a SeqFile { + // SAFETY: The caller ensures that the reference is valid for 'a. There's no way to trigger + // a data race by using the `&SeqFile` since this is the only thread accessing the seq_file. + // + // CAST: The layout of `struct seq_file` and `SeqFile` is compatible. + unsafe { &*ptr.cast() } + } + + /// Used by the [`seq_print`] macro. + pub fn call_printf(&self, args: core::fmt::Arguments<'_>) { + // SAFETY: Passing a void pointer to `Arguments` is valid for `%pA`. + unsafe { + bindings::seq_printf( + self.inner.get(), + c_str!("%pA").as_char_ptr(), + &args as *const _ as *const core::ffi::c_void, + ); + } + } +} + +/// Write to a [`SeqFile`] with the ordinary Rust formatting syntax. +#[macro_export] +macro_rules! seq_print { + ($m:expr, $($arg:tt)+) => ( + $m.call_printf(format_args!($($arg)+)) + ); +} +pub use seq_print;