Skip to contentSkip to conversation

LOCKDEP and Rust locking changes for v6.15

GIT PULL Applied Boqun Feng 5 participants 31 messages Feb 26, 2025 – Mar 8, 2025

Subsystems (6)
lore
Share & tools
lore

Boqun Feng

author
#0 lore raw

Hi Peter & Ingo,

Please pull the changes of lockdep and Rust locking for v6.15 into tip.

The following changes since commit 337369f8ce9e20226402cf139c4f0d3ada7d1705:

locking/mutex: Add MUTEX_WARN_ON() into fast path (2025-02-21 20:19:12 +0100)

are available in the Git repository at:

git://git.kernel.org/pub/scm/linux/kernel/git/boqun/linux.git tags/lockdep-for-tip.2025.02.25

for you to fetch changes up to 3b5b307cf84ca3a73abe797df31e0efe897411a9:

rust: lockdep: Use Pin for all LockClassKey usages (2025-02-25 08:53:08 -0800)

Regards,
Boqun

----------------------------------------------------------------
Lockdep changes for v6.15:

- Fix kernel-doc for rtmutex.
- Fix lock wait context check on softirq for PREEMPT_RT.
- Disable KASAN for lockdep to improve debug kernel performance.

Miscellaneous locking changes for v6.15:

- Use wake_q for semaphore to avoid wake-up in lock critical sections.

Rust locking changes for v6.15:

- Fix the soundness issue around dynamically allocated lock class keys.
- Add CondVar::wait_interruptible_freezable() to allow freezable waits.
- Add Guard::lock_ref() to access the lock reference behind a lock guard.

----------------------------------------------------------------
Alice Ryhl (2):
rust: sync: Add accessor for the lock behind a given guard
rust: sync: condvar: Add wait_interruptible_freezable()

Boqun Feng (1):
rust: sync: lock: Add an example for Guard::lock_ref()

Mitchell Levy (2):
rust: lockdep: Remove support for dynamically allocated LockClassKeys
rust: lockdep: Use Pin for all LockClassKey usages

Randy Dunlap (1):
locking/rtmutex: Use struct keyword in kernel-doc comment

Ryo Takakura (1):
lockdep: Fix wait context check on softirq for PREEMPT_RT

Waiman Long (5):
locking/semaphore: Use wake_q to wake up processes outside lock critical section locking/lock_events: Add locking events for rtmutex slow paths locking/lock_events: Add locking events for lockdep locking/lockdep: Disable KASAN instrumentation of lockdep.c locking/lockdep: Add kasan_check_byte() check in lock_acquire()

 include/linux/bottom_half.h       |  8 +++++
 kernel/locking/Makefile           |  3 +-
 kernel/locking/lock_events_list.h | 28 +++++++++++++++++
 kernel/locking/lockdep.c          | 17 ++++++++++-
 kernel/locking/rtmutex.c          | 29 ++++++++++++++----
 kernel/locking/rtmutex_common.h   |  4 +--
 kernel/locking/semaphore.c        | 13 +++++---
 kernel/softirq.c                  | 12 ++++++++
 rust/helpers/helpers.c            |  1 +
 rust/helpers/sync.c               | 13 ++++++++
 rust/kernel/sync.rs               | 63 ++++++++++++++++++++++++++++++++-------
 rust/kernel/sync/condvar.rs       | 28 ++++++++++++++---
 rust/kernel/sync/lock.rs          | 35 ++++++++++++++++++++--
 rust/kernel/sync/lock/global.rs   |  5 ++--
 rust/kernel/sync/poll.rs          |  2 +-
 rust/kernel/task.rs               |  2 ++
 rust/kernel/workqueue.rs          |  2 +-
 17 files changed, 231 insertions(+), 34 deletions(-)
 create mode 100644 rust/helpers/sync.c
author
#1 lore raw
Quoted 2 lines · Boqun Feng

Hi Peter & Ingo,

Ping ;-)

Regards,
Boqun

Quoted 80 lines

Please pull the changes of lockdep and Rust locking for v6.15 into tip.

The following changes since commit 337369f8ce9e20226402cf139c4f0d3ada7d1705:

locking/mutex: Add MUTEX_WARN_ON() into fast path (2025-02-21 20:19:12 +0100)

are available in the Git repository at:

git://git.kernel.org/pub/scm/linux/kernel/git/boqun/linux.git tags/lockdep-for-tip.2025.02.25

for you to fetch changes up to 3b5b307cf84ca3a73abe797df31e0efe897411a9:

rust: lockdep: Use Pin for all LockClassKey usages (2025-02-25 08:53:08 -0800)

Regards,
Boqun

----------------------------------------------------------------
Lockdep changes for v6.15:

- Fix kernel-doc for rtmutex.
- Fix lock wait context check on softirq for PREEMPT_RT.
- Disable KASAN for lockdep to improve debug kernel performance.

Miscellaneous locking changes for v6.15:

- Use wake_q for semaphore to avoid wake-up in lock critical sections.

Rust locking changes for v6.15:

- Fix the soundness issue around dynamically allocated lock class keys.
- Add CondVar::wait_interruptible_freezable() to allow freezable waits.
- Add Guard::lock_ref() to access the lock reference behind a lock guard.

----------------------------------------------------------------
Alice Ryhl (2):
rust: sync: Add accessor for the lock behind a given guard
rust: sync: condvar: Add wait_interruptible_freezable()

Boqun Feng (1):
rust: sync: lock: Add an example for Guard::lock_ref()

Mitchell Levy (2):
rust: lockdep: Remove support for dynamically allocated LockClassKeys
rust: lockdep: Use Pin for all LockClassKey usages

Randy Dunlap (1):
locking/rtmutex: Use struct keyword in kernel-doc comment

Ryo Takakura (1):
lockdep: Fix wait context check on softirq for PREEMPT_RT

Waiman Long (5):
locking/semaphore: Use wake_q to wake up processes outside lock critical section locking/lock_events: Add locking events for rtmutex slow paths locking/lock_events: Add locking events for lockdep locking/lockdep: Disable KASAN instrumentation of lockdep.c locking/lockdep: Add kasan_check_byte() check in lock_acquire()

 include/linux/bottom_half.h       |  8 +++++
 kernel/locking/Makefile           |  3 +-
 kernel/locking/lock_events_list.h | 28 +++++++++++++++++
 kernel/locking/lockdep.c          | 17 ++++++++++-
 kernel/locking/rtmutex.c          | 29 ++++++++++++++----
 kernel/locking/rtmutex_common.h   |  4 +--
 kernel/locking/semaphore.c        | 13 +++++---
 kernel/softirq.c                  | 12 ++++++++
 rust/helpers/helpers.c            |  1 +
 rust/helpers/sync.c               | 13 ++++++++
 rust/kernel/sync.rs               | 63 ++++++++++++++++++++++++++++++++-------
 rust/kernel/sync/condvar.rs       | 28 ++++++++++++++---
 rust/kernel/sync/lock.rs          | 35 ++++++++++++++++++++--
 rust/kernel/sync/lock/global.rs   |  5 ++--
 rust/kernel/sync/poll.rs          |  2 +-
 rust/kernel/task.rs               |  2 ++
 rust/kernel/workqueue.rs          |  2 +-
 17 files changed, 231 insertions(+), 34 deletions(-)
 create mode 100644 rust/helpers/sync.c
#2 lore raw
Quoted 4 lines · Boqun Feng
Quoted 2 lines · Boqun Feng

Hi Peter & Ingo,

Ping ;-)

Hi Peter, are you going to pull this lockep branch into tip?

Thanks,
Longman

maintainer
#3 lore raw
In reply to Boqun Feng
Quoted 17 lines · Boqun Feng

Alice Ryhl (2):
rust: sync: Add accessor for the lock behind a given guard
rust: sync: condvar: Add wait_interruptible_freezable()

Boqun Feng (1):
rust: sync: lock: Add an example for Guard::lock_ref()

Mitchell Levy (2):
rust: lockdep: Remove support for dynamically allocated LockClassKeys
rust: lockdep: Use Pin for all LockClassKey usages

Randy Dunlap (1):
locking/rtmutex: Use struct keyword in kernel-doc comment

Ryo Takakura (1):
lockdep: Fix wait context check on softirq for PREEMPT_RT

Quoted 6 lines

Waiman Long (5):
locking/semaphore: Use wake_q to wake up processes outside lock critical section locking/lock_events: Add locking events for rtmutex slow paths locking/lock_events: Add locking events for lockdep locking/lockdep: Disable KASAN instrumentation of lockdep.c locking/lockdep: Add kasan_check_byte() check in lock_acquire()

OK, done!

Thanks, and sorry for being tardy, somehow time got away from me :/

author
#4 lore raw

cover LOCKDEP and Rust locking changes for v6.15

In reply to Boqun Feng

Hi Ingo & Peter,

As discussed, I'm resending the pull request for lockdep and Rust locking for v6.15 in the format of email patches. I dropped one patch and will postpone it for v6.16 because of a bug [1], and I think the fix
[2] needs more reviews.

[1]: https://lore.kernel.org/lkml/20250306122413.GBZ8mT7Z61Tmgnh5Y9@fat_crate.local/
[2]: https://lore.kernel.org/lkml/Z8t8imzJVhWyDvhC@boqun-archlinux/

Regards,
Boqun

Alice Ryhl (2):
rust: sync: Add accessor for the lock behind a given guard
rust: sync: condvar: Add wait_interruptible_freezable()

Boqun Feng (1):
rust: sync: lock: Add an example for Guard::lock_ref()

Mitchell Levy (2):
rust: lockdep: Remove support for dynamically allocated LockClassKeys
rust: lockdep: Use Pin for all LockClassKey usages

Randy Dunlap (1):
locking/rtmutex: Use struct keyword in kernel-doc comment

Waiman Long (5):
locking/semaphore: Use wake_q to wake up processes outside lock
critical section
locking/lock_events: Add locking events for rtmutex slow paths locking/lock_events: Add locking events for lockdep locking/lockdep: Disable KASAN instrumentation of lockdep.c locking/lockdep: Add kasan_check_byte() check in lock_acquire()

 kernel/locking/Makefile           |  3 +-
 kernel/locking/lock_events_list.h | 28 ++++++++++++++
 kernel/locking/lockdep.c          | 17 ++++++++-
 kernel/locking/rtmutex.c          | 29 +++++++++++---
 kernel/locking/rtmutex_common.h   |  4 +-
 kernel/locking/semaphore.c        | 13 +++++--
 rust/helpers/helpers.c            |  1 +
 rust/helpers/sync.c               | 13 +++++++
 rust/kernel/sync.rs               | 63 ++++++++++++++++++++++++++-----
 rust/kernel/sync/condvar.rs       | 28 ++++++++++++--
 rust/kernel/sync/lock.rs          | 35 +++++++++++++++--
 rust/kernel/sync/lock/global.rs   |  5 ++-
 rust/kernel/sync/poll.rs          |  2 +-
 rust/kernel/task.rs               |  2 +
 rust/kernel/workqueue.rs          |  2 +-
 15 files changed, 211 insertions(+), 34 deletions(-)
 create mode 100644 rust/helpers/sync.c
Signature · 1 line
2.47.1
author
#5 lore raw

PATCH 1/11 locking/rtmutex: Use struct keyword in kernel-doc comment

From: Randy Dunlap <[email protected]>

Add the "struct" keyword to prevent a kernel-doc warning:

rtmutex_common.h:67: warning: cannot understand function prototype: 'struct rt_wake_q_head '

---
 kernel/locking/rtmutex_common.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/locking/rtmutex_common.h +2 -2
index c38a2d2d4a7e..78dd3d8c6554 100644
@@ -59,8 +59,8 @@ struct rt_mutex_waiter {
 };
 
 /**
- * rt_wake_q_head - Wrapper around regular wake_q_head to support
- *		    "sleeping" spinlocks on RT
+ * struct rt_wake_q_head - Wrapper around regular wake_q_head to support
+ *			   "sleeping" spinlocks on RT
  * @head:		The regular wake_q_head for sleeping lock variants
  * @rtlock_task:	Task pointer for RT lock (spin/rwlock) wakeups
  */
Signature · 1 line
2.47.1
merge bot Applied
#6 lore raw

[tip: locking/core] locking/rtmutex: Use the 'struct' keyword in kernel-doc comment

The following commit has been merged into the locking/core branch of tip:

The following commit has been merged into the locking/core branch of tip:

Commit-ID:     b3c5ec8b79bf6bc49cc4850d0949d712830283d7
Gitweb:        https://git.kernel.org/tip/b3c5ec8b79bf6bc49cc4850d0949d712830283d7
Author:        Randy Dunlap <[email protected]>
AuthorDate:    Fri, 07 Mar 2025 15:26:51 -08:00
Committer:     Ingo Molnar <[email protected]>
CommitterDate: Sat, 08 Mar 2025 00:52:01 +01:00

locking/rtmutex: Use the 'struct' keyword in kernel-doc comment

Add the "struct" keyword to prevent a kernel-doc warning:

rtmutex_common.h:67: warning: cannot understand function prototype: 'struct rt_wake_q_head '

---
 kernel/locking/rtmutex_common.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/locking/rtmutex_common.h +2 -2
index c38a2d2..78dd3d8 100644
@@ -59,8 +59,8 @@ struct rt_mutex_waiter {
 };
 
 /**
- * rt_wake_q_head - Wrapper around regular wake_q_head to support
- *		    "sleeping" spinlocks on RT
+ * struct rt_wake_q_head - Wrapper around regular wake_q_head to support
+ *			   "sleeping" spinlocks on RT
  * @head:		The regular wake_q_head for sleeping lock variants
  * @rtlock_task:	Task pointer for RT lock (spin/rwlock) wakeups
  */
author
#7 lore raw

PATCH 2/11 locking/semaphore: Use wake_q to wake up processes outside lock critical section

In reply to Boqun Feng

From: Waiman Long <[email protected]>

A circular lock dependency splat has been seen involving down_trylock().

[ 4011.795602] ======================================================
[ 4011.795603] WARNING: possible circular locking dependency detected
[ 4011.795607] 6.12.0-41.el10.s390x+debug
[ 4011.795612] ------------------------------------------------------
[ 4011.795613] dd/32479 is trying to acquire lock:
[ 4011.795617] 0015a20accd0d4f8 ((console_sem).lock){-.-.}-{2:2}, at: down_trylock+0x26/0x90
[ 4011.795636]
[ 4011.795636] but task is already holding lock:
[ 4011.795637] 000000017e461698 (&zone->lock){-.-.}-{2:2}, at: rmqueue_bulk+0xac/0x8f0

the existing dependency chain (in reverse order) is:
-> #4 (&zone->lock){-.-.}-{2:2}:
-> #3 (hrtimer_bases.lock){-.-.}-{2:2}:
-> #2 (&rq->__lock){-.-.}-{2:2}:
-> #1 (&p->pi_lock){-.-.}-{2:2}:
-> #0 ((console_sem).lock){-.-.}-{2:2}:

The console_sem -> pi_lock dependency is due to calling try_to_wake_up() while holding the console.sem raw_spinlock. This dependency can be broken by using wake_q to do the wakeup instead of calling try_to_wake_up() under the console_sem lock. This will also make the semaphore's raw_spinlock become a terminal lock without taking any further locks underneath it.

The hrtimer_bases.lock is a raw_spinlock while zone->lock is a spinlock. The hrtimer_bases.lock -> zone->lock dependency happens via the debug_objects_fill_pool() helper function in the debugobjects code.

[ 4011.795646] -> #4 (&zone->lock){-.-.}-{2:2}:
[ 4011.795650]        __lock_acquire+0xe86/0x1cc0
[ 4011.795655]        lock_acquire.part.0+0x258/0x630
[ 4011.795657]        lock_acquire+0xb8/0xe0
[ 4011.795659]        _raw_spin_lock_irqsave+0xb4/0x120
[ 4011.795663]        rmqueue_bulk+0xac/0x8f0
[ 4011.795665]        __rmqueue_pcplist+0x580/0x830
[ 4011.795667]        rmqueue_pcplist+0xfc/0x470
[ 4011.795669]        rmqueue.isra.0+0xdec/0x11b0
[ 4011.795671]        get_page_from_freelist+0x2ee/0xeb0
[ 4011.795673]        __alloc_pages_noprof+0x2c2/0x520
[ 4011.795676]        alloc_pages_mpol_noprof+0x1fc/0x4d0
[ 4011.795681]        alloc_pages_noprof+0x8c/0xe0
[ 4011.795684]        allocate_slab+0x320/0x460
[ 4011.795686]        ___slab_alloc+0xa58/0x12b0
[ 4011.795688]        __slab_alloc.isra.0+0x42/0x60
[ 4011.795690]        kmem_cache_alloc_noprof+0x304/0x350
[ 4011.795692]        fill_pool+0xf6/0x450
[ 4011.795697]        debug_object_activate+0xfe/0x360
[ 4011.795700]        enqueue_hrtimer+0x34/0x190
[ 4011.795703]        __run_hrtimer+0x3c8/0x4c0
[ 4011.795705]        __hrtimer_run_queues+0x1b2/0x260
[ 4011.795707]        hrtimer_interrupt+0x316/0x760
[ 4011.795709]        do_IRQ+0x9a/0xe0
[ 4011.795712]        do_irq_async+0xf6/0x160

Normally raw_spinlock to spinlock dependency is not legit and will be warned if PROVE_RAW_LOCK_NESTING is enabled, but debug_objects_fill_pool() is an exception as it explicitly allows this dependency for non-PREEMPT_RT kernel without causing PROVE_RAW_LOCK_NESTING lockdep splat. As a result, this dependency is legit and not a bug.

Anyway, semaphore is the only locking primitive left that is still using try_to_wake_up() to do wakeup inside critical section, all the other locking primitives had been migrated to use wake_q to do wakeup outside of the critical section. It is also possible that there are other circular locking dependencies involving printk/console_sem or other existing/new semaphores lurking somewhere which may show up in the future. Let just do the migration now to wake_q to avoid headache like this.

---
 kernel/locking/semaphore.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)
kernel/locking/semaphore.c +9 -4
index 34bfae72f295..de9117c0e671 100644
@@ -29,6 +29,7 @@
 #include <linux/export.h>
 #include <linux/sched.h>
 #include <linux/sched/debug.h>
+#include <linux/sched/wake_q.h>
 #include <linux/semaphore.h>
 #include <linux/spinlock.h>
 #include <linux/ftrace.h>
@@ -38,7 +39,7 @@ static noinline void __down(struct semaphore *sem);
 static noinline int __down_interruptible(struct semaphore *sem);
 static noinline int __down_killable(struct semaphore *sem);
 static noinline int __down_timeout(struct semaphore *sem, long timeout);
-static noinline void __up(struct semaphore *sem);
+static noinline void __up(struct semaphore *sem, struct wake_q_head *wake_q);
 
 /**
  * down - acquire the semaphore
@@ -183,13 +184,16 @@ EXPORT_SYMBOL(down_timeout);
 void __sched up(struct semaphore *sem)
 {
 	unsigned long flags;
+	DEFINE_WAKE_Q(wake_q);
 
 	raw_spin_lock_irqsave(&sem->lock, flags);
 	if (likely(list_empty(&sem->wait_list)))
 		sem->count++;
 	else
-		__up(sem);
+		__up(sem, &wake_q);
 	raw_spin_unlock_irqrestore(&sem->lock, flags);
+	if (!wake_q_empty(&wake_q))
+		wake_up_q(&wake_q);
 }
 EXPORT_SYMBOL(up);
 
@@ -269,11 +273,12 @@ static noinline int __sched __down_timeout(struct semaphore *sem, long timeout)
 	return __down_common(sem, TASK_UNINTERRUPTIBLE, timeout);
 }
 
-static noinline void __sched __up(struct semaphore *sem)
+static noinline void __sched __up(struct semaphore *sem,
+				  struct wake_q_head *wake_q)
 {
 	struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list,
 						struct semaphore_waiter, list);
 	list_del(&waiter->list);
 	waiter->up = true;
-	wake_up_process(waiter->task);
+	wake_q_add(wake_q, waiter->task);
 }
Signature · 1 line
2.47.1
merge bot Applied
#8 lore raw

[tip: locking/core] locking/semaphore: Use wake_q to wake up processes outside lock critical section

The following commit has been merged into the locking/core branch of tip:

The following commit has been merged into the locking/core branch of tip:

Commit-ID:     85b2b9c16d053364e2004883140538e73b333cdb
Gitweb:        https://git.kernel.org/tip/85b2b9c16d053364e2004883140538e73b333cdb
Author:        Waiman Long <[email protected]>
AuthorDate:    Fri, 07 Mar 2025 15:26:52 -08:00
Committer:     Ingo Molnar <[email protected]>
CommitterDate: Sat, 08 Mar 2025 00:52:01 +01:00

locking/semaphore: Use wake_q to wake up processes outside lock critical section

A circular lock dependency splat has been seen involving down_trylock():

======================================================
WARNING: possible circular locking dependency detected 6.12.0-41.el10.s390x+debug
------------------------------------------------------
dd/32479 is trying to acquire lock:
0015a20accd0d4f8 ((console_sem).lock){-.-.}-{2:2}, at: down_trylock+0x26/0x90

but task is already holding lock:
000000017e461698 (&zone->lock){-.-.}-{2:2}, at: rmqueue_bulk+0xac/0x8f0

the existing dependency chain (in reverse order) is:
-> #4 (&zone->lock){-.-.}-{2:2}:
-> #3 (hrtimer_bases.lock){-.-.}-{2:2}:
-> #2 (&rq->__lock){-.-.}-{2:2}:
-> #1 (&p->pi_lock){-.-.}-{2:2}:
-> #0 ((console_sem).lock){-.-.}-{2:2}:

The console_sem -> pi_lock dependency is due to calling try_to_wake_up() while holding the console_sem raw_spinlock. This dependency can be broken by using wake_q to do the wakeup instead of calling try_to_wake_up() under the console_sem lock. This will also make the semaphore's raw_spinlock become a terminal lock without taking any further locks underneath it.

The hrtimer_bases.lock is a raw_spinlock while zone->lock is a spinlock. The hrtimer_bases.lock -> zone->lock dependency happens via the debug_objects_fill_pool() helper function in the debugobjects code.

-> #4 (&zone->lock){-.-.}-{2:2}:

         __lock_acquire+0xe86/0x1cc0
         lock_acquire.part.0+0x258/0x630
         lock_acquire+0xb8/0xe0
         _raw_spin_lock_irqsave+0xb4/0x120
         rmqueue_bulk+0xac/0x8f0
         __rmqueue_pcplist+0x580/0x830
         rmqueue_pcplist+0xfc/0x470
         rmqueue.isra.0+0xdec/0x11b0
         get_page_from_freelist+0x2ee/0xeb0
         __alloc_pages_noprof+0x2c2/0x520
         alloc_pages_mpol_noprof+0x1fc/0x4d0
         alloc_pages_noprof+0x8c/0xe0
         allocate_slab+0x320/0x460
         ___slab_alloc+0xa58/0x12b0
         __slab_alloc.isra.0+0x42/0x60
         kmem_cache_alloc_noprof+0x304/0x350
         fill_pool+0xf6/0x450
         debug_object_activate+0xfe/0x360
         enqueue_hrtimer+0x34/0x190
         __run_hrtimer+0x3c8/0x4c0
         __hrtimer_run_queues+0x1b2/0x260
         hrtimer_interrupt+0x316/0x760
         do_IRQ+0x9a/0xe0
         do_irq_async+0xf6/0x160

Normally a raw_spinlock to spinlock dependency is not legitimate and will be warned if CONFIG_PROVE_RAW_LOCK_NESTING is enabled, but debug_objects_fill_pool() is an exception as it explicitly allows this dependency for non-PREEMPT_RT kernel without causing PROVE_RAW_LOCK_NESTING lockdep splat. As a result, this dependency is legitimate and not a bug.

Anyway, semaphore is the only locking primitive left that is still using try_to_wake_up() to do wakeup inside critical section, all the other locking primitives had been migrated to use wake_q to do wakeup outside of the critical section. It is also possible that there are other circular locking dependencies involving printk/console_sem or other existing/new semaphores lurking somewhere which may show up in the future. Let just do the migration now to wake_q to avoid headache like this.

---
 kernel/locking/semaphore.c | 13 +++++++++----
 1 file changed, 9 insertions(+), 4 deletions(-)
kernel/locking/semaphore.c +9 -4
index 34bfae7..de9117c 100644
@@ -29,6 +29,7 @@
 #include <linux/export.h>
 #include <linux/sched.h>
 #include <linux/sched/debug.h>
+#include <linux/sched/wake_q.h>
 #include <linux/semaphore.h>
 #include <linux/spinlock.h>
 #include <linux/ftrace.h>
@@ -38,7 +39,7 @@ static noinline void __down(struct semaphore *sem);
 static noinline int __down_interruptible(struct semaphore *sem);
 static noinline int __down_killable(struct semaphore *sem);
 static noinline int __down_timeout(struct semaphore *sem, long timeout);
-static noinline void __up(struct semaphore *sem);
+static noinline void __up(struct semaphore *sem, struct wake_q_head *wake_q);
 
 /**
  * down - acquire the semaphore
@@ -183,13 +184,16 @@ EXPORT_SYMBOL(down_timeout);
 void __sched up(struct semaphore *sem)
 {
 	unsigned long flags;
+	DEFINE_WAKE_Q(wake_q);
 
 	raw_spin_lock_irqsave(&sem->lock, flags);
 	if (likely(list_empty(&sem->wait_list)))
 		sem->count++;
 	else
-		__up(sem);
+		__up(sem, &wake_q);
 	raw_spin_unlock_irqrestore(&sem->lock, flags);
+	if (!wake_q_empty(&wake_q))
+		wake_up_q(&wake_q);
 }
 EXPORT_SYMBOL(up);
 
@@ -269,11 +273,12 @@ static noinline int __sched __down_timeout(struct semaphore *sem, long timeout)
 	return __down_common(sem, TASK_UNINTERRUPTIBLE, timeout);
 }
 
-static noinline void __sched __up(struct semaphore *sem)
+static noinline void __sched __up(struct semaphore *sem,
+				  struct wake_q_head *wake_q)
 {
 	struct semaphore_waiter *waiter = list_first_entry(&sem->wait_list,
 						struct semaphore_waiter, list);
 	list_del(&waiter->list);
 	waiter->up = true;
-	wake_up_process(waiter->task);
+	wake_q_add(wake_q, waiter->task);
 }
author
#9 lore raw

PATCH 3/11 locking/lock_events: Add locking events for rtmutex slow paths

In reply to Boqun Feng

From: Waiman Long <[email protected]>

Add locking events for rtlock_slowlock() and rt_mutex_slowlock() for profiling the slow path behavior of rt_spin_lock() and rt_mutex_lock().

---
 kernel/locking/lock_events_list.h | 21 +++++++++++++++++++++
 kernel/locking/rtmutex.c          | 29 ++++++++++++++++++++++++-----
 2 files changed, 45 insertions(+), 5 deletions(-)
kernel/locking/lock_events_list.h +21 -0
index 97fb6f3f840a..80b11f194c9f 100644
@@ -67,3 +67,24 @@ LOCK_EVENT(rwsem_rlock_handoff)	/* # of read lock handoffs		*/
 LOCK_EVENT(rwsem_wlock)		/* # of write locks acquired		*/
 LOCK_EVENT(rwsem_wlock_fail)	/* # of failed write lock acquisitions	*/
 LOCK_EVENT(rwsem_wlock_handoff)	/* # of write lock handoffs		*/
+
+/*
+ * Locking events for rtlock_slowlock()
+ */
+LOCK_EVENT(rtlock_slowlock)	/* # of rtlock_slowlock() calls		*/
+LOCK_EVENT(rtlock_slow_acq1)	/* # of locks acquired after wait_lock	*/
+LOCK_EVENT(rtlock_slow_acq2)	/* # of locks acquired in for loop	*/
+LOCK_EVENT(rtlock_slow_sleep)	/* # of sleeps				*/
+LOCK_EVENT(rtlock_slow_wake)	/* # of wakeup's			*/
+
+/*
+ * Locking events for rt_mutex_slowlock()
+ */
+LOCK_EVENT(rtmutex_slowlock)	/* # of rt_mutex_slowlock() calls	*/
+LOCK_EVENT(rtmutex_slow_block)	/* # of rt_mutex_slowlock_block() calls	*/
+LOCK_EVENT(rtmutex_slow_acq1)	/* # of locks acquired after wait_lock	*/
+LOCK_EVENT(rtmutex_slow_acq2)	/* # of locks acquired at the end	*/
+LOCK_EVENT(rtmutex_slow_acq3)	/* # of locks acquired in *block()	*/
+LOCK_EVENT(rtmutex_slow_sleep)	/* # of sleeps				*/
+LOCK_EVENT(rtmutex_slow_wake)	/* # of wakeup's			*/
+LOCK_EVENT(rtmutex_deadlock)	/* # of rt_mutex_handle_deadlock()'s	*/
kernel/locking/rtmutex.c +24 -5
index 4a8df1800cbb..c80902eacd79 100644
@@ -27,6 +27,7 @@
 #include <trace/events/lock.h>
 
 #include "rtmutex_common.h"
+#include "lock_events.h"
 
 #ifndef WW_RT
 # define build_ww_mutex()	(false)
@@ -1612,10 +1613,13 @@ static int __sched rt_mutex_slowlock_block(struct rt_mutex_base *lock,
 	struct task_struct *owner;
 	int ret = 0;
 
+	lockevent_inc(rtmutex_slow_block);
 	for (;;) {
 		/* Try to acquire the lock: */
-		if (try_to_take_rt_mutex(lock, current, waiter))
+		if (try_to_take_rt_mutex(lock, current, waiter)) {
+			lockevent_inc(rtmutex_slow_acq3);
 			break;
+		}
 
 		if (timeout && !timeout->task) {
 			ret = -ETIMEDOUT;
@@ -1638,8 +1642,10 @@ static int __sched rt_mutex_slowlock_block(struct rt_mutex_base *lock,
 			owner = NULL;
 		raw_spin_unlock_irq_wake(&lock->wait_lock, wake_q);
 
-		if (!owner || !rtmutex_spin_on_owner(lock, waiter, owner))
+		if (!owner || !rtmutex_spin_on_owner(lock, waiter, owner)) {
+			lockevent_inc(rtmutex_slow_sleep);
 			rt_mutex_schedule();
+		}
 
 		raw_spin_lock_irq(&lock->wait_lock);
 		set_current_state(state);
@@ -1694,6 +1700,7 @@ static int __sched __rt_mutex_slowlock(struct rt_mutex_base *lock,
 	int ret;
 
 	lockdep_assert_held(&lock->wait_lock);
+	lockevent_inc(rtmutex_slowlock);
 
 	/* Try to acquire the lock again: */
 	if (try_to_take_rt_mutex(lock, current, NULL)) {
@@ -1701,6 +1708,7 @@ static int __sched __rt_mutex_slowlock(struct rt_mutex_base *lock,
 			__ww_mutex_check_waiters(rtm, ww_ctx, wake_q);
 			ww_mutex_lock_acquired(ww, ww_ctx);
 		}
+		lockevent_inc(rtmutex_slow_acq1);
 		return 0;
 	}
 
@@ -1719,10 +1727,12 @@ static int __sched __rt_mutex_slowlock(struct rt_mutex_base *lock,
 				__ww_mutex_check_waiters(rtm, ww_ctx, wake_q);
 			ww_mutex_lock_acquired(ww, ww_ctx);
 		}
+		lockevent_inc(rtmutex_slow_acq2);
 	} else {
 		__set_current_state(TASK_RUNNING);
 		remove_waiter(lock, waiter);
 		rt_mutex_handle_deadlock(ret, chwalk, lock, waiter);
+		lockevent_inc(rtmutex_deadlock);
 	}
 
 	/*
@@ -1751,6 +1761,7 @@ static inline int __rt_mutex_slowlock_locked(struct rt_mutex_base *lock,
 				  &waiter, wake_q);
 
 	debug_rt_mutex_free_waiter(&waiter);
+	lockevent_cond_inc(rtmutex_slow_wake, !wake_q_empty(wake_q));
 	return ret;
 }
 
@@ -1823,9 +1834,12 @@ static void __sched rtlock_slowlock_locked(struct rt_mutex_base *lock,
 	struct task_struct *owner;
 
 	lockdep_assert_held(&lock->wait_lock);
+	lockevent_inc(rtlock_slowlock);
 
-	if (try_to_take_rt_mutex(lock, current, NULL))
+	if (try_to_take_rt_mutex(lock, current, NULL)) {
+		lockevent_inc(rtlock_slow_acq1);
 		return;
+	}
 
 	rt_mutex_init_rtlock_waiter(&waiter);
 
@@ -1838,8 +1852,10 @@ static void __sched rtlock_slowlock_locked(struct rt_mutex_base *lock,
 
 	for (;;) {
 		/* Try to acquire the lock again */
-		if (try_to_take_rt_mutex(lock, current, &waiter))
+		if (try_to_take_rt_mutex(lock, current, &waiter)) {
+			lockevent_inc(rtlock_slow_acq2);
 			break;
+		}
 
 		if (&waiter == rt_mutex_top_waiter(lock))
 			owner = rt_mutex_owner(lock);
@@ -1847,8 +1863,10 @@ static void __sched rtlock_slowlock_locked(struct rt_mutex_base *lock,
 			owner = NULL;
 		raw_spin_unlock_irq_wake(&lock->wait_lock, wake_q);
 
-		if (!owner || !rtmutex_spin_on_owner(lock, &waiter, owner))
+		if (!owner || !rtmutex_spin_on_owner(lock, &waiter, owner)) {
+			lockevent_inc(rtlock_slow_sleep);
 			schedule_rtlock();
+		}
 
 		raw_spin_lock_irq(&lock->wait_lock);
 		set_current_state(TASK_RTLOCK_WAIT);
@@ -1865,6 +1883,7 @@ static void __sched rtlock_slowlock_locked(struct rt_mutex_base *lock,
 	debug_rt_mutex_free_waiter(&waiter);
 
 	trace_contention_end(lock, 0);
+	lockevent_cond_inc(rtlock_slow_wake, !wake_q_empty(wake_q));
 }
 
 static __always_inline void __sched rtlock_slowlock(struct rt_mutex_base *lock)
Signature · 1 line
2.47.1
merge bot Applied
#10 lore raw

[tip: locking/core] locking/lock_events: Add locking events for rtmutex slow paths

The following commit has been merged into the locking/core branch of tip:

The following commit has been merged into the locking/core branch of tip:

Commit-ID:     b76b44fb656100fcd8482d9102d35d1b6a5129e9
Gitweb:        https://git.kernel.org/tip/b76b44fb656100fcd8482d9102d35d1b6a5129e9
Author:        Waiman Long <[email protected]>
AuthorDate:    Fri, 07 Mar 2025 15:26:53 -08:00
Committer:     Ingo Molnar <[email protected]>
CommitterDate: Sat, 08 Mar 2025 00:55:03 +01:00

locking/lock_events: Add locking events for rtmutex slow paths

Add locking events for rtlock_slowlock() and rt_mutex_slowlock() for profiling the slow path behavior of rt_spin_lock() and rt_mutex_lock().

---
 kernel/locking/lock_events_list.h | 21 +++++++++++++++++++++
 kernel/locking/rtmutex.c          | 29 ++++++++++++++++++++++++-----
 2 files changed, 45 insertions(+), 5 deletions(-)
kernel/locking/lock_events_list.h +21 -0
index 97fb6f3..80b11f1 100644
@@ -67,3 +67,24 @@ LOCK_EVENT(rwsem_rlock_handoff)	/* # of read lock handoffs		*/
 LOCK_EVENT(rwsem_wlock)		/* # of write locks acquired		*/
 LOCK_EVENT(rwsem_wlock_fail)	/* # of failed write lock acquisitions	*/
 LOCK_EVENT(rwsem_wlock_handoff)	/* # of write lock handoffs		*/
+
+/*
+ * Locking events for rtlock_slowlock()
+ */
+LOCK_EVENT(rtlock_slowlock)	/* # of rtlock_slowlock() calls		*/
+LOCK_EVENT(rtlock_slow_acq1)	/* # of locks acquired after wait_lock	*/
+LOCK_EVENT(rtlock_slow_acq2)	/* # of locks acquired in for loop	*/
+LOCK_EVENT(rtlock_slow_sleep)	/* # of sleeps				*/
+LOCK_EVENT(rtlock_slow_wake)	/* # of wakeup's			*/
+
+/*
+ * Locking events for rt_mutex_slowlock()
+ */
+LOCK_EVENT(rtmutex_slowlock)	/* # of rt_mutex_slowlock() calls	*/
+LOCK_EVENT(rtmutex_slow_block)	/* # of rt_mutex_slowlock_block() calls	*/
+LOCK_EVENT(rtmutex_slow_acq1)	/* # of locks acquired after wait_lock	*/
+LOCK_EVENT(rtmutex_slow_acq2)	/* # of locks acquired at the end	*/
+LOCK_EVENT(rtmutex_slow_acq3)	/* # of locks acquired in *block()	*/
+LOCK_EVENT(rtmutex_slow_sleep)	/* # of sleeps				*/
+LOCK_EVENT(rtmutex_slow_wake)	/* # of wakeup's			*/
+LOCK_EVENT(rtmutex_deadlock)	/* # of rt_mutex_handle_deadlock()'s	*/
kernel/locking/rtmutex.c +24 -5
index 4a8df18..c80902e 100644
@@ -27,6 +27,7 @@
 #include <trace/events/lock.h>
 
 #include "rtmutex_common.h"
+#include "lock_events.h"
 
 #ifndef WW_RT
 # define build_ww_mutex()	(false)
@@ -1612,10 +1613,13 @@ static int __sched rt_mutex_slowlock_block(struct rt_mutex_base *lock,
 	struct task_struct *owner;
 	int ret = 0;
 
+	lockevent_inc(rtmutex_slow_block);
 	for (;;) {
 		/* Try to acquire the lock: */
-		if (try_to_take_rt_mutex(lock, current, waiter))
+		if (try_to_take_rt_mutex(lock, current, waiter)) {
+			lockevent_inc(rtmutex_slow_acq3);
 			break;
+		}
 
 		if (timeout && !timeout->task) {
 			ret = -ETIMEDOUT;
@@ -1638,8 +1642,10 @@ static int __sched rt_mutex_slowlock_block(struct rt_mutex_base *lock,
 			owner = NULL;
 		raw_spin_unlock_irq_wake(&lock->wait_lock, wake_q);
 
-		if (!owner || !rtmutex_spin_on_owner(lock, waiter, owner))
+		if (!owner || !rtmutex_spin_on_owner(lock, waiter, owner)) {
+			lockevent_inc(rtmutex_slow_sleep);
 			rt_mutex_schedule();
+		}
 
 		raw_spin_lock_irq(&lock->wait_lock);
 		set_current_state(state);
@@ -1694,6 +1700,7 @@ static int __sched __rt_mutex_slowlock(struct rt_mutex_base *lock,
 	int ret;
 
 	lockdep_assert_held(&lock->wait_lock);
+	lockevent_inc(rtmutex_slowlock);
 
 	/* Try to acquire the lock again: */
 	if (try_to_take_rt_mutex(lock, current, NULL)) {
@@ -1701,6 +1708,7 @@ static int __sched __rt_mutex_slowlock(struct rt_mutex_base *lock,
 			__ww_mutex_check_waiters(rtm, ww_ctx, wake_q);
 			ww_mutex_lock_acquired(ww, ww_ctx);
 		}
+		lockevent_inc(rtmutex_slow_acq1);
 		return 0;
 	}
 
@@ -1719,10 +1727,12 @@ static int __sched __rt_mutex_slowlock(struct rt_mutex_base *lock,
 				__ww_mutex_check_waiters(rtm, ww_ctx, wake_q);
 			ww_mutex_lock_acquired(ww, ww_ctx);
 		}
+		lockevent_inc(rtmutex_slow_acq2);
 	} else {
 		__set_current_state(TASK_RUNNING);
 		remove_waiter(lock, waiter);
 		rt_mutex_handle_deadlock(ret, chwalk, lock, waiter);
+		lockevent_inc(rtmutex_deadlock);
 	}
 
 	/*
@@ -1751,6 +1761,7 @@ static inline int __rt_mutex_slowlock_locked(struct rt_mutex_base *lock,
 				  &waiter, wake_q);
 
 	debug_rt_mutex_free_waiter(&waiter);
+	lockevent_cond_inc(rtmutex_slow_wake, !wake_q_empty(wake_q));
 	return ret;
 }
 
@@ -1823,9 +1834,12 @@ static void __sched rtlock_slowlock_locked(struct rt_mutex_base *lock,
 	struct task_struct *owner;
 
 	lockdep_assert_held(&lock->wait_lock);
+	lockevent_inc(rtlock_slowlock);
 
-	if (try_to_take_rt_mutex(lock, current, NULL))
+	if (try_to_take_rt_mutex(lock, current, NULL)) {
+		lockevent_inc(rtlock_slow_acq1);
 		return;
+	}
 
 	rt_mutex_init_rtlock_waiter(&waiter);
 
@@ -1838,8 +1852,10 @@ static void __sched rtlock_slowlock_locked(struct rt_mutex_base *lock,
 
 	for (;;) {
 		/* Try to acquire the lock again */
-		if (try_to_take_rt_mutex(lock, current, &waiter))
+		if (try_to_take_rt_mutex(lock, current, &waiter)) {
+			lockevent_inc(rtlock_slow_acq2);
 			break;
+		}
 
 		if (&waiter == rt_mutex_top_waiter(lock))
 			owner = rt_mutex_owner(lock);
@@ -1847,8 +1863,10 @@ static void __sched rtlock_slowlock_locked(struct rt_mutex_base *lock,
 			owner = NULL;
 		raw_spin_unlock_irq_wake(&lock->wait_lock, wake_q);
 
-		if (!owner || !rtmutex_spin_on_owner(lock, &waiter, owner))
+		if (!owner || !rtmutex_spin_on_owner(lock, &waiter, owner)) {
+			lockevent_inc(rtlock_slow_sleep);
 			schedule_rtlock();
+		}
 
 		raw_spin_lock_irq(&lock->wait_lock);
 		set_current_state(TASK_RTLOCK_WAIT);
@@ -1865,6 +1883,7 @@ static void __sched rtlock_slowlock_locked(struct rt_mutex_base *lock,
 	debug_rt_mutex_free_waiter(&waiter);
 
 	trace_contention_end(lock, 0);
+	lockevent_cond_inc(rtlock_slow_wake, !wake_q_empty(wake_q));
 }
 
 static __always_inline void __sched rtlock_slowlock(struct rt_mutex_base *lock)
author
#11 lore raw

PATCH 4/11 locking/lock_events: Add locking events for lockdep

In reply to Boqun Feng

From: Waiman Long <[email protected]>

Add some lock events to the lockdep for profiling its behavior.

---
 kernel/locking/lock_events_list.h | 7 +++++++
 kernel/locking/lockdep.c          | 8 +++++++-
 2 files changed, 14 insertions(+), 1 deletion(-)
kernel/locking/lock_events_list.h +7 -0
index 80b11f194c9f..9ef9850aeebe 100644
@@ -88,3 +88,10 @@ LOCK_EVENT(rtmutex_slow_acq3)	/* # of locks acquired in *block()	*/
 LOCK_EVENT(rtmutex_slow_sleep)	/* # of sleeps				*/
 LOCK_EVENT(rtmutex_slow_wake)	/* # of wakeup's			*/
 LOCK_EVENT(rtmutex_deadlock)	/* # of rt_mutex_handle_deadlock()'s	*/
+
+/*
+ * Locking events for lockdep
+ */
+LOCK_EVENT(lockdep_acquire)
+LOCK_EVENT(lockdep_lock)
+LOCK_EVENT(lockdep_nocheck)
kernel/locking/lockdep.c +7 -1
index 4470680f0226..8436f017c74d 100644
@@ -61,6 +61,7 @@
 #include <asm/sections.h>
 
 #include "lockdep_internals.h"
+#include "lock_events.h"
 
 #include <trace/events/lock.h>
 
@@ -170,6 +171,7 @@ static struct task_struct *lockdep_selftest_task_struct;
 static int graph_lock(void)
 {
 	lockdep_lock();
+	lockevent_inc(lockdep_lock);
 	/*
 	 * Make sure that if another CPU detected a bug while
 	 * walking the graph we dont change it (while the other
@@ -5091,8 +5093,12 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
 	if (unlikely(lock->key == &__lockdep_no_track__))
 		return 0;
 
-	if (!prove_locking || lock->key == &__lockdep_no_validate__)
+	lockevent_inc(lockdep_acquire);
+
+	if (!prove_locking || lock->key == &__lockdep_no_validate__) {
 		check = 0;
+		lockevent_inc(lockdep_nocheck);
+	}
 
 	if (subclass < NR_LOCKDEP_CACHING_CLASSES)
 		class = lock->class_cache[subclass];
Signature · 1 line
2.47.1
merge bot Applied
#12 lore raw

[tip: locking/core] locking/lock_events: Add locking events for lockdep

The following commit has been merged into the locking/core branch of tip:

The following commit has been merged into the locking/core branch of tip:

Commit-ID:     a94d32446ab5e85c7ba97e48a8c9bd85be4fe889
Gitweb:        https://git.kernel.org/tip/a94d32446ab5e85c7ba97e48a8c9bd85be4fe889
Author:        Waiman Long <[email protected]>
AuthorDate:    Fri, 07 Mar 2025 15:26:54 -08:00
Committer:     Ingo Molnar <[email protected]>
CommitterDate: Sat, 08 Mar 2025 00:55:03 +01:00

locking/lock_events: Add locking events for lockdep

Add some lock events to lockdep to profile its behavior.

---
 kernel/locking/lock_events_list.h | 7 +++++++
 kernel/locking/lockdep.c          | 8 +++++++-
 2 files changed, 14 insertions(+), 1 deletion(-)
kernel/locking/lock_events_list.h +7 -0
index 80b11f1..9ef9850 100644
@@ -88,3 +88,10 @@ LOCK_EVENT(rtmutex_slow_acq3)	/* # of locks acquired in *block()	*/
 LOCK_EVENT(rtmutex_slow_sleep)	/* # of sleeps				*/
 LOCK_EVENT(rtmutex_slow_wake)	/* # of wakeup's			*/
 LOCK_EVENT(rtmutex_deadlock)	/* # of rt_mutex_handle_deadlock()'s	*/
+
+/*
+ * Locking events for lockdep
+ */
+LOCK_EVENT(lockdep_acquire)
+LOCK_EVENT(lockdep_lock)
+LOCK_EVENT(lockdep_nocheck)
kernel/locking/lockdep.c +7 -1
index 4470680..8436f01 100644
@@ -61,6 +61,7 @@
 #include <asm/sections.h>
 
 #include "lockdep_internals.h"
+#include "lock_events.h"
 
 #include <trace/events/lock.h>
 
@@ -170,6 +171,7 @@ static struct task_struct *lockdep_selftest_task_struct;
 static int graph_lock(void)
 {
 	lockdep_lock();
+	lockevent_inc(lockdep_lock);
 	/*
 	 * Make sure that if another CPU detected a bug while
 	 * walking the graph we dont change it (while the other
@@ -5091,8 +5093,12 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass,
 	if (unlikely(lock->key == &__lockdep_no_track__))
 		return 0;
 
-	if (!prove_locking || lock->key == &__lockdep_no_validate__)
+	lockevent_inc(lockdep_acquire);
+
+	if (!prove_locking || lock->key == &__lockdep_no_validate__) {
 		check = 0;
+		lockevent_inc(lockdep_nocheck);
+	}
 
 	if (subclass < NR_LOCKDEP_CACHING_CLASSES)
 		class = lock->class_cache[subclass];
author
#13 lore raw

PATCH 5/11 locking/lockdep: Disable KASAN instrumentation of lockdep.c

In reply to Boqun Feng

From: Waiman Long <[email protected]>

Both KASAN and LOCKDEP are commonly enabled in building a debug kernel. Each of them can significantly slow down the speed of a debug kernel. Enabling KASAN instrumentation of the LOCKDEP code will further slow thing down.

Since LOCKDEP is a high overhead debugging tool, it will never get enabled in a production kernel. The LOCKDEP code is also pretty mature and is unlikely to get major changes. There is also a possibility of recursion similar to KCSAN.

To evaluate the performance impact of disabling KASAN instrumentation of lockdep.c, the time to do a parallel build of the Linux defconfig kernel was used as the benchmark. Two x86-64 systems (Skylake & Zen 2) and an arm64 system were used as test beds. Two sets of non-RT and RT kernels with similar configurations except mainly CONFIG_PREEMPT_RT were used for evaulation.

For the Skylake system:

Kernel Run time Sys time
------ -------- --------
Non-debug kernel (baseline) 0m47.642s 4m19.811s

[CONFIG_KASAN_INLINE=y]
Debug kernel 2m11.108s (x2.8) 38m20.467s (x8.9)
Debug kernel (patched) 1m49.602s (x2.3) 31m28.501s (x7.3)
Debug kernel
(patched + mitigations=off) 1m30.988s (x1.9) 26m41.993s (x6.2)

RT kernel (baseline) 0m54.871s 7m15.340s

[CONFIG_KASAN_INLINE=n]
RT debug kernel 6m07.151s (x6.7) 135m47.428s (x18.7)
RT debug kernel (patched) 3m42.434s (x4.1) 74m51.636s (x10.3)
RT debug kernel
(patched + mitigations=off) 2m40.383s (x2.9) 57m54.369s (x8.0)

[CONFIG_KASAN_INLINE=y]
RT debug kernel 3m22.155s (x3.7) 77m53.018s (x10.7)
RT debug kernel (patched) 2m36.700s (x2.9) 54m31.195s (x7.5)
RT debug kernel
(patched + mitigations=off) 2m06.110s (x2.3) 45m49.493s (x6.3)

For the Zen 2 system:

Kernel Run time Sys time
------ -------- --------
Non-debug kernel (baseline) 1m42.806s 39m48.714s

[CONFIG_KASAN_INLINE=y]
Debug kernel 4m04.524s (x2.4) 125m35.904s (x3.2)
Debug kernel (patched) 3m56.241s (x2.3) 127m22.378s (x3.2)
Debug kernel
(patched + mitigations=off) 2m38.157s (x1.5) 92m35.680s (x2.3)

RT kernel (baseline) 1m51.500s 14m56.322s

[CONFIG_KASAN_INLINE=n]
RT debug kernel 16m04.962s (x8.7) 244m36.463s (x16.4)
RT debug kernel (patched) 9m09.073s (x4.9) 129m28.439s (x8.7)
RT debug kernel
(patched + mitigations=off) 3m31.662s (x1.9) 51m01.391s (x3.4)

For the arm64 system:

Kernel Run time Sys time
------ -------- --------
Non-debug kernel (baseline) 1m56.844s 8m47.150s
Debug kernel 3m54.774s (x2.0) 92m30.098s (x10.5)
Debug kernel (patched) 3m32.429s (x1.8) 77m40.779s (x8.8)

RT kernel (baseline) 4m01.641s 18m16.777s

[CONFIG_KASAN_INLINE=n]
RT debug kernel 19m32.977s (x4.9) 304m23.965s (x16.7)
RT debug kernel (patched) 16m28.354s (x4.1) 234m18.149s (x12.8)

Turning the mitigations off doesn't seems to have any noticeable impact on the performance of the arm64 system. So the mitigation=off entries aren't included.

For the x86 CPUs, cpu mitigations has a much bigger
impact on performance, especially the RT debug kernel with CONFIG_KASAN_INLINE=n. The SRSO mitigation in Zen 2 has an especially big impact on the debug kernel. It is also the majority of the slowdown with mitigations on. It is because the patched ret instruction slows down function returns. A lot of helper functions that are normally compiled out or inlined may become real function calls in the debug kernel.

With CONFIG_KASAN_INLINE=n, the KASAN instrumentation inserts a lot of __asan_loadX*() and __kasan_check_read() function calls to memory access portion of the code. The lockdep's __lock_acquire() function, for instance, has 66 __asan_loadX*() and 6 __kasan_check_read() calls added with KASAN instrumentation. Of course, the actual numbers may vary depending on the compiler used and the exact version of the lockdep code.

With the Skylake test system, the parallel kernel build times reduction of the RT debug kernel with this patch are:

CONFIG_KASAN_INLINE=n: -37%
CONFIG_KASAN_INLINE=y: -22%

The time reduction is less with CONFIG_KASAN_INLINE=y, but it is still significant.

Setting CONFIG_KASAN_INLINE=y can result in a significant performance improvement. The major drawback is a significant increase in the size of kernel text. In the case of vmlinux, its text size increases from 45997948 to 67606807. That is a 47% size increase (about 21 Mbytes). The size increase of other kernel modules should be similar.

With the newly added rtmutex and lockdep lock events, the relevant event counts for the test runs with the Skylake system were:

Event type Debug kernel RT debug kernel
---------- ------------ ---------------
lockdep_acquire 1,968,663,277 5,425,313,953
rtlock_slowlock - 401,701,156
rtmutex_slowlock - 139,672

The __lock_acquire() calls in the RT debug kernel are x2.8 times of the non-RT debug kernel with the same workload. Since the __lock_acquire() function is a big hitter in term of performance slowdown, this makes the RT debug kernel much slower than the non-RT one. The average lock nesting depth is likely to be higher in the RT debug kernel too leading to longer execution time in the __lock_acquire() function.

As the small advantage of enabling KASAN instrumentation to catch potential memory access error in the lockdep debugging tool is probably not worth the drawback of further slowing down a debug kernel, disable KASAN instrumentation in the lockdep code to allow the debug kernels to regain some performance back, especially for the RT debug kernels.

---
 kernel/locking/Makefile | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/locking/Makefile +2 -1
index 0db4093d17b8..a114949eeed5 100644
@@ -5,7 +5,8 @@ KCOV_INSTRUMENT		:= n
 
 obj-y += mutex.o semaphore.o rwsem.o percpu-rwsem.o
 
-# Avoid recursion lockdep -> sanitizer -> ... -> lockdep.
+# Avoid recursion lockdep -> sanitizer -> ... -> lockdep & improve performance.
+KASAN_SANITIZE_lockdep.o := n
 KCSAN_SANITIZE_lockdep.o := n
 
 ifdef CONFIG_FUNCTION_TRACER
Signature · 1 line
2.47.1
merge bot Applied
#14 lore raw

[tip: locking/core] locking/lockdep: Disable KASAN instrumentation of lockdep.c

The following commit has been merged into the locking/core branch of tip:

The following commit has been merged into the locking/core branch of tip:

Commit-ID:     ee57ab5a32129f599ee1d358548dbebcb5e45953
Gitweb:        https://git.kernel.org/tip/ee57ab5a32129f599ee1d358548dbebcb5e45953
Author:        Waiman Long <[email protected]>
AuthorDate:    Fri, 07 Mar 2025 15:26:55 -08:00
Committer:     Ingo Molnar <[email protected]>
CommitterDate: Sat, 08 Mar 2025 00:55:03 +01:00

locking/lockdep: Disable KASAN instrumentation of lockdep.c

Both KASAN and LOCKDEP are commonly enabled in building a debug kernel. Each of them can significantly slow down the speed of a debug kernel. Enabling KASAN instrumentation of the LOCKDEP code will further slow things down.

Since LOCKDEP is a high overhead debugging tool, it will never get enabled in a production kernel. The LOCKDEP code is also pretty mature and is unlikely to get major changes. There is also a possibility of recursion similar to KCSAN.

To evaluate the performance impact of disabling KASAN instrumentation of lockdep.c, the time to do a parallel build of the Linux defconfig kernel was used as the benchmark. Two x86-64 systems (Skylake & Zen 2) and an arm64 system were used as test beds. Two sets of non-RT and RT kernels with similar configurations except mainly CONFIG_PREEMPT_RT were used for evaluation.

For the Skylake system:

Kernel Run time Sys time
------ -------- --------
Non-debug kernel (baseline) 0m47.642s 4m19.811s

[CONFIG_KASAN_INLINE=y]
Debug kernel 2m11.108s (x2.8) 38m20.467s (x8.9)
Debug kernel (patched) 1m49.602s (x2.3) 31m28.501s (x7.3)
Debug kernel
(patched + mitigations=off) 1m30.988s (x1.9) 26m41.993s (x6.2)

RT kernel (baseline) 0m54.871s 7m15.340s

[CONFIG_KASAN_INLINE=n]
RT debug kernel 6m07.151s (x6.7) 135m47.428s (x18.7)
RT debug kernel (patched) 3m42.434s (x4.1) 74m51.636s (x10.3)
RT debug kernel
(patched + mitigations=off) 2m40.383s (x2.9) 57m54.369s (x8.0)

[CONFIG_KASAN_INLINE=y]
RT debug kernel 3m22.155s (x3.7) 77m53.018s (x10.7)
RT debug kernel (patched) 2m36.700s (x2.9) 54m31.195s (x7.5)
RT debug kernel
(patched + mitigations=off) 2m06.110s (x2.3) 45m49.493s (x6.3)

For the Zen 2 system:

Kernel Run time Sys time
------ -------- --------
Non-debug kernel (baseline) 1m42.806s 39m48.714s

[CONFIG_KASAN_INLINE=y]
Debug kernel 4m04.524s (x2.4) 125m35.904s (x3.2)
Debug kernel (patched) 3m56.241s (x2.3) 127m22.378s (x3.2)
Debug kernel
(patched + mitigations=off) 2m38.157s (x1.5) 92m35.680s (x2.3)

RT kernel (baseline) 1m51.500s 14m56.322s

[CONFIG_KASAN_INLINE=n]
RT debug kernel 16m04.962s (x8.7) 244m36.463s (x16.4)
RT debug kernel (patched) 9m09.073s (x4.9) 129m28.439s (x8.7)
RT debug kernel
(patched + mitigations=off) 3m31.662s (x1.9) 51m01.391s (x3.4)

For the arm64 system:

Kernel Run time Sys time
------ -------- --------
Non-debug kernel (baseline) 1m56.844s 8m47.150s
Debug kernel 3m54.774s (x2.0) 92m30.098s (x10.5)
Debug kernel (patched) 3m32.429s (x1.8) 77m40.779s (x8.8)

RT kernel (baseline) 4m01.641s 18m16.777s

[CONFIG_KASAN_INLINE=n]
RT debug kernel 19m32.977s (x4.9) 304m23.965s (x16.7)
RT debug kernel (patched) 16m28.354s (x4.1) 234m18.149s (x12.8)

Turning the mitigations off doesn't seems to have any noticeable impact on the performance of the arm64 system. So the mitigation=off entries aren't included.

For the x86 CPUs, CPU mitigations has a much bigger
impact on performance, especially the RT debug kernel with CONFIG_KASAN_INLINE=n. The SRSO mitigation in Zen 2 has an especially big impact on the debug kernel. It is also the majority of the slowdown with mitigations on. It is because the patched RET instruction slows down function returns. A lot of helper functions that are normally compiled out or inlined may become real function calls in the debug kernel.

With !CONFIG_KASAN_INLINE, the KASAN instrumentation inserts a lot of __asan_loadX*() and __kasan_check_read() function calls to memory access portion of the code. The lockdep's __lock_acquire() function, for instance, has 66 __asan_loadX*() and 6 __kasan_check_read() calls added with KASAN instrumentation. Of course, the actual numbers may vary depending on the compiler used and the exact version of the lockdep code.

With the Skylake test system, the parallel kernel build times reduction of the RT debug kernel with this patch are:

CONFIG_KASAN_INLINE=n: -37%
CONFIG_KASAN_INLINE=y: -22%

The time reduction is less with CONFIG_KASAN_INLINE=y, but it is still significant.

Setting CONFIG_KASAN_INLINE=y can result in a significant performance improvement. The major drawback is a significant increase in the size of kernel text. In the case of vmlinux, its text size increases from 45997948 to 67606807. That is a 47% size increase (about 21 Mbytes). The size increase of other kernel modules should be similar.

With the newly added rtmutex and lockdep lock events, the relevant event counts for the test runs with the Skylake system were:

Event type Debug kernel RT debug kernel
---------- ------------ ---------------
lockdep_acquire 1,968,663,277 5,425,313,953
rtlock_slowlock - 401,701,156
rtmutex_slowlock - 139,672

The __lock_acquire() calls in the RT debug kernel are x2.8 times of the non-RT debug kernel with the same workload. Since the __lock_acquire() function is a big hitter in term of performance slowdown, this makes the RT debug kernel much slower than the non-RT one. The average lock nesting depth is likely to be higher in the RT debug kernel too leading to longer execution time in the __lock_acquire() function.

As the small advantage of enabling KASAN instrumentation to catch potential memory access error in the lockdep debugging tool is probably not worth the drawback of further slowing down a debug kernel, disable KASAN instrumentation in the lockdep code to allow the debug kernels to regain some performance back, especially for the RT debug kernels.

---
 kernel/locking/Makefile | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/locking/Makefile +2 -1
index 0db4093..a114949 100644
@@ -5,7 +5,8 @@ KCOV_INSTRUMENT		:= n
 
 obj-y += mutex.o semaphore.o rwsem.o percpu-rwsem.o
 
-# Avoid recursion lockdep -> sanitizer -> ... -> lockdep.
+# Avoid recursion lockdep -> sanitizer -> ... -> lockdep & improve performance.
+KASAN_SANITIZE_lockdep.o := n
 KCSAN_SANITIZE_lockdep.o := n
 
 ifdef CONFIG_FUNCTION_TRACER
author
#15 lore raw

PATCH 6/11 locking/lockdep: Add kasan_check_byte() check in lock_acquire()

In reply to Boqun Feng

From: Waiman Long <[email protected]>

KASAN instrumentation of lockdep has been disabled as we don't need KASAN to check the validity of lockdep internal data structures and incur unnecessary performance overhead. However, the lockdep_map pointer passed in externally may not be valid (e.g. use-after-free) and we run the risk of using garbage data resulting in false lockdep reports.

Add kasan_check_byte() call in lock_acquire() for non kernel core data object to catch invalid lockdep_map and print out a KASAN report before any lockdep splat, if any.

---
 kernel/locking/lockdep.c | 9 +++++++++
 1 file changed, 9 insertions(+)
kernel/locking/lockdep.c +9 -0
index 8436f017c74d..b15757e63626 100644
@@ -57,6 +57,7 @@
 #include <linux/lockdep.h>
 #include <linux/context_tracking.h>
 #include <linux/console.h>
+#include <linux/kasan.h>
 
 #include <asm/sections.h>
 
@@ -5830,6 +5831,14 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
 	if (!debug_locks)
 		return;
 
+	/*
+	 * As KASAN instrumentation is disabled and lock_acquire() is usually
+	 * the first lockdep call when a task tries to acquire a lock, add
+	 * kasan_check_byte() here to check for use-after-free and other
+	 * memory errors.
+	 */
+	kasan_check_byte(lock);
+
 	if (unlikely(!lockdep_enabled())) {
 		/* XXX allow trylock from NMI ?!? */
 		if (lockdep_nmi() && !trylock) {
Signature · 1 line
2.47.1
merge bot Applied
#16 lore raw

[tip: locking/core] locking/lockdep: Add kasan_check_byte() check in lock_acquire()

The following commit has been merged into the locking/core branch of tip:

The following commit has been merged into the locking/core branch of tip:

Commit-ID:     de4b59d652646cf00cf632174348ca2266099edc
Gitweb:        https://git.kernel.org/tip/de4b59d652646cf00cf632174348ca2266099edc
Author:        Waiman Long <[email protected]>
AuthorDate:    Fri, 07 Mar 2025 15:26:56 -08:00
Committer:     Ingo Molnar <[email protected]>
CommitterDate: Sat, 08 Mar 2025 00:55:04 +01:00

locking/lockdep: Add kasan_check_byte() check in lock_acquire()

KASAN instrumentation of lockdep has been disabled, as we don't need KASAN to check the validity of lockdep internal data structures and incur unnecessary performance overhead. However, the lockdep_map pointer passed in externally may not be valid (e.g. use-after-free) and we run the risk of using garbage data resulting in false lockdep reports.

Add kasan_check_byte() call in lock_acquire() for non kernel core data object to catch invalid lockdep_map and print out a KASAN report before any lockdep splat, if any.

---
 kernel/locking/lockdep.c |  9 +++++++++
 1 file changed, 9 insertions(+)
kernel/locking/lockdep.c +9 -0
index 8436f01..b15757e 100644
@@ -57,6 +57,7 @@
 #include <linux/lockdep.h>
 #include <linux/context_tracking.h>
 #include <linux/console.h>
+#include <linux/kasan.h>
 
 #include <asm/sections.h>
 
@@ -5830,6 +5831,14 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass,
 	if (!debug_locks)
 		return;
 
+	/*
+	 * As KASAN instrumentation is disabled and lock_acquire() is usually
+	 * the first lockdep call when a task tries to acquire a lock, add
+	 * kasan_check_byte() here to check for use-after-free and other
+	 * memory errors.
+	 */
+	kasan_check_byte(lock);
+
 	if (unlikely(!lockdep_enabled())) {
 		/* XXX allow trylock from NMI ?!? */
 		if (lockdep_nmi() && !trylock) {
author
#17 lore raw

PATCH 7/11 rust: sync: Add accessor for the lock behind a given guard

In reply to Boqun Feng

From: Alice Ryhl <[email protected]>

In order to assert a particular Guard is associated with a particular Lock, add an accessor to obtain a reference to the underlying Lock of a Guard.

Binder needs this assertion to ensure unsafe list operations are done with the correct lock held.

[Boqun: Capitalize the title and reword the commit log]

---
 rust/kernel/sync/lock.rs | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
rust/kernel/sync/lock.rs +6 -1
index eb80048e0110..8e7e6d5f61e4 100644
@@ -199,7 +199,12 @@ pub struct Guard<'a, T: ?Sized, B: Backend> {
 // SAFETY: `Guard` is sync when the data protected by the lock is also sync.
 unsafe impl<T: Sync + ?Sized, B: Backend> Sync for Guard<'_, T, B> {}
 
-impl<T: ?Sized, B: Backend> Guard<'_, T, B> {
+impl<'a, T: ?Sized, B: Backend> Guard<'a, T, B> {
+    /// Returns the lock that this guard originates from.
+    pub fn lock_ref(&self) -> &'a Lock<T, B> {
+        self.lock
+    }
+
     pub(crate) fn do_unlocked<U>(&mut self, cb: impl FnOnce() -> U) -> U {
         // SAFETY: The caller owns the lock, so it is safe to unlock it.
         unsafe { B::unlock(self.lock.state.get(), &self.state) };
Signature · 1 line
2.47.1
merge bot Applied
#18 lore raw

[tip: locking/core] rust: sync: Add accessor for the lock behind a given guard

The following commit has been merged into the locking/core branch of tip:

The following commit has been merged into the locking/core branch of tip:

Commit-ID:     8f65291dae0e75941cf76e427088e5612c4d692e
Gitweb:        https://git.kernel.org/tip/8f65291dae0e75941cf76e427088e5612c4d692e
Author:        Alice Ryhl <[email protected]>
AuthorDate:    Fri, 07 Mar 2025 15:26:57 -08:00
Committer:     Ingo Molnar <[email protected]>
CommitterDate: Sat, 08 Mar 2025 00:55:04 +01:00

rust: sync: Add accessor for the lock behind a given guard

In order to assert a particular Guard is associated with a particular Lock, add an accessor to obtain a reference to the underlying Lock of a Guard.

Binder needs this assertion to ensure unsafe list operations are done with the correct lock held.

[Boqun: Capitalize the title and reword the commit log]

---
 rust/kernel/sync/lock.rs | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
rust/kernel/sync/lock.rs +6 -1
index eb80048..8e7e6d5 100644
@@ -199,7 +199,12 @@ pub struct Guard<'a, T: ?Sized, B: Backend> {
 // SAFETY: `Guard` is sync when the data protected by the lock is also sync.
 unsafe impl<T: Sync + ?Sized, B: Backend> Sync for Guard<'_, T, B> {}
 
-impl<T: ?Sized, B: Backend> Guard<'_, T, B> {
+impl<'a, T: ?Sized, B: Backend> Guard<'a, T, B> {
+    /// Returns the lock that this guard originates from.
+    pub fn lock_ref(&self) -> &'a Lock<T, B> {
+        self.lock
+    }
+
     pub(crate) fn do_unlocked<U>(&mut self, cb: impl FnOnce() -> U) -> U {
         // SAFETY: The caller owns the lock, so it is safe to unlock it.
         unsafe { B::unlock(self.lock.state.get(), &self.state) };
author
#19 lore raw

PATCH 8/11 rust: sync: lock: Add an example for Guard::lock_ref()

In reply to Boqun Feng

To provide examples on usage of Guard::lock_ref() along with the unit test, an "assert a lock is held by a guard" example is added.

[boqun: Apply feedback from Benno]

---
 rust/kernel/sync/lock.rs | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
rust/kernel/sync/lock.rs +24 -0
index 8e7e6d5f61e4..f53e87d04cd2 100644
@@ -201,6 +201,30 @@ unsafe impl<T: Sync + ?Sized, B: Backend> Sync for Guard<'_, T, B> {}
 
 impl<'a, T: ?Sized, B: Backend> Guard<'a, T, B> {
     /// Returns the lock that this guard originates from.
+    ///
+    /// # Examples
+    ///
+    /// The following example shows how to use [`Guard::lock_ref()`] to assert the corresponding
+    /// lock is held.
+    ///
+    /// ```
+    /// # use kernel::{new_spinlock, stack_pin_init, sync::lock::{Backend, Guard, Lock}};
+    ///
+    /// fn assert_held<T, B: Backend>(guard: &Guard<'_, T, B>, lock: &Lock<T, B>) {
+    ///     // Address-equal means the same lock.
+    ///     assert!(core::ptr::eq(guard.lock_ref(), lock));
+    /// }
+    ///
+    /// // Creates a new lock on the stack.
+    /// stack_pin_init!{
+    ///     let l = new_spinlock!(42)
+    /// }
+    ///
+    /// let g = l.lock();
+    ///
+    /// // `g` originates from `l`.
+    /// assert_held(&g, &l);
+    /// ```
     pub fn lock_ref(&self) -> &'a Lock<T, B> {
         self.lock
     }
Signature · 1 line
2.47.1
merge bot Applied
#20 lore raw

[tip: locking/core] rust: sync: lock: Add an example for Guard:: Lock_ref()

The following commit has been merged into the locking/core branch of tip:

The following commit has been merged into the locking/core branch of tip:

Commit-ID:     c2849afafd08a1c3ad881129de48ebe1642f7675
Gitweb:        https://git.kernel.org/tip/c2849afafd08a1c3ad881129de48ebe1642f7675
Author:        Boqun Feng <[email protected]>
AuthorDate:    Fri, 07 Mar 2025 15:26:58 -08:00
Committer:     Ingo Molnar <[email protected]>
CommitterDate: Sat, 08 Mar 2025 00:55:04 +01:00

rust: sync: lock: Add an example for Guard:: Lock_ref()

To provide examples on usage of Guard::lock_ref() along with the unit test, an "assert a lock is held by a guard" example is added.

(Also apply feedback from Benno.)

---
 rust/kernel/sync/lock.rs | 24 ++++++++++++++++++++++++
 1 file changed, 24 insertions(+)
rust/kernel/sync/lock.rs +24 -0
index 8e7e6d5..f53e87d 100644
@@ -201,6 +201,30 @@ unsafe impl<T: Sync + ?Sized, B: Backend> Sync for Guard<'_, T, B> {}
 
 impl<'a, T: ?Sized, B: Backend> Guard<'a, T, B> {
     /// Returns the lock that this guard originates from.
+    ///
+    /// # Examples
+    ///
+    /// The following example shows how to use [`Guard::lock_ref()`] to assert the corresponding
+    /// lock is held.
+    ///
+    /// ```
+    /// # use kernel::{new_spinlock, stack_pin_init, sync::lock::{Backend, Guard, Lock}};
+    ///
+    /// fn assert_held<T, B: Backend>(guard: &Guard<'_, T, B>, lock: &Lock<T, B>) {
+    ///     // Address-equal means the same lock.
+    ///     assert!(core::ptr::eq(guard.lock_ref(), lock));
+    /// }
+    ///
+    /// // Creates a new lock on the stack.
+    /// stack_pin_init!{
+    ///     let l = new_spinlock!(42)
+    /// }
+    ///
+    /// let g = l.lock();
+    ///
+    /// // `g` originates from `l`.
+    /// assert_held(&g, &l);
+    /// ```
     pub fn lock_ref(&self) -> &'a Lock<T, B> {
         self.lock
     }
author
#21 lore raw

PATCH 9/11 rust: sync: condvar: Add wait_interruptible_freezable()

In reply to Boqun Feng

From: Alice Ryhl <[email protected]>

To support waiting for a CondVar as a freezable process, add a wait_interruptible_freezable() function.

Binder needs this function in the appropriate places to freeze a process where some of its threads are blocked on the Binder driver.

[Boqun: Capitalize the title, reword the commit log and rephrase the function doc comment with the impersonal style to align with rest of the file]

---
 rust/kernel/sync/condvar.rs | 23 ++++++++++++++++++++++-
 rust/kernel/task.rs         |  2 ++
 2 files changed, 24 insertions(+), 1 deletion(-)
rust/kernel/sync/condvar.rs +22 -1
index 7df565038d7d..5c1e546a26c3 100644
@@ -11,7 +11,9 @@
     init::PinInit,
     pin_init,
     str::CStr,
-    task::{MAX_SCHEDULE_TIMEOUT, TASK_INTERRUPTIBLE, TASK_NORMAL, TASK_UNINTERRUPTIBLE},
+    task::{
+        MAX_SCHEDULE_TIMEOUT, TASK_FREEZABLE, TASK_INTERRUPTIBLE, TASK_NORMAL, TASK_UNINTERRUPTIBLE,
+    },
     time::Jiffies,
     types::Opaque,
 };
@@ -159,6 +161,25 @@ pub fn wait_interruptible<T: ?Sized, B: Backend>(&self, guard: &mut Guard<'_, T,
         crate::current!().signal_pending()
     }
 
+    /// Releases the lock and waits for a notification in interruptible and freezable mode.
+    ///
+    /// The process is allowed to be frozen during this sleep. No lock should be held when calling
+    /// this function, and there is a lockdep assertion for this. Freezing a task that holds a lock
+    /// can trivially deadlock vs another task that needs that lock to complete before it too can
+    /// hit freezable.
+    #[must_use = "wait_interruptible_freezable returns if a signal is pending, so the caller must check the return value"]
+    pub fn wait_interruptible_freezable<T: ?Sized, B: Backend>(
+        &self,
+        guard: &mut Guard<'_, T, B>,
+    ) -> bool {
+        self.wait_internal(
+            TASK_INTERRUPTIBLE | TASK_FREEZABLE,
+            guard,
+            MAX_SCHEDULE_TIMEOUT,
+        );
+        crate::current!().signal_pending()
+    }
+
     /// Releases the lock and waits for a notification in interruptible mode.
     ///
     /// Atomically releases the given lock (whose ownership is proven by the guard) and puts the
rust/kernel/task.rs +2 -0
index 07bc22a7645c..ea43a3b8d9c5 100644
@@ -23,6 +23,8 @@
 pub const TASK_INTERRUPTIBLE: c_int = bindings::TASK_INTERRUPTIBLE as c_int;
 /// Bitmask for tasks that are sleeping in an uninterruptible state.
 pub const TASK_UNINTERRUPTIBLE: c_int = bindings::TASK_UNINTERRUPTIBLE as c_int;
+/// Bitmask for tasks that are sleeping in a freezable state.
+pub const TASK_FREEZABLE: c_int = bindings::TASK_FREEZABLE as c_int;
 /// Convenience constant for waking up tasks regardless of whether they are in interruptible or
 /// uninterruptible sleep.
 pub const TASK_NORMAL: c_uint = bindings::TASK_NORMAL as c_uint;
Signature · 1 line
2.47.1
merge bot Applied
#22 lore raw

[tip: locking/core] rust: sync: condvar: Add wait_interruptible_freezable()

The following commit has been merged into the locking/core branch of tip:

The following commit has been merged into the locking/core branch of tip:

Commit-ID:     70b9c8563c9c29102a785d4822f0d77d33fee808
Gitweb:        https://git.kernel.org/tip/70b9c8563c9c29102a785d4822f0d77d33fee808
Author:        Alice Ryhl <[email protected]>
AuthorDate:    Fri, 07 Mar 2025 15:26:59 -08:00
Committer:     Ingo Molnar <[email protected]>
CommitterDate: Sat, 08 Mar 2025 00:55:04 +01:00

rust: sync: condvar: Add wait_interruptible_freezable()

To support waiting for a CondVar as a freezable process, add a wait_interruptible_freezable() function.

Binder needs this function in the appropriate places to freeze a process where some of its threads are blocked on the Binder driver.

[ Boqun: Cleaned up the changelog and documentation. ]

---
 rust/kernel/sync/condvar.rs | 23 ++++++++++++++++++++++-
 rust/kernel/task.rs         |  2 ++
 2 files changed, 24 insertions(+), 1 deletion(-)
rust/kernel/sync/condvar.rs +22 -1
index 7df5650..5c1e546 100644
@@ -11,7 +11,9 @@ use crate::{
     init::PinInit,
     pin_init,
     str::CStr,
-    task::{MAX_SCHEDULE_TIMEOUT, TASK_INTERRUPTIBLE, TASK_NORMAL, TASK_UNINTERRUPTIBLE},
+    task::{
+        MAX_SCHEDULE_TIMEOUT, TASK_FREEZABLE, TASK_INTERRUPTIBLE, TASK_NORMAL, TASK_UNINTERRUPTIBLE,
+    },
     time::Jiffies,
     types::Opaque,
 };
@@ -159,6 +161,25 @@ impl CondVar {
         crate::current!().signal_pending()
     }
 
+    /// Releases the lock and waits for a notification in interruptible and freezable mode.
+    ///
+    /// The process is allowed to be frozen during this sleep. No lock should be held when calling
+    /// this function, and there is a lockdep assertion for this. Freezing a task that holds a lock
+    /// can trivially deadlock vs another task that needs that lock to complete before it too can
+    /// hit freezable.
+    #[must_use = "wait_interruptible_freezable returns if a signal is pending, so the caller must check the return value"]
+    pub fn wait_interruptible_freezable<T: ?Sized, B: Backend>(
+        &self,
+        guard: &mut Guard<'_, T, B>,
+    ) -> bool {
+        self.wait_internal(
+            TASK_INTERRUPTIBLE | TASK_FREEZABLE,
+            guard,
+            MAX_SCHEDULE_TIMEOUT,
+        );
+        crate::current!().signal_pending()
+    }
+
     /// Releases the lock and waits for a notification in interruptible mode.
     ///
     /// Atomically releases the given lock (whose ownership is proven by the guard) and puts the
rust/kernel/task.rs +2 -0
index 07bc22a..ea43a3b 100644
@@ -23,6 +23,8 @@ pub const MAX_SCHEDULE_TIMEOUT: c_long = c_long::MAX;
 pub const TASK_INTERRUPTIBLE: c_int = bindings::TASK_INTERRUPTIBLE as c_int;
 /// Bitmask for tasks that are sleeping in an uninterruptible state.
 pub const TASK_UNINTERRUPTIBLE: c_int = bindings::TASK_UNINTERRUPTIBLE as c_int;
+/// Bitmask for tasks that are sleeping in a freezable state.
+pub const TASK_FREEZABLE: c_int = bindings::TASK_FREEZABLE as c_int;
 /// Convenience constant for waking up tasks regardless of whether they are in interruptible or
 /// uninterruptible sleep.
 pub const TASK_NORMAL: c_uint = bindings::TASK_NORMAL as c_uint;
author
#23 lore raw

PATCH 10/11 rust: lockdep: Remove support for dynamically allocated LockClassKeys

In reply to Boqun Feng

From: Mitchell Levy <[email protected]>

Currently, dynamically allocated LockCLassKeys can be used from the Rust side without having them registered. This is a soundness issue, so remove them.

---
 rust/kernel/sync.rs | 16 ++++------------
 1 file changed, 4 insertions(+), 12 deletions(-)
rust/kernel/sync.rs +4 -12
index 3498fb344dc9..16eab9138b2b 100644
@@ -30,28 +30,20 @@
 unsafe impl Sync for LockClassKey {}
 
 impl LockClassKey {
-    /// Creates a new lock class key.
-    pub const fn new() -> Self {
-        Self(Opaque::uninit())
-    }
-
     pub(crate) fn as_ptr(&self) -> *mut bindings::lock_class_key {
         self.0.get()
     }
 }
 
-impl Default for LockClassKey {
-    fn default() -> Self {
-        Self::new()
-    }
-}
-
 /// Defines a new static lock class and returns a pointer to it.
 #[doc(hidden)]
 #[macro_export]
 macro_rules! static_lock_class {
     () => {{
-        static CLASS: $crate::sync::LockClassKey = $crate::sync::LockClassKey::new();
+        static CLASS: $crate::sync::LockClassKey =
+            // SAFETY: lockdep expects uninitialized memory when it's handed a statically allocated
+            // lock_class_key
+            unsafe { ::core::mem::MaybeUninit::uninit().assume_init() };
         &CLASS
     }};
 }
Signature · 1 line
2.47.1
merge bot Applied
#24 lore raw

[tip: locking/core] rust: lockdep: Remove support for dynamically allocated LockClassKeys

The following commit has been merged into the locking/core branch of tip:

The following commit has been merged into the locking/core branch of tip:

Commit-ID:     966944f3711665db13e214fef6d02982c49bb972
Gitweb:        https://git.kernel.org/tip/966944f3711665db13e214fef6d02982c49bb972
Author:        Mitchell Levy <[email protected]>
AuthorDate:    Fri, 07 Mar 2025 15:27:00 -08:00
Committer:     Ingo Molnar <[email protected]>
CommitterDate: Sat, 08 Mar 2025 00:52:00 +01:00

rust: lockdep: Remove support for dynamically allocated LockClassKeys

Currently, dynamically allocated LockCLassKeys can be used from the Rust side without having them registered. This is a soundness issue, so remove them.

---
 rust/kernel/sync.rs | 16 ++++------------
 1 file changed, 4 insertions(+), 12 deletions(-)
rust/kernel/sync.rs +4 -12
index 3498fb3..16eab91 100644
@@ -30,28 +30,20 @@ pub struct LockClassKey(Opaque<bindings::lock_class_key>);
 unsafe impl Sync for LockClassKey {}
 
 impl LockClassKey {
-    /// Creates a new lock class key.
-    pub const fn new() -> Self {
-        Self(Opaque::uninit())
-    }
-
     pub(crate) fn as_ptr(&self) -> *mut bindings::lock_class_key {
         self.0.get()
     }
 }
 
-impl Default for LockClassKey {
-    fn default() -> Self {
-        Self::new()
-    }
-}
-
 /// Defines a new static lock class and returns a pointer to it.
 #[doc(hidden)]
 #[macro_export]
 macro_rules! static_lock_class {
     () => {{
-        static CLASS: $crate::sync::LockClassKey = $crate::sync::LockClassKey::new();
+        static CLASS: $crate::sync::LockClassKey =
+            // SAFETY: lockdep expects uninitialized memory when it's handed a statically allocated
+            // lock_class_key
+            unsafe { ::core::mem::MaybeUninit::uninit().assume_init() };
         &CLASS
     }};
 }
author
#25 lore raw

PATCH 11/11 rust: lockdep: Use Pin for all LockClassKey usages

In reply to Boqun Feng

From: Mitchell Levy <[email protected]>

Reintroduce dynamically-allocated LockClassKeys such that they are automatically (de)registered. Require that all usages of LockClassKeys ensure that they are Pin'd.

Currently, only 'static LockClassKeys are supported, so Pin is redundant. However, it is intended that dynamically-allocated LockClassKeys will eventually be supported, so using Pin from the outset will make that change simpler.

---
 rust/helpers/helpers.c          |  1 +
 rust/helpers/sync.c             | 13 ++++++++
 rust/kernel/sync.rs             | 57 +++++++++++++++++++++++++++++++--
 rust/kernel/sync/condvar.rs     |  5 ++-
 rust/kernel/sync/lock.rs        |  4 +--
 rust/kernel/sync/lock/global.rs |  5 +--
 rust/kernel/sync/poll.rs        |  2 +-
 rust/kernel/workqueue.rs        |  2 +-
 8 files changed, 77 insertions(+), 12 deletions(-)
 create mode 100644 rust/helpers/sync.c
rust/helpers/helpers.c +1 -0
index 0640b7e115be..4c1a10a419cf 100644
@@ -30,6 +30,7 @@
 #include "signal.c"
 #include "slab.c"
 #include "spinlock.c"
+#include "sync.c"
 #include "task.c"
 #include "uaccess.c"
 #include "vmalloc.c"
rust/helpers/sync.c new file +13 -0
new file mode 100644
index 000000000000..ff7e68b48810
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/lockdep.h>
+
+void rust_helper_lockdep_register_key(struct lock_class_key *k)
+{
+	lockdep_register_key(k);
+}
+
+void rust_helper_lockdep_unregister_key(struct lock_class_key *k)
+{
+	lockdep_unregister_key(k);
+}
rust/kernel/sync.rs +54 -3

82 lines not on this page · raw message

rust/kernel/sync/condvar.rs +2 -3
index 5c1e546a26c3..fbf68ada582f 100644
@@ -17,8 +17,7 @@
     time::Jiffies,
     types::Opaque,
 };
-use core::marker::PhantomPinned;
-use core::ptr;
+use core::{marker::PhantomPinned, pin::Pin, ptr};
 use macros::pin_data;
 
 /// Creates a [`CondVar`] initialiser with the given name and a newly-created lock class.
@@ -103,7 +102,7 @@ unsafe impl Sync for CondVar {}
 
 impl CondVar {
     /// Constructs a new condvar initialiser.
-    pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> {
+    pub fn new(name: &'static CStr, key: Pin<&'static LockClassKey>) -> impl PinInit<Self> {
         pin_init!(Self {
             _pin: PhantomPinned,
             // SAFETY: `slot` is valid while the closure is called and both `name` and `key` have
rust/kernel/sync/lock.rs +2 -2
index f53e87d04cd2..360a10a9216d 100644
@@ -12,7 +12,7 @@
     str::CStr,
     types::{NotThreadSafe, Opaque, ScopeGuard},
 };
-use core::{cell::UnsafeCell, marker::PhantomPinned};
+use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin};
 use macros::pin_data;
 
 pub mod mutex;
@@ -129,7 +129,7 @@ unsafe impl<T: ?Sized + Send, B: Backend> Sync for Lock<T, B> {}
 
 impl<T, B: Backend> Lock<T, B> {
     /// Constructs a new lock initialiser.
-    pub fn new(t: T, name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> {
+    pub fn new(t: T, name: &'static CStr, key: Pin<&'static LockClassKey>) -> impl PinInit<Self> {
         pin_init!(Self {
             data: UnsafeCell::new(t),
             _pin: PhantomPinned,
rust/kernel/sync/lock/global.rs +3 -2
index 480ee724e3cc..d65f94b5caf2 100644
@@ -13,6 +13,7 @@
 use core::{
     cell::UnsafeCell,
     marker::{PhantomData, PhantomPinned},
+    pin::Pin,
 };
 
 /// Trait implemented for marker types for global locks.
@@ -26,7 +27,7 @@ pub trait GlobalLockBackend {
     /// The backend used for this global lock.
     type Backend: Backend + 'static;
     /// The class for this global lock.
-    fn get_lock_class() -> &'static LockClassKey;
+    fn get_lock_class() -> Pin<&'static LockClassKey>;
 }
 
 /// Type used for global locks.
@@ -270,7 +271,7 @@ impl $crate::sync::lock::GlobalLockBackend for $name {
             type Item = $valuety;
             type Backend = $crate::global_lock_inner!(backend $kind);
 
-            fn get_lock_class() -> &'static $crate::sync::LockClassKey {
+            fn get_lock_class() -> Pin<&'static $crate::sync::LockClassKey> {
                 $crate::static_lock_class!()
             }
         }
rust/kernel/sync/poll.rs +1 -1
index d5f17153b424..c4934f82d68b 100644
@@ -89,7 +89,7 @@ pub struct PollCondVar {
 
 impl PollCondVar {
     /// Constructs a new condvar initialiser.
-    pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> {
+    pub fn new(name: &'static CStr, key: Pin<&'static LockClassKey>) -> impl PinInit<Self> {
         pin_init!(Self {
             inner <- CondVar::new(name, key),
         })
rust/kernel/workqueue.rs +1 -1
index 0cd100d2aefb..6b6f3ad08951 100644
@@ -369,7 +369,7 @@ unsafe impl<T: ?Sized, const ID: u64> Sync for Work<T, ID> {}
 impl<T: ?Sized, const ID: u64> Work<T, ID> {
     /// Creates a new instance of [`Work`].
     #[inline]
-    pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self>
+    pub fn new(name: &'static CStr, key: Pin<&'static LockClassKey>) -> impl PinInit<Self>
     where
         T: WorkItem<ID>,
     {
Signature · 1 line
2.47.1
merge bot Applied
#26 lore raw

[tip: locking/core] rust: lockdep: Use Pin for all LockClassKey usages

The following commit has been merged into the locking/core branch of tip:

The following commit has been merged into the locking/core branch of tip:

Commit-ID:     f73ca66f0d7f4371d172d6f5b1f9a00e367ba921
Gitweb:        https://git.kernel.org/tip/f73ca66f0d7f4371d172d6f5b1f9a00e367ba921
Author:        Mitchell Levy <[email protected]>
AuthorDate:    Fri, 07 Mar 2025 15:27:01 -08:00
Committer:     Ingo Molnar <[email protected]>
CommitterDate: Sat, 08 Mar 2025 00:55:04 +01:00

rust: lockdep: Use Pin for all LockClassKey usages

Reintroduce dynamically-allocated LockClassKeys such that they are automatically (de)registered. Require that all usages of LockClassKeys ensure that they are Pin'd.

Currently, only 'static LockClassKeys are supported, so Pin is redundant. However, it is intended that dynamically-allocated LockClassKeys will eventually be supported, so using Pin from the outset will make that change simpler.

---
 rust/helpers/helpers.c          |  1 +-
 rust/helpers/sync.c             | 13 +++++++-
 rust/kernel/sync.rs             | 57 ++++++++++++++++++++++++++++++--
 rust/kernel/sync/condvar.rs     |  5 +--
 rust/kernel/sync/lock.rs        |  4 +-
 rust/kernel/sync/lock/global.rs |  5 +--
 rust/kernel/sync/poll.rs        |  2 +-
 rust/kernel/workqueue.rs        |  2 +-
 8 files changed, 77 insertions(+), 12 deletions(-)
 create mode 100644 rust/helpers/sync.c
rust/helpers/helpers.c +1 -0
index 0640b7e..4c1a10a 100644
@@ -30,6 +30,7 @@
 #include "signal.c"
 #include "slab.c"
 #include "spinlock.c"
+#include "sync.c"
 #include "task.c"
 #include "uaccess.c"
 #include "vmalloc.c"
rust/helpers/sync.c new file +13 -0
new file mode 100644
index 0000000..ff7e68b
@@ -0,0 +1,13 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <linux/lockdep.h>
+
+void rust_helper_lockdep_register_key(struct lock_class_key *k)
+{
+	lockdep_register_key(k);
+}
+
+void rust_helper_lockdep_unregister_key(struct lock_class_key *k)
+{
+	lockdep_unregister_key(k);
+}
rust/kernel/sync.rs +54 -3

82 lines not on this page · raw message

rust/kernel/sync/condvar.rs +2 -3
index 5c1e546..fbf68ad 100644
@@ -17,8 +17,7 @@ use crate::{
     time::Jiffies,
     types::Opaque,
 };
-use core::marker::PhantomPinned;
-use core::ptr;
+use core::{marker::PhantomPinned, pin::Pin, ptr};
 use macros::pin_data;
 
 /// Creates a [`CondVar`] initialiser with the given name and a newly-created lock class.
@@ -103,7 +102,7 @@ unsafe impl Sync for CondVar {}
 
 impl CondVar {
     /// Constructs a new condvar initialiser.
-    pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> {
+    pub fn new(name: &'static CStr, key: Pin<&'static LockClassKey>) -> impl PinInit<Self> {
         pin_init!(Self {
             _pin: PhantomPinned,
             // SAFETY: `slot` is valid while the closure is called and both `name` and `key` have
rust/kernel/sync/lock.rs +2 -2
index f53e87d..360a10a 100644
@@ -12,7 +12,7 @@ use crate::{
     str::CStr,
     types::{NotThreadSafe, Opaque, ScopeGuard},
 };
-use core::{cell::UnsafeCell, marker::PhantomPinned};
+use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin};
 use macros::pin_data;
 
 pub mod mutex;
@@ -129,7 +129,7 @@ unsafe impl<T: ?Sized + Send, B: Backend> Sync for Lock<T, B> {}
 
 impl<T, B: Backend> Lock<T, B> {
     /// Constructs a new lock initialiser.
-    pub fn new(t: T, name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> {
+    pub fn new(t: T, name: &'static CStr, key: Pin<&'static LockClassKey>) -> impl PinInit<Self> {
         pin_init!(Self {
             data: UnsafeCell::new(t),
             _pin: PhantomPinned,
rust/kernel/sync/lock/global.rs +3 -2
index 480ee72..d65f94b 100644
@@ -13,6 +13,7 @@ use crate::{
 use core::{
     cell::UnsafeCell,
     marker::{PhantomData, PhantomPinned},
+    pin::Pin,
 };
 
 /// Trait implemented for marker types for global locks.
@@ -26,7 +27,7 @@ pub trait GlobalLockBackend {
     /// The backend used for this global lock.
     type Backend: Backend + 'static;
     /// The class for this global lock.
-    fn get_lock_class() -> &'static LockClassKey;
+    fn get_lock_class() -> Pin<&'static LockClassKey>;
 }
 
 /// Type used for global locks.
@@ -270,7 +271,7 @@ macro_rules! global_lock {
             type Item = $valuety;
             type Backend = $crate::global_lock_inner!(backend $kind);
 
-            fn get_lock_class() -> &'static $crate::sync::LockClassKey {
+            fn get_lock_class() -> Pin<&'static $crate::sync::LockClassKey> {
                 $crate::static_lock_class!()
             }
         }
rust/kernel/sync/poll.rs +1 -1
index d5f1715..c4934f8 100644
@@ -89,7 +89,7 @@ pub struct PollCondVar {
 
 impl PollCondVar {
     /// Constructs a new condvar initialiser.
-    pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self> {
+    pub fn new(name: &'static CStr, key: Pin<&'static LockClassKey>) -> impl PinInit<Self> {
         pin_init!(Self {
             inner <- CondVar::new(name, key),
         })
rust/kernel/workqueue.rs +1 -1
index 0cd100d..6b6f3ad 100644
@@ -369,7 +369,7 @@ unsafe impl<T: ?Sized, const ID: u64> Sync for Work<T, ID> {}
 impl<T: ?Sized, const ID: u64> Work<T, ID> {
     /// Creates a new instance of [`Work`].
     #[inline]
-    pub fn new(name: &'static CStr, key: &'static LockClassKey) -> impl PinInit<Self>
+    pub fn new(name: &'static CStr, key: Pin<&'static LockClassKey>) -> impl PinInit<Self>
     where
         T: WorkItem<ID>,
     {
Applied
#27 lore raw
In reply to Boqun Feng
Quoted 27 lines · Boqun Feng

Hi Ingo & Peter,

As discussed, I'm resending the pull request for lockdep and Rust locking for v6.15 in the format of email patches. I dropped one patch and will postpone it for v6.16 because of a bug [1], and I think the fix
[2] needs more reviews.

[1]: https://lore.kernel.org/lkml/20250306122413.GBZ8mT7Z61Tmgnh5Y9@fat_crate.local/
[2]: https://lore.kernel.org/lkml/Z8t8imzJVhWyDvhC@boqun-archlinux/

Regards,
Boqun

Alice Ryhl (2):
rust: sync: Add accessor for the lock behind a given guard
rust: sync: condvar: Add wait_interruptible_freezable()

Boqun Feng (1):
rust: sync: lock: Add an example for Guard::lock_ref()

Mitchell Levy (2):
rust: lockdep: Remove support for dynamically allocated LockClassKeys
rust: lockdep: Use Pin for all LockClassKey usages

Randy Dunlap (1):
locking/rtmutex: Use struct keyword in kernel-doc comment

Quoted 7 lines

Waiman Long (5):
locking/semaphore: Use wake_q to wake up processes outside lock
critical section
locking/lock_events: Add locking events for rtmutex slow paths locking/lock_events: Add locking events for lockdep locking/lockdep: Disable KASAN instrumentation of lockdep.c locking/lockdep: Add kasan_check_byte() check in lock_acquire()

Thanks Boqun!

I've applied these 3 patches to the tip:locking/urgent tree:

locking/semaphore: Use wake_q to wake up processes outside lock critical section locking/rtmutex: Use the 'struct' keyword in kernel-doc comment
rust: lockdep: Remove support for dynamically allocated LockClassKeys

As a general rule, if a patch is marked Cc: stable, it must also be applied to current upstream.

I have applied the others to tip:locking/core:

locking/lock_events: Add locking events for rtmutex slow pathsa94d32446ab5 locking/lock_events: Add locking events for lockdep locking/lockdep: Disable KASAN instrumentation of lockdep.c
locking/lockdep: Add kasan_check_byte() check in lock_acquire()
rust: sync: Add accessor for the lock behind a given guard
rust: sync: lock: Add an example for Guard:: Lock_ref()
rust: sync: condvar: Add wait_interruptible_freezable()
rust: lockdep: Use Pin for all LockClassKey usages

I cleaned up changelogs where necessary - for example we generally don't include printk timestamps in changelogs, unless it's relevant, plus there were a number of typos and grammar mistakes left in some of the changelogs.

Thanks,

Ingo

author
#28 lore raw
Quoted 38 lines · Ingo Molnar
Quoted 27 lines · Boqun Feng

Hi Ingo & Peter,

As discussed, I'm resending the pull request for lockdep and Rust locking for v6.15 in the format of email patches. I dropped one patch and will postpone it for v6.16 because of a bug [1], and I think the fix
[2] needs more reviews.

[1]: https://lore.kernel.org/lkml/20250306122413.GBZ8mT7Z61Tmgnh5Y9@fat_crate.local/
[2]: https://lore.kernel.org/lkml/Z8t8imzJVhWyDvhC@boqun-archlinux/

Regards,
Boqun

Alice Ryhl (2):
rust: sync: Add accessor for the lock behind a given guard
rust: sync: condvar: Add wait_interruptible_freezable()

Boqun Feng (1):
rust: sync: lock: Add an example for Guard::lock_ref()

Mitchell Levy (2):
rust: lockdep: Remove support for dynamically allocated LockClassKeys
rust: lockdep: Use Pin for all LockClassKey usages

Randy Dunlap (1):
locking/rtmutex: Use struct keyword in kernel-doc comment

Quoted 7 lines

Waiman Long (5):
locking/semaphore: Use wake_q to wake up processes outside lock
critical section
locking/lock_events: Add locking events for rtmutex slow paths locking/lock_events: Add locking events for lockdep locking/lockdep: Disable KASAN instrumentation of lockdep.c locking/lockdep: Add kasan_check_byte() check in lock_acquire()

Quoted 2 lines

Thanks Boqun!

Thanks.

Quoted 9 lines

I've applied these 3 patches to the tip:locking/urgent tree:

locking/semaphore: Use wake_q to wake up processes outside lock critical section locking/rtmutex: Use the 'struct' keyword in kernel-doc comment
rust: lockdep: Remove support for dynamically allocated LockClassKeys

As a general rule, if a patch is marked Cc: stable, it must also be applied to current upstream.

Do you prefer a separate pull request for the future? I can send one for urgent and one for locking/core.

Quoted 10 lines

I have applied the others to tip:locking/core:

locking/lock_events: Add locking events for rtmutex slow pathsa94d32446ab5 locking/lock_events: Add locking events for lockdep locking/lockdep: Disable KASAN instrumentation of lockdep.c
locking/lockdep: Add kasan_check_byte() check in lock_acquire()
rust: sync: Add accessor for the lock behind a given guard
rust: sync: lock: Add an example for Guard:: Lock_ref()
rust: sync: condvar: Add wait_interruptible_freezable()
rust: lockdep: Use Pin for all LockClassKey usages

Quoted 2 lines

I cleaned up changelogs where necessary - for example we generally don't include printk timestamps in changelogs, unless it's relevant,

Got it, I will avoid them in the future.

Quoted 3 lines

plus there were a number of typos and grammar mistakes left in some of the changelogs.

Will take a look at your updates and keep working on improve them, thanks!

Regards,
Boqun

Quoted 3 lines

Thanks,

Ingo

#29 lore raw
Quoted 50 lines · Boqun Feng
Quoted 38 lines · Ingo Molnar
Quoted 27 lines · Boqun Feng

Hi Ingo & Peter,

As discussed, I'm resending the pull request for lockdep and Rust locking for v6.15 in the format of email patches. I dropped one patch and will postpone it for v6.16 because of a bug [1], and I think the fix
[2] needs more reviews.

[1]: https://lore.kernel.org/lkml/20250306122413.GBZ8mT7Z61Tmgnh5Y9@fat_crate.local/
[2]: https://lore.kernel.org/lkml/Z8t8imzJVhWyDvhC@boqun-archlinux/

Regards,
Boqun

Alice Ryhl (2):
rust: sync: Add accessor for the lock behind a given guard
rust: sync: condvar: Add wait_interruptible_freezable()

Boqun Feng (1):
rust: sync: lock: Add an example for Guard::lock_ref()

Mitchell Levy (2):
rust: lockdep: Remove support for dynamically allocated LockClassKeys
rust: lockdep: Use Pin for all LockClassKey usages

Randy Dunlap (1):
locking/rtmutex: Use struct keyword in kernel-doc comment

Quoted 7 lines

Waiman Long (5):
locking/semaphore: Use wake_q to wake up processes outside lock
critical section
locking/lock_events: Add locking events for rtmutex slow paths locking/lock_events: Add locking events for lockdep locking/lockdep: Disable KASAN instrumentation of lockdep.c locking/lockdep: Add kasan_check_byte() check in lock_acquire()

Quoted 2 lines

Thanks Boqun!

Thanks.

Quoted 6 lines

I've applied these 3 patches to the tip:locking/urgent tree:

locking/semaphore: Use wake_q to wake up processes outside lock critical section locking/rtmutex: Use the 'struct' keyword in kernel-doc comment
rust: lockdep: Remove support for dynamically allocated LockClassKeys

Quoted 6 lines
Quoted 3 lines

As a general rule, if a patch is marked Cc: stable, it must also be applied to current upstream.

Do you prefer a separate pull request for the future? I can send one for urgent and one for locking/core.

One tree is fine - maybe indicate which ones are urgent material and keep them at the head of the tree?

Thanks,

Ingo

author
#30 lore raw

On Sat, Mar 08, 2025 at 01:11:36AM +0100, Ingo Molnar wrote:
[...]

Quoted 10 lines
Quoted 10 lines
Quoted 9 lines

I've applied these 3 patches to the tip:locking/urgent tree:

locking/semaphore: Use wake_q to wake up processes outside lock critical section locking/rtmutex: Use the 'struct' keyword in kernel-doc comment
rust: lockdep: Remove support for dynamically allocated LockClassKeys

As a general rule, if a patch is marked Cc: stable, it must also be applied to current upstream.

Quoted 6 lines
Quoted 2 lines

Do you prefer a separate pull request for the future? I can send one for urgent and one for locking/core.

One tree is fine - maybe indicate which ones are urgent material and keep them at the head of the tree?

Sounds good to me, will do.

Regards,
Boqun

Quoted 3 lines

Thanks,

Ingo