2024-04-10 22:47:47

by Thomas Gleixner

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

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 <[email protected]>
---
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();
}




2024-04-12 07:35:53

by Anna-Maria Behnsen

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

Thomas Gleixner <[email protected]> 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 <[email protected]>

Reviewed-by: Anna-Maria Behnsen <[email protected]>

2024-04-12 18:49:28

by Eric W. Biederman

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

Thomas Gleixner <[email protected]> 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 <[email protected]>
> ---
> 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();
> }
>

2024-04-12 19:57:07

by Thomas Gleixner

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

On Fri, Apr 12 2024 at 13:25, Eric W. Biederman wrote:
> Thomas Gleixner <[email protected]> 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

2024-04-16 14:47:17

by Oleg Nesterov

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

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.


2024-04-17 09:24:08

by Anna-Maria Behnsen

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

Oleg Nesterov <[email protected]> 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


2024-04-17 11:09:49

by Oleg Nesterov

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

On 04/17, Anna-Maria Behnsen wrote:
>
> Oleg Nesterov <[email protected]> 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.


2024-04-17 20:44:48

by Frederic Weisbecker

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

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 <[email protected]>

Reviewed-by: Frederic Weisbecker <[email protected]>