Reduce latency impact of PREEMPT_RCU CPU offline
cover Reduce latency impact of PREEMPT_RCU CPU offline
Hello!
This series reduces worst-case CPU-hotplug latency for PREEMPT_RCU by avoiding an O(N) list move, where N is the number of threads that were preempted recently while in an RCU read-side critical section. This situation is rare, occurring only when the last CPU corresponding to a given rcu_node structure goes offline, for example, when CPUs 1-14 are all offline and CPU 15 goes offline. In this case, all the tasks that were recently preempted while running on one of CPUs 0-15 will be moved to the root rcu_node structure. Because this could be a very large number of tasks, and because this moving is carried out with interrupts disabled, a very large latency spike can result. This series therefore reworks RCU's CPU-hotplug code and grace-period computation to remove the need for moving tasks.
Because there was an obscure bug in the task-move process, this change also fixes that bug by annihilating the function containing it. This bug manifests only when RCU priority boosting is enabled, and even then occurs only roughly once per hundred hours or so of focused rcutorture testing. It was made somewhat more probable by a recent change to rcutorture that registers 60,000 RCU callbacks in three batches of 20,000 each, with one jiffy between each batch.
The individual commits in this series are as follows:
1. Fix a comment: softirqs are disabled, not interrupts.
2. Apply ACCESS_ONCE to rcu_boost().
3. Change rcu_read_unlock_special()'s "empty" variable's name to
"empty_norm" to make room for a new "empty" that will track the emptiness of the full list rather than just that part that is blocking the current normal (non-expedited) grace period.
4. Abstract rcu_cleanup_dead_rnp() from rcu_cleanup_dead_cpu().
The new rcu_cleanup_dead_rnp() function clears ->qsmaskinit bits up the rcu_node tree to allow for the last CPU in a given leaf rcu_node structure going offline. This function will be called from rcu_read_unlock_special() when the last blocked task exits its outermost RCU read-side critical section.
5. Make rcu_read_unlock_special() to propagate ->qsmaskinit bit
clearing up the rcu_node tree once the last task has exited its RCU read-side critical section.
6. Stop migrating the list of blocked tasks to the root rcu_node
structure.
7. Stop holding the irq-disabled ->orphan_lock across the
->qsmaskinit bit-clearing process, thus reducing the length of time that interrupts are disabled.
8. Make use of the new rcu_preempt_has_tasks() function.
9. Stop creating an rcub kthread for the root rcu_node structure,
which no longer has tasks in its ->blkd_tasks list (unless it is also the sole leaf rcu_node structure).
10. Drop the code from force_qs_rnp() that attempts to awaken the
now-nonexistent root rcu_node structure's rcub kthread.
Thanx, Paul
------------------------------------------------------------------------
b/kernel/rcu/tree.c | 103 ++++++++++++++++------------- b/kernel/rcu/tree.h | 13 --- b/kernel/rcu/tree_plugin.h | 159 +++++++++++---------------------------------- 3 files changed, 98 insertions(+), 177 deletions(-)
PATCH 4/10 rcu: Abstract rcu_cleanup_dead_rnp() from rcu_cleanup_dead_cpu()
In reply to Paul E. McKenneyFrom: "Paul E. McKenney" <[email protected]>
This commit abstracts rcu_cleanup_dead_rnp() from rcu_cleanup_dead_cpu() in preparation for the rework of RCU priority boosting. This new function will be invoked from rcu_read_unlock_special() in the reworked scheme, which is why rcu_cleanup_dead_rnp() assumes that the leaf rcu_node structure's ->qsmaskinit field has already been updated.
--- kernel/rcu/tree.c | 67 ++++++++++++++++++++++++++++++++++-------------- kernel/rcu/tree.h | 1 + kernel/rcu/tree_plugin.h | 17 ++++++++++++ 3 files changed, 66 insertions(+), 19 deletions(-)
kernel/rcu/tree.c +48 -19
@@ -2195,6 +2195,46 @@ static void rcu_cleanup_dying_cpu(struct rcu_state *rsp) }/* +* All CPUs for the specified rcu_node structure have gone offline, +* and all tasks that were preempted within an RCU read-side critical +* section while running on one of those CPUs have since exited their RCU +* read-side critical section. Some other CPU is reporting this fact with +* the specified rcu_node structure's ->lock held and interrupts disabled. +* This function therefore goes up the tree of rcu_node structures, +* clearing the corresponding bits in the ->qsmaskinit fields. Note that +* the leaf rcu_node structure's ->qsmaskinit field has already been +* updated +* +* This function does check that the specified rcu_node structure has +* all CPUs offline and no blocked tasks, so it is OK to invoke it +* prematurely. That said, invoking it after the fact will cost you +* a needless lock acquisition. So once it has done its work, don't +* invoke it again. +*/ +static void rcu_cleanup_dead_rnp (struct rcu_node *rnp_leaf) +{ +long mask; +struct rcu_node *rnp = rnp_leaf; + +if (rnp->qsmaskinit ||rcu_preempt_has_tasks (rnp)) +return ; +for (;;) { + mask = rnp->grpmask; + rnp = rnp->parent; +if (!rnp) +break ; +raw_spin_lock (&rnp->lock);/* irqs already disabled. */ +smp_mb__after_unlock_lock ();/* GP memory ordering. */ + rnp->qsmaskinit &= ~mask; +if (rnp->qsmaskinit) { +raw_spin_unlock (&rnp->lock);/* irqs remain disabled. */ +return ; + } +raw_spin_unlock (&rnp->lock);/* irqs remain disabled. */ + } +} + +/* * The CPU has been completely removed, and some other CPU is reporting * this fact from process context. Do the remainder of the cleanup, * including orphaning the outgoing CPU's RCU callbacks, and also
@@ -2204,7 +2244,6 @@ static void rcu_cleanup_dying_cpu(struct rcu_state *rsp)static void rcu_cleanup_dead_cpu (int cpu,struct rcu_state *rsp) {unsigned long flags; -unsigned long mask;int need_report =0 ;struct rcu_data *rdp =per_cpu_ptr (rsp->rda, cpu);struct rcu_node *rnp = rdp->mynode;/* Outgoing CPU's rdp & rnp. */
@@ -2220,24 +2259,14 @@ static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp)rcu_send_cbs_to_orphanage (cpu, rsp, rnp, rdp);rcu_adopt_orphan_cbs (rsp, flags); -/* Remove the outgoing CPU from the masks in the rcu_node hierarchy. */ - mask = rdp->grpmask;/* rnp->grplo is constant. */ -do { -raw_spin_lock (&rnp->lock);/* irqs already disabled. */ -smp_mb__after_unlock_lock (); - rnp->qsmaskinit &= ~mask; -if (rnp->qsmaskinit !=0 ) { -if (rnp != rdp->mynode) -raw_spin_unlock (&rnp->lock);/* irqs remain disabled. */ -break ; - } -if (rnp == rdp->mynode) - need_report =rcu_preempt_offline_tasks (rsp, rnp, rdp); -else -raw_spin_unlock (&rnp->lock);/* irqs remain disabled. */ - mask = rnp->grpmask; - rnp = rnp->parent; - }while (rnp !=NULL ); +/* Remove outgoing CPU from mask in the leaf rcu_node structure. */ +raw_spin_lock (&rnp->lock);/* irqs already disabled. */ +smp_mb__after_unlock_lock ();/* Enforce GP memory-order guarantee. */ + rnp->qsmaskinit &= ~rdp->grpmask; +if (rnp->qsmaskinit ==0 ) { + need_report =rcu_preempt_offline_tasks (rsp, rnp, rdp); +rcu_cleanup_dead_rnp (rnp); + }/* * We still hold the leaf rcu_node structure lock here, and
kernel/rcu/tree.h +1 -0
@@ -553,6 +553,7 @@ static int rcu_preempt_blocked_readers_cgp(struct rcu_node *rnp);static void rcu_report_unblock_qs_rnp (struct rcu_node *rnp,unsigned long flags);#endif /* #ifdef CONFIG_HOTPLUG_CPU */ +static bool rcu_preempt_has_tasks (struct rcu_node *rnp);static void rcu_print_detail_task_stall (struct rcu_state *rsp);static int rcu_print_task_stall (struct rcu_node *rnp);static void rcu_preempt_check_blocked_tasks (struct rcu_node *rnp);
kernel/rcu/tree_plugin.h +17 -0
@@ -307,6 +307,15 @@ static struct list_head *rcu_next_node_entry(struct task_struct *t, }/* +* Return true if the specified rcu_node structure has tasks that were +* preempted within an RCU read-side critical section. +*/ +static bool rcu_preempt_has_tasks (struct rcu_node *rnp) +{ +return !list_empty (&rnp->blkd_tasks); +} + +/* * Handle special cases during rcu_read_unlock(), such as needing to * notify RCU core processing or task having blocked during the RCU * read-side critical section.
@@ -970,6 +979,14 @@ static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp, unsigned long flags)#endif /* #ifdef CONFIG_HOTPLUG_CPU */ /* +* Because there is no preemptible RCU, there can be no readers blocked. +*/ +static bool rcu_preempt_has_tasks (struct rcu_node *rnp) +{ +return false; +} + +/* * Because preemptible RCU does not exist, we never have to check for * tasks blocked within RCU read-side critical sections. */
Signature · 1 line
1.8.1.5
PATCH 2/10 rcu: Protect rcu_boost() lockless accesses with ACCESS_ONCE()
In reply to Paul E. McKenneyFrom: "Paul E. McKenney" <[email protected]>
This commit prevents random compiler optimizations by applying ACCESS_ONCE() to lockless accesses.
--- kernel/rcu/tree_plugin.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/rcu/tree_plugin.h +2 -1
@@ -1127,7 +1127,8 @@ static int rcu_boost(struct rcu_node *rnp)struct task_struct *t;struct list_head *tb; -if (rnp->exp_tasks ==NULL && rnp->boost_tasks ==NULL ) +if (ACCESS_ONCE (rnp->exp_tasks) ==NULL && +ACCESS_ONCE (rnp->boost_tasks) ==NULL )return 0 ;/* Nothing left to boost. */ raw_spin_lock_irqsave (&rnp->lock, flags);
Signature · 1 line
1.8.1.5
PATCH 7/10 rcu: Shorten irq-disable region in rcu_cleanup_dead_cpu()
In reply to Paul E. McKenneyFrom: "Paul E. McKenney" <[email protected]>
Now that we are not migrating callbacks, there is no need to hold the ->orphan_lock across the the ->qsmaskinit bit-clearing process. This commit therefore releases ->orphan_lock immediately after adopting the orphaned RCU callbacks.
--- kernel/rcu/tree.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
kernel/rcu/tree.c +2 -2
@@ -2257,14 +2257,14 @@ static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp)/* Orphan the dead CPU's callbacks, and adopt them if appropriate. */ rcu_send_cbs_to_orphanage (cpu, rsp, rnp, rdp);rcu_adopt_orphan_cbs (rsp, flags); +raw_spin_unlock_irqrestore (&rsp->orphan_lock, flags);/* Remove outgoing CPU from mask in the leaf rcu_node structure. */ -raw_spin_lock (&rnp->lock);/* irqs already disabled. */ +raw_spin_lock_irqsave (&rnp->lock, flags);smp_mb__after_unlock_lock ();/* Enforce GP memory-order guarantee. */ rnp->qsmaskinit &= ~rdp->grpmask;if (rnp->qsmaskinit ==0 && !rcu_preempt_has_tasks (rnp))rcu_cleanup_dead_rnp (rnp); -raw_spin_unlock (&rsp->orphan_lock);/* irqs remain disabled. */ raw_spin_unlock_irqrestore (&rnp->lock, flags); WARN_ONCE(rdp->qlen != 0 || rdp->nxtlist != NULL, "rcu_cleanup_dead_cpu: Callbacks on offline CPU %d: qlen=%lu, nxtlist=%p\n",
Signature · 1 line
1.8.1.5
PATCH 8/10 rcu: Make use of rcu_preempt_has_tasks()
In reply to Paul E. McKenneyFrom: "Paul E. McKenney" <[email protected]>
Given that there is now arcu_preempt_has_tasks() function that checks to see if the ->blkd_tasks list is non-empty, this commit makes use of it.
--- kernel/rcu/tree_plugin.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
kernel/rcu/tree_plugin.h +3 -3
@@ -538,7 +538,7 @@ static int rcu_print_task_stall(struct rcu_node *rnp)static void rcu_preempt_check_blocked_tasks (struct rcu_node *rnp) {WARN_ON_ONCE (rcu_preempt_blocked_readers_cgp (rnp)); -if (!list_empty (&rnp->blkd_tasks)) +if (rcu_preempt_has_tasks (rnp)) rnp->gp_tasks = rnp->blkd_tasks.next;WARN_ON_ONCE (rnp->qsmask); }
@@ -704,7 +704,7 @@ sync_rcu_preempt_exp_init(struct rcu_state *rsp, struct rcu_node *rnp)raw_spin_lock_irqsave (&rnp->lock, flags);smp_mb__after_unlock_lock (); -if (list_empty (&rnp->blkd_tasks)) { +if (!rcu_preempt_has_tasks (rnp)) {raw_spin_unlock_irqrestore (&rnp->lock, flags); }else { rnp->exp_tasks = rnp->blkd_tasks.next;
@@ -1004,7 +1004,7 @@ void exit_rcu(void)static void rcu_initiate_boost_trace (struct rcu_node *rnp) { -if (list_empty (&rnp->blkd_tasks)) +if (!rcu_preempt_has_tasks (rnp)) rnp->n_balk_blkd_tasks++;else if (rnp->exp_tasks ==NULL && rnp->gp_tasks ==NULL ) rnp->n_balk_exp_gp_tasks++;
Signature · 1 line
1.8.1.5
PATCH 1/10 rcu: Fix invoke_rcu_callbacks() comment
In reply to Paul E. McKenneyFrom: "Paul E. McKenney" <[email protected]>
Despite what the comment says, it is only softirqs that are disabled, not interrupts. This commit therefore fixes the comment.
--- kernel/rcu/tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/rcu/tree.c +1 -1
@@ -2569,7 +2569,7 @@ static void rcu_process_callbacks(struct softirq_action *unused)* Schedule RCU callback invocation. If the specified type of RCU * does not support RCU priority boosting, just do a direct call, * otherwise wake up the per-CPU kernel kthread. Note that because we -* are running on the current CPU with interrupts disabled, the +* are running on the current CPU with softirqs disabled, the * rcu_cpu_kthread_task cannot disappear out from under us. */ static void invoke_rcu_callbacks (struct rcu_state *rsp,struct rcu_data *rdp)
Signature · 1 line
1.8.1.5
PATCH 6/10 rcu: Don't migrate blocked tasks even if all corresponding CPUs offline
From: "Paul E. McKenney" <[email protected]>
When the last CPU associated with a given leaf rcu_node structure goes offline, something must be done about the tasks queued on that rcu_node structure. Each of these tasks has been preempted on one of the leaf rcu_node structure's CPUs while in an RCU read-side critical section that it have not yet exited. Handling these tasks is the job of rcu_preempt_offline_tasks(), which migrates them from the leaf rcu_node structure to the root rcu_node structure.
Unfortunately, this migration has to be done one task at a time because each tasks allegiance must be shifted from the original leaf rcu_node to the root, so that future attempts to deal with these tasks will acquire the root rcu_node structure's ->lock rather than that of the leaf. Worse yet, this migration must be done with interrupts disabled, which is not so good for realtime response, especially given that there is no bound on the number of tasks on a given rcu_node structure's list. (OK, OK, there is a bound, it is just that it is unreasonably large, especially on 64-bit systems.) This was not considered a problem back when rcu_preempt_offline_tasks() was first written because realtime systems were assumed not to do CPU-hotplug operations while real-time applications were running. This assumption has proved of dubious validity given that people are starting to run multiple realtime applications on a single SMP system and that it is common practice to offline then online a CPU before starting its real-time application in order to clear extraneous processing off of that CPU. So we now need CPU hotplug operations to avoid undue latencies.
This commit therefore avoids migrating these tasks, instead letting them be dequeued one by one from the original leaf rcu_node structure by rcu_read_unlock_special(). This means that the clearing of bits from the upper-level rcu_node structures must be deferred until the last such task has been dequeued, because otherwise subsequent grace periods won't wait on them. This commit has the beneficial side effect of simplifying the CPU-hotplug code for TREE_PREEMPT_RCU, especially in CONFIG_RCU_BOOST builds.
--- kernel/rcu/tree.c | 20 +-------- kernel/rcu/tree.h | 12 ------ kernel/rcu/tree_plugin.h | 103 ----------------------------------------------- 3 files changed, 2 insertions(+), 133 deletions(-)
kernel/rcu/tree.c +2 -18
@@ -2244,7 +2244,6 @@ static void rcu_cleanup_dead_rnp(struct rcu_node *rnp_leaf)static void rcu_cleanup_dead_cpu (int cpu,struct rcu_state *rsp) {unsigned long flags; -int need_report =0 ;struct rcu_data *rdp =per_cpu_ptr (rsp->rda, cpu);struct rcu_node *rnp = rdp->mynode;/* Outgoing CPU's rdp & rnp. */
@@ -2263,25 +2262,10 @@ static void rcu_cleanup_dead_cpu(int cpu, struct rcu_state *rsp)raw_spin_lock (&rnp->lock);/* irqs already disabled. */ smp_mb__after_unlock_lock ();/* Enforce GP memory-order guarantee. */ rnp->qsmaskinit &= ~rdp->grpmask; -if (rnp->qsmaskinit ==0 ) { - need_report =rcu_preempt_offline_tasks (rsp, rnp, rdp); +if (rnp->qsmaskinit ==0 && !rcu_preempt_has_tasks (rnp))rcu_cleanup_dead_rnp (rnp); - } - -/* -* We still hold the leaf rcu_node structure lock here, and -* irqs are still disabled. The reason for this subterfuge is -* because invoking rcu_report_unblock_qs_rnp() with ->orphan_lock -* held leads to deadlock. -*/ raw_spin_unlock (&rsp->orphan_lock);/* irqs remain disabled. */ - rnp = rdp->mynode; -if (need_report &RCU_OFL_TASKS_NORM_GP ) -rcu_report_unblock_qs_rnp (rnp, flags); -else -raw_spin_unlock_irqrestore (&rnp->lock, flags); -if (need_report &RCU_OFL_TASKS_EXP_GP ) -rcu_report_exp_rnp (rsp, rnp, true); +raw_spin_unlock_irqrestore (&rnp->lock, flags);WARN_ONCE (rdp->qlen !=0 || rdp->nxtlist !=NULL ,"rcu_cleanup_dead_cpu: Callbacks on offline CPU %d: qlen=%lu, nxtlist=%p\n" , cpu, rdp->qlen, rdp->nxtlist);
kernel/rcu/tree.h +0 -12
@@ -514,13 +514,6 @@ extern struct list_head rcu_struct_flavors;#define for_each_rcu_flavor (rsp) \ list_for_each_entry((rsp), &rcu_struct_flavors, flavors) -/* Return values for rcu_preempt_offline_tasks(). */ - -#define RCU_OFL_TASKS_NORM_GP 0x1/* Tasks blocking normal */ -/* GP were moved to root. */ -#define RCU_OFL_TASKS_EXP_GP 0x2/* Tasks blocking expedited */ -/* GP were moved to root. */ -/* * RCU implementation internal declarations: */
@@ -557,11 +550,6 @@ static bool rcu_preempt_has_tasks(struct rcu_node *rnp);static void rcu_print_detail_task_stall (struct rcu_state *rsp);static int rcu_print_task_stall (struct rcu_node *rnp);static void rcu_preempt_check_blocked_tasks (struct rcu_node *rnp); -#ifdef CONFIG_HOTPLUG_CPU -static int rcu_preempt_offline_tasks (struct rcu_state *rsp, -struct rcu_node *rnp, -struct rcu_data *rdp); -#endif /* #ifdef CONFIG_HOTPLUG_CPU */ static void rcu_preempt_check_callbacks (void );void call_rcu (struct rcu_head *head,void (*func)(struct rcu_head *rcu));#if defined(CONFIG_HOTPLUG_CPU ) || defined(CONFIG_PREEMPT_RCU )
kernel/rcu/tree_plugin.h +0 -103
115 lines not on this page · raw message
Signature · 1 line
1.8.1.5
PATCH 9/10 rcu: Don't spawn rcub kthreads on root rcu_node structure
In reply to Paul E. McKenneyFrom: "Paul E. McKenney" <[email protected]>
Now that offlining CPUs no longer moves leaf rcu_node structures' ->blkd_tasks lists to the root, there is no way for the root rcu_node structure's ->blkd_task list to be nonempty, unless the root node is also the sole leaf node. This commit therefore refrains from creating an rcub kthread for the root rcu_node structure unless it is also the sole leaf.
--- kernel/rcu/tree_plugin.h | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-)
kernel/rcu/tree_plugin.h +2 -6
@@ -1371,12 +1371,8 @@ static void __init rcu_spawn_boost_kthreads(void)for_each_possible_cpu (cpu)per_cpu (rcu_cpu_has_work, cpu) =0 ;BUG_ON (smpboot_register_percpu_thread (&rcu_cpu_thread_spec)); - rnp =rcu_get_root (rcu_state_p); - (void )rcu_spawn_one_boost_kthread (rcu_state_p, rnp); -if (NUM_RCU_NODES >1 ) { -rcu_for_each_leaf_node (rcu_state_p, rnp) - (void )rcu_spawn_one_boost_kthread (rcu_state_p, rnp); - } +rcu_for_each_leaf_node (rcu_state_p, rnp) + (void )rcu_spawn_one_boost_kthread (rcu_state_p, rnp); }static void rcu_prepare_kthreads (int cpu)
Signature · 1 line
1.8.1.5
PATCH 3/10 rcu: Rename "empty" to "empty_norm" in preparation for boost rework
In reply to Paul E. McKenneyFrom: "Paul E. McKenney" <[email protected]>
This commit undertakes a simple variable renaming to make way for some rework of RCU priority boosting.
--- kernel/rcu/tree_plugin.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
kernel/rcu/tree_plugin.h +3 -3
@@ -313,8 +313,8 @@ static struct list_head *rcu_next_node_entry(struct task_struct *t,*/ void rcu_read_unlock_special (struct task_struct *t) { -int empty;int empty_exp; +int empty_norm;int empty_exp_now;unsigned long flags;struct list_head *np;
@@ -367,7 +367,7 @@ void rcu_read_unlock_special(struct task_struct *t)break ;raw_spin_unlock (&rnp->lock);/* irqs remain disabled. */ } - empty = !rcu_preempt_blocked_readers_cgp (rnp); + empty_norm = !rcu_preempt_blocked_readers_cgp (rnp); empty_exp = !rcu_preempted_readers_exp (rnp);smp_mb ();/* ensure expedited fastpath sees end of RCU c-s. */ np =rcu_next_node_entry (t, rnp);
@@ -393,7 +393,7 @@ void rcu_read_unlock_special(struct task_struct *t)* so we must take a snapshot of the expedited state. */ empty_exp_now = !rcu_preempted_readers_exp (rnp); -if (!empty && !rcu_preempt_blocked_readers_cgp (rnp)) { +if (!empty_norm && !rcu_preempt_blocked_readers_cgp (rnp)) { trace_rcu_quiescent_state_report(TPS("preempt_rcu"), rnp->gpnum, 0, rnp->qsmask,
Signature · 1 line
1.8.1.5
PATCH 5/10 rcu: Make rcu_read_unlock_special() propagate ->qsmaskinit bit clearing
In reply to Paul E. McKenneyFrom: "Paul E. McKenney" <[email protected]>
This commit causes rcu_read_unlock_special() to propagate ->qsmaskinit bit clearing up the rcu_node tree once a given rcu_node structure's blkd_tasks list becomes empty. This is the final commit in preparation for the rework of RCU priority boosting: It enables preempted tasks to remain queued on their rcu_node structure even after all of that rcu_node structure's CPUs have gone offline.
--- kernel/rcu/tree.c | 4 ++++ kernel/rcu/tree_plugin.h | 16 +++++++++++++--- 2 files changed, 17 insertions(+), 3 deletions(-)
kernel/rcu/tree.c +4 -0
@@ -2297,6 +2297,10 @@ static void rcu_cleanup_dying_cpu(struct rcu_state *rsp) { } +static void __maybe_unused rcu_cleanup_dead_rnp (struct rcu_node *rnp_leaf) +{ +} +static void rcu_cleanup_dead_cpu (int cpu,struct rcu_state *rsp) { }
kernel/rcu/tree_plugin.h +13 -3
@@ -322,9 +322,10 @@ static bool rcu_preempt_has_tasks(struct rcu_node *rnp)*/ void rcu_read_unlock_special (struct task_struct *t) { -int empty_exp; -int empty_norm; -int empty_exp_now; +bool empty; +bool empty_exp; +bool empty_norm; +bool empty_exp_now;unsigned long flags;struct list_head *np;#ifdef CONFIG_RCU_BOOST
@@ -376,6 +377,7 @@ void rcu_read_unlock_special(struct task_struct *t)break ;raw_spin_unlock (&rnp->lock);/* irqs remain disabled. */ } + empty = !rcu_preempt_has_tasks (rnp); empty_norm = !rcu_preempt_blocked_readers_cgp (rnp); empty_exp = !rcu_preempted_readers_exp (rnp);smp_mb ();/* ensure expedited fastpath sees end of RCU c-s. */
@@ -396,6 +398,14 @@ void rcu_read_unlock_special(struct task_struct *t)#endif /* #ifdef CONFIG_RCU_BOOST */ /* +* If this was the last task on the list, go see if we +* need to propagate ->qsmaskinit bit clearing up the +* rcu_node tree. +*/ +if (!empty && !rcu_preempt_has_tasks (rnp)) +rcu_cleanup_dead_rnp (rnp); + +/* * If this was the last task on the current list, and if * we aren't waiting on any CPUs, report the quiescent state. * Note that rcu_report_unblock_qs_rnp() releases rnp->lock,
Signature · 1 line
1.8.1.5
PATCH 10/10 rcu: Don't initiate RCU priority boosting on root rcu_node
In reply to Paul E. McKenneyFrom: "Paul E. McKenney" <[email protected]>
Because there is no longer any preempted tasks on the root rcu_node, and because there is no longer ever an rcub kthread for the root rcu_node, this commit drops the code in force_qs_rnp() that attempts to awaken the non-existent root rcub kthread. This is strictly a performance enhancement, removing a root rcu_node ->lock acquisition and release along with some tests in rcu_initiate_boost(), ending with the test that notes that there is no rcub kthread.
--- kernel/rcu/tree.c | 6 ------ 1 file changed, 6 deletions(-)
kernel/rcu/tree.c +0 -6
@@ -2481,12 +2481,6 @@ static void force_qs_rnp(struct rcu_state *rsp, }raw_spin_unlock_irqrestore (&rnp->lock, flags); } - rnp =rcu_get_root (rsp); -if (rnp->qsmask ==0 ) { -raw_spin_lock_irqsave (&rnp->lock, flags); -smp_mb__after_unlock_lock (); -rcu_initiate_boost (rnp, flags);/* releases rnp->lock. */ - } }/*
Signature · 1 line
1.8.1.5