Message ID | 20190418084254.729689921@linutronix.de (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | stacktrace: Consolidate stack trace usage | expand |
On Thu, Apr 18, 2019 at 10:41:37AM +0200, Thomas Gleixner wrote: > There is only one caller of check_prev_add() which hands in a zeroed struct > stack trace and a function pointer to save_stack(). Inside check_prev_add() > the stack_trace struct is checked for being empty, which is always > true. Based on that one code path stores a stack trace which is unused. The > comment there does not make sense either. It's all leftovers from > historical lockdep code (cross release). I was more or less expecting a revert of: ce07a9415f26 ("locking/lockdep: Make check_prev_add() able to handle external stack_trace") And then I read the comment that went with the "static struct stack_trace trace" that got removed (in the above commit) and realized that your patch will consume more stack entries. The problem is when the held lock stack in check_prevs_add() has multple trylock entries on top, in that case we call check_prev_add() multiple times, and this patch will then save the exact same stack-trace multiple times, consuming static resources. Possibly we should copy what stackdepot does (but we cannot use it directly because stackdepot uses locks; but possible we can share bits), but that is a patch for another day I think. So while convoluted, perhaps we should retain this code for now.
On Wed, 24 Apr 2019, Peter Zijlstra wrote: > On Thu, Apr 18, 2019 at 10:41:37AM +0200, Thomas Gleixner wrote: > > There is only one caller of check_prev_add() which hands in a zeroed struct > > stack trace and a function pointer to save_stack(). Inside check_prev_add() > > the stack_trace struct is checked for being empty, which is always > > true. Based on that one code path stores a stack trace which is unused. The > > comment there does not make sense either. It's all leftovers from > > historical lockdep code (cross release). > > I was more or less expecting a revert of: > > ce07a9415f26 ("locking/lockdep: Make check_prev_add() able to handle external stack_trace") > > And then I read the comment that went with the "static struct > stack_trace trace" that got removed (in the above commit) and realized > that your patch will consume more stack entries. > > The problem is when the held lock stack in check_prevs_add() has multple > trylock entries on top, in that case we call check_prev_add() multiple > times, and this patch will then save the exact same stack-trace multiple > times, consuming static resources. > > Possibly we should copy what stackdepot does (but we cannot use it > directly because stackdepot uses locks; but possible we can share bits), > but that is a patch for another day I think. > > So while convoluted, perhaps we should retain this code for now. Uurg, what a mess.
--- a/kernel/locking/lockdep.c +++ b/kernel/locking/lockdep.c @@ -2158,10 +2158,10 @@ check_deadlock(struct task_struct *curr, */ static int check_prev_add(struct task_struct *curr, struct held_lock *prev, - struct held_lock *next, int distance, struct stack_trace *trace, - int (*save)(struct stack_trace *trace)) + struct held_lock *next, int distance) { struct lock_list *uninitialized_var(target_entry); + struct stack_trace trace; struct lock_list *entry; struct lock_list this; int ret; @@ -2196,17 +2196,8 @@ check_prev_add(struct task_struct *curr, this.class = hlock_class(next); this.parent = NULL; ret = check_noncircular(&this, hlock_class(prev), &target_entry); - if (unlikely(!ret)) { - if (!trace->entries) { - /* - * If @save fails here, the printing might trigger - * a WARN but because of the !nr_entries it should - * not do bad things. - */ - save(trace); - } + if (unlikely(!ret)) return print_circular_bug(&this, target_entry, next, prev); - } else if (unlikely(ret < 0)) return print_bfs_bug(ret); @@ -2253,7 +2244,7 @@ check_prev_add(struct task_struct *curr, return print_bfs_bug(ret); - if (!trace->entries && !save(trace)) + if (!save_trace(&trace)) return 0; /* @@ -2262,14 +2253,14 @@ check_prev_add(struct task_struct *curr, */ ret = add_lock_to_list(hlock_class(next), hlock_class(prev), &hlock_class(prev)->locks_after, - next->acquire_ip, distance, trace); + next->acquire_ip, distance, &trace); if (!ret) return 0; ret = add_lock_to_list(hlock_class(prev), hlock_class(next), &hlock_class(next)->locks_before, - next->acquire_ip, distance, trace); + next->acquire_ip, distance, &trace); if (!ret) return 0; @@ -2287,12 +2278,6 @@ check_prevs_add(struct task_struct *curr { int depth = curr->lockdep_depth; struct held_lock *hlock; - struct stack_trace trace = { - .nr_entries = 0, - .max_entries = 0, - .entries = NULL, - .skip = 0, - }; /* * Debugging checks. @@ -2318,7 +2303,8 @@ check_prevs_add(struct task_struct *curr * added: */ if (hlock->read != 2 && hlock->check) { - int ret = check_prev_add(curr, hlock, next, distance, &trace, save_trace); + int ret = check_prev_add(curr, hlock, next, distance); + if (!ret) return 0;
There is only one caller of check_prev_add() which hands in a zeroed struct stack trace and a function pointer to save_stack(). Inside check_prev_add() the stack_trace struct is checked for being empty, which is always true. Based on that one code path stores a stack trace which is unused. The comment there does not make sense either. It's all leftovers from historical lockdep code (cross release). Move the variable into check_prev_add() itself and cleanup the nonsensical checks and the pointless stack trace recording. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> --- kernel/locking/lockdep.c | 30 ++++++++---------------------- 1 file changed, 8 insertions(+), 22 deletions(-)