* Q: lockdep_assert_held_read() after downgrade_write() @ 2017-01-30 21:25 J. R. Okajima 2017-01-30 21:30 ` Jens Axboe 0 siblings, 1 reply; 20+ messages in thread From: J. R. Okajima @ 2017-01-30 21:25 UTC (permalink / raw) To: peterz; +Cc: linux-kernel, axboe, darrick.wong, david Peter Zijlstra, May I ask you a question? v4.10-rc1 got a commit f831948 2016-11-30 locking/lockdep: Provide a type check for lock_is_held I've tested a little and lockdep splat a stack trace. { DECLARE_RWSEM(rw); static struct lock_class_key key; lockdep_set_class(&rw, &key); down_read(&rw); lockdep_assert_held_read(&rw); up_read(&rw); down_write(&rw); lockdep_assert_held_exclusive(&rw); up_write(&rw); downgrade_write(&rw); lockdep_assert_held_read(&rw); <-- here up_read(&rw); } I was expecting that lockdep_assert_held_read() splat nothing after downgrade_write(). Is this warning an intentional behaviour? Also the final up_read() gives me a warning too. It is produced at lockdep.c:3514:lock_release(): DEBUG_LOCKS_WARN_ON(depth <= 0) As an additional information, I increased some lockdep constants. Do you think this is related? include/linux/lockdep.h +#define MAX_LOCKDEP_SUBCLASSES (8UL + 4) +#define MAX_LOCKDEP_KEYS_BITS (13 + 3) kernel/locking/lockdep_internals.h +#define MAX_LOCKDEP_ENTRIES (32768UL << 5) +#define MAX_LOCKDEP_CHAINS_BITS (16 + 5) +#define MAX_STACK_TRACE_ENTRIES (524288UL << 5) J. R. Okajima ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Q: lockdep_assert_held_read() after downgrade_write() 2017-01-30 21:25 Q: lockdep_assert_held_read() after downgrade_write() J. R. Okajima @ 2017-01-30 21:30 ` Jens Axboe 2017-01-31 10:36 ` Peter Zijlstra 2017-01-31 15:40 ` J. R. Okajima 0 siblings, 2 replies; 20+ messages in thread From: Jens Axboe @ 2017-01-30 21:30 UTC (permalink / raw) To: J. R. Okajima, peterz; +Cc: linux-kernel, darrick.wong, david On 01/30/2017 02:25 PM, J. R. Okajima wrote: > Peter Zijlstra, > > May I ask you a question? > v4.10-rc1 got a commit > f831948 2016-11-30 locking/lockdep: Provide a type check for lock_is_held > I've tested a little and lockdep splat a stack trace. > > { > DECLARE_RWSEM(rw); > static struct lock_class_key key; > lockdep_set_class(&rw, &key); > > down_read(&rw); > lockdep_assert_held_read(&rw); > up_read(&rw); > > down_write(&rw); > lockdep_assert_held_exclusive(&rw); > up_write(&rw); > > downgrade_write(&rw); > lockdep_assert_held_read(&rw); <-- here > up_read(&rw); > } > > I was expecting that lockdep_assert_held_read() splat nothing after > downgrade_write(). Is this warning an intentional behaviour? > > Also the final up_read() gives me a warning too. It is produced at > lockdep.c:3514:lock_release(): DEBUG_LOCKS_WARN_ON(depth <= 0) I don't think you understand how it works. downgrade_write() turns a write lock into read held. To make that last sequence valid, you'd need: down_write(&rw); downgrade_write(&rw); lockdep_assert_held_read(&rw) up_read(&rw); or just not drop up_write() from the last section. -- Jens Axboe ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Q: lockdep_assert_held_read() after downgrade_write() 2017-01-30 21:30 ` Jens Axboe @ 2017-01-31 10:36 ` Peter Zijlstra 2017-01-31 11:25 ` Peter Zijlstra 2017-01-31 15:40 ` J. R. Okajima 1 sibling, 1 reply; 20+ messages in thread From: Peter Zijlstra @ 2017-01-31 10:36 UTC (permalink / raw) To: Jens Axboe; +Cc: J. R. Okajima, linux-kernel, darrick.wong, david On Mon, Jan 30, 2017 at 02:30:45PM -0700, Jens Axboe wrote: > On 01/30/2017 02:25 PM, J. R. Okajima wrote: > > Peter Zijlstra, > > > > May I ask you a question? > > v4.10-rc1 got a commit > > f831948 2016-11-30 locking/lockdep: Provide a type check for lock_is_held > > I've tested a little and lockdep splat a stack trace. > > > > { > > DECLARE_RWSEM(rw); > > static struct lock_class_key key; > > lockdep_set_class(&rw, &key); > > > > down_read(&rw); > > lockdep_assert_held_read(&rw); > > up_read(&rw); > > > > down_write(&rw); > > lockdep_assert_held_exclusive(&rw); > > up_write(&rw); > > > > downgrade_write(&rw); > > lockdep_assert_held_read(&rw); <-- here > > up_read(&rw); > > } > > > > I was expecting that lockdep_assert_held_read() splat nothing after > > downgrade_write(). Is this warning an intentional behaviour? > > > > Also the final up_read() gives me a warning too. It is produced at > > lockdep.c:3514:lock_release(): DEBUG_LOCKS_WARN_ON(depth <= 0) > > I don't think you understand how it works. downgrade_write() turns a write > lock into read held. To make that last sequence valid, you'd need: Correct, and I'm surprised that didn't explode in different ways. > > down_write(&rw); > downgrade_write(&rw); > lockdep_assert_held_read(&rw) > up_read(&rw); > > or just not drop up_write() from the last section. Right, but also, there seems to be a missing lockdep annotation to make that work. That is, downgrade_write() doesn't have a lockdep annotation, so it (lockdep) will still think its a write lock. Let me try and fix both issues. ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Q: lockdep_assert_held_read() after downgrade_write() 2017-01-31 10:36 ` Peter Zijlstra @ 2017-01-31 11:25 ` Peter Zijlstra 2017-01-31 14:23 ` Waiman Long 0 siblings, 1 reply; 20+ messages in thread From: Peter Zijlstra @ 2017-01-31 11:25 UTC (permalink / raw) To: Jens Axboe Cc: J. R. Okajima, linux-kernel, darrick.wong, david, longman, dave On Tue, Jan 31, 2017 at 11:36:20AM +0100, Peter Zijlstra wrote: > On Mon, Jan 30, 2017 at 02:30:45PM -0700, Jens Axboe wrote: > > I don't think you understand how it works. downgrade_write() turns a write > > lock into read held. To make that last sequence valid, you'd need: > > Correct, and I'm surprised that didn't explode in different ways. > > > > > down_write(&rw); > > downgrade_write(&rw); > > lockdep_assert_held_read(&rw) > > up_read(&rw); > > > > or just not drop up_write() from the last section. > > Right, but also, there seems to be a missing lockdep annotation to make > that work. That is, downgrade_write() doesn't have a lockdep annotation, > so it (lockdep) will still think its a write lock. > > > Let me try and fix both issues. Something like so I suppose,... completely untested. There could be a good reason for the current lockdep behaviour, but I cannot remember. --- diff --git a/kernel/locking/rwsem.c b/kernel/locking/rwsem.c index 45ba475d4be3..dfa9e40f83d5 100644 --- a/kernel/locking/rwsem.c +++ b/kernel/locking/rwsem.c @@ -123,10 +123,9 @@ EXPORT_SYMBOL(up_write); */ void downgrade_write(struct rw_semaphore *sem) { - /* - * lockdep: a downgraded write will live on as a write - * dependency. - */ + rwsem_release(&sem->dep_map, 1, _RET_IP_); + rwsem_acquire_read(&sem->dep_map, 0, 0, _RET_IP_); + rwsem_set_reader_owned(sem); __downgrade_write(sem); } diff --git a/kernel/locking/rwsem.h b/kernel/locking/rwsem.h index a699f4048ba1..3bd584c81b0b 100644 --- a/kernel/locking/rwsem.h +++ b/kernel/locking/rwsem.h @@ -40,8 +40,10 @@ static inline void rwsem_set_reader_owned(struct rw_semaphore *sem) * do a write to the rwsem cacheline when it is really necessary * to minimize cacheline contention. */ - if (sem->owner != RWSEM_READER_OWNED) + if (sem->owner != RWSEM_READER_OWNED) { + WARN_ON_ONCE(sem->owner != current); WRITE_ONCE(sem->owner, RWSEM_READER_OWNED); + } } static inline bool rwsem_owner_is_writer(struct task_struct *owner) ^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: Q: lockdep_assert_held_read() after downgrade_write() 2017-01-31 11:25 ` Peter Zijlstra @ 2017-01-31 14:23 ` Waiman Long 2017-01-31 14:26 ` Peter Zijlstra 0 siblings, 1 reply; 20+ messages in thread From: Waiman Long @ 2017-01-31 14:23 UTC (permalink / raw) To: Peter Zijlstra, Jens Axboe Cc: J. R. Okajima, linux-kernel, darrick.wong, david, dave On 01/31/2017 06:25 AM, Peter Zijlstra wrote: > On Tue, Jan 31, 2017 at 11:36:20AM +0100, Peter Zijlstra wrote: >> On Mon, Jan 30, 2017 at 02:30:45PM -0700, Jens Axboe wrote: >>> I don't think you understand how it works. downgrade_write() turns a write >>> lock into read held. To make that last sequence valid, you'd need: >> Correct, and I'm surprised that didn't explode in different ways. >> >>> down_write(&rw); >>> downgrade_write(&rw); >>> lockdep_assert_held_read(&rw) >>> up_read(&rw); >>> >>> or just not drop up_write() from the last section. >> Right, but also, there seems to be a missing lockdep annotation to make >> that work. That is, downgrade_write() doesn't have a lockdep annotation, >> so it (lockdep) will still think its a write lock. >> >> >> Let me try and fix both issues. > Something like so I suppose,... completely untested. > > There could be a good reason for the current lockdep behaviour, but I > cannot remember. > > --- > diff --git a/kernel/locking/rwsem.c b/kernel/locking/rwsem.c > index 45ba475d4be3..dfa9e40f83d5 100644 > --- a/kernel/locking/rwsem.c > +++ b/kernel/locking/rwsem.c > @@ -123,10 +123,9 @@ EXPORT_SYMBOL(up_write); > */ > void downgrade_write(struct rw_semaphore *sem) > { > - /* > - * lockdep: a downgraded write will live on as a write > - * dependency. > - */ > + rwsem_release(&sem->dep_map, 1, _RET_IP_); > + rwsem_acquire_read(&sem->dep_map, 0, 0, _RET_IP_); > + > rwsem_set_reader_owned(sem); > __downgrade_write(sem); > } > diff --git a/kernel/locking/rwsem.h b/kernel/locking/rwsem.h > index a699f4048ba1..3bd584c81b0b 100644 > --- a/kernel/locking/rwsem.h > +++ b/kernel/locking/rwsem.h > @@ -40,8 +40,10 @@ static inline void rwsem_set_reader_owned(struct rw_semaphore *sem) > * do a write to the rwsem cacheline when it is really necessary > * to minimize cacheline contention. > */ > - if (sem->owner != RWSEM_READER_OWNED) > + if (sem->owner != RWSEM_READER_OWNED) { > + WARN_ON_ONCE(sem->owner != current); > WRITE_ONCE(sem->owner, RWSEM_READER_OWNED); > + } > } > > static inline bool rwsem_owner_is_writer(struct task_struct *owner) I don't think you can do a WARN_ON_ONCE() check for sem->owner != current here. If the rwsem starts from an unlock state, sem->owner will be NULL and an incorrect warning message will be printed. Cheers, Longman ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Q: lockdep_assert_held_read() after downgrade_write() 2017-01-31 14:23 ` Waiman Long @ 2017-01-31 14:26 ` Peter Zijlstra 0 siblings, 0 replies; 20+ messages in thread From: Peter Zijlstra @ 2017-01-31 14:26 UTC (permalink / raw) To: Waiman Long Cc: Jens Axboe, J. R. Okajima, linux-kernel, darrick.wong, david, dave On Tue, Jan 31, 2017 at 09:23:08AM -0500, Waiman Long wrote: > On 01/31/2017 06:25 AM, Peter Zijlstra wrote: > > @@ -40,8 +40,10 @@ static inline void rwsem_set_reader_owned(struct rw_semaphore *sem) > > * do a write to the rwsem cacheline when it is really necessary > > * to minimize cacheline contention. > > */ > > - if (sem->owner != RWSEM_READER_OWNED) > > + if (sem->owner != RWSEM_READER_OWNED) { > > + WARN_ON_ONCE(sem->owner != current); > > WRITE_ONCE(sem->owner, RWSEM_READER_OWNED); > > + } > > } > > > > static inline bool rwsem_owner_is_writer(struct task_struct *owner) > > I don't think you can do a WARN_ON_ONCE() check for sem->owner != > current here. If the rwsem starts from an unlock state, sem->owner will > be NULL and an incorrect warning message will be printed. Argh, I only looked at the downgrade_write() user and forgot to look if it was used elsewhere. ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Q: lockdep_assert_held_read() after downgrade_write() 2017-01-30 21:30 ` Jens Axboe 2017-01-31 10:36 ` Peter Zijlstra @ 2017-01-31 15:40 ` J. R. Okajima 2017-01-31 16:32 ` Peter Zijlstra 1 sibling, 1 reply; 20+ messages in thread From: J. R. Okajima @ 2017-01-31 15:40 UTC (permalink / raw) To: Jens Axboe; +Cc: peterz, linux-kernel, darrick.wong, david Jens Axboe: > I don't think you understand how it works. downgrade_write() turns a write > lock into read held. To make that last sequence valid, you'd need: > > down_write(&rw); > downgrade_write(&rw); > lockdep_assert_held_read(&rw) > up_read(&rw); > > or just not drop up_write() from the last section. Arg... It is my bonehead mistake that I inserted up_write() before downgrade_write(). Sorry about that. Fortunately Peter Zijlstra reviewed downgrade_write() and sent a patch. Thank you, it passed my first test. Now allow me going on the second test (based upon Peter's patch) - two rwsem, rwA and rwB. - the locking order is rwA first, and then rwB. - good case down_read(rwA) down_read(rwB) up_read(rwB) up_read(rwA) down_write(rwA) down_write(rwB) up_write(rwB) up_write(rwA) - questionable case down_write(rwA) down_write(rwB) downgrade_write(rwA) downgrade_write(rwB) up_read(rwB) up_read(rwA) These two downgrade_write() have their strict order? If so, what is that? Do the added two lines + rwsem_release(&sem->dep_map, 1, _RET_IP_); + rwsem_acquire_read(&sem->dep_map, 0, 0, _RET_IP_); produce a traditional AB-BA deadlock warning, don't they? J. R. Okajima ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: Q: lockdep_assert_held_read() after downgrade_write() 2017-01-31 15:40 ` J. R. Okajima @ 2017-01-31 16:32 ` Peter Zijlstra 2017-02-02 16:33 ` J. R. Okajima 2017-02-02 16:38 ` [PATCH 1/3] lockdep: consolidate by new find_held_lock() J. R. Okajima 0 siblings, 2 replies; 20+ messages in thread From: Peter Zijlstra @ 2017-01-31 16:32 UTC (permalink / raw) To: J. R. Okajima; +Cc: Jens Axboe, linux-kernel, darrick.wong, david On Wed, Feb 01, 2017 at 12:40:03AM +0900, J. R. Okajima wrote: > Now allow me going on the second test (based upon Peter's patch) > > - two rwsem, rwA and rwB. > - the locking order is rwA first, and then rwB. > - good case > down_read(rwA) > down_read(rwB) > up_read(rwB) > up_read(rwA) > > down_write(rwA) > down_write(rwB) > up_write(rwB) > up_write(rwA) > > - questionable case > down_write(rwA) > down_write(rwB) > downgrade_write(rwA) > downgrade_write(rwB) > up_read(rwB) > up_read(rwA) > > These two downgrade_write() have their strict order? If so, what is > that? > Do the added two lines > + rwsem_release(&sem->dep_map, 1, _RET_IP_); > + rwsem_acquire_read(&sem->dep_map, 0, 0, _RET_IP_); > produce a traditional AB-BA deadlock warning, don't they? Blergh, yes, because we do a full release. Does something like the below work better? The annotation in downgrade_write() would look something like: + lock_downgrade(&sem->dep_map, 1, _RET_IP_); Not even compile tested and lacks the !LOCKDEP build bits. --- diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index 1e327bb..76cf149 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -361,6 +361,8 @@ static inline void lock_set_subclass(struct lockdep_map *lock, lock_set_class(lock, lock->name, lock->key, subclass, ip); } +extern void lock_downgrade(struct lockdep_map *lock, int read, unsigned long ip); + extern void lockdep_set_current_reclaim_state(gfp_t gfp_mask); extern void lockdep_clear_current_reclaim_state(void); extern void lockdep_trace_alloc(gfp_t mask); diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index 7c38f8f..88517b6 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -3488,6 +3488,63 @@ __lock_set_class(struct lockdep_map *lock, const char *name, return 1; } +static int __lock_downgrade(struct lockdep_map *lock, int read, unsigned long ip) +{ + struct task_struct *curr = current; + struct held_lock *hlock, *prev_hlock; + struct lock_class *class; + unsigned int depth; + int i; + + depth = curr->lockdep_depth; + /* + * This function is about (re)setting the class of a held lock, + * yet we're not actually holding any locks. Naughty user! + */ + if (DEBUG_LOCKS_WARN_ON(!depth)) + return 0; + + prev_hlock = NULL; + for (i = depth-1; i >= 0; i--) { + hlock = curr->held_locks + i; + /* + * We must not cross into another context: + */ + if (prev_hlock && prev_hlock->irq_context != hlock->irq_context) + break; + if (match_held_lock(hlock, lock)) + goto found_it; + prev_hlock = hlock; + } + return print_unlock_imbalance_bug(curr, lock, ip); + +found_it: + curr->lockdep_depth = i; + curr->curr_chain_key = hlock->prev_chain_key; + + WARN(hlock->read, "downgrading a read lock"); + hlock->read = read; + hlock->acquire_ip = ip; + + for (; i < depth; i++) { + hlock = curr->held_locks + i; + if (!__lock_acquire(hlock->instance, + hlock_class(hlock)->subclass, hlock->trylock, + hlock->read, hlock->check, hlock->hardirqs_off, + hlock->nest_lock, hlock->acquire_ip, + hlock->references, hlock->pin_count)) + return 0; + } + + /* + * I took it apart and put it back together again, except now I have + * these 'spare' parts.. where shall I put them. + */ + if (DEBUG_LOCKS_WARN_ON(curr->lockdep_depth != depth)) + return 0; + return 1; +} + /* * Remove the lock to the list of currently held locks - this gets * called on mutex_unlock()/spin_unlock*() (or on a failed @@ -3732,6 +3789,23 @@ void lock_set_class(struct lockdep_map *lock, const char *name, } EXPORT_SYMBOL_GPL(lock_set_class); +void lock_downgrade(struct lockdep_map *lock, int read, unsigned long ip) +{ + unsigned long flags; + + if (unlikely(current->lockdep_recursion)) + return; + + raw_local_irq_save(flags); + current->lockdep_recursion = 1; + check_flags(flags); + if (__lock_downgrade(lock, read, ip)) + check_chain_key(current); + current->lockdep_recursion = 0; + raw_local_irq_restore(flags); +} +EXPORT_SYMBOL_GPL(lock_downgrade); + /* * We are not always called with irqs disabled - do that here, * and also avoid lockdep recursion: ^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: Q: lockdep_assert_held_read() after downgrade_write() 2017-01-31 16:32 ` Peter Zijlstra @ 2017-02-02 16:33 ` J. R. Okajima 2017-02-02 16:38 ` [PATCH 1/3] lockdep: consolidate by new find_held_lock() J. R. Okajima 1 sibling, 0 replies; 20+ messages in thread From: J. R. Okajima @ 2017-02-02 16:33 UTC (permalink / raw) To: Peter Zijlstra; +Cc: Jens Axboe, linux-kernel, darrick.wong, david Peter Zijlstra: > Does something like the below work better? The annotation in > downgrade_write() would look something like: > > + lock_downgrade(&sem->dep_map, 1, _RET_IP_); > > Not even compile tested and lacks the !LOCKDEP build bits. Thanks for the patch. It seems working expectedly. I began writing a similar patch locally with minor consolidations by adding a new function or two. I will send a patch series. Please review and merge them into v4.10. If you don't like the patch, especially the new function name, feel free to change it. I don't know whether !LOCKDEP build bits are necessary or not. J. R. Okajima ^ permalink raw reply [flat|nested] 20+ messages in thread
* [PATCH 1/3] lockdep: consolidate by new find_held_lock() 2017-01-31 16:32 ` Peter Zijlstra 2017-02-02 16:33 ` J. R. Okajima @ 2017-02-02 16:38 ` J. R. Okajima 2017-02-02 16:38 ` [PATCH 2/3] lockdep: consolidate by new validate_held_lock() J. R. Okajima ` (2 more replies) 1 sibling, 3 replies; 20+ messages in thread From: J. R. Okajima @ 2017-02-02 16:38 UTC (permalink / raw) To: peterz; +Cc: linux-kernel A simple consolidataion. The behaviour should not change. Signed-off-by: J. R. Okajima <hooanon05g@gmail.com> --- kernel/locking/lockdep.c | 114 ++++++++++++++++++++++------------------------- 1 file changed, 54 insertions(+), 60 deletions(-) diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index 85d9222..b7a2001 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -3428,13 +3428,49 @@ static int match_held_lock(struct held_lock *hlock, struct lockdep_map *lock) return 0; } +/* @depth must not be zero */ +static struct held_lock *find_held_lock(struct task_struct *curr, + struct lockdep_map *lock, + unsigned int depth, int *idx) +{ + struct held_lock *ret, *hlock, *prev_hlock; + int i; + + i = depth - 1; + hlock = curr->held_locks + i; + ret = hlock; + if (match_held_lock(hlock, lock)) + goto out; + + ret = NULL; + for (i--, prev_hlock = hlock--; + i >= 0; + i--, prev_hlock = hlock--) { + /* + * We must not cross into another context: + */ + if (prev_hlock->irq_context != hlock->irq_context) { + ret = NULL; + break; + } + if (match_held_lock(hlock, lock)) { + ret = hlock; + break; + } + } + +out: + *idx = i; + return ret; +} + static int __lock_set_class(struct lockdep_map *lock, const char *name, struct lock_class_key *key, unsigned int subclass, unsigned long ip) { struct task_struct *curr = current; - struct held_lock *hlock, *prev_hlock; + struct held_lock *hlock; struct lock_class *class; unsigned int depth; int i; @@ -3447,21 +3483,10 @@ __lock_set_class(struct lockdep_map *lock, const char *name, if (DEBUG_LOCKS_WARN_ON(!depth)) return 0; - prev_hlock = NULL; - for (i = depth-1; i >= 0; i--) { - hlock = curr->held_locks + i; - /* - * We must not cross into another context: - */ - if (prev_hlock && prev_hlock->irq_context != hlock->irq_context) - break; - if (match_held_lock(hlock, lock)) - goto found_it; - prev_hlock = hlock; - } - return print_unlock_imbalance_bug(curr, lock, ip); + hlock = find_held_lock(curr, lock, depth, &i); + if (!hlock) + return print_unlock_imbalance_bug(curr, lock, ip); -found_it: lockdep_init_map(lock, name, key, 0); class = register_lock_class(lock, subclass, 0); hlock->class_idx = class - lock_classes + 1; @@ -3499,7 +3524,7 @@ static int __lock_release(struct lockdep_map *lock, int nested, unsigned long ip) { struct task_struct *curr = current; - struct held_lock *hlock, *prev_hlock; + struct held_lock *hlock; unsigned int depth; int i; @@ -3518,21 +3543,10 @@ __lock_release(struct lockdep_map *lock, int nested, unsigned long ip) * Check whether the lock exists in the current stack * of held locks: */ - prev_hlock = NULL; - for (i = depth-1; i >= 0; i--) { - hlock = curr->held_locks + i; - /* - * We must not cross into another context: - */ - if (prev_hlock && prev_hlock->irq_context != hlock->irq_context) - break; - if (match_held_lock(hlock, lock)) - goto found_it; - prev_hlock = hlock; - } - return print_unlock_imbalance_bug(curr, lock, ip); + hlock = find_held_lock(curr, lock, depth, &i); + if (!hlock) + return print_unlock_imbalance_bug(curr, lock, ip); -found_it: if (hlock->instance == lock) lock_release_holdtime(hlock); @@ -3894,7 +3908,7 @@ static void __lock_contended(struct lockdep_map *lock, unsigned long ip) { struct task_struct *curr = current; - struct held_lock *hlock, *prev_hlock; + struct held_lock *hlock; struct lock_class_stats *stats; unsigned int depth; int i, contention_point, contending_point; @@ -3907,22 +3921,12 @@ __lock_contended(struct lockdep_map *lock, unsigned long ip) if (DEBUG_LOCKS_WARN_ON(!depth)) return; - prev_hlock = NULL; - for (i = depth-1; i >= 0; i--) { - hlock = curr->held_locks + i; - /* - * We must not cross into another context: - */ - if (prev_hlock && prev_hlock->irq_context != hlock->irq_context) - break; - if (match_held_lock(hlock, lock)) - goto found_it; - prev_hlock = hlock; + hlock = find_held_lock(curr, lock, depth, &i); + if (!hlock) { + print_lock_contention_bug(curr, lock, ip); + return; } - print_lock_contention_bug(curr, lock, ip); - return; -found_it: if (hlock->instance != lock) return; @@ -3946,7 +3950,7 @@ static void __lock_acquired(struct lockdep_map *lock, unsigned long ip) { struct task_struct *curr = current; - struct held_lock *hlock, *prev_hlock; + struct held_lock *hlock; struct lock_class_stats *stats; unsigned int depth; u64 now, waittime = 0; @@ -3960,22 +3964,12 @@ __lock_acquired(struct lockdep_map *lock, unsigned long ip) if (DEBUG_LOCKS_WARN_ON(!depth)) return; - prev_hlock = NULL; - for (i = depth-1; i >= 0; i--) { - hlock = curr->held_locks + i; - /* - * We must not cross into another context: - */ - if (prev_hlock && prev_hlock->irq_context != hlock->irq_context) - break; - if (match_held_lock(hlock, lock)) - goto found_it; - prev_hlock = hlock; + hlock = find_held_lock(curr, lock, depth, &i); + if (!hlock) { + print_lock_contention_bug(curr, lock, _RET_IP_); + return; } - print_lock_contention_bug(curr, lock, _RET_IP_); - return; -found_it: if (hlock->instance != lock) return; -- 2.1.4 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 2/3] lockdep: consolidate by new validate_held_lock() 2017-02-02 16:38 ` [PATCH 1/3] lockdep: consolidate by new find_held_lock() J. R. Okajima @ 2017-02-02 16:38 ` J. R. Okajima 2017-02-14 12:09 ` Peter Zijlstra 2017-03-16 11:25 ` [tip:locking/core] locking/lockdep: Factor out the validate_held_lock() helper function tip-bot for J. R. Okajima 2017-02-02 16:38 ` [PATCH 3/3] lockdep: new annotation lock_downgrade() J. R. Okajima 2017-03-16 11:24 ` [tip:locking/core] locking/lockdep: Factor out the find_held_lock() helper function tip-bot for J. R. Okajima 2 siblings, 2 replies; 20+ messages in thread From: J. R. Okajima @ 2017-02-02 16:38 UTC (permalink / raw) To: peterz; +Cc: linux-kernel A simple consolidataion. The behaviour should not change. Signed-off-by: J. R. Okajima <hooanon05g@gmail.com> --- kernel/locking/lockdep.c | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index b7a2001..7dc8f8e 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -3464,6 +3464,23 @@ static struct held_lock *find_held_lock(struct task_struct *curr, return ret; } +static int validate_held_lock(struct task_struct *curr, unsigned int depth, + int idx) +{ + struct held_lock *hlock; + + for (hlock = curr->held_locks + idx; idx < depth; idx++, hlock++) + if (!__lock_acquire(hlock->instance, + hlock_class(hlock)->subclass, + hlock->trylock, + hlock->read, hlock->check, + hlock->hardirqs_off, + hlock->nest_lock, hlock->acquire_ip, + hlock->references, hlock->pin_count)) + return 1; + return 0; +} + static int __lock_set_class(struct lockdep_map *lock, const char *name, struct lock_class_key *key, unsigned int subclass, @@ -3494,15 +3511,8 @@ __lock_set_class(struct lockdep_map *lock, const char *name, curr->lockdep_depth = i; curr->curr_chain_key = hlock->prev_chain_key; - for (; i < depth; i++) { - hlock = curr->held_locks + i; - if (!__lock_acquire(hlock->instance, - hlock_class(hlock)->subclass, hlock->trylock, - hlock->read, hlock->check, hlock->hardirqs_off, - hlock->nest_lock, hlock->acquire_ip, - hlock->references, hlock->pin_count)) - return 0; - } + if (validate_held_lock(curr, depth, i)) + return 0; /* * I took it apart and put it back together again, except now I have @@ -3573,15 +3583,8 @@ __lock_release(struct lockdep_map *lock, int nested, unsigned long ip) curr->lockdep_depth = i; curr->curr_chain_key = hlock->prev_chain_key; - for (i++; i < depth; i++) { - hlock = curr->held_locks + i; - if (!__lock_acquire(hlock->instance, - hlock_class(hlock)->subclass, hlock->trylock, - hlock->read, hlock->check, hlock->hardirqs_off, - hlock->nest_lock, hlock->acquire_ip, - hlock->references, hlock->pin_count)) - return 0; - } + if (validate_held_lock(curr, depth, i + 1)) + return 0; /* * We had N bottles of beer on the wall, we drank one, but now -- 2.1.4 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH 2/3] lockdep: consolidate by new validate_held_lock() 2017-02-02 16:38 ` [PATCH 2/3] lockdep: consolidate by new validate_held_lock() J. R. Okajima @ 2017-02-14 12:09 ` Peter Zijlstra 2017-03-16 11:25 ` [tip:locking/core] locking/lockdep: Factor out the validate_held_lock() helper function tip-bot for J. R. Okajima 1 sibling, 0 replies; 20+ messages in thread From: Peter Zijlstra @ 2017-02-14 12:09 UTC (permalink / raw) To: J. R. Okajima; +Cc: linux-kernel On Fri, Feb 03, 2017 at 01:38:16AM +0900, J. R. Okajima wrote: > A simple consolidataion. The behaviour should not change. > > Signed-off-by: J. R. Okajima <hooanon05g@gmail.com> > --- > kernel/locking/lockdep.c | 39 +++++++++++++++++++++------------------ > 1 file changed, 21 insertions(+), 18 deletions(-) > > diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c > index b7a2001..7dc8f8e 100644 > --- a/kernel/locking/lockdep.c > +++ b/kernel/locking/lockdep.c > @@ -3464,6 +3464,23 @@ static struct held_lock *find_held_lock(struct task_struct *curr, > return ret; > } > > +static int validate_held_lock(struct task_struct *curr, unsigned int depth, > + int idx) > +{ > + struct held_lock *hlock; > + > + for (hlock = curr->held_locks + idx; idx < depth; idx++, hlock++) > + if (!__lock_acquire(hlock->instance, > + hlock_class(hlock)->subclass, > + hlock->trylock, > + hlock->read, hlock->check, > + hlock->hardirqs_off, > + hlock->nest_lock, hlock->acquire_ip, > + hlock->references, hlock->pin_count)) > + return 1; > + return 0; > +} I added the extra { } required by coding style and renamed the function to reacquire_held_locks(). Plural because it has the loop, and reacquire because that is what it does. Alternatively 'rebuild' is also possible if someone really doesn't like reacquire. ^ permalink raw reply [flat|nested] 20+ messages in thread
* [tip:locking/core] locking/lockdep: Factor out the validate_held_lock() helper function 2017-02-02 16:38 ` [PATCH 2/3] lockdep: consolidate by new validate_held_lock() J. R. Okajima 2017-02-14 12:09 ` Peter Zijlstra @ 2017-03-16 11:25 ` tip-bot for J. R. Okajima 1 sibling, 0 replies; 20+ messages in thread From: tip-bot for J. R. Okajima @ 2017-03-16 11:25 UTC (permalink / raw) To: linux-tip-commits Cc: peterz, akpm, hooanon05g, torvalds, tglx, paulmck, hpa, linux-kernel, mingo Commit-ID: e969970be033841d4c16b2e8ec8a3608347db861 Gitweb: http://git.kernel.org/tip/e969970be033841d4c16b2e8ec8a3608347db861 Author: J. R. Okajima <hooanon05g@gmail.com> AuthorDate: Fri, 3 Feb 2017 01:38:16 +0900 Committer: Ingo Molnar <mingo@kernel.org> CommitDate: Thu, 16 Mar 2017 09:57:07 +0100 locking/lockdep: Factor out the validate_held_lock() helper function Behaviour should not change. Signed-off-by: J. R. Okajima <hooanon05g@gmail.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/1486053497-9948-2-git-send-email-hooanon05g@gmail.com Signed-off-by: Ingo Molnar <mingo@kernel.org> --- kernel/locking/lockdep.c | 40 ++++++++++++++++++++++------------------ 1 file changed, 22 insertions(+), 18 deletions(-) diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index 0d28b82..da79548 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -3473,6 +3473,24 @@ out: return ret; } +static int reacquire_held_locks(struct task_struct *curr, unsigned int depth, + int idx) +{ + struct held_lock *hlock; + + for (hlock = curr->held_locks + idx; idx < depth; idx++, hlock++) { + if (!__lock_acquire(hlock->instance, + hlock_class(hlock)->subclass, + hlock->trylock, + hlock->read, hlock->check, + hlock->hardirqs_off, + hlock->nest_lock, hlock->acquire_ip, + hlock->references, hlock->pin_count)) + return 1; + } + return 0; +} + static int __lock_set_class(struct lockdep_map *lock, const char *name, struct lock_class_key *key, unsigned int subclass, @@ -3503,15 +3521,8 @@ __lock_set_class(struct lockdep_map *lock, const char *name, curr->lockdep_depth = i; curr->curr_chain_key = hlock->prev_chain_key; - for (; i < depth; i++) { - hlock = curr->held_locks + i; - if (!__lock_acquire(hlock->instance, - hlock_class(hlock)->subclass, hlock->trylock, - hlock->read, hlock->check, hlock->hardirqs_off, - hlock->nest_lock, hlock->acquire_ip, - hlock->references, hlock->pin_count)) - return 0; - } + if (reacquire_held_locks(curr, depth, i)) + return 0; /* * I took it apart and put it back together again, except now I have @@ -3582,15 +3593,8 @@ __lock_release(struct lockdep_map *lock, int nested, unsigned long ip) curr->lockdep_depth = i; curr->curr_chain_key = hlock->prev_chain_key; - for (i++; i < depth; i++) { - hlock = curr->held_locks + i; - if (!__lock_acquire(hlock->instance, - hlock_class(hlock)->subclass, hlock->trylock, - hlock->read, hlock->check, hlock->hardirqs_off, - hlock->nest_lock, hlock->acquire_ip, - hlock->references, hlock->pin_count)) - return 0; - } + if (reacquire_held_locks(curr, depth, i + 1)) + return 0; /* * We had N bottles of beer on the wall, we drank one, but now ^ permalink raw reply related [flat|nested] 20+ messages in thread
* [PATCH 3/3] lockdep: new annotation lock_downgrade() 2017-02-02 16:38 ` [PATCH 1/3] lockdep: consolidate by new find_held_lock() J. R. Okajima 2017-02-02 16:38 ` [PATCH 2/3] lockdep: consolidate by new validate_held_lock() J. R. Okajima @ 2017-02-02 16:38 ` J. R. Okajima 2017-02-02 17:59 ` kbuild test robot 2017-03-16 11:25 ` [tip:locking/core] locking/lockdep: Add new check to lock_downgrade() tip-bot for J. R. Okajima 2017-03-16 11:24 ` [tip:locking/core] locking/lockdep: Factor out the find_held_lock() helper function tip-bot for J. R. Okajima 2 siblings, 2 replies; 20+ messages in thread From: J. R. Okajima @ 2017-02-02 16:38 UTC (permalink / raw) To: peterz; +Cc: linux-kernel The commit f831948 2016-11-30 locking/lockdep: Provide a type check for lock_is_held didn't fully support rwsem. Here downgrade_write() supports the added type. Originally-written-by: Peter Zijlstra <peterz@infradead.org> See-also: http://marc.info/?l=linux-kernel&m=148581164003149&w=2 Signed-off-by: J. R. Okajima <hooanon05g@gmail.com> --- include/linux/lockdep.h | 2 ++ kernel/locking/lockdep.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ kernel/locking/rwsem.c | 6 ++---- 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index 0345cbf..22f304c 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -361,6 +361,8 @@ static inline void lock_set_subclass(struct lockdep_map *lock, lock_set_class(lock, lock->name, lock->key, subclass, ip); } +extern void lock_downgrade(struct lockdep_map *lock, unsigned long ip); + extern void lockdep_set_current_reclaim_state(gfp_t gfp_mask); extern void lockdep_clear_current_reclaim_state(void); extern void lockdep_trace_alloc(gfp_t mask); diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index 7dc8f8e..6a4a740 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -3523,6 +3523,44 @@ __lock_set_class(struct lockdep_map *lock, const char *name, return 1; } +static int __lock_downgrade(struct lockdep_map *lock, unsigned long ip) +{ + struct task_struct *curr = current; + struct held_lock *hlock; + unsigned int depth; + int i; + + depth = curr->lockdep_depth; + /* + * This function is about (re)setting the class of a held lock, + * yet we're not actually holding any locks. Naughty user! + */ + if (DEBUG_LOCKS_WARN_ON(!depth)) + return 0; + + hlock = find_held_lock(curr, lock, depth, &i); + if (!hlock) + return print_unlock_imbalance_bug(curr, lock, ip); + + curr->lockdep_depth = i; + curr->curr_chain_key = hlock->prev_chain_key; + + WARN(hlock->read, "downgrading a read lock"); + hlock->read = 1; + hlock->acquire_ip = ip; + + if (validate_held_lock(curr, depth, i)) + return 0; + + /* + * I took it apart and put it back together again, except now I have + * these 'spare' parts.. where shall I put them. + */ + if (DEBUG_LOCKS_WARN_ON(curr->lockdep_depth != depth)) + return 0; + return 1; +} + /* * Remove the lock to the list of currently held locks - this gets * called on mutex_unlock()/spin_unlock*() (or on a failed @@ -3749,6 +3787,23 @@ void lock_set_class(struct lockdep_map *lock, const char *name, } EXPORT_SYMBOL_GPL(lock_set_class); +void lock_downgrade(struct lockdep_map *lock, unsigned long ip) +{ + unsigned long flags; + + if (unlikely(current->lockdep_recursion)) + return; + + raw_local_irq_save(flags); + current->lockdep_recursion = 1; + check_flags(flags); + if (__lock_downgrade(lock, ip)) + check_chain_key(current); + current->lockdep_recursion = 0; + raw_local_irq_restore(flags); +} +EXPORT_SYMBOL_GPL(lock_downgrade); + /* * We are not always called with irqs disabled - do that here, * and also avoid lockdep recursion: diff --git a/kernel/locking/rwsem.c b/kernel/locking/rwsem.c index 45ba475..31db3ef 100644 --- a/kernel/locking/rwsem.c +++ b/kernel/locking/rwsem.c @@ -123,10 +123,8 @@ EXPORT_SYMBOL(up_write); */ void downgrade_write(struct rw_semaphore *sem) { - /* - * lockdep: a downgraded write will live on as a write - * dependency. - */ + lock_downgrade(&sem->dep_map, _RET_IP_); + rwsem_set_reader_owned(sem); __downgrade_write(sem); } -- 2.1.4 ^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH 3/3] lockdep: new annotation lock_downgrade() 2017-02-02 16:38 ` [PATCH 3/3] lockdep: new annotation lock_downgrade() J. R. Okajima @ 2017-02-02 17:59 ` kbuild test robot 2017-02-02 18:45 ` Peter Zijlstra 2017-03-16 11:25 ` [tip:locking/core] locking/lockdep: Add new check to lock_downgrade() tip-bot for J. R. Okajima 1 sibling, 1 reply; 20+ messages in thread From: kbuild test robot @ 2017-02-02 17:59 UTC (permalink / raw) To: J. R. Okajima; +Cc: kbuild-all, peterz, linux-kernel [-- Attachment #1: Type: text/plain, Size: 1508 bytes --] Hi Okajima, [auto build test ERROR on tip/locking/core] [also build test ERROR on v4.10-rc6 next-20170202] [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] url: https://github.com/0day-ci/linux/commits/J-R-Okajima/lockdep-consolidate-by-new-find_held_lock/20170203-010303 config: x86_64-randconfig-x018-201705 (attached as .config) compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901 reproduce: # save the attached .config to linux build tree make ARCH=x86_64 All errors (new ones prefixed by >>): kernel/locking/rwsem.c: In function 'downgrade_write': >> kernel/locking/rwsem.c:126:2: error: implicit declaration of function 'lock_downgrade' [-Werror=implicit-function-declaration] lock_downgrade(&sem->dep_map, _RET_IP_); ^~~~~~~~~~~~~~ >> kernel/locking/rwsem.c:126:21: error: 'struct rw_semaphore' has no member named 'dep_map' lock_downgrade(&sem->dep_map, _RET_IP_); ^~ cc1: some warnings being treated as errors vim +/lock_downgrade +126 kernel/locking/rwsem.c 120 121 /* 122 * downgrade write lock to read lock 123 */ 124 void downgrade_write(struct rw_semaphore *sem) 125 { > 126 lock_downgrade(&sem->dep_map, _RET_IP_); 127 128 rwsem_set_reader_owned(sem); 129 __downgrade_write(sem); --- 0-DAY kernel test infrastructure Open Source Technology Center https://lists.01.org/pipermail/kbuild-all Intel Corporation [-- Attachment #2: .config.gz --] [-- Type: application/gzip, Size: 22012 bytes --] ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 3/3] lockdep: new annotation lock_downgrade() 2017-02-02 17:59 ` kbuild test robot @ 2017-02-02 18:45 ` Peter Zijlstra 2017-02-02 21:05 ` J. R. Okajima 0 siblings, 1 reply; 20+ messages in thread From: Peter Zijlstra @ 2017-02-02 18:45 UTC (permalink / raw) To: kbuild test robot; +Cc: J. R. Okajima, kbuild-all, linux-kernel On Fri, Feb 03, 2017 at 01:59:37AM +0800, kbuild test robot wrote: > Hi Okajima, > > [auto build test ERROR on tip/locking/core] > [also build test ERROR on v4.10-rc6 next-20170202] > [if your patch is applied to the wrong git tree, please drop us a note to help improve the system] > > url: https://github.com/0day-ci/linux/commits/J-R-Okajima/lockdep-consolidate-by-new-find_held_lock/20170203-010303 > config: x86_64-randconfig-x018-201705 (attached as .config) > compiler: gcc-6 (Debian 6.2.0-3) 6.2.0 20160901 > reproduce: > # save the attached .config to linux build tree > make ARCH=x86_64 > > All errors (new ones prefixed by >>): > > kernel/locking/rwsem.c: In function 'downgrade_write': > >> kernel/locking/rwsem.c:126:2: error: implicit declaration of function 'lock_downgrade' [-Werror=implicit-function-declaration] > lock_downgrade(&sem->dep_map, _RET_IP_); > ^~~~~~~~~~~~~~ > >> kernel/locking/rwsem.c:126:21: error: 'struct rw_semaphore' has no member named 'dep_map' > lock_downgrade(&sem->dep_map, _RET_IP_); > ^~ > cc1: some warnings being treated as errors > > vim +/lock_downgrade +126 kernel/locking/rwsem.c > > 120 > 121 /* > 122 * downgrade write lock to read lock > 123 */ > 124 void downgrade_write(struct rw_semaphore *sem) > 125 { > > 126 lock_downgrade(&sem->dep_map, _RET_IP_); > 127 > 128 rwsem_set_reader_owned(sem); > 129 __downgrade_write(sem); This is what you need !LOCKDEP stubs for ;-) ^ permalink raw reply [flat|nested] 20+ messages in thread
* Re: [PATCH 3/3] lockdep: new annotation lock_downgrade() 2017-02-02 18:45 ` Peter Zijlstra @ 2017-02-02 21:05 ` J. R. Okajima 2017-02-14 12:11 ` Peter Zijlstra 0 siblings, 1 reply; 20+ messages in thread From: J. R. Okajima @ 2017-02-02 21:05 UTC (permalink / raw) To: Peter Zijlstra; +Cc: kbuild test robot, kbuild-all, linux-kernel Peter Zijlstra: > > >> kernel/locking/rwsem.c:126:2: error: implicit declaration of functi= on 'lock_downgrade' [-Werror=3Dimplicit-function-declaration] > > lock_downgrade(&sem->dep_map, _RET_IP_); > > ^~~~~~~~~~~~~~ ::: > This is what you need !LOCKDEP stubs for ;-) Ok, here is the update. Just one line added. J. R. Okajima commit 6874cbfb3c4f757efecbeb800bfd4db1050698f6 Author: J. R. Okajima <hooanon05g@gmail.com> Date: Thu Feb 2 23:41:38 2017 +0900 lockdep: new annotation lock_downgrade() = The commit f831948 2016-11-30 locking/lockdep: Provide a type check for lock_is_= held didn't fully support rwsem. Here downgrade_write() supports the added = type. = Originally-written-by: Peter Zijlstra <peterz@infradead.org> See-also: http://marc.info/?l=3Dlinux-kernel&m=3D148581164003149&w=3D2 Signed-off-by: J. R. Okajima <hooanon05g@gmail.com> diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index 0345cbf..ba75d06 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -361,6 +361,8 @@ static inline void lock_set_subclass(struct lockdep_ma= p *lock, lock_set_class(lock, lock->name, lock->key, subclass, ip); } = +extern void lock_downgrade(struct lockdep_map *lock, unsigned long ip); + extern void lockdep_set_current_reclaim_state(gfp_t gfp_mask); extern void lockdep_clear_current_reclaim_state(void); extern void lockdep_trace_alloc(gfp_t mask); @@ -413,6 +415,7 @@ static inline void lockdep_on(void) = # define lock_acquire(l, s, t, r, c, n, i) do { } while (0) # define lock_release(l, n, i) do { } while (0) +# define lock_downgrade(l, i) do { } while (0) # define lock_set_class(l, n, k, s, i) do { } while (0) # define lock_set_subclass(l, s, i) do { } while (0) # define lockdep_set_current_reclaim_state(g) do { } while (0) diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index 7dc8f8e..6a4a740 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -3523,6 +3523,44 @@ __lock_set_class(struct lockdep_map *lock, const ch= ar *name, return 1; } = +static int __lock_downgrade(struct lockdep_map *lock, unsigned long ip) +{ + struct task_struct *curr =3D current; + struct held_lock *hlock; + unsigned int depth; + int i; + + depth =3D curr->lockdep_depth; + /* + * This function is about (re)setting the class of a held lock, + * yet we're not actually holding any locks. Naughty user! + */ + if (DEBUG_LOCKS_WARN_ON(!depth)) + return 0; + + hlock =3D find_held_lock(curr, lock, depth, &i); + if (!hlock) + return print_unlock_imbalance_bug(curr, lock, ip); + + curr->lockdep_depth =3D i; + curr->curr_chain_key =3D hlock->prev_chain_key; + + WARN(hlock->read, "downgrading a read lock"); + hlock->read =3D 1; + hlock->acquire_ip =3D ip; + + if (validate_held_lock(curr, depth, i)) + return 0; + + /* + * I took it apart and put it back together again, except now I have + * these 'spare' parts.. where shall I put them. + */ + if (DEBUG_LOCKS_WARN_ON(curr->lockdep_depth !=3D depth)) + return 0; + return 1; +} + /* * Remove the lock to the list of currently held locks - this gets * called on mutex_unlock()/spin_unlock*() (or on a failed @@ -3749,6 +3787,23 @@ void lock_set_class(struct lockdep_map *lock, const= char *name, } EXPORT_SYMBOL_GPL(lock_set_class); = +void lock_downgrade(struct lockdep_map *lock, unsigned long ip) +{ + unsigned long flags; + + if (unlikely(current->lockdep_recursion)) + return; + + raw_local_irq_save(flags); + current->lockdep_recursion =3D 1; + check_flags(flags); + if (__lock_downgrade(lock, ip)) + check_chain_key(current); + current->lockdep_recursion =3D 0; + raw_local_irq_restore(flags); +} +EXPORT_SYMBOL_GPL(lock_downgrade); + /* * We are not always called with irqs disabled - do that here, * and also avoid lockdep recursion: diff --git a/kernel/locking/rwsem.c b/kernel/locking/rwsem.c index 45ba475..31db3ef 100644 --- a/kernel/locking/rwsem.c +++ b/kernel/locking/rwsem.c @@ -123,10 +123,8 @@ EXPORT_SYMBOL(up_write); */ void downgrade_write(struct rw_semaphore *sem) { - /* - * lockdep: a downgraded write will live on as a write - * dependency. - */ + lock_downgrade(&sem->dep_map, _RET_IP_); + rwsem_set_reader_owned(sem); __downgrade_write(sem); } ^ permalink raw reply related [flat|nested] 20+ messages in thread
* Re: [PATCH 3/3] lockdep: new annotation lock_downgrade() 2017-02-02 21:05 ` J. R. Okajima @ 2017-02-14 12:11 ` Peter Zijlstra 0 siblings, 0 replies; 20+ messages in thread From: Peter Zijlstra @ 2017-02-14 12:11 UTC (permalink / raw) To: J. R. Okajima; +Cc: kbuild test robot, kbuild-all, linux-kernel On Fri, Feb 03, 2017 at 06:05:31AM +0900, J. R. Okajima wrote: > Peter Zijlstra: > > > >> kernel/locking/rwsem.c:126:2: error: implicit declaration of functi= > on 'lock_downgrade' [-Werror=3Dimplicit-function-declaration] > > > lock_downgrade(&sem->dep_map, _RET_IP_); > > > ^~~~~~~~~~~~~~ > ::: > > This is what you need !LOCKDEP stubs for ;-) > > Ok, here is the update. > Just one line added. Thanks! (this version was white-space mangled but I took the old one and added the one line). ^ permalink raw reply [flat|nested] 20+ messages in thread
* [tip:locking/core] locking/lockdep: Add new check to lock_downgrade() 2017-02-02 16:38 ` [PATCH 3/3] lockdep: new annotation lock_downgrade() J. R. Okajima 2017-02-02 17:59 ` kbuild test robot @ 2017-03-16 11:25 ` tip-bot for J. R. Okajima 1 sibling, 0 replies; 20+ messages in thread From: tip-bot for J. R. Okajima @ 2017-03-16 11:25 UTC (permalink / raw) To: linux-tip-commits Cc: torvalds, akpm, tglx, paulmck, linux-kernel, hpa, mingo, hooanon05g, peterz Commit-ID: 6419c4af777a773a45a1b1af735de0fcd9a7dcc7 Gitweb: http://git.kernel.org/tip/6419c4af777a773a45a1b1af735de0fcd9a7dcc7 Author: J. R. Okajima <hooanon05g@gmail.com> AuthorDate: Fri, 3 Feb 2017 01:38:17 +0900 Committer: Ingo Molnar <mingo@kernel.org> CommitDate: Thu, 16 Mar 2017 09:57:07 +0100 locking/lockdep: Add new check to lock_downgrade() Commit: f8319483f57f ("locking/lockdep: Provide a type check for lock_is_held") didn't fully cover rwsems as downgrade_write() was left out. Introduce lock_downgrade() and use it to add new checks. See-also: http://marc.info/?l=linux-kernel&m=148581164003149&w=2 Originally-written-by: Peter Zijlstra <peterz@infradead.org> Signed-off-by: J. R. Okajima <hooanon05g@gmail.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/1486053497-9948-3-git-send-email-hooanon05g@gmail.com [ Rewrote the changelog. ] Signed-off-by: Ingo Molnar <mingo@kernel.org> --- include/linux/lockdep.h | 3 +++ kernel/locking/lockdep.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++ kernel/locking/rwsem.c | 6 ++---- 3 files changed, 60 insertions(+), 4 deletions(-) diff --git a/include/linux/lockdep.h b/include/linux/lockdep.h index 1e327bb..fffe49f 100644 --- a/include/linux/lockdep.h +++ b/include/linux/lockdep.h @@ -361,6 +361,8 @@ static inline void lock_set_subclass(struct lockdep_map *lock, lock_set_class(lock, lock->name, lock->key, subclass, ip); } +extern void lock_downgrade(struct lockdep_map *lock, unsigned long ip); + extern void lockdep_set_current_reclaim_state(gfp_t gfp_mask); extern void lockdep_clear_current_reclaim_state(void); extern void lockdep_trace_alloc(gfp_t mask); @@ -411,6 +413,7 @@ static inline void lockdep_on(void) # define lock_acquire(l, s, t, r, c, n, i) do { } while (0) # define lock_release(l, n, i) do { } while (0) +# define lock_downgrade(l, i) do { } while (0) # define lock_set_class(l, n, k, s, i) do { } while (0) # define lock_set_subclass(l, s, i) do { } while (0) # define lockdep_set_current_reclaim_state(g) do { } while (0) diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index da79548..b1a1cef 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -3533,6 +3533,44 @@ __lock_set_class(struct lockdep_map *lock, const char *name, return 1; } +static int __lock_downgrade(struct lockdep_map *lock, unsigned long ip) +{ + struct task_struct *curr = current; + struct held_lock *hlock; + unsigned int depth; + int i; + + depth = curr->lockdep_depth; + /* + * This function is about (re)setting the class of a held lock, + * yet we're not actually holding any locks. Naughty user! + */ + if (DEBUG_LOCKS_WARN_ON(!depth)) + return 0; + + hlock = find_held_lock(curr, lock, depth, &i); + if (!hlock) + return print_unlock_imbalance_bug(curr, lock, ip); + + curr->lockdep_depth = i; + curr->curr_chain_key = hlock->prev_chain_key; + + WARN(hlock->read, "downgrading a read lock"); + hlock->read = 1; + hlock->acquire_ip = ip; + + if (reacquire_held_locks(curr, depth, i)) + return 0; + + /* + * I took it apart and put it back together again, except now I have + * these 'spare' parts.. where shall I put them. + */ + if (DEBUG_LOCKS_WARN_ON(curr->lockdep_depth != depth)) + return 0; + return 1; +} + /* * Remove the lock to the list of currently held locks - this gets * called on mutex_unlock()/spin_unlock*() (or on a failed @@ -3759,6 +3797,23 @@ void lock_set_class(struct lockdep_map *lock, const char *name, } EXPORT_SYMBOL_GPL(lock_set_class); +void lock_downgrade(struct lockdep_map *lock, unsigned long ip) +{ + unsigned long flags; + + if (unlikely(current->lockdep_recursion)) + return; + + raw_local_irq_save(flags); + current->lockdep_recursion = 1; + check_flags(flags); + if (__lock_downgrade(lock, ip)) + check_chain_key(current); + current->lockdep_recursion = 0; + raw_local_irq_restore(flags); +} +EXPORT_SYMBOL_GPL(lock_downgrade); + /* * We are not always called with irqs disabled - do that here, * and also avoid lockdep recursion: diff --git a/kernel/locking/rwsem.c b/kernel/locking/rwsem.c index 90a74cc..4d48b1c 100644 --- a/kernel/locking/rwsem.c +++ b/kernel/locking/rwsem.c @@ -124,10 +124,8 @@ EXPORT_SYMBOL(up_write); */ void downgrade_write(struct rw_semaphore *sem) { - /* - * lockdep: a downgraded write will live on as a write - * dependency. - */ + lock_downgrade(&sem->dep_map, _RET_IP_); + rwsem_set_reader_owned(sem); __downgrade_write(sem); } ^ permalink raw reply related [flat|nested] 20+ messages in thread
* [tip:locking/core] locking/lockdep: Factor out the find_held_lock() helper function 2017-02-02 16:38 ` [PATCH 1/3] lockdep: consolidate by new find_held_lock() J. R. Okajima 2017-02-02 16:38 ` [PATCH 2/3] lockdep: consolidate by new validate_held_lock() J. R. Okajima 2017-02-02 16:38 ` [PATCH 3/3] lockdep: new annotation lock_downgrade() J. R. Okajima @ 2017-03-16 11:24 ` tip-bot for J. R. Okajima 2 siblings, 0 replies; 20+ messages in thread From: tip-bot for J. R. Okajima @ 2017-03-16 11:24 UTC (permalink / raw) To: linux-tip-commits Cc: hooanon05g, linux-kernel, mingo, torvalds, paulmck, peterz, akpm, hpa, tglx Commit-ID: 41c2c5b86a5e1a691ddacfc03b631b87a0b19043 Gitweb: http://git.kernel.org/tip/41c2c5b86a5e1a691ddacfc03b631b87a0b19043 Author: J. R. Okajima <hooanon05g@gmail.com> AuthorDate: Fri, 3 Feb 2017 01:38:15 +0900 Committer: Ingo Molnar <mingo@kernel.org> CommitDate: Thu, 16 Mar 2017 09:57:06 +0100 locking/lockdep: Factor out the find_held_lock() helper function A simple consolidataion to factor out repeated patterns. The behaviour should not change. Signed-off-by: J. R. Okajima <hooanon05g@gmail.com> Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Thomas Gleixner <tglx@linutronix.de> Link: http://lkml.kernel.org/r/1486053497-9948-1-git-send-email-hooanon05g@gmail.com Signed-off-by: Ingo Molnar <mingo@kernel.org> --- kernel/locking/lockdep.c | 114 ++++++++++++++++++++++------------------------- 1 file changed, 54 insertions(+), 60 deletions(-) diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c index a95e5d1..0d28b82 100644 --- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -3437,13 +3437,49 @@ static int match_held_lock(struct held_lock *hlock, struct lockdep_map *lock) return 0; } +/* @depth must not be zero */ +static struct held_lock *find_held_lock(struct task_struct *curr, + struct lockdep_map *lock, + unsigned int depth, int *idx) +{ + struct held_lock *ret, *hlock, *prev_hlock; + int i; + + i = depth - 1; + hlock = curr->held_locks + i; + ret = hlock; + if (match_held_lock(hlock, lock)) + goto out; + + ret = NULL; + for (i--, prev_hlock = hlock--; + i >= 0; + i--, prev_hlock = hlock--) { + /* + * We must not cross into another context: + */ + if (prev_hlock->irq_context != hlock->irq_context) { + ret = NULL; + break; + } + if (match_held_lock(hlock, lock)) { + ret = hlock; + break; + } + } + +out: + *idx = i; + return ret; +} + static int __lock_set_class(struct lockdep_map *lock, const char *name, struct lock_class_key *key, unsigned int subclass, unsigned long ip) { struct task_struct *curr = current; - struct held_lock *hlock, *prev_hlock; + struct held_lock *hlock; struct lock_class *class; unsigned int depth; int i; @@ -3456,21 +3492,10 @@ __lock_set_class(struct lockdep_map *lock, const char *name, if (DEBUG_LOCKS_WARN_ON(!depth)) return 0; - prev_hlock = NULL; - for (i = depth-1; i >= 0; i--) { - hlock = curr->held_locks + i; - /* - * We must not cross into another context: - */ - if (prev_hlock && prev_hlock->irq_context != hlock->irq_context) - break; - if (match_held_lock(hlock, lock)) - goto found_it; - prev_hlock = hlock; - } - return print_unlock_imbalance_bug(curr, lock, ip); + hlock = find_held_lock(curr, lock, depth, &i); + if (!hlock) + return print_unlock_imbalance_bug(curr, lock, ip); -found_it: lockdep_init_map(lock, name, key, 0); class = register_lock_class(lock, subclass, 0); hlock->class_idx = class - lock_classes + 1; @@ -3508,7 +3533,7 @@ static int __lock_release(struct lockdep_map *lock, int nested, unsigned long ip) { struct task_struct *curr = current; - struct held_lock *hlock, *prev_hlock; + struct held_lock *hlock; unsigned int depth; int i; @@ -3527,21 +3552,10 @@ __lock_release(struct lockdep_map *lock, int nested, unsigned long ip) * Check whether the lock exists in the current stack * of held locks: */ - prev_hlock = NULL; - for (i = depth-1; i >= 0; i--) { - hlock = curr->held_locks + i; - /* - * We must not cross into another context: - */ - if (prev_hlock && prev_hlock->irq_context != hlock->irq_context) - break; - if (match_held_lock(hlock, lock)) - goto found_it; - prev_hlock = hlock; - } - return print_unlock_imbalance_bug(curr, lock, ip); + hlock = find_held_lock(curr, lock, depth, &i); + if (!hlock) + return print_unlock_imbalance_bug(curr, lock, ip); -found_it: if (hlock->instance == lock) lock_release_holdtime(hlock); @@ -3903,7 +3917,7 @@ static void __lock_contended(struct lockdep_map *lock, unsigned long ip) { struct task_struct *curr = current; - struct held_lock *hlock, *prev_hlock; + struct held_lock *hlock; struct lock_class_stats *stats; unsigned int depth; int i, contention_point, contending_point; @@ -3916,22 +3930,12 @@ __lock_contended(struct lockdep_map *lock, unsigned long ip) if (DEBUG_LOCKS_WARN_ON(!depth)) return; - prev_hlock = NULL; - for (i = depth-1; i >= 0; i--) { - hlock = curr->held_locks + i; - /* - * We must not cross into another context: - */ - if (prev_hlock && prev_hlock->irq_context != hlock->irq_context) - break; - if (match_held_lock(hlock, lock)) - goto found_it; - prev_hlock = hlock; + hlock = find_held_lock(curr, lock, depth, &i); + if (!hlock) { + print_lock_contention_bug(curr, lock, ip); + return; } - print_lock_contention_bug(curr, lock, ip); - return; -found_it: if (hlock->instance != lock) return; @@ -3955,7 +3959,7 @@ static void __lock_acquired(struct lockdep_map *lock, unsigned long ip) { struct task_struct *curr = current; - struct held_lock *hlock, *prev_hlock; + struct held_lock *hlock; struct lock_class_stats *stats; unsigned int depth; u64 now, waittime = 0; @@ -3969,22 +3973,12 @@ __lock_acquired(struct lockdep_map *lock, unsigned long ip) if (DEBUG_LOCKS_WARN_ON(!depth)) return; - prev_hlock = NULL; - for (i = depth-1; i >= 0; i--) { - hlock = curr->held_locks + i; - /* - * We must not cross into another context: - */ - if (prev_hlock && prev_hlock->irq_context != hlock->irq_context) - break; - if (match_held_lock(hlock, lock)) - goto found_it; - prev_hlock = hlock; + hlock = find_held_lock(curr, lock, depth, &i); + if (!hlock) { + print_lock_contention_bug(curr, lock, _RET_IP_); + return; } - print_lock_contention_bug(curr, lock, _RET_IP_); - return; -found_it: if (hlock->instance != lock) return; ^ permalink raw reply related [flat|nested] 20+ messages in thread
end of thread, other threads:[~2017-03-16 11:26 UTC | newest] Thread overview: 20+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2017-01-30 21:25 Q: lockdep_assert_held_read() after downgrade_write() J. R. Okajima 2017-01-30 21:30 ` Jens Axboe 2017-01-31 10:36 ` Peter Zijlstra 2017-01-31 11:25 ` Peter Zijlstra 2017-01-31 14:23 ` Waiman Long 2017-01-31 14:26 ` Peter Zijlstra 2017-01-31 15:40 ` J. R. Okajima 2017-01-31 16:32 ` Peter Zijlstra 2017-02-02 16:33 ` J. R. Okajima 2017-02-02 16:38 ` [PATCH 1/3] lockdep: consolidate by new find_held_lock() J. R. Okajima 2017-02-02 16:38 ` [PATCH 2/3] lockdep: consolidate by new validate_held_lock() J. R. Okajima 2017-02-14 12:09 ` Peter Zijlstra 2017-03-16 11:25 ` [tip:locking/core] locking/lockdep: Factor out the validate_held_lock() helper function tip-bot for J. R. Okajima 2017-02-02 16:38 ` [PATCH 3/3] lockdep: new annotation lock_downgrade() J. R. Okajima 2017-02-02 17:59 ` kbuild test robot 2017-02-02 18:45 ` Peter Zijlstra 2017-02-02 21:05 ` J. R. Okajima 2017-02-14 12:11 ` Peter Zijlstra 2017-03-16 11:25 ` [tip:locking/core] locking/lockdep: Add new check to lock_downgrade() tip-bot for J. R. Okajima 2017-03-16 11:24 ` [tip:locking/core] locking/lockdep: Factor out the find_held_lock() helper function tip-bot for J. R. Okajima
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).