Skip to content

Commit

Permalink
time: export time information for KVM pvclock
Browse files Browse the repository at this point in the history
As suggested by John, export time data similarly to how its
done by vsyscall support. This allows KVM to retrieve necessary
information to implement vsyscall support in KVM guests.

Acked-by: John Stultz <[email protected]>
Signed-off-by: Marcelo Tosatti <[email protected]>
  • Loading branch information
matosatti committed Nov 28, 2012
1 parent 886b470 commit e0b306f
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 0 deletions.
9 changes: 9 additions & 0 deletions include/linux/pvclock_gtod.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#ifndef _PVCLOCK_GTOD_H
#define _PVCLOCK_GTOD_H

#include <linux/notifier.h>

extern int pvclock_gtod_register_notifier(struct notifier_block *nb);
extern int pvclock_gtod_unregister_notifier(struct notifier_block *nb);

#endif /* _PVCLOCK_GTOD_H */
50 changes: 50 additions & 0 deletions kernel/time/timekeeping.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <linux/time.h>
#include <linux/tick.h>
#include <linux/stop_machine.h>
#include <linux/pvclock_gtod.h>


static struct timekeeper timekeeper;
Expand Down Expand Up @@ -180,6 +181,54 @@ static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk)
return nsec + arch_gettimeoffset();
}

static RAW_NOTIFIER_HEAD(pvclock_gtod_chain);

static void update_pvclock_gtod(struct timekeeper *tk)
{
raw_notifier_call_chain(&pvclock_gtod_chain, 0, tk);
}

/**
* pvclock_gtod_register_notifier - register a pvclock timedata update listener
*
* Must hold write on timekeeper.lock
*/
int pvclock_gtod_register_notifier(struct notifier_block *nb)
{
struct timekeeper *tk = &timekeeper;
unsigned long flags;
int ret;

write_seqlock_irqsave(&tk->lock, flags);
ret = raw_notifier_chain_register(&pvclock_gtod_chain, nb);
/* update timekeeping data */
update_pvclock_gtod(tk);
write_sequnlock_irqrestore(&tk->lock, flags);

return ret;
}
EXPORT_SYMBOL_GPL(pvclock_gtod_register_notifier);

/**
* pvclock_gtod_unregister_notifier - unregister a pvclock
* timedata update listener
*
* Must hold write on timekeeper.lock
*/
int pvclock_gtod_unregister_notifier(struct notifier_block *nb)
{
struct timekeeper *tk = &timekeeper;
unsigned long flags;
int ret;

write_seqlock_irqsave(&tk->lock, flags);
ret = raw_notifier_chain_unregister(&pvclock_gtod_chain, nb);
write_sequnlock_irqrestore(&tk->lock, flags);

return ret;
}
EXPORT_SYMBOL_GPL(pvclock_gtod_unregister_notifier);

/* must hold write on timekeeper.lock */
static void timekeeping_update(struct timekeeper *tk, bool clearntp)
{
Expand All @@ -188,6 +237,7 @@ static void timekeeping_update(struct timekeeper *tk, bool clearntp)
ntp_clear();
}
update_vsyscall(tk);
update_pvclock_gtod(tk);
}

/**
Expand Down

0 comments on commit e0b306f

Please sign in to comment.