Skip to content

Commit e7904a2

Browse files
Peter ZijlstraIngo Molnar
authored andcommitted
locking/lockdep, sched/core: Implement a better lock pinning scheme
The problem with the existing lock pinning is that each pin is of value 1; this mean you can simply unpin if you know its pinned, without having any extra information. This scheme generates a random (16 bit) cookie for each pin and requires this same cookie to unpin. This means you have to keep the cookie in context. No objsize difference for !LOCKDEP kernels. Signed-off-by: Peter Zijlstra (Intel) <[email protected]> Cc: Andrew Morton <[email protected]> Cc: Linus Torvalds <[email protected]> Cc: Mike Galbraith <[email protected]> Cc: Paul E. McKenney <[email protected]> Cc: Peter Zijlstra <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: [email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent eb58075 commit e7904a2

File tree

9 files changed

+140
-68
lines changed

9 files changed

+140
-68
lines changed

include/linux/lockdep.h

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -354,8 +354,13 @@ extern void lockdep_set_current_reclaim_state(gfp_t gfp_mask);
354354
extern void lockdep_clear_current_reclaim_state(void);
355355
extern void lockdep_trace_alloc(gfp_t mask);
356356

357-
extern void lock_pin_lock(struct lockdep_map *lock);
358-
extern void lock_unpin_lock(struct lockdep_map *lock);
357+
struct pin_cookie { unsigned int val; };
358+
359+
#define NIL_COOKIE (struct pin_cookie){ .val = 0U, }
360+
361+
extern struct pin_cookie lock_pin_lock(struct lockdep_map *lock);
362+
extern void lock_repin_lock(struct lockdep_map *lock, struct pin_cookie);
363+
extern void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie);
359364

360365
# define INIT_LOCKDEP .lockdep_recursion = 0, .lockdep_reclaim_gfp = 0,
361366

@@ -371,8 +376,9 @@ extern void lock_unpin_lock(struct lockdep_map *lock);
371376

372377
#define lockdep_recursing(tsk) ((tsk)->lockdep_recursion)
373378

374-
#define lockdep_pin_lock(l) lock_pin_lock(&(l)->dep_map)
375-
#define lockdep_unpin_lock(l) lock_unpin_lock(&(l)->dep_map)
379+
#define lockdep_pin_lock(l) lock_pin_lock(&(l)->dep_map)
380+
#define lockdep_repin_lock(l,c) lock_repin_lock(&(l)->dep_map, (c))
381+
#define lockdep_unpin_lock(l,c) lock_unpin_lock(&(l)->dep_map, (c))
376382

377383
#else /* !CONFIG_LOCKDEP */
378384

@@ -425,8 +431,13 @@ struct lock_class_key { };
425431

426432
#define lockdep_recursing(tsk) (0)
427433

428-
#define lockdep_pin_lock(l) do { (void)(l); } while (0)
429-
#define lockdep_unpin_lock(l) do { (void)(l); } while (0)
434+
struct pin_cookie { };
435+
436+
#define NIL_COOKIE (struct pin_cookie){ }
437+
438+
#define lockdep_pin_lock(l) ({ struct pin_cookie cookie; cookie; })
439+
#define lockdep_repin_lock(l, c) do { (void)(l); (void)(c); } while (0)
440+
#define lockdep_unpin_lock(l, c) do { (void)(l); (void)(c); } while (0)
430441

431442
#endif /* !LOCKDEP */
432443

kernel/locking/lockdep.c

Lines changed: 62 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@
4545
#include <linux/bitops.h>
4646
#include <linux/gfp.h>
4747
#include <linux/kmemcheck.h>
48+
#include <linux/random.h>
4849

4950
#include <asm/sections.h>
5051

@@ -3554,7 +3555,35 @@ static int __lock_is_held(struct lockdep_map *lock)
35543555
return 0;
35553556
}
35563557

3557-
static void __lock_pin_lock(struct lockdep_map *lock)
3558+
static struct pin_cookie __lock_pin_lock(struct lockdep_map *lock)
3559+
{
3560+
struct pin_cookie cookie = NIL_COOKIE;
3561+
struct task_struct *curr = current;
3562+
int i;
3563+
3564+
if (unlikely(!debug_locks))
3565+
return cookie;
3566+
3567+
for (i = 0; i < curr->lockdep_depth; i++) {
3568+
struct held_lock *hlock = curr->held_locks + i;
3569+
3570+
if (match_held_lock(hlock, lock)) {
3571+
/*
3572+
* Grab 16bits of randomness; this is sufficient to not
3573+
* be guessable and still allows some pin nesting in
3574+
* our u32 pin_count.
3575+
*/
3576+
cookie.val = 1 + (prandom_u32() >> 16);
3577+
hlock->pin_count += cookie.val;
3578+
return cookie;
3579+
}
3580+
}
3581+
3582+
WARN(1, "pinning an unheld lock\n");
3583+
return cookie;
3584+
}
3585+
3586+
static void __lock_repin_lock(struct lockdep_map *lock, struct pin_cookie cookie)
35583587
{
35593588
struct task_struct *curr = current;
35603589
int i;
@@ -3566,15 +3595,15 @@ static void __lock_pin_lock(struct lockdep_map *lock)
35663595
struct held_lock *hlock = curr->held_locks + i;
35673596

35683597
if (match_held_lock(hlock, lock)) {
3569-
hlock->pin_count++;
3598+
hlock->pin_count += cookie.val;
35703599
return;
35713600
}
35723601
}
35733602

35743603
WARN(1, "pinning an unheld lock\n");
35753604
}
35763605

3577-
static void __lock_unpin_lock(struct lockdep_map *lock)
3606+
static void __lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie cookie)
35783607
{
35793608
struct task_struct *curr = current;
35803609
int i;
@@ -3589,7 +3618,11 @@ static void __lock_unpin_lock(struct lockdep_map *lock)
35893618
if (WARN(!hlock->pin_count, "unpinning an unpinned lock\n"))
35903619
return;
35913620

3592-
hlock->pin_count--;
3621+
hlock->pin_count -= cookie.val;
3622+
3623+
if (WARN((int)hlock->pin_count < 0, "pin count corrupted\n"))
3624+
hlock->pin_count = 0;
3625+
35933626
return;
35943627
}
35953628
}
@@ -3720,24 +3753,44 @@ int lock_is_held(struct lockdep_map *lock)
37203753
}
37213754
EXPORT_SYMBOL_GPL(lock_is_held);
37223755

3723-
void lock_pin_lock(struct lockdep_map *lock)
3756+
struct pin_cookie lock_pin_lock(struct lockdep_map *lock)
37243757
{
3758+
struct pin_cookie cookie = NIL_COOKIE;
37253759
unsigned long flags;
37263760

37273761
if (unlikely(current->lockdep_recursion))
3728-
return;
3762+
return cookie;
37293763

37303764
raw_local_irq_save(flags);
37313765
check_flags(flags);
37323766

37333767
current->lockdep_recursion = 1;
3734-
__lock_pin_lock(lock);
3768+
cookie = __lock_pin_lock(lock);
37353769
current->lockdep_recursion = 0;
37363770
raw_local_irq_restore(flags);
3771+
3772+
return cookie;
37373773
}
37383774
EXPORT_SYMBOL_GPL(lock_pin_lock);
37393775

3740-
void lock_unpin_lock(struct lockdep_map *lock)
3776+
void lock_repin_lock(struct lockdep_map *lock, struct pin_cookie cookie)
3777+
{
3778+
unsigned long flags;
3779+
3780+
if (unlikely(current->lockdep_recursion))
3781+
return;
3782+
3783+
raw_local_irq_save(flags);
3784+
check_flags(flags);
3785+
3786+
current->lockdep_recursion = 1;
3787+
__lock_repin_lock(lock, cookie);
3788+
current->lockdep_recursion = 0;
3789+
raw_local_irq_restore(flags);
3790+
}
3791+
EXPORT_SYMBOL_GPL(lock_repin_lock);
3792+
3793+
void lock_unpin_lock(struct lockdep_map *lock, struct pin_cookie cookie)
37413794
{
37423795
unsigned long flags;
37433796

@@ -3748,7 +3801,7 @@ void lock_unpin_lock(struct lockdep_map *lock)
37483801
check_flags(flags);
37493802

37503803
current->lockdep_recursion = 1;
3751-
__lock_unpin_lock(lock);
3804+
__lock_unpin_lock(lock, cookie);
37523805
current->lockdep_recursion = 0;
37533806
raw_local_irq_restore(flags);
37543807
}

0 commit comments

Comments
 (0)