diff options
Diffstat (limited to 'kernel/rcutree.h')
| -rw-r--r-- | kernel/rcutree.h | 69 | 
1 files changed, 58 insertions, 11 deletions
diff --git a/kernel/rcutree.h b/kernel/rcutree.h index 1899023b096..d2a0046f63b 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -34,10 +34,11 @@   * In practice, this has not been tested, so there is probably some   * bug somewhere.   */ -#define MAX_RCU_LVLS 3 +#define MAX_RCU_LVLS 4  #define RCU_FANOUT	      (CONFIG_RCU_FANOUT)  #define RCU_FANOUT_SQ	      (RCU_FANOUT * RCU_FANOUT)  #define RCU_FANOUT_CUBE	      (RCU_FANOUT_SQ * RCU_FANOUT) +#define RCU_FANOUT_FOURTH     (RCU_FANOUT_CUBE * RCU_FANOUT)  #if NR_CPUS <= RCU_FANOUT  #  define NUM_RCU_LVLS	      1 @@ -45,23 +46,33 @@  #  define NUM_RCU_LVL_1	      (NR_CPUS)  #  define NUM_RCU_LVL_2	      0  #  define NUM_RCU_LVL_3	      0 +#  define NUM_RCU_LVL_4	      0  #elif NR_CPUS <= RCU_FANOUT_SQ  #  define NUM_RCU_LVLS	      2  #  define NUM_RCU_LVL_0	      1  #  define NUM_RCU_LVL_1	      DIV_ROUND_UP(NR_CPUS, RCU_FANOUT)  #  define NUM_RCU_LVL_2	      (NR_CPUS)  #  define NUM_RCU_LVL_3	      0 +#  define NUM_RCU_LVL_4	      0  #elif NR_CPUS <= RCU_FANOUT_CUBE  #  define NUM_RCU_LVLS	      3  #  define NUM_RCU_LVL_0	      1  #  define NUM_RCU_LVL_1	      DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_SQ)  #  define NUM_RCU_LVL_2	      DIV_ROUND_UP(NR_CPUS, RCU_FANOUT)  #  define NUM_RCU_LVL_3	      NR_CPUS +#  define NUM_RCU_LVL_4	      0 +#elif NR_CPUS <= RCU_FANOUT_FOURTH +#  define NUM_RCU_LVLS	      4 +#  define NUM_RCU_LVL_0	      1 +#  define NUM_RCU_LVL_1	      DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_CUBE) +#  define NUM_RCU_LVL_2	      DIV_ROUND_UP(NR_CPUS, RCU_FANOUT_SQ) +#  define NUM_RCU_LVL_3	      DIV_ROUND_UP(NR_CPUS, RCU_FANOUT) +#  define NUM_RCU_LVL_4	      NR_CPUS  #else  # error "CONFIG_RCU_FANOUT insufficient for NR_CPUS"  #endif /* #if (NR_CPUS) <= RCU_FANOUT */ -#define RCU_SUM (NUM_RCU_LVL_0 + NUM_RCU_LVL_1 + NUM_RCU_LVL_2 + NUM_RCU_LVL_3) +#define RCU_SUM (NUM_RCU_LVL_0 + NUM_RCU_LVL_1 + NUM_RCU_LVL_2 + NUM_RCU_LVL_3 + NUM_RCU_LVL_4)  #define NUM_RCU_NODES (RCU_SUM - NR_CPUS)  /* @@ -84,14 +95,21 @@ struct rcu_node {  	long	gpnum;		/* Current grace period for this node. */  				/*  This will either be equal to or one */  				/*  behind the root rcu_node's gpnum. */ +	long	completed;	/* Last grace period completed for this node. */ +				/*  This will either be equal to or one */ +				/*  behind the root rcu_node's gpnum. */  	unsigned long qsmask;	/* CPUs or groups that need to switch in */  				/*  order for current grace period to proceed.*/  				/*  In leaf rcu_node, each bit corresponds to */  				/*  an rcu_data structure, otherwise, each */  				/*  bit corresponds to a child rcu_node */  				/*  structure. */ +	unsigned long expmask;	/* Groups that have ->blocked_tasks[] */ +				/*  elements that need to drain to allow the */ +				/*  current expedited grace period to */ +				/*  complete (only for TREE_PREEMPT_RCU). */  	unsigned long qsmaskinit; -				/* Per-GP initialization for qsmask. */ +				/* Per-GP initial value for qsmask & expmask. */  	unsigned long grpmask;	/* Mask to apply to parent qsmask. */  				/*  Only one bit will be set in this mask. */  	int	grplo;		/* lowest-numbered CPU or group here. */ @@ -99,7 +117,7 @@ struct rcu_node {  	u8	grpnum;		/* CPU/group number for next level up. */  	u8	level;		/* root is at level 0. */  	struct rcu_node *parent; -	struct list_head blocked_tasks[2]; +	struct list_head blocked_tasks[4];  				/* Tasks blocked in RCU read-side critsect. */  				/*  Grace period number (->gpnum) x blocked */  				/*  by tasks on the (x & 0x1) element of the */ @@ -114,6 +132,21 @@ struct rcu_node {  	for ((rnp) = &(rsp)->node[0]; \  	     (rnp) < &(rsp)->node[NUM_RCU_NODES]; (rnp)++) +/* + * Do a breadth-first scan of the non-leaf rcu_node structures for the + * specified rcu_state structure.  Note that if there is a singleton + * rcu_node tree with but one rcu_node structure, this loop is a no-op. + */ +#define rcu_for_each_nonleaf_node_breadth_first(rsp, rnp) \ +	for ((rnp) = &(rsp)->node[0]; \ +	     (rnp) < (rsp)->level[NUM_RCU_LVLS - 1]; (rnp)++) + +/* + * Scan the leaves of the rcu_node hierarchy for the specified rcu_state + * structure.  Note that if there is a singleton rcu_node tree with but + * one rcu_node structure, this loop -will- visit the rcu_node structure. + * It is still a leaf node, even if it is also the root node. + */  #define rcu_for_each_leaf_node(rsp, rnp) \  	for ((rnp) = (rsp)->level[NUM_RCU_LVLS - 1]; \  	     (rnp) < &(rsp)->node[NUM_RCU_NODES]; (rnp)++) @@ -204,11 +237,12 @@ struct rcu_data {  #define RCU_GP_IDLE		0	/* No grace period in progress. */  #define RCU_GP_INIT		1	/* Grace period being initialized. */  #define RCU_SAVE_DYNTICK	2	/* Need to scan dyntick state. */ -#define RCU_FORCE_QS		3	/* Need to force quiescent state. */ +#define RCU_SAVE_COMPLETED	3	/* Need to save rsp->completed. */ +#define RCU_FORCE_QS		4	/* Need to force quiescent state. */  #ifdef CONFIG_NO_HZ  #define RCU_SIGNAL_INIT		RCU_SAVE_DYNTICK  #else /* #ifdef CONFIG_NO_HZ */ -#define RCU_SIGNAL_INIT		RCU_FORCE_QS +#define RCU_SIGNAL_INIT		RCU_SAVE_COMPLETED  #endif /* #else #ifdef CONFIG_NO_HZ */  #define RCU_JIFFIES_TILL_FORCE_QS	 3	/* for rsp->jiffies_force_qs */ @@ -246,7 +280,7 @@ struct rcu_state {  	long	gpnum;				/* Current gp number. */  	long	completed;			/* # of last completed gp. */ -	/* End  of fields guarded by root rcu_node's lock. */ +	/* End of fields guarded by root rcu_node's lock. */  	spinlock_t onofflock;			/* exclude on/offline and */  						/*  starting new GP.  Also */ @@ -260,6 +294,8 @@ struct rcu_state {  	long orphan_qlen;			/* Number of orphaned cbs. */  	spinlock_t fqslock;			/* Only one task forcing */  						/*  quiescent states. */ +	long	completed_fqs;			/* Value of completed @ snap. */ +						/*  Protected by fqslock. */  	unsigned long jiffies_force_qs;		/* Time at which to invoke */  						/*  force_quiescent_state(). */  	unsigned long n_force_qs;		/* Number of calls to */ @@ -274,11 +310,15 @@ struct rcu_state {  	unsigned long jiffies_stall;		/* Time at which to check */  						/*  for CPU stalls. */  #endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ -#ifdef CONFIG_NO_HZ -	long dynticks_completed;		/* Value of completed @ snap. */ -#endif /* #ifdef CONFIG_NO_HZ */  }; +/* 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. */ +  #ifdef RCU_TREE_NONCORE  /* @@ -298,10 +338,14 @@ DECLARE_PER_CPU(struct rcu_data, rcu_preempt_data);  #else /* #ifdef RCU_TREE_NONCORE */  /* Forward declarations for rcutree_plugin.h */ -static inline void rcu_bootup_announce(void); +static void rcu_bootup_announce(void);  long rcu_batches_completed(void);  static void rcu_preempt_note_context_switch(int cpu);  static int rcu_preempted_readers(struct rcu_node *rnp); +#ifdef CONFIG_HOTPLUG_CPU +static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp, +				      unsigned long flags); +#endif /* #ifdef CONFIG_HOTPLUG_CPU */  #ifdef CONFIG_RCU_CPU_STALL_DETECTOR  static void rcu_print_task_stall(struct rcu_node *rnp);  #endif /* #ifdef CONFIG_RCU_CPU_STALL_DETECTOR */ @@ -315,6 +359,9 @@ static void rcu_preempt_offline_cpu(int cpu);  static void rcu_preempt_check_callbacks(int cpu);  static void rcu_preempt_process_callbacks(void);  void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu)); +#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_TREE_PREEMPT_RCU) +static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp); +#endif /* #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_TREE_PREEMPT_RCU) */  static int rcu_preempt_pending(int cpu);  static int rcu_preempt_needs_cpu(int cpu);  static void __cpuinit rcu_preempt_init_percpu_data(int cpu);  |