Create rcutree plugins to handle hotplug CPU for multi-level trees.
PATCH 1/1 Create rcutree plugins to handle hotplug CPU for multi-level trees.
When offlining CPUs from a multi-level tree, there is the possibility of offlining the last CPU from a given node when there are preempted RCU read-side critical sections that started life on one of the CPUs on that node. In this case, the corresponding tasks will be enqueued via the task_struct's rcu_node_entry list_head onto one of the rcu_node's blocked_tasks[] lists. These tasks need to be moved somewhere else so that they will prevent the current grace period from ending. That somewhere is the root rcu_node.
---
include/linux/init_task.h | 2 - include/linux/sched.h | 4 +- kernel/rcutree.c | 2 + kernel/rcutree_plugin.h | 69 ++++++++++++++++++++++++++++++++++++++++++---- 4 files changed, 69 insertions(+), 8 deletions(-)
include/linux/init_task.h +1 -1
@@ -98,7 +98,7 @@ extern struct group_info init_groups;#define INIT_TASK_RCU_PREEMPT (tsk) \ .rcu_read_lock_nesting = 0, \ .rcu_read_unlock_special = 0, \ - .rcu_blocked_cpu = -1, \ + .rcu_blocked_node = NULL, \ .rcu_node_entry = LIST_HEAD_INIT(tsk.rcu_node_entry),#else #define INIT_TASK_RCU_PREEMPT (tsk)
include/linux/sched.h +2 -2
@@ -1208,7 +1208,7 @@ struct task_struct {#ifdef CONFIG_TREE_PREEMPT_RCU int rcu_read_lock_nesting;char rcu_read_unlock_special; -int rcu_blocked_cpu; +void *rcu_blocked_node;struct list_head rcu_node_entry;#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
@@ -1735,7 +1735,7 @@ static inline void rcu_copy_process(struct task_struct *p) { p->rcu_read_lock_nesting =0 ; p->rcu_read_unlock_special =0 ; - p->rcu_blocked_cpu =-1 ; + p->rcu_blocked_node =NULL ;INIT_LIST_HEAD (&p->rcu_node_entry); }
kernel/rcutree.c +2 -0
@@ -81,6 +81,7 @@ struct rcu_state rcu_bh_state = RCU_STATE_INITIALIZER(rcu_bh_state); DEFINE_PER_CPU(struct rcu_data, rcu_bh_data);extern long rcu_batches_completed_sched (void ); +static struct rcu_node *rcu_get_root (struct rcu_state *rsp);static void cpu_quiet_msk (unsigned long mask,struct rcu_state *rsp,struct rcu_node *rnp,unsigned long flags);static void cpu_quiet_msk_finish (struct rcu_state *rsp,unsigned long flags);
@@ -876,6 +877,7 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp)spin_unlock (&rnp->lock);/* irqs remain disabled. */ break ; } +rcu_preempt_offline_tasks (rsp, rnp); mask = rnp->grpmask;spin_unlock (&rnp->lock);/* irqs remain disabled. */ rnp = rnp->parent;
kernel/rcutree_plugin.h +64 -5
95 lines not on this page · raw message
[tip:core/rcu] rcu: Create rcutree plugins to handle hotplug CPU for multi-level trees
Commit-ID: dd5d19bafd90d33043a4a14b2e2d98612caa293c Gitweb: http://git.kernel.org/tip/dd5d19bafd90d33043a4a14b2e2d98612caa293c Author: Paul E. McKenney <[email protected]> AuthorDate: Thu, 27 Aug 2009 14:58:16 -0700 Committer: Ingo Molnar <[email protected]> CommitDate: Sat, 29 Aug 2009 15:34:39 +0200
rcu: Create rcutree plugins to handle hotplug CPU for multi-level trees
When offlining CPUs from a multi-level tree, there is the possibility of offlining the last CPU from a given node when there are preempted RCU read-side critical sections that started life on one of the CPUs on that node.
In this case, the corresponding tasks will be enqueued via the task_struct's rcu_node_entry list_head onto one of the rcu_node's blocked_tasks[] lists. These tasks need to be moved somewhere else so that they will prevent the current grace period from ending. That somewhere is the root rcu_node.
LKML-Reference: <[email protected]>
--- include/linux/init_task.h | 2 +- include/linux/sched.h | 4 +- kernel/rcutree.c | 2 + kernel/rcutree_plugin.h | 69 +++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 69 insertions(+), 8 deletions(-)
include/linux/init_task.h +1 -1
@@ -98,7 +98,7 @@ extern struct group_info init_groups;#define INIT_TASK_RCU_PREEMPT (tsk) \ .rcu_read_lock_nesting = 0, \ .rcu_read_unlock_special = 0, \ - .rcu_blocked_cpu = -1, \ + .rcu_blocked_node = NULL, \ .rcu_node_entry = LIST_HEAD_INIT(tsk.rcu_node_entry),#else #define INIT_TASK_RCU_PREEMPT (tsk)
include/linux/sched.h +2 -2
@@ -1208,7 +1208,7 @@ struct task_struct {#ifdef CONFIG_TREE_PREEMPT_RCU int rcu_read_lock_nesting;char rcu_read_unlock_special; -int rcu_blocked_cpu; +void *rcu_blocked_node;struct list_head rcu_node_entry;#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
@@ -1735,7 +1735,7 @@ static inline void rcu_copy_process(struct task_struct *p) { p->rcu_read_lock_nesting =0 ; p->rcu_read_unlock_special =0 ; - p->rcu_blocked_cpu =-1 ; + p->rcu_blocked_node =NULL ;INIT_LIST_HEAD (&p->rcu_node_entry); }
kernel/rcutree.c +2 -0
@@ -81,6 +81,7 @@ struct rcu_state rcu_bh_state = RCU_STATE_INITIALIZER(rcu_bh_state); DEFINE_PER_CPU(struct rcu_data, rcu_bh_data);extern long rcu_batches_completed_sched (void ); +static struct rcu_node *rcu_get_root (struct rcu_state *rsp);static void cpu_quiet_msk (unsigned long mask,struct rcu_state *rsp,struct rcu_node *rnp,unsigned long flags);static void cpu_quiet_msk_finish (struct rcu_state *rsp,unsigned long flags);
@@ -876,6 +877,7 @@ static void __rcu_offline_cpu(int cpu, struct rcu_state *rsp)spin_unlock (&rnp->lock);/* irqs remain disabled. */ break ; } +rcu_preempt_offline_tasks (rsp, rnp); mask = rnp->grpmask;spin_unlock (&rnp->lock);/* irqs remain disabled. */ rnp = rnp->parent;
kernel/rcutree_plugin.h +64 -5
95 lines not on this page · raw message