--- kernel-3.10.0-1160.6.1.el7/linux-3.10.0-1160.6.1.el7.x86_64/kernel/timer.c	2020-10-21 13:17:08.000000000 -0400
+++ kernel-3.10.0-1160.11.1.el7/linux-3.10.0-1160.11.1.el7.x86_64/kernel/timer.c	2020-11-30 12:40:05.000000000 -0500
@@ -1213,6 +1213,95 @@
 	}
 }
 
+/*
+ * Total number of list_head entries in tv1-tv5 of struct tvec_base.
+ */
+#define TVEC_LEN	((offsetofend(struct tvec_base, tv5) -	\
+			  offsetof(struct tvec_base, tv1)) /	\
+			  sizeof(struct list_head))
+
+/**
+ * requeue_timers - requeue all the timers in the timer wheel
+ * @base: the timer vector to be processed.
+ *
+ * When a cpu is idle for a long period of time, it is possible that
+ * timer_jiffies can significantly lag behind jiffies making the iterative
+ * jiffies check in __run_timers() takes a long time to complete causing
+ * soft or hard system lockup.
+ *
+ * This function remedies this situation by requeuing all the timers in
+ * the cascading timer wheel and adjusting timer_jiffies to the min() of
+ * current jiffies and the expiry times of all active timers. The expiry
+ * times of expired deferrable timers will be set to the new timer_jiffies.
+ */
+static noinline void requeue_timers(struct tvec_base *base)
+{
+	struct timer_list *timer, *tmp;
+	struct list_head list, head, *vecs;
+	unsigned long min_jiffies = jiffies;
+	unsigned long nactive = base->active_timers;
+	unsigned long nall = base->all_timers;
+	int i;
+
+	lockdep_assert_held(&base->lock);
+	INIT_LIST_HEAD(&head);
+
+	/*
+	 * tv1-tv5 are processed together as a single array of list_head's.
+	 */
+	vecs = (struct list_head *)&base->tv1;
+	for (i = 0; i < TVEC_LEN; i++, vecs++) {
+		if (list_empty(vecs))
+			continue;
+
+		list_replace_init(vecs, &list);
+
+		/*
+		 * Check all the timers in list and move them over to head.
+		 */
+		list_for_each_entry_safe(timer, tmp, &list, entry) {
+			base->all_timers--;
+			if (!tbase_get_deferrable(timer->base)) {
+				base->active_timers--;
+				if (time_before(timer->expires, min_jiffies))
+					min_jiffies = timer->expires;
+			}
+			list_add_tail(&timer->entry, &head);
+		}
+		if (!base->all_timers)
+			break;
+	}
+	WARN_ON_ONCE(base->all_timers || base->active_timers);
+
+	/*
+	 * Restore all_timers and active_timers.
+	 * Requeue timers back into timer wheel with timer_jiffies
+	 * set to min_jiffies.
+	 */
+	base->all_timers = nall;
+	base->active_timers = nactive;
+	base->timer_jiffies = min_jiffies;
+
+	list_for_each_entry_safe(timer, tmp, &head, entry) {
+		unsigned long old_expires;
+		bool restore = false;
+
+		/*
+		 * For expiry time that is < min_jiffies (deferrable ones),
+		 * temporarily change it to min_jiffies, insert the timer
+		 * without accounting and restore the expiry time.
+		 */
+		if (time_before(timer->expires, min_jiffies)) {
+			old_expires = timer->expires;
+			timer->expires = min_jiffies;
+			restore = true;
+		}
+		__internal_add_timer(base, timer);
+		if (restore)
+			timer->expires = old_expires;
+	}
+}
+
 #define INDEX(N) ((base->timer_jiffies >> (TVR_BITS + (N) * TVN_BITS)) & TVN_MASK)
 
 /**
@@ -1228,6 +1317,13 @@
 
 	spin_lock_irq(&base->lock);
 
+	/*
+	 * Requeue the timers if jiffies - timer_jiffies >= 2*TVEC_LEN.
+	 */
+	if (base->all_timers &&
+	    time_after_eq(jiffies, base->timer_jiffies + 2 * TVEC_LEN))
+		requeue_timers(base);
+
 	while (time_after_eq(jiffies, base->timer_jiffies)) {
 		struct list_head work_list;
 		struct list_head *head = &work_list;
