/**
  * __timer_delete - Internal function: Deactivate a timer
  * @timer:     The timer to be deactivated
+ * @shutdown:  If true, this indicates that the timer is about to be
+ *             shutdown permanently.
+ *
+ * If @shutdown is true then @timer->function is set to NULL under the
+ * timer base lock which prevents further rearming of the time. In that
+ * case any attempt to rearm @timer after this function returns will be
+ * silently ignored.
  *
  * Return:
  * * %0 - The timer was not pending
  * * %1 - The timer was pending and deactivated
  */
-static int __timer_delete(struct timer_list *timer)
+static int __timer_delete(struct timer_list *timer, bool shutdown)
 {
        struct timer_base *base;
        unsigned long flags;
 
        debug_assert_init(timer);
 
-       if (timer_pending(timer)) {
+       /*
+        * If @shutdown is set then the lock has to be taken whether the
+        * timer is pending or not to protect against a concurrent rearm
+        * which might hit between the lockless pending check and the lock
+        * aquisition. By taking the lock it is ensured that such a newly
+        * enqueued timer is dequeued and cannot end up with
+        * timer->function == NULL in the expiry code.
+        *
+        * If timer->function is currently executed, then this makes sure
+        * that the callback cannot requeue the timer.
+        */
+       if (timer_pending(timer) || shutdown) {
                base = lock_timer_base(timer, &flags);
                ret = detach_if_pending(timer, base, true);
+               if (shutdown)
+                       timer->function = NULL;
                raw_spin_unlock_irqrestore(&base->lock, flags);
        }
 
  */
 int timer_delete(struct timer_list *timer)
 {
-       return __timer_delete(timer);
+       return __timer_delete(timer, false);
 }
 EXPORT_SYMBOL(timer_delete);
 
 /**
  * __try_to_del_timer_sync - Internal function: Try to deactivate a timer
  * @timer:     Timer to deactivate
+ * @shutdown:  If true, this indicates that the timer is about to be
+ *             shutdown permanently.
+ *
+ * If @shutdown is true then @timer->function is set to NULL under the
+ * timer base lock which prevents further rearming of the timer. Any
+ * attempt to rearm @timer after this function returns will be silently
+ * ignored.
+ *
+ * This function cannot guarantee that the timer cannot be rearmed
+ * right after dropping the base lock if @shutdown is false. That
+ * needs to be prevented by the calling code if necessary.
  *
  * Return:
  * * %0  - The timer was not pending
  * * %1  - The timer was pending and deactivated
  * * %-1 - The timer callback function is running on a different CPU
  */
-static int __try_to_del_timer_sync(struct timer_list *timer)
+static int __try_to_del_timer_sync(struct timer_list *timer, bool shutdown)
 {
        struct timer_base *base;
        unsigned long flags;
 
        if (base->running_timer != timer)
                ret = detach_if_pending(timer, base, true);
+       if (shutdown)
+               timer->function = NULL;
 
        raw_spin_unlock_irqrestore(&base->lock, flags);
 
  */
 int try_to_del_timer_sync(struct timer_list *timer)
 {
-       return __try_to_del_timer_sync(timer);
+       return __try_to_del_timer_sync(timer, false);
 }
 EXPORT_SYMBOL(try_to_del_timer_sync);
 
  * __timer_delete_sync - Internal function: Deactivate a timer and wait
  *                      for the handler to finish.
  * @timer:     The timer to be deactivated
+ * @shutdown:  If true, @timer->function will be set to NULL under the
+ *             timer base lock which prevents rearming of @timer
+ *
+ * If @shutdown is not set the timer can be rearmed later. If the timer can
+ * be rearmed concurrently, i.e. after dropping the base lock then the
+ * return value is meaningless.
+ *
+ * If @shutdown is set then @timer->function is set to NULL under timer
+ * base lock which prevents rearming of the timer. Any attempt to rearm
+ * a shutdown timer is silently ignored.
+ *
+ * If the timer should be reused after shutdown it has to be initialized
+ * again.
  *
  * Return:
  * * %0        - The timer was not pending
  * * %1        - The timer was pending and deactivated
  */
-static int __timer_delete_sync(struct timer_list *timer)
+static int __timer_delete_sync(struct timer_list *timer, bool shutdown)
 {
        int ret;
 
                lockdep_assert_preemption_enabled();
 
        do {
-               ret = __try_to_del_timer_sync(timer);
+               ret = __try_to_del_timer_sync(timer, shutdown);
 
                if (unlikely(ret < 0)) {
                        del_timer_wait_running(timer);
  */
 int timer_delete_sync(struct timer_list *timer)
 {
-       return __timer_delete_sync(timer);
+       return __timer_delete_sync(timer, false);
 }
 EXPORT_SYMBOL(timer_delete_sync);