|
@@ -2104,7 +2104,8 @@ bool rcu_is_nocb_cpu(int cpu)
|
|
|
static void __call_rcu_nocb_enqueue(struct rcu_data *rdp,
|
|
|
struct rcu_head *rhp,
|
|
|
struct rcu_head **rhtp,
|
|
|
- int rhcount, int rhcount_lazy)
|
|
|
+ int rhcount, int rhcount_lazy,
|
|
|
+ unsigned long flags)
|
|
|
{
|
|
|
int len;
|
|
|
struct rcu_head **old_rhpp;
|
|
@@ -2125,9 +2126,16 @@ static void __call_rcu_nocb_enqueue(struct rcu_data *rdp,
|
|
|
}
|
|
|
len = atomic_long_read(&rdp->nocb_q_count);
|
|
|
if (old_rhpp == &rdp->nocb_head) {
|
|
|
- wake_up(&rdp->nocb_wq); /* ... only if queue was empty ... */
|
|
|
+ if (!irqs_disabled_flags(flags)) {
|
|
|
+ wake_up(&rdp->nocb_wq); /* ... if queue was empty ... */
|
|
|
+ trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu,
|
|
|
+ TPS("WakeEmpty"));
|
|
|
+ } else {
|
|
|
+ rdp->nocb_defer_wakeup = true;
|
|
|
+ trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu,
|
|
|
+ TPS("WakeEmptyIsDeferred"));
|
|
|
+ }
|
|
|
rdp->qlen_last_fqs_check = 0;
|
|
|
- trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, TPS("WakeEmpty"));
|
|
|
} else if (len > rdp->qlen_last_fqs_check + qhimark) {
|
|
|
wake_up_process(t); /* ... or if many callbacks queued. */
|
|
|
rdp->qlen_last_fqs_check = LONG_MAX / 2;
|
|
@@ -2148,12 +2156,12 @@ static void __call_rcu_nocb_enqueue(struct rcu_data *rdp,
|
|
|
* "rcuo" kthread can find it.
|
|
|
*/
|
|
|
static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp,
|
|
|
- bool lazy)
|
|
|
+ bool lazy, unsigned long flags)
|
|
|
{
|
|
|
|
|
|
if (!rcu_is_nocb_cpu(rdp->cpu))
|
|
|
return 0;
|
|
|
- __call_rcu_nocb_enqueue(rdp, rhp, &rhp->next, 1, lazy);
|
|
|
+ __call_rcu_nocb_enqueue(rdp, rhp, &rhp->next, 1, lazy, flags);
|
|
|
if (__is_kfree_rcu_offset((unsigned long)rhp->func))
|
|
|
trace_rcu_kfree_callback(rdp->rsp->name, rhp,
|
|
|
(unsigned long)rhp->func,
|
|
@@ -2171,7 +2179,8 @@ static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp,
|
|
|
* not a no-CBs CPU.
|
|
|
*/
|
|
|
static bool __maybe_unused rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp,
|
|
|
- struct rcu_data *rdp)
|
|
|
+ struct rcu_data *rdp,
|
|
|
+ unsigned long flags)
|
|
|
{
|
|
|
long ql = rsp->qlen;
|
|
|
long qll = rsp->qlen_lazy;
|
|
@@ -2185,14 +2194,14 @@ static bool __maybe_unused rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp,
|
|
|
/* First, enqueue the donelist, if any. This preserves CB ordering. */
|
|
|
if (rsp->orphan_donelist != NULL) {
|
|
|
__call_rcu_nocb_enqueue(rdp, rsp->orphan_donelist,
|
|
|
- rsp->orphan_donetail, ql, qll);
|
|
|
+ rsp->orphan_donetail, ql, qll, flags);
|
|
|
ql = qll = 0;
|
|
|
rsp->orphan_donelist = NULL;
|
|
|
rsp->orphan_donetail = &rsp->orphan_donelist;
|
|
|
}
|
|
|
if (rsp->orphan_nxtlist != NULL) {
|
|
|
__call_rcu_nocb_enqueue(rdp, rsp->orphan_nxtlist,
|
|
|
- rsp->orphan_nxttail, ql, qll);
|
|
|
+ rsp->orphan_nxttail, ql, qll, flags);
|
|
|
ql = qll = 0;
|
|
|
rsp->orphan_nxtlist = NULL;
|
|
|
rsp->orphan_nxttail = &rsp->orphan_nxtlist;
|
|
@@ -2314,6 +2323,22 @@ static int rcu_nocb_kthread(void *arg)
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+/* Is a deferred wakeup of rcu_nocb_kthread() required? */
|
|
|
+static bool rcu_nocb_need_deferred_wakeup(struct rcu_data *rdp)
|
|
|
+{
|
|
|
+ return ACCESS_ONCE(rdp->nocb_defer_wakeup);
|
|
|
+}
|
|
|
+
|
|
|
+/* Do a deferred wakeup of rcu_nocb_kthread(). */
|
|
|
+static void do_nocb_deferred_wakeup(struct rcu_data *rdp)
|
|
|
+{
|
|
|
+ if (!rcu_nocb_need_deferred_wakeup(rdp))
|
|
|
+ return;
|
|
|
+ ACCESS_ONCE(rdp->nocb_defer_wakeup) = false;
|
|
|
+ wake_up(&rdp->nocb_wq);
|
|
|
+ trace_rcu_nocb_wake(rdp->rsp->name, rdp->cpu, TPS("DeferredWakeEmpty"));
|
|
|
+}
|
|
|
+
|
|
|
/* Initialize per-rcu_data variables for no-CBs CPUs. */
|
|
|
static void __init rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp)
|
|
|
{
|
|
@@ -2369,13 +2394,14 @@ static void rcu_init_one_nocb(struct rcu_node *rnp)
|
|
|
}
|
|
|
|
|
|
static bool __call_rcu_nocb(struct rcu_data *rdp, struct rcu_head *rhp,
|
|
|
- bool lazy)
|
|
|
+ bool lazy, unsigned long flags)
|
|
|
{
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
static bool __maybe_unused rcu_nocb_adopt_orphan_cbs(struct rcu_state *rsp,
|
|
|
- struct rcu_data *rdp)
|
|
|
+ struct rcu_data *rdp,
|
|
|
+ unsigned long flags)
|
|
|
{
|
|
|
return 0;
|
|
|
}
|
|
@@ -2384,6 +2410,15 @@ static void __init rcu_boot_init_nocb_percpu_data(struct rcu_data *rdp)
|
|
|
{
|
|
|
}
|
|
|
|
|
|
+static bool rcu_nocb_need_deferred_wakeup(struct rcu_data *rdp)
|
|
|
+{
|
|
|
+ return false;
|
|
|
+}
|
|
|
+
|
|
|
+static void do_nocb_deferred_wakeup(struct rcu_data *rdp)
|
|
|
+{
|
|
|
+}
|
|
|
+
|
|
|
static void __init rcu_spawn_nocb_kthreads(struct rcu_state *rsp)
|
|
|
{
|
|
|
}
|