}
 }
 
+#define MOD_TIMER_PENDING_ONLY         0x01
+#define MOD_TIMER_REDUCE               0x02
+
 static inline int
-__mod_timer(struct timer_list *timer, unsigned long expires, bool pending_only)
+__mod_timer(struct timer_list *timer, unsigned long expires, unsigned int options)
 {
        struct timer_base *base, *new_base;
        unsigned int idx = UINT_MAX;
                 * larger granularity than you would get from adding a new
                 * timer with this expiry.
                 */
-               if (timer->expires == expires)
+               long diff = timer->expires - expires;
+
+               if (!diff)
+                       return 1;
+               if (options & MOD_TIMER_REDUCE && diff <= 0)
                        return 1;
 
                /*
                base = lock_timer_base(timer, &flags);
                forward_timer_base(base);
 
+               if (timer_pending(timer) && (options & MOD_TIMER_REDUCE) &&
+                   time_before_eq(timer->expires, expires)) {
+                       ret = 1;
+                       goto out_unlock;
+               }
+
                clk = base->clk;
                idx = calc_wheel_index(expires, clk);
 
                 * subsequent call will exit in the expires check above.
                 */
                if (idx == timer_get_idx(timer)) {
-                       timer->expires = expires;
+                       if (!(options & MOD_TIMER_REDUCE))
+                               timer->expires = expires;
+                       else if (time_after(timer->expires, expires))
+                               timer->expires = expires;
                        ret = 1;
                        goto out_unlock;
                }
        }
 
        ret = detach_if_pending(timer, base, false);
-       if (!ret && pending_only)
+       if (!ret && (options & MOD_TIMER_PENDING_ONLY))
                goto out_unlock;
 
        debug_activate(timer, expires);
  */
 int mod_timer_pending(struct timer_list *timer, unsigned long expires)
 {
-       return __mod_timer(timer, expires, true);
+       return __mod_timer(timer, expires, MOD_TIMER_PENDING_ONLY);
 }
 EXPORT_SYMBOL(mod_timer_pending);
 
  */
 int mod_timer(struct timer_list *timer, unsigned long expires)
 {
-       return __mod_timer(timer, expires, false);
+       return __mod_timer(timer, expires, 0);
 }
 EXPORT_SYMBOL(mod_timer);
 
+/**
+ * timer_reduce - Modify a timer's timeout if it would reduce the timeout
+ * @timer:     The timer to be modified
+ * @expires:   New timeout in jiffies
+ *
+ * timer_reduce() is very similar to mod_timer(), except that it will only
+ * modify a running timer if that would reduce the expiration time (it will
+ * start a timer that isn't running).
+ */
+int timer_reduce(struct timer_list *timer, unsigned long expires)
+{
+       return __mod_timer(timer, expires, MOD_TIMER_REDUCE);
+}
+EXPORT_SYMBOL(timer_reduce);
+
 /**
  * add_timer - start a timer
  * @timer: the timer to be added
 
        timer.task = current;
        timer_setup_on_stack(&timer.timer, process_timeout, 0);
-       __mod_timer(&timer.timer, expire, false);
+       __mod_timer(&timer.timer, expire, 0);
        schedule();
        del_singleshot_timer_sync(&timer.timer);