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

Commit cb7e9704 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull RCU fixes from Paul McKenney:
 "I must confess that this past merge window was not RCU's best showing.
  This series contains three more fixes for RCU regressions:

   1.   A fix to __DECLARE_TRACE_RCU() that causes it to act as an
        interrupt from idle rather than as a task switch from idle.
        This change is needed due to the recent use of _rcuidle()
        tracepoints that can be invoked from interrupt handlers as well
        as from idle.  Without this fix, invoking _rcuidle() tracepoints
        from interrupt handlers results in splats and (more seriously)
        confusion on RCU's part as to whether a given CPU is idle or not.
        This confusion can in turn result in too-short grace periods and
        therefore random memory corruption.

   2.   A fix to a subtle deadlock that could result due to RCU doing
        a wakeup while holding one of its rcu_node structure's locks.
        Although the probability of occurrence is low, it really
        does happen.  The fix, courtesy of Steven Rostedt, uses
        irq_work_queue() to avoid the deadlock.

   3.   A fix to a silent deadlock (invisible to lockdep) due to the
        interaction of timeouts posted by RCU debug code enabled by
        CONFIG_PROVE_RCU_DELAY=y, grace-period initialization, and CPU
        hotplug operations.  This will not occur in production kernels,
        but really does occur in randconfig testing.  Diagnosis courtesy
        of Steven Rostedt"

* 'rcu/urgent' of git://git.kernel.org/pub/scm/linux/kernel/git/paulmck/linux-rcu:
  rcu: Fix deadlock with CPU hotplug, RCU GP init, and timer migration
  rcu: Don't call wakeup() with rcu_node structure ->lock held
  trace: Allow idle-safe tracepoints to be called from irq
parents dcae7f2d 971394f3
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -145,8 +145,8 @@ static inline void tracepoint_synchronize_unregister(void)
				TP_PROTO(data_proto),			\
				TP_ARGS(data_args),			\
				TP_CONDITION(cond),			\
				rcu_idle_exit(),			\
				rcu_idle_enter());			\
				rcu_irq_enter(),			\
				rcu_irq_exit());			\
	}
#else
#define __DECLARE_TRACE_RCU(name, proto, args, cond, data_proto, data_args)
+1 −0
Original line number Diff line number Diff line
@@ -431,6 +431,7 @@ choice
config TREE_RCU
	bool "Tree-based hierarchical RCU"
	depends on !PREEMPT && SMP
	select IRQ_WORK
	help
	  This option selects the RCU implementation that is
	  designed for very large SMP system with hundreds or
+17 −4
Original line number Diff line number Diff line
@@ -1451,9 +1451,9 @@ static int rcu_gp_init(struct rcu_state *rsp)
					    rnp->grphi, rnp->qsmask);
		raw_spin_unlock_irq(&rnp->lock);
#ifdef CONFIG_PROVE_RCU_DELAY
		if ((prandom_u32() % (rcu_num_nodes * 8)) == 0 &&
		if ((prandom_u32() % (rcu_num_nodes + 1)) == 0 &&
		    system_state == SYSTEM_RUNNING)
			schedule_timeout_uninterruptible(2);
			udelay(200);
#endif /* #ifdef CONFIG_PROVE_RCU_DELAY */
		cond_resched();
	}
@@ -1613,6 +1613,14 @@ static int __noreturn rcu_gp_kthread(void *arg)
	}
}

static void rsp_wakeup(struct irq_work *work)
{
	struct rcu_state *rsp = container_of(work, struct rcu_state, wakeup_work);

	/* Wake up rcu_gp_kthread() to start the grace period. */
	wake_up(&rsp->gp_wq);
}

/*
 * Start a new RCU grace period if warranted, re-initializing the hierarchy
 * in preparation for detecting the next grace period.  The caller must hold
@@ -1637,8 +1645,12 @@ rcu_start_gp_advanced(struct rcu_state *rsp, struct rcu_node *rnp,
	}
	rsp->gp_flags = RCU_GP_FLAG_INIT;

	/* Wake up rcu_gp_kthread() to start the grace period. */
	wake_up(&rsp->gp_wq);
	/*
	 * We can't do wakeups while holding the rnp->lock, as that
	 * could cause possible deadlocks with the rq->lock. Deter
	 * the wakeup to interrupt context.
	 */
	irq_work_queue(&rsp->wakeup_work);
}

/*
@@ -3235,6 +3247,7 @@ static void __init rcu_init_one(struct rcu_state *rsp,

	rsp->rda = rda;
	init_waitqueue_head(&rsp->gp_wq);
	init_irq_work(&rsp->wakeup_work, rsp_wakeup);
	rnp = rsp->level[rcu_num_lvls - 1];
	for_each_possible_cpu(i) {
		while (i > rnp->grphi)
+2 −0
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@
#include <linux/threads.h>
#include <linux/cpumask.h>
#include <linux/seqlock.h>
#include <linux/irq_work.h>

/*
 * Define shape of hierarchy based on NR_CPUS, CONFIG_RCU_FANOUT, and
@@ -442,6 +443,7 @@ struct rcu_state {
	char *name;				/* Name of structure. */
	char abbr;				/* Abbreviated name. */
	struct list_head flavors;		/* List of RCU flavors. */
	struct irq_work wakeup_work;		/* Postponed wakeups */
};

/* Values for rcu_state structure's gp_flags field. */