|
@@ -85,11 +85,21 @@ static void __init rcu_bootup_announce_oddness(void)
|
|
|
if (nr_cpu_ids != NR_CPUS)
|
|
|
printk(KERN_INFO "\tRCU restricting CPUs from NR_CPUS=%d to nr_cpu_ids=%d.\n", NR_CPUS, nr_cpu_ids);
|
|
|
#ifdef CONFIG_RCU_NOCB_CPU
|
|
|
+#ifndef CONFIG_RCU_NOCB_CPU_NONE
|
|
|
+ if (!have_rcu_nocb_mask) {
|
|
|
+ alloc_bootmem_cpumask_var(&rcu_nocb_mask);
|
|
|
+ have_rcu_nocb_mask = true;
|
|
|
+ }
|
|
|
+#ifdef CONFIG_RCU_NOCB_CPU_ZERO
|
|
|
+ pr_info("\tExperimental no-CBs CPU 0\n");
|
|
|
+ cpumask_set_cpu(0, rcu_nocb_mask);
|
|
|
+#endif /* #ifdef CONFIG_RCU_NOCB_CPU_ZERO */
|
|
|
+#ifdef CONFIG_RCU_NOCB_CPU_ALL
|
|
|
+ pr_info("\tExperimental no-CBs for all CPUs\n");
|
|
|
+ cpumask_setall(rcu_nocb_mask);
|
|
|
+#endif /* #ifdef CONFIG_RCU_NOCB_CPU_ALL */
|
|
|
+#endif /* #ifndef CONFIG_RCU_NOCB_CPU_NONE */
|
|
|
if (have_rcu_nocb_mask) {
|
|
|
- if (cpumask_test_cpu(0, rcu_nocb_mask)) {
|
|
|
- cpumask_clear_cpu(0, rcu_nocb_mask);
|
|
|
- pr_info("\tCPU 0: illegal no-CBs CPU (cleared).\n");
|
|
|
- }
|
|
|
cpulist_scnprintf(nocb_buf, sizeof(nocb_buf), rcu_nocb_mask);
|
|
|
pr_info("\tExperimental no-CBs CPUs: %s.\n", nocb_buf);
|
|
|
if (rcu_nocb_poll)
|
|
@@ -101,7 +111,7 @@ static void __init rcu_bootup_announce_oddness(void)
|
|
|
#ifdef CONFIG_TREE_PREEMPT_RCU
|
|
|
|
|
|
struct rcu_state rcu_preempt_state =
|
|
|
- RCU_STATE_INITIALIZER(rcu_preempt, call_rcu);
|
|
|
+ RCU_STATE_INITIALIZER(rcu_preempt, 'p', call_rcu);
|
|
|
DEFINE_PER_CPU(struct rcu_data, rcu_preempt_data);
|
|
|
static struct rcu_state *rcu_state = &rcu_preempt_state;
|
|
|
|
|
@@ -1533,14 +1543,7 @@ static void __cpuinit rcu_prepare_kthreads(int cpu)
|
|
|
int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
|
|
|
{
|
|
|
*delta_jiffies = ULONG_MAX;
|
|
|
- return rcu_cpu_has_callbacks(cpu);
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Because we do not have RCU_FAST_NO_HZ, don't bother initializing for it.
|
|
|
- */
|
|
|
-static void rcu_prepare_for_idle_init(int cpu)
|
|
|
-{
|
|
|
+ return rcu_cpu_has_callbacks(cpu, NULL);
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -1577,16 +1580,6 @@ static void rcu_idle_count_callbacks_posted(void)
|
|
|
*
|
|
|
* The following three proprocessor symbols control this state machine:
|
|
|
*
|
|
|
- * RCU_IDLE_FLUSHES gives the maximum number of times that we will attempt
|
|
|
- * to satisfy RCU. Beyond this point, it is better to incur a periodic
|
|
|
- * scheduling-clock interrupt than to loop through the state machine
|
|
|
- * at full power.
|
|
|
- * RCU_IDLE_OPT_FLUSHES gives the number of RCU_IDLE_FLUSHES that are
|
|
|
- * optional if RCU does not need anything immediately from this
|
|
|
- * CPU, even if this CPU still has RCU callbacks queued. The first
|
|
|
- * times through the state machine are mandatory: we need to give
|
|
|
- * the state machine a chance to communicate a quiescent state
|
|
|
- * to the RCU core.
|
|
|
* RCU_IDLE_GP_DELAY gives the number of jiffies that a CPU is permitted
|
|
|
* to sleep in dyntick-idle mode with RCU callbacks pending. This
|
|
|
* is sized to be roughly one RCU grace period. Those energy-efficiency
|
|
@@ -1602,186 +1595,108 @@ static void rcu_idle_count_callbacks_posted(void)
|
|
|
* adjustment, they can be converted into kernel config parameters, though
|
|
|
* making the state machine smarter might be a better option.
|
|
|
*/
|
|
|
-#define RCU_IDLE_FLUSHES 5 /* Number of dyntick-idle tries. */
|
|
|
-#define RCU_IDLE_OPT_FLUSHES 3 /* Optional dyntick-idle tries. */
|
|
|
#define RCU_IDLE_GP_DELAY 4 /* Roughly one grace period. */
|
|
|
#define RCU_IDLE_LAZY_GP_DELAY (6 * HZ) /* Roughly six seconds. */
|
|
|
|
|
|
-extern int tick_nohz_enabled;
|
|
|
-
|
|
|
-/*
|
|
|
- * Does the specified flavor of RCU have non-lazy callbacks pending on
|
|
|
- * the specified CPU? Both RCU flavor and CPU are specified by the
|
|
|
- * rcu_data structure.
|
|
|
- */
|
|
|
-static bool __rcu_cpu_has_nonlazy_callbacks(struct rcu_data *rdp)
|
|
|
-{
|
|
|
- return rdp->qlen != rdp->qlen_lazy;
|
|
|
-}
|
|
|
+static int rcu_idle_gp_delay = RCU_IDLE_GP_DELAY;
|
|
|
+module_param(rcu_idle_gp_delay, int, 0644);
|
|
|
+static int rcu_idle_lazy_gp_delay = RCU_IDLE_LAZY_GP_DELAY;
|
|
|
+module_param(rcu_idle_lazy_gp_delay, int, 0644);
|
|
|
|
|
|
-#ifdef CONFIG_TREE_PREEMPT_RCU
|
|
|
+extern int tick_nohz_enabled;
|
|
|
|
|
|
/*
|
|
|
- * Are there non-lazy RCU-preempt callbacks? (There cannot be if there
|
|
|
- * is no RCU-preempt in the kernel.)
|
|
|
+ * Try to advance callbacks for all flavors of RCU on the current CPU.
|
|
|
+ * Afterwards, if there are any callbacks ready for immediate invocation,
|
|
|
+ * return true.
|
|
|
*/
|
|
|
-static bool rcu_preempt_cpu_has_nonlazy_callbacks(int cpu)
|
|
|
+static bool rcu_try_advance_all_cbs(void)
|
|
|
{
|
|
|
- struct rcu_data *rdp = &per_cpu(rcu_preempt_data, cpu);
|
|
|
-
|
|
|
- return __rcu_cpu_has_nonlazy_callbacks(rdp);
|
|
|
-}
|
|
|
-
|
|
|
-#else /* #ifdef CONFIG_TREE_PREEMPT_RCU */
|
|
|
+ bool cbs_ready = false;
|
|
|
+ struct rcu_data *rdp;
|
|
|
+ struct rcu_node *rnp;
|
|
|
+ struct rcu_state *rsp;
|
|
|
|
|
|
-static bool rcu_preempt_cpu_has_nonlazy_callbacks(int cpu)
|
|
|
-{
|
|
|
- return 0;
|
|
|
-}
|
|
|
+ for_each_rcu_flavor(rsp) {
|
|
|
+ rdp = this_cpu_ptr(rsp->rda);
|
|
|
+ rnp = rdp->mynode;
|
|
|
|
|
|
-#endif /* else #ifdef CONFIG_TREE_PREEMPT_RCU */
|
|
|
+ /*
|
|
|
+ * Don't bother checking unless a grace period has
|
|
|
+ * completed since we last checked and there are
|
|
|
+ * callbacks not yet ready to invoke.
|
|
|
+ */
|
|
|
+ if (rdp->completed != rnp->completed &&
|
|
|
+ rdp->nxttail[RCU_DONE_TAIL] != rdp->nxttail[RCU_NEXT_TAIL])
|
|
|
+ rcu_process_gp_end(rsp, rdp);
|
|
|
|
|
|
-/*
|
|
|
- * Does any flavor of RCU have non-lazy callbacks on the specified CPU?
|
|
|
- */
|
|
|
-static bool rcu_cpu_has_nonlazy_callbacks(int cpu)
|
|
|
-{
|
|
|
- return __rcu_cpu_has_nonlazy_callbacks(&per_cpu(rcu_sched_data, cpu)) ||
|
|
|
- __rcu_cpu_has_nonlazy_callbacks(&per_cpu(rcu_bh_data, cpu)) ||
|
|
|
- rcu_preempt_cpu_has_nonlazy_callbacks(cpu);
|
|
|
+ if (cpu_has_callbacks_ready_to_invoke(rdp))
|
|
|
+ cbs_ready = true;
|
|
|
+ }
|
|
|
+ return cbs_ready;
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * Allow the CPU to enter dyntick-idle mode if either: (1) There are no
|
|
|
- * callbacks on this CPU, (2) this CPU has not yet attempted to enter
|
|
|
- * dyntick-idle mode, or (3) this CPU is in the process of attempting to
|
|
|
- * enter dyntick-idle mode. Otherwise, if we have recently tried and failed
|
|
|
- * to enter dyntick-idle mode, we refuse to try to enter it. After all,
|
|
|
- * it is better to incur scheduling-clock interrupts than to spin
|
|
|
- * continuously for the same time duration!
|
|
|
+ * Allow the CPU to enter dyntick-idle mode unless it has callbacks ready
|
|
|
+ * to invoke. If the CPU has callbacks, try to advance them. Tell the
|
|
|
+ * caller to set the timeout based on whether or not there are non-lazy
|
|
|
+ * callbacks.
|
|
|
*
|
|
|
- * The delta_jiffies argument is used to store the time when RCU is
|
|
|
- * going to need the CPU again if it still has callbacks. The reason
|
|
|
- * for this is that rcu_prepare_for_idle() might need to post a timer,
|
|
|
- * but if so, it will do so after tick_nohz_stop_sched_tick() has set
|
|
|
- * the wakeup time for this CPU. This means that RCU's timer can be
|
|
|
- * delayed until the wakeup time, which defeats the purpose of posting
|
|
|
- * a timer.
|
|
|
+ * The caller must have disabled interrupts.
|
|
|
*/
|
|
|
-int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
|
|
|
+int rcu_needs_cpu(int cpu, unsigned long *dj)
|
|
|
{
|
|
|
struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu);
|
|
|
|
|
|
- /* Flag a new idle sojourn to the idle-entry state machine. */
|
|
|
- rdtp->idle_first_pass = 1;
|
|
|
+ /* Snapshot to detect later posting of non-lazy callback. */
|
|
|
+ rdtp->nonlazy_posted_snap = rdtp->nonlazy_posted;
|
|
|
+
|
|
|
/* If no callbacks, RCU doesn't need the CPU. */
|
|
|
- if (!rcu_cpu_has_callbacks(cpu)) {
|
|
|
- *delta_jiffies = ULONG_MAX;
|
|
|
+ if (!rcu_cpu_has_callbacks(cpu, &rdtp->all_lazy)) {
|
|
|
+ *dj = ULONG_MAX;
|
|
|
return 0;
|
|
|
}
|
|
|
- if (rdtp->dyntick_holdoff == jiffies) {
|
|
|
- /* RCU recently tried and failed, so don't try again. */
|
|
|
- *delta_jiffies = 1;
|
|
|
+
|
|
|
+ /* Attempt to advance callbacks. */
|
|
|
+ if (rcu_try_advance_all_cbs()) {
|
|
|
+ /* Some ready to invoke, so initiate later invocation. */
|
|
|
+ invoke_rcu_core();
|
|
|
return 1;
|
|
|
}
|
|
|
- /* Set up for the possibility that RCU will post a timer. */
|
|
|
- if (rcu_cpu_has_nonlazy_callbacks(cpu)) {
|
|
|
- *delta_jiffies = round_up(RCU_IDLE_GP_DELAY + jiffies,
|
|
|
- RCU_IDLE_GP_DELAY) - jiffies;
|
|
|
+ rdtp->last_accelerate = jiffies;
|
|
|
+
|
|
|
+ /* Request timer delay depending on laziness, and round. */
|
|
|
+ if (rdtp->all_lazy) {
|
|
|
+ *dj = round_up(rcu_idle_gp_delay + jiffies,
|
|
|
+ rcu_idle_gp_delay) - jiffies;
|
|
|
} else {
|
|
|
- *delta_jiffies = jiffies + RCU_IDLE_LAZY_GP_DELAY;
|
|
|
- *delta_jiffies = round_jiffies(*delta_jiffies) - jiffies;
|
|
|
+ *dj = round_jiffies(rcu_idle_lazy_gp_delay + jiffies) - jiffies;
|
|
|
}
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * Handler for smp_call_function_single(). The only point of this
|
|
|
- * handler is to wake the CPU up, so the handler does only tracing.
|
|
|
- */
|
|
|
-void rcu_idle_demigrate(void *unused)
|
|
|
-{
|
|
|
- trace_rcu_prep_idle("Demigrate");
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Timer handler used to force CPU to start pushing its remaining RCU
|
|
|
- * callbacks in the case where it entered dyntick-idle mode with callbacks
|
|
|
- * pending. The hander doesn't really need to do anything because the
|
|
|
- * real work is done upon re-entry to idle, or by the next scheduling-clock
|
|
|
- * interrupt should idle not be re-entered.
|
|
|
- *
|
|
|
- * One special case: the timer gets migrated without awakening the CPU
|
|
|
- * on which the timer was scheduled on. In this case, we must wake up
|
|
|
- * that CPU. We do so with smp_call_function_single().
|
|
|
- */
|
|
|
-static void rcu_idle_gp_timer_func(unsigned long cpu_in)
|
|
|
-{
|
|
|
- int cpu = (int)cpu_in;
|
|
|
-
|
|
|
- trace_rcu_prep_idle("Timer");
|
|
|
- if (cpu != smp_processor_id())
|
|
|
- smp_call_function_single(cpu, rcu_idle_demigrate, NULL, 0);
|
|
|
- else
|
|
|
- WARN_ON_ONCE(1); /* Getting here can hang the system... */
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Initialize the timer used to pull CPUs out of dyntick-idle mode.
|
|
|
- */
|
|
|
-static void rcu_prepare_for_idle_init(int cpu)
|
|
|
-{
|
|
|
- struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu);
|
|
|
-
|
|
|
- rdtp->dyntick_holdoff = jiffies - 1;
|
|
|
- setup_timer(&rdtp->idle_gp_timer, rcu_idle_gp_timer_func, cpu);
|
|
|
- rdtp->idle_gp_timer_expires = jiffies - 1;
|
|
|
- rdtp->idle_first_pass = 1;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Clean up for exit from idle. Because we are exiting from idle, there
|
|
|
- * is no longer any point to ->idle_gp_timer, so cancel it. This will
|
|
|
- * do nothing if this timer is not active, so just cancel it unconditionally.
|
|
|
- */
|
|
|
-static void rcu_cleanup_after_idle(int cpu)
|
|
|
-{
|
|
|
- struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu);
|
|
|
-
|
|
|
- del_timer(&rdtp->idle_gp_timer);
|
|
|
- trace_rcu_prep_idle("Cleanup after idle");
|
|
|
- rdtp->tick_nohz_enabled_snap = ACCESS_ONCE(tick_nohz_enabled);
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Check to see if any RCU-related work can be done by the current CPU,
|
|
|
- * and if so, schedule a softirq to get it done. This function is part
|
|
|
- * of the RCU implementation; it is -not- an exported member of the RCU API.
|
|
|
- *
|
|
|
- * The idea is for the current CPU to clear out all work required by the
|
|
|
- * RCU core for the current grace period, so that this CPU can be permitted
|
|
|
- * to enter dyntick-idle mode. In some cases, it will need to be awakened
|
|
|
- * at the end of the grace period by whatever CPU ends the grace period.
|
|
|
- * This allows CPUs to go dyntick-idle more quickly, and to reduce the
|
|
|
- * number of wakeups by a modest integer factor.
|
|
|
- *
|
|
|
- * Because it is not legal to invoke rcu_process_callbacks() with irqs
|
|
|
- * disabled, we do one pass of force_quiescent_state(), then do a
|
|
|
- * invoke_rcu_core() to cause rcu_process_callbacks() to be invoked
|
|
|
- * later. The ->dyntick_drain field controls the sequencing.
|
|
|
+ * Prepare a CPU for idle from an RCU perspective. The first major task
|
|
|
+ * is to sense whether nohz mode has been enabled or disabled via sysfs.
|
|
|
+ * The second major task is to check to see if a non-lazy callback has
|
|
|
+ * arrived at a CPU that previously had only lazy callbacks. The third
|
|
|
+ * major task is to accelerate (that is, assign grace-period numbers to)
|
|
|
+ * any recently arrived callbacks.
|
|
|
*
|
|
|
* The caller must have disabled interrupts.
|
|
|
*/
|
|
|
static void rcu_prepare_for_idle(int cpu)
|
|
|
{
|
|
|
- struct timer_list *tp;
|
|
|
+ struct rcu_data *rdp;
|
|
|
struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu);
|
|
|
+ struct rcu_node *rnp;
|
|
|
+ struct rcu_state *rsp;
|
|
|
int tne;
|
|
|
|
|
|
/* Handle nohz enablement switches conservatively. */
|
|
|
tne = ACCESS_ONCE(tick_nohz_enabled);
|
|
|
if (tne != rdtp->tick_nohz_enabled_snap) {
|
|
|
- if (rcu_cpu_has_callbacks(cpu))
|
|
|
+ if (rcu_cpu_has_callbacks(cpu, NULL))
|
|
|
invoke_rcu_core(); /* force nohz to see update. */
|
|
|
rdtp->tick_nohz_enabled_snap = tne;
|
|
|
return;
|
|
@@ -1789,125 +1704,56 @@ static void rcu_prepare_for_idle(int cpu)
|
|
|
if (!tne)
|
|
|
return;
|
|
|
|
|
|
- /* Adaptive-tick mode, where usermode execution is idle to RCU. */
|
|
|
- if (!is_idle_task(current)) {
|
|
|
- rdtp->dyntick_holdoff = jiffies - 1;
|
|
|
- if (rcu_cpu_has_nonlazy_callbacks(cpu)) {
|
|
|
- trace_rcu_prep_idle("User dyntick with callbacks");
|
|
|
- rdtp->idle_gp_timer_expires =
|
|
|
- round_up(jiffies + RCU_IDLE_GP_DELAY,
|
|
|
- RCU_IDLE_GP_DELAY);
|
|
|
- } else if (rcu_cpu_has_callbacks(cpu)) {
|
|
|
- rdtp->idle_gp_timer_expires =
|
|
|
- round_jiffies(jiffies + RCU_IDLE_LAZY_GP_DELAY);
|
|
|
- trace_rcu_prep_idle("User dyntick with lazy callbacks");
|
|
|
- } else {
|
|
|
- return;
|
|
|
- }
|
|
|
- tp = &rdtp->idle_gp_timer;
|
|
|
- mod_timer_pinned(tp, rdtp->idle_gp_timer_expires);
|
|
|
+ /* If this is a no-CBs CPU, no callbacks, just return. */
|
|
|
+ if (is_nocb_cpu(cpu))
|
|
|
return;
|
|
|
- }
|
|
|
|
|
|
/*
|
|
|
- * If this is an idle re-entry, for example, due to use of
|
|
|
- * RCU_NONIDLE() or the new idle-loop tracing API within the idle
|
|
|
- * loop, then don't take any state-machine actions, unless the
|
|
|
- * momentary exit from idle queued additional non-lazy callbacks.
|
|
|
- * Instead, repost the ->idle_gp_timer if this CPU has callbacks
|
|
|
- * pending.
|
|
|
+ * If a non-lazy callback arrived at a CPU having only lazy
|
|
|
+ * callbacks, invoke RCU core for the side-effect of recalculating
|
|
|
+ * idle duration on re-entry to idle.
|
|
|
*/
|
|
|
- if (!rdtp->idle_first_pass &&
|
|
|
- (rdtp->nonlazy_posted == rdtp->nonlazy_posted_snap)) {
|
|
|
- if (rcu_cpu_has_callbacks(cpu)) {
|
|
|
- tp = &rdtp->idle_gp_timer;
|
|
|
- mod_timer_pinned(tp, rdtp->idle_gp_timer_expires);
|
|
|
- }
|
|
|
+ if (rdtp->all_lazy &&
|
|
|
+ rdtp->nonlazy_posted != rdtp->nonlazy_posted_snap) {
|
|
|
+ invoke_rcu_core();
|
|
|
return;
|
|
|
}
|
|
|
- rdtp->idle_first_pass = 0;
|
|
|
- rdtp->nonlazy_posted_snap = rdtp->nonlazy_posted - 1;
|
|
|
|
|
|
/*
|
|
|
- * If there are no callbacks on this CPU, enter dyntick-idle mode.
|
|
|
- * Also reset state to avoid prejudicing later attempts.
|
|
|
+ * If we have not yet accelerated this jiffy, accelerate all
|
|
|
+ * callbacks on this CPU.
|
|
|
*/
|
|
|
- if (!rcu_cpu_has_callbacks(cpu)) {
|
|
|
- rdtp->dyntick_holdoff = jiffies - 1;
|
|
|
- rdtp->dyntick_drain = 0;
|
|
|
- trace_rcu_prep_idle("No callbacks");
|
|
|
+ if (rdtp->last_accelerate == jiffies)
|
|
|
return;
|
|
|
+ rdtp->last_accelerate = jiffies;
|
|
|
+ for_each_rcu_flavor(rsp) {
|
|
|
+ rdp = per_cpu_ptr(rsp->rda, cpu);
|
|
|
+ if (!*rdp->nxttail[RCU_DONE_TAIL])
|
|
|
+ continue;
|
|
|
+ rnp = rdp->mynode;
|
|
|
+ raw_spin_lock(&rnp->lock); /* irqs already disabled. */
|
|
|
+ rcu_accelerate_cbs(rsp, rnp, rdp);
|
|
|
+ raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */
|
|
|
}
|
|
|
+}
|
|
|
|
|
|
- /*
|
|
|
- * If in holdoff mode, just return. We will presumably have
|
|
|
- * refrained from disabling the scheduling-clock tick.
|
|
|
- */
|
|
|
- if (rdtp->dyntick_holdoff == jiffies) {
|
|
|
- trace_rcu_prep_idle("In holdoff");
|
|
|
- return;
|
|
|
- }
|
|
|
+/*
|
|
|
+ * Clean up for exit from idle. Attempt to advance callbacks based on
|
|
|
+ * any grace periods that elapsed while the CPU was idle, and if any
|
|
|
+ * callbacks are now ready to invoke, initiate invocation.
|
|
|
+ */
|
|
|
+static void rcu_cleanup_after_idle(int cpu)
|
|
|
+{
|
|
|
+ struct rcu_data *rdp;
|
|
|
+ struct rcu_state *rsp;
|
|
|
|
|
|
- /* Check and update the ->dyntick_drain sequencing. */
|
|
|
- if (rdtp->dyntick_drain <= 0) {
|
|
|
- /* First time through, initialize the counter. */
|
|
|
- rdtp->dyntick_drain = RCU_IDLE_FLUSHES;
|
|
|
- } else if (rdtp->dyntick_drain <= RCU_IDLE_OPT_FLUSHES &&
|
|
|
- !rcu_pending(cpu) &&
|
|
|
- !local_softirq_pending()) {
|
|
|
- /* Can we go dyntick-idle despite still having callbacks? */
|
|
|
- rdtp->dyntick_drain = 0;
|
|
|
- rdtp->dyntick_holdoff = jiffies;
|
|
|
- if (rcu_cpu_has_nonlazy_callbacks(cpu)) {
|
|
|
- trace_rcu_prep_idle("Dyntick with callbacks");
|
|
|
- rdtp->idle_gp_timer_expires =
|
|
|
- round_up(jiffies + RCU_IDLE_GP_DELAY,
|
|
|
- RCU_IDLE_GP_DELAY);
|
|
|
- } else {
|
|
|
- rdtp->idle_gp_timer_expires =
|
|
|
- round_jiffies(jiffies + RCU_IDLE_LAZY_GP_DELAY);
|
|
|
- trace_rcu_prep_idle("Dyntick with lazy callbacks");
|
|
|
- }
|
|
|
- tp = &rdtp->idle_gp_timer;
|
|
|
- mod_timer_pinned(tp, rdtp->idle_gp_timer_expires);
|
|
|
- rdtp->nonlazy_posted_snap = rdtp->nonlazy_posted;
|
|
|
- return; /* Nothing more to do immediately. */
|
|
|
- } else if (--(rdtp->dyntick_drain) <= 0) {
|
|
|
- /* We have hit the limit, so time to give up. */
|
|
|
- rdtp->dyntick_holdoff = jiffies;
|
|
|
- trace_rcu_prep_idle("Begin holdoff");
|
|
|
- invoke_rcu_core(); /* Force the CPU out of dyntick-idle. */
|
|
|
+ if (is_nocb_cpu(cpu))
|
|
|
return;
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- * Do one step of pushing the remaining RCU callbacks through
|
|
|
- * the RCU core state machine.
|
|
|
- */
|
|
|
-#ifdef CONFIG_TREE_PREEMPT_RCU
|
|
|
- if (per_cpu(rcu_preempt_data, cpu).nxtlist) {
|
|
|
- rcu_preempt_qs(cpu);
|
|
|
- force_quiescent_state(&rcu_preempt_state);
|
|
|
- }
|
|
|
-#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
|
|
|
- if (per_cpu(rcu_sched_data, cpu).nxtlist) {
|
|
|
- rcu_sched_qs(cpu);
|
|
|
- force_quiescent_state(&rcu_sched_state);
|
|
|
- }
|
|
|
- if (per_cpu(rcu_bh_data, cpu).nxtlist) {
|
|
|
- rcu_bh_qs(cpu);
|
|
|
- force_quiescent_state(&rcu_bh_state);
|
|
|
- }
|
|
|
-
|
|
|
- /*
|
|
|
- * If RCU callbacks are still pending, RCU still needs this CPU.
|
|
|
- * So try forcing the callbacks through the grace period.
|
|
|
- */
|
|
|
- if (rcu_cpu_has_callbacks(cpu)) {
|
|
|
- trace_rcu_prep_idle("More callbacks");
|
|
|
- invoke_rcu_core();
|
|
|
- } else {
|
|
|
- trace_rcu_prep_idle("Callbacks drained");
|
|
|
+ rcu_try_advance_all_cbs();
|
|
|
+ for_each_rcu_flavor(rsp) {
|
|
|
+ rdp = per_cpu_ptr(rsp->rda, cpu);
|
|
|
+ if (cpu_has_callbacks_ready_to_invoke(rdp))
|
|
|
+ invoke_rcu_core();
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -2015,16 +1861,13 @@ early_initcall(rcu_register_oom_notifier);
|
|
|
static void print_cpu_stall_fast_no_hz(char *cp, int cpu)
|
|
|
{
|
|
|
struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu);
|
|
|
- struct timer_list *tltp = &rdtp->idle_gp_timer;
|
|
|
- char c;
|
|
|
+ unsigned long nlpd = rdtp->nonlazy_posted - rdtp->nonlazy_posted_snap;
|
|
|
|
|
|
- c = rdtp->dyntick_holdoff == jiffies ? 'H' : '.';
|
|
|
- if (timer_pending(tltp))
|
|
|
- sprintf(cp, "drain=%d %c timer=%lu",
|
|
|
- rdtp->dyntick_drain, c, tltp->expires - jiffies);
|
|
|
- else
|
|
|
- sprintf(cp, "drain=%d %c timer not pending",
|
|
|
- rdtp->dyntick_drain, c);
|
|
|
+ sprintf(cp, "last_accelerate: %04lx/%04lx, nonlazy_posted: %ld, %c%c",
|
|
|
+ rdtp->last_accelerate & 0xffff, jiffies & 0xffff,
|
|
|
+ ulong2long(nlpd),
|
|
|
+ rdtp->all_lazy ? 'L' : '.',
|
|
|
+ rdtp->tick_nohz_enabled_snap ? '.' : 'D');
|
|
|
}
|
|
|
|
|
|
#else /* #ifdef CONFIG_RCU_FAST_NO_HZ */
|
|
@@ -2070,10 +1913,11 @@ static void print_cpu_stall_info(struct rcu_state *rsp, int cpu)
|
|
|
ticks_value = rsp->gpnum - rdp->gpnum;
|
|
|
}
|
|
|
print_cpu_stall_fast_no_hz(fast_no_hz, cpu);
|
|
|
- printk(KERN_ERR "\t%d: (%lu %s) idle=%03x/%llx/%d %s\n",
|
|
|
+ printk(KERN_ERR "\t%d: (%lu %s) idle=%03x/%llx/%d softirq=%u/%u %s\n",
|
|
|
cpu, ticks_value, ticks_title,
|
|
|
atomic_read(&rdtp->dynticks) & 0xfff,
|
|
|
rdtp->dynticks_nesting, rdtp->dynticks_nmi_nesting,
|
|
|
+ rdp->softirq_snap, kstat_softirqs_cpu(RCU_SOFTIRQ, cpu),
|
|
|
fast_no_hz);
|
|
|
}
|
|
|
|
|
@@ -2087,6 +1931,7 @@ static void print_cpu_stall_info_end(void)
|
|
|
static void zero_cpu_stall_ticks(struct rcu_data *rdp)
|
|
|
{
|
|
|
rdp->ticks_this_gp = 0;
|
|
|
+ rdp->softirq_snap = kstat_softirqs_cpu(RCU_SOFTIRQ, smp_processor_id());
|
|
|
}
|
|
|
|
|
|
/* Increment ->ticks_this_gp for all flavors of RCU. */
|
|
@@ -2165,6 +2010,47 @@ static int __init parse_rcu_nocb_poll(char *arg)
|
|
|
}
|
|
|
early_param("rcu_nocb_poll", parse_rcu_nocb_poll);
|
|
|
|
|
|
+/*
|
|
|
+ * Do any no-CBs CPUs need another grace period?
|
|
|
+ *
|
|
|
+ * Interrupts must be disabled. If the caller does not hold the root
|
|
|
+ * rnp_node structure's ->lock, the results are advisory only.
|
|
|
+ */
|
|
|
+static int rcu_nocb_needs_gp(struct rcu_state *rsp)
|
|
|
+{
|
|
|
+ struct rcu_node *rnp = rcu_get_root(rsp);
|
|
|
+
|
|
|
+ return rnp->need_future_gp[(ACCESS_ONCE(rnp->completed) + 1) & 0x1];
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Wake up any no-CBs CPUs' kthreads that were waiting on the just-ended
|
|
|
+ * grace period.
|
|
|
+ */
|
|
|
+static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp)
|
|
|
+{
|
|
|
+ wake_up_all(&rnp->nocb_gp_wq[rnp->completed & 0x1]);
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * Set the root rcu_node structure's ->need_future_gp field
|
|
|
+ * based on the sum of those of all rcu_node structures. This does
|
|
|
+ * double-count the root rcu_node structure's requests, but this
|
|
|
+ * is necessary to handle the possibility of a rcu_nocb_kthread()
|
|
|
+ * having awakened during the time that the rcu_node structures
|
|
|
+ * were being updated for the end of the previous grace period.
|
|
|
+ */
|
|
|
+static void rcu_nocb_gp_set(struct rcu_node *rnp, int nrq)
|
|
|
+{
|
|
|
+ rnp->need_future_gp[(rnp->completed + 1) & 0x1] += nrq;
|
|
|
+}
|
|
|
+
|
|
|
+static void rcu_init_one_nocb(struct rcu_node *rnp)
|
|
|
+{
|
|
|
+ init_waitqueue_head(&rnp->nocb_gp_wq[0]);
|
|
|
+ init_waitqueue_head(&rnp->nocb_gp_wq[1]);
|
|
|
+}
|
|
|
+
|
|
|
/* Is the specified CPU a no-CPUs CPU? */
|
|
|
static bool is_nocb_cpu(int cpu)
|
|
|
{
|
|
@@ -2227,6 +2113,13 @@ static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp,
|
|
|
if (!is_nocb_cpu(rdp->cpu))
|
|
|
return 0;
|
|
|
__call_rcu_nocb_enqueue(rdp, rhp, &rhp->next, 1, lazy);
|
|
|
+ if (__is_kfree_rcu_offset((unsigned long)rhp->func))
|
|
|
+ trace_rcu_kfree_callback(rdp->rsp->name, rhp,
|
|
|
+ (unsigned long)rhp->func,
|
|
|
+ rdp->qlen_lazy, rdp->qlen);
|
|
|
+ else
|
|
|
+ trace_rcu_callback(rdp->rsp->name, rhp,
|
|
|
+ rdp->qlen_lazy, rdp->qlen);
|
|
|
return 1;
|
|
|
}
|
|
|
|
|
@@ -2265,95 +2158,36 @@ static bool __maybe_unused rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp,
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
- * There must be at least one non-no-CBs CPU in operation at any given
|
|
|
- * time, because no-CBs CPUs are not capable of initiating grace periods
|
|
|
- * independently. This function therefore complains if the specified
|
|
|
- * CPU is the last non-no-CBs CPU, allowing the CPU-hotplug system to
|
|
|
- * avoid offlining the last such CPU. (Recursion is a wonderful thing,
|
|
|
- * but you have to have a base case!)
|
|
|
+ * If necessary, kick off a new grace period, and either way wait
|
|
|
+ * for a subsequent grace period to complete.
|
|
|
*/
|
|
|
-static bool nocb_cpu_expendable(int cpu)
|
|
|
+static void rcu_nocb_wait_gp(struct rcu_data *rdp)
|
|
|
{
|
|
|
- cpumask_var_t non_nocb_cpus;
|
|
|
- int ret;
|
|
|
+ unsigned long c;
|
|
|
+ bool d;
|
|
|
+ unsigned long flags;
|
|
|
+ struct rcu_node *rnp = rdp->mynode;
|
|
|
+
|
|
|
+ raw_spin_lock_irqsave(&rnp->lock, flags);
|
|
|
+ c = rcu_start_future_gp(rnp, rdp);
|
|
|
+ raw_spin_unlock_irqrestore(&rnp->lock, flags);
|
|
|
|
|
|
/*
|
|
|
- * If there are no no-CB CPUs or if this CPU is not a no-CB CPU,
|
|
|
- * then offlining this CPU is harmless. Let it happen.
|
|
|
+ * Wait for the grace period. Do so interruptibly to avoid messing
|
|
|
+ * up the load average.
|
|
|
*/
|
|
|
- if (!have_rcu_nocb_mask || is_nocb_cpu(cpu))
|
|
|
- return 1;
|
|
|
-
|
|
|
- /* If no memory, play it safe and keep the CPU around. */
|
|
|
- if (!alloc_cpumask_var(&non_nocb_cpus, GFP_NOIO))
|
|
|
- return 0;
|
|
|
- cpumask_andnot(non_nocb_cpus, cpu_online_mask, rcu_nocb_mask);
|
|
|
- cpumask_clear_cpu(cpu, non_nocb_cpus);
|
|
|
- ret = !cpumask_empty(non_nocb_cpus);
|
|
|
- free_cpumask_var(non_nocb_cpus);
|
|
|
- return ret;
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Helper structure for remote registry of RCU callbacks.
|
|
|
- * This is needed for when a no-CBs CPU needs to start a grace period.
|
|
|
- * If it just invokes call_rcu(), the resulting callback will be queued,
|
|
|
- * which can result in deadlock.
|
|
|
- */
|
|
|
-struct rcu_head_remote {
|
|
|
- struct rcu_head *rhp;
|
|
|
- call_rcu_func_t *crf;
|
|
|
- void (*func)(struct rcu_head *rhp);
|
|
|
-};
|
|
|
-
|
|
|
-/*
|
|
|
- * Register a callback as specified by the rcu_head_remote struct.
|
|
|
- * This function is intended to be invoked via smp_call_function_single().
|
|
|
- */
|
|
|
-static void call_rcu_local(void *arg)
|
|
|
-{
|
|
|
- struct rcu_head_remote *rhrp =
|
|
|
- container_of(arg, struct rcu_head_remote, rhp);
|
|
|
-
|
|
|
- rhrp->crf(rhrp->rhp, rhrp->func);
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Set up an rcu_head_remote structure and the invoke call_rcu_local()
|
|
|
- * on CPU 0 (which is guaranteed to be a non-no-CBs CPU) via
|
|
|
- * smp_call_function_single().
|
|
|
- */
|
|
|
-static void invoke_crf_remote(struct rcu_head *rhp,
|
|
|
- void (*func)(struct rcu_head *rhp),
|
|
|
- call_rcu_func_t crf)
|
|
|
-{
|
|
|
- struct rcu_head_remote rhr;
|
|
|
-
|
|
|
- rhr.rhp = rhp;
|
|
|
- rhr.crf = crf;
|
|
|
- rhr.func = func;
|
|
|
- smp_call_function_single(0, call_rcu_local, &rhr, 1);
|
|
|
-}
|
|
|
-
|
|
|
-/*
|
|
|
- * Helper functions to be passed to wait_rcu_gp(), each of which
|
|
|
- * invokes invoke_crf_remote() to register a callback appropriately.
|
|
|
- */
|
|
|
-static void __maybe_unused
|
|
|
-call_rcu_preempt_remote(struct rcu_head *rhp,
|
|
|
- void (*func)(struct rcu_head *rhp))
|
|
|
-{
|
|
|
- invoke_crf_remote(rhp, func, call_rcu);
|
|
|
-}
|
|
|
-static void call_rcu_bh_remote(struct rcu_head *rhp,
|
|
|
- void (*func)(struct rcu_head *rhp))
|
|
|
-{
|
|
|
- invoke_crf_remote(rhp, func, call_rcu_bh);
|
|
|
-}
|
|
|
-static void call_rcu_sched_remote(struct rcu_head *rhp,
|
|
|
- void (*func)(struct rcu_head *rhp))
|
|
|
-{
|
|
|
- invoke_crf_remote(rhp, func, call_rcu_sched);
|
|
|
+ trace_rcu_future_gp(rnp, rdp, c, "StartWait");
|
|
|
+ for (;;) {
|
|
|
+ wait_event_interruptible(
|
|
|
+ rnp->nocb_gp_wq[c & 0x1],
|
|
|
+ (d = ULONG_CMP_GE(ACCESS_ONCE(rnp->completed), c)));
|
|
|
+ if (likely(d))
|
|
|
+ break;
|
|
|
+ flush_signals(current);
|
|
|
+ trace_rcu_future_gp(rnp, rdp, c, "ResumeWait");
|
|
|
+ }
|
|
|
+ trace_rcu_future_gp(rnp, rdp, c, "EndWait");
|
|
|
+ smp_mb(); /* Ensure that CB invocation happens after GP end. */
|
|
|
}
|
|
|
|
|
|
/*
|
|
@@ -2390,7 +2224,7 @@ static int rcu_nocb_kthread(void *arg)
|
|
|
cl = atomic_long_xchg(&rdp->nocb_q_count_lazy, 0);
|
|
|
ACCESS_ONCE(rdp->nocb_p_count) += c;
|
|
|
ACCESS_ONCE(rdp->nocb_p_count_lazy) += cl;
|
|
|
- wait_rcu_gp(rdp->rsp->call_remote);
|
|
|
+ rcu_nocb_wait_gp(rdp);
|
|
|
|
|
|
/* Each pass through the following loop invokes a callback. */
|
|
|
trace_rcu_batch_start(rdp->rsp->name, cl, c, -1);
|
|
@@ -2436,32 +2270,41 @@ static void __init rcu_spawn_nocb_kthreads(struct rcu_state *rsp)
|
|
|
return;
|
|
|
for_each_cpu(cpu, rcu_nocb_mask) {
|
|
|
rdp = per_cpu_ptr(rsp->rda, cpu);
|
|
|
- t = kthread_run(rcu_nocb_kthread, rdp, "rcuo%d", cpu);
|
|
|
+ t = kthread_run(rcu_nocb_kthread, rdp,
|
|
|
+ "rcuo%c/%d", rsp->abbr, cpu);
|
|
|
BUG_ON(IS_ERR(t));
|
|
|
ACCESS_ONCE(rdp->nocb_kthread) = t;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* Prevent __call_rcu() from enqueuing callbacks on no-CBs CPUs */
|
|
|
-static void init_nocb_callback_list(struct rcu_data *rdp)
|
|
|
+static bool init_nocb_callback_list(struct rcu_data *rdp)
|
|
|
{
|
|
|
if (rcu_nocb_mask == NULL ||
|
|
|
!cpumask_test_cpu(rdp->cpu, rcu_nocb_mask))
|
|
|
- return;
|
|
|
+ return false;
|
|
|
rdp->nxttail[RCU_NEXT_TAIL] = NULL;
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
+#else /* #ifdef CONFIG_RCU_NOCB_CPU */
|
|
|
+
|
|
|
+static int rcu_nocb_needs_gp(struct rcu_state *rsp)
|
|
|
+{
|
|
|
+ return 0;
|
|
|
}
|
|
|
|
|
|
-/* Initialize the ->call_remote fields in the rcu_state structures. */
|
|
|
-static void __init rcu_init_nocb(void)
|
|
|
+static void rcu_nocb_gp_cleanup(struct rcu_state *rsp, struct rcu_node *rnp)
|
|
|
{
|
|
|
-#ifdef CONFIG_PREEMPT_RCU
|
|
|
- rcu_preempt_state.call_remote = call_rcu_preempt_remote;
|
|
|
-#endif /* #ifdef CONFIG_PREEMPT_RCU */
|
|
|
- rcu_bh_state.call_remote = call_rcu_bh_remote;
|
|
|
- rcu_sched_state.call_remote = call_rcu_sched_remote;
|
|
|
}
|
|
|
|
|
|
-#else /* #ifdef CONFIG_RCU_NOCB_CPU */
|
|
|
+static void rcu_nocb_gp_set(struct rcu_node *rnp, int nrq)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
+static void rcu_init_one_nocb(struct rcu_node *rnp)
|
|
|
+{
|
|
|
+}
|
|
|
|
|
|
static bool is_nocb_cpu(int cpu)
|
|
|
{
|
|
@@ -2480,11 +2323,6 @@ static bool __maybe_unused rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
-static bool nocb_cpu_expendable(int cpu)
|
|
|
-{
|
|
|
- return 1;
|
|
|
-}
|
|
|
-
|
|
|
static void __init rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp)
|
|
|
{
|
|
|
}
|
|
@@ -2493,12 +2331,9 @@ static void __init rcu_spawn_nocb_kthreads(struct rcu_state *rsp)
|
|
|
{
|
|
|
}
|
|
|
|
|
|
-static void init_nocb_callback_list(struct rcu_data *rdp)
|
|
|
-{
|
|
|
-}
|
|
|
-
|
|
|
-static void __init rcu_init_nocb(void)
|
|
|
+static bool init_nocb_callback_list(struct rcu_data *rdp)
|
|
|
{
|
|
|
+ return false;
|
|
|
}
|
|
|
|
|
|
#endif /* #else #ifdef CONFIG_RCU_NOCB_CPU */
|