Skip to content

Commit b53440f

Browse files
committed
Merge tag 'locking-core-2025-12-01' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull locking updates from Ingo Molnar: "Mutexes: - Redo __mutex_init() to reduce generated code size (Sebastian Andrzej Siewior) Seqlocks: - Introduce scoped_seqlock_read() (Peter Zijlstra) - Change thread_group_cputime() to use scoped_seqlock_read() (Oleg Nesterov) - Change do_task_stat() to use scoped_seqlock_read() (Oleg Nesterov) - Change do_io_accounting() to use scoped_seqlock_read() (Oleg Nesterov) - Fix the incorrect documentation of read_seqbegin_or_lock() / need_seqretry() (Oleg Nesterov) - Allow KASAN to fail optimizing (Peter Zijlstra) Local lock updates: - Fix all kernel-doc warnings (Randy Dunlap) - Add the <linux/local_lock*.h> headers to MAINTAINERS (Sebastian Andrzej Siewior) - Reduce the risk of shadowing via s/l/__l/ and s/tl/__tl/ (Vincent Mailhol) Lock debugging: - spinlock/debug: Fix data-race in do_raw_write_lock (Alexander Sverdlin) Atomic primitives infrastructure: - atomic: Skip alignment check for try_cmpxchg() old arg (Arnd Bergmann) Rust runtime integration: - sync: atomic: Enable generated Atomic<T> usage (Boqun Feng) - sync: atomic: Implement Debug for Atomic<Debug> (Boqun Feng) - debugfs: Remove Rust native atomics and replace them with Linux versions (Boqun Feng) - debugfs: Implement Reader for Mutex<T> only when T is Unpin (Boqun Feng) - lock: guard: Add T: Unpin bound to DerefMut (Daniel Almeida) - lock: Pin the inner data (Daniel Almeida) - lock: Add a Pin<&mut T> accessor (Daniel Almeida)" * tag 'locking-core-2025-12-01' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: locking/local_lock: Fix all kernel-doc warnings locking/local_lock: s/l/__l/ and s/tl/__tl/ to reduce the risk of shadowing locking/local_lock: Add the <linux/local_lock*.h> headers to MAINTAINERS locking/mutex: Redo __mutex_init() to reduce generated code size rust: debugfs: Replace the usage of Rust native atomics rust: sync: atomic: Implement Debug for Atomic<Debug> rust: sync: atomic: Make Atomic*Ops pub(crate) seqlock: Allow KASAN to fail optimizing rust: debugfs: Implement Reader for Mutex<T> only when T is Unpin seqlock: Change do_io_accounting() to use scoped_seqlock_read() seqlock: Change do_task_stat() to use scoped_seqlock_read() seqlock: Change thread_group_cputime() to use scoped_seqlock_read() seqlock: Introduce scoped_seqlock_read() documentation: seqlock: fix the wrong documentation of read_seqbegin_or_lock/need_seqretry atomic: Skip alignment check for try_cmpxchg() old arg rust: lock: Add a Pin<&mut T> accessor rust: lock: Pin the inner data rust: lock: guard: Add T: Unpin bound to DerefMut locking/spinlock/debug: Fix data-race in do_raw_write_lock
2 parents 1b5dd29 + 43decb6 commit b53440f

22 files changed

Lines changed: 339 additions & 172 deletions

File tree

Documentation/locking/seqlock.rst

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -220,13 +220,14 @@ Read path, three categories:
220220
according to a passed marker. This is used to avoid lockless readers
221221
starvation (too much retry loops) in case of a sharp spike in write
222222
activity. First, a lockless read is tried (even marker passed). If
223-
that trial fails (odd sequence counter is returned, which is used as
224-
the next iteration marker), the lockless read is transformed to a
225-
full locking read and no retry loop is necessary::
223+
that trial fails (sequence counter doesn't match), make the marker
224+
odd for the next iteration, the lockless read is transformed to a
225+
full locking read and no retry loop is necessary, for example::
226226

227227
/* marker; even initialization */
228-
int seq = 0;
228+
int seq = 1;
229229
do {
230+
seq++; /* 2 on the 1st/lockless path, otherwise odd */
230231
read_seqbegin_or_lock(&foo_seqlock, &seq);
231232
232233
/* ... [[read-side critical section]] ... */

MAINTAINERS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14536,6 +14536,7 @@ S: Maintained
1453614536
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git locking/core
1453714537
F: Documentation/locking/
1453814538
F: arch/*/include/asm/spinlock*.h
14539+
F: include/linux/local_lock*.h
1453914540
F: include/linux/lockdep*.h
1454014541
F: include/linux/mutex*.h
1454114542
F: include/linux/rwlock*.h

fs/proc/array.c

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,6 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
481481
unsigned long flags;
482482
int exit_code = task->exit_code;
483483
struct signal_struct *sig = task->signal;
484-
unsigned int seq = 1;
485484

486485
state = *get_task_state(task);
487486
vsize = eip = esp = 0;
@@ -538,10 +537,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
538537
if (permitted && (!whole || num_threads < 2))
539538
wchan = !task_is_running(task);
540539

541-
do {
542-
seq++; /* 2 on the 1st/lockless path, otherwise odd */
543-
flags = read_seqbegin_or_lock_irqsave(&sig->stats_lock, &seq);
544-
540+
scoped_seqlock_read (&sig->stats_lock, ss_lock_irqsave) {
545541
cmin_flt = sig->cmin_flt;
546542
cmaj_flt = sig->cmaj_flt;
547543
cutime = sig->cutime;
@@ -563,8 +559,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,
563559
}
564560
rcu_read_unlock();
565561
}
566-
} while (need_seqretry(&sig->stats_lock, seq));
567-
done_seqretry_irqrestore(&sig->stats_lock, seq, flags);
562+
}
568563

569564
if (whole) {
570565
thread_group_cputime_adjusted(task, &utime, &stime);

fs/proc/base.c

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3043,21 +3043,14 @@ static int do_io_accounting(struct task_struct *task, struct seq_file *m, int wh
30433043
if (whole) {
30443044
struct signal_struct *sig = task->signal;
30453045
struct task_struct *t;
3046-
unsigned int seq = 1;
3047-
unsigned long flags;
3048-
3049-
rcu_read_lock();
3050-
do {
3051-
seq++; /* 2 on the 1st/lockless path, otherwise odd */
3052-
flags = read_seqbegin_or_lock_irqsave(&sig->stats_lock, &seq);
30533046

3047+
guard(rcu)();
3048+
scoped_seqlock_read (&sig->stats_lock, ss_lock_irqsave) {
30543049
acct = sig->ioac;
30553050
__for_each_thread(sig, t)
30563051
task_io_accounting_add(&acct, &t->ioac);
30573052

3058-
} while (need_seqretry(&sig->stats_lock, seq));
3059-
done_seqretry_irqrestore(&sig->stats_lock, seq, flags);
3060-
rcu_read_unlock();
3053+
}
30613054
} else {
30623055
acct = task->ioac;
30633056
}

include/linux/atomic/atomic-instrumented.h

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1276,7 +1276,7 @@ atomic_try_cmpxchg(atomic_t *v, int *old, int new)
12761276
{
12771277
kcsan_mb();
12781278
instrument_atomic_read_write(v, sizeof(*v));
1279-
instrument_atomic_read_write(old, sizeof(*old));
1279+
instrument_read_write(old, sizeof(*old));
12801280
return raw_atomic_try_cmpxchg(v, old, new);
12811281
}
12821282

@@ -1298,7 +1298,7 @@ static __always_inline bool
12981298
atomic_try_cmpxchg_acquire(atomic_t *v, int *old, int new)
12991299
{
13001300
instrument_atomic_read_write(v, sizeof(*v));
1301-
instrument_atomic_read_write(old, sizeof(*old));
1301+
instrument_read_write(old, sizeof(*old));
13021302
return raw_atomic_try_cmpxchg_acquire(v, old, new);
13031303
}
13041304

@@ -1321,7 +1321,7 @@ atomic_try_cmpxchg_release(atomic_t *v, int *old, int new)
13211321
{
13221322
kcsan_release();
13231323
instrument_atomic_read_write(v, sizeof(*v));
1324-
instrument_atomic_read_write(old, sizeof(*old));
1324+
instrument_read_write(old, sizeof(*old));
13251325
return raw_atomic_try_cmpxchg_release(v, old, new);
13261326
}
13271327

@@ -1343,7 +1343,7 @@ static __always_inline bool
13431343
atomic_try_cmpxchg_relaxed(atomic_t *v, int *old, int new)
13441344
{
13451345
instrument_atomic_read_write(v, sizeof(*v));
1346-
instrument_atomic_read_write(old, sizeof(*old));
1346+
instrument_read_write(old, sizeof(*old));
13471347
return raw_atomic_try_cmpxchg_relaxed(v, old, new);
13481348
}
13491349

@@ -2854,7 +2854,7 @@ atomic64_try_cmpxchg(atomic64_t *v, s64 *old, s64 new)
28542854
{
28552855
kcsan_mb();
28562856
instrument_atomic_read_write(v, sizeof(*v));
2857-
instrument_atomic_read_write(old, sizeof(*old));
2857+
instrument_read_write(old, sizeof(*old));
28582858
return raw_atomic64_try_cmpxchg(v, old, new);
28592859
}
28602860

@@ -2876,7 +2876,7 @@ static __always_inline bool
28762876
atomic64_try_cmpxchg_acquire(atomic64_t *v, s64 *old, s64 new)
28772877
{
28782878
instrument_atomic_read_write(v, sizeof(*v));
2879-
instrument_atomic_read_write(old, sizeof(*old));
2879+
instrument_read_write(old, sizeof(*old));
28802880
return raw_atomic64_try_cmpxchg_acquire(v, old, new);
28812881
}
28822882

@@ -2899,7 +2899,7 @@ atomic64_try_cmpxchg_release(atomic64_t *v, s64 *old, s64 new)
28992899
{
29002900
kcsan_release();
29012901
instrument_atomic_read_write(v, sizeof(*v));
2902-
instrument_atomic_read_write(old, sizeof(*old));
2902+
instrument_read_write(old, sizeof(*old));
29032903
return raw_atomic64_try_cmpxchg_release(v, old, new);
29042904
}
29052905

@@ -2921,7 +2921,7 @@ static __always_inline bool
29212921
atomic64_try_cmpxchg_relaxed(atomic64_t *v, s64 *old, s64 new)
29222922
{
29232923
instrument_atomic_read_write(v, sizeof(*v));
2924-
instrument_atomic_read_write(old, sizeof(*old));
2924+
instrument_read_write(old, sizeof(*old));
29252925
return raw_atomic64_try_cmpxchg_relaxed(v, old, new);
29262926
}
29272927

@@ -4432,7 +4432,7 @@ atomic_long_try_cmpxchg(atomic_long_t *v, long *old, long new)
44324432
{
44334433
kcsan_mb();
44344434
instrument_atomic_read_write(v, sizeof(*v));
4435-
instrument_atomic_read_write(old, sizeof(*old));
4435+
instrument_read_write(old, sizeof(*old));
44364436
return raw_atomic_long_try_cmpxchg(v, old, new);
44374437
}
44384438

@@ -4454,7 +4454,7 @@ static __always_inline bool
44544454
atomic_long_try_cmpxchg_acquire(atomic_long_t *v, long *old, long new)
44554455
{
44564456
instrument_atomic_read_write(v, sizeof(*v));
4457-
instrument_atomic_read_write(old, sizeof(*old));
4457+
instrument_read_write(old, sizeof(*old));
44584458
return raw_atomic_long_try_cmpxchg_acquire(v, old, new);
44594459
}
44604460

@@ -4477,7 +4477,7 @@ atomic_long_try_cmpxchg_release(atomic_long_t *v, long *old, long new)
44774477
{
44784478
kcsan_release();
44794479
instrument_atomic_read_write(v, sizeof(*v));
4480-
instrument_atomic_read_write(old, sizeof(*old));
4480+
instrument_read_write(old, sizeof(*old));
44814481
return raw_atomic_long_try_cmpxchg_release(v, old, new);
44824482
}
44834483

@@ -4499,7 +4499,7 @@ static __always_inline bool
44994499
atomic_long_try_cmpxchg_relaxed(atomic_long_t *v, long *old, long new)
45004500
{
45014501
instrument_atomic_read_write(v, sizeof(*v));
4502-
instrument_atomic_read_write(old, sizeof(*old));
4502+
instrument_read_write(old, sizeof(*old));
45034503
return raw_atomic_long_try_cmpxchg_relaxed(v, old, new);
45044504
}
45054505

@@ -5050,4 +5050,4 @@ atomic_long_dec_if_positive(atomic_long_t *v)
50505050

50515051

50525052
#endif /* _LINUX_ATOMIC_INSTRUMENTED_H */
5053-
// 8829b337928e9508259079d32581775ececd415b
5053+
// f618ac667f868941a84ce0ab2242f1786e049ed4

include/linux/local_lock.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
/**
88
* local_lock_init - Runtime initialize a lock instance
9+
* @lock: The lock variable
910
*/
1011
#define local_lock_init(lock) __local_lock_init(lock)
1112

@@ -52,7 +53,8 @@
5253
__local_unlock_irqrestore(this_cpu_ptr(lock), flags)
5354

5455
/**
55-
* local_lock_init - Runtime initialize a lock instance
56+
* local_trylock_init - Runtime initialize a lock instance
57+
* @lock: The lock variable
5658
*/
5759
#define local_trylock_init(lock) __local_trylock_init(lock)
5860

include/linux/local_lock_internal.h

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -99,18 +99,18 @@ do { \
9999

100100
#define __local_lock_acquire(lock) \
101101
do { \
102-
local_trylock_t *tl; \
103-
local_lock_t *l; \
102+
local_trylock_t *__tl; \
103+
local_lock_t *__l; \
104104
\
105-
l = (local_lock_t *)(lock); \
106-
tl = (local_trylock_t *)l; \
105+
__l = (local_lock_t *)(lock); \
106+
__tl = (local_trylock_t *)__l; \
107107
_Generic((lock), \
108108
local_trylock_t *: ({ \
109-
lockdep_assert(tl->acquired == 0); \
110-
WRITE_ONCE(tl->acquired, 1); \
109+
lockdep_assert(__tl->acquired == 0); \
110+
WRITE_ONCE(__tl->acquired, 1); \
111111
}), \
112112
local_lock_t *: (void)0); \
113-
local_lock_acquire(l); \
113+
local_lock_acquire(__l); \
114114
} while (0)
115115

116116
#define __local_lock(lock) \
@@ -133,53 +133,53 @@ do { \
133133

134134
#define __local_trylock(lock) \
135135
({ \
136-
local_trylock_t *tl; \
136+
local_trylock_t *__tl; \
137137
\
138138
preempt_disable(); \
139-
tl = (lock); \
140-
if (READ_ONCE(tl->acquired)) { \
139+
__tl = (lock); \
140+
if (READ_ONCE(__tl->acquired)) { \
141141
preempt_enable(); \
142-
tl = NULL; \
142+
__tl = NULL; \
143143
} else { \
144-
WRITE_ONCE(tl->acquired, 1); \
144+
WRITE_ONCE(__tl->acquired, 1); \
145145
local_trylock_acquire( \
146-
(local_lock_t *)tl); \
146+
(local_lock_t *)__tl); \
147147
} \
148-
!!tl; \
148+
!!__tl; \
149149
})
150150

151151
#define __local_trylock_irqsave(lock, flags) \
152152
({ \
153-
local_trylock_t *tl; \
153+
local_trylock_t *__tl; \
154154
\
155155
local_irq_save(flags); \
156-
tl = (lock); \
157-
if (READ_ONCE(tl->acquired)) { \
156+
__tl = (lock); \
157+
if (READ_ONCE(__tl->acquired)) { \
158158
local_irq_restore(flags); \
159-
tl = NULL; \
159+
__tl = NULL; \
160160
} else { \
161-
WRITE_ONCE(tl->acquired, 1); \
161+
WRITE_ONCE(__tl->acquired, 1); \
162162
local_trylock_acquire( \
163-
(local_lock_t *)tl); \
163+
(local_lock_t *)__tl); \
164164
} \
165-
!!tl; \
165+
!!__tl; \
166166
})
167167

168168
/* preemption or migration must be disabled before calling __local_lock_is_locked */
169169
#define __local_lock_is_locked(lock) READ_ONCE(this_cpu_ptr(lock)->acquired)
170170

171171
#define __local_lock_release(lock) \
172172
do { \
173-
local_trylock_t *tl; \
174-
local_lock_t *l; \
173+
local_trylock_t *__tl; \
174+
local_lock_t *__l; \
175175
\
176-
l = (local_lock_t *)(lock); \
177-
tl = (local_trylock_t *)l; \
178-
local_lock_release(l); \
176+
__l = (local_lock_t *)(lock); \
177+
__tl = (local_trylock_t *)__l; \
178+
local_lock_release(__l); \
179179
_Generic((lock), \
180180
local_trylock_t *: ({ \
181-
lockdep_assert(tl->acquired == 1); \
182-
WRITE_ONCE(tl->acquired, 0); \
181+
lockdep_assert(__tl->acquired == 1); \
182+
WRITE_ONCE(__tl->acquired, 0); \
183183
}), \
184184
local_lock_t *: (void)0); \
185185
} while (0)
@@ -223,12 +223,12 @@ typedef spinlock_t local_trylock_t;
223223
#define INIT_LOCAL_LOCK(lockname) __LOCAL_SPIN_LOCK_UNLOCKED((lockname))
224224
#define INIT_LOCAL_TRYLOCK(lockname) __LOCAL_SPIN_LOCK_UNLOCKED((lockname))
225225

226-
#define __local_lock_init(l) \
226+
#define __local_lock_init(__l) \
227227
do { \
228-
local_spin_lock_init((l)); \
228+
local_spin_lock_init((__l)); \
229229
} while (0)
230230

231-
#define __local_trylock_init(l) __local_lock_init(l)
231+
#define __local_trylock_init(__l) __local_lock_init(__l)
232232

233233
#define __local_lock(__lock) \
234234
do { \

include/linux/mutex.h

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -86,8 +86,23 @@ do { \
8686
#define DEFINE_MUTEX(mutexname) \
8787
struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
8888

89-
extern void __mutex_init(struct mutex *lock, const char *name,
90-
struct lock_class_key *key);
89+
#ifdef CONFIG_DEBUG_LOCK_ALLOC
90+
void mutex_init_lockep(struct mutex *lock, const char *name, struct lock_class_key *key);
91+
92+
static inline void __mutex_init(struct mutex *lock, const char *name,
93+
struct lock_class_key *key)
94+
{
95+
mutex_init_lockep(lock, name, key);
96+
}
97+
#else
98+
extern void mutex_init_generic(struct mutex *lock);
99+
100+
static inline void __mutex_init(struct mutex *lock, const char *name,
101+
struct lock_class_key *key)
102+
{
103+
mutex_init_generic(lock);
104+
}
105+
#endif /* !CONFIG_DEBUG_LOCK_ALLOC */
91106

92107
/**
93108
* mutex_is_locked - is the mutex locked
@@ -111,17 +126,27 @@ extern bool mutex_is_locked(struct mutex *lock);
111126
#define DEFINE_MUTEX(mutexname) \
112127
struct mutex mutexname = __MUTEX_INITIALIZER(mutexname)
113128

114-
extern void __mutex_rt_init(struct mutex *lock, const char *name,
115-
struct lock_class_key *key);
116-
117129
#define mutex_is_locked(l) rt_mutex_base_is_locked(&(l)->rtmutex)
118130

119-
#define __mutex_init(mutex, name, key) \
120-
do { \
121-
rt_mutex_base_init(&(mutex)->rtmutex); \
122-
__mutex_rt_init((mutex), name, key); \
123-
} while (0)
131+
#ifdef CONFIG_DEBUG_LOCK_ALLOC
132+
extern void mutex_rt_init_lockdep(struct mutex *mutex, const char *name,
133+
struct lock_class_key *key);
134+
135+
static inline void __mutex_init(struct mutex *lock, const char *name,
136+
struct lock_class_key *key)
137+
{
138+
mutex_rt_init_lockdep(lock, name, key);
139+
}
124140

141+
#else
142+
extern void mutex_rt_init_generic(struct mutex *mutex);
143+
144+
static inline void __mutex_init(struct mutex *lock, const char *name,
145+
struct lock_class_key *key)
146+
{
147+
mutex_rt_init_generic(lock);
148+
}
149+
#endif /* !CONFIG_LOCKDEP */
125150
#endif /* CONFIG_PREEMPT_RT */
126151

127152
#ifdef CONFIG_DEBUG_MUTEXES

0 commit comments

Comments
 (0)