Skip to content

Commit 5258d3f

Browse files
timekeeping: Fix potential lost pv notification of time change
In 780427f (Indicate that clock was set in the pvclock gtod notifier), logic was added to pass a CLOCK_WAS_SET notification to the pvclock notifier chain. While that patch added a action flag returned from accumulate_nsecs_to_secs(), it only uses the returned value in one location, and not in the logarithmic accumulation. This means if a leap second triggered during the logarithmic accumulation (which is most likely where it would happen), the notification that the clock was set would not make it to the pv notifiers. This patch extends the logarithmic_accumulation pass down that action flag so proper notification will occur. This patch also changes the varialbe action -> clock_set per Ingo's suggestion. Cc: Sasha Levin <sasha.levin@oracle.com> Cc: Thomas Gleixner <tglx@linutronix.de> Cc: Ingo Molnar <mingo@kernel.org> Cc: David Vrabel <david.vrabel@citrix.com> Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Cc: Prarit Bhargava <prarit@redhat.com> Cc: Richard Cochran <richardcochran@gmail.com> Cc: <xen-devel@lists.xen.org> Cc: stable <stable@vger.kernel.org> #3.11+ Signed-off-by: John Stultz <john.stultz@linaro.org>
1 parent f55c076 commit 5258d3f

File tree

1 file changed

+11
-9
lines changed

1 file changed

+11
-9
lines changed

kernel/time/timekeeping.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1256,7 +1256,7 @@ static void timekeeping_adjust(struct timekeeper *tk, s64 offset)
12561256
static inline unsigned int accumulate_nsecs_to_secs(struct timekeeper *tk)
12571257
{
12581258
u64 nsecps = (u64)NSEC_PER_SEC << tk->shift;
1259-
unsigned int action = 0;
1259+
unsigned int clock_set = 0;
12601260

12611261
while (tk->xtime_nsec >= nsecps) {
12621262
int leap;
@@ -1279,10 +1279,10 @@ static inline unsigned int accumulate_nsecs_to_secs(struct timekeeper *tk)
12791279
__timekeeping_set_tai_offset(tk, tk->tai_offset - leap);
12801280

12811281
clock_was_set_delayed();
1282-
action = TK_CLOCK_WAS_SET;
1282+
clock_set = TK_CLOCK_WAS_SET;
12831283
}
12841284
}
1285-
return action;
1285+
return clock_set;
12861286
}
12871287

12881288
/**
@@ -1295,7 +1295,8 @@ static inline unsigned int accumulate_nsecs_to_secs(struct timekeeper *tk)
12951295
* Returns the unconsumed cycles.
12961296
*/
12971297
static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset,
1298-
u32 shift)
1298+
u32 shift,
1299+
unsigned int *clock_set)
12991300
{
13001301
cycle_t interval = tk->cycle_interval << shift;
13011302
u64 raw_nsecs;
@@ -1309,7 +1310,7 @@ static cycle_t logarithmic_accumulation(struct timekeeper *tk, cycle_t offset,
13091310
tk->cycle_last += interval;
13101311

13111312
tk->xtime_nsec += tk->xtime_interval << shift;
1312-
accumulate_nsecs_to_secs(tk);
1313+
*clock_set |= accumulate_nsecs_to_secs(tk);
13131314

13141315
/* Accumulate raw time */
13151316
raw_nsecs = (u64)tk->raw_interval << shift;
@@ -1367,7 +1368,7 @@ static void update_wall_time(void)
13671368
struct timekeeper *tk = &shadow_timekeeper;
13681369
cycle_t offset;
13691370
int shift = 0, maxshift;
1370-
unsigned int action;
1371+
unsigned int clock_set = 0;
13711372
unsigned long flags;
13721373

13731374
raw_spin_lock_irqsave(&timekeeper_lock, flags);
@@ -1402,7 +1403,8 @@ static void update_wall_time(void)
14021403
maxshift = (64 - (ilog2(ntp_tick_length())+1)) - 1;
14031404
shift = min(shift, maxshift);
14041405
while (offset >= tk->cycle_interval) {
1405-
offset = logarithmic_accumulation(tk, offset, shift);
1406+
offset = logarithmic_accumulation(tk, offset, shift,
1407+
&clock_set);
14061408
if (offset < tk->cycle_interval<<shift)
14071409
shift--;
14081410
}
@@ -1420,7 +1422,7 @@ static void update_wall_time(void)
14201422
* Finally, make sure that after the rounding
14211423
* xtime_nsec isn't larger than NSEC_PER_SEC
14221424
*/
1423-
action = accumulate_nsecs_to_secs(tk);
1425+
clock_set |= accumulate_nsecs_to_secs(tk);
14241426

14251427
write_seqcount_begin(&timekeeper_seq);
14261428
/* Update clock->cycle_last with the new value */
@@ -1436,7 +1438,7 @@ static void update_wall_time(void)
14361438
* updating.
14371439
*/
14381440
memcpy(real_tk, tk, sizeof(*tk));
1439-
timekeeping_update(real_tk, action);
1441+
timekeeping_update(real_tk, clock_set);
14401442
write_seqcount_end(&timekeeper_seq);
14411443
out:
14421444
raw_spin_unlock_irqrestore(&timekeeper_lock, flags);

0 commit comments

Comments
 (0)