This notifier will fire when clocksource is changed or any properties of the clocksource are changed which alter the clocksource nature, for example its stability property Signed-off-by: Denis Plotnikov <dplotnikov@xxxxxxxxxxxxx> --- include/linux/cs_notifier.h | 17 +++++++++++++++ kernel/time/timekeeping.c | 51 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) create mode 100644 include/linux/cs_notifier.h diff --git a/include/linux/cs_notifier.h b/include/linux/cs_notifier.h new file mode 100644 index 0000000..2b1b4e6 --- /dev/null +++ b/include/linux/cs_notifier.h @@ -0,0 +1,17 @@ +#ifndef _CS_CHANGES_H +#define _CS_CHANGES_H + +#include <linux/notifier.h> + +/* + * The clocksource changes notifier is called when the system + * clocksource is changed or some properties of the current + * system clocksource is changed that can affect other parts of the system, + * for example KVM guests + */ + +extern void clocksource_changes_notify(void); +extern int clocksource_changes_register_notifier(struct notifier_block *nb); +extern int clocksource_changes_unregister_notifier(struct notifier_block *nb); + +#endif /* _CS_CHANGES_H */ diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index b6d7882..1cef214 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -592,6 +592,55 @@ int pvclock_gtod_unregister_notifier(struct notifier_block *nb) } EXPORT_SYMBOL_GPL(pvclock_gtod_unregister_notifier); +/* notification chain when there is some changes in the clocksource */ +static RAW_NOTIFIER_HEAD(clocksource_changes_chain); + +/** + * notify_clocksource_changing - notify all the listeners about changes + * happened in the clocksource: changing a clocksource, changing the sensitive + * parameters of the clocksource, e.g. stability flag for kvmclock + */ +void clocksource_changes_notify(void) +{ + raw_notifier_call_chain(&clocksource_changes_chain, 0L, NULL); +} +EXPORT_SYMBOL_GPL(clocksource_changes_notify); + +/** + * clocksource_changes_register_notifier - register + * a clocksource changes listener + */ +int clocksource_changes_register_notifier(struct notifier_block *nb) +{ + unsigned long flags; + int ret; + + raw_spin_lock_irqsave(&timekeeper_lock, flags); + ret = raw_notifier_chain_register(&clocksource_changes_chain, nb); + clocksource_changes_notify(); + raw_spin_unlock_irqrestore(&timekeeper_lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(clocksource_changes_register_notifier); + +/** + * clocksource_changes_unregister_notifier - unregister + * a clocksource changes listener + */ +int clocksource_changes_unregister_notifier(struct notifier_block *nb) +{ + unsigned long flags; + int ret; + + raw_spin_lock_irqsave(&timekeeper_lock, flags); + ret = raw_notifier_chain_unregister(&clocksource_changes_chain, nb); + raw_spin_unlock_irqrestore(&timekeeper_lock, flags); + + return ret; +} +EXPORT_SYMBOL_GPL(clocksource_changes_unregister_notifier); + /* * tk_update_leap_state - helper to update the next_leap_ktime */ @@ -1342,6 +1391,7 @@ static int change_clocksource(void *data) } } timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET); + clocksource_changes_notify(); write_seqcount_end(&tk_core.seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); @@ -1521,6 +1571,7 @@ void __init timekeeping_init(void) tk_set_wall_to_mono(tk, tmp); timekeeping_update(tk, TK_MIRROR | TK_CLOCK_WAS_SET); + clocksource_changes_notify(); write_seqcount_end(&tk_core.seq); raw_spin_unlock_irqrestore(&timekeeper_lock, flags); -- 2.7.4