aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorMarcelo Tosatti <mtosatti@redhat.com>2012-11-27 20:28:59 -0500
committerMarcelo Tosatti <mtosatti@redhat.com>2012-11-27 20:29:12 -0500
commite0b306fef90556233797d2e1747bd6a3ae35ea93 (patch)
tree0340c76e923fc02a47e5be8bd88c1d75ee0a84f1 /kernel
parent886b470cb14733a0286e365c77f1844c240c33a4 (diff)
time: export time information for KVM pvclock
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 <johnstul@us.ibm.com> Signed-off-by: Marcelo Tosatti <mtosatti@redhat.com>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/time/timekeeping.c50
1 files changed, 50 insertions, 0 deletions
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index e424970bb562..69f5342e8d1c 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -21,6 +21,7 @@
21#include <linux/time.h> 21#include <linux/time.h>
22#include <linux/tick.h> 22#include <linux/tick.h>
23#include <linux/stop_machine.h> 23#include <linux/stop_machine.h>
24#include <linux/pvclock_gtod.h>
24 25
25 26
26static struct timekeeper timekeeper; 27static struct timekeeper timekeeper;
@@ -180,6 +181,54 @@ static inline s64 timekeeping_get_ns_raw(struct timekeeper *tk)
180 return nsec + arch_gettimeoffset(); 181 return nsec + arch_gettimeoffset();
181} 182}
182 183
184static RAW_NOTIFIER_HEAD(pvclock_gtod_chain);
185
186static void update_pvclock_gtod(struct timekeeper *tk)
187{
188 raw_notifier_call_chain(&pvclock_gtod_chain, 0, tk);
189}
190
191/**
192 * pvclock_gtod_register_notifier - register a pvclock timedata update listener
193 *
194 * Must hold write on timekeeper.lock
195 */
196int pvclock_gtod_register_notifier(struct notifier_block *nb)
197{
198 struct timekeeper *tk = &timekeeper;
199 unsigned long flags;
200 int ret;
201
202 write_seqlock_irqsave(&tk->lock, flags);
203 ret = raw_notifier_chain_register(&pvclock_gtod_chain, nb);
204 /* update timekeeping data */
205 update_pvclock_gtod(tk);
206 write_sequnlock_irqrestore(&tk->lock, flags);
207
208 return ret;
209}
210EXPORT_SYMBOL_GPL(pvclock_gtod_register_notifier);
211
212/**
213 * pvclock_gtod_unregister_notifier - unregister a pvclock
214 * timedata update listener
215 *
216 * Must hold write on timekeeper.lock
217 */
218int pvclock_gtod_unregister_notifier(struct notifier_block *nb)
219{
220 struct timekeeper *tk = &timekeeper;
221 unsigned long flags;
222 int ret;
223
224 write_seqlock_irqsave(&tk->lock, flags);
225 ret = raw_notifier_chain_unregister(&pvclock_gtod_chain, nb);
226 write_sequnlock_irqrestore(&tk->lock, flags);
227
228 return ret;
229}
230EXPORT_SYMBOL_GPL(pvclock_gtod_unregister_notifier);
231
183/* must hold write on timekeeper.lock */ 232/* must hold write on timekeeper.lock */
184static void timekeeping_update(struct timekeeper *tk, bool clearntp) 233static void timekeeping_update(struct timekeeper *tk, bool clearntp)
185{ 234{
@@ -188,6 +237,7 @@ static void timekeeping_update(struct timekeeper *tk, bool clearntp)
188 ntp_clear(); 237 ntp_clear();
189 } 238 }
190 update_vsyscall(tk); 239 update_vsyscall(tk);
240 update_pvclock_gtod(tk);
191} 241}
192 242
193/** 243/**