summaryrefslogtreecommitdiffstats
path: root/include/linux/lockdep.h
diff options
context:
space:
mode:
authorByungchul Park <byungchul.park@lge.com>2017-08-07 03:12:52 -0400
committerIngo Molnar <mingo@kernel.org>2017-08-10 06:29:07 -0400
commitb09be676e0ff25bd6d2e7637e26d349f9109ad75 (patch)
tree8dc82ceaa001d29bb07a51f5c4814759b303e8e4 /include/linux/lockdep.h
parentce07a9415f266e181a0a33033a5f7138760240a4 (diff)
locking/lockdep: Implement the 'crossrelease' feature
Lockdep is a runtime locking correctness validator that detects and reports a deadlock or its possibility by checking dependencies between locks. It's useful since it does not report just an actual deadlock but also the possibility of a deadlock that has not actually happened yet. That enables problems to be fixed before they affect real systems. However, this facility is only applicable to typical locks, such as spinlocks and mutexes, which are normally released within the context in which they were acquired. However, synchronization primitives like page locks or completions, which are allowed to be released in any context, also create dependencies and can cause a deadlock. So lockdep should track these locks to do a better job. The 'crossrelease' implementation makes these primitives also be tracked. Signed-off-by: Byungchul Park <byungchul.park@lge.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: akpm@linux-foundation.org Cc: boqun.feng@gmail.com Cc: kernel-team@lge.com Cc: kirill@shutemov.name Cc: npiggin@gmail.com Cc: walken@google.com Cc: willy@infradead.org Link: http://lkml.kernel.org/r/1502089981-21272-6-git-send-email-byungchul.park@lge.com Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'include/linux/lockdep.h')
-rw-r--r--include/linux/lockdep.h110
1 files changed, 103 insertions, 7 deletions
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index 0a4c02c2d7a2..e1e0fcd99613 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -155,6 +155,12 @@ struct lockdep_map {
155 int cpu; 155 int cpu;
156 unsigned long ip; 156 unsigned long ip;
157#endif 157#endif
158#ifdef CONFIG_LOCKDEP_CROSSRELEASE
159 /*
160 * Whether it's a crosslock.
161 */
162 int cross;
163#endif
158}; 164};
159 165
160static inline void lockdep_copy_map(struct lockdep_map *to, 166static inline void lockdep_copy_map(struct lockdep_map *to,
@@ -258,8 +264,62 @@ struct held_lock {
258 unsigned int hardirqs_off:1; 264 unsigned int hardirqs_off:1;
259 unsigned int references:12; /* 32 bits */ 265 unsigned int references:12; /* 32 bits */
260 unsigned int pin_count; 266 unsigned int pin_count;
267#ifdef CONFIG_LOCKDEP_CROSSRELEASE
268 /*
269 * Generation id.
270 *
271 * A value of cross_gen_id will be stored when holding this,
272 * which is globally increased whenever each crosslock is held.
273 */
274 unsigned int gen_id;
275#endif
276};
277
278#ifdef CONFIG_LOCKDEP_CROSSRELEASE
279#define MAX_XHLOCK_TRACE_ENTRIES 5
280
281/*
282 * This is for keeping locks waiting for commit so that true dependencies
283 * can be added at commit step.
284 */
285struct hist_lock {
286 /*
287 * Seperate stack_trace data. This will be used at commit step.
288 */
289 struct stack_trace trace;
290 unsigned long trace_entries[MAX_XHLOCK_TRACE_ENTRIES];
291
292 /*
293 * Seperate hlock instance. This will be used at commit step.
294 *
295 * TODO: Use a smaller data structure containing only necessary
296 * data. However, we should make lockdep code able to handle the
297 * smaller one first.
298 */
299 struct held_lock hlock;
300};
301
302/*
303 * To initialize a lock as crosslock, lockdep_init_map_crosslock() should
304 * be called instead of lockdep_init_map().
305 */
306struct cross_lock {
307 /*
308 * Seperate hlock instance. This will be used at commit step.
309 *
310 * TODO: Use a smaller data structure containing only necessary
311 * data. However, we should make lockdep code able to handle the
312 * smaller one first.
313 */
314 struct held_lock hlock;
261}; 315};
262 316
317struct lockdep_map_cross {
318 struct lockdep_map map;
319 struct cross_lock xlock;
320};
321#endif
322
263/* 323/*
264 * Initialization, self-test and debugging-output methods: 324 * Initialization, self-test and debugging-output methods:
265 */ 325 */
@@ -282,13 +342,6 @@ extern void lockdep_init_map(struct lockdep_map *lock, const char *name,
282 struct lock_class_key *key, int subclass); 342 struct lock_class_key *key, int subclass);
283 343
284/* 344/*
285 * To initialize a lockdep_map statically use this macro.
286 * Note that _name must not be NULL.
287 */
288#define STATIC_LOCKDEP_MAP_INIT(_name, _key) \
289 { .name = (_name), .key = (void *)(_key), }
290
291/*
292 * Reinitialize a lock key - for cases where there is special locking or 345 * Reinitialize a lock key - for cases where there is special locking or
293 * special initialization of locks so that the validator gets the scope 346 * special initialization of locks so that the validator gets the scope
294 * of dependencies wrong: they are either too broad (they need a class-split) 347 * of dependencies wrong: they are either too broad (they need a class-split)
@@ -460,6 +513,49 @@ struct pin_cookie { };
460 513
461#endif /* !LOCKDEP */ 514#endif /* !LOCKDEP */
462 515
516enum xhlock_context_t {
517 XHLOCK_HARD,
518 XHLOCK_SOFT,
519 XHLOCK_PROC,
520 XHLOCK_CTX_NR,
521};
522
523#ifdef CONFIG_LOCKDEP_CROSSRELEASE
524extern void lockdep_init_map_crosslock(struct lockdep_map *lock,
525 const char *name,
526 struct lock_class_key *key,
527 int subclass);
528extern void lock_commit_crosslock(struct lockdep_map *lock);
529
530#define STATIC_CROSS_LOCKDEP_MAP_INIT(_name, _key) \
531 { .map.name = (_name), .map.key = (void *)(_key), \
532 .map.cross = 1, }
533
534/*
535 * To initialize a lockdep_map statically use this macro.
536 * Note that _name must not be NULL.
537 */
538#define STATIC_LOCKDEP_MAP_INIT(_name, _key) \
539 { .name = (_name), .key = (void *)(_key), .cross = 0, }
540
541extern void crossrelease_hist_start(enum xhlock_context_t c);
542extern void crossrelease_hist_end(enum xhlock_context_t c);
543extern void lockdep_init_task(struct task_struct *task);
544extern void lockdep_free_task(struct task_struct *task);
545#else
546/*
547 * To initialize a lockdep_map statically use this macro.
548 * Note that _name must not be NULL.
549 */
550#define STATIC_LOCKDEP_MAP_INIT(_name, _key) \
551 { .name = (_name), .key = (void *)(_key), }
552
553static inline void crossrelease_hist_start(enum xhlock_context_t c) {}
554static inline void crossrelease_hist_end(enum xhlock_context_t c) {}
555static inline void lockdep_init_task(struct task_struct *task) {}
556static inline void lockdep_free_task(struct task_struct *task) {}
557#endif
558
463#ifdef CONFIG_LOCK_STAT 559#ifdef CONFIG_LOCK_STAT
464 560
465extern void lock_contended(struct lockdep_map *lock, unsigned long ip); 561extern void lock_contended(struct lockdep_map *lock, unsigned long ip);