OSDN Git Service

Merge tag 'slab-for-5.18' of git://git.kernel.org/pub/scm/linux/kernel/git/vbabka...
[uclinux-h8/linux.git] / kernel / time / tick-sched.c
index 17a283c..2d76c91 100644 (file)
@@ -169,6 +169,8 @@ static ktime_t tick_init_jiffy_update(void)
        return period;
 }
 
+#define MAX_STALLED_JIFFIES 5
+
 static void tick_sched_do_timer(struct tick_sched *ts, ktime_t now)
 {
        int cpu = smp_processor_id();
@@ -196,6 +198,21 @@ static void tick_sched_do_timer(struct tick_sched *ts, ktime_t now)
        if (tick_do_timer_cpu == cpu)
                tick_do_update_jiffies64(now);
 
+       /*
+        * If jiffies update stalled for too long (timekeeper in stop_machine()
+        * or VMEXIT'ed for several msecs), force an update.
+        */
+       if (ts->last_tick_jiffies != jiffies) {
+               ts->stalled_jiffies = 0;
+               ts->last_tick_jiffies = READ_ONCE(jiffies);
+       } else {
+               if (++ts->stalled_jiffies == MAX_STALLED_JIFFIES) {
+                       tick_do_update_jiffies64(now);
+                       ts->stalled_jiffies = 0;
+                       ts->last_tick_jiffies = READ_ONCE(jiffies);
+               }
+       }
+
        if (ts->inidle)
                ts->got_idle_tick = 1;
 }
@@ -768,7 +785,7 @@ static inline bool local_timer_softirq_pending(void)
 
 static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)
 {
-       u64 basemono, next_tick, next_tmr, next_rcu, delta, expires;
+       u64 basemono, next_tick, delta, expires;
        unsigned long basejiff;
        unsigned int seq;
 
@@ -791,7 +808,7 @@ static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)
         * minimal delta which brings us back to this place
         * immediately. Lather, rinse and repeat...
         */
-       if (rcu_needs_cpu(basemono, &next_rcu) || arch_needs_cpu() ||
+       if (rcu_needs_cpu() || arch_needs_cpu() ||
            irq_work_needs_cpu() || local_timer_softirq_pending()) {
                next_tick = basemono + TICK_NSEC;
        } else {
@@ -802,10 +819,8 @@ static ktime_t tick_nohz_next_event(struct tick_sched *ts, int cpu)
                 * disabled this also looks at the next expiring
                 * hrtimer.
                 */
-               next_tmr = get_next_timer_interrupt(basejiff, basemono);
-               ts->next_timer = next_tmr;
-               /* Take the next rcu event into account */
-               next_tick = next_rcu < next_tmr ? next_rcu : next_tmr;
+               next_tick = get_next_timer_interrupt(basejiff, basemono);
+               ts->next_timer = next_tick;
        }
 
        /*
@@ -984,6 +999,45 @@ static void tick_nohz_full_update_tick(struct tick_sched *ts)
        __tick_nohz_full_update_tick(ts, ktime_get());
 }
 
+/*
+ * A pending softirq outside an IRQ (or softirq disabled section) context
+ * should be waiting for ksoftirqd to handle it. Therefore we shouldn't
+ * reach here due to the need_resched() early check in can_stop_idle_tick().
+ *
+ * However if we are between CPUHP_AP_SMPBOOT_THREADS and CPU_TEARDOWN_CPU on the
+ * cpu_down() process, softirqs can still be raised while ksoftirqd is parked,
+ * triggering the below since wakep_softirqd() is ignored.
+ *
+ */
+static bool report_idle_softirq(void)
+{
+       static int ratelimit;
+       unsigned int pending = local_softirq_pending();
+
+       if (likely(!pending))
+               return false;
+
+       /* Some softirqs claim to be safe against hotplug and ksoftirqd parking */
+       if (!cpu_active(smp_processor_id())) {
+               pending &= ~SOFTIRQ_HOTPLUG_SAFE_MASK;
+               if (!pending)
+                       return false;
+       }
+
+       if (ratelimit < 10)
+               return false;
+
+       /* On RT, softirqs handling may be waiting on some lock */
+       if (!local_bh_blocked())
+               return false;
+
+       pr_warn("NOHZ tick-stop error: local softirq work is pending, handler #%02x!!!\n",
+               pending);
+       ratelimit++;
+
+       return true;
+}
+
 static bool can_stop_idle_tick(int cpu, struct tick_sched *ts)
 {
        /*
@@ -1010,17 +1064,8 @@ static bool can_stop_idle_tick(int cpu, struct tick_sched *ts)
        if (need_resched())
                return false;
 
-       if (unlikely(local_softirq_pending())) {
-               static int ratelimit;
-
-               if (ratelimit < 10 && !local_bh_blocked() &&
-                   (local_softirq_pending() & SOFTIRQ_STOP_IDLE_MASK)) {
-                       pr_warn("NOHZ tick-stop error: Non-RCU local softirq work is pending, handler #%02x!!!\n",
-                               (unsigned int) local_softirq_pending());
-                       ratelimit++;
-               }
+       if (unlikely(report_idle_softirq()))
                return false;
-       }
 
        if (tick_nohz_full_enabled()) {
                /*