Skip to content

Commit 7b367f5

Browse files
committed
Merge branch 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull core kernel fixes from Ingo Molnar: "This contains the nohz/atomic cleanup/fix for the fetch_or() ugliness you noted during the original nohz pull request, plus there's also misc fixes: - fix liblockdep build bug - fix uapi header build bug - print more lockdep hash collision info to help debug recent reports of hash collisions - update MAINTAINERS email address" * 'core-urgent-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: MAINTAINERS: Update my email address locking/lockdep: Print chain_key collision information uapi/linux/stddef.h: Provide __always_inline to userspace headers tools/lib/lockdep: Fix unsupported 'basename -s' in run_tests.sh locking/atomic, sched: Unexport fetch_or() timers/nohz: Convert tick dependency mask to atomic_t locking/atomic: Introduce atomic_fetch_or()
2 parents 17084b7 + 353def9 commit 7b367f5

File tree

9 files changed

+158
-58
lines changed

9 files changed

+158
-58
lines changed

MAINTAINERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6403,7 +6403,7 @@ KPROBES
64036403
M: Ananth N Mavinakayanahalli <[email protected]>
64046404
M: Anil S Keshavamurthy <[email protected]>
64056405
M: "David S. Miller" <[email protected]>
6406-
M: Masami Hiramatsu <[email protected]>
6406+
M: Masami Hiramatsu <[email protected]>
64076407
S: Maintained
64086408
F: Documentation/kprobes.txt
64096409
F: include/linux/kprobes.h

include/linux/atomic.h

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -559,25 +559,25 @@ static inline int atomic_dec_if_positive(atomic_t *v)
559559
#endif
560560

561561
/**
562-
* fetch_or - perform *ptr |= mask and return old value of *ptr
563-
* @ptr: pointer to value
564-
* @mask: mask to OR on the value
565-
*
566-
* cmpxchg based fetch_or, macro so it works for different integer types
562+
* atomic_fetch_or - perform *p |= mask and return old value of *p
563+
* @p: pointer to atomic_t
564+
* @mask: mask to OR on the atomic_t
567565
*/
568-
#ifndef fetch_or
569-
#define fetch_or(ptr, mask) \
570-
({ typeof(*(ptr)) __old, __val = *(ptr); \
571-
for (;;) { \
572-
__old = cmpxchg((ptr), __val, __val | (mask)); \
573-
if (__old == __val) \
574-
break; \
575-
__val = __old; \
576-
} \
577-
__old; \
578-
})
579-
#endif
566+
#ifndef atomic_fetch_or
567+
static inline int atomic_fetch_or(atomic_t *p, int mask)
568+
{
569+
int old, val = atomic_read(p);
570+
571+
for (;;) {
572+
old = atomic_cmpxchg(p, val, val | mask);
573+
if (old == val)
574+
break;
575+
val = old;
576+
}
580577

578+
return old;
579+
}
580+
#endif
581581

582582
#ifdef CONFIG_GENERIC_ATOMIC64
583583
#include <asm-generic/atomic64.h>

include/linux/sched.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,7 @@ struct signal_struct {
720720
struct task_cputime cputime_expires;
721721

722722
#ifdef CONFIG_NO_HZ_FULL
723-
unsigned long tick_dep_mask;
723+
atomic_t tick_dep_mask;
724724
#endif
725725

726726
struct list_head cpu_timers[3];
@@ -1549,7 +1549,7 @@ struct task_struct {
15491549
#endif
15501550

15511551
#ifdef CONFIG_NO_HZ_FULL
1552-
unsigned long tick_dep_mask;
1552+
atomic_t tick_dep_mask;
15531553
#endif
15541554
unsigned long nvcsw, nivcsw; /* context switch counts */
15551555
u64 start_time; /* monotonic time in nsec */

include/uapi/linux/stddef.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
11
#include <linux/compiler.h>
2+
3+
#ifndef __always_inline
4+
#define __always_inline inline
5+
#endif

kernel/locking/lockdep.c

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1999,6 +1999,77 @@ static inline int get_first_held_lock(struct task_struct *curr,
19991999
return ++i;
20002000
}
20012001

2002+
/*
2003+
* Returns the next chain_key iteration
2004+
*/
2005+
static u64 print_chain_key_iteration(int class_idx, u64 chain_key)
2006+
{
2007+
u64 new_chain_key = iterate_chain_key(chain_key, class_idx);
2008+
2009+
printk(" class_idx:%d -> chain_key:%016Lx",
2010+
class_idx,
2011+
(unsigned long long)new_chain_key);
2012+
return new_chain_key;
2013+
}
2014+
2015+
static void
2016+
print_chain_keys_held_locks(struct task_struct *curr, struct held_lock *hlock_next)
2017+
{
2018+
struct held_lock *hlock;
2019+
u64 chain_key = 0;
2020+
int depth = curr->lockdep_depth;
2021+
int i;
2022+
2023+
printk("depth: %u\n", depth + 1);
2024+
for (i = get_first_held_lock(curr, hlock_next); i < depth; i++) {
2025+
hlock = curr->held_locks + i;
2026+
chain_key = print_chain_key_iteration(hlock->class_idx, chain_key);
2027+
2028+
print_lock(hlock);
2029+
}
2030+
2031+
print_chain_key_iteration(hlock_next->class_idx, chain_key);
2032+
print_lock(hlock_next);
2033+
}
2034+
2035+
static void print_chain_keys_chain(struct lock_chain *chain)
2036+
{
2037+
int i;
2038+
u64 chain_key = 0;
2039+
int class_id;
2040+
2041+
printk("depth: %u\n", chain->depth);
2042+
for (i = 0; i < chain->depth; i++) {
2043+
class_id = chain_hlocks[chain->base + i];
2044+
chain_key = print_chain_key_iteration(class_id + 1, chain_key);
2045+
2046+
print_lock_name(lock_classes + class_id);
2047+
printk("\n");
2048+
}
2049+
}
2050+
2051+
static void print_collision(struct task_struct *curr,
2052+
struct held_lock *hlock_next,
2053+
struct lock_chain *chain)
2054+
{
2055+
printk("\n");
2056+
printk("======================\n");
2057+
printk("[chain_key collision ]\n");
2058+
print_kernel_ident();
2059+
printk("----------------------\n");
2060+
printk("%s/%d: ", current->comm, task_pid_nr(current));
2061+
printk("Hash chain already cached but the contents don't match!\n");
2062+
2063+
printk("Held locks:");
2064+
print_chain_keys_held_locks(curr, hlock_next);
2065+
2066+
printk("Locks in cached chain:");
2067+
print_chain_keys_chain(chain);
2068+
2069+
printk("\nstack backtrace:\n");
2070+
dump_stack();
2071+
}
2072+
20022073
/*
20032074
* Checks whether the chain and the current held locks are consistent
20042075
* in depth and also in content. If they are not it most likely means
@@ -2014,14 +2085,18 @@ static int check_no_collision(struct task_struct *curr,
20142085

20152086
i = get_first_held_lock(curr, hlock);
20162087

2017-
if (DEBUG_LOCKS_WARN_ON(chain->depth != curr->lockdep_depth - (i - 1)))
2088+
if (DEBUG_LOCKS_WARN_ON(chain->depth != curr->lockdep_depth - (i - 1))) {
2089+
print_collision(curr, hlock, chain);
20182090
return 0;
2091+
}
20192092

20202093
for (j = 0; j < chain->depth - 1; j++, i++) {
20212094
id = curr->held_locks[i].class_idx - 1;
20222095

2023-
if (DEBUG_LOCKS_WARN_ON(chain_hlocks[chain->base + j] != id))
2096+
if (DEBUG_LOCKS_WARN_ON(chain_hlocks[chain->base + j] != id)) {
2097+
print_collision(curr, hlock, chain);
20242098
return 0;
2099+
}
20252100
}
20262101
#endif
20272102
return 1;

kernel/sched/core.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,24 @@ static inline void init_hrtick(void)
321321
}
322322
#endif /* CONFIG_SCHED_HRTICK */
323323

324+
/*
325+
* cmpxchg based fetch_or, macro so it works for different integer types
326+
*/
327+
#define fetch_or(ptr, mask) \
328+
({ \
329+
typeof(ptr) _ptr = (ptr); \
330+
typeof(mask) _mask = (mask); \
331+
typeof(*_ptr) _old, _val = *_ptr; \
332+
\
333+
for (;;) { \
334+
_old = cmpxchg(_ptr, _val, _val | _mask); \
335+
if (_old == _val) \
336+
break; \
337+
_val = _old; \
338+
} \
339+
_old; \
340+
})
341+
324342
#if defined(CONFIG_SMP) && defined(TIF_POLLING_NRFLAG)
325343
/*
326344
* Atomically set TIF_NEED_RESCHED and test for TIF_POLLING_NRFLAG,

kernel/time/tick-sched.c

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -157,52 +157,50 @@ static void tick_sched_handle(struct tick_sched *ts, struct pt_regs *regs)
157157
cpumask_var_t tick_nohz_full_mask;
158158
cpumask_var_t housekeeping_mask;
159159
bool tick_nohz_full_running;
160-
static unsigned long tick_dep_mask;
160+
static atomic_t tick_dep_mask;
161161

162-
static void trace_tick_dependency(unsigned long dep)
162+
static bool check_tick_dependency(atomic_t *dep)
163163
{
164-
if (dep & TICK_DEP_MASK_POSIX_TIMER) {
164+
int val = atomic_read(dep);
165+
166+
if (val & TICK_DEP_MASK_POSIX_TIMER) {
165167
trace_tick_stop(0, TICK_DEP_MASK_POSIX_TIMER);
166-
return;
168+
return true;
167169
}
168170

169-
if (dep & TICK_DEP_MASK_PERF_EVENTS) {
171+
if (val & TICK_DEP_MASK_PERF_EVENTS) {
170172
trace_tick_stop(0, TICK_DEP_MASK_PERF_EVENTS);
171-
return;
173+
return true;
172174
}
173175

174-
if (dep & TICK_DEP_MASK_SCHED) {
176+
if (val & TICK_DEP_MASK_SCHED) {
175177
trace_tick_stop(0, TICK_DEP_MASK_SCHED);
176-
return;
178+
return true;
177179
}
178180

179-
if (dep & TICK_DEP_MASK_CLOCK_UNSTABLE)
181+
if (val & TICK_DEP_MASK_CLOCK_UNSTABLE) {
180182
trace_tick_stop(0, TICK_DEP_MASK_CLOCK_UNSTABLE);
183+
return true;
184+
}
185+
186+
return false;
181187
}
182188

183189
static bool can_stop_full_tick(struct tick_sched *ts)
184190
{
185191
WARN_ON_ONCE(!irqs_disabled());
186192

187-
if (tick_dep_mask) {
188-
trace_tick_dependency(tick_dep_mask);
193+
if (check_tick_dependency(&tick_dep_mask))
189194
return false;
190-
}
191195

192-
if (ts->tick_dep_mask) {
193-
trace_tick_dependency(ts->tick_dep_mask);
196+
if (check_tick_dependency(&ts->tick_dep_mask))
194197
return false;
195-
}
196198

197-
if (current->tick_dep_mask) {
198-
trace_tick_dependency(current->tick_dep_mask);
199+
if (check_tick_dependency(&current->tick_dep_mask))
199200
return false;
200-
}
201201

202-
if (current->signal->tick_dep_mask) {
203-
trace_tick_dependency(current->signal->tick_dep_mask);
202+
if (check_tick_dependency(&current->signal->tick_dep_mask))
204203
return false;
205-
}
206204

207205
return true;
208206
}
@@ -259,12 +257,12 @@ static void tick_nohz_full_kick_all(void)
259257
preempt_enable();
260258
}
261259

262-
static void tick_nohz_dep_set_all(unsigned long *dep,
260+
static void tick_nohz_dep_set_all(atomic_t *dep,
263261
enum tick_dep_bits bit)
264262
{
265-
unsigned long prev;
263+
int prev;
266264

267-
prev = fetch_or(dep, BIT_MASK(bit));
265+
prev = atomic_fetch_or(dep, BIT(bit));
268266
if (!prev)
269267
tick_nohz_full_kick_all();
270268
}
@@ -280,7 +278,7 @@ void tick_nohz_dep_set(enum tick_dep_bits bit)
280278

281279
void tick_nohz_dep_clear(enum tick_dep_bits bit)
282280
{
283-
clear_bit(bit, &tick_dep_mask);
281+
atomic_andnot(BIT(bit), &tick_dep_mask);
284282
}
285283

286284
/*
@@ -289,12 +287,12 @@ void tick_nohz_dep_clear(enum tick_dep_bits bit)
289287
*/
290288
void tick_nohz_dep_set_cpu(int cpu, enum tick_dep_bits bit)
291289
{
292-
unsigned long prev;
290+
int prev;
293291
struct tick_sched *ts;
294292

295293
ts = per_cpu_ptr(&tick_cpu_sched, cpu);
296294

297-
prev = fetch_or(&ts->tick_dep_mask, BIT_MASK(bit));
295+
prev = atomic_fetch_or(&ts->tick_dep_mask, BIT(bit));
298296
if (!prev) {
299297
preempt_disable();
300298
/* Perf needs local kick that is NMI safe */
@@ -313,7 +311,7 @@ void tick_nohz_dep_clear_cpu(int cpu, enum tick_dep_bits bit)
313311
{
314312
struct tick_sched *ts = per_cpu_ptr(&tick_cpu_sched, cpu);
315313

316-
clear_bit(bit, &ts->tick_dep_mask);
314+
atomic_andnot(BIT(bit), &ts->tick_dep_mask);
317315
}
318316

319317
/*
@@ -331,7 +329,7 @@ void tick_nohz_dep_set_task(struct task_struct *tsk, enum tick_dep_bits bit)
331329

332330
void tick_nohz_dep_clear_task(struct task_struct *tsk, enum tick_dep_bits bit)
333331
{
334-
clear_bit(bit, &tsk->tick_dep_mask);
332+
atomic_andnot(BIT(bit), &tsk->tick_dep_mask);
335333
}
336334

337335
/*
@@ -345,7 +343,7 @@ void tick_nohz_dep_set_signal(struct signal_struct *sig, enum tick_dep_bits bit)
345343

346344
void tick_nohz_dep_clear_signal(struct signal_struct *sig, enum tick_dep_bits bit)
347345
{
348-
clear_bit(bit, &sig->tick_dep_mask);
346+
atomic_andnot(BIT(bit), &sig->tick_dep_mask);
349347
}
350348

351349
/*
@@ -366,7 +364,8 @@ void __tick_nohz_task_switch(void)
366364
ts = this_cpu_ptr(&tick_cpu_sched);
367365

368366
if (ts->tick_stopped) {
369-
if (current->tick_dep_mask || current->signal->tick_dep_mask)
367+
if (atomic_read(&current->tick_dep_mask) ||
368+
atomic_read(&current->signal->tick_dep_mask))
370369
tick_nohz_full_kick();
371370
}
372371
out:

kernel/time/tick-sched.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ struct tick_sched {
6060
u64 next_timer;
6161
ktime_t idle_expires;
6262
int do_timer_last;
63-
unsigned long tick_dep_mask;
63+
atomic_t tick_dep_mask;
6464
};
6565

6666
extern struct tick_sched *tick_get_tick_sched(int cpu);

tools/lib/lockdep/run_tests.sh

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,29 @@
33
make &> /dev/null
44

55
for i in `ls tests/*.c`; do
6-
testname=$(basename -s .c "$i")
6+
testname=$(basename "$i" .c)
77
gcc -o tests/$testname -pthread -lpthread $i liblockdep.a -Iinclude -D__USE_LIBLOCKDEP &> /dev/null
88
echo -ne "$testname... "
99
if [ $(timeout 1 ./tests/$testname | wc -l) -gt 0 ]; then
1010
echo "PASSED!"
1111
else
1212
echo "FAILED!"
1313
fi
14-
rm tests/$testname
14+
if [ -f "tests/$testname" ]; then
15+
rm tests/$testname
16+
fi
1517
done
1618

1719
for i in `ls tests/*.c`; do
18-
testname=$(basename -s .c "$i")
20+
testname=$(basename "$i" .c)
1921
gcc -o tests/$testname -pthread -lpthread -Iinclude $i &> /dev/null
2022
echo -ne "(PRELOAD) $testname... "
2123
if [ $(timeout 1 ./lockdep ./tests/$testname | wc -l) -gt 0 ]; then
2224
echo "PASSED!"
2325
else
2426
echo "FAILED!"
2527
fi
26-
rm tests/$testname
28+
if [ -f "tests/$testname" ]; then
29+
rm tests/$testname
30+
fi
2731
done

0 commit comments

Comments
 (0)