diff options
| author | Oleg Nesterov <[email protected]> | 2024-01-23 16:33:55 +0100 | 
|---|---|---|
| committer | Andrew Morton <[email protected]> | 2024-02-07 21:20:33 -0800 | 
| commit | 60f92acb60a989b14e4b744501a0df0f82ef30a3 (patch) | |
| tree | fdec1eac862c098882aea8b09ae86a2ed8859023 /fs/proc/array.c | |
| parent | f7ec1cd5cc7ef3ad964b677ba82b8b77f1c93009 (diff) | |
fs/proc: do_task_stat: move thread_group_cputime_adjusted() outside of lock_task_sighand()
Patch series "fs/proc: do_task_stat: use sig->stats_".
do_task_stat() has the same problem as getrusage() had before "getrusage:
use sig->stats_lock rather than lock_task_sighand()": a hard lockup.  If
NR_CPUS threads call lock_task_sighand() at the same time and the process
has NR_THREADS, spin_lock_irq will spin with irqs disabled O(NR_CPUS *
NR_THREADS) time.
This patch (of 3):
thread_group_cputime() does its own locking, we can safely shift
thread_group_cputime_adjusted() which does another for_each_thread loop
outside of ->siglock protected section.
Not only this removes for_each_thread() from the critical section with
irqs disabled, this removes another case when stats_lock is taken with
siglock held.  We want to remove this dependency, then we can change the
users of stats_lock to not disable irqs.
Link: https://lkml.kernel.org/r/[email protected]
Link: https://lkml.kernel.org/r/[email protected]
Signed-off-by: Oleg Nesterov <[email protected]>
Signed-off-by: Dylan Hatch <[email protected]>
Cc: Eric W. Biederman <[email protected]>
Cc: <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Diffstat (limited to 'fs/proc/array.c')
| -rw-r--r-- | fs/proc/array.c | 10 | 
1 files changed, 6 insertions, 4 deletions
| diff --git a/fs/proc/array.c b/fs/proc/array.c index ff08a8957552..45ba91863808 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -511,7 +511,7 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,  	sigemptyset(&sigign);  	sigemptyset(&sigcatch); -	cutime = cstime = utime = stime = 0; +	cutime = cstime = 0;  	cgtime = gtime = 0;  	if (lock_task_sighand(task, &flags)) { @@ -546,7 +546,6 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,  			min_flt += sig->min_flt;  			maj_flt += sig->maj_flt; -			thread_group_cputime_adjusted(task, &utime, &stime);  			gtime += sig->gtime;  			if (sig->flags & (SIGNAL_GROUP_EXIT | SIGNAL_STOP_STOPPED)) @@ -562,10 +561,13 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,  	if (permitted && (!whole || num_threads < 2))  		wchan = !task_is_running(task); -	if (!whole) { + +	if (whole) { +		thread_group_cputime_adjusted(task, &utime, &stime); +	} else { +		task_cputime_adjusted(task, &utime, &stime);  		min_flt = task->min_flt;  		maj_flt = task->maj_flt; -		task_cputime_adjusted(task, &utime, &stime);  		gtime = task_gtime(task);  	} |