diff options
Diffstat (limited to 'kernel/time/posix-cpu-timers.c')
| -rw-r--r-- | kernel/time/posix-cpu-timers.c | 143 | 
1 files changed, 58 insertions, 85 deletions
diff --git a/kernel/time/posix-cpu-timers.c b/kernel/time/posix-cpu-timers.c index d2a1e6dd0291..a3bd5dbe0dc4 100644 --- a/kernel/time/posix-cpu-timers.c +++ b/kernel/time/posix-cpu-timers.c @@ -12,6 +12,11 @@  #include <trace/events/timer.h>  #include <linux/tick.h>  #include <linux/workqueue.h> +#include <linux/compat.h> + +#include "posix-timers.h" + +static void posix_cpu_timer_rearm(struct k_itimer *timer);  /*   * Called after updating RLIMIT_CPU to run cpu timer and update @@ -322,6 +327,8 @@ static int posix_cpu_timer_create(struct k_itimer *new_timer)  	if (CPUCLOCK_WHICH(new_timer->it_clock) >= CPUCLOCK_MAX)  		return -EINVAL; +	new_timer->kclock = &clock_posix_cpu; +  	INIT_LIST_HEAD(&new_timer->it.cpu.entry);  	rcu_read_lock(); @@ -524,7 +531,8 @@ static void cpu_timer_fire(struct k_itimer *timer)  		 * reload the timer.  But we need to keep it  		 * ticking in case the signal is deliverable next time.  		 */ -		posix_cpu_timer_schedule(timer); +		posix_cpu_timer_rearm(timer); +		++timer->it_requeue_pending;  	}  } @@ -572,7 +580,11 @@ static int posix_cpu_timer_set(struct k_itimer *timer, int timer_flags,  	WARN_ON_ONCE(p == NULL); -	new_expires = timespec64_to_ns(&new->it_value); +	/* +	 * Use the to_ktime conversion because that clamps the maximum +	 * value to KTIME_MAX and avoid multiplication overflows. +	 */ +	new_expires = ktime_to_ns(timespec64_to_ktime(new->it_value));  	/*  	 * Protect against sighand release/switch in exit/exec and p->cpu_timers @@ -712,10 +724,8 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp  	 */  	itp->it_interval = ns_to_timespec64(timer->it.cpu.incr); -	if (timer->it.cpu.expires == 0) {	/* Timer not armed at all.  */ -		itp->it_value.tv_sec = itp->it_value.tv_nsec = 0; +	if (!timer->it.cpu.expires)  		return; -	}  	/*  	 * Sample the clock to take the difference with the expiry time. @@ -739,7 +749,6 @@ static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp  			 * Call the timer disarmed, nothing else to do.  			 */  			timer->it.cpu.expires = 0; -			itp->it_value = ns_to_timespec64(timer->it.cpu.expires);  			return;  		} else {  			cpu_timer_sample_group(timer->it_clock, p, &now); @@ -976,10 +985,10 @@ static void check_process_timers(struct task_struct *tsk,  }  /* - * This is called from the signal code (via do_schedule_next_timer) + * This is called from the signal code (via posixtimer_rearm)   * when the last timer signal was delivered and we have to reload the timer.   */ -void posix_cpu_timer_schedule(struct k_itimer *timer) +static void posix_cpu_timer_rearm(struct k_itimer *timer)  {  	struct sighand_struct *sighand;  	unsigned long flags; @@ -995,12 +1004,12 @@ void posix_cpu_timer_schedule(struct k_itimer *timer)  		cpu_clock_sample(timer->it_clock, p, &now);  		bump_cpu_timer(timer, now);  		if (unlikely(p->exit_state)) -			goto out; +			return;  		/* Protect timer list r/w in arm_timer() */  		sighand = lock_task_sighand(p, &flags);  		if (!sighand) -			goto out; +			return;  	} else {  		/*  		 * Protect arm_timer() and timer sampling in case of call to @@ -1013,11 +1022,10 @@ void posix_cpu_timer_schedule(struct k_itimer *timer)  			 * We can't even collect a sample any more.  			 */  			timer->it.cpu.expires = 0; -			goto out; +			return;  		} else if (unlikely(p->exit_state) && thread_group_empty(p)) { -			unlock_task_sighand(p, &flags); -			/* Optimizations: if the process is dying, no need to rearm */ -			goto out; +			/* If the process is dying, no need to rearm */ +			goto unlock;  		}  		cpu_timer_sample_group(timer->it_clock, p, &now);  		bump_cpu_timer(timer, now); @@ -1029,12 +1037,8 @@ void posix_cpu_timer_schedule(struct k_itimer *timer)  	 */  	WARN_ON_ONCE(!irqs_disabled());  	arm_timer(timer); +unlock:  	unlock_task_sighand(p, &flags); - -out: -	timer->it_overrun_last = timer->it_overrun; -	timer->it_overrun = -1; -	++timer->it_requeue_pending;  }  /** @@ -1227,9 +1231,11 @@ void set_process_cpu_timer(struct task_struct *tsk, unsigned int clock_idx,  }  static int do_cpu_nanosleep(const clockid_t which_clock, int flags, -			    struct timespec64 *rqtp, struct itimerspec64 *it) +			    const struct timespec64 *rqtp)  { +	struct itimerspec64 it;  	struct k_itimer timer; +	u64 expires;  	int error;  	/* @@ -1243,12 +1249,13 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,  	timer.it_process = current;  	if (!error) {  		static struct itimerspec64 zero_it; +		struct restart_block *restart; -		memset(it, 0, sizeof *it); -		it->it_value = *rqtp; +		memset(&it, 0, sizeof(it)); +		it.it_value = *rqtp;  		spin_lock_irq(&timer.it_lock); -		error = posix_cpu_timer_set(&timer, flags, it, NULL); +		error = posix_cpu_timer_set(&timer, flags, &it, NULL);  		if (error) {  			spin_unlock_irq(&timer.it_lock);  			return error; @@ -1277,8 +1284,8 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,  		/*  		 * We were interrupted by a signal.  		 */ -		*rqtp = ns_to_timespec64(timer.it.cpu.expires); -		error = posix_cpu_timer_set(&timer, 0, &zero_it, it); +		expires = timer.it.cpu.expires; +		error = posix_cpu_timer_set(&timer, 0, &zero_it, &it);  		if (!error) {  			/*  			 * Timer is now unarmed, deletion can not fail. @@ -1298,7 +1305,7 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,  			spin_unlock_irq(&timer.it_lock);  		} -		if ((it->it_value.tv_sec | it->it_value.tv_nsec) == 0) { +		if ((it.it_value.tv_sec | it.it_value.tv_nsec) == 0) {  			/*  			 * It actually did fire already.  			 */ @@ -1306,6 +1313,13 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,  		}  		error = -ERESTART_RESTARTBLOCK; +		/* +		 * Report back to the user the time still remaining. +		 */ +		restart = ¤t->restart_block; +		restart->nanosleep.expires = expires; +		if (restart->nanosleep.type != TT_NONE) +			error = nanosleep_copyout(restart, &it.it_value);  	}  	return error; @@ -1314,11 +1328,9 @@ static int do_cpu_nanosleep(const clockid_t which_clock, int flags,  static long posix_cpu_nsleep_restart(struct restart_block *restart_block);  static int posix_cpu_nsleep(const clockid_t which_clock, int flags, -			    struct timespec64 *rqtp, struct timespec __user *rmtp) +			    const struct timespec64 *rqtp)  {  	struct restart_block *restart_block = ¤t->restart_block; -	struct itimerspec64 it; -	struct timespec ts;  	int error;  	/* @@ -1329,23 +1341,15 @@ static int posix_cpu_nsleep(const clockid_t which_clock, int flags,  	     CPUCLOCK_PID(which_clock) == task_pid_vnr(current)))  		return -EINVAL; -	error = do_cpu_nanosleep(which_clock, flags, rqtp, &it); +	error = do_cpu_nanosleep(which_clock, flags, rqtp);  	if (error == -ERESTART_RESTARTBLOCK) {  		if (flags & TIMER_ABSTIME)  			return -ERESTARTNOHAND; -		/* -		 * Report back to the user the time still remaining. -		 */ -		ts = timespec64_to_timespec(it.it_value); -		if (rmtp && copy_to_user(rmtp, &ts, sizeof(*rmtp))) -			return -EFAULT;  		restart_block->fn = posix_cpu_nsleep_restart;  		restart_block->nanosleep.clockid = which_clock; -		restart_block->nanosleep.rmtp = rmtp; -		restart_block->nanosleep.expires = timespec64_to_ns(rqtp);  	}  	return error;  } @@ -1353,28 +1357,11 @@ static int posix_cpu_nsleep(const clockid_t which_clock, int flags,  static long posix_cpu_nsleep_restart(struct restart_block *restart_block)  {  	clockid_t which_clock = restart_block->nanosleep.clockid; -	struct itimerspec64 it;  	struct timespec64 t; -	struct timespec tmp; -	int error;  	t = ns_to_timespec64(restart_block->nanosleep.expires); -	error = do_cpu_nanosleep(which_clock, TIMER_ABSTIME, &t, &it); - -	if (error == -ERESTART_RESTARTBLOCK) { -		struct timespec __user *rmtp = restart_block->nanosleep.rmtp; -		/* -		 * Report back to the user the time still remaining. -		 */ -		 tmp = timespec64_to_timespec(it.it_value); -		if (rmtp && copy_to_user(rmtp, &tmp, sizeof(*rmtp))) -			return -EFAULT; - -		restart_block->nanosleep.expires = timespec64_to_ns(&t); -	} -	return error; - +	return do_cpu_nanosleep(which_clock, TIMER_ABSTIME, &t);  }  #define PROCESS_CLOCK	MAKE_PROCESS_CPUCLOCK(0, CPUCLOCK_SCHED) @@ -1396,14 +1383,9 @@ static int process_cpu_timer_create(struct k_itimer *timer)  	return posix_cpu_timer_create(timer);  }  static int process_cpu_nsleep(const clockid_t which_clock, int flags, -			      struct timespec64 *rqtp, -			      struct timespec __user *rmtp) +			      const struct timespec64 *rqtp)  { -	return posix_cpu_nsleep(PROCESS_CLOCK, flags, rqtp, rmtp); -} -static long process_cpu_nsleep_restart(struct restart_block *restart_block) -{ -	return -EINVAL; +	return posix_cpu_nsleep(PROCESS_CLOCK, flags, rqtp);  }  static int thread_cpu_clock_getres(const clockid_t which_clock,  				   struct timespec64 *tp) @@ -1421,36 +1403,27 @@ static int thread_cpu_timer_create(struct k_itimer *timer)  	return posix_cpu_timer_create(timer);  } -struct k_clock clock_posix_cpu = { +const struct k_clock clock_posix_cpu = {  	.clock_getres	= posix_cpu_clock_getres,  	.clock_set	= posix_cpu_clock_set,  	.clock_get	= posix_cpu_clock_get,  	.timer_create	= posix_cpu_timer_create,  	.nsleep		= posix_cpu_nsleep, -	.nsleep_restart	= posix_cpu_nsleep_restart,  	.timer_set	= posix_cpu_timer_set,  	.timer_del	= posix_cpu_timer_del,  	.timer_get	= posix_cpu_timer_get, +	.timer_rearm	= posix_cpu_timer_rearm,  }; -static __init int init_posix_cpu_timers(void) -{ -	struct k_clock process = { -		.clock_getres	= process_cpu_clock_getres, -		.clock_get	= process_cpu_clock_get, -		.timer_create	= process_cpu_timer_create, -		.nsleep		= process_cpu_nsleep, -		.nsleep_restart	= process_cpu_nsleep_restart, -	}; -	struct k_clock thread = { -		.clock_getres	= thread_cpu_clock_getres, -		.clock_get	= thread_cpu_clock_get, -		.timer_create	= thread_cpu_timer_create, -	}; - -	posix_timers_register_clock(CLOCK_PROCESS_CPUTIME_ID, &process); -	posix_timers_register_clock(CLOCK_THREAD_CPUTIME_ID, &thread); +const struct k_clock clock_process = { +	.clock_getres	= process_cpu_clock_getres, +	.clock_get	= process_cpu_clock_get, +	.timer_create	= process_cpu_timer_create, +	.nsleep		= process_cpu_nsleep, +}; -	return 0; -} -__initcall(init_posix_cpu_timers); +const struct k_clock clock_thread = { +	.clock_getres	= thread_cpu_clock_getres, +	.clock_get	= thread_cpu_clock_get, +	.timer_create	= thread_cpu_timer_create, +};  |