[patch V2 07/50] posix-cpu-timers: Split up posix_cpu_timer_get()

Thomas Gleixner posted 50 patches 1 year, 8 months ago
There is a newer version of this series
[patch V2 07/50] posix-cpu-timers: Split up posix_cpu_timer_get()
Posted by Thomas Gleixner 1 year, 8 months ago
In preparation for addressing issues in the timer_get() and timer_set()
functions of posix CPU timers.

No functional change.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
---
V2: Split out into new patch to make review simpler - Frederic
---
 kernel/time/posix-cpu-timers.c |   51 +++++++++++++++++++----------------------
 1 file changed, 24 insertions(+), 27 deletions(-)

--- a/kernel/time/posix-cpu-timers.c
+++ b/kernel/time/posix-cpu-timers.c
@@ -785,33 +785,9 @@ static int posix_cpu_timer_set(struct k_
 	return ret;
 }
 
-static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp)
+static void __posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp, u64 now)
 {
-	clockid_t clkid = CPUCLOCK_WHICH(timer->it_clock);
-	struct cpu_timer *ctmr = &timer->it.cpu;
-	u64 now, expires = cpu_timer_getexpires(ctmr);
-	struct task_struct *p;
-
-	rcu_read_lock();
-	p = cpu_timer_task_rcu(timer);
-	if (!p)
-		goto out;
-
-	/*
-	 * Easy part: convert the reload time.
-	 */
-	itp->it_interval = ktime_to_timespec64(timer->it_interval);
-
-	if (!expires)
-		goto out;
-
-	/*
-	 * Sample the clock to take the difference with the expiry time.
-	 */
-	if (CPUCLOCK_PERTHREAD(timer->it_clock))
-		now = cpu_clock_sample(clkid, p);
-	else
-		now = cpu_clock_sample_group(clkid, p, false);
+	u64 expires = cpu_timer_getexpires(&timer->it.cpu);
 
 	if (now < expires) {
 		itp->it_value = ns_to_timespec64(expires - now);
@@ -823,7 +799,28 @@ static void posix_cpu_timer_get(struct k
 		itp->it_value.tv_nsec = 1;
 		itp->it_value.tv_sec = 0;
 	}
-out:
+}
+
+static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp)
+{
+	clockid_t clkid = CPUCLOCK_WHICH(timer->it_clock);
+	struct task_struct *p;
+	u64 now;
+
+	rcu_read_lock();
+	p = cpu_timer_task_rcu(timer);
+	if (p) {
+		itp->it_interval = ktime_to_timespec64(timer->it_interval);
+
+		if (cpu_timer_getexpires(&timer->it.cpu)) {
+			if (CPUCLOCK_PERTHREAD(timer->it_clock))
+				now = cpu_clock_sample(clkid, p);
+			else
+				now = cpu_clock_sample_group(clkid, p, false);
+
+			__posix_cpu_timer_get(timer, itp, now);
+		}
+	}
 	rcu_read_unlock();
 }
Re: [patch V2 07/50] posix-cpu-timers: Split up posix_cpu_timer_get()
Posted by Frederic Weisbecker 1 year, 8 months ago
Le Thu, Apr 11, 2024 at 12:46:24AM +0200, Thomas Gleixner a écrit :
> In preparation for addressing issues in the timer_get() and timer_set()
> functions of posix CPU timers.
> 
> No functional change.
> 
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
Re: [patch V2 07/50] posix-cpu-timers: Split up posix_cpu_timer_get()
Posted by Oleg Nesterov 1 year, 8 months ago
On 04/11, Thomas Gleixner wrote:
>
> In preparation for addressing issues in the timer_get() and timer_set()
> functions of posix CPU timers.

Cough... I must have missed something, but posix_cpu_timer_get()
doesn't look right with or without this trivial patch.

It doesn't initialize itp->it_value if cpu_timer_getexpires() == 0,
this means that sys_timer_gettime() will copy the uninitialized
cur_setting->it_value on the stack to userspace?

Oleg.
Re: [patch V2 07/50] posix-cpu-timers: Split up posix_cpu_timer_get()
Posted by Anna-Maria Behnsen 1 year, 8 months ago
Oleg Nesterov <oleg@redhat.com> writes:

> On 04/11, Thomas Gleixner wrote:
>>
>> In preparation for addressing issues in the timer_get() and timer_set()
>> functions of posix CPU timers.
>
> Cough... I must have missed something, but posix_cpu_timer_get()
> doesn't look right with or without this trivial patch.
>
> It doesn't initialize itp->it_value if cpu_timer_getexpires() == 0,
> this means that sys_timer_gettime() will copy the uninitialized
> cur_setting->it_value on the stack to userspace?

The initialization of itp is already done by the callsites.
do_timer_settime() in posix-timers.c as well as do_cpu_nanosleep() in
posix-cpu-timers.c execute a memset before calling
posix_cpu_timer_get(). So this should be fine - or did I miss something
here?

Thanks,

	Anna-Maria
Re: [patch V2 07/50] posix-cpu-timers: Split up posix_cpu_timer_get()
Posted by Oleg Nesterov 1 year, 8 months ago
On 04/17, Anna-Maria Behnsen wrote:
>
> Oleg Nesterov <oleg@redhat.com> writes:
>
> > On 04/11, Thomas Gleixner wrote:
> >>
> >> In preparation for addressing issues in the timer_get() and timer_set()
> >> functions of posix CPU timers.
> >
> > Cough... I must have missed something, but posix_cpu_timer_get()
> > doesn't look right with or without this trivial patch.
> >
> > It doesn't initialize itp->it_value if cpu_timer_getexpires() == 0,
> > this means that sys_timer_gettime() will copy the uninitialized
> > cur_setting->it_value on the stack to userspace?
>
> The initialization of itp is already done by the callsites.
> do_timer_settime() in posix-timers.c as well as do_cpu_nanosleep() in
> posix-cpu-timers.c execute a memset before calling
> posix_cpu_timer_get().

Indeed. Somehow I missed this memset(). Even if I tried to read the
simple do_timer_gettime/posix_cpu_timer_get functions several times ;)

Thanks for correcting me!

Oleg.
Re: [patch V2 07/50] posix-cpu-timers: Split up posix_cpu_timer_get()
Posted by Eric W. Biederman 1 year, 8 months ago
Thomas Gleixner <tglx@linutronix.de> writes:

> In preparation for addressing issues in the timer_get() and timer_set()
> functions of posix CPU timers.

To see that this was safe I had to lookup and see that
cpu_timer_getexpires is a truly trivial function.

static inline u64 cpu_timer_getexpires(struct cpu_timer *ctmr)
{
	return ctmr->node.expires;
}

I am a bit confused by the purpose of this function in
posix-cpu-timers.c.  In some places this helper is used (like below),
and in other places like bump_cpu_timer the expires member is
accessed directly.

It isn't really a problem, but it is something that might be
worth making consistent in the code to make it easier to read.

Eric

> No functional change.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> ---
> V2: Split out into new patch to make review simpler - Frederic
> ---
>  kernel/time/posix-cpu-timers.c |   51 +++++++++++++++++++----------------------
>  1 file changed, 24 insertions(+), 27 deletions(-)
>
> --- a/kernel/time/posix-cpu-timers.c
> +++ b/kernel/time/posix-cpu-timers.c
> @@ -785,33 +785,9 @@ static int posix_cpu_timer_set(struct k_
>  	return ret;
>  }
>  
> -static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp)
> +static void __posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp, u64 now)
>  {
> -	clockid_t clkid = CPUCLOCK_WHICH(timer->it_clock);
> -	struct cpu_timer *ctmr = &timer->it.cpu;
> -	u64 now, expires = cpu_timer_getexpires(ctmr);
> -	struct task_struct *p;
> -
> -	rcu_read_lock();
> -	p = cpu_timer_task_rcu(timer);
> -	if (!p)
> -		goto out;
> -
> -	/*
> -	 * Easy part: convert the reload time.
> -	 */
> -	itp->it_interval = ktime_to_timespec64(timer->it_interval);
> -
> -	if (!expires)
> -		goto out;
> -
> -	/*
> -	 * Sample the clock to take the difference with the expiry time.
> -	 */
> -	if (CPUCLOCK_PERTHREAD(timer->it_clock))
> -		now = cpu_clock_sample(clkid, p);
> -	else
> -		now = cpu_clock_sample_group(clkid, p, false);
> +	u64 expires = cpu_timer_getexpires(&timer->it.cpu);
>  
>  	if (now < expires) {
>  		itp->it_value = ns_to_timespec64(expires - now);
> @@ -823,7 +799,28 @@ static void posix_cpu_timer_get(struct k
>  		itp->it_value.tv_nsec = 1;
>  		itp->it_value.tv_sec = 0;
>  	}
> -out:
> +}
> +
> +static void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec64 *itp)
> +{
> +	clockid_t clkid = CPUCLOCK_WHICH(timer->it_clock);
> +	struct task_struct *p;
> +	u64 now;
> +
> +	rcu_read_lock();
> +	p = cpu_timer_task_rcu(timer);
> +	if (p) {
> +		itp->it_interval = ktime_to_timespec64(timer->it_interval);
> +
> +		if (cpu_timer_getexpires(&timer->it.cpu)) {
> +			if (CPUCLOCK_PERTHREAD(timer->it_clock))
> +				now = cpu_clock_sample(clkid, p);
> +			else
> +				now = cpu_clock_sample_group(clkid, p, false);
> +
> +			__posix_cpu_timer_get(timer, itp, now);
> +		}
> +	}
>  	rcu_read_unlock();
>  }
>
Re: [patch V2 07/50] posix-cpu-timers: Split up posix_cpu_timer_get()
Posted by Thomas Gleixner 1 year, 8 months ago
On Fri, Apr 12 2024 at 13:25, Eric W. Biederman wrote:
> Thomas Gleixner <tglx@linutronix.de> writes:
>> In preparation for addressing issues in the timer_get() and timer_set()
>> functions of posix CPU timers.
>
> To see that this was safe I had to lookup and see that
> cpu_timer_getexpires is a truly trivial function.
>
> static inline u64 cpu_timer_getexpires(struct cpu_timer *ctmr)
> {
> 	return ctmr->node.expires;
> }
>
> I am a bit confused by the purpose of this function in
> posix-cpu-timers.c.

I added that back then when I converted the code over to use a
timerqueue instead of a linked list mostly because I did not want to
fiddle in the inwars of timerqueue.

> In some places this helper is used (like below), and in other places
> like bump_cpu_timer the expires member is accessed directly.
>
> It isn't really a problem, but it is something that might be
> worth making consistent in the code to make it easier to read.

Yes, that's definitely inconsistent. I'll have a look.

Thanks,

        tglx
Re: [patch V2 07/50] posix-cpu-timers: Split up posix_cpu_timer_get()
Posted by Anna-Maria Behnsen 1 year, 8 months ago
Thomas Gleixner <tglx@linutronix.de> writes:

> In preparation for addressing issues in the timer_get() and timer_set()
> functions of posix CPU timers.
>
> No functional change.
>
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>

Reviewed-by: Anna-Maria Behnsen <anna-maria@linutronix.de>