diff options
-rw-r--r-- | include/linux/lockdep.h | 4 | ||||
-rw-r--r-- | kernel/lockdep.c | 89 |
2 files changed, 80 insertions, 13 deletions
diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index a6d5e5e4d08..47d42eff612 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h | |||
@@ -213,10 +213,12 @@ struct held_lock { | |||
213 | * interrupt context: | 213 | * interrupt context: |
214 | */ | 214 | */ |
215 | unsigned int irq_context:2; /* bit 0 - soft, bit 1 - hard */ | 215 | unsigned int irq_context:2; /* bit 0 - soft, bit 1 - hard */ |
216 | unsigned int trylock:1; | 216 | unsigned int trylock:1; /* 16 bits */ |
217 | |||
217 | unsigned int read:2; /* see lock_acquire() comment */ | 218 | unsigned int read:2; /* see lock_acquire() comment */ |
218 | unsigned int check:2; /* see lock_acquire() comment */ | 219 | unsigned int check:2; /* see lock_acquire() comment */ |
219 | unsigned int hardirqs_off:1; | 220 | unsigned int hardirqs_off:1; |
221 | unsigned int references:11; /* 32 bits */ | ||
220 | }; | 222 | }; |
221 | 223 | ||
222 | /* | 224 | /* |
diff --git a/kernel/lockdep.c b/kernel/lockdep.c index 28914a50991..0bb246e21cd 100644 --- a/kernel/lockdep.c +++ b/kernel/lockdep.c | |||
@@ -2708,13 +2708,15 @@ EXPORT_SYMBOL_GPL(lockdep_init_map); | |||
2708 | */ | 2708 | */ |
2709 | static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass, | 2709 | static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass, |
2710 | int trylock, int read, int check, int hardirqs_off, | 2710 | int trylock, int read, int check, int hardirqs_off, |
2711 | struct lockdep_map *nest_lock, unsigned long ip) | 2711 | struct lockdep_map *nest_lock, unsigned long ip, |
2712 | int references) | ||
2712 | { | 2713 | { |
2713 | struct task_struct *curr = current; | 2714 | struct task_struct *curr = current; |
2714 | struct lock_class *class = NULL; | 2715 | struct lock_class *class = NULL; |
2715 | struct held_lock *hlock; | 2716 | struct held_lock *hlock; |
2716 | unsigned int depth, id; | 2717 | unsigned int depth, id; |
2717 | int chain_head = 0; | 2718 | int chain_head = 0; |
2719 | int class_idx; | ||
2718 | u64 chain_key; | 2720 | u64 chain_key; |
2719 | 2721 | ||
2720 | if (!prove_locking) | 2722 | if (!prove_locking) |
@@ -2762,10 +2764,24 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass, | |||
2762 | if (DEBUG_LOCKS_WARN_ON(depth >= MAX_LOCK_DEPTH)) | 2764 | if (DEBUG_LOCKS_WARN_ON(depth >= MAX_LOCK_DEPTH)) |
2763 | return 0; | 2765 | return 0; |
2764 | 2766 | ||
2767 | class_idx = class - lock_classes + 1; | ||
2768 | |||
2769 | if (depth) { | ||
2770 | hlock = curr->held_locks + depth - 1; | ||
2771 | if (hlock->class_idx == class_idx && nest_lock) { | ||
2772 | if (hlock->references) | ||
2773 | hlock->references++; | ||
2774 | else | ||
2775 | hlock->references = 2; | ||
2776 | |||
2777 | return 1; | ||
2778 | } | ||
2779 | } | ||
2780 | |||
2765 | hlock = curr->held_locks + depth; | 2781 | hlock = curr->held_locks + depth; |
2766 | if (DEBUG_LOCKS_WARN_ON(!class)) | 2782 | if (DEBUG_LOCKS_WARN_ON(!class)) |
2767 | return 0; | 2783 | return 0; |
2768 | hlock->class_idx = class - lock_classes + 1; | 2784 | hlock->class_idx = class_idx; |
2769 | hlock->acquire_ip = ip; | 2785 | hlock->acquire_ip = ip; |
2770 | hlock->instance = lock; | 2786 | hlock->instance = lock; |
2771 | hlock->nest_lock = nest_lock; | 2787 | hlock->nest_lock = nest_lock; |
@@ -2773,6 +2789,7 @@ static int __lock_acquire(struct lockdep_map *lock, unsigned int subclass, | |||
2773 | hlock->read = read; | 2789 | hlock->read = read; |
2774 | hlock->check = check; | 2790 | hlock->check = check; |
2775 | hlock->hardirqs_off = !!hardirqs_off; | 2791 | hlock->hardirqs_off = !!hardirqs_off; |
2792 | hlock->references = references; | ||
2776 | #ifdef CONFIG_LOCK_STAT | 2793 | #ifdef CONFIG_LOCK_STAT |
2777 | hlock->waittime_stamp = 0; | 2794 | hlock->waittime_stamp = 0; |
2778 | hlock->holdtime_stamp = sched_clock(); | 2795 | hlock->holdtime_stamp = sched_clock(); |
@@ -2881,6 +2898,30 @@ static int check_unlock(struct task_struct *curr, struct lockdep_map *lock, | |||
2881 | return 1; | 2898 | return 1; |
2882 | } | 2899 | } |
2883 | 2900 | ||
2901 | static int match_held_lock(struct held_lock *hlock, struct lockdep_map *lock) | ||
2902 | { | ||
2903 | if (hlock->instance == lock) | ||
2904 | return 1; | ||
2905 | |||
2906 | if (hlock->references) { | ||
2907 | struct lock_class *class = lock->class_cache; | ||
2908 | |||
2909 | if (!class) | ||
2910 | class = look_up_lock_class(lock, 0); | ||
2911 | |||
2912 | if (DEBUG_LOCKS_WARN_ON(!class)) | ||
2913 | return 0; | ||
2914 | |||
2915 | if (DEBUG_LOCKS_WARN_ON(!hlock->nest_lock)) | ||
2916 | return 0; | ||
2917 | |||
2918 | if (hlock->class_idx == class - lock_classes + 1) | ||
2919 | return 1; | ||
2920 | } | ||
2921 | |||
2922 | return 0; | ||
2923 | } | ||
2924 | |||
2884 | static int | 2925 | static int |
2885 | __lock_set_class(struct lockdep_map *lock, const char *name, | 2926 | __lock_set_class(struct lockdep_map *lock, const char *name, |
2886 | struct lock_class_key *key, unsigned int subclass, | 2927 | struct lock_class_key *key, unsigned int subclass, |
@@ -2904,7 +2945,7 @@ __lock_set_class(struct lockdep_map *lock, const char *name, | |||
2904 | */ | 2945 | */ |
2905 | if (prev_hlock && prev_hlock->irq_context != hlock->irq_context) | 2946 | if (prev_hlock && prev_hlock->irq_context != hlock->irq_context) |
2906 | break; | 2947 | break; |
2907 | if (hlock->instance == lock) | 2948 | if (match_held_lock(hlock, lock)) |
2908 | goto found_it; | 2949 | goto found_it; |
2909 | prev_hlock = hlock; | 2950 | prev_hlock = hlock; |
2910 | } | 2951 | } |
@@ -2923,7 +2964,8 @@ found_it: | |||
2923 | if (!__lock_acquire(hlock->instance, | 2964 | if (!__lock_acquire(hlock->instance, |
2924 | hlock_class(hlock)->subclass, hlock->trylock, | 2965 | hlock_class(hlock)->subclass, hlock->trylock, |
2925 | hlock->read, hlock->check, hlock->hardirqs_off, | 2966 | hlock->read, hlock->check, hlock->hardirqs_off, |
2926 | hlock->nest_lock, hlock->acquire_ip)) | 2967 | hlock->nest_lock, hlock->acquire_ip, |
2968 | hlock->references)) | ||
2927 | return 0; | 2969 | return 0; |
2928 | } | 2970 | } |
2929 | 2971 | ||
@@ -2962,20 +3004,34 @@ lock_release_non_nested(struct task_struct *curr, | |||
2962 | */ | 3004 | */ |
2963 | if (prev_hlock && prev_hlock->irq_context != hlock->irq_context) | 3005 | if (prev_hlock && prev_hlock->irq_context != hlock->irq_context) |
2964 | break; | 3006 | break; |
2965 | if (hlock->instance == lock) | 3007 | if (match_held_lock(hlock, lock)) |
2966 | goto found_it; | 3008 | goto found_it; |
2967 | prev_hlock = hlock; | 3009 | prev_hlock = hlock; |
2968 | } | 3010 | } |
2969 | return print_unlock_inbalance_bug(curr, lock, ip); | 3011 | return print_unlock_inbalance_bug(curr, lock, ip); |
2970 | 3012 | ||
2971 | found_it: | 3013 | found_it: |
2972 | lock_release_holdtime(hlock); | 3014 | if (hlock->instance == lock) |
3015 | lock_release_holdtime(hlock); | ||
3016 | |||
3017 | if (hlock->references) { | ||
3018 | hlock->references--; | ||
3019 | if (hlock->references) { | ||
3020 | /* | ||
3021 | * We had, and after removing one, still have | ||
3022 | * references, the current lock stack is still | ||
3023 | * valid. We're done! | ||
3024 | */ | ||
3025 | return 1; | ||
3026 | } | ||
3027 | } | ||
2973 | 3028 | ||
2974 | /* | 3029 | /* |
2975 | * We have the right lock to unlock, 'hlock' points to it. | 3030 | * We have the right lock to unlock, 'hlock' points to it. |
2976 | * Now we remove it from the stack, and add back the other | 3031 | * Now we remove it from the stack, and add back the other |
2977 | * entries (if any), recalculating the hash along the way: | 3032 | * entries (if any), recalculating the hash along the way: |
2978 | */ | 3033 | */ |
3034 | |||
2979 | curr->lockdep_depth = i; | 3035 | curr->lockdep_depth = i; |
2980 | curr->curr_chain_key = hlock->prev_chain_key; | 3036 | curr->curr_chain_key = hlock->prev_chain_key; |
2981 | 3037 | ||
@@ -2984,7 +3040,8 @@ found_it: | |||
2984 | if (!__lock_acquire(hlock->instance, | 3040 | if (!__lock_acquire(hlock->instance, |
2985 | hlock_class(hlock)->subclass, hlock->trylock, | 3041 | hlock_class(hlock)->subclass, hlock->trylock, |
2986 | hlock->read, hlock->check, hlock->hardirqs_off, | 3042 | hlock->read, hlock->check, hlock->hardirqs_off, |
2987 | hlock->nest_lock, hlock->acquire_ip)) | 3043 | hlock->nest_lock, hlock->acquire_ip, |
3044 | hlock->references)) | ||
2988 | return 0; | 3045 | return 0; |
2989 | } | 3046 | } |
2990 | 3047 | ||
@@ -3014,7 +3071,7 @@ static int lock_release_nested(struct task_struct *curr, | |||
3014 | /* | 3071 | /* |
3015 | * Is the unlock non-nested: | 3072 | * Is the unlock non-nested: |
3016 | */ | 3073 | */ |
3017 | if (hlock->instance != lock) | 3074 | if (hlock->instance != lock || hlock->references) |
3018 | return lock_release_non_nested(curr, lock, ip); | 3075 | return lock_release_non_nested(curr, lock, ip); |
3019 | curr->lockdep_depth--; | 3076 | curr->lockdep_depth--; |
3020 | 3077 | ||
@@ -3065,7 +3122,9 @@ static int __lock_is_held(struct lockdep_map *lock) | |||
3065 | int i; | 3122 | int i; |
3066 | 3123 | ||
3067 | for (i = 0; i < curr->lockdep_depth; i++) { | 3124 | for (i = 0; i < curr->lockdep_depth; i++) { |
3068 | if (curr->held_locks[i].instance == lock) | 3125 | struct held_lock *hlock = curr->held_locks + i; |
3126 | |||
3127 | if (match_held_lock(hlock, lock)) | ||
3069 | return 1; | 3128 | return 1; |
3070 | } | 3129 | } |
3071 | 3130 | ||
@@ -3148,7 +3207,7 @@ void lock_acquire(struct lockdep_map *lock, unsigned int subclass, | |||
3148 | 3207 | ||
3149 | current->lockdep_recursion = 1; | 3208 | current->lockdep_recursion = 1; |
3150 | __lock_acquire(lock, subclass, trylock, read, check, | 3209 | __lock_acquire(lock, subclass, trylock, read, check, |
3151 | irqs_disabled_flags(flags), nest_lock, ip); | 3210 | irqs_disabled_flags(flags), nest_lock, ip, 0); |
3152 | current->lockdep_recursion = 0; | 3211 | current->lockdep_recursion = 0; |
3153 | raw_local_irq_restore(flags); | 3212 | raw_local_irq_restore(flags); |
3154 | } | 3213 | } |
@@ -3252,7 +3311,7 @@ __lock_contended(struct lockdep_map *lock, unsigned long ip) | |||
3252 | */ | 3311 | */ |
3253 | if (prev_hlock && prev_hlock->irq_context != hlock->irq_context) | 3312 | if (prev_hlock && prev_hlock->irq_context != hlock->irq_context) |
3254 | break; | 3313 | break; |
3255 | if (hlock->instance == lock) | 3314 | if (match_held_lock(hlock, lock)) |
3256 | goto found_it; | 3315 | goto found_it; |
3257 | prev_hlock = hlock; | 3316 | prev_hlock = hlock; |
3258 | } | 3317 | } |
@@ -3260,6 +3319,9 @@ __lock_contended(struct lockdep_map *lock, unsigned long ip) | |||
3260 | return; | 3319 | return; |
3261 | 3320 | ||
3262 | found_it: | 3321 | found_it: |
3322 | if (hlock->instance != lock) | ||
3323 | return; | ||
3324 | |||
3263 | hlock->waittime_stamp = sched_clock(); | 3325 | hlock->waittime_stamp = sched_clock(); |
3264 | 3326 | ||
3265 | contention_point = lock_point(hlock_class(hlock)->contention_point, ip); | 3327 | contention_point = lock_point(hlock_class(hlock)->contention_point, ip); |
@@ -3299,7 +3361,7 @@ __lock_acquired(struct lockdep_map *lock, unsigned long ip) | |||
3299 | */ | 3361 | */ |
3300 | if (prev_hlock && prev_hlock->irq_context != hlock->irq_context) | 3362 | if (prev_hlock && prev_hlock->irq_context != hlock->irq_context) |
3301 | break; | 3363 | break; |
3302 | if (hlock->instance == lock) | 3364 | if (match_held_lock(hlock, lock)) |
3303 | goto found_it; | 3365 | goto found_it; |
3304 | prev_hlock = hlock; | 3366 | prev_hlock = hlock; |
3305 | } | 3367 | } |
@@ -3307,6 +3369,9 @@ __lock_acquired(struct lockdep_map *lock, unsigned long ip) | |||
3307 | return; | 3369 | return; |
3308 | 3370 | ||
3309 | found_it: | 3371 | found_it: |
3372 | if (hlock->instance != lock) | ||
3373 | return; | ||
3374 | |||
3310 | cpu = smp_processor_id(); | 3375 | cpu = smp_processor_id(); |
3311 | if (hlock->waittime_stamp) { | 3376 | if (hlock->waittime_stamp) { |
3312 | now = sched_clock(); | 3377 | now = sched_clock(); |