diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/rcutree.c | 17 | ||||
| -rw-r--r-- | kernel/rcutree.h | 2 | 
2 files changed, 17 insertions, 2 deletions
diff --git a/kernel/rcutree.c b/kernel/rcutree.c index 16ea6792501..b61d20c5ee7 100644 --- a/kernel/rcutree.c +++ b/kernel/rcutree.c @@ -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) diff --git a/kernel/rcutree.h b/kernel/rcutree.h index da77a8f57ff..4df503470e4 100644 --- a/kernel/rcutree.h +++ b/kernel/rcutree.h @@ -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. */  |