Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge tag 'locking-core-2025-07-29' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull locking updates from Ingo Molnar:
"Locking primitives:

- Mark devm_mutex_init() as __must_check and fix drivers that didn't
check the return code (Thomas Weißschuh)

- Reorganize <linux/local_lock.h> to better expose the internal APIs
to local variables (Sebastian Andrzej Siewior)

- Remove OWNER_SPINNABLE in rwsem (Jinliang Zheng)

- Remove redundant #ifdefs in the mutex code (Ran Xiaokai)

Lockdep:

- Avoid returning struct in lock_stats() (Arnd Bergmann)

- Change `static const` into enum for LOCKF_*_IRQ_* (Arnd Bergmann)

- Temporarily use synchronize_rcu_expedited() in
lockdep_unregister_key() to speed things up. (Breno Leitao)

Rust runtime:

- Add #[must_use] to Lock::try_lock() (Jason Devers)"

* tag 'locking-core-2025-07-29' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
lockdep: Speed up lockdep_unregister_key() with expedited RCU synchronization
locking/mutex: Remove redundant #ifdefs
locking/lockdep: Change 'static const' variables to enum values
locking/lockdep: Avoid struct return in lock_stats()
locking/rwsem: Use OWNER_NONSPINNABLE directly instead of OWNER_SPINNABLE
rust: sync: Add #[must_use] to Lock::try_lock()
locking/mutex: Mark devm_mutex_init() as __must_check
leds: lp8860: Check return value of devm_mutex_init()
spi: spi-nxp-fspi: Check return value of devm_mutex_init()
local_lock: Move this_cpu_ptr() notation from internal to main header

+75 -65
+3 -1
drivers/leds/leds-lp8860.c
··· 307 307 led->client = client; 308 308 led->led_dev.brightness_set_blocking = lp8860_brightness_set; 309 309 310 - devm_mutex_init(&client->dev, &led->lock); 310 + ret = devm_mutex_init(&client->dev, &led->lock); 311 + if (ret) 312 + return dev_err_probe(&client->dev, ret, "Failed to initialize lock\n"); 311 313 312 314 led->regmap = devm_regmap_init_i2c(client, &lp8860_regmap_config); 313 315 if (IS_ERR(led->regmap)) {
+3 -1
drivers/spi/spi-nxp-fspi.c
··· 1272 1272 if (ret) 1273 1273 return dev_err_probe(dev, ret, "Failed to request irq\n"); 1274 1274 1275 - devm_mutex_init(dev, &f->lock); 1275 + ret = devm_mutex_init(dev, &f->lock); 1276 + if (ret) 1277 + return dev_err_probe(dev, ret, "Failed to initialize lock\n"); 1276 1278 1277 1279 ctlr->bus_num = -1; 1278 1280 ctlr->num_chipselect = NXP_FSPI_MAX_CHIPSELECT;
+10 -10
include/linux/local_lock.h
··· 13 13 * local_lock - Acquire a per CPU local lock 14 14 * @lock: The lock variable 15 15 */ 16 - #define local_lock(lock) __local_lock(lock) 16 + #define local_lock(lock) __local_lock(this_cpu_ptr(lock)) 17 17 18 18 /** 19 19 * local_lock_irq - Acquire a per CPU local lock and disable interrupts 20 20 * @lock: The lock variable 21 21 */ 22 - #define local_lock_irq(lock) __local_lock_irq(lock) 22 + #define local_lock_irq(lock) __local_lock_irq(this_cpu_ptr(lock)) 23 23 24 24 /** 25 25 * local_lock_irqsave - Acquire a per CPU local lock, save and disable ··· 28 28 * @flags: Storage for interrupt flags 29 29 */ 30 30 #define local_lock_irqsave(lock, flags) \ 31 - __local_lock_irqsave(lock, flags) 31 + __local_lock_irqsave(this_cpu_ptr(lock), flags) 32 32 33 33 /** 34 34 * local_unlock - Release a per CPU local lock 35 35 * @lock: The lock variable 36 36 */ 37 - #define local_unlock(lock) __local_unlock(lock) 37 + #define local_unlock(lock) __local_unlock(this_cpu_ptr(lock)) 38 38 39 39 /** 40 40 * local_unlock_irq - Release a per CPU local lock and enable interrupts 41 41 * @lock: The lock variable 42 42 */ 43 - #define local_unlock_irq(lock) __local_unlock_irq(lock) 43 + #define local_unlock_irq(lock) __local_unlock_irq(this_cpu_ptr(lock)) 44 44 45 45 /** 46 46 * local_unlock_irqrestore - Release a per CPU local lock and restore ··· 49 49 * @flags: Interrupt flags to restore 50 50 */ 51 51 #define local_unlock_irqrestore(lock, flags) \ 52 - __local_unlock_irqrestore(lock, flags) 52 + __local_unlock_irqrestore(this_cpu_ptr(lock), flags) 53 53 54 54 /** 55 55 * local_lock_init - Runtime initialize a lock instance ··· 64 64 * locking constrains it will _always_ fail to acquire the lock in NMI or 65 65 * HARDIRQ context on PREEMPT_RT. 66 66 */ 67 - #define local_trylock(lock) __local_trylock(lock) 67 + #define local_trylock(lock) __local_trylock(this_cpu_ptr(lock)) 68 68 69 69 /** 70 70 * local_trylock_irqsave - Try to acquire a per CPU local lock, save and disable ··· 77 77 * HARDIRQ context on PREEMPT_RT. 78 78 */ 79 79 #define local_trylock_irqsave(lock, flags) \ 80 - __local_trylock_irqsave(lock, flags) 80 + __local_trylock_irqsave(this_cpu_ptr(lock), flags) 81 81 82 82 DEFINE_GUARD(local_lock, local_lock_t __percpu*, 83 83 local_lock(_T), ··· 91 91 unsigned long flags) 92 92 93 93 #define local_lock_nested_bh(_lock) \ 94 - __local_lock_nested_bh(_lock) 94 + __local_lock_nested_bh(this_cpu_ptr(_lock)) 95 95 96 96 #define local_unlock_nested_bh(_lock) \ 97 - __local_unlock_nested_bh(_lock) 97 + __local_unlock_nested_bh(this_cpu_ptr(_lock)) 98 98 99 99 DEFINE_GUARD(local_lock_nested_bh, local_lock_t __percpu*, 100 100 local_lock_nested_bh(_T),
+15 -15
include/linux/local_lock_internal.h
··· 99 99 local_trylock_t *tl; \ 100 100 local_lock_t *l; \ 101 101 \ 102 - l = (local_lock_t *)this_cpu_ptr(lock); \ 102 + l = (local_lock_t *)(lock); \ 103 103 tl = (local_trylock_t *)l; \ 104 104 _Generic((lock), \ 105 - __percpu local_trylock_t *: ({ \ 105 + local_trylock_t *: ({ \ 106 106 lockdep_assert(tl->acquired == 0); \ 107 107 WRITE_ONCE(tl->acquired, 1); \ 108 108 }), \ 109 - __percpu local_lock_t *: (void)0); \ 109 + local_lock_t *: (void)0); \ 110 110 local_lock_acquire(l); \ 111 111 } while (0) 112 112 ··· 133 133 local_trylock_t *tl; \ 134 134 \ 135 135 preempt_disable(); \ 136 - tl = this_cpu_ptr(lock); \ 136 + tl = (lock); \ 137 137 if (READ_ONCE(tl->acquired)) { \ 138 138 preempt_enable(); \ 139 139 tl = NULL; \ ··· 150 150 local_trylock_t *tl; \ 151 151 \ 152 152 local_irq_save(flags); \ 153 - tl = this_cpu_ptr(lock); \ 153 + tl = (lock); \ 154 154 if (READ_ONCE(tl->acquired)) { \ 155 155 local_irq_restore(flags); \ 156 156 tl = NULL; \ ··· 167 167 local_trylock_t *tl; \ 168 168 local_lock_t *l; \ 169 169 \ 170 - l = (local_lock_t *)this_cpu_ptr(lock); \ 170 + l = (local_lock_t *)(lock); \ 171 171 tl = (local_trylock_t *)l; \ 172 172 local_lock_release(l); \ 173 173 _Generic((lock), \ 174 - __percpu local_trylock_t *: ({ \ 174 + local_trylock_t *: ({ \ 175 175 lockdep_assert(tl->acquired == 1); \ 176 176 WRITE_ONCE(tl->acquired, 0); \ 177 177 }), \ 178 - __percpu local_lock_t *: (void)0); \ 178 + local_lock_t *: (void)0); \ 179 179 } while (0) 180 180 181 181 #define __local_unlock(lock) \ ··· 199 199 #define __local_lock_nested_bh(lock) \ 200 200 do { \ 201 201 lockdep_assert_in_softirq(); \ 202 - local_lock_acquire(this_cpu_ptr(lock)); \ 202 + local_lock_acquire((lock)); \ 203 203 } while (0) 204 204 205 205 #define __local_unlock_nested_bh(lock) \ 206 - local_lock_release(this_cpu_ptr(lock)) 206 + local_lock_release((lock)) 207 207 208 208 #else /* !CONFIG_PREEMPT_RT */ 209 209 ··· 227 227 #define __local_lock(__lock) \ 228 228 do { \ 229 229 migrate_disable(); \ 230 - spin_lock(this_cpu_ptr((__lock))); \ 230 + spin_lock((__lock)); \ 231 231 } while (0) 232 232 233 233 #define __local_lock_irq(lock) __local_lock(lock) ··· 241 241 242 242 #define __local_unlock(__lock) \ 243 243 do { \ 244 - spin_unlock(this_cpu_ptr((__lock))); \ 244 + spin_unlock((__lock)); \ 245 245 migrate_enable(); \ 246 246 } while (0) 247 247 ··· 252 252 #define __local_lock_nested_bh(lock) \ 253 253 do { \ 254 254 lockdep_assert_in_softirq_func(); \ 255 - spin_lock(this_cpu_ptr(lock)); \ 255 + spin_lock((lock)); \ 256 256 } while (0) 257 257 258 258 #define __local_unlock_nested_bh(lock) \ 259 259 do { \ 260 - spin_unlock(this_cpu_ptr((lock))); \ 260 + spin_unlock((lock)); \ 261 261 } while (0) 262 262 263 263 #define __local_trylock(lock) \ ··· 268 268 __locked = 0; \ 269 269 } else { \ 270 270 migrate_disable(); \ 271 - __locked = spin_trylock(this_cpu_ptr((lock))); \ 271 + __locked = spin_trylock((lock)); \ 272 272 if (!__locked) \ 273 273 migrate_enable(); \ 274 274 } \
+1 -1
include/linux/lockdep_types.h
··· 175 175 unsigned long bounces[nr_bounce_types]; 176 176 }; 177 177 178 - struct lock_class_stats lock_stats(struct lock_class *class); 178 + void lock_stats(struct lock_class *class, struct lock_class_stats *stats); 179 179 void clear_lock_stats(struct lock_class *class); 180 180 #endif 181 181
+7 -4
include/linux/mutex.h
··· 126 126 127 127 #ifdef CONFIG_DEBUG_MUTEXES 128 128 129 - int __devm_mutex_init(struct device *dev, struct mutex *lock); 129 + int __must_check __devm_mutex_init(struct device *dev, struct mutex *lock); 130 130 131 131 #else 132 132 133 - static inline int __devm_mutex_init(struct device *dev, struct mutex *lock) 133 + static inline int __must_check __devm_mutex_init(struct device *dev, struct mutex *lock) 134 134 { 135 135 /* 136 136 * When CONFIG_DEBUG_MUTEXES is off mutex_destroy() is just a nop so ··· 141 141 142 142 #endif 143 143 144 - #define devm_mutex_init(dev, mutex) \ 144 + #define __mutex_init_ret(mutex) \ 145 145 ({ \ 146 146 typeof(mutex) mutex_ = (mutex); \ 147 147 \ 148 148 mutex_init(mutex_); \ 149 - __devm_mutex_init(dev, mutex_); \ 149 + mutex_; \ 150 150 }) 151 + 152 + #define devm_mutex_init(dev, mutex) \ 153 + __devm_mutex_init(dev, __mutex_init_ret(mutex)) 151 154 152 155 /* 153 156 * See kernel/locking/mutex.c for detailed documentation of these APIs.
+22 -17
kernel/locking/lockdep.c
··· 297 297 dst->nr += src->nr; 298 298 } 299 299 300 - struct lock_class_stats lock_stats(struct lock_class *class) 300 + void lock_stats(struct lock_class *class, struct lock_class_stats *stats) 301 301 { 302 - struct lock_class_stats stats; 303 302 int cpu, i; 304 303 305 - memset(&stats, 0, sizeof(struct lock_class_stats)); 304 + memset(stats, 0, sizeof(struct lock_class_stats)); 306 305 for_each_possible_cpu(cpu) { 307 306 struct lock_class_stats *pcs = 308 307 &per_cpu(cpu_lock_stats, cpu)[class - lock_classes]; 309 308 310 - for (i = 0; i < ARRAY_SIZE(stats.contention_point); i++) 311 - stats.contention_point[i] += pcs->contention_point[i]; 309 + for (i = 0; i < ARRAY_SIZE(stats->contention_point); i++) 310 + stats->contention_point[i] += pcs->contention_point[i]; 312 311 313 - for (i = 0; i < ARRAY_SIZE(stats.contending_point); i++) 314 - stats.contending_point[i] += pcs->contending_point[i]; 312 + for (i = 0; i < ARRAY_SIZE(stats->contending_point); i++) 313 + stats->contending_point[i] += pcs->contending_point[i]; 315 314 316 - lock_time_add(&pcs->read_waittime, &stats.read_waittime); 317 - lock_time_add(&pcs->write_waittime, &stats.write_waittime); 315 + lock_time_add(&pcs->read_waittime, &stats->read_waittime); 316 + lock_time_add(&pcs->write_waittime, &stats->write_waittime); 318 317 319 - lock_time_add(&pcs->read_holdtime, &stats.read_holdtime); 320 - lock_time_add(&pcs->write_holdtime, &stats.write_holdtime); 318 + lock_time_add(&pcs->read_holdtime, &stats->read_holdtime); 319 + lock_time_add(&pcs->write_holdtime, &stats->write_holdtime); 321 320 322 - for (i = 0; i < ARRAY_SIZE(stats.bounces); i++) 323 - stats.bounces[i] += pcs->bounces[i]; 321 + for (i = 0; i < ARRAY_SIZE(stats->bounces); i++) 322 + stats->bounces[i] += pcs->bounces[i]; 324 323 } 325 - 326 - return stats; 327 324 } 328 325 329 326 void clear_lock_stats(struct lock_class *class) ··· 6616 6619 if (need_callback) 6617 6620 call_rcu(&delayed_free.rcu_head, free_zapped_rcu); 6618 6621 6619 - /* Wait until is_dynamic_key() has finished accessing k->hash_entry. */ 6620 - synchronize_rcu(); 6622 + /* 6623 + * Wait until is_dynamic_key() has finished accessing k->hash_entry. 6624 + * 6625 + * Some operations like __qdisc_destroy() will call this in a debug 6626 + * kernel, and the network traffic is disabled while waiting, hence 6627 + * the delay of the wait matters in debugging cases. Currently use a 6628 + * synchronize_rcu_expedited() to speed up the wait at the cost of 6629 + * system IPIs. TODO: Replace RCU with hazptr for this. 6630 + */ 6631 + synchronize_rcu_expedited(); 6621 6632 } 6622 6633 EXPORT_SYMBOL_GPL(lockdep_unregister_key); 6623 6634
+10 -8
kernel/locking/lockdep_internals.h
··· 47 47 __LOCKF(USED_READ) 48 48 }; 49 49 50 + enum { 50 51 #define LOCKDEP_STATE(__STATE) LOCKF_ENABLED_##__STATE | 51 - static const unsigned long LOCKF_ENABLED_IRQ = 52 + LOCKF_ENABLED_IRQ = 52 53 #include "lockdep_states.h" 53 - 0; 54 + 0, 54 55 #undef LOCKDEP_STATE 55 56 56 57 #define LOCKDEP_STATE(__STATE) LOCKF_USED_IN_##__STATE | 57 - static const unsigned long LOCKF_USED_IN_IRQ = 58 + LOCKF_USED_IN_IRQ = 58 59 #include "lockdep_states.h" 59 - 0; 60 + 0, 60 61 #undef LOCKDEP_STATE 61 62 62 63 #define LOCKDEP_STATE(__STATE) LOCKF_ENABLED_##__STATE##_READ | 63 - static const unsigned long LOCKF_ENABLED_IRQ_READ = 64 + LOCKF_ENABLED_IRQ_READ = 64 65 #include "lockdep_states.h" 65 - 0; 66 + 0, 66 67 #undef LOCKDEP_STATE 67 68 68 69 #define LOCKDEP_STATE(__STATE) LOCKF_USED_IN_##__STATE##_READ | 69 - static const unsigned long LOCKF_USED_IN_IRQ_READ = 70 + LOCKF_USED_IN_IRQ_READ = 70 71 #include "lockdep_states.h" 71 - 0; 72 + 0, 72 73 #undef LOCKDEP_STATE 74 + }; 73 75 74 76 #define LOCKF_ENABLED_IRQ_ALL (LOCKF_ENABLED_IRQ | LOCKF_ENABLED_IRQ_READ) 75 77 #define LOCKF_USED_IN_IRQ_ALL (LOCKF_USED_IN_IRQ | LOCKF_USED_IN_IRQ_READ)
+1 -1
kernel/locking/lockdep_proc.c
··· 657 657 if (!test_bit(idx, lock_classes_in_use)) 658 658 continue; 659 659 iter->class = class; 660 - iter->stats = lock_stats(class); 660 + lock_stats(class, &iter->stats); 661 661 iter++; 662 662 } 663 663
-4
kernel/locking/mutex.c
··· 191 191 __mutex_add_waiter(struct mutex *lock, struct mutex_waiter *waiter, 192 192 struct list_head *list) 193 193 { 194 - #ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER 195 194 hung_task_set_blocker(lock, BLOCKER_TYPE_MUTEX); 196 - #endif 197 195 debug_mutex_add_waiter(lock, waiter, current); 198 196 199 197 list_add_tail(&waiter->list, list); ··· 207 209 __mutex_clear_flag(lock, MUTEX_FLAGS); 208 210 209 211 debug_mutex_remove_waiter(lock, waiter, current); 210 - #ifdef CONFIG_DETECT_HUNG_TASK_BLOCKER 211 212 hung_task_clear_blocker(); 212 - #endif 213 213 } 214 214 215 215 /*
+1 -3
kernel/locking/rwsem.c
··· 727 727 return ret; 728 728 } 729 729 730 - #define OWNER_SPINNABLE (OWNER_NULL | OWNER_WRITER | OWNER_READER) 731 - 732 730 static inline enum owner_state 733 731 rwsem_owner_state(struct task_struct *owner, unsigned long flags) 734 732 { ··· 833 835 enum owner_state owner_state; 834 836 835 837 owner_state = rwsem_spin_on_owner(sem); 836 - if (!(owner_state & OWNER_SPINNABLE)) 838 + if (owner_state == OWNER_NONSPINNABLE) 837 839 break; 838 840 839 841 /*
+2
rust/kernel/sync/lock.rs
··· 175 175 /// Tries to acquire the lock. 176 176 /// 177 177 /// Returns a guard that can be used to access the data protected by the lock if successful. 178 + // `Option<T>` is not `#[must_use]` even if `T` is, thus the attribute is needed here. 179 + #[must_use = "if unused, the lock will be immediately unlocked"] 178 180 pub fn try_lock(&self) -> Option<Guard<'_, T, B>> { 179 181 // SAFETY: The constructor of the type calls `init`, so the existence of the object proves 180 182 // that `init` was called.