[patch v6 02/20] posix-timers: Make signal overrun accounting sensible

Thomas Gleixner posted 20 patches 3 weeks, 3 days ago
There is a newer version of this series
[patch v6 02/20] posix-timers: Make signal overrun accounting sensible
Posted by Thomas Gleixner 3 weeks, 3 days ago
The handling of the timer overrun in the signal code is inconsistent as it
takes previous overruns into account. This is just wrong as after the
reprogramming of a timer the overrun count starts over from a clean state,
i.e. 0.

Don't touch info::si_overrun in send_sigqueue() and only store the overrun
value at signal delivery time, which is computed from the timer itself
relative to the expiry time.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
---
V6: Fold the timer_overrun_to_int() cleanup from Frederic and remove all
    overrun fiddling from the signal path.
---
 kernel/signal.c            |    6 ------
 kernel/time/posix-timers.c |   11 ++++++-----
 2 files changed, 6 insertions(+), 11 deletions(-)
---

--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1968,15 +1968,9 @@ int send_sigqueue(struct sigqueue *q, st
 
 	ret = 0;
 	if (unlikely(!list_empty(&q->list))) {
-		/*
-		 * If an SI_TIMER entry is already queue just increment
-		 * the overrun count.
-		 */
-		q->info.si_overrun++;
 		result = TRACE_SIGNAL_ALREADY_PENDING;
 		goto out;
 	}
-	q->info.si_overrun = 0;
 
 	signalfd_notify(t, sig);
 	pending = (type != PIDTYPE_PID) ? &t->signal->shared_pending : &t->pending;
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -233,11 +233,12 @@ static __init int init_posix_timers(void
  * The siginfo si_overrun field and the return value of timer_getoverrun(2)
  * are of type int. Clamp the overrun value to INT_MAX
  */
-static inline int timer_overrun_to_int(struct k_itimer *timr, int baseval)
+static inline int timer_overrun_to_int(struct k_itimer *timr)
 {
-	s64 sum = timr->it_overrun_last + (s64)baseval;
+	if (timr->it_overrun_last > (s64)INT_MAX)
+		return INT_MAX;
 
-	return sum > (s64)INT_MAX ? INT_MAX : (int)sum;
+	return (int)timr->it_overrun_last;
 }
 
 static void common_hrtimer_rearm(struct k_itimer *timr)
@@ -280,7 +281,7 @@ bool posixtimer_deliver_signal(struct ke
 		timr->it_overrun = -1LL;
 		++timr->it_signal_seq;
 
-		info->si_overrun = timer_overrun_to_int(timr, info->si_overrun);
+		info->si_overrun = timer_overrun_to_int(timr);
 	}
 	ret = true;
 
@@ -774,7 +775,7 @@ SYSCALL_DEFINE1(timer_getoverrun, timer_
 	if (!timr)
 		return -EINVAL;
 
-	overrun = timer_overrun_to_int(timr, 0);
+	overrun = timer_overrun_to_int(timr);
 	unlock_timer(timr, flags);
 
 	return overrun;
Re: [patch v6 02/20] posix-timers: Make signal overrun accounting sensible
Posted by Frederic Weisbecker 3 weeks, 2 days ago
Le Thu, Oct 31, 2024 at 04:46:25PM +0100, Thomas Gleixner a écrit :
> The handling of the timer overrun in the signal code is inconsistent as it
> takes previous overruns into account. This is just wrong as after the
> reprogramming of a timer the overrun count starts over from a clean state,
> i.e. 0.
> 
> Don't touch info::si_overrun in send_sigqueue() and only store the overrun
> value at signal delivery time, which is computed from the timer itself
> relative to the expiry time.
> 
> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
> Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
> ---
> V6: Fold the timer_overrun_to_int() cleanup from Frederic and remove all
>     overrun fiddling from the signal path.
> ---
>  kernel/signal.c            |    6 ------
>  kernel/time/posix-timers.c |   11 ++++++-----
>  2 files changed, 6 insertions(+), 11 deletions(-)
> ---
> 
> --- a/kernel/signal.c
> +++ b/kernel/signal.c
> @@ -1968,15 +1968,9 @@ int send_sigqueue(struct sigqueue *q, st
>  
>  	ret = 0;
>  	if (unlikely(!list_empty(&q->list))) {
> -		/*
> -		 * If an SI_TIMER entry is already queue just increment
> -		 * the overrun count.
> -		 */
> -		q->info.si_overrun++;
>  		result = TRACE_SIGNAL_ALREADY_PENDING;
>  		goto out;
>  	}
> -	q->info.si_overrun = 0;

So it's not cleared anymore on signal queue?

Not sure if it's a big problem but if an interval timer gets a signal with
overruns and then the timer is reset later as non interval, the resulting
upcoming signals will still carry the previous non-zero overruns?

However it's better to keep the overrun update on a single place so
perhaps this?

diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
index 66ed49efc02f..f06c52731d65 100644
--- a/kernel/time/posix-timers.c
+++ b/kernel/time/posix-timers.c
@@ -282,6 +282,8 @@ bool posixtimer_deliver_signal(struct kernel_siginfo *info)
 		++timr->it_signal_seq;
 
 		info->si_overrun = timer_overrun_to_int(timr);
+	} else {
+		info->si_overrun = 0;
 	}
 	ret = true;
 
Other than that:

Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
Re: [patch v6 02/20] posix-timers: Make signal overrun accounting sensible
Posted by Thomas Gleixner 3 weeks, 2 days ago
On Fri, Nov 01 2024 at 13:51, Frederic Weisbecker wrote:
> Le Thu, Oct 31, 2024 at 04:46:25PM +0100, Thomas Gleixner a écrit :
>> @@ -1968,15 +1968,9 @@ int send_sigqueue(struct sigqueue *q, st
>>  
>>  	ret = 0;
>>  	if (unlikely(!list_empty(&q->list))) {
>> -		/*
>> -		 * If an SI_TIMER entry is already queue just increment
>> -		 * the overrun count.
>> -		 */
>> -		q->info.si_overrun++;
>>  		result = TRACE_SIGNAL_ALREADY_PENDING;
>>  		goto out;
>>  	}
>> -	q->info.si_overrun = 0;
>
> So it's not cleared anymore on signal queue?
>
> Not sure if it's a big problem but if an interval timer gets a signal with
> overruns and then the timer is reset later as non interval, the resulting
> upcoming signals will still carry the previous non-zero overruns?

Duh. Yes.

> However it's better to keep the overrun update on a single place so
> perhaps this?
>
> diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
> index 66ed49efc02f..f06c52731d65 100644
> --- a/kernel/time/posix-timers.c
> +++ b/kernel/time/posix-timers.c
> @@ -282,6 +282,8 @@ bool posixtimer_deliver_signal(struct kernel_siginfo *info)
>  		++timr->it_signal_seq;
>  
>  		info->si_overrun = timer_overrun_to_int(timr);
> +	} else {
> +		info->si_overrun = 0;
>  	}
>  	ret = true;
>  
> Other than that:

Let me fold that.

> Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
Re: [patch v6 02/20] posix-timers: Make signal overrun accounting sensible
Posted by Thomas Gleixner 3 weeks, 1 day ago
On Fri, Nov 01 2024 at 21:36, Thomas Gleixner wrote:
> On Fri, Nov 01 2024 at 13:51, Frederic Weisbecker wrote:
>> Le Thu, Oct 31, 2024 at 04:46:25PM +0100, Thomas Gleixner a écrit :
>>> @@ -1968,15 +1968,9 @@ int send_sigqueue(struct sigqueue *q, st
>>>  
>>>  	ret = 0;
>>>  	if (unlikely(!list_empty(&q->list))) {
>>> -		/*
>>> -		 * If an SI_TIMER entry is already queue just increment
>>> -		 * the overrun count.
>>> -		 */
>>> -		q->info.si_overrun++;
>>>  		result = TRACE_SIGNAL_ALREADY_PENDING;
>>>  		goto out;
>>>  	}
>>> -	q->info.si_overrun = 0;
>>
>> So it's not cleared anymore on signal queue?
>>
>> Not sure if it's a big problem but if an interval timer gets a signal with
>> overruns and then the timer is reset later as non interval, the resulting
>> upcoming signals will still carry the previous non-zero overruns?
>
> Duh. Yes.
>
>> However it's better to keep the overrun update on a single place so
>> perhaps this?
>>
>> diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
>> index 66ed49efc02f..f06c52731d65 100644
>> --- a/kernel/time/posix-timers.c
>> +++ b/kernel/time/posix-timers.c
>> @@ -282,6 +282,8 @@ bool posixtimer_deliver_signal(struct kernel_siginfo *info)
>>  		++timr->it_signal_seq;
>>  
>>  		info->si_overrun = timer_overrun_to_int(timr);
>> +	} else {
>> +		info->si_overrun = 0;
>>  	}
>>  	ret = true;
>>  
>> Other than that:
>
> Let me fold that.

Actually no. info is the siginfo which was allocated by the signal
delivery code on stack.

collect_signal() copies timer->sigqueue.info into that siginfo
struct. As timer->sigqueue.info.si_overrun is zero and never written to,
this else path is pointless.

Thanks,

        tglx
Re: [patch v6 02/20] posix-timers: Make signal overrun accounting sensible
Posted by Frederic Weisbecker 3 weeks, 1 day ago
Le Sat, Nov 02, 2024 at 08:41:53PM +0100, Thomas Gleixner a écrit :
> On Fri, Nov 01 2024 at 21:36, Thomas Gleixner wrote:
> > On Fri, Nov 01 2024 at 13:51, Frederic Weisbecker wrote:
> >> Le Thu, Oct 31, 2024 at 04:46:25PM +0100, Thomas Gleixner a écrit :
> >>> @@ -1968,15 +1968,9 @@ int send_sigqueue(struct sigqueue *q, st
> >>>  
> >>>  	ret = 0;
> >>>  	if (unlikely(!list_empty(&q->list))) {
> >>> -		/*
> >>> -		 * If an SI_TIMER entry is already queue just increment
> >>> -		 * the overrun count.
> >>> -		 */
> >>> -		q->info.si_overrun++;
> >>>  		result = TRACE_SIGNAL_ALREADY_PENDING;
> >>>  		goto out;
> >>>  	}
> >>> -	q->info.si_overrun = 0;
> >>
> >> So it's not cleared anymore on signal queue?
> >>
> >> Not sure if it's a big problem but if an interval timer gets a signal with
> >> overruns and then the timer is reset later as non interval, the resulting
> >> upcoming signals will still carry the previous non-zero overruns?
> >
> > Duh. Yes.
> >
> >> However it's better to keep the overrun update on a single place so
> >> perhaps this?
> >>
> >> diff --git a/kernel/time/posix-timers.c b/kernel/time/posix-timers.c
> >> index 66ed49efc02f..f06c52731d65 100644
> >> --- a/kernel/time/posix-timers.c
> >> +++ b/kernel/time/posix-timers.c
> >> @@ -282,6 +282,8 @@ bool posixtimer_deliver_signal(struct kernel_siginfo *info)
> >>  		++timr->it_signal_seq;
> >>  
> >>  		info->si_overrun = timer_overrun_to_int(timr);
> >> +	} else {
> >> +		info->si_overrun = 0;
> >>  	}
> >>  	ret = true;
> >>  
> >> Other than that:
> >
> > Let me fold that.
> 
> Actually no. info is the siginfo which was allocated by the signal
> delivery code on stack.
> 
> collect_signal() copies timer->sigqueue.info into that siginfo
> struct. As timer->sigqueue.info.si_overrun is zero and never written to,
> this else path is pointless.

Good point, thanks for pointing out!