* @nr_retries:                Total number of hrtimer interrupt retries
  * @nr_hangs:          Total number of hrtimer interrupt hangs
  * @max_hang_time:     Maximum time spent in hrtimer_interrupt
+ * @softirq_expiry_lock: Lock which is taken while softirq based hrtimer are
+ *                      expired
+ * @timer_waiters:     A hrtimer_cancel() invocation waits for the timer
+ *                     callback to finish.
  * @expires_next:      absolute time of the next event, is required for remote
  *                     hrtimer enqueue; it is the total first expiry time (hard
  *                     and soft hrtimer are taken into account)
        unsigned short                  nr_retries;
        unsigned short                  nr_hangs;
        unsigned int                    max_hang_time;
+#endif
+#ifdef CONFIG_PREEMPT_RT
+       spinlock_t                      softirq_expiry_lock;
+       atomic_t                        timer_waiters;
 #endif
        ktime_t                         expires_next;
        struct hrtimer                  *next_timer;
 
 DECLARE_PER_CPU(struct tick_device, tick_cpu_device);
 
+#ifdef CONFIG_PREEMPT_RT
+void hrtimer_cancel_wait_running(const struct hrtimer *timer);
+#else
+static inline void hrtimer_cancel_wait_running(struct hrtimer *timer)
+{
+       cpu_relax();
+}
+#endif
 
 /* Exported timer functions: */
 
 
 }
 EXPORT_SYMBOL_GPL(hrtimer_try_to_cancel);
 
+#ifdef CONFIG_PREEMPT_RT
+static void hrtimer_cpu_base_init_expiry_lock(struct hrtimer_cpu_base *base)
+{
+       spin_lock_init(&base->softirq_expiry_lock);
+}
+
+static void hrtimer_cpu_base_lock_expiry(struct hrtimer_cpu_base *base)
+{
+       spin_lock(&base->softirq_expiry_lock);
+}
+
+static void hrtimer_cpu_base_unlock_expiry(struct hrtimer_cpu_base *base)
+{
+       spin_unlock(&base->softirq_expiry_lock);
+}
+
+/*
+ * The counterpart to hrtimer_cancel_wait_running().
+ *
+ * If there is a waiter for cpu_base->expiry_lock, then it was waiting for
+ * the timer callback to finish. Drop expiry_lock and reaquire it. That
+ * allows the waiter to acquire the lock and make progress.
+ */
+static void hrtimer_sync_wait_running(struct hrtimer_cpu_base *cpu_base,
+                                     unsigned long flags)
+{
+       if (atomic_read(&cpu_base->timer_waiters)) {
+               raw_spin_unlock_irqrestore(&cpu_base->lock, flags);
+               spin_unlock(&cpu_base->softirq_expiry_lock);
+               spin_lock(&cpu_base->softirq_expiry_lock);
+               raw_spin_lock_irq(&cpu_base->lock);
+       }
+}
+
+/*
+ * This function is called on PREEMPT_RT kernels when the fast path
+ * deletion of a timer failed because the timer callback function was
+ * running.
+ *
+ * This prevents priority inversion, if the softirq thread on a remote CPU
+ * got preempted, and it prevents a life lock when the task which tries to
+ * delete a timer preempted the softirq thread running the timer callback
+ * function.
+ */
+void hrtimer_cancel_wait_running(const struct hrtimer *timer)
+{
+       struct hrtimer_clock_base *base = timer->base;
+
+       if (!timer->is_soft || !base || !base->cpu_base) {
+               cpu_relax();
+               return;
+       }
+
+       /*
+        * Mark the base as contended and grab the expiry lock, which is
+        * held by the softirq across the timer callback. Drop the lock
+        * immediately so the softirq can expire the next timer. In theory
+        * the timer could already be running again, but that's more than
+        * unlikely and just causes another wait loop.
+        */
+       atomic_inc(&base->cpu_base->timer_waiters);
+       spin_lock_bh(&base->cpu_base->softirq_expiry_lock);
+       atomic_dec(&base->cpu_base->timer_waiters);
+       spin_unlock_bh(&base->cpu_base->softirq_expiry_lock);
+}
+#else
+static inline void
+hrtimer_cpu_base_init_expiry_lock(struct hrtimer_cpu_base *base) { }
+static inline void
+hrtimer_cpu_base_lock_expiry(struct hrtimer_cpu_base *base) { }
+static inline void
+hrtimer_cpu_base_unlock_expiry(struct hrtimer_cpu_base *base) { }
+static inline void hrtimer_sync_wait_running(struct hrtimer_cpu_base *base,
+                                            unsigned long flags) { }
+#endif
+
 /**
  * hrtimer_cancel - cancel a timer and wait for the handler to finish.
  * @timer:     the timer to be cancelled
  */
 int hrtimer_cancel(struct hrtimer *timer)
 {
-       for (;;) {
-               int ret = hrtimer_try_to_cancel(timer);
+       int ret;
 
-               if (ret >= 0)
-                       return ret;
-               cpu_relax();
-       }
+       do {
+               ret = hrtimer_try_to_cancel(timer);
+
+               if (ret < 0)
+                       hrtimer_cancel_wait_running(timer);
+       } while (ret < 0);
+       return ret;
 }
 EXPORT_SYMBOL_GPL(hrtimer_cancel);
 
                                break;
 
                        __run_hrtimer(cpu_base, base, timer, &basenow, flags);
+                       if (active_mask == HRTIMER_ACTIVE_SOFT)
+                               hrtimer_sync_wait_running(cpu_base, flags);
                }
        }
 }
        unsigned long flags;
        ktime_t now;
 
+       hrtimer_cpu_base_lock_expiry(cpu_base);
        raw_spin_lock_irqsave(&cpu_base->lock, flags);
 
        now = hrtimer_update_base(cpu_base);
        hrtimer_update_softirq_timer(cpu_base, true);
 
        raw_spin_unlock_irqrestore(&cpu_base->lock, flags);
+       hrtimer_cpu_base_unlock_expiry(cpu_base);
 }
 
 #ifdef CONFIG_HIGH_RES_TIMERS
        cpu_base->softirq_next_timer = NULL;
        cpu_base->expires_next = KTIME_MAX;
        cpu_base->softirq_expires_next = KTIME_MAX;
+       hrtimer_cpu_base_init_expiry_lock(cpu_base);
        return 0;
 }