diff options
-rw-r--r-- | kernel/rcu/tree.c | 20 |
1 files changed, 19 insertions, 1 deletions
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c index 3e89b5b83ea0..71395e91b876 100644 --- a/kernel/rcu/tree.c +++ b/kernel/rcu/tree.c | |||
@@ -56,6 +56,7 @@ | |||
56 | #include <linux/smpboot.h> | 56 | #include <linux/smpboot.h> |
57 | #include <linux/jiffies.h> | 57 | #include <linux/jiffies.h> |
58 | #include <linux/sched/isolation.h> | 58 | #include <linux/sched/isolation.h> |
59 | #include <linux/sched/clock.h> | ||
59 | #include "../time/tick-internal.h" | 60 | #include "../time/tick-internal.h" |
60 | 61 | ||
61 | #include "tree.h" | 62 | #include "tree.h" |
@@ -416,6 +417,12 @@ module_param(qlowmark, long, 0444); | |||
416 | static ulong jiffies_till_first_fqs = ULONG_MAX; | 417 | static ulong jiffies_till_first_fqs = ULONG_MAX; |
417 | static ulong jiffies_till_next_fqs = ULONG_MAX; | 418 | static ulong jiffies_till_next_fqs = ULONG_MAX; |
418 | static bool rcu_kick_kthreads; | 419 | static bool rcu_kick_kthreads; |
420 | static int rcu_divisor = 7; | ||
421 | module_param(rcu_divisor, int, 0644); | ||
422 | |||
423 | /* Force an exit from rcu_do_batch() after 3 milliseconds. */ | ||
424 | static long rcu_resched_ns = 3 * NSEC_PER_MSEC; | ||
425 | module_param(rcu_resched_ns, long, 0644); | ||
419 | 426 | ||
420 | /* | 427 | /* |
421 | * How long the grace period must be before we start recruiting | 428 | * How long the grace period must be before we start recruiting |
@@ -2109,6 +2116,7 @@ static void rcu_do_batch(struct rcu_data *rdp) | |||
2109 | struct rcu_head *rhp; | 2116 | struct rcu_head *rhp; |
2110 | struct rcu_cblist rcl = RCU_CBLIST_INITIALIZER(rcl); | 2117 | struct rcu_cblist rcl = RCU_CBLIST_INITIALIZER(rcl); |
2111 | long bl, count; | 2118 | long bl, count; |
2119 | long pending, tlimit = 0; | ||
2112 | 2120 | ||
2113 | /* If no callbacks are ready, just return. */ | 2121 | /* If no callbacks are ready, just return. */ |
2114 | if (!rcu_segcblist_ready_cbs(&rdp->cblist)) { | 2122 | if (!rcu_segcblist_ready_cbs(&rdp->cblist)) { |
@@ -2130,7 +2138,10 @@ static void rcu_do_batch(struct rcu_data *rdp) | |||
2130 | local_irq_save(flags); | 2138 | local_irq_save(flags); |
2131 | rcu_nocb_lock(rdp); | 2139 | rcu_nocb_lock(rdp); |
2132 | WARN_ON_ONCE(cpu_is_offline(smp_processor_id())); | 2140 | WARN_ON_ONCE(cpu_is_offline(smp_processor_id())); |
2133 | bl = rdp->blimit; | 2141 | pending = rcu_segcblist_n_cbs(&rdp->cblist); |
2142 | bl = max(rdp->blimit, pending >> rcu_divisor); | ||
2143 | if (unlikely(bl > 100)) | ||
2144 | tlimit = local_clock() + rcu_resched_ns; | ||
2134 | trace_rcu_batch_start(rcu_state.name, | 2145 | trace_rcu_batch_start(rcu_state.name, |
2135 | rcu_segcblist_n_lazy_cbs(&rdp->cblist), | 2146 | rcu_segcblist_n_lazy_cbs(&rdp->cblist), |
2136 | rcu_segcblist_n_cbs(&rdp->cblist), bl); | 2147 | rcu_segcblist_n_cbs(&rdp->cblist), bl); |
@@ -2153,6 +2164,13 @@ static void rcu_do_batch(struct rcu_data *rdp) | |||
2153 | (need_resched() || | 2164 | (need_resched() || |
2154 | (!is_idle_task(current) && !rcu_is_callbacks_kthread()))) | 2165 | (!is_idle_task(current) && !rcu_is_callbacks_kthread()))) |
2155 | break; | 2166 | break; |
2167 | if (unlikely(tlimit)) { | ||
2168 | /* only call local_clock() every 32 callbacks */ | ||
2169 | if (likely((-rcl.len & 31) || local_clock() < tlimit)) | ||
2170 | continue; | ||
2171 | /* Exceeded the time limit, so leave. */ | ||
2172 | break; | ||
2173 | } | ||
2156 | if (offloaded) { | 2174 | if (offloaded) { |
2157 | WARN_ON_ONCE(in_serving_softirq()); | 2175 | WARN_ON_ONCE(in_serving_softirq()); |
2158 | local_bh_enable(); | 2176 | local_bh_enable(); |