aboutsummaryrefslogtreecommitdiffstats
path: root/include/linux
diff options
context:
space:
mode:
authorPeter Zijlstra <peterz@infradead.org>2015-06-11 08:46:53 -0400
committerThomas Gleixner <tglx@linutronix.de>2015-06-18 18:25:27 -0400
commita24fc60d63da2b0b31bf7c876d12a51ed4b778bd (patch)
tree8f18a0b885a75b45b22b6f0b6b94abc3b8fab01d /include/linux
parente0f56fd7066f35ae3765d080e036fa676a9d4128 (diff)
lockdep: Implement lock pinning
Add a lockdep annotation that WARNs if you 'accidentially' unlock a lock. This is especially helpful for code with callbacks, where the upper layer assumes a lock remains taken but a lower layer thinks it maybe can drop and reacquire the lock. By unwittingly breaking up the lock, races can be introduced. Lock pinning is a lockdep annotation that helps with this, when you lockdep_pin_lock() a held lock, any unlock without a lockdep_unpin_lock() will produce a WARN. Think of this as a relative of lockdep_assert_held(), except you don't only assert its held now, but ensure it stays held until you release your assertion. RFC: a possible alternative API would be something like: int cookie = lockdep_pin_lock(&foo); ... lockdep_unpin_lock(&foo, cookie); Where we pick a random number for the pin_count; this makes it impossible to sneak a lock break in without also passing the right cookie along. I've not done this because it ends up generating code for !LOCKDEP, esp. if you need to pass the cookie around for some reason. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: ktkhai@parallels.com Cc: rostedt@goodmis.org Cc: juri.lelli@gmail.com Cc: pang.xunlei@linaro.org Cc: oleg@redhat.com Cc: wanpeng.li@linux.intel.com Cc: umgwanakikbuti@gmail.com Link: http://lkml.kernel.org/r/20150611124743.906731065@infradead.org Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'include/linux')
-rw-r--r--include/linux/lockdep.h10
1 files changed, 10 insertions, 0 deletions
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h
index 066ba4157541..c5b6b5830acf 100644
--- a/include/linux/lockdep.h
+++ b/include/linux/lockdep.h
@@ -255,6 +255,7 @@ struct held_lock {
255 unsigned int check:1; /* see lock_acquire() comment */ 255 unsigned int check:1; /* see lock_acquire() comment */
256 unsigned int hardirqs_off:1; 256 unsigned int hardirqs_off:1;
257 unsigned int references:12; /* 32 bits */ 257 unsigned int references:12; /* 32 bits */
258 unsigned int pin_count;
258}; 259};
259 260
260/* 261/*
@@ -354,6 +355,9 @@ extern void lockdep_set_current_reclaim_state(gfp_t gfp_mask);
354extern void lockdep_clear_current_reclaim_state(void); 355extern void lockdep_clear_current_reclaim_state(void);
355extern void lockdep_trace_alloc(gfp_t mask); 356extern void lockdep_trace_alloc(gfp_t mask);
356 357
358extern void lock_pin_lock(struct lockdep_map *lock);
359extern void lock_unpin_lock(struct lockdep_map *lock);
360
357# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0, 361# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0,
358 362
359#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0) 363#define lockdep_depth(tsk) (debug_locks ? (tsk)->lockdep_depth : 0)
@@ -368,6 +372,9 @@ extern void lockdep_trace_alloc(gfp_t mask);
368 372
369#define lockdep_recursing(tsk) ((tsk)->lockdep_recursion) 373#define lockdep_recursing(tsk) ((tsk)->lockdep_recursion)
370 374
375#define lockdep_pin_lock(l) lock_pin_lock(&(l)->dep_map)
376#define lockdep_unpin_lock(l) lock_unpin_lock(&(l)->dep_map)
377
371#else /* !CONFIG_LOCKDEP */ 378#else /* !CONFIG_LOCKDEP */
372 379
373static inline void lockdep_off(void) 380static inline void lockdep_off(void)
@@ -420,6 +427,9 @@ struct lock_class_key { };
420 427
421#define lockdep_recursing(tsk) (0) 428#define lockdep_recursing(tsk) (0)
422 429
430#define lockdep_pin_lock(l) do { (void)(l); } while (0)
431#define lockdep_unpin_lock(l) do { (void)(l); } while (0)
432
423#endif /* !LOCKDEP */ 433#endif /* !LOCKDEP */
424 434
425#ifdef CONFIG_LOCK_STAT 435#ifdef CONFIG_LOCK_STAT