hrtimer: Provide clock_was_set_delayed()
clock_was_set() cannot be called from hard interrupt context because it calls on_each_cpu(). For fixing the widely reported leap seconds issue it is necessary to call it from hard interrupt context, i.e. the timer tick code, which does the timekeeping updates. Provide a new function which denotes it in the hrtimer cpu base structure of the cpu on which it is called and raise the hrtimer softirq. We then execute the clock_was_set() notificiation from softirq context in run_hrtimer_softirq(). The hrtimer softirq is rarely used, so polling the flag there is not a performance issue. [ tglx: Made it depend on CONFIG_HIGH_RES_TIMERS. We really should get rid of all this ifdeffery ASAP ] Signed-off-by: John Stultz <johnstul@us.ibm.com> Reported-by: Jan Engelhardt <jengelh@inai.de> Reviewed-by: Ingo Molnar <mingo@kernel.org> Acked-by: Peter Zijlstra <a.p.zijlstra@chello.nl> Acked-by: Prarit Bhargava <prarit@redhat.com> Cc: stable@vger.kernel.org Link: http://lkml.kernel.org/r/1341960205-56738-2-git-send-email-johnstul@us.ibm.com Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
		
					parent
					
						
							
								055c9fa887
							
						
					
				
			
			
				commit
				
					
						f55a6faa38
					
				
			
		
					 2 changed files with 28 additions and 1 deletions
				
			
		|  | @ -165,6 +165,7 @@ enum  hrtimer_base_type { | ||||||
|  * @lock:		lock protecting the base and associated clock bases |  * @lock:		lock protecting the base and associated clock bases | ||||||
|  *			and timers |  *			and timers | ||||||
|  * @active_bases:	Bitfield to mark bases with active timers |  * @active_bases:	Bitfield to mark bases with active timers | ||||||
|  |  * @clock_was_set:	Indicates that clock was set from irq context. | ||||||
|  * @expires_next:	absolute time of the next event which was scheduled |  * @expires_next:	absolute time of the next event which was scheduled | ||||||
|  *			via clock_set_next_event() |  *			via clock_set_next_event() | ||||||
|  * @hres_active:	State of high resolution mode |  * @hres_active:	State of high resolution mode | ||||||
|  | @ -177,7 +178,8 @@ enum  hrtimer_base_type { | ||||||
|  */ |  */ | ||||||
| struct hrtimer_cpu_base { | struct hrtimer_cpu_base { | ||||||
| 	raw_spinlock_t			lock; | 	raw_spinlock_t			lock; | ||||||
| 	unsigned long			active_bases; | 	unsigned int			active_bases; | ||||||
|  | 	unsigned int			clock_was_set; | ||||||
| #ifdef CONFIG_HIGH_RES_TIMERS | #ifdef CONFIG_HIGH_RES_TIMERS | ||||||
| 	ktime_t				expires_next; | 	ktime_t				expires_next; | ||||||
| 	int				hres_active; | 	int				hres_active; | ||||||
|  | @ -286,6 +288,8 @@ extern void hrtimer_peek_ahead_timers(void); | ||||||
| # define MONOTONIC_RES_NSEC	HIGH_RES_NSEC | # define MONOTONIC_RES_NSEC	HIGH_RES_NSEC | ||||||
| # define KTIME_MONOTONIC_RES	KTIME_HIGH_RES | # define KTIME_MONOTONIC_RES	KTIME_HIGH_RES | ||||||
| 
 | 
 | ||||||
|  | extern void clock_was_set_delayed(void); | ||||||
|  | 
 | ||||||
| #else | #else | ||||||
| 
 | 
 | ||||||
| # define MONOTONIC_RES_NSEC	LOW_RES_NSEC | # define MONOTONIC_RES_NSEC	LOW_RES_NSEC | ||||||
|  | @ -306,6 +310,9 @@ static inline int hrtimer_is_hres_active(struct hrtimer *timer) | ||||||
| { | { | ||||||
| 	return 0; | 	return 0; | ||||||
| } | } | ||||||
|  | 
 | ||||||
|  | static inline void clock_was_set_delayed(void) { } | ||||||
|  | 
 | ||||||
| #endif | #endif | ||||||
| 
 | 
 | ||||||
| extern void clock_was_set(void); | extern void clock_was_set(void); | ||||||
|  |  | ||||||
|  | @ -717,6 +717,19 @@ static int hrtimer_switch_to_hres(void) | ||||||
| 	return 1; | 	return 1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /*
 | ||||||
|  |  * Called from timekeeping code to reprogramm the hrtimer interrupt | ||||||
|  |  * device. If called from the timer interrupt context we defer it to | ||||||
|  |  * softirq context. | ||||||
|  |  */ | ||||||
|  | void clock_was_set_delayed(void) | ||||||
|  | { | ||||||
|  | 	struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); | ||||||
|  | 
 | ||||||
|  | 	cpu_base->clock_was_set = 1; | ||||||
|  | 	__raise_softirq_irqoff(HRTIMER_SOFTIRQ); | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #else | #else | ||||||
| 
 | 
 | ||||||
| static inline int hrtimer_hres_active(void) { return 0; } | static inline int hrtimer_hres_active(void) { return 0; } | ||||||
|  | @ -1395,6 +1408,13 @@ void hrtimer_peek_ahead_timers(void) | ||||||
| 
 | 
 | ||||||
| static void run_hrtimer_softirq(struct softirq_action *h) | static void run_hrtimer_softirq(struct softirq_action *h) | ||||||
| { | { | ||||||
|  | 	struct hrtimer_cpu_base *cpu_base = &__get_cpu_var(hrtimer_bases); | ||||||
|  | 
 | ||||||
|  | 	if (cpu_base->clock_was_set) { | ||||||
|  | 		cpu_base->clock_was_set = 0; | ||||||
|  | 		clock_was_set(); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	hrtimer_peek_ahead_timers(); | 	hrtimer_peek_ahead_timers(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 John Stultz
				John Stultz