diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/compat.c | 24 | ||||
| -rw-r--r-- | kernel/time/tick-sched.c | 14 | ||||
| -rw-r--r-- | kernel/time/timekeeping.c | 5 | 
3 files changed, 38 insertions, 5 deletions
| diff --git a/kernel/compat.c b/kernel/compat.c index 633394f442f8..ebb3c369d03d 100644 --- a/kernel/compat.c +++ b/kernel/compat.c @@ -226,7 +226,7 @@ static long compat_nanosleep_restart(struct restart_block *restart)  	ret = hrtimer_nanosleep_restart(restart);  	set_fs(oldfs); -	if (ret) { +	if (ret == -ERESTART_RESTARTBLOCK) {  		rmtp = restart->nanosleep.compat_rmtp;  		if (rmtp && compat_put_timespec(&rmt, rmtp)) @@ -256,7 +256,26 @@ COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp,  				HRTIMER_MODE_REL, CLOCK_MONOTONIC);  	set_fs(oldfs); -	if (ret) { +	/* +	 * hrtimer_nanosleep() can only return 0 or +	 * -ERESTART_RESTARTBLOCK here because: +	 * +	 * - we call it with HRTIMER_MODE_REL and therefor exclude the +	 *   -ERESTARTNOHAND return path. +	 * +	 * - we supply the rmtp argument from the task stack (due to +	 *   the necessary compat conversion. So the update cannot +	 *   fail, which excludes the -EFAULT return path as well. If +	 *   it fails nevertheless we have a bigger problem and wont +	 *   reach this place anymore. +	 * +	 * - if the return value is 0, we do not have to update rmtp +	 *    because there is no remaining time. +	 * +	 * We check for -ERESTART_RESTARTBLOCK nevertheless if the +	 * core implementation decides to return random nonsense. +	 */ +	if (ret == -ERESTART_RESTARTBLOCK) {  		struct restart_block *restart  			= ¤t_thread_info()->restart_block; @@ -266,7 +285,6 @@ COMPAT_SYSCALL_DEFINE2(nanosleep, struct compat_timespec __user *, rqtp,  		if (rmtp && compat_put_timespec(&rmt, rmtp))  			return -EFAULT;  	} -  	return ret;  } diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index 99aa6ee3908f..f654a8a298fa 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -225,6 +225,20 @@ static DEFINE_PER_CPU(struct irq_work, nohz_full_kick_work) = {  };  /* + * Kick this CPU if it's full dynticks in order to force it to + * re-evaluate its dependency on the tick and restart it if necessary. + * This kick, unlike tick_nohz_full_kick_cpu() and tick_nohz_full_kick_all(), + * is NMI safe. + */ +void tick_nohz_full_kick(void) +{ +	if (!tick_nohz_full_cpu(smp_processor_id())) +		return; + +	irq_work_queue(&__get_cpu_var(nohz_full_kick_work)); +} + +/*   * Kick the CPU if it's full dynticks in order to force it to   * re-evaluate its dependency on the tick and restart it if necessary.   */ diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c index fb4a9c2cf8d9..ec1791fae965 100644 --- a/kernel/time/timekeeping.c +++ b/kernel/time/timekeeping.c @@ -442,11 +442,12 @@ static void timekeeping_update(struct timekeeper *tk, unsigned int action)  		tk->ntp_error = 0;  		ntp_clear();  	} -	update_vsyscall(tk); -	update_pvclock_gtod(tk, action & TK_CLOCK_WAS_SET);  	tk_update_ktime_data(tk); +	update_vsyscall(tk); +	update_pvclock_gtod(tk, action & TK_CLOCK_WAS_SET); +  	if (action & TK_MIRROR)  		memcpy(&shadow_timekeeper, &tk_core.timekeeper,  		       sizeof(tk_core.timekeeper)); | 
