summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul E. McKenney <paulmck@kernel.org>2021-07-28 11:32:28 -0700
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2023-09-02 09:17:08 +0200
commit69347c3340711f7c52c63a4245f83b3335485e60 (patch)
treecde38a4579a394285bc34741cc8a813d6be5ae47
parent8046fb611f707a3518831a0c186fbb67574970a0 (diff)
downloadlinux-stable-69347c3340711f7c52c63a4245f83b3335485e60.tar.gz
linux-stable-69347c3340711f7c52c63a4245f83b3335485e60.tar.bz2
linux-stable-69347c3340711f7c52c63a4245f83b3335485e60.zip
rcu-tasks: Add trc_inspect_reader() checks for exiting critical section
commit 18f08e758f34e6dfe0668bee51bd2af7adacf381 upstream. Currently, trc_inspect_reader() treats a task exiting its RCU Tasks Trace read-side critical section the same as being within that critical section. However, this can fail because that task might have already checked its .need_qs field, which means that it might never decrement the all-important trc_n_readers_need_end counter. Of course, for that to happen, the task would need to never again execute an RCU Tasks Trace read-side critical section, but this really could happen if the system's last trampoline was removed. Note that exit from such a critical section cannot be treated as a quiescent state due to the possibility of nested critical sections. This means that if trc_inspect_reader() sees a negative nesting value, it must set up to try again later. This commit therefore ignores tasks that are exiting their RCU Tasks Trace read-side critical sections so that they will be rechecked later. [ paulmck: Apply feedback from Neeraj Upadhyay and Boqun Feng. ] Signed-off-by: Paul E. McKenney <paulmck@kernel.org> Cc: Joel Fernandes <joel@joelfernandes.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--kernel/rcu/tasks.h18
1 files changed, 9 insertions, 9 deletions
diff --git a/kernel/rcu/tasks.h b/kernel/rcu/tasks.h
index 6b37216a08e4..28f628c70245 100644
--- a/kernel/rcu/tasks.h
+++ b/kernel/rcu/tasks.h
@@ -951,7 +951,7 @@ reset_ipi:
static bool trc_inspect_reader(struct task_struct *t, void *arg)
{
int cpu = task_cpu(t);
- bool in_qs = false;
+ int nesting;
bool ofl = cpu_is_offline(cpu);
if (task_curr(t)) {
@@ -971,18 +971,18 @@ static bool trc_inspect_reader(struct task_struct *t, void *arg)
n_heavy_reader_updates++;
if (ofl)
n_heavy_reader_ofl_updates++;
- in_qs = true;
+ nesting = 0;
} else {
// The task is not running, so C-language access is safe.
- in_qs = likely(!t->trc_reader_nesting);
+ nesting = t->trc_reader_nesting;
}
- // Mark as checked so that the grace-period kthread will
- // remove it from the holdout list.
- t->trc_reader_checked = true;
-
- if (in_qs)
- return true; // Already in quiescent state, done!!!
+ // If not exiting a read-side critical section, mark as checked
+ // so that the grace-period kthread will remove it from the
+ // holdout list.
+ t->trc_reader_checked = nesting >= 0;
+ if (nesting <= 0)
+ return !nesting; // If in QS, done, otherwise try again later.
// The task is in a read-side critical section, so set up its
// state so that it will awaken the grace-period kthread upon exit