[PATCH] locking/mutex: Redo __mutex_init()

Sebastian Andrzej Siewior posted 1 patch 1 month, 2 weeks ago
There is a newer version of this series
include/linux/mutex.h        | 45 ++++++++++++++++++++++++++++--------
kernel/locking/mutex.c       | 22 +++++++++++++-----
kernel/locking/rtmutex_api.c | 19 +++++++++++----
3 files changed, 66 insertions(+), 20 deletions(-)
[PATCH] locking/mutex: Redo __mutex_init()
Posted by Sebastian Andrzej Siewior 1 month, 2 weeks ago
mutex_init() invokes __mutex_init() providing the name of the lock and
a pointer to a the lock class. With LOCKDEP enabled this information is
useful but without LOCKDEP it not used at all. Passing the pointer
information of the lock class might be considered negligible but the
name of the lock is passed as well and the string is stored. This
information is wasting storage.

Split __mutex_init() into a _plain() variant doing the initialisation of
the lock and a _ld() version which does _plain() plus the lockdep bits.
Restrict the lockdep version to lockdep enabled builds allowing the
compiler to remove the unused parameter.

This results in the following size reduction:

      text     data       bss        dec  filename
| 30237599  8161430   1176624   39575653  vmlinux.defconfig
| 30233269  8149142   1176560   39558971  vmlinux.defconfig.patched
   -4.2KiB   -12KiB

| 32455099  8471098  12934684   53860881  vmlinux.defconfig.lockdep
| 32455100  8471098  12934684   53860882  vmlinux.defconfig.patched.lockdep

| 27152407  7191822   2068040   36412269  vmlinux.defconfig.preempt_rt
| 27145937  7183630   2067976   36397543  vmlinux.defconfig.patched.preempt_rt
   -6.3KiB    -8KiB

| 29382020  7505742  13784608   50672370  vmlinux.defconfig.preempt_rt.lockdep
| 29376229  7505742  13784544   50666515  vmlinux.defconfig.patched.preempt_rt.lockdep
   -5.6KiB

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
 include/linux/mutex.h        | 45 ++++++++++++++++++++++++++++--------
 kernel/locking/mutex.c       | 22 +++++++++++++-----
 kernel/locking/rtmutex_api.c | 19 +++++++++++----
 3 files changed, 66 insertions(+), 20 deletions(-)

diff --git a/include/linux/mutex.h b/include/linux/mutex.h
index 847b81ca64368..e731ef82aa0a0 100644
--- a/include/linux/mutex.h
+++ b/include/linux/mutex.h
@@ -86,8 +86,23 @@ do {									\
 #define DEFINE_MUTEX(mutexname) \
 	struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
 
-extern void __mutex_init(struct mutex *lock, const char *name,
-			 struct lock_class_key *key);
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+void mutex_init_ld(struct mutex *lock, const char *name, struct lock_class_key *key);
+
+static inline void __mutex_init(struct mutex *lock, const char *name,
+				struct lock_class_key *key)
+{
+	mutex_init_ld(lock, name, key);
+}
+#else
+extern void mutex_init_plain(struct mutex *lock);
+
+static inline void __mutex_init(struct mutex *lock, const char *name,
+				struct lock_class_key *key)
+{
+	mutex_init_plain(lock);
+}
+#endif /* !CONFIG_DEBUG_LOCK_ALLOC */
 
 /**
  * mutex_is_locked - is the mutex locked
@@ -111,17 +126,27 @@ extern bool mutex_is_locked(struct mutex *lock);
 #define DEFINE_MUTEX(mutexname)						\
 	struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
 
-extern void __mutex_rt_init(struct mutex *lock, const char *name,
-			    struct lock_class_key *key);
-
 #define mutex_is_locked(l)	rt_mutex_base_is_locked(&(l)->rtmutex)
 
-#define __mutex_init(mutex, name, key)			\
-do {							\
-	rt_mutex_base_init(&(mutex)->rtmutex);		\
-	__mutex_rt_init((mutex), name, key);		\
-} while (0)
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+extern void mutex_rt_init_ld(struct mutex *mutex, const char *name,
+			     struct lock_class_key *key);
 
+static inline void __mutex_init(struct mutex *lock, const char *name,
+				struct lock_class_key *key)
+{
+	mutex_rt_init_ld(lock, name, key);
+}
+
+#else
+extern void mutex_rt_init_plain(struct mutex *mutex);
+
+static inline void __mutex_init(struct mutex *lock, const char *name,
+				struct lock_class_key *key)
+{
+	mutex_rt_init_plain(lock);
+}
+#endif /* !CONFIG_LOCKDEP */
 #endif /* CONFIG_PREEMPT_RT */
 
 #ifdef CONFIG_DEBUG_MUTEXES
diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
index de7d6702cd96c..5a69d2bd44069 100644
--- a/kernel/locking/mutex.c
+++ b/kernel/locking/mutex.c
@@ -43,8 +43,7 @@
 # define MUTEX_WARN_ON(cond)
 #endif
 
-void
-__mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
+static void __mutex_init_plain(struct mutex *lock)
 {
 	atomic_long_set(&lock->owner, 0);
 	raw_spin_lock_init(&lock->wait_lock);
@@ -52,10 +51,7 @@ __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
 #ifdef CONFIG_MUTEX_SPIN_ON_OWNER
 	osq_lock_init(&lock->osq);
 #endif
-
-	debug_mutex_init(lock, name, key);
 }
-EXPORT_SYMBOL(__mutex_init);
 
 static inline struct task_struct *__owner_task(unsigned long owner)
 {
@@ -142,6 +138,11 @@ static inline bool __mutex_trylock(struct mutex *lock)
  * There is nothing that would stop spreading the lockdep annotations outwards
  * except more code.
  */
+void mutex_init_plain(struct mutex *lock)
+{
+	__mutex_init_plain(lock);
+}
+EXPORT_SYMBOL(mutex_init_plain);
 
 /*
  * Optimistic trylock that only works in the uncontended case. Make sure to
@@ -166,7 +167,16 @@ static __always_inline bool __mutex_unlock_fast(struct mutex *lock)
 
 	return atomic_long_try_cmpxchg_release(&lock->owner, &curr, 0UL);
 }
-#endif
+
+#else /* !CONFIG_DEBUG_LOCK_ALLOC */
+
+void mutex_init_ld(struct mutex *lock, const char *name, struct lock_class_key *key)
+{
+	__mutex_init_plain(lock);
+	debug_mutex_init(lock, name, key);
+}
+EXPORT_SYMBOL(mutex_init_ld);
+#endif /* !CONFIG_DEBUG_LOCK_ALLOC */
 
 static inline void __mutex_set_flag(struct mutex *lock, unsigned long flag)
 {
diff --git a/kernel/locking/rtmutex_api.c b/kernel/locking/rtmutex_api.c
index bafd5af98eaec..43d62b29739fc 100644
--- a/kernel/locking/rtmutex_api.c
+++ b/kernel/locking/rtmutex_api.c
@@ -515,13 +515,11 @@ void rt_mutex_debug_task_free(struct task_struct *task)
 
 #ifdef CONFIG_PREEMPT_RT
 /* Mutexes */
-void __mutex_rt_init(struct mutex *mutex, const char *name,
-		     struct lock_class_key *key)
+static void __mutex_rt_init_plain(struct mutex *mutex)
 {
+	rt_mutex_base_init(&mutex->rtmutex);
 	debug_check_no_locks_freed((void *)mutex, sizeof(*mutex));
-	lockdep_init_map_wait(&mutex->dep_map, name, key, 0, LD_WAIT_SLEEP);
 }
-EXPORT_SYMBOL(__mutex_rt_init);
 
 static __always_inline int __mutex_lock_common(struct mutex *lock,
 					       unsigned int state,
@@ -542,6 +540,13 @@ static __always_inline int __mutex_lock_common(struct mutex *lock,
 }
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
+void mutex_rt_init_ld(struct mutex *mutex, const char *name, struct lock_class_key *key)
+{
+	__mutex_rt_init_plain(mutex);
+	lockdep_init_map_wait(&mutex->dep_map, name, key, 0, LD_WAIT_SLEEP);
+}
+EXPORT_SYMBOL(mutex_rt_init_ld);
+
 void __sched mutex_lock_nested(struct mutex *lock, unsigned int subclass)
 {
 	__mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, subclass, NULL, _RET_IP_);
@@ -598,6 +603,12 @@ int __sched _mutex_trylock_nest_lock(struct mutex *lock,
 EXPORT_SYMBOL_GPL(_mutex_trylock_nest_lock);
 #else /* CONFIG_DEBUG_LOCK_ALLOC */
 
+void mutex_rt_init_plain(struct mutex *mutex)
+{
+	__mutex_rt_init_plain(mutex);
+}
+EXPORT_SYMBOL(mutex_rt_init_plain);
+
 void __sched mutex_lock(struct mutex *lock)
 {
 	__mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0, NULL, _RET_IP_);
-- 
2.51.0
Re: [PATCH] locking/mutex: Redo __mutex_init()
Posted by Waiman Long 1 month, 2 weeks ago
On 11/4/25 9:00 AM, Sebastian Andrzej Siewior wrote:
> mutex_init() invokes __mutex_init() providing the name of the lock and
> a pointer to a the lock class. With LOCKDEP enabled this information is
> useful but without LOCKDEP it not used at all. Passing the pointer
> information of the lock class might be considered negligible but the
> name of the lock is passed as well and the string is stored. This
> information is wasting storage.
>
> Split __mutex_init() into a _plain() variant doing the initialisation of
> the lock and a _ld() version which does _plain() plus the lockdep bits.
> Restrict the lockdep version to lockdep enabled builds allowing the
> compiler to remove the unused parameter.
>
> This results in the following size reduction:
>
>        text     data       bss        dec  filename
> | 30237599  8161430   1176624   39575653  vmlinux.defconfig
> | 30233269  8149142   1176560   39558971  vmlinux.defconfig.patched
>     -4.2KiB   -12KiB
>
> | 32455099  8471098  12934684   53860881  vmlinux.defconfig.lockdep
> | 32455100  8471098  12934684   53860882  vmlinux.defconfig.patched.lockdep
>
> | 27152407  7191822   2068040   36412269  vmlinux.defconfig.preempt_rt
> | 27145937  7183630   2067976   36397543  vmlinux.defconfig.patched.preempt_rt
>     -6.3KiB    -8KiB
>
> | 29382020  7505742  13784608   50672370  vmlinux.defconfig.preempt_rt.lockdep
> | 29376229  7505742  13784544   50666515  vmlinux.defconfig.patched.preempt_rt.lockdep
>     -5.6KiB
>
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> ---
>   include/linux/mutex.h        | 45 ++++++++++++++++++++++++++++--------
>   kernel/locking/mutex.c       | 22 +++++++++++++-----
>   kernel/locking/rtmutex_api.c | 19 +++++++++++----
>   3 files changed, 66 insertions(+), 20 deletions(-)
>
> diff --git a/include/linux/mutex.h b/include/linux/mutex.h
> index 847b81ca64368..e731ef82aa0a0 100644
> --- a/include/linux/mutex.h
> +++ b/include/linux/mutex.h
> @@ -86,8 +86,23 @@ do {									\
>   #define DEFINE_MUTEX(mutexname) \
>   	struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
>   
> -extern void __mutex_init(struct mutex *lock, const char *name,
> -			 struct lock_class_key *key);
> +#ifdef CONFIG_DEBUG_LOCK_ALLOC
> +void mutex_init_ld(struct mutex *lock, const char *name, struct lock_class_key *key);
> +
> +static inline void __mutex_init(struct mutex *lock, const char *name,
> +				struct lock_class_key *key)
> +{
> +	mutex_init_ld(lock, name, key);
> +}
> +#else
> +extern void mutex_init_plain(struct mutex *lock);
> +
> +static inline void __mutex_init(struct mutex *lock, const char *name,
> +				struct lock_class_key *key)
> +{
> +	mutex_init_plain(lock);
> +}
> +#endif /* !CONFIG_DEBUG_LOCK_ALLOC */

I think it is a good idea to eliminate useless strings in non-lockdep 
kernel. However, the function names are kind of awkward to me. First of 
all, it is hard to associate "ld" with lockdep as ld is also the name of 
the GNU linker. I would prefer to fully spell out as "lockdep". The 
"_plain" suffix also looks odd to me. How about using the original 
__mutex_init for the plain version and __mutex_init_lockdep as the 
lockdep version which calls __mutex_init and use similar naming scheme 
for the RT versions. What do you think?

Cheers,
Longman
Re: [PATCH] locking/mutex: Redo __mutex_init()
Posted by Sebastian Andrzej Siewior 1 month, 1 week ago
On 2025-11-04 11:21:27 [-0500], Waiman Long wrote:
> > +#ifdef CONFIG_DEBUG_LOCK_ALLOC
> > +void mutex_init_ld(struct mutex *lock, const char *name, struct lock_class_key *key);
> > +
> > +static inline void __mutex_init(struct mutex *lock, const char *name,
> > +				struct lock_class_key *key)
> > +{
> > +	mutex_init_ld(lock, name, key);
> > +}
> > +#else
> > +extern void mutex_init_plain(struct mutex *lock);
> > +
> > +static inline void __mutex_init(struct mutex *lock, const char *name,
> > +				struct lock_class_key *key)
> > +{
> > +	mutex_init_plain(lock);
> > +}
> > +#endif /* !CONFIG_DEBUG_LOCK_ALLOC */
> 
> I think it is a good idea to eliminate useless strings in non-lockdep
> kernel. However, the function names are kind of awkward to me. First of all,
> it is hard to associate "ld" with lockdep as ld is also the name of the GNU
> linker. I would prefer to fully spell out as "lockdep". The "_plain" suffix
> also looks odd to me. How about using the original __mutex_init for the
> plain version and __mutex_init_lockdep as the lockdep version which calls
> __mutex_init and use similar naming scheme for the RT versions. What do you
> think?

What about
	mutex_init_plain() -> mutex_init_generic()
	mutex_init_ld() -> mutex_init_lockdep()

Using __mutex_init() for the basic/ generic init could work but we have
already users 13 users (drivers/ mm/ net/) and the rust bindings are
also attached to it. I would prefer the generic/ lockdep suffix.

If you want __mutex_init() for the generic, regardless, we would first
need to make room and then something like mutex_init_lockdep() could be
the public interface replacing __mutex_init() in its current function.

> Cheers,
> Longman

Sebastian
Re: [PATCH] locking/mutex: Redo __mutex_init()
Posted by Waiman Long 1 month, 1 week ago
On 11/5/25 2:57 AM, Sebastian Andrzej Siewior wrote:
> On 2025-11-04 11:21:27 [-0500], Waiman Long wrote:
>>> +#ifdef CONFIG_DEBUG_LOCK_ALLOC
>>> +void mutex_init_ld(struct mutex *lock, const char *name, struct lock_class_key *key);
>>> +
>>> +static inline void __mutex_init(struct mutex *lock, const char *name,
>>> +				struct lock_class_key *key)
>>> +{
>>> +	mutex_init_ld(lock, name, key);
>>> +}
>>> +#else
>>> +extern void mutex_init_plain(struct mutex *lock);
>>> +
>>> +static inline void __mutex_init(struct mutex *lock, const char *name,
>>> +				struct lock_class_key *key)
>>> +{
>>> +	mutex_init_plain(lock);
>>> +}
>>> +#endif /* !CONFIG_DEBUG_LOCK_ALLOC */
>> I think it is a good idea to eliminate useless strings in non-lockdep
>> kernel. However, the function names are kind of awkward to me. First of all,
>> it is hard to associate "ld" with lockdep as ld is also the name of the GNU
>> linker. I would prefer to fully spell out as "lockdep". The "_plain" suffix
>> also looks odd to me. How about using the original __mutex_init for the
>> plain version and __mutex_init_lockdep as the lockdep version which calls
>> __mutex_init and use similar naming scheme for the RT versions. What do you
>> think?
> What about
> 	mutex_init_plain() -> mutex_init_generic()
> 	mutex_init_ld() -> mutex_init_lockdep()
Yes, generic is a much better name.
>
> Using __mutex_init() for the basic/ generic init could work but we have
> already users 13 users (drivers/ mm/ net/) and the rust bindings are
> also attached to it. I would prefer the generic/ lockdep suffix.
>
> If you want __mutex_init() for the generic, regardless, we would first
> need to make room and then something like mutex_init_lockdep() could be
> the public interface replacing __mutex_init() in its current function.

Ah, I don't realize that there are users of __mutex_init() outside of 
the locking subsystem. In this case, we have to maintain the semantics 
of __mutex_init() to avoid affecting other subsystems.

Thanks for the clarification.

Cheers,
Longman
Re: [PATCH] locking/mutex: Redo __mutex_init()
Posted by Sebastian Andrzej Siewior 1 month, 1 week ago
On 2025-11-05 08:49:05 [-0500], Waiman Long wrote:
> > If you want __mutex_init() for the generic, regardless, we would first
> > need to make room and then something like mutex_init_lockdep() could be
> > the public interface replacing __mutex_init() in its current function.
> 
> Ah, I don't realize that there are users of __mutex_init() outside of the
> locking subsystem. In this case, we have to maintain the semantics of
> __mutex_init() to avoid affecting other subsystems.

Well, we could update them to mutex_init() +
lockdep_set_class_and_name(). Except probably for rust. But still if we
like _generic, we like _generic ;)

> Thanks for the clarification.
> 
> Cheers,
> Longman

Sebastian
[PATCH v2] locking/mutex: Redo __mutex_init()
Posted by Sebastian Andrzej Siewior 1 month, 1 week ago
mutex_init() invokes __mutex_init() providing the name of the lock and
a pointer to a the lock class. With LOCKDEP enabled this information is
useful but without LOCKDEP it not used at all. Passing the pointer
information of the lock class might be considered negligible but the
name of the lock is passed as well and the string is stored. This
information is wasting storage.

Split __mutex_init() into a _genereic() variant doing the initialisation
of the lock and a _lockdep() version which does _genereic() plus the
lockdep bits. Restrict the lockdep version to lockdep enabled builds
allowing the compiler to remove the unused parameter.

This results in the following size reduction:

      text     data       bss        dec  filename
| 30237599  8161430   1176624   39575653  vmlinux.defconfig
| 30233269  8149142   1176560   39558971  vmlinux.defconfig.patched
   -4.2KiB   -12KiB

| 32455099  8471098  12934684   53860881  vmlinux.defconfig.lockdep
| 32455100  8471098  12934684   53860882  vmlinux.defconfig.patched.lockdep

| 27152407  7191822   2068040   36412269  vmlinux.defconfig.preempt_rt
| 27145937  7183630   2067976   36397543  vmlinux.defconfig.patched.preempt_rt
   -6.3KiB    -8KiB

| 29382020  7505742  13784608   50672370  vmlinux.defconfig.preempt_rt.lockdep
| 29376229  7505742  13784544   50666515  vmlinux.defconfig.patched.preempt_rt.lockdep
   -5.6KiB

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
---
v1…v2:
  - s/_init_ld/_init_lockep/
  - s/_init_plain/_init_generic/

 include/linux/mutex.h        | 45 ++++++++++++++++++++++++++++--------
 kernel/locking/mutex.c       | 22 +++++++++++++-----
 kernel/locking/rtmutex_api.c | 19 +++++++++++----
 3 files changed, 66 insertions(+), 20 deletions(-)

diff --git a/include/linux/mutex.h b/include/linux/mutex.h
index 847b81ca64368..bf535f0118bb8 100644
--- a/include/linux/mutex.h
+++ b/include/linux/mutex.h
@@ -86,8 +86,23 @@ do {									\
 #define DEFINE_MUTEX(mutexname) \
 	struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
 
-extern void __mutex_init(struct mutex *lock, const char *name,
-			 struct lock_class_key *key);
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+void mutex_init_lockep(struct mutex *lock, const char *name, struct lock_class_key *key);
+
+static inline void __mutex_init(struct mutex *lock, const char *name,
+				struct lock_class_key *key)
+{
+	mutex_init_lockep(lock, name, key);
+}
+#else
+extern void mutex_init_generic(struct mutex *lock);
+
+static inline void __mutex_init(struct mutex *lock, const char *name,
+				struct lock_class_key *key)
+{
+	mutex_init_generic(lock);
+}
+#endif /* !CONFIG_DEBUG_LOCK_ALLOC */
 
 /**
  * mutex_is_locked - is the mutex locked
@@ -111,17 +126,27 @@ extern bool mutex_is_locked(struct mutex *lock);
 #define DEFINE_MUTEX(mutexname)						\
 	struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
 
-extern void __mutex_rt_init(struct mutex *lock, const char *name,
-			    struct lock_class_key *key);
-
 #define mutex_is_locked(l)	rt_mutex_base_is_locked(&(l)->rtmutex)
 
-#define __mutex_init(mutex, name, key)			\
-do {							\
-	rt_mutex_base_init(&(mutex)->rtmutex);		\
-	__mutex_rt_init((mutex), name, key);		\
-} while (0)
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+extern void mutex_rt_init_lockdep(struct mutex *mutex, const char *name,
+			     struct lock_class_key *key);
 
+static inline void __mutex_init(struct mutex *lock, const char *name,
+				struct lock_class_key *key)
+{
+	mutex_rt_init_lockdep(lock, name, key);
+}
+
+#else
+extern void mutex_rt_init_generic(struct mutex *mutex);
+
+static inline void __mutex_init(struct mutex *lock, const char *name,
+				struct lock_class_key *key)
+{
+	mutex_rt_init_generic(lock);
+}
+#endif /* !CONFIG_LOCKDEP */
 #endif /* CONFIG_PREEMPT_RT */
 
 #ifdef CONFIG_DEBUG_MUTEXES
diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
index de7d6702cd96c..f3bb352a368d9 100644
--- a/kernel/locking/mutex.c
+++ b/kernel/locking/mutex.c
@@ -43,8 +43,7 @@
 # define MUTEX_WARN_ON(cond)
 #endif
 
-void
-__mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
+static void __mutex_init_generic(struct mutex *lock)
 {
 	atomic_long_set(&lock->owner, 0);
 	raw_spin_lock_init(&lock->wait_lock);
@@ -52,10 +51,7 @@ __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
 #ifdef CONFIG_MUTEX_SPIN_ON_OWNER
 	osq_lock_init(&lock->osq);
 #endif
-
-	debug_mutex_init(lock, name, key);
 }
-EXPORT_SYMBOL(__mutex_init);
 
 static inline struct task_struct *__owner_task(unsigned long owner)
 {
@@ -142,6 +138,11 @@ static inline bool __mutex_trylock(struct mutex *lock)
  * There is nothing that would stop spreading the lockdep annotations outwards
  * except more code.
  */
+void mutex_init_generic(struct mutex *lock)
+{
+	__mutex_init_generic(lock);
+}
+EXPORT_SYMBOL(mutex_init_generic);
 
 /*
  * Optimistic trylock that only works in the uncontended case. Make sure to
@@ -166,7 +167,16 @@ static __always_inline bool __mutex_unlock_fast(struct mutex *lock)
 
 	return atomic_long_try_cmpxchg_release(&lock->owner, &curr, 0UL);
 }
-#endif
+
+#else /* !CONFIG_DEBUG_LOCK_ALLOC */
+
+void mutex_init_lockep(struct mutex *lock, const char *name, struct lock_class_key *key)
+{
+	__mutex_init_generic(lock);
+	debug_mutex_init(lock, name, key);
+}
+EXPORT_SYMBOL(mutex_init_lockep);
+#endif /* !CONFIG_DEBUG_LOCK_ALLOC */
 
 static inline void __mutex_set_flag(struct mutex *lock, unsigned long flag)
 {
diff --git a/kernel/locking/rtmutex_api.c b/kernel/locking/rtmutex_api.c
index bafd5af98eaec..59dbd29cb219b 100644
--- a/kernel/locking/rtmutex_api.c
+++ b/kernel/locking/rtmutex_api.c
@@ -515,13 +515,11 @@ void rt_mutex_debug_task_free(struct task_struct *task)
 
 #ifdef CONFIG_PREEMPT_RT
 /* Mutexes */
-void __mutex_rt_init(struct mutex *mutex, const char *name,
-		     struct lock_class_key *key)
+static void __mutex_rt_init_generic(struct mutex *mutex)
 {
+	rt_mutex_base_init(&mutex->rtmutex);
 	debug_check_no_locks_freed((void *)mutex, sizeof(*mutex));
-	lockdep_init_map_wait(&mutex->dep_map, name, key, 0, LD_WAIT_SLEEP);
 }
-EXPORT_SYMBOL(__mutex_rt_init);
 
 static __always_inline int __mutex_lock_common(struct mutex *lock,
 					       unsigned int state,
@@ -542,6 +540,13 @@ static __always_inline int __mutex_lock_common(struct mutex *lock,
 }
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
+void mutex_rt_init_lockdep(struct mutex *mutex, const char *name, struct lock_class_key *key)
+{
+	__mutex_rt_init_generic(mutex);
+	lockdep_init_map_wait(&mutex->dep_map, name, key, 0, LD_WAIT_SLEEP);
+}
+EXPORT_SYMBOL(mutex_rt_init_lockdep);
+
 void __sched mutex_lock_nested(struct mutex *lock, unsigned int subclass)
 {
 	__mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, subclass, NULL, _RET_IP_);
@@ -598,6 +603,12 @@ int __sched _mutex_trylock_nest_lock(struct mutex *lock,
 EXPORT_SYMBOL_GPL(_mutex_trylock_nest_lock);
 #else /* CONFIG_DEBUG_LOCK_ALLOC */
 
+void mutex_rt_init_generic(struct mutex *mutex)
+{
+	__mutex_rt_init_generic(mutex);
+}
+EXPORT_SYMBOL(mutex_rt_init_generic);
+
 void __sched mutex_lock(struct mutex *lock)
 {
 	__mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0, NULL, _RET_IP_);
-- 
2.51.0
Re: [PATCH v2] locking/mutex: Redo __mutex_init()
Posted by Waiman Long 1 month, 1 week ago
On 11/5/25 9:23 AM, Sebastian Andrzej Siewior wrote:
> mutex_init() invokes __mutex_init() providing the name of the lock and
> a pointer to a the lock class. With LOCKDEP enabled this information is
> useful but without LOCKDEP it not used at all. Passing the pointer
> information of the lock class might be considered negligible but the
> name of the lock is passed as well and the string is stored. This
> information is wasting storage.
>
> Split __mutex_init() into a _genereic() variant doing the initialisation
> of the lock and a _lockdep() version which does _genereic() plus the
> lockdep bits. Restrict the lockdep version to lockdep enabled builds
> allowing the compiler to remove the unused parameter.
>
> This results in the following size reduction:
>
>        text     data       bss        dec  filename
> | 30237599  8161430   1176624   39575653  vmlinux.defconfig
> | 30233269  8149142   1176560   39558971  vmlinux.defconfig.patched
>     -4.2KiB   -12KiB
>
> | 32455099  8471098  12934684   53860881  vmlinux.defconfig.lockdep
> | 32455100  8471098  12934684   53860882  vmlinux.defconfig.patched.lockdep
>
> | 27152407  7191822   2068040   36412269  vmlinux.defconfig.preempt_rt
> | 27145937  7183630   2067976   36397543  vmlinux.defconfig.patched.preempt_rt
>     -6.3KiB    -8KiB
>
> | 29382020  7505742  13784608   50672370  vmlinux.defconfig.preempt_rt.lockdep
> | 29376229  7505742  13784544   50666515  vmlinux.defconfig.patched.preempt_rt.lockdep
>     -5.6KiB
>
> Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> ---
> v1…v2:
>    - s/_init_ld/_init_lockep/
>    - s/_init_plain/_init_generic/
>
>   include/linux/mutex.h        | 45 ++++++++++++++++++++++++++++--------
>   kernel/locking/mutex.c       | 22 +++++++++++++-----
>   kernel/locking/rtmutex_api.c | 19 +++++++++++----
>   3 files changed, 66 insertions(+), 20 deletions(-)
>
> diff --git a/include/linux/mutex.h b/include/linux/mutex.h
> index 847b81ca64368..bf535f0118bb8 100644
> --- a/include/linux/mutex.h
> +++ b/include/linux/mutex.h
> @@ -86,8 +86,23 @@ do {									\
>   #define DEFINE_MUTEX(mutexname) \
>   	struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
>   
> -extern void __mutex_init(struct mutex *lock, const char *name,
> -			 struct lock_class_key *key);
> +#ifdef CONFIG_DEBUG_LOCK_ALLOC
> +void mutex_init_lockep(struct mutex *lock, const char *name, struct lock_class_key *key);
> +
> +static inline void __mutex_init(struct mutex *lock, const char *name,
> +				struct lock_class_key *key)
> +{
> +	mutex_init_lockep(lock, name, key);
> +}
> +#else
> +extern void mutex_init_generic(struct mutex *lock);
> +
> +static inline void __mutex_init(struct mutex *lock, const char *name,
> +				struct lock_class_key *key)
> +{
> +	mutex_init_generic(lock);
> +}
> +#endif /* !CONFIG_DEBUG_LOCK_ALLOC */
>   
>   /**
>    * mutex_is_locked - is the mutex locked
> @@ -111,17 +126,27 @@ extern bool mutex_is_locked(struct mutex *lock);
>   #define DEFINE_MUTEX(mutexname)						\
>   	struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
>   
> -extern void __mutex_rt_init(struct mutex *lock, const char *name,
> -			    struct lock_class_key *key);
> -
>   #define mutex_is_locked(l)	rt_mutex_base_is_locked(&(l)->rtmutex)
>   
> -#define __mutex_init(mutex, name, key)			\
> -do {							\
> -	rt_mutex_base_init(&(mutex)->rtmutex);		\
> -	__mutex_rt_init((mutex), name, key);		\
> -} while (0)
> +#ifdef CONFIG_DEBUG_LOCK_ALLOC
> +extern void mutex_rt_init_lockdep(struct mutex *mutex, const char *name,
> +			     struct lock_class_key *key);
>   
> +static inline void __mutex_init(struct mutex *lock, const char *name,
> +				struct lock_class_key *key)
> +{
> +	mutex_rt_init_lockdep(lock, name, key);
> +}
> +
> +#else
> +extern void mutex_rt_init_generic(struct mutex *mutex);
> +
> +static inline void __mutex_init(struct mutex *lock, const char *name,
> +				struct lock_class_key *key)
> +{
> +	mutex_rt_init_generic(lock);
> +}
> +#endif /* !CONFIG_LOCKDEP */
>   #endif /* CONFIG_PREEMPT_RT */
>   
>   #ifdef CONFIG_DEBUG_MUTEXES
> diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
> index de7d6702cd96c..f3bb352a368d9 100644
> --- a/kernel/locking/mutex.c
> +++ b/kernel/locking/mutex.c
> @@ -43,8 +43,7 @@
>   # define MUTEX_WARN_ON(cond)
>   #endif
>   
> -void
> -__mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
> +static void __mutex_init_generic(struct mutex *lock)
>   {
>   	atomic_long_set(&lock->owner, 0);
>   	raw_spin_lock_init(&lock->wait_lock);
> @@ -52,10 +51,7 @@ __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
>   #ifdef CONFIG_MUTEX_SPIN_ON_OWNER
>   	osq_lock_init(&lock->osq);
>   #endif
> -
> -	debug_mutex_init(lock, name, key);
>   }
> -EXPORT_SYMBOL(__mutex_init);
>   
>   static inline struct task_struct *__owner_task(unsigned long owner)
>   {
> @@ -142,6 +138,11 @@ static inline bool __mutex_trylock(struct mutex *lock)
>    * There is nothing that would stop spreading the lockdep annotations outwards
>    * except more code.
>    */
> +void mutex_init_generic(struct mutex *lock)
> +{
> +	__mutex_init_generic(lock);
> +}
> +EXPORT_SYMBOL(mutex_init_generic);
>   
>   /*
>    * Optimistic trylock that only works in the uncontended case. Make sure to
> @@ -166,7 +167,16 @@ static __always_inline bool __mutex_unlock_fast(struct mutex *lock)
>   
>   	return atomic_long_try_cmpxchg_release(&lock->owner, &curr, 0UL);
>   }
> -#endif
> +
> +#else /* !CONFIG_DEBUG_LOCK_ALLOC */
> +
> +void mutex_init_lockep(struct mutex *lock, const char *name, struct lock_class_key *key)
> +{
> +	__mutex_init_generic(lock);
> +	debug_mutex_init(lock, name, key);
> +}
> +EXPORT_SYMBOL(mutex_init_lockep);
> +#endif /* !CONFIG_DEBUG_LOCK_ALLOC */
>   
>   static inline void __mutex_set_flag(struct mutex *lock, unsigned long flag)
>   {
> diff --git a/kernel/locking/rtmutex_api.c b/kernel/locking/rtmutex_api.c
> index bafd5af98eaec..59dbd29cb219b 100644
> --- a/kernel/locking/rtmutex_api.c
> +++ b/kernel/locking/rtmutex_api.c
> @@ -515,13 +515,11 @@ void rt_mutex_debug_task_free(struct task_struct *task)
>   
>   #ifdef CONFIG_PREEMPT_RT
>   /* Mutexes */
> -void __mutex_rt_init(struct mutex *mutex, const char *name,
> -		     struct lock_class_key *key)
> +static void __mutex_rt_init_generic(struct mutex *mutex)
>   {
> +	rt_mutex_base_init(&mutex->rtmutex);
>   	debug_check_no_locks_freed((void *)mutex, sizeof(*mutex));
> -	lockdep_init_map_wait(&mutex->dep_map, name, key, 0, LD_WAIT_SLEEP);
>   }
> -EXPORT_SYMBOL(__mutex_rt_init);
>   
>   static __always_inline int __mutex_lock_common(struct mutex *lock,
>   					       unsigned int state,
> @@ -542,6 +540,13 @@ static __always_inline int __mutex_lock_common(struct mutex *lock,
>   }
>   
>   #ifdef CONFIG_DEBUG_LOCK_ALLOC
> +void mutex_rt_init_lockdep(struct mutex *mutex, const char *name, struct lock_class_key *key)
> +{
> +	__mutex_rt_init_generic(mutex);
> +	lockdep_init_map_wait(&mutex->dep_map, name, key, 0, LD_WAIT_SLEEP);
> +}
> +EXPORT_SYMBOL(mutex_rt_init_lockdep);
> +
>   void __sched mutex_lock_nested(struct mutex *lock, unsigned int subclass)
>   {
>   	__mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, subclass, NULL, _RET_IP_);
> @@ -598,6 +603,12 @@ int __sched _mutex_trylock_nest_lock(struct mutex *lock,
>   EXPORT_SYMBOL_GPL(_mutex_trylock_nest_lock);
>   #else /* CONFIG_DEBUG_LOCK_ALLOC */
>   
> +void mutex_rt_init_generic(struct mutex *mutex)
> +{
> +	__mutex_rt_init_generic(mutex);
> +}
> +EXPORT_SYMBOL(mutex_rt_init_generic);
> +
>   void __sched mutex_lock(struct mutex *lock)
>   {
>   	__mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0, NULL, _RET_IP_);
Reviewed-by: Waiman Long <longman@redhat.com>

[tip: locking/core] locking/mutex: Redo __mutex_init() to reduce generated code size
Posted by tip-bot2 for Sebastian Andrzej Siewior 2 weeks, 4 days ago
The following commit has been merged into the locking/core branch of tip:

Commit-ID:     51d7a054521de7085783a9a1ba15c3530863409a
Gitweb:        https://git.kernel.org/tip/51d7a054521de7085783a9a1ba15c3530863409a
Author:        Sebastian Andrzej Siewior <bigeasy@linutronix.de>
AuthorDate:    Wed, 05 Nov 2025 15:23:50 +01:00
Committer:     Ingo Molnar <mingo@kernel.org>
CommitterDate: Mon, 01 Dec 2025 06:51:57 +01:00

locking/mutex: Redo __mutex_init() to reduce generated code size

mutex_init() invokes __mutex_init() providing the name of the lock and
a pointer to a the lock class. With LOCKDEP enabled this information is
useful but without LOCKDEP it not used at all. Passing the pointer
information of the lock class might be considered negligible but the
name of the lock is passed as well and the string is stored. This
information is wasting storage.

Split __mutex_init() into a _genereic() variant doing the initialisation
of the lock and a _lockdep() version which does _genereic() plus the
lockdep bits. Restrict the lockdep version to lockdep enabled builds
allowing the compiler to remove the unused parameter.

This results in the following size reduction:

        text     data       bss        dec  filename
  | 30237599  8161430   1176624   39575653  vmlinux.defconfig
  | 30233269  8149142   1176560   39558971  vmlinux.defconfig.patched
     -4.2KiB   -12KiB

  | 32455099  8471098  12934684   53860881  vmlinux.defconfig.lockdep
  | 32455100  8471098  12934684   53860882  vmlinux.defconfig.patched.lockdep

  | 27152407  7191822   2068040   36412269  vmlinux.defconfig.preempt_rt
  | 27145937  7183630   2067976   36397543  vmlinux.defconfig.patched.preempt_rt
     -6.3KiB    -8KiB

  | 29382020  7505742  13784608   50672370  vmlinux.defconfig.preempt_rt.lockdep
  | 29376229  7505742  13784544   50666515  vmlinux.defconfig.patched.preempt_rt.lockdep
     -5.6KiB

[peterz: folded fix from boqun]

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Ingo Molnar <mingo@kernel.org>
Reviewed-by: Waiman Long <longman@redhat.com>
Link: https://lkml.kernel.org/r/20251125145425.68319-1-boqun.feng@gmail.com
Link: https://patch.msgid.link/20251105142350.Tfeevs2N@linutronix.de
---
 include/linux/mutex.h        | 45 +++++++++++++++++++++++++++--------
 kernel/locking/mutex-debug.c | 10 +--------
 kernel/locking/mutex.c       | 28 +++++++++++++++++-----
 kernel/locking/mutex.h       |  5 +---
 kernel/locking/rtmutex_api.c | 19 +++++++++++----
 5 files changed, 75 insertions(+), 32 deletions(-)

diff --git a/include/linux/mutex.h b/include/linux/mutex.h
index 847b81c..bf535f0 100644
--- a/include/linux/mutex.h
+++ b/include/linux/mutex.h
@@ -86,8 +86,23 @@ do {									\
 #define DEFINE_MUTEX(mutexname) \
 	struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
 
-extern void __mutex_init(struct mutex *lock, const char *name,
-			 struct lock_class_key *key);
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+void mutex_init_lockep(struct mutex *lock, const char *name, struct lock_class_key *key);
+
+static inline void __mutex_init(struct mutex *lock, const char *name,
+				struct lock_class_key *key)
+{
+	mutex_init_lockep(lock, name, key);
+}
+#else
+extern void mutex_init_generic(struct mutex *lock);
+
+static inline void __mutex_init(struct mutex *lock, const char *name,
+				struct lock_class_key *key)
+{
+	mutex_init_generic(lock);
+}
+#endif /* !CONFIG_DEBUG_LOCK_ALLOC */
 
 /**
  * mutex_is_locked - is the mutex locked
@@ -111,17 +126,27 @@ extern bool mutex_is_locked(struct mutex *lock);
 #define DEFINE_MUTEX(mutexname)						\
 	struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
 
-extern void __mutex_rt_init(struct mutex *lock, const char *name,
-			    struct lock_class_key *key);
-
 #define mutex_is_locked(l)	rt_mutex_base_is_locked(&(l)->rtmutex)
 
-#define __mutex_init(mutex, name, key)			\
-do {							\
-	rt_mutex_base_init(&(mutex)->rtmutex);		\
-	__mutex_rt_init((mutex), name, key);		\
-} while (0)
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+extern void mutex_rt_init_lockdep(struct mutex *mutex, const char *name,
+			     struct lock_class_key *key);
+
+static inline void __mutex_init(struct mutex *lock, const char *name,
+				struct lock_class_key *key)
+{
+	mutex_rt_init_lockdep(lock, name, key);
+}
 
+#else
+extern void mutex_rt_init_generic(struct mutex *mutex);
+
+static inline void __mutex_init(struct mutex *lock, const char *name,
+				struct lock_class_key *key)
+{
+	mutex_rt_init_generic(lock);
+}
+#endif /* !CONFIG_LOCKDEP */
 #endif /* CONFIG_PREEMPT_RT */
 
 #ifdef CONFIG_DEBUG_MUTEXES
diff --git a/kernel/locking/mutex-debug.c b/kernel/locking/mutex-debug.c
index 949103f..2c6b02d 100644
--- a/kernel/locking/mutex-debug.c
+++ b/kernel/locking/mutex-debug.c
@@ -78,16 +78,8 @@ void debug_mutex_unlock(struct mutex *lock)
 	}
 }
 
-void debug_mutex_init(struct mutex *lock, const char *name,
-		      struct lock_class_key *key)
+void debug_mutex_init(struct mutex *lock)
 {
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-	/*
-	 * Make sure we are not reinitializing a held lock:
-	 */
-	debug_check_no_locks_freed((void *)lock, sizeof(*lock));
-	lockdep_init_map_wait(&lock->dep_map, name, key, 0, LD_WAIT_SLEEP);
-#endif
 	lock->magic = lock;
 }
 
diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
index de7d670..2a1d165 100644
--- a/kernel/locking/mutex.c
+++ b/kernel/locking/mutex.c
@@ -43,8 +43,7 @@
 # define MUTEX_WARN_ON(cond)
 #endif
 
-void
-__mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
+static void __mutex_init_generic(struct mutex *lock)
 {
 	atomic_long_set(&lock->owner, 0);
 	raw_spin_lock_init(&lock->wait_lock);
@@ -52,10 +51,8 @@ __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
 #ifdef CONFIG_MUTEX_SPIN_ON_OWNER
 	osq_lock_init(&lock->osq);
 #endif
-
-	debug_mutex_init(lock, name, key);
+	debug_mutex_init(lock);
 }
-EXPORT_SYMBOL(__mutex_init);
 
 static inline struct task_struct *__owner_task(unsigned long owner)
 {
@@ -142,6 +139,11 @@ static inline bool __mutex_trylock(struct mutex *lock)
  * There is nothing that would stop spreading the lockdep annotations outwards
  * except more code.
  */
+void mutex_init_generic(struct mutex *lock)
+{
+	__mutex_init_generic(lock);
+}
+EXPORT_SYMBOL(mutex_init_generic);
 
 /*
  * Optimistic trylock that only works in the uncontended case. Make sure to
@@ -166,7 +168,21 @@ static __always_inline bool __mutex_unlock_fast(struct mutex *lock)
 
 	return atomic_long_try_cmpxchg_release(&lock->owner, &curr, 0UL);
 }
-#endif
+
+#else /* !CONFIG_DEBUG_LOCK_ALLOC */
+
+void mutex_init_lockep(struct mutex *lock, const char *name, struct lock_class_key *key)
+{
+	__mutex_init_generic(lock);
+
+	/*
+	 * Make sure we are not reinitializing a held lock:
+	 */
+	debug_check_no_locks_freed((void *)lock, sizeof(*lock));
+	lockdep_init_map_wait(&lock->dep_map, name, key, 0, LD_WAIT_SLEEP);
+}
+EXPORT_SYMBOL(mutex_init_lockep);
+#endif /* !CONFIG_DEBUG_LOCK_ALLOC */
 
 static inline void __mutex_set_flag(struct mutex *lock, unsigned long flag)
 {
diff --git a/kernel/locking/mutex.h b/kernel/locking/mutex.h
index 2e8080a..9ad4da8 100644
--- a/kernel/locking/mutex.h
+++ b/kernel/locking/mutex.h
@@ -59,8 +59,7 @@ extern void debug_mutex_add_waiter(struct mutex *lock,
 extern void debug_mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter,
 				      struct task_struct *task);
 extern void debug_mutex_unlock(struct mutex *lock);
-extern void debug_mutex_init(struct mutex *lock, const char *name,
-			     struct lock_class_key *key);
+extern void debug_mutex_init(struct mutex *lock);
 #else /* CONFIG_DEBUG_MUTEXES */
 # define debug_mutex_lock_common(lock, waiter)		do { } while (0)
 # define debug_mutex_wake_waiter(lock, waiter)		do { } while (0)
@@ -68,6 +67,6 @@ extern void debug_mutex_init(struct mutex *lock, const char *name,
 # define debug_mutex_add_waiter(lock, waiter, ti)	do { } while (0)
 # define debug_mutex_remove_waiter(lock, waiter, ti)	do { } while (0)
 # define debug_mutex_unlock(lock)			do { } while (0)
-# define debug_mutex_init(lock, name, key)		do { } while (0)
+# define debug_mutex_init(lock)				do { } while (0)
 #endif /* !CONFIG_DEBUG_MUTEXES */
 #endif /* CONFIG_PREEMPT_RT */
diff --git a/kernel/locking/rtmutex_api.c b/kernel/locking/rtmutex_api.c
index bafd5af..59dbd29 100644
--- a/kernel/locking/rtmutex_api.c
+++ b/kernel/locking/rtmutex_api.c
@@ -515,13 +515,11 @@ void rt_mutex_debug_task_free(struct task_struct *task)
 
 #ifdef CONFIG_PREEMPT_RT
 /* Mutexes */
-void __mutex_rt_init(struct mutex *mutex, const char *name,
-		     struct lock_class_key *key)
+static void __mutex_rt_init_generic(struct mutex *mutex)
 {
+	rt_mutex_base_init(&mutex->rtmutex);
 	debug_check_no_locks_freed((void *)mutex, sizeof(*mutex));
-	lockdep_init_map_wait(&mutex->dep_map, name, key, 0, LD_WAIT_SLEEP);
 }
-EXPORT_SYMBOL(__mutex_rt_init);
 
 static __always_inline int __mutex_lock_common(struct mutex *lock,
 					       unsigned int state,
@@ -542,6 +540,13 @@ static __always_inline int __mutex_lock_common(struct mutex *lock,
 }
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
+void mutex_rt_init_lockdep(struct mutex *mutex, const char *name, struct lock_class_key *key)
+{
+	__mutex_rt_init_generic(mutex);
+	lockdep_init_map_wait(&mutex->dep_map, name, key, 0, LD_WAIT_SLEEP);
+}
+EXPORT_SYMBOL(mutex_rt_init_lockdep);
+
 void __sched mutex_lock_nested(struct mutex *lock, unsigned int subclass)
 {
 	__mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, subclass, NULL, _RET_IP_);
@@ -598,6 +603,12 @@ int __sched _mutex_trylock_nest_lock(struct mutex *lock,
 EXPORT_SYMBOL_GPL(_mutex_trylock_nest_lock);
 #else /* CONFIG_DEBUG_LOCK_ALLOC */
 
+void mutex_rt_init_generic(struct mutex *mutex)
+{
+	__mutex_rt_init_generic(mutex);
+}
+EXPORT_SYMBOL(mutex_rt_init_generic);
+
 void __sched mutex_lock(struct mutex *lock)
 {
 	__mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0, NULL, _RET_IP_);
[tip: locking/core] locking/mutex: Redo __mutex_init()
Posted by tip-bot2 for Sebastian Andrzej Siewior 2 weeks, 6 days ago
The following commit has been merged into the locking/core branch of tip:

Commit-ID:     01f38611a451da4d7f0ad0261367310f931622d6
Gitweb:        https://git.kernel.org/tip/01f38611a451da4d7f0ad0261367310f931622d6
Author:        Sebastian Andrzej Siewior <bigeasy@linutronix.de>
AuthorDate:    Wed, 05 Nov 2025 15:23:50 +01:00
Committer:     Peter Zijlstra <peterz@infradead.org>
CommitterDate: Fri, 28 Nov 2025 10:40:47 +01:00

locking/mutex: Redo __mutex_init()

mutex_init() invokes __mutex_init() providing the name of the lock and
a pointer to a the lock class. With LOCKDEP enabled this information is
useful but without LOCKDEP it not used at all. Passing the pointer
information of the lock class might be considered negligible but the
name of the lock is passed as well and the string is stored. This
information is wasting storage.

Split __mutex_init() into a _genereic() variant doing the initialisation
of the lock and a _lockdep() version which does _genereic() plus the
lockdep bits. Restrict the lockdep version to lockdep enabled builds
allowing the compiler to remove the unused parameter.

This results in the following size reduction:

      text     data       bss        dec  filename
| 30237599  8161430   1176624   39575653  vmlinux.defconfig
| 30233269  8149142   1176560   39558971  vmlinux.defconfig.patched
   -4.2KiB   -12KiB

| 32455099  8471098  12934684   53860881  vmlinux.defconfig.lockdep
| 32455100  8471098  12934684   53860882  vmlinux.defconfig.patched.lockdep

| 27152407  7191822   2068040   36412269  vmlinux.defconfig.preempt_rt
| 27145937  7183630   2067976   36397543  vmlinux.defconfig.patched.preempt_rt
   -6.3KiB    -8KiB

| 29382020  7505742  13784608   50672370  vmlinux.defconfig.preempt_rt.lockdep
| 29376229  7505742  13784544   50666515  vmlinux.defconfig.patched.preempt_rt.lockdep
   -5.6KiB

[peterz: folded fix from boqun]
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Reviewed-by: Waiman Long <longman@redhat.com>
Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
Link: https://lkml.kernel.org/r/20251125145425.68319-1-boqun.feng@gmail.com
Link: https://patch.msgid.link/20251105142350.Tfeevs2N@linutronix.de
---
 include/linux/mutex.h        | 45 +++++++++++++++++++++++++++--------
 kernel/locking/mutex-debug.c | 10 +--------
 kernel/locking/mutex.c       | 28 +++++++++++++++++-----
 kernel/locking/mutex.h       |  5 +---
 kernel/locking/rtmutex_api.c | 19 +++++++++++----
 5 files changed, 75 insertions(+), 32 deletions(-)

diff --git a/include/linux/mutex.h b/include/linux/mutex.h
index 847b81c..bf535f0 100644
--- a/include/linux/mutex.h
+++ b/include/linux/mutex.h
@@ -86,8 +86,23 @@ do {									\
 #define DEFINE_MUTEX(mutexname) \
 	struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
 
-extern void __mutex_init(struct mutex *lock, const char *name,
-			 struct lock_class_key *key);
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+void mutex_init_lockep(struct mutex *lock, const char *name, struct lock_class_key *key);
+
+static inline void __mutex_init(struct mutex *lock, const char *name,
+				struct lock_class_key *key)
+{
+	mutex_init_lockep(lock, name, key);
+}
+#else
+extern void mutex_init_generic(struct mutex *lock);
+
+static inline void __mutex_init(struct mutex *lock, const char *name,
+				struct lock_class_key *key)
+{
+	mutex_init_generic(lock);
+}
+#endif /* !CONFIG_DEBUG_LOCK_ALLOC */
 
 /**
  * mutex_is_locked - is the mutex locked
@@ -111,17 +126,27 @@ extern bool mutex_is_locked(struct mutex *lock);
 #define DEFINE_MUTEX(mutexname)						\
 	struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
 
-extern void __mutex_rt_init(struct mutex *lock, const char *name,
-			    struct lock_class_key *key);
-
 #define mutex_is_locked(l)	rt_mutex_base_is_locked(&(l)->rtmutex)
 
-#define __mutex_init(mutex, name, key)			\
-do {							\
-	rt_mutex_base_init(&(mutex)->rtmutex);		\
-	__mutex_rt_init((mutex), name, key);		\
-} while (0)
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+extern void mutex_rt_init_lockdep(struct mutex *mutex, const char *name,
+			     struct lock_class_key *key);
+
+static inline void __mutex_init(struct mutex *lock, const char *name,
+				struct lock_class_key *key)
+{
+	mutex_rt_init_lockdep(lock, name, key);
+}
 
+#else
+extern void mutex_rt_init_generic(struct mutex *mutex);
+
+static inline void __mutex_init(struct mutex *lock, const char *name,
+				struct lock_class_key *key)
+{
+	mutex_rt_init_generic(lock);
+}
+#endif /* !CONFIG_LOCKDEP */
 #endif /* CONFIG_PREEMPT_RT */
 
 #ifdef CONFIG_DEBUG_MUTEXES
diff --git a/kernel/locking/mutex-debug.c b/kernel/locking/mutex-debug.c
index 949103f..2c6b02d 100644
--- a/kernel/locking/mutex-debug.c
+++ b/kernel/locking/mutex-debug.c
@@ -78,16 +78,8 @@ void debug_mutex_unlock(struct mutex *lock)
 	}
 }
 
-void debug_mutex_init(struct mutex *lock, const char *name,
-		      struct lock_class_key *key)
+void debug_mutex_init(struct mutex *lock)
 {
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-	/*
-	 * Make sure we are not reinitializing a held lock:
-	 */
-	debug_check_no_locks_freed((void *)lock, sizeof(*lock));
-	lockdep_init_map_wait(&lock->dep_map, name, key, 0, LD_WAIT_SLEEP);
-#endif
 	lock->magic = lock;
 }
 
diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
index de7d670..2a1d165 100644
--- a/kernel/locking/mutex.c
+++ b/kernel/locking/mutex.c
@@ -43,8 +43,7 @@
 # define MUTEX_WARN_ON(cond)
 #endif
 
-void
-__mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
+static void __mutex_init_generic(struct mutex *lock)
 {
 	atomic_long_set(&lock->owner, 0);
 	raw_spin_lock_init(&lock->wait_lock);
@@ -52,10 +51,8 @@ __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
 #ifdef CONFIG_MUTEX_SPIN_ON_OWNER
 	osq_lock_init(&lock->osq);
 #endif
-
-	debug_mutex_init(lock, name, key);
+	debug_mutex_init(lock);
 }
-EXPORT_SYMBOL(__mutex_init);
 
 static inline struct task_struct *__owner_task(unsigned long owner)
 {
@@ -142,6 +139,11 @@ static inline bool __mutex_trylock(struct mutex *lock)
  * There is nothing that would stop spreading the lockdep annotations outwards
  * except more code.
  */
+void mutex_init_generic(struct mutex *lock)
+{
+	__mutex_init_generic(lock);
+}
+EXPORT_SYMBOL(mutex_init_generic);
 
 /*
  * Optimistic trylock that only works in the uncontended case. Make sure to
@@ -166,7 +168,21 @@ static __always_inline bool __mutex_unlock_fast(struct mutex *lock)
 
 	return atomic_long_try_cmpxchg_release(&lock->owner, &curr, 0UL);
 }
-#endif
+
+#else /* !CONFIG_DEBUG_LOCK_ALLOC */
+
+void mutex_init_lockep(struct mutex *lock, const char *name, struct lock_class_key *key)
+{
+	__mutex_init_generic(lock);
+
+	/*
+	 * Make sure we are not reinitializing a held lock:
+	 */
+	debug_check_no_locks_freed((void *)lock, sizeof(*lock));
+	lockdep_init_map_wait(&lock->dep_map, name, key, 0, LD_WAIT_SLEEP);
+}
+EXPORT_SYMBOL(mutex_init_lockep);
+#endif /* !CONFIG_DEBUG_LOCK_ALLOC */
 
 static inline void __mutex_set_flag(struct mutex *lock, unsigned long flag)
 {
diff --git a/kernel/locking/mutex.h b/kernel/locking/mutex.h
index 2e8080a..9ad4da8 100644
--- a/kernel/locking/mutex.h
+++ b/kernel/locking/mutex.h
@@ -59,8 +59,7 @@ extern void debug_mutex_add_waiter(struct mutex *lock,
 extern void debug_mutex_remove_waiter(struct mutex *lock, struct mutex_waiter *waiter,
 				      struct task_struct *task);
 extern void debug_mutex_unlock(struct mutex *lock);
-extern void debug_mutex_init(struct mutex *lock, const char *name,
-			     struct lock_class_key *key);
+extern void debug_mutex_init(struct mutex *lock);
 #else /* CONFIG_DEBUG_MUTEXES */
 # define debug_mutex_lock_common(lock, waiter)		do { } while (0)
 # define debug_mutex_wake_waiter(lock, waiter)		do { } while (0)
@@ -68,6 +67,6 @@ extern void debug_mutex_init(struct mutex *lock, const char *name,
 # define debug_mutex_add_waiter(lock, waiter, ti)	do { } while (0)
 # define debug_mutex_remove_waiter(lock, waiter, ti)	do { } while (0)
 # define debug_mutex_unlock(lock)			do { } while (0)
-# define debug_mutex_init(lock, name, key)		do { } while (0)
+# define debug_mutex_init(lock)				do { } while (0)
 #endif /* !CONFIG_DEBUG_MUTEXES */
 #endif /* CONFIG_PREEMPT_RT */
diff --git a/kernel/locking/rtmutex_api.c b/kernel/locking/rtmutex_api.c
index bafd5af..59dbd29 100644
--- a/kernel/locking/rtmutex_api.c
+++ b/kernel/locking/rtmutex_api.c
@@ -515,13 +515,11 @@ void rt_mutex_debug_task_free(struct task_struct *task)
 
 #ifdef CONFIG_PREEMPT_RT
 /* Mutexes */
-void __mutex_rt_init(struct mutex *mutex, const char *name,
-		     struct lock_class_key *key)
+static void __mutex_rt_init_generic(struct mutex *mutex)
 {
+	rt_mutex_base_init(&mutex->rtmutex);
 	debug_check_no_locks_freed((void *)mutex, sizeof(*mutex));
-	lockdep_init_map_wait(&mutex->dep_map, name, key, 0, LD_WAIT_SLEEP);
 }
-EXPORT_SYMBOL(__mutex_rt_init);
 
 static __always_inline int __mutex_lock_common(struct mutex *lock,
 					       unsigned int state,
@@ -542,6 +540,13 @@ static __always_inline int __mutex_lock_common(struct mutex *lock,
 }
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
+void mutex_rt_init_lockdep(struct mutex *mutex, const char *name, struct lock_class_key *key)
+{
+	__mutex_rt_init_generic(mutex);
+	lockdep_init_map_wait(&mutex->dep_map, name, key, 0, LD_WAIT_SLEEP);
+}
+EXPORT_SYMBOL(mutex_rt_init_lockdep);
+
 void __sched mutex_lock_nested(struct mutex *lock, unsigned int subclass)
 {
 	__mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, subclass, NULL, _RET_IP_);
@@ -598,6 +603,12 @@ int __sched _mutex_trylock_nest_lock(struct mutex *lock,
 EXPORT_SYMBOL_GPL(_mutex_trylock_nest_lock);
 #else /* CONFIG_DEBUG_LOCK_ALLOC */
 
+void mutex_rt_init_generic(struct mutex *mutex)
+{
+	__mutex_rt_init_generic(mutex);
+}
+EXPORT_SYMBOL(mutex_rt_init_generic);
+
 void __sched mutex_lock(struct mutex *lock)
 {
 	__mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0, NULL, _RET_IP_);
[tip: locking/core] locking/mutex: Redo __mutex_init()
Posted by tip-bot2 for Sebastian Andrzej Siewior 1 month ago
The following commit has been merged into the locking/core branch of tip:

Commit-ID:     3572e2edc7b611d0b564c487bafda04b5dbb5134
Gitweb:        https://git.kernel.org/tip/3572e2edc7b611d0b564c487bafda04b5dbb5134
Author:        Sebastian Andrzej Siewior <bigeasy@linutronix.de>
AuthorDate:    Wed, 05 Nov 2025 15:23:50 +01:00
Committer:     Boqun Feng <boqun.feng@gmail.com>
CommitterDate: Wed, 12 Nov 2025 08:56:42 -08:00

locking/mutex: Redo __mutex_init()

mutex_init() invokes __mutex_init() providing the name of the lock and
a pointer to a the lock class. With LOCKDEP enabled this information is
useful but without LOCKDEP it not used at all. Passing the pointer
information of the lock class might be considered negligible but the
name of the lock is passed as well and the string is stored. This
information is wasting storage.

Split __mutex_init() into a _genereic() variant doing the initialisation
of the lock and a _lockdep() version which does _genereic() plus the
lockdep bits. Restrict the lockdep version to lockdep enabled builds
allowing the compiler to remove the unused parameter.

This results in the following size reduction:

      text     data       bss        dec  filename
| 30237599  8161430   1176624   39575653  vmlinux.defconfig
| 30233269  8149142   1176560   39558971  vmlinux.defconfig.patched
   -4.2KiB   -12KiB

| 32455099  8471098  12934684   53860881  vmlinux.defconfig.lockdep
| 32455100  8471098  12934684   53860882  vmlinux.defconfig.patched.lockdep

| 27152407  7191822   2068040   36412269  vmlinux.defconfig.preempt_rt
| 27145937  7183630   2067976   36397543  vmlinux.defconfig.patched.preempt_rt
   -6.3KiB    -8KiB

| 29382020  7505742  13784608   50672370  vmlinux.defconfig.preempt_rt.lockdep
| 29376229  7505742  13784544   50666515  vmlinux.defconfig.patched.preempt_rt.lockdep
   -5.6KiB

Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Reviewed-by: Waiman Long <longman@redhat.com>
Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
Link: https://patch.msgid.link/20251105142350.Tfeevs2N@linutronix.de
---
 include/linux/mutex.h        | 45 +++++++++++++++++++++++++++--------
 kernel/locking/mutex.c       | 22 ++++++++++++-----
 kernel/locking/rtmutex_api.c | 19 +++++++++++----
 3 files changed, 66 insertions(+), 20 deletions(-)

diff --git a/include/linux/mutex.h b/include/linux/mutex.h
index 847b81c..bf535f0 100644
--- a/include/linux/mutex.h
+++ b/include/linux/mutex.h
@@ -86,8 +86,23 @@ do {									\
 #define DEFINE_MUTEX(mutexname) \
 	struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
 
-extern void __mutex_init(struct mutex *lock, const char *name,
-			 struct lock_class_key *key);
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+void mutex_init_lockep(struct mutex *lock, const char *name, struct lock_class_key *key);
+
+static inline void __mutex_init(struct mutex *lock, const char *name,
+				struct lock_class_key *key)
+{
+	mutex_init_lockep(lock, name, key);
+}
+#else
+extern void mutex_init_generic(struct mutex *lock);
+
+static inline void __mutex_init(struct mutex *lock, const char *name,
+				struct lock_class_key *key)
+{
+	mutex_init_generic(lock);
+}
+#endif /* !CONFIG_DEBUG_LOCK_ALLOC */
 
 /**
  * mutex_is_locked - is the mutex locked
@@ -111,17 +126,27 @@ extern bool mutex_is_locked(struct mutex *lock);
 #define DEFINE_MUTEX(mutexname)						\
 	struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
 
-extern void __mutex_rt_init(struct mutex *lock, const char *name,
-			    struct lock_class_key *key);
-
 #define mutex_is_locked(l)	rt_mutex_base_is_locked(&(l)->rtmutex)
 
-#define __mutex_init(mutex, name, key)			\
-do {							\
-	rt_mutex_base_init(&(mutex)->rtmutex);		\
-	__mutex_rt_init((mutex), name, key);		\
-} while (0)
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+extern void mutex_rt_init_lockdep(struct mutex *mutex, const char *name,
+			     struct lock_class_key *key);
+
+static inline void __mutex_init(struct mutex *lock, const char *name,
+				struct lock_class_key *key)
+{
+	mutex_rt_init_lockdep(lock, name, key);
+}
 
+#else
+extern void mutex_rt_init_generic(struct mutex *mutex);
+
+static inline void __mutex_init(struct mutex *lock, const char *name,
+				struct lock_class_key *key)
+{
+	mutex_rt_init_generic(lock);
+}
+#endif /* !CONFIG_LOCKDEP */
 #endif /* CONFIG_PREEMPT_RT */
 
 #ifdef CONFIG_DEBUG_MUTEXES
diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
index de7d670..f3bb352 100644
--- a/kernel/locking/mutex.c
+++ b/kernel/locking/mutex.c
@@ -43,8 +43,7 @@
 # define MUTEX_WARN_ON(cond)
 #endif
 
-void
-__mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
+static void __mutex_init_generic(struct mutex *lock)
 {
 	atomic_long_set(&lock->owner, 0);
 	raw_spin_lock_init(&lock->wait_lock);
@@ -52,10 +51,7 @@ __mutex_init(struct mutex *lock, const char *name, struct lock_class_key *key)
 #ifdef CONFIG_MUTEX_SPIN_ON_OWNER
 	osq_lock_init(&lock->osq);
 #endif
-
-	debug_mutex_init(lock, name, key);
 }
-EXPORT_SYMBOL(__mutex_init);
 
 static inline struct task_struct *__owner_task(unsigned long owner)
 {
@@ -142,6 +138,11 @@ static inline bool __mutex_trylock(struct mutex *lock)
  * There is nothing that would stop spreading the lockdep annotations outwards
  * except more code.
  */
+void mutex_init_generic(struct mutex *lock)
+{
+	__mutex_init_generic(lock);
+}
+EXPORT_SYMBOL(mutex_init_generic);
 
 /*
  * Optimistic trylock that only works in the uncontended case. Make sure to
@@ -166,7 +167,16 @@ static __always_inline bool __mutex_unlock_fast(struct mutex *lock)
 
 	return atomic_long_try_cmpxchg_release(&lock->owner, &curr, 0UL);
 }
-#endif
+
+#else /* !CONFIG_DEBUG_LOCK_ALLOC */
+
+void mutex_init_lockep(struct mutex *lock, const char *name, struct lock_class_key *key)
+{
+	__mutex_init_generic(lock);
+	debug_mutex_init(lock, name, key);
+}
+EXPORT_SYMBOL(mutex_init_lockep);
+#endif /* !CONFIG_DEBUG_LOCK_ALLOC */
 
 static inline void __mutex_set_flag(struct mutex *lock, unsigned long flag)
 {
diff --git a/kernel/locking/rtmutex_api.c b/kernel/locking/rtmutex_api.c
index bafd5af..59dbd29 100644
--- a/kernel/locking/rtmutex_api.c
+++ b/kernel/locking/rtmutex_api.c
@@ -515,13 +515,11 @@ void rt_mutex_debug_task_free(struct task_struct *task)
 
 #ifdef CONFIG_PREEMPT_RT
 /* Mutexes */
-void __mutex_rt_init(struct mutex *mutex, const char *name,
-		     struct lock_class_key *key)
+static void __mutex_rt_init_generic(struct mutex *mutex)
 {
+	rt_mutex_base_init(&mutex->rtmutex);
 	debug_check_no_locks_freed((void *)mutex, sizeof(*mutex));
-	lockdep_init_map_wait(&mutex->dep_map, name, key, 0, LD_WAIT_SLEEP);
 }
-EXPORT_SYMBOL(__mutex_rt_init);
 
 static __always_inline int __mutex_lock_common(struct mutex *lock,
 					       unsigned int state,
@@ -542,6 +540,13 @@ static __always_inline int __mutex_lock_common(struct mutex *lock,
 }
 
 #ifdef CONFIG_DEBUG_LOCK_ALLOC
+void mutex_rt_init_lockdep(struct mutex *mutex, const char *name, struct lock_class_key *key)
+{
+	__mutex_rt_init_generic(mutex);
+	lockdep_init_map_wait(&mutex->dep_map, name, key, 0, LD_WAIT_SLEEP);
+}
+EXPORT_SYMBOL(mutex_rt_init_lockdep);
+
 void __sched mutex_lock_nested(struct mutex *lock, unsigned int subclass)
 {
 	__mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, subclass, NULL, _RET_IP_);
@@ -598,6 +603,12 @@ int __sched _mutex_trylock_nest_lock(struct mutex *lock,
 EXPORT_SYMBOL_GPL(_mutex_trylock_nest_lock);
 #else /* CONFIG_DEBUG_LOCK_ALLOC */
 
+void mutex_rt_init_generic(struct mutex *mutex)
+{
+	__mutex_rt_init_generic(mutex);
+}
+EXPORT_SYMBOL(mutex_rt_init_generic);
+
 void __sched mutex_lock(struct mutex *lock)
 {
 	__mutex_lock_common(lock, TASK_UNINTERRUPTIBLE, 0, NULL, _RET_IP_);