From 3f9ebeba9878679bb43ee2db7d50a4691f55e3a5 Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Mon, 24 Mar 2025 14:18:34 +0800 Subject: rust: sync: Mark CondVar::notify_*() inline When build the kernel using the llvm-18.1.3-rust-1.85.0-x86_64 with ARCH=arm64, the following symbols are generated: $nm vmlinux | grep ' _R'.*CondVar | rustfilt ... T ::notify_all ... T ::notify_one ... T ::notify_sync ... These notify_*() symbols are trivial wrappers around the C functions __wake_up() and __wake_up_sync(). It doesn't make sense to go through a trivial wrapper for these functions, so mark them inline. [boqun: Reword the commit title for consistency and reformat the commit log.] Suggested-by: Alice Ryhl Link: https://github.com/Rust-for-Linux/linux/issues/1145 Co-developed-by: Grace Deng Signed-off-by: Grace Deng Signed-off-by: Kunwu Chan Reviewed-by: Benno Lossin Reviewed-by: Alice Ryhl Signed-off-by: Boqun Feng Link: https://lore.kernel.org/r/20250324061835.1693125-1-kunwu.chan@linux.dev --- rust/kernel/sync/condvar.rs | 3 +++ 1 file changed, 3 insertions(+) (limited to 'rust/kernel') diff --git a/rust/kernel/sync/condvar.rs b/rust/kernel/sync/condvar.rs index caebf03f553b..c6ec64295c9f 100644 --- a/rust/kernel/sync/condvar.rs +++ b/rust/kernel/sync/condvar.rs @@ -216,6 +216,7 @@ impl CondVar { /// This method behaves like `notify_one`, except that it hints to the scheduler that the /// current thread is about to go to sleep, so it should schedule the target thread on the same /// CPU. + #[inline] pub fn notify_sync(&self) { // SAFETY: `wait_queue_head` points to valid memory. unsafe { bindings::__wake_up_sync(self.wait_queue_head.get(), TASK_NORMAL) }; @@ -225,6 +226,7 @@ impl CondVar { /// /// This is not 'sticky' in the sense that if no thread is waiting, the notification is lost /// completely (as opposed to automatically waking up the next waiter). + #[inline] pub fn notify_one(&self) { self.notify(1); } @@ -233,6 +235,7 @@ impl CondVar { /// /// This is not 'sticky' in the sense that if no thread is waiting, the notification is lost /// completely (as opposed to automatically waking up the next waiter). + #[inline] pub fn notify_all(&self) { self.notify(0); } -- cgit v1.2.3 From 11867144ff81ab98f4b11c99716c3e8b714b8755 Mon Sep 17 00:00:00 2001 From: Kunwu Chan Date: Mon, 17 Mar 2025 10:52:05 +0800 Subject: rust: sync: Mark PollCondVar::drop() inline When building the kernel using the llvm-18.1.3-rust-1.85.0-x86_64 with ARCH=arm64, the following symbols are generated: $nm vmlinux | grep ' _R'.*PollCondVar | rustfilt ... T ::drop ... This Rust symbol is trivial wrappers around the C functions __wake_up_pollfree() and synchronize_rcu(). It doesn't make sense to go through a trivial wrapper for its functions, so mark it inline. [boqun: Reword the commit title and re-format the commit log per tip tree's requirement, remove unnecessary information from "nm vmlinux" result.] Link: https://github.com/Rust-for-Linux/linux/issues/1145 Suggested-by: Alice Ryhl Co-developed-by: Grace Deng Signed-off-by: Grace Deng Signed-off-by: Kunwu Chan Reviewed-by: Alice Ryhl Reviewed-by: Benno Lossin Signed-off-by: Boqun Feng Link: https://lore.kernel.org/r/20250317025205.2366518-1-kunwu.chan@linux.dev --- rust/kernel/sync/poll.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'rust/kernel') diff --git a/rust/kernel/sync/poll.rs b/rust/kernel/sync/poll.rs index d7e6e59e124b..7b973d72229b 100644 --- a/rust/kernel/sync/poll.rs +++ b/rust/kernel/sync/poll.rs @@ -107,6 +107,7 @@ impl Deref for PollCondVar { #[pinned_drop] impl PinnedDrop for PollCondVar { + #[inline] fn drop(self: Pin<&mut Self>) { // Clear anything registered using `register_wait`. // -- cgit v1.2.3 From 0a41f5af19391ce55cae1f0d7a562e8694bf1fd5 Mon Sep 17 00:00:00 2001 From: Panagiotis Foliadis Date: Sat, 15 Mar 2025 12:23:01 +0000 Subject: rust: task: Mark Task methods inline When building the kernel using the llvm-18.1.3-rust-1.85.0-x86_64 toolchain provided by kernel.org, the following symbols are generated: $ nm vmlinux | grep ' _R'.*Task | rustfilt ... T ::get_pid_ns ... T ::tgid_nr_ns ... T ::current_pid_ns ... T ::signal_pending ... T ::uid ... T ::euid ... T ::current ... T ::wake_up ... T ::dec_ref ... T ::inc_ref These Rust symbols are trivial wrappers around the C functions. It doesn't make sense to go through a trivial wrapper for these functions, so mark them inline. [boqun: Capitalize the title, reword a bit to avoid listing all the C functions as the code already shows them and remove the addresses of the symbols in the commit log as they are different from build to build.] Link: https://github.com/Rust-for-Linux/linux/issues/1145 Reviewed-by: Benno Lossin Reviewed-by: Christian Schrefl Reviewed-by: Charalampos Mitrodimas Reviewed-by: Alice Ryhl Signed-off-by: Panagiotis Foliadis Signed-off-by: Boqun Feng Link: https://lore.kernel.org/r/20250315-inline-c-wrappers-v3-1-048e43fcef7d@posteo.net --- rust/kernel/task.rs | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'rust/kernel') diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs index 927413d85484..834368313088 100644 --- a/rust/kernel/task.rs +++ b/rust/kernel/task.rs @@ -173,6 +173,7 @@ impl Task { /// Callers must ensure that the returned object is only used to access a [`CurrentTask`] /// within the task context that was active when this function was called. For more details, /// see the invariants section for [`CurrentTask`]. + #[inline] pub unsafe fn current() -> impl Deref { struct TaskRef { task: *const CurrentTask, @@ -222,24 +223,28 @@ impl Task { } /// Returns the UID of the given task. + #[inline] pub fn uid(&self) -> Kuid { // SAFETY: It's always safe to call `task_uid` on a valid task. Kuid::from_raw(unsafe { bindings::task_uid(self.as_ptr()) }) } /// Returns the effective UID of the given task. + #[inline] pub fn euid(&self) -> Kuid { // SAFETY: It's always safe to call `task_euid` on a valid task. Kuid::from_raw(unsafe { bindings::task_euid(self.as_ptr()) }) } /// Determines whether the given task has pending signals. + #[inline] pub fn signal_pending(&self) -> bool { // SAFETY: It's always safe to call `signal_pending` on a valid task. unsafe { bindings::signal_pending(self.as_ptr()) != 0 } } /// Returns task's pid namespace with elevated reference count + #[inline] pub fn get_pid_ns(&self) -> Option> { // SAFETY: By the type invariant, we know that `self.0` is valid. let ptr = unsafe { bindings::task_get_pid_ns(self.as_ptr()) }; @@ -255,6 +260,7 @@ impl Task { /// Returns the given task's pid in the provided pid namespace. #[doc(alias = "task_tgid_nr_ns")] + #[inline] pub fn tgid_nr_ns(&self, pidns: Option<&PidNamespace>) -> Pid { let pidns = match pidns { Some(pidns) => pidns.as_ptr(), @@ -268,6 +274,7 @@ impl Task { } /// Wakes up the task. + #[inline] pub fn wake_up(&self) { // SAFETY: It's always safe to call `wake_up_process` on a valid task, even if the task // running. @@ -341,11 +348,13 @@ impl CurrentTask { // SAFETY: The type invariants guarantee that `Task` is always refcounted. unsafe impl crate::types::AlwaysRefCounted for Task { + #[inline] fn inc_ref(&self) { // SAFETY: The existence of a shared reference means that the refcount is nonzero. unsafe { bindings::get_task_struct(self.as_ptr()) }; } + #[inline] unsafe fn dec_ref(obj: ptr::NonNull) { // SAFETY: The safety requirements guarantee that the refcount is nonzero. unsafe { bindings::put_task_struct(obj.cast().as_ptr()) } -- cgit v1.2.3 From 0aa2b78ce5a9eac8f3332192ea77755d63a831cd Mon Sep 17 00:00:00 2001 From: Boqun Feng Date: Sun, 15 Jun 2025 15:14:00 -0700 Subject: rust: Introduce file_from_location() Most of kernel debugging facilities take a nul-terminated string for file names for a callsite (generated from __FILE__), however the Rust courterpart, Location, would return a Rust string (not nul-terminated) from method .file(). And such a string cannot be passed to C debugging function directly. There is ongoing work to support a Location::file_with_nul() [1], which returns a nul-terminated string from a Location. Since it's still working in progress, and it will take some time before the feature finally gets stabilized and the kernel's minimal rustc version might also take a while to bump to a version that at least has that feature, introduce a file_from_location() function, which returns a warning string if Location::file_with_nul() is not available. This should work in most cases because as for now the known usage of Location::file_with_nul() is only in debugging code (e.g. might_sleep()) and there might be other information reported by the debugging code that could help locate the problematic function, so missing the file name is fine at the moment. Link: https://github.com/rust-lang/rust/issues/141727 [1] Signed-off-by: Boqun Feng Link: https://lore.kernel.org/r/20250619151007.61767-2-boqun.feng@gmail.com --- init/Kconfig | 3 +++ rust/kernel/lib.rs | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) (limited to 'rust/kernel') diff --git a/init/Kconfig b/init/Kconfig index af4c2f085455..6f4ec5633ffa 100644 --- a/init/Kconfig +++ b/init/Kconfig @@ -142,6 +142,9 @@ config RUSTC_HAS_SPAN_FILE config RUSTC_HAS_UNNECESSARY_TRANSMUTES def_bool RUSTC_VERSION >= 108800 +config RUSTC_HAS_FILE_WITH_NUL + def_bool RUSTC_VERSION >= 108900 + config PAHOLE_VERSION int default $(shell,$(srctree)/scripts/pahole-version.sh $(PAHOLE)) diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs index 6b4774b2b1c3..717a5b6160ca 100644 --- a/rust/kernel/lib.rs +++ b/rust/kernel/lib.rs @@ -40,6 +40,10 @@ #![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(coerce_unsized))] #![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(dispatch_from_dyn))] #![cfg_attr(not(CONFIG_RUSTC_HAS_COERCE_POINTEE), feature(unsize))] +// +// `feature(file_with_nul)` is expected to become stable. Before Rust 1.89.0, it did not exist, so +// enable it conditionally. +#![cfg_attr(CONFIG_RUSTC_HAS_FILE_WITH_NUL, feature(file_with_nul))] // Ensure conditional compilation based on the kernel configuration works; // otherwise we may silently break things like initcall handling. @@ -274,3 +278,47 @@ macro_rules! asm { ::core::arch::asm!( $($asm)*, $($rest)* ) }; } + +/// Gets the C string file name of a [`Location`]. +/// +/// If `file_with_nul()` is not available, returns a string that warns about it. +/// +/// [`Location`]: core::panic::Location +/// +/// # Examples +/// +/// ``` +/// # use kernel::file_from_location; +/// +/// #[track_caller] +/// fn foo() { +/// let caller = core::panic::Location::caller(); +/// +/// // Output: +/// // - A path like "rust/kernel/example.rs" if file_with_nul() is available. +/// // - "" otherwise. +/// let caller_file = file_from_location(caller); +/// +/// // Prints out the message with caller's file name. +/// pr_info!("foo() called in file {caller_file:?}\n"); +/// +/// # if cfg!(CONFIG_RUSTC_HAS_FILE_WITH_NUL) { +/// # assert_eq!(Ok(caller.file()), caller_file.to_str()); +/// # } +/// } +/// +/// # foo(); +/// ``` +#[inline] +pub fn file_from_location<'a>(loc: &'a core::panic::Location<'a>) -> &'a core::ffi::CStr { + #[cfg(CONFIG_RUSTC_HAS_FILE_WITH_NUL)] + { + loc.file_with_nul() + } + + #[cfg(not(CONFIG_RUSTC_HAS_FILE_WITH_NUL))] + { + let _ = loc; + c"" + } +} -- cgit v1.2.3 From 7e611710acf966df1e14bcf4e067385e38e549a1 Mon Sep 17 00:00:00 2001 From: FUJITA Tomonori Date: Fri, 11 Apr 2025 07:56:23 +0900 Subject: rust: task: Add Rust version of might_sleep() Add a helper function equivalent to the C's might_sleep(), which serves as a debugging aid and a potential scheduling point. Note that this function can only be used in a nonatomic context. This will be used by Rust version of read_poll_timeout(). [boqun: Use file_from_location() to get a C string instead of changing __might_sleep()] Signed-off-by: FUJITA Tomonori Reviewed-by: Alice Ryhl Signed-off-by: Boqun Feng Link: https://lore.kernel.org/r/20250619151007.61767-3-boqun.feng@gmail.com --- rust/helpers/task.c | 6 ++++++ rust/kernel/task.rs | 24 ++++++++++++++++++++++++ 2 files changed, 30 insertions(+) (limited to 'rust/kernel') diff --git a/rust/helpers/task.c b/rust/helpers/task.c index 31c33ea2dce6..2c85bbc2727e 100644 --- a/rust/helpers/task.c +++ b/rust/helpers/task.c @@ -1,7 +1,13 @@ // SPDX-License-Identifier: GPL-2.0 +#include #include +void rust_helper_might_resched(void) +{ + might_resched(); +} + struct task_struct *rust_helper_get_current(void) { return current; diff --git a/rust/kernel/task.rs b/rust/kernel/task.rs index 834368313088..7d0935bc325c 100644 --- a/rust/kernel/task.rs +++ b/rust/kernel/task.rs @@ -400,3 +400,27 @@ impl PartialEq for Kuid { } impl Eq for Kuid {} + +/// Annotation for functions that can sleep. +/// +/// Equivalent to the C side [`might_sleep()`], this function serves as +/// a debugging aid and a potential scheduling point. +/// +/// This function can only be used in a nonatomic context. +/// +/// [`might_sleep()`]: https://docs.kernel.org/driver-api/basics.html#c.might_sleep +#[track_caller] +#[inline] +pub fn might_sleep() { + #[cfg(CONFIG_DEBUG_ATOMIC_SLEEP)] + { + let loc = core::panic::Location::caller(); + let file = kernel::file_from_location(loc); + + // SAFETY: `file.as_ptr()` is valid for reading and guaranteed to be nul-terminated. + unsafe { crate::bindings::__might_sleep(file.as_ptr().cast(), loc.line() as i32) } + } + + // SAFETY: Always safe to call. + unsafe { crate::bindings::might_resched() } +} -- cgit v1.2.3