]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
posix-timers: Make signal overrun accounting sensible
authorThomas Gleixner <tglx@linutronix.de>
Tue, 5 Nov 2024 08:14:32 +0000 (09:14 +0100)
committerThomas Gleixner <tglx@linutronix.de>
Thu, 7 Nov 2024 01:14:43 +0000 (02:14 +0100)
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>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/all/20241105064213.106738193@linutronix.de
kernel/signal.c
kernel/time/posix-timers.c

index 68e6bc70ccf2cfb5738e681e4b848d3c711a3276..ba7159b25d514fc5c961be790e2c6f875ded1c41 100644 (file)
@@ -1968,15 +1968,9 @@ int send_sigqueue(struct sigqueue *q, struct pid *pid, enum pid_type type, int s
 
        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;
index b380e25d49474d674a93ba4896d7bd32021bd267..66ed49efc02f44c3ddddf7baf7f77d024d5ecb82 100644 (file)
@@ -233,11 +233,12 @@ __initcall(init_posix_timers);
  * 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 kernel_siginfo *info)
                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_t, timer_id)
        if (!timr)
                return -EINVAL;
 
-       overrun = timer_overrun_to_int(timr, 0);
+       overrun = timer_overrun_to_int(timr);
        unlock_timer(timr, flags);
 
        return overrun;