diff options
Diffstat (limited to 'kernel/time/tick-sched.c')
| -rw-r--r-- | kernel/time/tick-sched.c | 87 | 
1 files changed, 38 insertions, 49 deletions
| diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index c792429e98c6..7c7ec4515983 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -197,27 +197,9 @@ static bool can_stop_full_tick(void)  	return true;  } -static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now); - -/* - * Re-evaluate the need for the tick on the current CPU - * and restart it if necessary. - */ -void __tick_nohz_full_check(void) -{ -	struct tick_sched *ts = this_cpu_ptr(&tick_cpu_sched); - -	if (tick_nohz_full_cpu(smp_processor_id())) { -		if (ts->tick_stopped && !is_idle_task(current)) { -			if (!can_stop_full_tick()) -				tick_nohz_restart_sched_tick(ts, ktime_get()); -		} -	} -} -  static void nohz_full_kick_work_func(struct irq_work *work)  { -	__tick_nohz_full_check(); +	/* Empty, the tick restart happens on tick_nohz_irq_exit() */  }  static DEFINE_PER_CPU(struct irq_work, nohz_full_kick_work) = { @@ -252,7 +234,7 @@ void tick_nohz_full_kick_cpu(int cpu)  static void nohz_full_kick_ipi(void *info)  { -	__tick_nohz_full_check(); +	/* Empty, the tick restart happens on tick_nohz_irq_exit() */  }  /* @@ -276,7 +258,7 @@ void tick_nohz_full_kick_all(void)   * It might need the tick due to per task/process properties:   * perf events, posix cpu timers, ...   */ -void __tick_nohz_task_switch(struct task_struct *tsk) +void __tick_nohz_task_switch(void)  {  	unsigned long flags; @@ -308,16 +290,17 @@ static int __init tick_nohz_full_setup(char *str)  __setup("nohz_full=", tick_nohz_full_setup);  static int tick_nohz_cpu_down_callback(struct notifier_block *nfb, -						 unsigned long action, -						 void *hcpu) +				       unsigned long action, +				       void *hcpu)  {  	unsigned int cpu = (unsigned long)hcpu;  	switch (action & ~CPU_TASKS_FROZEN) {  	case CPU_DOWN_PREPARE:  		/* -		 * If we handle the timekeeping duty for full dynticks CPUs, -		 * we can't safely shutdown that CPU. +		 * The boot CPU handles housekeeping duty (unbound timers, +		 * workqueues, timekeeping, ...) on behalf of full dynticks +		 * CPUs. It must remain online when nohz full is enabled.  		 */  		if (tick_nohz_full_running && tick_do_timer_cpu == cpu)  			return NOTIFY_BAD; @@ -388,6 +371,12 @@ void __init tick_nohz_init(void)  	cpu_notifier(tick_nohz_cpu_down_callback, 0);  	pr_info("NO_HZ: Full dynticks CPUs: %*pbl.\n",  		cpumask_pr_args(tick_nohz_full_mask)); + +	/* +	 * We need at least one CPU to handle housekeeping work such +	 * as timekeeping, unbound timers, workqueues, ... +	 */ +	WARN_ON_ONCE(cpumask_empty(housekeeping_mask));  }  #endif @@ -705,21 +694,38 @@ out:  	return tick;  } -static void tick_nohz_full_stop_tick(struct tick_sched *ts) +static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now) +{ +	/* Update jiffies first */ +	tick_do_update_jiffies64(now); +	update_cpu_load_nohz(); + +	calc_load_exit_idle(); +	touch_softlockup_watchdog(); +	/* +	 * Cancel the scheduled timer and restore the tick +	 */ +	ts->tick_stopped  = 0; +	ts->idle_exittime = now; + +	tick_nohz_restart(ts, now); +} + +static void tick_nohz_full_update_tick(struct tick_sched *ts)  {  #ifdef CONFIG_NO_HZ_FULL  	int cpu = smp_processor_id(); -	if (!tick_nohz_full_cpu(cpu) || is_idle_task(current)) +	if (!tick_nohz_full_cpu(cpu))  		return;  	if (!ts->tick_stopped && ts->nohz_mode == NOHZ_MODE_INACTIVE)  		return; -	if (!can_stop_full_tick()) -		return; - -	tick_nohz_stop_sched_tick(ts, ktime_get(), cpu); +	if (can_stop_full_tick()) +		tick_nohz_stop_sched_tick(ts, ktime_get(), cpu); +	else if (ts->tick_stopped) +		tick_nohz_restart_sched_tick(ts, ktime_get());  #endif  } @@ -849,7 +855,7 @@ void tick_nohz_irq_exit(void)  	if (ts->inidle)  		__tick_nohz_idle_enter(ts);  	else -		tick_nohz_full_stop_tick(ts); +		tick_nohz_full_update_tick(ts);  }  /** @@ -864,23 +870,6 @@ ktime_t tick_nohz_get_sleep_length(void)  	return ts->sleep_length;  } -static void tick_nohz_restart_sched_tick(struct tick_sched *ts, ktime_t now) -{ -	/* Update jiffies first */ -	tick_do_update_jiffies64(now); -	update_cpu_load_nohz(); - -	calc_load_exit_idle(); -	touch_softlockup_watchdog(); -	/* -	 * Cancel the scheduled timer and restore the tick -	 */ -	ts->tick_stopped  = 0; -	ts->idle_exittime = now; - -	tick_nohz_restart(ts, now); -} -  static void tick_nohz_account_idle_ticks(struct tick_sched *ts)  {  #ifndef CONFIG_VIRT_CPU_ACCOUNTING_NATIVE |