FAILED: patch "[PATCH] fs/proc: do_task_stat: use sig->stats_lock to gather the" failed to apply to 6.6-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 6.6-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-6.6.y
git checkout FETCH_HEAD
git cherry-pick -x 7601df8031fd67310af891897ef6cc0df4209305
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2024021918-unmanaged-rarity-ec6e@gregkh' --subject-prefix 'PATCH 6.6.y' HEAD^..
Possible dependencies:
7601df8031fd ("fs/proc: do_task_stat: use sig->stats_lock to gather the threads/children stats") 60f92acb60a9 ("fs/proc: do_task_stat: move thread_group_cputime_adjusted() outside of lock_task_sighand()") 7904e53ed5a2 ("fs/proc: do_task_stat: use __for_each_thread()")
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 7601df8031fd67310af891897ef6cc0df4209305 Mon Sep 17 00:00:00 2001
From: Oleg Nesterov <[email protected]>
Date: Tue, 23 Jan 2024 16:33:57 +0100
Subject: [PATCH] fs/proc: do_task_stat: use sig->stats_lock to gather the
threads/children stats
lock_task_sighand() can trigger a hard lockup. If NR_CPUS threads call do_task_stat() at the same time and the process has NR_THREADS, it will spin with irqs disabled O(NR_CPUS * NR_THREADS) time.
Change do_task_stat() to use sig->stats_lock to gather the statistics outside of ->siglock protected section, in the likely case this code will run lockless.
fs/proc/array.c +32 -26
@@ -477,13 +477,13 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,int permitted;struct mm_struct *mm;unsigned long long start_time; -unsigned long cmin_flt =0 , cmaj_flt =0 ; -unsigned long min_flt =0 , maj_flt =0 ; -u64 cutime, cstime, utime, stime; -u64 cgtime, gtime; +unsigned long cmin_flt, cmaj_flt, min_flt, maj_flt; +u64 cutime, cstime, cgtime, utime, stime, gtime;unsigned long rsslim =0 ;unsigned long flags;int exit_code = task->exit_code; +struct signal_struct *sig = task->signal; +unsigned int seq =1 ; state = *get_task_state (task); vsize = eip = esp =0 ;
@@ -511,12 +511,8 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,sigemptyset (&sigign);sigemptyset (&sigcatch); - cutime = cstime =0 ; - cgtime = gtime =0 ;if (lock_task_sighand (task, &flags)) { -struct signal_struct *sig = task->signal; -if (sig->tty) {struct pid *pgrp =tty_get_pgrp (sig->tty); tty_pgrp =pid_nr_ns (pgrp, ns);
@@ -527,27 +523,9 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns, num_threads =get_nr_threads (task);collect_sigign_sigcatch (task, &sigign, &sigcatch); - cmin_flt = sig->cmin_flt; - cmaj_flt = sig->cmaj_flt; - cutime = sig->cutime; - cstime = sig->cstime; - cgtime = sig->cgtime; rsslim =READ_ONCE (sig->rlim[RLIMIT_RSS ].rlim_cur); -/* add up live thread stats at the group level */ if (whole) { -struct task_struct *t; - -__for_each_thread (sig, t) { - min_flt += t->min_flt; - maj_flt += t->maj_flt; - gtime +=task_gtime (t); - } - - min_flt += sig->min_flt; - maj_flt += sig->maj_flt; - gtime += sig->gtime; -if (sig->flags & (SIGNAL_GROUP_EXIT |SIGNAL_STOP_STOPPED )) exit_code = sig->group_exit_code; }
@@ -562,6 +540,34 @@ static int do_task_stat(struct seq_file *m, struct pid_namespace *ns,if (permitted && (!whole || num_threads <2 )) wchan = !task_is_running (task); +do { + seq++;/* 2 on the 1st/lockless path, otherwise odd */ + flags =read_seqbegin_or_lock_irqsave (&sig->stats_lock, &seq); + + cmin_flt = sig->cmin_flt; + cmaj_flt = sig->cmaj_flt; + cutime = sig->cutime; + cstime = sig->cstime; + cgtime = sig->cgtime; + +if (whole) { +struct task_struct *t; + + min_flt = sig->min_flt; + maj_flt = sig->maj_flt; + gtime = sig->gtime; + +rcu_read_lock (); +__for_each_thread (sig, t) { + min_flt += t->min_flt; + maj_flt += t->maj_flt; + gtime +=task_gtime (t); + } +rcu_read_unlock (); + } + }while (need_seqretry (&sig->stats_lock, seq)); +done_seqretry_irqrestore (&sig->stats_lock, seq, flags); +if (whole) {thread_group_cputime_adjusted (task, &utime, &stime); }else {