Skip to content

Commit 780427f

Browse files
David VrabelKAGA-KOKO
authored andcommitted
timekeeping: Indicate that clock was set in the pvclock gtod notifier
If the clock was set (stepped), set the action parameter to functions in the pvclock gtod notifier chain to non-zero. This allows the callee to only do work if the clock was stepped. This will be used on Xen as the synchronization of the Xen wallclock to the control domain's (dom0) system time will be done with this notifier and updating on every timer tick is unnecessary and too expensive. Signed-off-by: David Vrabel <david.vrabel@citrix.com> Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> Cc: John Stultz <john.stultz@linaro.org> Cc: <xen-devel@lists.xen.org> Link: http://lkml.kernel.org/r/1372329348-20841-4-git-send-email-david.vrabel@citrix.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
1 parent 04397fe commit 780427f

File tree

2 files changed

+25
-12
lines changed

2 files changed

+25
-12
lines changed

include/linux/pvclock_gtod.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@
33

44
#include <linux/notifier.h>
55

6+
/*
7+
* The pvclock gtod notifier is called when the system time is updated
8+
* and is used to keep guest time synchronized with host time.
9+
*
10+
* The 'action' parameter in the notifier function is false (0), or
11+
* true (non-zero) if system time was stepped.
12+
*/
613
extern int pvclock_gtod_register_notifier(struct notifier_block *nb);
714
extern int pvclock_gtod_unregister_notifier(struct notifier_block *nb);
815

kernel/time/timekeeping.c

Lines changed: 18 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
#define TK_CLEAR_NTP (1 << 0)
3131
#define TK_MIRROR (1 << 1)
32+
#define TK_CLOCK_WAS_SET (1 << 2)
3233

3334
static struct timekeeper timekeeper;
3435
static DEFINE_RAW_SPINLOCK(timekeeper_lock);
@@ -204,9 +205,9 @@ static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk)
204205

205206
static RAW_NOTIFIER_HEAD(pvclock_gtod_chain);
206207

207-
static void update_pvclock_gtod(struct timekeeper *tk)
208+
static void update_pvclock_gtod(struct timekeeper *tk, bool was_set)
208209
{
209-
raw_notifier_call_chain(&pvclock_gtod_chain, 0, tk);
210+
raw_notifier_call_chain(&pvclock_gtod_chain, was_set, tk);
210211
}
211212

212213
/**
@@ -220,7 +221,7 @@ int pvclock_gtod_register_notifier(struct notifier_block *nb)
220221

221222
raw_spin_lock_irqsave(&timekeeper_lock, flags);
222223
ret = raw_notifier_chain_register(&pvclock_gtod_chain, nb);
223-
update_pvclock_gtod(tk);
224+
update_pvclock_gtod(tk, true);
224225
raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
225226

226227
return ret;
@@ -252,7 +253,7 @@ static void timekeeping_update(struct timekeeper *tk, unsigned int action)
252253
ntp_clear();
253254
}
254255
update_vsyscall(tk);
255-
update_pvclock_gtod(tk);
256+
update_pvclock_gtod(tk, action & TK_CLOCK_WAS_SET);
256257

257258
if (action & TK_MIRROR)
258259
memcpy(&shadow_timekeeper, &timekeeper, sizeof(timekeeper));
@@ -512,7 +513,7 @@ int do_settimeofday(const struct timespec *tv)
512513

513514
tk_set_xtime(tk, tv);
514515

515-
timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR);
516+
timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET);
516517

517518
write_seqcount_end(&timekeeper_seq);
518519
raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
@@ -556,7 +557,7 @@ int timekeeping_inject_offset(struct timespec *ts)
556557
tk_set_wall_to_mono(tk, timespec_sub(tk->wall_to_monotonic, *ts));
557558

558559
error: /* even if we error out, we forwarded the time, so call update */
559-
timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR);
560+
timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET);
560561

561562
write_seqcount_end(&timekeeper_seq);
562563
raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
@@ -646,7 +647,7 @@ static int change_clocksource(void *data)
646647
module_put(new->owner);
647648
}
648649
}
649-
timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR);
650+
timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET);
650651

651652
write_seqcount_end(&timekeeper_seq);
652653
raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
@@ -887,7 +888,7 @@ void timekeeping_inject_sleeptime(struct timespec *delta)
887888

888889
__timekeeping_inject_sleeptime(tk, delta);
889890

890-
timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR);
891+
timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET);
891892

892893
write_seqcount_end(&timekeeper_seq);
893894
raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
@@ -969,7 +970,7 @@ static void timekeeping_resume(void)
969970
tk->cycle_last = clock->cycle_last = cycle_now;
970971
tk->ntp_error = 0;
971972
timekeeping_suspended = 0;
972-
timekeeping_update(tk, TK_MIRROR);
973+
timekeeping_update(tk, TK_MIRROR | TK_CLOCK_WAS_SET);
973974
write_seqcount_end(&timekeeper_seq);
974975
raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
975976

@@ -1243,9 +1244,10 @@ static void timekeeping_adjust(struct timekeeper *tk, s64 offset)
12431244
* It also calls into the NTP code to handle leapsecond processing.
12441245
*
12451246
*/
1246-
static inline void accumulate_nsecs_to_secs(struct timekeeper *tk)
1247+
static inline unsigned int accumulate_nsecs_to_secs(struct timekeeper *tk)
12471248
{
12481249
u64 nsecps = (u64)NSEC_PER_SEC << tk->shift;
1250+
unsigned int action = 0;
12491251

12501252
while (tk->xtime_nsec >= nsecps) {
12511253
int leap;
@@ -1268,8 +1270,10 @@ static inline void accumulate_nsecs_to_secs(struct timekeeper *tk)
12681270
__timekeeping_set_tai_offset(tk, tk->tai_offset - leap);
12691271

12701272
clock_was_set_delayed();
1273+
action = TK_CLOCK_WAS_SET;
12711274
}
12721275
}
1276+
return action;
12731277
}
12741278

12751279
/**
@@ -1354,6 +1358,7 @@ static void update_wall_time(void)
13541358
struct timekeeper *tk = &shadow_timekeeper;
13551359
cycle_t offset;
13561360
int shift = 0, maxshift;
1361+
unsigned int action;
13571362
unsigned long flags;
13581363

13591364
raw_spin_lock_irqsave(&timekeeper_lock, flags);
@@ -1406,7 +1411,7 @@ static void update_wall_time(void)
14061411
* Finally, make sure that after the rounding
14071412
* xtime_nsec isn't larger than NSEC_PER_SEC
14081413
*/
1409-
accumulate_nsecs_to_secs(tk);
1414+
action = accumulate_nsecs_to_secs(tk);
14101415

14111416
write_seqcount_begin(&timekeeper_seq);
14121417
/* Update clock->cycle_last with the new value */
@@ -1422,7 +1427,7 @@ static void update_wall_time(void)
14221427
* updating.
14231428
*/
14241429
memcpy(real_tk, tk, sizeof(*tk));
1425-
timekeeping_update(real_tk, 0);
1430+
timekeeping_update(real_tk, action);
14261431
write_seqcount_end(&timekeeper_seq);
14271432
out:
14281433
raw_spin_unlock_irqrestore(&timekeeper_lock, flags);
@@ -1684,6 +1689,7 @@ int do_adjtimex(struct timex *txc)
16841689

16851690
if (tai != orig_tai) {
16861691
__timekeeping_set_tai_offset(tk, tai);
1692+
update_pvclock_gtod(tk, true);
16871693
clock_was_set_delayed();
16881694
}
16891695
write_seqcount_end(&timekeeper_seq);

0 commit comments

Comments
 (0)