Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b3dbec76 authored by Paul E. McKenney's avatar Paul E. McKenney
Browse files

rcu: Move RCU grace-period initialization into a kthread



As the first step towards allowing grace-period initialization to be
preemptible, this commit moves the RCU grace-period initialization
into its own kthread.  This is needed to keep large-system scheduling
latency at reasonable levels.

Also change raw_spin_lock_irqsave() to raw_spin_lock_irq() as suggested
by Peter Zijlstra in review comments.

Reported-by: default avatarMike Galbraith <mgalbraith@suse.de>
Reported-by: default avatarDimitri Sivanich <sivanich@sgi.com>
Signed-off-by: default avatarPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Reviewed-by: default avatarJosh Triplett <josh@joshtriplett.org>
parent a10d206e
Loading
Loading
Loading
Loading
+126 −64
Original line number Diff line number Diff line
@@ -1042,49 +1042,52 @@ rcu_start_gp_per_cpu(struct rcu_state *rsp, struct rcu_node *rnp, struct rcu_dat
}

/*
 * Start a new RCU grace period if warranted, re-initializing the hierarchy
 * in preparation for detecting the next grace period.  The caller must hold
 * the root node's ->lock, which is released before return.  Hard irqs must
 * be disabled.
 *
 * Note that it is legal for a dying CPU (which is marked as offline) to
 * invoke this function.  This can happen when the dying CPU reports its
 * quiescent state.
 * Body of kthread that handles grace periods.
 */
static void
rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
	__releases(rcu_get_root(rsp)->lock)
static int rcu_gp_kthread(void *arg)
{
	struct rcu_data *rdp = this_cpu_ptr(rsp->rda);
	struct rcu_node *rnp = rcu_get_root(rsp);
	struct rcu_data *rdp;
	struct rcu_node *rnp;
	struct rcu_state *rsp = arg;

	if (!rcu_scheduler_fully_active ||
	    !cpu_needs_another_gp(rsp, rdp)) {
	for (;;) {

		/* Handle grace-period start. */
		rnp = rcu_get_root(rsp);
		for (;;) {
			wait_event_interruptible(rsp->gp_wq, rsp->gp_flags);
			if (rsp->gp_flags)
				break;
			flush_signals(current);
		}
		raw_spin_lock_irq(&rnp->lock);
		rsp->gp_flags = 0;
		rdp = this_cpu_ptr(rsp->rda);

		if (rcu_gp_in_progress(rsp)) {
			/*
		 * Either the scheduler hasn't yet spawned the first
		 * non-idle task or this CPU does not need another
		 * grace period.  Either way, don't start a new grace
		 * period.
			 * A grace period is already in progress, so
			 * don't start another one.
			 */
		raw_spin_unlock_irqrestore(&rnp->lock, flags);
		return;
			raw_spin_unlock_irq(&rnp->lock);
			continue;
		}

		if (rsp->fqs_active) {
			/*
		 * This CPU needs a grace period, but force_quiescent_state()
		 * is running.  Tell it to start one on this CPU's behalf.
			 * We need a grace period, but force_quiescent_state()
			 * is running.  Tell it to start one on our behalf.
			 */
			rsp->fqs_need_gp = 1;
		raw_spin_unlock_irqrestore(&rnp->lock, flags);
		return;
			raw_spin_unlock_irq(&rnp->lock);
			continue;
		}

		/* Advance to a new grace period and initialize state. */
		rsp->gpnum++;
		trace_rcu_grace_period(rsp->name, rsp->gpnum, "start");
		WARN_ON_ONCE(rsp->fqs_state == RCU_GP_INIT);
	rsp->fqs_state = RCU_GP_INIT; /* Hold off force_quiescent_state. */
		rsp->fqs_state = RCU_GP_INIT; /* Stop force_quiescent_state. */
		rsp->jiffies_force_qs = jiffies + RCU_JIFFIES_TILL_FORCE_QS;
		record_gp_stall_check_time(rsp);
		raw_spin_unlock(&rnp->lock);  /* leave irqs disabled. */
@@ -1095,19 +1098,19 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
		/*
		 * Set the quiescent-state-needed bits in all the rcu_node
		 * structures for all currently online CPUs in breadth-first
	 * order, starting from the root rcu_node structure.  This
	 * operation relies on the layout of the hierarchy within the
	 * rsp->node[] array.  Note that other CPUs will access only
	 * the leaves of the hierarchy, which still indicate that no
	 * grace period is in progress, at least until the corresponding
	 * leaf node has been initialized.  In addition, we have excluded
	 * CPU-hotplug operations.
		 * order, starting from the root rcu_node structure.
		 * This operation relies on the layout of the hierarchy
		 * within the rsp->node[] array.  Note that other CPUs will
		 * access only the leaves of the hierarchy, which still
		 * indicate that no grace period is in progress, at least
		 * until the corresponding leaf node has been initialized.
		 * In addition, we have excluded CPU-hotplug operations.
		 *
	 * Note that the grace period cannot complete until we finish
	 * the initialization process, as there will be at least one
	 * qsmask bit set in the root node until that time, namely the
	 * one corresponding to this CPU, due to the fact that we have
	 * irqs disabled.
		 * Note that the grace period cannot complete until
		 * we finish the initialization process, as there will
		 * be at least one qsmask bit set in the root node until
		 * that time, namely the one corresponding to this CPU,
		 * due to the fact that we have irqs disabled.
		 */
		rcu_for_each_node_breadth_first(rsp, rnp) {
			raw_spin_lock(&rnp->lock); /* irqs already disabled. */
@@ -1126,9 +1129,45 @@ rcu_start_gp(struct rcu_state *rsp, unsigned long flags)

		rnp = rcu_get_root(rsp);
		raw_spin_lock(&rnp->lock); /* irqs already disabled. */
	rsp->fqs_state = RCU_SIGNAL_INIT; /* force_quiescent_state now OK. */
		/* force_quiescent_state() now OK. */
		rsp->fqs_state = RCU_SIGNAL_INIT;
		raw_spin_unlock(&rnp->lock); /* irqs remain disabled. */
	raw_spin_unlock_irqrestore(&rsp->onofflock, flags);
		raw_spin_unlock_irq(&rsp->onofflock);
	}
	return 0;
}

/*
 * Start a new RCU grace period if warranted, re-initializing the hierarchy
 * in preparation for detecting the next grace period.  The caller must hold
 * the root node's ->lock, which is released before return.  Hard irqs must
 * be disabled.
 *
 * Note that it is legal for a dying CPU (which is marked as offline) to
 * invoke this function.  This can happen when the dying CPU reports its
 * quiescent state.
 */
static void
rcu_start_gp(struct rcu_state *rsp, unsigned long flags)
	__releases(rcu_get_root(rsp)->lock)
{
	struct rcu_data *rdp = this_cpu_ptr(rsp->rda);
	struct rcu_node *rnp = rcu_get_root(rsp);

	if (!rsp->gp_kthread ||
	    !cpu_needs_another_gp(rsp, rdp)) {
		/*
		 * Either we have not yet spawned the grace-period
		 * task or this CPU does not need another grace period.
		 * Either way, don't start a new grace period.
		 */
		raw_spin_unlock_irqrestore(&rnp->lock, flags);
		return;
	}

	rsp->gp_flags = 1;
	raw_spin_unlock_irqrestore(&rnp->lock, flags);
	wake_up(&rsp->gp_wq);
}

/*
@@ -2628,6 +2667,28 @@ static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
	return NOTIFY_OK;
}

/*
 * Spawn the kthread that handles this RCU flavor's grace periods.
 */
static int __init rcu_spawn_gp_kthread(void)
{
	unsigned long flags;
	struct rcu_node *rnp;
	struct rcu_state *rsp;
	struct task_struct *t;

	for_each_rcu_flavor(rsp) {
		t = kthread_run(rcu_gp_kthread, rsp, rsp->name);
		BUG_ON(IS_ERR(t));
		rnp = rcu_get_root(rsp);
		raw_spin_lock_irqsave(&rnp->lock, flags);
		rsp->gp_kthread = t;
		raw_spin_unlock_irqrestore(&rnp->lock, flags);
	}
	return 0;
}
early_initcall(rcu_spawn_gp_kthread);

/*
 * This function is invoked towards the end of the scheduler's initialization
 * process.  Before this is called, the idle task might contain
@@ -2729,6 +2790,7 @@ static void __init rcu_init_one(struct rcu_state *rsp,
	}

	rsp->rda = rda;
	init_waitqueue_head(&rsp->gp_wq);
	rnp = rsp->level[rcu_num_lvls - 1];
	for_each_possible_cpu(i) {
		while (i > rnp->grphi)
+3 −0
Original line number Diff line number Diff line
@@ -385,6 +385,9 @@ struct rcu_state {
	u8	boost;				/* Subject to priority boost. */
	unsigned long gpnum;			/* Current gp number. */
	unsigned long completed;		/* # of last completed gp. */
	struct task_struct *gp_kthread;		/* Task for grace periods. */
	wait_queue_head_t gp_wq;		/* Where GP task waits. */
	int gp_flags;				/* Commands for GP task. */

	/* End of fields guarded by root rcu_node's lock. */