]> Pileus Git - ~andy/linux/blobdiff - kernel/time/timekeeping.c
timekeeping: Avoid possible deadlock from clock_was_set_delayed
[~andy/linux] / kernel / time / timekeeping.c
index 051855fe68bcb560a21ebe71e5ad18483a75e8d5..d62682b6df4a57c3d4b024feaa1f764174851fa1 100644 (file)
@@ -1278,7 +1278,6 @@ static inline unsigned int accumulate_nsecs_to_secs(struct timekeeper *tk)
 
                        __timekeeping_set_tai_offset(tk, tk->tai_offset - leap);
 
-                       clock_was_set_delayed();
                        clock_set = TK_CLOCK_WAS_SET;
                }
        }
@@ -1442,6 +1441,19 @@ static void update_wall_time(void)
        write_seqcount_end(&timekeeper_seq);
 out:
        raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
+       if (clock_was_set) {
+               /*
+                * XXX -  I'd rather we just call clock_was_set(), but
+                * since we're currently holding the jiffies lock, calling
+                * clock_was_set would trigger an ipi which would then grab
+                * the jiffies lock and we'd deadlock. :(
+                * The right solution should probably be droping
+                * the jiffies lock before calling update_wall_time
+                * but that requires some rework of the tick sched
+                * code.
+                */
+               clock_was_set_delayed();
+       }
 }
 
 /**
@@ -1702,11 +1714,13 @@ int do_adjtimex(struct timex *txc)
        if (tai != orig_tai) {
                __timekeeping_set_tai_offset(tk, tai);
                timekeeping_update(tk, TK_MIRROR | TK_CLOCK_WAS_SET);
-               clock_was_set_delayed();
        }
        write_seqcount_end(&timekeeper_seq);
        raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
 
+       if (tai != orig_tai)
+               clock_was_set();
+
        ntp_notify_cmos_timer();
 
        return ret;