posix-timers: Fixes and cleanups
cover posix-timers: Fixes and cleanups
Hi!
A recent syzcaller/KCSAN report about a data race and an actually broken loop termination due to that race made me look deeper into the posix timer code.
Aside of the loop termination issue this unearthed another issue in the exit() path where timer deletion might livelock on RT enabled kernels.
While going through the code with a fine comb, I stumbled over another place which needs READ/WRITE_ONCE() annotations, tons of outdated and/or uncomprehensible comments and a bunch of silly code.
The series has therefore a larger set of cleanups on top of the two fixes.
It is based on
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git timers/core
and also availble from git:
git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.git timers/posix
Thanks,
tglx
--- include/linux/sched/signal.h | 2 kernel/time/posix-timers.c | 523 ++++++++++++++++++++++++++----------------- 2 files changed, 321 insertions(+), 204 deletions(-)
PATCH 1/20 posix-timers: Prevent RT livelock in itimer_delete()
itimer_delete() has a retry loop when the timer is concurrently expired. On non-RT kernels this just spin-waits until the timer callback has completed. On RT kernels this is a potential livelock when the exiting task preempted the hrtimer soft interrupt.
This only affects hrtimer based timers as Posix CPU timers cannot be concurrently expired. For CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y this is obviously impossible as the task cannot run task work and exit at the same time. The CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n (only non-RT) is prevented because interrupts are disabled.
Replace spin_unlock() with an invocation of timer_wait_running() to handle it the same way as the other retry loops in the posix timer code.
--- kernel/time/posix-timers.c | 50 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 8 deletions(-)
kernel/time/posix-timers.c +42 -8
@@ -1037,27 +1037,59 @@ SYSCALL_DEFINE1(timer_delete, timer_t, t }/* -* return timer owned by the process, used by exit_itimers +* Delete a timer if it is armed, remove it from the hash and schedule it +* for RCU freeing. */ static void itimer_delete (struct k_itimer *timer) { -retry_delete: -spin_lock_irq (&timer->it_lock); +unsigned long flags; +retry_delete: +/* +* irqsave is required to make timer_wait_running() work. +*/ +spin_lock_irqsave (&timer->it_lock, flags); + +/* +* Even if the timer is not longer accessible from other tasks +* it still might be armed and queued in the underlying timer +* mechanism. Worse, that timer mechanism might run the expiry +* function concurrently. +*/ if (timer_delete_hook (timer) ==TIMER_RETRY ) { -spin_unlock_irq (&timer->it_lock); +/* +* Timer is expired concurrently, prevent livelocks +* and pointless spinning on RT. +* +* The CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y case is +* irrelevant here because obviously the exiting task +* cannot be expiring timer in task work concurrently. +* Ditto for CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n as the +* tick interrupt cannot run on this CPU because the above +* spin_lock disabled interrupts. +* +* timer_wait_running() drops timer::it_lock, which opens +* the possibility for another task to delete the timer. +* +* That's not possible here because this is invoked from +* do_exit() only for the last thread of the thread group. +* So no other task can access that timer. +*/ +if (WARN_ON_ONCE (timer_wait_running (timer, &flags) != timer)) +return ; + goto retry_delete; }list_del (&timer->list); -spin_unlock_irq (&timer->it_lock); +spin_unlock_irqrestore (&timer->it_lock, flags);release_posix_timer (timer,IT_ID_SET ); }/* -* This is called by do_exit or de_thread, only when nobody else can -* modify the signal->posix_timers list. Yet we need sighand->siglock -* to prevent the race with /proc/pid/timers. +* Invoked from do_exit() when the last thread of a thread group exits. +* At that point no other task can access the timers of the dying +* task anymore. */ void exit_itimers (struct task_struct *tsk) {
@@ -1067,10 +1099,12 @@ void exit_itimers(struct task_struct *tsif (list_empty (&tsk->signal->posix_timers))return ; +/* Protect against concurrent read via /proc/$PID/timers */ spin_lock_irq (&tsk->sighand->siglock);list_replace_init (&tsk->signal->posix_timers, &timers);spin_unlock_irq (&tsk->sighand->siglock); +/* The timers are not longer accessible via tsk::signal */ while (!list_empty (&timers)) { tmr = list_first_entry(&timers, struct k_itimer, list);itimer_delete (tmr);
Frederic Weisbecker
maintainerRe: [patch 01/20] posix-timers: Prevent RT livelock in itimer_delete()
Quoted 10 lines · Thomas Gleixner
itimer_delete()has a retry loop when the timer is concurrently expired. On non-RT kernels this just spin-waits until the timer callback has completed. On RT kernels this is a potential livelock when the exiting task preempted the hrtimer soft interrupt.This only affects hrtimer based timers as Posix CPU timers cannot be concurrently expired. For
CONFIG_POSIX_CPU_TIMERS_TASK_WORK=ythis is obviously impossible as the task cannot run task work and exit at the same time. TheCONFIG_POSIX_CPU_TIMERS_TASK_WORK=n(only non-RT) is prevented because interrupts are disabled.
But the owner of the timer is not the same as the target of the timer, right?
Though I seem to remember that we forbid setting a timer to a target outside the current process, in which case the owner and the target are the same at this exit stage. But I can't remember what enforces that permission in pid_for_clock()...
Thanks.
Re: [patch 01/20] posix-timers: Prevent RT livelock in itimer_delete()
Quoted 12 lines · Frederic Weisbecker
Quoted 10 lines · Thomas Gleixner
itimer_delete()has a retry loop when the timer is concurrently expired. On non-RT kernels this just spin-waits until the timer callback has completed. On RT kernels this is a potential livelock when the exiting task preempted the hrtimer soft interrupt.This only affects hrtimer based timers as Posix CPU timers cannot be concurrently expired. For
CONFIG_POSIX_CPU_TIMERS_TASK_WORK=ythis is obviously impossible as the task cannot run task work and exit at the same time. TheCONFIG_POSIX_CPU_TIMERS_TASK_WORK=n(only non-RT) is prevented because interrupts are disabled.
Quoted 6 lines
But the owner of the timer is not the same as the target of the timer, right?
Though I seem to remember that we forbid setting a timer to a target outside the current process, in which case the owner and the target are the same at this exit stage. But I can't remember what enforces that permission in
pid_for_clock()..
The owner of the timer is always the one which needs to find the entity to synchronize on, whether that's the right hrtimer base or the task which runs the expiry code.
wait_for_running_timer() is taking that into account:
- The hrtimer timer based posix timers lock the hrtimer base expiry lock on the base to which the timer is currently associated
- Posix CPU timers can be armed on a differnet process (only per thread timers are restricted to currents threadgroup) but the wait_for_running() callback "knows" how to find that process:
When the timer is moved to the expiry list it gets:
cputimer->firing = 1; rcu_assign_pointer(ctmr->handling, current);
and the wait for running side does:
rcu_read_lock()
tsk = rcu_dereference(timr->it.cpu.handling);
....
mutex_lock(&tsk->posix_cputimers_work.mutex); See collect_timerqueue(), handle_posix_cpu_timers() and posix_cpu_timer_wait_running() for details.
commit f7abf14f0001 ("posix-cpu-timers: Implement the missing timer_wait_running callback") has quite some prose in the changelog.
Thanks,
tglx
Re: [patch 01/20] posix-timers: Prevent RT livelock in itimer_delete()
Quoted 45 lines · Thomas Gleixner
Quoted 12 lines · Frederic Weisbecker
Quoted 10 lines · Thomas Gleixner
itimer_delete()has a retry loop when the timer is concurrently expired. On non-RT kernels this just spin-waits until the timer callback has completed. On RT kernels this is a potential livelock when the exiting task preempted the hrtimer soft interrupt.This only affects hrtimer based timers as Posix CPU timers cannot be concurrently expired. For
CONFIG_POSIX_CPU_TIMERS_TASK_WORK=ythis is obviously impossible as the task cannot run task work and exit at the same time. TheCONFIG_POSIX_CPU_TIMERS_TASK_WORK=n(only non-RT) is prevented because interrupts are disabled.Quoted 6 lines
But the owner of the timer is not the same as the target of the timer, right?
Though I seem to remember that we forbid setting a timer to a target outside the current process, in which case the owner and the target are the same at this exit stage. But I can't remember what enforces that permission in
pid_for_clock()..The owner of the timer is always the one which needs to find the entity to synchronize on, whether that's the right hrtimer base or the task which runs the expiry code.
wait_for_running_timer()is taking that into account:- The hrtimer timer based posix timers lock the hrtimer base expiry lock on the base to which the timer is currently associated
- Posix CPU timers can be armed on a differnet process (only per thread timers are restricted to currents threadgroup) but the
wait_for_running()callback "knows" how to find that process:When the timer is moved to the expiry list it gets:
cputimer->firing= 1;rcu_assign_pointer(ctmr->handling, current);and the wait for running side does:
rcu_read_lock() tsk = rcu_dereference(timr->it.cpu.handling); .... mutex_lock(&tsk->posix_cputimers_work.mutex);
Quoted 5 lines
See
collect_timerqueue(),handle_posix_cpu_timers()andposix_cpu_timer_wait_running()for details.commit
f7abf14f0001("posix-cpu-timers: Implement the missingtimer_wait_runningcallback") has quite some prose in the changelog.
But you have a point. The comment I added in itimer_delete() vs. CPU timers is wrong for timers which are armed on a different process. Needs to be removed.
Thanks,
tglx
PATCH v2 1/20 posix-timers: Prevent RT livelock in itimer_delete()
itimer_delete() has a retry loop when the timer is concurrently expired. On non-RT kernels this just spin-waits until the timer callback has completed. On RT kernels this is a potential livelock when the exiting task preempted the hrtimer soft interrupt.
Replace spin_unlock() with an invocation of timer_wait_running() to handle it the same way as the other retry loops in the posix timer code.
---
V2: Remove the bogus claims about posix CPU timers - Frederic
--- kernel/time/posix-timers.c | 50 +++++++++++++++++++++++++++++++++++++-------- 1 file changed, 42 insertions(+), 8 deletions(-)
kernel/time/posix-timers.c +42 -8
@@ -1037,27 +1037,59 @@ SYSCALL_DEFINE1(timer_delete, timer_t, t }/* -* return timer owned by the process, used by exit_itimers +* Delete a timer if it is armed, remove it from the hash and schedule it +* for RCU freeing. */ static void itimer_delete (struct k_itimer *timer) { -retry_delete: -spin_lock_irq (&timer->it_lock); +unsigned long flags; +retry_delete: +/* +* irqsave is required to make timer_wait_running() work. +*/ +spin_lock_irqsave (&timer->it_lock, flags); + +/* +* Even if the timer is not longer accessible from other tasks +* it still might be armed and queued in the underlying timer +* mechanism. Worse, that timer mechanism might run the expiry +* function concurrently. +*/ if (timer_delete_hook (timer) ==TIMER_RETRY ) { -spin_unlock_irq (&timer->it_lock); +/* +* Timer is expired concurrently, prevent livelocks +* and pointless spinning on RT. +* +* The CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y case is +* irrelevant here because obviously the exiting task +* cannot be expiring timer in task work concurrently. +* Ditto for CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n as the +* tick interrupt cannot run on this CPU because the above +* spin_lock disabled interrupts. +* +* timer_wait_running() drops timer::it_lock, which opens +* the possibility for another task to delete the timer. +* +* That's not possible here because this is invoked from +* do_exit() only for the last thread of the thread group. +* So no other task can access that timer. +*/ +if (WARN_ON_ONCE (timer_wait_running (timer, &flags) != timer)) +return ; + goto retry_delete; }list_del (&timer->list); -spin_unlock_irq (&timer->it_lock); +spin_unlock_irqrestore (&timer->it_lock, flags);release_posix_timer (timer,IT_ID_SET ); }/* -* This is called by do_exit or de_thread, only when nobody else can -* modify the signal->posix_timers list. Yet we need sighand->siglock -* to prevent the race with /proc/pid/timers. +* Invoked from do_exit() when the last thread of a thread group exits. +* At that point no other task can access the timers of the dying +* task anymore. */ void exit_itimers (struct task_struct *tsk) {
@@ -1067,10 +1099,12 @@ void exit_itimers(struct task_struct *tsif (list_empty (&tsk->signal->posix_timers))return ; +/* Protect against concurrent read via /proc/$PID/timers */ spin_lock_irq (&tsk->sighand->siglock);list_replace_init (&tsk->signal->posix_timers, &timers);spin_unlock_irq (&tsk->sighand->siglock); +/* The timers are not longer accessible via tsk::signal */ while (!list_empty (&timers)) { tmr = list_first_entry(&timers, struct k_itimer, list);itimer_delete (tmr);
PATCH 1/20 posix-timers: Prevent RT livelock in itimer_delete()
itimer_delete() has a retry loop when the timer is concurrently expired. On non-RT kernels this just spin-waits until the timer callback has completed. On RT kernels this is a potential livelock when the exiting task preempted the hrtimer soft interrupt.
Replace spin_unlock() with an invocation of timer_wait_running() to handle it the same way as the other retry loops in the posix timer code.
---
V2: Remove bogus comments vs. posix CPU timers - Frederic V2a: Send the real fixed up version --- kernel/time/posix-timers.c | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-)
kernel/time/posix-timers.c +35 -8
@@ -1037,27 +1037,52 @@ SYSCALL_DEFINE1(timer_delete, timer_t, t }/* -* return timer owned by the process, used by exit_itimers +* Delete a timer if it is armed, remove it from the hash and schedule it +* for RCU freeing. */ static void itimer_delete (struct k_itimer *timer) { -retry_delete: -spin_lock_irq (&timer->it_lock); +unsigned long flags; +retry_delete: +/* +* irqsave is required to make timer_wait_running() work. +*/ +spin_lock_irqsave (&timer->it_lock, flags); + +/* +* Even if the timer is not longer accessible from other tasks +* it still might be armed and queued in the underlying timer +* mechanism. Worse, that timer mechanism might run the expiry +* function concurrently. +*/ if (timer_delete_hook (timer) ==TIMER_RETRY ) { -spin_unlock_irq (&timer->it_lock); +/* +* Timer is expired concurrently, prevent livelocks +* and pointless spinning on RT. +* +* timer_wait_running() drops timer::it_lock, which opens +* the possibility for another task to delete the timer. +* +* That's not possible here because this is invoked from +* do_exit() only for the last thread of the thread group. +* So no other task can access and delete that timer. +*/ +if (WARN_ON_ONCE (timer_wait_running (timer, &flags) != timer)) +return ; + goto retry_delete; }list_del (&timer->list); -spin_unlock_irq (&timer->it_lock); +spin_unlock_irqrestore (&timer->it_lock, flags);release_posix_timer (timer,IT_ID_SET ); }/* -* This is called by do_exit or de_thread, only when nobody else can -* modify the signal->posix_timers list. Yet we need sighand->siglock -* to prevent the race with /proc/pid/timers. +* Invoked from do_exit() when the last thread of a thread group exits. +* At that point no other task can access the timers of the dying +* task anymore. */ void exit_itimers (struct task_struct *tsk) {
@@ -1067,10 +1092,12 @@ void exit_itimers(struct task_struct *tsif (list_empty (&tsk->signal->posix_timers))return ; +/* Protect against concurrent read via /proc/$PID/timers */ spin_lock_irq (&tsk->sighand->siglock);list_replace_init (&tsk->signal->posix_timers, &timers);spin_unlock_irq (&tsk->sighand->siglock); +/* The timers are not longer accessible via tsk::signal */ while (!list_empty (&timers)) { tmr = list_first_entry(&timers, struct k_itimer, list);itimer_delete (tmr);
Re: [patch v2a 01/20] posix-timers: Prevent RT livelock in itimer_delete()
Quoted 4 lines · Thomas Gleixner
itimer_delete()has a retry loop when the timer is concurrently expired. On non-RT kernels this just spin-waits until the timer callback has completed. On RT kernels this is a potential livelock when the exiting task preempted the hrtimer soft interrupt.
It's not just RT but also archs supporting HAVE_POSIX_CPU_TIMERS_TASK_WORK
Quoted 36 lines
Replace
spin_unlock()with an invocation oftimer_wait_running()to handle it the same way as the other retry loops in the posix timer code.Fixes ec8f954a40da ("posix-timers: Use a callback for cancel synchronization on PREEMPT_RT")Signed-off-by Thomas Gleixner <[email protected]>---
V2: Remove bogus comments vs. posix CPU timers - Frederic V2a: Send the real fixed up version --- kernel/time/posix-timers.c | 43 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 35 insertions(+), 8 deletions(-)kernel/time/posix-timers.c +10
-3@@ -1037,27 +1037,52 @@ SYSCALL_DEFINE1(timer_delete, timer_t, t }/* -* return timer owned by the process, used by exit_itimers +* Delete a timer if it is armed, remove it from the hash and schedule it +* for RCU freeing. */ static void itimer_delete (struct k_itimer *timer) { -retry_delete: -spin_lock_irq (&timer->it_lock); +unsigned long flags; +retry_delete: +/* +* irqsave is required to make timer_wait_running() work. +*/ +spin_lock_irqsave (&timer->it_lock, flags); + +/*
kernel/time/posix-timers.c SYSCALL_DEFINE1(timer_delete, timer_t, t · line 1062
Quoted 10 lines
kernel/time/posix-timers.c +8
-1+* Even if the timer is not longer accessible from other tasks +* it still might be armed and queued in the underlying timer +* mechanism. Worse, that timer mechanism might run the expiry +* function concurrently. +*/ if (timer_delete_hook (timer) ==TIMER_RETRY ) { -spin_unlock_irq (&timer->it_lock); +/* +* Timer is expired concurrently, prevent livelocks +* and pointless spinning on RT.
Ditto.
Thanks.
[tip: timers/core] posix-timers: Prevent RT livelock in itimer_delete()
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 1b59b2577582f9cf3d0f17245675a76859175cc1 Gitweb: https://git.kernel.org/tip/1b59b2577582f9cf3d0f17245675a76859175cc1 Author: Thomas Gleixner <[email protected]> AuthorDate: Thu, 01 Jun 2023 22:16:34 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Mon, 05 Jun 2023 17:03:36 +02:00
posix-timers: Prevent RT livelock in itimer_delete()
itimer_delete() has a retry loop when the timer is concurrently expired. On non-RT kernels this just spin-waits until the timer callback has completed, except for posix CPU timers which have HAVE_POSIX_CPU_TIMERS_TASK_WORK enabled.
In that case and on RT kernels the existing task could live lock when preempting the task which does the timer delivery.
Replace spin_unlock() with an invocation of timer_wait_running() to handle it the same way as the other retry loops in the posix timer code.
--- kernel/time/posix-timers.c | 41 ++++++++++++++++++++++++++++++------- 1 file changed, 34 insertions(+), 7 deletions(-)
kernel/time/posix-timers.c +34 -7
@@ -1037,27 +1037,52 @@ retry_delete: }/* -* return timer owned by the process, used by exit_itimers +* Delete a timer if it is armed, remove it from the hash and schedule it +* for RCU freeing. */ static void itimer_delete (struct k_itimer *timer) { +unsigned long flags; + retry_delete: -spin_lock_irq (&timer->it_lock); +/* +* irqsave is required to make timer_wait_running() work. +*/ +spin_lock_irqsave (&timer->it_lock, flags); +/* +* Even if the timer is not longer accessible from other tasks +* it still might be armed and queued in the underlying timer +* mechanism. Worse, that timer mechanism might run the expiry +* function concurrently. +*/ if (timer_delete_hook (timer) ==TIMER_RETRY ) { -spin_unlock_irq (&timer->it_lock); +/* +* Timer is expired concurrently, prevent livelocks +* and pointless spinning on RT. +* +* timer_wait_running() drops timer::it_lock, which opens +* the possibility for another task to delete the timer. +* +* That's not possible here because this is invoked from +* do_exit() only for the last thread of the thread group. +* So no other task can access and delete that timer. +*/ +if (WARN_ON_ONCE (timer_wait_running (timer, &flags) != timer)) +return ; + goto retry_delete; }list_del (&timer->list); -spin_unlock_irq (&timer->it_lock); +spin_unlock_irqrestore (&timer->it_lock, flags);release_posix_timer (timer,IT_ID_SET ); }/* -* This is called by do_exit or de_thread, only when nobody else can -* modify the signal->posix_timers list. Yet we need sighand->siglock -* to prevent the race with /proc/pid/timers. +* Invoked from do_exit() when the last thread of a thread group exits. +* At that point no other task can access the timers of the dying +* task anymore. */ void exit_itimers (struct task_struct *tsk) {
@@ -1067,10 +1092,12 @@ void exit_itimers(struct task_struct *tsk)if (list_empty (&tsk->signal->posix_timers))return ; +/* Protect against concurrent read via /proc/$PID/timers */ spin_lock_irq (&tsk->sighand->siglock);list_replace_init (&tsk->signal->posix_timers, &timers);spin_unlock_irq (&tsk->sighand->siglock); +/* The timers are not longer accessible via tsk::signal */ while (!list_empty (&timers)) { tmr = list_first_entry(&timers, struct k_itimer, list);itimer_delete (tmr);
[tip: timers/core] posix-timers: Prevent RT livelock in itimer_delete()
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 9d9e522010eb5685d8b53e8a24320653d9d4cbbf Gitweb: https://git.kernel.org/tip/9d9e522010eb5685d8b53e8a24320653d9d4cbbf Author: Thomas Gleixner <[email protected]> AuthorDate: Thu, 01 Jun 2023 22:16:34 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Sun, 18 Jun 2023 22:40:42 +02:00
posix-timers: Prevent RT livelock in itimer_delete()
itimer_delete() has a retry loop when the timer is concurrently expired. On non-RT kernels this just spin-waits until the timer callback has completed, except for posix CPU timers which have HAVE_POSIX_CPU_TIMERS_TASK_WORK enabled.
In that case and on RT kernels the existing task could live lock when preempting the task which does the timer delivery.
Replace spin_unlock() with an invocation of timer_wait_running() to handle it the same way as the other retry loops in the posix timer code.
--- kernel/time/posix-timers.c | 43 ++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 8 deletions(-)
kernel/time/posix-timers.c +35 -8
@@ -1037,27 +1037,52 @@ retry_delete: }/* -* return timer owned by the process, used by exit_itimers +* Delete a timer if it is armed, remove it from the hash and schedule it +* for RCU freeing. */ static void itimer_delete (struct k_itimer *timer) { -retry_delete: -spin_lock_irq (&timer->it_lock); +unsigned long flags; + +/* +* irqsave is required to make timer_wait_running() work. +*/ +spin_lock_irqsave (&timer->it_lock, flags); +retry_delete: +/* +* Even if the timer is not longer accessible from other tasks +* it still might be armed and queued in the underlying timer +* mechanism. Worse, that timer mechanism might run the expiry +* function concurrently. +*/ if (timer_delete_hook (timer) ==TIMER_RETRY ) { -spin_unlock_irq (&timer->it_lock); +/* +* Timer is expired concurrently, prevent livelocks +* and pointless spinning on RT. +* +* timer_wait_running() drops timer::it_lock, which opens +* the possibility for another task to delete the timer. +* +* That's not possible here because this is invoked from +* do_exit() only for the last thread of the thread group. +* So no other task can access and delete that timer. +*/ +if (WARN_ON_ONCE (timer_wait_running (timer, &flags) != timer)) +return ; + goto retry_delete; }list_del (&timer->list); -spin_unlock_irq (&timer->it_lock); +spin_unlock_irqrestore (&timer->it_lock, flags);release_posix_timer (timer,IT_ID_SET ); }/* -* This is called by do_exit or de_thread, only when nobody else can -* modify the signal->posix_timers list. Yet we need sighand->siglock -* to prevent the race with /proc/pid/timers. +* Invoked from do_exit() when the last thread of a thread group exits. +* At that point no other task can access the timers of the dying +* task anymore. */ void exit_itimers (struct task_struct *tsk) {
@@ -1067,10 +1092,12 @@ void exit_itimers(struct task_struct *tsk)if (list_empty (&tsk->signal->posix_timers))return ; +/* Protect against concurrent read via /proc/$PID/timers */ spin_lock_irq (&tsk->sighand->siglock);list_replace_init (&tsk->signal->posix_timers, &timers);spin_unlock_irq (&tsk->sighand->siglock); +/* The timers are not longer accessible via tsk::signal */ while (!list_empty (&timers)) { tmr = list_first_entry(&timers, struct k_itimer, list);itimer_delete (tmr);
PATCH 2/20 posix-timers: Ensure timer ID search-loop limit is valid
In reply to Thomas Gleixnerposix_timer_add() tries to allocate a posix timer ID by starting from the cached ID which was stored by the last successful allocation.
This is done in a loop searching the ID space for a free slot one by one. The loop has to terminate when the search wrapped around to the starting point.
But that's racy vs. establishing the starting point. That is read out lockless, which leads to the following problem:
CPU0 CPU1posix_timer_add()
start = sig->posix_timer_id;
lock(hash_lock);
... posix_timer_add()
if (++sig->posix_timer_id < 0)
start = sig->posix_timer_id;
sig->posix_timer_id = 0;So CPU1 can observe a negative start value, i.e. -1, and the loop break never happens because the condition can never be true:
if (sig->posix_timer_id == start)
break;
While this is unlikely to ever turn into an endless loop as the ID space is huge (INT_MAX), the racy read of the start value caught the attention of KCSAN and Dmitry unearthed that incorrectness.
Rewrite it so that the start condition can never observe the negative value and annotate the read and the write with READ_ONCE()/WRITE_ONCE().
--- include/linux/sched/signal.h | 2 +- kernel/time/posix-timers.c | 30 +++++++++++++++++------------- 2 files changed, 18 insertions(+), 14 deletions(-)
include/linux/sched/signal.h +1 -1
@@ -135,7 +135,7 @@ struct signal_struct {#ifdef CONFIG_POSIX_TIMERS /* POSIX.1b Interval Timers */ -int posix_timer_id; +unsigned int next_posix_timer_id;struct list_head posix_timers;/* ITIMER_REAL timer for the process */
kernel/time/posix-timers.c +17 -13
@@ -140,25 +140,29 @@ static struct k_itimer *posix_timer_by_istatic int posix_timer_add (struct k_itimer *timer) {struct signal_struct *sig = current->signal; -int first_free_id = sig->posix_timer_id;struct hlist_head *head; -int ret = -ENOENT ; +unsigned int start, id; -do { +/* Can be written by a different task concurrently in the loop below */ + start =READ_ONCE (sig->next_posix_timer_id); + +for (id = ~start; start != id; id++) {spin_lock (&hash_lock); - head = &posix_timers_hashtable[hash (sig, sig->posix_timer_id)]; -if (!__posix_timers_find (head, sig, sig->posix_timer_id)) { + id = sig->next_posix_timer_id; + +/* Write the next ID back. Clamp it to the positive space */ +WRITE_ONCE (sig->next_posix_timer_id, (id +1 ) &INT_MAX ); + + head = &posix_timers_hashtable[hash (sig, id)]; +if (!__posix_timers_find (head, sig, id)) {hlist_add_head_rcu (&timer->t_hash, head); - ret = sig->posix_timer_id; +spin_unlock (&hash_lock); +return id; } -if (++sig->posix_timer_id <0 ) - sig->posix_timer_id =0 ; -if ((sig->posix_timer_id == first_free_id) && (ret == -ENOENT )) -/* Loop over all possible ids completed */ - ret = -EAGAIN ;spin_unlock (&hash_lock); - }while (ret == -ENOENT ); -return ret; + } +/* POSIX return code when no timer ID could be allocated */ +return -EAGAIN ; }static inline void unlock_timer (struct k_itimer *timr,unsigned long flags)
Frederic Weisbecker
maintainerRe: [patch 02/20] posix-timers: Ensure timer ID search-loop limit is valid
Quoted 64 lines · Thomas Gleixner
posix_timer_add()tries to allocate a posix timer ID by starting from the cached ID which was stored by the last successful allocation.This is done in a loop searching the ID space for a free slot one by one. The loop has to terminate when the search wrapped around to the starting point.
But that's racy vs. establishing the starting point. That is read out lockless, which leads to the following problem:
CPU0 CPU1
posix_timer_add()
start =sig->posix_timer_id;
lock(hash_lock);
...posix_timer_add()
if (++sig->posix_timer_id < 0)start = sig->posix_timer_id; sig->posix_timer_id = 0;So CPU1 can observe a negative start value, i.e. -1, and the loop break never happens because the condition can never be true:
if (
sig->posix_timer_id== start)break;While this is unlikely to ever turn into an endless loop as the ID space is huge (
INT_MAX), the racy read of the start value caught the attention of KCSAN and Dmitry unearthed that incorrectness.Rewrite it so that the start condition can never observe the negative value and annotate the read and the write with READ_ONCE()/WRITE_ONCE().
Reported-by [email protected]Reported-by Dmitry Vyukov <[email protected]>Signed-off-by Thomas Gleixner <[email protected]>--- include/linux/sched/signal.h | 2 +- kernel/time/posix-timers.c | 30 +++++++++++++++++------------- 2 files changed, 18 insertions(+), 14 deletions(-)include/linux/sched/signal.h +1
-1@@ -135,7 +135,7 @@ struct signal_struct {#ifdef CONFIG_POSIX_TIMERS /* POSIX.1b Interval Timers */ -int posix_timer_id; +unsigned int next_posix_timer_id;struct list_head posix_timers;/* ITIMER_REAL timer for the process */ kernel/time/posix-timers.c +2
-3@@ -140,25 +140,29 @@ static struct k_itimer *posix_timer_by_istatic int posix_timer_add (struct k_itimer *timer) {struct signal_struct *sig = current->signal; -int first_free_id = sig->posix_timer_id;struct hlist_head *head; -int ret = -ENOENT ; +unsigned int start, id; - do { +/* Can be written by a different task concurrently in the loop below */
kernel/time/posix-timers.c static struct k_itimer *posix_timer_by_i · line 154
Quoted 10 lines
kernel/time/posix-timers.c +7
-2+ start =READ_ONCE (sig->next_posix_timer_id); + +for (id = ~start; start != id; id++) {spin_lock (&hash_lock); - head = &posix_timers_hashtable[hash (sig, sig->posix_timer_id)]; -if (!__posix_timers_find (head, sig, sig->posix_timer_id)) { + id = sig->next_posix_timer_id; + +/* Write the next ID back. Clamp it to the positive space */ +WRITE_ONCE (sig->next_posix_timer_id, (id +1 ) &INT_MAX );
Isn't that looping forever?
Thanks.
Re: [patch 02/20] posix-timers: Ensure timer ID search-loop limit is valid
Quoted 16 lines · Frederic Weisbecker
kernel/time/posix-timers.c static struct k_itimer *posix_timer_by_i · line 154
Quoted 13 lines · Thomas Gleixner
kernel/time/posix-timers.c +8
-3- do { +/* Can be written by a different task concurrently in the loop below */ + start =READ_ONCE (sig->next_posix_timer_id); + +for (id = ~start; start != id; id++) {spin_lock (&hash_lock); - head = &posix_timers_hashtable[hash(sig, sig->posix_timer_id)]; - if (!__posix_timers_find(head, sig, sig->posix_timer_id)) { + id = sig->next_posix_timer_id; + +/* Write the next ID back. Clamp it to the positive space */ +WRITE_ONCE (sig->next_posix_timer_id, (id +1 ) &INT_MAX );Isn't that looping forever?
No. The loop breaks when @id reaches the locklessly read out @start value again.
I admit that the 'id = ~start' part in the for() expression is confusing without a comment. That initial @id value is in the invalid space to make sure that the termination condition 'start != id' does not trigger right away. But that value gets immediately overwritten after acquiring hash_lock by the real sig->next_posix_timer_id value.
The clamp to the positive space has nothing to do with that. That's required because the ID must be positive as a negative value would be an error when returned, right?
So the whole thing works like this:
start = READ_LOCKLESS(sig->next_id);
// Enfore that id and start are different to not terminate right away id = ~start;
loop:
if (id == start)
goto fail;
lock()
id = sig->next_id; <-- stable readout
sig->next_id = (id + 1) & INT_MAX; <-- prevent going negative
if (unused_id(id)) {
add_timer_to_hash(timer, id);
unlock();
return id;
} id++;
unlock();
goto loop;
As the initial lockless readout is guaranteed to be in the positive space, how is that supposed to be looping forever?
Admittedly this can be written less obscure, but not tonight :)
Thanks,
tglx
Re: [patch 02/20] posix-timers: Ensure timer ID search-loop limit is valid
Quoted 24 lines · Thomas Gleixner
On Fri, May 05 2023 at 16:50, Frederic Weisbecker wrote:
So the whole thing works like this:start = READ_LOCKLESS(sig->next_id);// Enfore that id and start are different to not terminate right away id = ~start;loop:
if (id == start) goto fail; lock() id = sig->next_id; <-- stable readout sig->next_id = (id + 1) & INT_MAX; <-- prevent going negative if (unused_id(id)) { add_timer_to_hash(timer, id); unlock(); return id; } id++; unlock(); goto loop;
Quoted 2 lines
As the initial lockless readout is guaranteed to be in the positive space, how is that supposed to be looping forever?
Unless you think about the theoretical case of an unlimited number of threads sharing the signal_struct which all concurrently try to allocate a timer id and then releasing it immediately again (to avoid resource limit exhaustion). Theoretically possible, but is this a real concern with a timer ID space of 2G?
I'm sure that it's incredibly hard to exploit this, but what's really bothering me is the hash table itself. The only reason why we have that is CRIU.
The only alternative solution I could come up with is a paritioned xarray where the index space would be segmented for each TGID, i.e.
segment.start = TGID * MAX_TIMERS_PER_PROCESS
segment.end = segment.start + MAX_TIMERS_PER_PROCESS - 1
where MAX_TIMERS_PER_PROCESS could be a copius 2^16 which would work for both 32bit and 64bit TID limits.
That would avoid the hash table lookups and the related issues, but OTH it would require to allocate one extra page per TGID if the application uses a single posix timer.
Not sure whether that's worth it though.
Thanks,
tglx
Re: [patch 02/20] posix-timers: Ensure timer ID search-loop limit is valid
Quoted 10 lines · Thomas Gleixner
Quoted 3 lines · Thomas Gleixner
On Fri, May 05 2023 at 16:50, Frederic Weisbecker wrote:
As the initial lockless readout is guaranteed to be in the positive space, how is that supposed to be looping forever?Unless you think about the theoretical case of an unlimited number of threads sharing the
signal_structwhich all concurrently try to allocate a timer id and then releasing it immediately again (to avoid resource limit exhaustion). Theoretically possible, but is this a real concern with a timer ID space of 2G?
It only hurts the process which does this and does not inflict any latencies by holding hash_lock over the full search for a free spot.
Quoted 6 lines
The only alternative solution I could come up with is a paritioned xarray where the index space would be segmented for each TGID, i.e.
segment.start = TGID *
MAX_TIMERS_PER_PROCESS
segment.end = segment.start +MAX_TIMERS_PER_PROCESS- 1
Quoted 8 lines
where
MAX_TIMERS_PER_PROCESScould be a copius 2^16 which would work for both 32bit and 64bit TID limits.That would avoid the hash table lookups and the related issues, but OTH it would require to allocate one extra page per TGID if the application uses a single posix timer.
Not sure whether that's worth it though.
More thoughts on this. If we go there and accept the extra page of memory then we can just go all the way and make the xarray per process, actually per signal.
That would also require another change, namely making the preallocated sigqueue part of struct k_itimer, which in turn would not be the worst of all ideas as it gets rid of the lookup in posixtimer_rearm() and would also allow for some clever handling of the nasty SIG_IGN issues.
Though that's separate from the problem at hand.
Thanks,
tglx
Re: [patch 02/20] posix-timers: Ensure timer ID search-loop limit is valid
Quoted 14 lines · Thomas Gleixner
Quoted 13 lines · Thomas Gleixner
The only alternative solution I could come up with is a paritioned xarray where the index space would be segmented for each TGID, i.e.
segment.start = TGID *
MAX_TIMERS_PER_PROCESS
segment.end = segment.start +MAX_TIMERS_PER_PROCESS- 1where
MAX_TIMERS_PER_PROCESScould be a copius 2^16 which would work for both 32bit and 64bit TID limits.That would avoid the hash table lookups and the related issues, but OTH it would require to allocate one extra page per TGID if the application uses a single posix timer.
Quoted 5 lines
Quoted 1 line
Not sure whether that's worth it though.
More thoughts on this. If we go there and accept the extra page of memory then we can just go all the way and make the xarray per process, actually per signal.
Thinking more about it. The current scheme how timer ID allocation works is really interesting vs. CRIU.
Assume a process creates/deletes timers frequently. It's not hard to move the next ID close to INT_MAX, i.e. 2G
Now checkpoint that thing and restore it which means to do the create/delete dance to move next ID up to the last one-1. Will only take a couple of hours....
Thanks,
tglx
Re: [patch 02/20] posix-timers: Ensure timer ID search-loop limit is valid
Quoted 8 lines · Thomas Gleixner
Quoted 3 lines · Thomas Gleixner
More thoughts on this. If we go there and accept the extra page of memory then we can just go all the way and make the xarray per process, actually per signal.
Thinking more about it. The current scheme how timer ID allocation works is really interesting vs. CRIU.
Quoted 6 lines
Assume a process creates/deletes timers frequently. It's not hard to move the next ID close to
INT_MAX, i.e. 2GNow checkpoint that thing and restore it which means to do the create/delete dance to move next ID up to the last one-1. Will only take a couple of hours....
I'm cursing myself for overlooking this back then when the CRIU changes to the timer ID management were made. Why?
Because that created an ABI which CRIU relies on.
The proper solution for this would be to make it possible to create a timer with a given ID. That's not rocket science, but we need buy in from the CRIU folks. Otherwise we are up the regression creek without a paddle.
Thanks,
tglx
[RFD] posix-timers: CRIU woes
Hi!
This is a summary of several mails so that the CRIU people have the full picture.
A recent syzbot report made me look at the timer ID management, which was modified 7 years ago to accomodate CRIU:
5ed67f05f66c ("posix timers: Allocate timer id per process (v2)")
and introduced that reported issue along with a bogus loop termination problem. See
https://lore.kernel.org/lkml/[email protected]/ https://lore.kernel.org/lkml/[email protected]
for details.
The intent to make the timer IDs per process is definitely correct, but the implementation is beyond suboptimal. I really regret that I did not catch this back then when picking those changes up.
The way it works is that each process keeps a 'next_timer_id' which it uses to allocate the next timer. That allows CRIU to reconstruct timers with the same ID by walking the ID space via
do {
timer_create(&timer, ...., &id);
if (id == original_id)
goto success;
timer_delete(&timer);
} while (idspace_not_exhausted());That works by some definition of works, but it is problematic in two ways:
1) As the timer ID space is up to INT_MAX, a process which creates and deletes timers frequently, can easily move up close to the INT_MAX id space over time.
If such a process is checkpointed and restored, then the above loop will run for at least an hour to restore a single timer.
And no, this is not only a hypothetical issue. There are legitimate scenarios where threads are created and the control thread arms a posix CPU timer on them. Such threads can be torn down on a regular base due to thread pool consolidations. As CRIU does not happen every 5 minutes it's not completely unlikely that such a process surives quite some time on a particular host and thereby approaches the ID space limit.
Sure we can restrict the ID space to a way smaller number so the search wraps around earlier, but what's a sensible limit?
Though restricting the ID space has its own issue vs. backwards compability. A process which created a timer on an older kernel with an ID larger than the newer kernels ID limit cannot longer be restored on that newer kernel.
Aside of that it does not solve the other problem this created:
2) That change created an user space ABI, which means that the kernel side has to stick with this next ID search mechanism forever.
That prevents to get rid of that global lock and hash table by sticking an xarray into task::signal which makes a lot of sense in terms of cache locality and gets rid of the extra timer list management in task::signal. Making this change would be very useful to address some other issues in the posix-timer code without creating yet more duct tape horrors.
Such a change obviously has to aim for a dense ID space to keep the memory overhead low, but that breaks existing CRIU userspace because dense ID space and next ID search does not fit together.
Next ID search is obviously creating non-recoverable holes in the case that timers are deleted afterwards.
A dense ID space approach can create holes too, but they are recoverable and well within the resource limits, because the process has to be able to create enough timers in the first place in order to release those in the middle.
With the next ID search brute force recovery is not possible on a kernel with dense ID as there is no way to create all intermediate timers first before reaching the one at the far end due to resource limits.
So because of that half thought out user space ABI we are now up the regression creek without a paddle, unless CRIU can accomodate to a different restore mechanism to lift this restriction from the kernel.
Thoughts?
Thanks,
tglx
Re: [RFD] posix-timers: CRIU woes
Quoted 87 lines · Thomas Gleixner
Hi!
This is a summary of several mails so that the CRIU people have the full picture.
A recent syzbot report made me look at the timer ID management, which was modified 7 years ago to accomodate CRIU:
5ed67f05f66c("posix timers: Allocate timer id per process (v2)")and introduced that reported issue along with a bogus loop termination problem. See
https://lore.kernel.org/lkml/[email protected]/ https://lore.kernel.org/lkml/[email protected]for details.
The intent to make the timer IDs per process is definitely correct, but the implementation is beyond suboptimal. I really regret that I did not catch this back then when picking those changes up.
The way it works is that each process keeps a '
next_timer_id' which it uses to allocate the next timer. That allows CRIU to reconstruct timers with the same ID by walking the ID space viado { timer_create(&timer, ...., &id); if (id == original_id) goto success; timer_delete(&timer); } while (idspace_not_exhausted());That works by some definition of works, but it is problematic in two ways:
1) As the timer ID space is up to
INT_MAX, a process which creates and deletes timers frequently, can easily move up close to theINT_MAXid space over time.If such a process is checkpointed and restored, then the above loop will run for at least an hour to restore a single timer.
And no, this is not only a hypothetical issue. There are legitimate scenarios where threads are created and the control thread arms a posix CPU timer on them. Such threads can be torn down on a regular base due to thread pool consolidations. As CRIU does not happen every 5 minutes it's not completely unlikely that such a process surives quite some time on a particular host and thereby approaches the ID space limit.
Sure we can restrict the ID space to a way smaller number so the search wraps around earlier, but what's a sensible limit?
Though restricting the ID space has its own issue vs. backwards compability. A process which created a timer on an older kernel with an ID larger than the newer kernels ID limit cannot longer be restored on that newer kernel.
Aside of that it does not solve the other problem this created:
2) That change created an user space ABI, which means that the kernel side has to stick with this next ID search mechanism forever.
That prevents to get rid of that global lock and hash table by sticking an xarray into
task::signalwhich makes a lot of sense in terms of cache locality and gets rid of the extra timer list management intask::signal. Making this change would be very useful to address some other issues in the posix-timer code without creating yet more duct tape horrors.Such a change obviously has to aim for a dense ID space to keep the memory overhead low, but that breaks existing CRIU userspace because dense ID space and next ID search does not fit together.
Next ID search is obviously creating non-recoverable holes in the case that timers are deleted afterwards.
A dense ID space approach can create holes too, but they are recoverable and well within the resource limits, because the process has to be able to create enough timers in the first place in order to release those in the middle.
With the next ID search brute force recovery is not possible on a kernel with dense ID as there is no way to create all intermediate timers first before reaching the one at the far end due to resource limits.
Quoted 5 lines
So because of that half thought out user space ABI we are now up the regression creek without a paddle, unless CRIU can accomodate to a different restore mechanism to lift this restriction from the kernel.
Thoughts?
Maybe we can do something similar to /proc/sys/kernel/ns_last_pid? Switch to per-(process->signal) idr based approach with idr_set_cursor to set next id for next posix timer from new sysctl?
Quoted 6 lines
Thanks,
tglx
Signature · 2 lines
Best regards, Tikhomirov Pavel Senior Software Developer, Virtuozzo.
Re: [RFD] posix-timers: CRIU woes
Pavel!
Quoted 10 lines · Pavel Tikhomirov
Quoted 5 lines · Thomas Gleixner
So because of that half thought out user space ABI we are now up the regression creek without a paddle, unless CRIU can accomodate to a different restore mechanism to lift this restriction from the kernel.
Thoughts?
Maybe we can do something similar to
/proc/sys/kernel/ns_last_pid? Switch to per-(process->signal) idr based approach withidr_set_cursorto set next id for next posix timer from new sysctl?
I'm not a fan of such sysctls. We have already too many of them and that particular one does not buy much.
We can simply let timer_create() or a new syscall create a timer at a given ID.
That allows CRIU to restore any checkpointed process no matter which kernel version it came from without doing this insane create/delete dance.
The downside is that this allows to create stupidly sparse timer IDs even for the non CRIU case, which increases per process kernel memory consumption and creates slightly more overhead in the signal delivery path. The latter is a burden on the process owning the timer and not affecting expiry, which is a context stealing operation. The memory part needs eventually some thoughts vs. accounting.
If the 'explicit at ID' option is not used then the ID mechanism is optimzied for dense IDs by using the first available ID in a bottom up search, which recovers holes created by a timer_delete() operation.
Thanks,
tglx
Re: [RFD] posix-timers: CRIU woes
Quoted 8 lines · Thomas Gleixner
Pavel!
Quoted 5 lines · Pavel Tikhomirov
Quoted 4 lines · Thomas Gleixner
So because of that half thought out user space ABI we are now up the regression creek without a paddle, unless CRIU can accomodate to a different restore mechanism to lift this restriction from the kernel.
Quoted 8 lines
Quoted 5 lines
Quoted 1 line
Thoughts?
Maybe we can do something similar to
/proc/sys/kernel/ns_last_pid? Switch to per-(process->signal) idr based approach withidr_set_cursorto set next id for next posix timer from new sysctl?I'm not a fan of such sysctls. We have already too many of them and that particular one does not buy much.
Sorry, it was a bad idea, what you suggest below is much better.
Quoted 3 lines
We can simply let
timer_create()or a new syscall create a timer at a given ID.
Yes this would work for CRIU. (note: in neighbor thread Andrei writes about adding a bit to sigevent.sigev_notify to request a timer with a specified id, new syscall is also a good option)
Quoted 4 lines
That allows CRIU to restore any checkpointed process no matter which kernel version it came from without doing this insane create/delete dance.
Yes, for CRIU this kind of API change is a big improvement.
Quoted 11 lines
The downside is that this allows to create stupidly sparse timer IDs even for the non CRIU case, which increases per process kernel memory consumption and creates slightly more overhead in the signal delivery path. The latter is a burden on the process owning the timer and not affecting expiry, which is a context stealing operation. The memory part needs eventually some thoughts vs. accounting.
If the 'explicit at ID' option is not used then the ID mechanism is optimzied for dense IDs by using the first available ID in a bottom up search, which recovers holes created by a
timer_delete()operation.
Not sure how kernel memory consumption increases with sparse timer IDs, global hashtable (posix_timers_hashtable) is the same size anyway, entries in hlists can be distributed differently as hash depends on id directly but we have same number of entries. Probably I miss something, why do we need dense IDs?
Quoted 4 lines
Thanks,
tglx
Signature · 2 lines
Best regards, Tikhomirov Pavel Senior Software Developer, Virtuozzo.
Re: [RFD] posix-timers: CRIU woes
Quoted 5 lines · Pavel Tikhomirov
Not sure how kernel memory consumption increases with sparse timer IDs, global hashtable (
posix_timers_hashtable) is the same size anyway, entries in hlists can be distributed differently as hash depends on id directly but we have same number of entries. Probably I miss something, why do we need dense IDs?
The proposal was to remove the global hash and use a signal_struct based xarray instead.
Re: [RFD] posix-timers: CRIU woes
In reply to Pavel TikhomirovQuoted 12 lines · Pavel Tikhomirov
Quoted 10 lines · Thomas Gleixner
The downside is that this allows to create stupidly sparse timer IDs even for the non CRIU case, which increases per process kernel memory consumption and creates slightly more overhead in the signal delivery path. The latter is a burden on the process owning the timer and not affecting expiry, which is a context stealing operation. The memory part needs eventually some thoughts vs. accounting.
If the 'explicit at ID' option is not used then the ID mechanism is optimzied for dense IDs by using the first available ID in a bottom up search, which recovers holes created by a
timer_delete()operation.
Quoted 5 lines
Not sure how kernel memory consumption increases with sparse timer IDs, global hashtable (
posix_timers_hashtable) is the same size anyway, entries in hlists can be distributed differently as hash depends on id directly but we have same number of entries. Probably I miss something, why do we need dense IDs?
Because I want to get rid of the global hash table as I explained in my summary mail.
Thanks,
tglx
RE: [RFD] posix-timers: CRIU woes
In reply to Pavel TikhomirovFrom: Pavel Tikhomirov
Quoted 1 line
Sent: 10 May 2023 05:37
...
Quoted 4 lines
Quoted 4 lines
A dense ID space approach can create holes too, but they are recoverable and well within the resource limits, because the process has to be able to create enough timers in the first place in order to release those in the middle.
While it doesn't help at all for creating items with fixed ids, my 'favourite' scheme for allocating ids it to allocate a number that will be a perfect hash onto an empty hash table slot.
The lookup check is then just array[id & mask].id == id. A FIFO freelist can be run through the free entries and the high bits incremented each time a slot is used. So allocation is usually fixed cost.
If the table is full it's size can easily be doubled. If the number of unused entries is doubled each time the table size is doubled then the you (more or less) guarantee that an id won't get reused any time soon after it is freed.
This would be ok for restoring ids allocated by the same scheme. But would need a fallback for restoring pathological list of ids.
David
-
Registered Address Lakeside, Bramley Road, Mount Farm, Milton Keynes, MK1 1PT, UK Registration No: 1397386 (Wales)
Re: [RFD] posix-timers: CRIU woes
In reply to Thomas GleixnerQuoted 88 lines · Thomas Gleixner
Hi!
This is a summary of several mails so that the CRIU people have the full picture.
A recent syzbot report made me look at the timer ID management, which was modified 7 years ago to accomodate CRIU:
5ed67f05f66c("posix timers: Allocate timer id per process (v2)")and introduced that reported issue along with a bogus loop termination problem. See
https://lore.kernel.org/lkml/[email protected]/ https://lore.kernel.org/lkml/[email protected]for details.
The intent to make the timer IDs per process is definitely correct, but the implementation is beyond suboptimal. I really regret that I did not catch this back then when picking those changes up.
The way it works is that each process keeps a '
next_timer_id' which it uses to allocate the next timer. That allows CRIU to reconstruct timers with the same ID by walking the ID space viado { timer_create(&timer, ...., &id); if (id == original_id) goto success; timer_delete(&timer); } while (idspace_not_exhausted());That works by some definition of works, but it is problematic in two ways:
1) As the timer ID space is up to
INT_MAX, a process which creates and deletes timers frequently, can easily move up close to theINT_MAXid space over time.If such a process is checkpointed and restored, then the above loop will run for at least an hour to restore a single timer.
And no, this is not only a hypothetical issue. There are legitimate scenarios where threads are created and the control thread arms a posix CPU timer on them. Such threads can be torn down on a regular base due to thread pool consolidations. As CRIU does not happen every 5 minutes it's not completely unlikely that such a process surives quite some time on a particular host and thereby approaches the ID space limit.
Sure we can restrict the ID space to a way smaller number so the search wraps around earlier, but what's a sensible limit?
Though restricting the ID space has its own issue vs. backwards compability. A process which created a timer on an older kernel with an ID larger than the newer kernels ID limit cannot longer be restored on that newer kernel.
Aside of that it does not solve the other problem this created:
2) That change created an user space ABI, which means that the kernel side has to stick with this next ID search mechanism forever.
That prevents to get rid of that global lock and hash table by sticking an xarray into
task::signalwhich makes a lot of sense in terms of cache locality and gets rid of the extra timer list management intask::signal. Making this change would be very useful to address some other issues in the posix-timer code without creating yet more duct tape horrors.Such a change obviously has to aim for a dense ID space to keep the memory overhead low, but that breaks existing CRIU userspace because dense ID space and next ID search does not fit together.
Next ID search is obviously creating non-recoverable holes in the case that timers are deleted afterwards.
A dense ID space approach can create holes too, but they are recoverable and well within the resource limits, because the process has to be able to create enough timers in the first place in order to release those in the middle.
With the next ID search brute force recovery is not possible on a kernel with dense ID as there is no way to create all intermediate timers first before reaching the one at the far end due to resource limits.
Quoted 5 lines
So because of that half thought out user space ABI we are now up the regression creek without a paddle, unless CRIU can accomodate to a different restore mechanism to lift this restriction from the kernel.
Thoughts?
Hi Thomas,
If you give us a new API to create timers with specified id-s, we will figure out how to live with it. It isn't good to ask users to update CRIU to work on new kernels, but here are reasons and event improvements for CRIU, so I think it's worth it.
As for API, we can use one bit of sigevent.sigev_notify to request a timer with a specified id.
Thanks,
Andrei
Re: [RFD] posix-timers: CRIU woes
Quoted 93 lines · Andrey Vagin
Quoted 92 lines · Thomas Gleixner
Hi!
This is a summary of several mails so that the CRIU people have the full picture.
A recent syzbot report made me look at the timer ID management, which was modified 7 years ago to accomodate CRIU:
5ed67f05f66c("posix timers: Allocate timer id per process (v2)")and introduced that reported issue along with a bogus loop termination problem. See
https://lore.kernel.org/lkml/[email protected]/ https://lore.kernel.org/lkml/[email protected]for details.
The intent to make the timer IDs per process is definitely correct, but the implementation is beyond suboptimal. I really regret that I did not catch this back then when picking those changes up.
The way it works is that each process keeps a '
next_timer_id' which it uses to allocate the next timer. That allows CRIU to reconstruct timers with the same ID by walking the ID space viado { timer_create(&timer, ...., &id); if (id == original_id) goto success; timer_delete(&timer); } while (idspace_not_exhausted());That works by some definition of works, but it is problematic in two ways:
1) As the timer ID space is up to
INT_MAX, a process which creates and deletes timers frequently, can easily move up close to theINT_MAXid space over time.If such a process is checkpointed and restored, then the above loop will run for at least an hour to restore a single timer.
And no, this is not only a hypothetical issue. There are legitimate scenarios where threads are created and the control thread arms a posix CPU timer on them. Such threads can be torn down on a regular base due to thread pool consolidations. As CRIU does not happen every 5 minutes it's not completely unlikely that such a process surives quite some time on a particular host and thereby approaches the ID space limit.
Sure we can restrict the ID space to a way smaller number so the search wraps around earlier, but what's a sensible limit?
Though restricting the ID space has its own issue vs. backwards compability. A process which created a timer on an older kernel with an ID larger than the newer kernels ID limit cannot longer be restored on that newer kernel.
Aside of that it does not solve the other problem this created:
2) That change created an user space ABI, which means that the kernel side has to stick with this next ID search mechanism forever.
That prevents to get rid of that global lock and hash table by sticking an xarray into
task::signalwhich makes a lot of sense in terms of cache locality and gets rid of the extra timer list management intask::signal. Making this change would be very useful to address some other issues in the posix-timer code without creating yet more duct tape horrors.Such a change obviously has to aim for a dense ID space to keep the memory overhead low, but that breaks existing CRIU userspace because dense ID space and next ID search does not fit together.
Next ID search is obviously creating non-recoverable holes in the case that timers are deleted afterwards.
A dense ID space approach can create holes too, but they are recoverable and well within the resource limits, because the process has to be able to create enough timers in the first place in order to release those in the middle.
With the next ID search brute force recovery is not possible on a kernel with dense ID as there is no way to create all intermediate timers first before reaching the one at the far end due to resource limits.
So because of that half thought out user space ABI we are now up the regression creek without a paddle, unless CRIU can accomodate to a different restore mechanism to lift this restriction from the kernel.
Quoted 8 lines
Quoted 1 line
Thoughts?
Hi Thomas,
If you give us a new API to create timers with specified id-s, we will figure out how to live with it. It isn't good to ask users to update CRIU to work on new kernels, but here are reasons and event improvements for CRIU, so I think it's worth it.
I agree, any API to create timers with specified id-s would work for new CRIU versions.
Quoted 3 lines
As for API, we can use one bit of sigevent.sigev_notify to request a timer with a specified id.
Yes, I agree, this kind of API is a good option.
Quoted 3 lines
Thanks,
Andrei
Signature · 2 lines
Best regards, Tikhomirov Pavel Senior Software Developer, Virtuozzo.
Re: [RFD] posix-timers: CRIU woes
Quoted 6 lines · Pavel Tikhomirov
Quoted 5 lines · Andrey Vagin
Quoted 5 lines
So because of that half thought out user space ABI we are now up the regression creek without a paddle, unless CRIU can accomodate to a different restore mechanism to lift this restriction from the kernel.
Quoted 7 lines
Quoted 4 lines
If you give us a new API to create timers with specified id-s, we will figure out how to live with it. It isn't good to ask users to update CRIU to work on new kernels, but here are reasons and event improvements for CRIU, so I think it's worth it.
I agree, any API to create timers with specified id-s would work for new CRIU versions.
The real question is whether this will cause any upheaval when a new kernel meets a non-updated CRIU stack.
You know the UABI regression rules of the kernel...
Thanks,
tglx
Re: [RFD] posix-timers: CRIU woes
Quoted 12 lines · Thomas Gleixner
Quoted 11 lines · Pavel Tikhomirov
Quoted 9 lines · Andrey Vagin
Quoted 5 lines
So because of that half thought out user space ABI we are now up the regression creek without a paddle, unless CRIU can accomodate to a different restore mechanism to lift this restriction from the kernel.
If you give us a new API to create timers with specified id-s, we will figure out how to live with it. It isn't good to ask users to update CRIU to work on new kernels, but here are reasons and event improvements for CRIU, so I think it's worth it.
Quoted 5 lines
Quoted 2 lines
I agree, any API to create timers with specified id-s would work for new CRIU versions.
The real question is whether this will cause any upheaval when a new kernel meets a non-updated CRIU stack.
Creation of posix timer would hang forever in this loop https://github.com/checkpoint-restore/criu/blob/33dd66c6fc93c47213aaa0447a94d97ba1fa56ba/criu/pie/restorer.c#L1185 if old criu is run on new kernel (without consecutive id allocation) AFAICS.
Quoted 6 lines
You know the UABI regression rules of the kernel...
Thanks,
tglx
Signature · 2 lines
Best regards, Tikhomirov Pavel Senior Software Developer, Virtuozzo.
Re: [RFD] posix-timers: CRIU woes
Quoted 16 lines · Pavel Tikhomirov
Quoted 15 lines · Thomas Gleixner
Quoted 13 lines · Pavel Tikhomirov
Quoted 9 lines · Andrey Vagin
Quoted 5 lines
So because of that half thought out user space ABI we are now up the regression creek without a paddle, unless CRIU can accomodate to a different restore mechanism to lift this restriction from the kernel.
If you give us a new API to create timers with specified id-s, we will figure out how to live with it. It isn't good to ask users to update CRIU to work on new kernels, but here are reasons and event improvements for CRIU, so I think it's worth it.
I agree, any API to create timers with specified id-s would work for new CRIU versions.
Quoted 6 lines
Quoted 2 lines
The real question is whether this will cause any upheaval when a new kernel meets a non-updated CRIU stack.
Creation of posix timer would hang forever in this loop
https://github.com/checkpoint-restore/criu/blob/33dd66c6fc93c47213aaa0447a94d97ba1fa56ba/criu/pie/restorer.c#L1185
if old criu is run on new kernel (without consecutive id allocation) AFAICS.
Yes, because that "sanity" check
if ((long)next_id > args->posix_timers[i].spt.it_id)
which tries to establish whether the kernel provides timer IDs in strict increasing order does not work for that case.
It "works" to detect the IDR case on older kernels by chance, but not under all circumstances. Assume the following case:
Global IDR has a free slot at index 1
Restore tries to create a timer for index 2
That will also loop forever, unless some other process creates a timer and occupies the free slot at index 1, right?
So this needs a fix anyway, which should be done so that the new kernel case is at least properly detected.
But even then there is still the problem of "it worked before I upgraded the kernel".
IOW, we are still up a creek without a paddle, unless you would be willing to utilize the existing CRIU bug to distribute the 'deal with new kernel' mechanics as a bug bounty :)
Fix for the loop termination below.
Thanks,
tglx
--- criu/pie/restorer.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-)
criu/pie/restorer.c +13 -11
@@ -1169,10 +1169,10 @@ static int timerfd_arm(struct task_restostatic int create_posix_timers (struct task_restore_args *args) {int ret, i; -kernel_timer_t next_id; +kernel_timer_t next_id, timer_id;struct sigevent sev; -for (i =0 ; i < args->posix_timers_n; i++) { +for (i =0 , next_id =0 ; i < args->posix_timers_n; i++) { sev.sigev_notify = args->posix_timers[i].spt.it_sigev_notify; sev.sigev_signo = args->posix_timers[i].spt.si_signo;#ifdef __GLIBC__
@@ -1183,25 +1183,27 @@ static int create_posix_timers(struct ta sev.sigev_value.sival_ptr = args->posix_timers[i].spt.sival_ptr;while (1 ) { - ret =sys_timer_create (args->posix_timers[i].spt.clock_id, &sev, &next_id); + ret =sys_timer_create (args->posix_timers[i].spt.clock_id, &sev, &timer_id);if (ret <0 ) {pr_err ("Can't create posix timer - %d\n" , i);return ret; } -if (next_id == args->posix_timers[i].spt.it_id) +if (timer_id != next_id) { +pr_err ("Can't create timers, kernel don't give them consequently\n" ); +return -1 ; + } + + next_id++; + +if (timer_id == args->posix_timers[i].spt.it_id)break ; - ret =sys_timer_delete (next_id); + ret =sys_timer_delete (timer_id);if (ret <0 ) { -pr_err ("Can't remove temporaty posix timer 0x%x\n" , next_id); +pr_err ("Can't remove temporaty posix timer 0x%x\n" , timer_id);return ret; } - -if ((long )next_id > args->posix_timers[i].spt.it_id) { -pr_err ("Can't create timers, kernel don't give them consequently\n" ); -return -1 ; - } } }
Re: [RFD] posix-timers: CRIU woes
Quoted 24 lines · Thomas Gleixner
Quoted 16 lines · Pavel Tikhomirov
Quoted 15 lines · Thomas Gleixner
Quoted 13 lines · Pavel Tikhomirov
Quoted 9 lines · Andrey Vagin
Quoted 5 lines
So because of that half thought out user space ABI we are now up the regression creek without a paddle, unless CRIU can accomodate to a different restore mechanism to lift this restriction from the kernel.
If you give us a new API to create timers with specified id-s, we will figure out how to live with it. It isn't good to ask users to update CRIU to work on new kernels, but here are reasons and event improvements for CRIU, so I think it's worth it.
I agree, any API to create timers with specified id-s would work for new CRIU versions.
Quoted 6 lines
Quoted 2 lines
The real question is whether this will cause any upheaval when a new kernel meets a non-updated CRIU stack.
Creation of posix timer would hang forever in this loop
https://github.com/checkpoint-restore/criu/blob/33dd66c6fc93c47213aaa0447a94d97ba1fa56ba/criu/pie/restorer.c#L1185
if old criu is run on new kernel (without consecutive id allocation) AFAICS.
Quoted 6 lines
Yes, because that "sanity" check
if ((long)next_id > args->posix_timers[i].spt.it_id)which tries to establish whether the kernel provides timer IDs in strict increasing order does not work for that case.
Yes, this check is not perfect, but it does at least something: It detects that posix timer creation missed needed id (if you start from 0 and increase by 1 each time you can not reach number > N before reaching N).
Quoted 10 lines
It "works" to detect the IDR case on older kernels by chance, but not under all circumstances. Assume the following case:
Global IDR has a free slot at index 1
Restore tries to create a timer for index 2
That will also loop forever, unless some other process creates a timer and occupies the free slot at index 1, right?
Yes on old-old kernel, where there were no ids increasing on create/delete, CRIU is broken, but CRIU does not support kernels earlier than 3.11 (https://criu.org/Check_the_kernel#Basic) so probably we are fine.
git describe --contains 5ed67f05f66c
v3.10-rc1~171^2~9
Quoted 11 lines
So this needs a fix anyway, which should be done so that the new kernel case is at least properly detected.
But even then there is still the problem of "it worked before I upgraded the kernel".
IOW, we are still up a creek without a paddle, unless you would be willing to utilize the existing CRIU bug to distribute the 'deal with new kernel' mechanics as a bug bounty :) >
Fix for the loop termination below.
It fixes the loop for new kernel, I agree.
Quoted 62 lines
Thanks,
tglx
--- criu/pie/restorer.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-)criu/pie/restorer.c +13
-11@@ -1169,10 +1169,10 @@ static int timerfd_arm(struct task_restostatic int create_posix_timers (struct task_restore_args *args) {int ret, i; -kernel_timer_t next_id; +kernel_timer_t next_id, timer_id;struct sigevent sev; -for (i =0 ; i < args->posix_timers_n; i++) { +for (i =0 , next_id =0 ; i < args->posix_timers_n; i++) { sev.sigev_notify = args->posix_timers[i].spt.it_sigev_notify; sev.sigev_signo = args->posix_timers[i].spt.si_signo;#ifdef __GLIBC__@@ -1183,25 +1183,27 @@ static int create_posix_timers(struct ta sev.sigev_value.sival_ptr = args->posix_timers[i].spt.sival_ptr;while (1 ) { - ret =sys_timer_create (args->posix_timers[i].spt.clock_id, &sev, &next_id); + ret =sys_timer_create (args->posix_timers[i].spt.clock_id, &sev, &timer_id);if (ret <0 ) {pr_err ("Can't create posix timer - %d\n" , i);return ret; } -if (next_id == args->posix_timers[i].spt.it_id) +if (timer_id != next_id) { +pr_err ("Can't create timers, kernel don't give them consequently\n" ); +return -1 ; + } + + next_id++; + +if (timer_id == args->posix_timers[i].spt.it_id)break ; - ret =sys_timer_delete (next_id); + ret =sys_timer_delete (timer_id);if (ret <0 ) { -pr_err ("Can't remove temporaty posix timer 0x%x\n" , next_id); +pr_err ("Can't remove temporaty posix timer 0x%x\n" , timer_id);return ret; } - -if ((long )next_id > args->posix_timers[i].spt.it_id) { -pr_err ("Can't create timers, kernel don't give them consequently\n" ); -return -1 ; - } } }
Signature · 2 lines
Best regards, Tikhomirov Pavel Senior Software Developer, Virtuozzo.
Re: [RFD] posix-timers: CRIU woes
In reply to Thomas GleixnerQuoted 44 lines · Thomas Gleixner
Quoted 16 lines · Pavel Tikhomirov
Quoted 15 lines · Thomas Gleixner
Quoted 13 lines · Pavel Tikhomirov
Quoted 9 lines · Andrey Vagin
Quoted 5 lines
So because of that half thought out user space ABI we are now up the regression creek without a paddle, unless CRIU can accomodate to a different restore mechanism to lift this restriction from the kernel.
If you give us a new API to create timers with specified id-s, we will figure out how to live with it. It isn't good to ask users to update CRIU to work on new kernels, but here are reasons and event improvements for CRIU, so I think it's worth it.
I agree, any API to create timers with specified id-s would work for new CRIU versions.
Quoted 6 lines
Quoted 2 lines
The real question is whether this will cause any upheaval when a new kernel meets a non-updated CRIU stack.
Creation of posix timer would hang forever in this loop
https://github.com/checkpoint-restore/criu/blob/33dd66c6fc93c47213aaa0447a94d97ba1fa56ba/criu/pie/restorer.c#L1185
if old criu is run on new kernel (without consecutive id allocation) AFAICS.Yes, because that "sanity" check
if ((long)next_id > args->posix_timers[i].spt.it_id)which tries to establish whether the kernel provides timer IDs in strict increasing order does not work for that case.
It "works" to detect the IDR case on older kernels by chance, but not under all circumstances. Assume the following case:
Global IDR has a free slot at index 1
Restore tries to create a timer for index 2
That will also loop forever, unless some other process creates a timer and occupies the free slot at index 1, right?
So this needs a fix anyway, which should be done so that the new kernel case is at least properly detected.
Quoted 8 lines
But even then there is still the problem of "it worked before I upgraded the kernel".
IOW, we are still up a creek without a paddle, unless you would be willing to utilize the existing CRIU bug to distribute the 'deal with new kernel' mechanics as a bug bounty :)
Fix for the loop termination below.
I've prepared a PR with your patch (with minimal change) and added you Signed-off-by:, hope it's ok:
https://github.com/checkpoint-restore/criu/pull/2174
Quoted 62 lines
Thanks,
tglx
--- criu/pie/restorer.c | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-)criu/pie/restorer.c +13
-11@@ -1169,10 +1169,10 @@ static int timerfd_arm(struct task_restostatic int create_posix_timers (struct task_restore_args *args) {int ret, i; -kernel_timer_t next_id; +kernel_timer_t next_id, timer_id;struct sigevent sev; -for (i =0 ; i < args->posix_timers_n; i++) { +for (i =0 , next_id =0 ; i < args->posix_timers_n; i++) { sev.sigev_notify = args->posix_timers[i].spt.it_sigev_notify; sev.sigev_signo = args->posix_timers[i].spt.si_signo;#ifdef __GLIBC__@@ -1183,25 +1183,27 @@ static int create_posix_timers(struct ta sev.sigev_value.sival_ptr = args->posix_timers[i].spt.sival_ptr;while (1 ) { - ret =sys_timer_create (args->posix_timers[i].spt.clock_id, &sev, &next_id); + ret =sys_timer_create (args->posix_timers[i].spt.clock_id, &sev, &timer_id);if (ret <0 ) {pr_err ("Can't create posix timer - %d\n" , i);return ret; } -if (next_id == args->posix_timers[i].spt.it_id) +if (timer_id != next_id) { +pr_err ("Can't create timers, kernel don't give them consequently\n" ); +return -1 ; + } + + next_id++; + +if (timer_id == args->posix_timers[i].spt.it_id)break ; - ret =sys_timer_delete (next_id); + ret =sys_timer_delete (timer_id);if (ret <0 ) { -pr_err ("Can't remove temporaty posix timer 0x%x\n" , next_id); +pr_err ("Can't remove temporaty posix timer 0x%x\n" , timer_id);return ret; } - -if ((long )next_id > args->posix_timers[i].spt.it_id) { -pr_err ("Can't create timers, kernel don't give them consequently\n" ); -return -1 ; - } } }
Signature · 2 lines
Best regards, Tikhomirov Pavel Senior Software Developer, Virtuozzo.
Re: [RFD] posix-timers: CRIU woes
In reply to Thomas GleixnerQuoted 13 lines · Thomas Gleixner
Quoted 11 lines · Pavel Tikhomirov
Quoted 9 lines · Andrey Vagin
Quoted 5 lines
So because of that half thought out user space ABI we are now up the regression creek without a paddle, unless CRIU can accomodate to a different restore mechanism to lift this restriction from the kernel.
If you give us a new API to create timers with specified id-s, we will figure out how to live with it. It isn't good to ask users to update CRIU to work on new kernels, but here are reasons and event improvements for CRIU, so I think it's worth it.
Quoted 5 lines
Quoted 2 lines
I agree, any API to create timers with specified id-s would work for new CRIU versions.
The real question is whether this will cause any upheaval when a new kernel meets a non-updated CRIU stack.
It depends on what you mean by upheaval. We found that CRIU can be stuck in a busy loop with the new changes. I suggest thinking about how to work around this case and make sure that CRIU reports an error. The error should minimize the time that users will need to spend to find the reason and ways to resolve the problem.
One of the ways to fix the problem is to return indexes in a backward direction from INT_MAX to zero. But in the kernel, user indices can be converted back to "normal" values:kernel_timer_id = INT_MAX - user_timer_id;
I have one idea of how to make these changes without breaking CRIU. CRIU does a few special things. First, it does all timer operations from a thread leader. Second, it calls timer_settime only after creating all timers. Third, it calls timer_delete for the last timer only. Any of these events can be a trigger to switch to the new algo of allocating timer id-s, but new processes allocate indices according to old rules. It seems unfortunate that a real application will create a set of very sparse indices without triggering one of these events.
I don't think that it is worth doing something like this, but if we want to strictly follow the rules, it is the choice.
Quoted 2 lines
You know the UABI regression rules of the kernel...
There is no rule without exceptions... With all pros and cons, we may consider this case as an exception. From our side, we will try to make everything to minimize the impact. Here are steps off the top of my head:
* releasing the criu fix before the kernel release.
* update packages in Linux distros (Debian, Ubuntu, Fedora, and others that we will find).
* send an announcement to the criu mailing list and to users that we know.
* add the error to FAQ.
* create a GitHub issue with a full description.
Thanks,
Andrei
Re: [RFD] posix-timers: CRIU woes
Andrey!
Quoted 4 lines · Andrey Vagin
Quoted 2 lines · Thomas Gleixner
You know the UABI regression rules of the kernel...
Quoted 10 lines
There is no rule without exceptions... With all pros and cons, we may consider this case as an exception. From our side, we will try to make everything to minimize the impact. Here are steps off the top of my head:
* releasing the criu fix before the kernel release.
* update packages in Linux distros (Debian, Ubuntu, Fedora, and others that we will find).
* send an announcement to the criu mailing list and to users that we know.
* add the error to FAQ.
* create a GitHub issue with a full description.
Thanks for this plan. After digging deeper I managed to resolve the actual problem I was chasing without changing that ID generator at all.
The main pain point of having to do that lookup from the signal delivery path is gone, which made it trivial to do the fix for the SIG_IGN mess w/o these global lookups too.
Addressing this global ID issues I pointed out becomes therefore an orthogonal issue which we can handle completely independent of the kernel internal problems I'm trying to address.
I still think we should do that for sanity sake, but we can stage that properly without dependencies outside of this particular ABI problem. That makes me way more comfortable as that's something which can be in the worst case reverted without doing any other damage.
Thanks,
tglx
Re: [RFD] posix-timers: CRIU woes
In reply to Andrey VaginOn Wed, May 10, 2023 at 01:16:26AM -0700, Andrey Vagin wrote:
...
Quoted 9 lines
Hi Thomas,
If you give us a new API to create timers with specified id-s, we will figure out how to live with it. It isn't good to ask users to update CRIU to work on new kernels, but here are reasons and event improvements for CRIU, so I think it's worth it.
As for API, we can use one bit of sigevent.sigev_notify to request a timer with a specified id.
Which will do the trick but would look somehow strange I think, since signals are not some how related to timer's ID. Another option might be to use output created_timer_id parameter as an input cookie.
Say we describe input as
struct {
u32 magic;
timer_t timer_id;
};Then if magic doesn't match we use created_timer_id for output only, and otherwise we read timer_id from input and use it. Of course there is a chance that some unitialized memory passed with existing old programs but i think false positive gonna be very-very low if ever. Just IMHO.
Cyrill
Re: [patch 02/20] posix-timers: Ensure timer ID search-loop limit is valid
In reply to Thomas GleixnerQuoted 20 lines · Thomas Gleixner
Quoted 8 lines · Thomas Gleixner
Quoted 3 lines · Thomas Gleixner
More thoughts on this. If we go there and accept the extra page of memory then we can just go all the way and make the xarray per process, actually per signal.
Thinking more about it. The current scheme how timer ID allocation works is really interesting vs. CRIU.
Quoted 6 lines
Assume a process creates/deletes timers frequently. It's not hard to move the next ID close to
INT_MAX, i.e. 2GNow checkpoint that thing and restore it which means to do the create/delete dance to move next ID up to the last one-1. Will only take a couple of hours....
I'm cursing myself for overlooking this back then when the CRIU changes to the timer ID management were made. Why?
Quoted 6 lines
Because that created an ABI which CRIU relies on.
The proper solution for this would be to make it possible to create a timer with a given ID. That's not rocket science, but we need buy in from the CRIU folks. Otherwise we are up the regression creek without a paddle.
Let's go with the proper solution. I will prepare CRIU changes when kernel patches are ready.
Thanks,
Andrei
Frederic Weisbecker
maintainerRe: [patch 02/20] posix-timers: Ensure timer ID search-loop limit is valid
In reply to Thomas GleixnerQuoted 25 lines · Thomas Gleixner
Quoted 24 lines · Thomas Gleixner
On Fri, May 05 2023 at 16:50, Frederic Weisbecker wrote:
So the whole thing works like this:start = READ_LOCKLESS(sig->next_id);// Enfore that id and start are different to not terminate right away id = ~start;loop:
if (id == start) goto fail; lock() id = sig->next_id; <-- stable readout sig->next_id = (id + 1) & INT_MAX; <-- prevent going negative if (unused_id(id)) { add_timer_to_hash(timer, id); unlock(); return id; } id++; unlock(); goto loop;
Quoted 8 lines
Quoted 2 lines
As the initial lockless readout is guaranteed to be in the positive space, how is that supposed to be looping forever?
Unless you think about the theoretical case of an unlimited number of threads sharing the
signal_structwhich all concurrently try to allocate a timer id and then releasing it immediately again (to avoid resource limit exhaustion). Theoretically possible, but is this a real concern with a timer ID space of 2G?
I didn't go that far actually, it was just me misunderstanding that loop and especially the (id =~start) part. Now I got it.
I guess the for statement can just be:
for (; start != id; id++)
Quoted 11 lines
I'm sure that it's incredibly hard to exploit this, but what's really bothering me is the hash table itself. The only reason why we have that is CRIU.
The only alternative solution I could come up with is a paritioned xarray where the index space would be segmented for each TGID, i.e.
segment.start = TGID *
MAX_TIMERS_PER_PROCESS
segment.end = segment.start +MAX_TIMERS_PER_PROCESS- 1
Quoted 8 lines
where
MAX_TIMERS_PER_PROCESScould be a copius 2^16 which would work for both 32bit and 64bit TID limits.That would avoid the hash table lookups and the related issues, but OTH it would require to allocate one extra page per TGID if the application uses a single posix timer.
Not sure whether that's worth it though.
Not sure either...
Thanks.
Re: [patch 02/20] posix-timers: Ensure timer ID search-loop limit is valid
Quoted 8 lines · Frederic Weisbecker
Quoted 5 lines · Thomas Gleixner
That would avoid the hash table lookups and the related issues, but OTH it would require to allocate one extra page per TGID if the application uses a single posix timer.
Not sure whether that's worth it though.
Not sure either...
See my other reply on that...
Re: [patch 02/20] posix-timers: Ensure timer ID search-loop limit is valid
In reply to Frederic WeisbeckerQuoted 7 lines · Frederic Weisbecker
Quoted 5 lines · Thomas Gleixner
Unless you think about the theoretical case of an unlimited number of threads sharing the
signal_structwhich all concurrently try to allocate a timer id and then releasing it immediately again (to avoid resource limit exhaustion). Theoretically possible, but is this a real concern with a timer ID space of 2G?
Quoted 6 lines
I didn't go that far actually, it was just me misunderstanding that loop and especially the (id =~start) part. Now I got it.
I guess the for statement can just be:
for (; start != id; id++)
My brain based compiler complains about uninitialized usage of @id. I'm pretty sure it's rightfully complaining and a real compiler would agree, no?
Thanks,
tglx
Frederic Weisbecker
maintainerRe: [patch 02/20] posix-timers: Ensure timer ID search-loop limit is valid
Quoted 11 lines · Thomas Gleixner
Quoted 10 lines · Frederic Weisbecker
Quoted 5 lines · Thomas Gleixner
Unless you think about the theoretical case of an unlimited number of threads sharing the
signal_structwhich all concurrently try to allocate a timer id and then releasing it immediately again (to avoid resource limit exhaustion). Theoretically possible, but is this a real concern with a timer ID space of 2G?I didn't go that far actually, it was just me misunderstanding that loop and especially the (id =~start) part. Now I got it.
Quoted 7 lines
Quoted 3 lines
I guess the for statement can just be:
for (; start != id; id++)
My brain based compiler complains about uninitialized usage of @id. I'm pretty sure it's rightfully complaining and a real compiler would agree, no?
*sigh* I should think more before pressing answer these days :)
PATCH v2 2/20 posix-timers: Ensure timer ID search-loop limit is valid
posix_timer_add() tries to allocate a posix timer ID by starting from the cached ID which was stored by the last successful allocation.
This is done in a loop searching the ID space for a free slot one by one. The loop has to terminate when the search wrapped around to the starting point.
But that's racy vs. establishing the starting point. That is read out lockless, which leads to the following problem:
CPU0 CPU1posix_timer_add()
start = sig->posix_timer_id;
lock(hash_lock);
... posix_timer_add()
if (++sig->posix_timer_id < 0)
start = sig->posix_timer_id;
sig->posix_timer_id = 0;So CPU1 can observe a negative start value, i.e. -1, and the loop break never happens because the condition can never be true:
if (sig->posix_timer_id == start)
break;
While this is unlikely to ever turn into an endless loop as the ID space is huge (INT_MAX), the racy read of the start value caught the attention of KCSAN and Dmitry unearthed that incorrectness.
Rewrite it so that all id operations are under the hash lock.
---
V2: Make the loop less hideous.
--- include/linux/sched/signal.h | 2 +- kernel/time/posix-timers.c | 31 ++++++++++++++++++------------- 2 files changed, 19 insertions(+), 14 deletions(-)
include/linux/sched/signal.h +1 -1
@@ -135,7 +135,7 @@ struct signal_struct {#ifdef CONFIG_POSIX_TIMERS /* POSIX.1b Interval Timers */ -int posix_timer_id; +unsigned int next_posix_timer_id;struct list_head posix_timers;/* ITIMER_REAL timer for the process */
kernel/time/posix-timers.c +18 -13
@@ -140,25 +140,30 @@ static struct k_itimer *posix_timer_by_istatic int posix_timer_add (struct k_itimer *timer) {struct signal_struct *sig = current->signal; -int first_free_id = sig->posix_timer_id;struct hlist_head *head; -int ret = -ENOENT ; +unsigned int cnt, id; -do { +/* +* FIXME: Replace this by a per signal struct xarray once there is +* a plan to handle the resulting CRIU regression gracefully. +*/ +for (cnt =0 ; cnt <=INT_MAX ; cnt++) {spin_lock (&hash_lock); - head = &posix_timers_hashtable[hash (sig, sig->posix_timer_id)]; -if (!__posix_timers_find (head, sig, sig->posix_timer_id)) { + id = sig->next_posix_timer_id; + +/* Write the next ID back. Clamp it to the positive space */ + sig->next_posix_timer_id = (id +1 ) &INT_MAX ; + + head = &posix_timers_hashtable[hash (sig, id)]; +if (!__posix_timers_find (head, sig, id)) {hlist_add_head_rcu (&timer->t_hash, head); - ret = sig->posix_timer_id; +spin_unlock (&hash_lock); +return id; } -if (++sig->posix_timer_id <0 ) - sig->posix_timer_id =0 ; -if ((sig->posix_timer_id == first_free_id) && (ret == -ENOENT )) -/* Loop over all possible ids completed */ - ret = -EAGAIN ;spin_unlock (&hash_lock); - }while (ret == -ENOENT ); -return ret; + } +/* POSIX return code when no timer ID could be allocated */ +return -EAGAIN ; }static inline void unlock_timer (struct k_itimer *timr,unsigned long flags)
Re: [patch v2 02/20] posix-timers: Ensure timer ID search-loop limit is valid
Quoted 29 lines · Thomas Gleixner
posix_timer_add()tries to allocate a posix timer ID by starting from the cached ID which was stored by the last successful allocation.This is done in a loop searching the ID space for a free slot one by one. The loop has to terminate when the search wrapped around to the starting point.
But that's racy vs. establishing the starting point. That is read out lockless, which leads to the following problem:
CPU0 CPU1
posix_timer_add()
start =sig->posix_timer_id;
lock(hash_lock);
...posix_timer_add()
if (++sig->posix_timer_id < 0)start = sig->posix_timer_id; sig->posix_timer_id = 0;So CPU1 can observe a negative start value, i.e. -1, and the loop break never happens because the condition can never be true:
if (
sig->posix_timer_id== start)break;While this is unlikely to ever turn into an endless loop as the ID space is huge (
INT_MAX), the racy read of the start value caught the attention of KCSAN and Dmitry unearthed that incorrectness.
Quoted 5 lines
Rewrite it so that all id operations are under the hash lock.
Reported-by [email protected]Reported-by Dmitry Vyukov <[email protected]>Signed-off-by Thomas Gleixner <[email protected]>
[tip: timers/core] posix-timers: Ensure timer ID search-loop limit is valid
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: cec58cad4614f44b76624f8d62ef771c8725c483 Gitweb: https://git.kernel.org/tip/cec58cad4614f44b76624f8d62ef771c8725c483 Author: Thomas Gleixner <[email protected]> AuthorDate: Thu, 01 Jun 2023 20:58:47 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Mon, 05 Jun 2023 17:03:36 +02:00
posix-timers: Ensure timer ID search-loop limit is valid
posix_timer_add() tries to allocate a posix timer ID by starting from the cached ID which was stored by the last successful allocation.
This is done in a loop searching the ID space for a free slot one by one. The loop has to terminate when the search wrapped around to the starting point.
But that's racy vs. establishing the starting point. That is read out lockless, which leads to the following problem:
CPU0 CPU1posix_timer_add()
start = sig->posix_timer_id;
lock(hash_lock);
... posix_timer_add()
if (++sig->posix_timer_id < 0)
start = sig->posix_timer_id;
sig->posix_timer_id = 0;So CPU1 can observe a negative start value, i.e. -1, and the loop break never happens because the condition can never be true:
if (sig->posix_timer_id == start)
break;
While this is unlikely to ever turn into an endless loop as the ID space is huge (INT_MAX), the racy read of the start value caught the attention of KCSAN and Dmitry unearthed that incorrectness.
Rewrite it so that all id operations are under the hash lock.
--- include/linux/sched/signal.h | 2 +- kernel/time/posix-timers.c | 31 ++++++++++++++++++------------- 2 files changed, 19 insertions(+), 14 deletions(-)
include/linux/sched/signal.h +1 -1
@@ -135,7 +135,7 @@ struct signal_struct {#ifdef CONFIG_POSIX_TIMERS /* POSIX.1b Interval Timers */ -int posix_timer_id; +unsigned int next_posix_timer_id;struct list_head posix_timers;/* ITIMER_REAL timer for the process */
kernel/time/posix-timers.c +18 -13
@@ -140,25 +140,30 @@ static struct k_itimer *posix_timer_by_id(timer_t id)static int posix_timer_add (struct k_itimer *timer) {struct signal_struct *sig = current->signal; -int first_free_id = sig->posix_timer_id;struct hlist_head *head; -int ret = -ENOENT ; +unsigned int cnt, id; -do { +/* +* FIXME: Replace this by a per signal struct xarray once there is +* a plan to handle the resulting CRIU regression gracefully. +*/ +for (cnt =0 ; cnt <=INT_MAX ; cnt++) {spin_lock (&hash_lock); - head = &posix_timers_hashtable[hash (sig, sig->posix_timer_id)]; -if (!__posix_timers_find (head, sig, sig->posix_timer_id)) { + id = sig->next_posix_timer_id; + +/* Write the next ID back. Clamp it to the positive space */ + sig->next_posix_timer_id = (id +1 ) &INT_MAX ; + + head = &posix_timers_hashtable[hash (sig, id)]; +if (!__posix_timers_find (head, sig, id)) {hlist_add_head_rcu (&timer->t_hash, head); - ret = sig->posix_timer_id; +spin_unlock (&hash_lock); +return id; } -if (++sig->posix_timer_id <0 ) - sig->posix_timer_id =0 ; -if ((sig->posix_timer_id == first_free_id) && (ret == -ENOENT )) -/* Loop over all possible ids completed */ - ret = -EAGAIN ;spin_unlock (&hash_lock); - }while (ret == -ENOENT ); -return ret; + } +/* POSIX return code when no timer ID could be allocated */ +return -EAGAIN ; }static inline void unlock_timer (struct k_itimer *timr,unsigned long flags)
[tip: timers/core] posix-timers: Ensure timer ID search-loop limit is valid
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 8ce8849dd1e78dadcee0ec9acbd259d239b7069f Gitweb: https://git.kernel.org/tip/8ce8849dd1e78dadcee0ec9acbd259d239b7069f Author: Thomas Gleixner <[email protected]> AuthorDate: Thu, 01 Jun 2023 20:58:47 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Sun, 18 Jun 2023 22:41:48 +02:00
posix-timers: Ensure timer ID search-loop limit is valid
posix_timer_add() tries to allocate a posix timer ID by starting from the cached ID which was stored by the last successful allocation.
This is done in a loop searching the ID space for a free slot one by one. The loop has to terminate when the search wrapped around to the starting point.
But that's racy vs. establishing the starting point. That is read out lockless, which leads to the following problem:
CPU0 CPU1posix_timer_add()
start = sig->posix_timer_id;
lock(hash_lock);
... posix_timer_add()
if (++sig->posix_timer_id < 0)
start = sig->posix_timer_id;
sig->posix_timer_id = 0;So CPU1 can observe a negative start value, i.e. -1, and the loop break never happens because the condition can never be true:
if (sig->posix_timer_id == start)
break;
While this is unlikely to ever turn into an endless loop as the ID space is huge (INT_MAX), the racy read of the start value caught the attention of KCSAN and Dmitry unearthed that incorrectness.
Rewrite it so that all id operations are under the hash lock.
--- include/linux/sched/signal.h | 2 +- kernel/time/posix-timers.c | 31 ++++++++++++++++++------------- 2 files changed, 19 insertions(+), 14 deletions(-)
include/linux/sched/signal.h +1 -1
@@ -135,7 +135,7 @@ struct signal_struct {#ifdef CONFIG_POSIX_TIMERS /* POSIX.1b Interval Timers */ -int posix_timer_id; +unsigned int next_posix_timer_id;struct list_head posix_timers;/* ITIMER_REAL timer for the process */
kernel/time/posix-timers.c +18 -13
@@ -140,25 +140,30 @@ static struct k_itimer *posix_timer_by_id(timer_t id)static int posix_timer_add (struct k_itimer *timer) {struct signal_struct *sig = current->signal; -int first_free_id = sig->posix_timer_id;struct hlist_head *head; -int ret = -ENOENT ; +unsigned int cnt, id; -do { +/* +* FIXME: Replace this by a per signal struct xarray once there is +* a plan to handle the resulting CRIU regression gracefully. +*/ +for (cnt =0 ; cnt <=INT_MAX ; cnt++) {spin_lock (&hash_lock); - head = &posix_timers_hashtable[hash (sig, sig->posix_timer_id)]; -if (!__posix_timers_find (head, sig, sig->posix_timer_id)) { + id = sig->next_posix_timer_id; + +/* Write the next ID back. Clamp it to the positive space */ + sig->next_posix_timer_id = (id +1 ) &INT_MAX ; + + head = &posix_timers_hashtable[hash (sig, id)]; +if (!__posix_timers_find (head, sig, id)) {hlist_add_head_rcu (&timer->t_hash, head); - ret = sig->posix_timer_id; +spin_unlock (&hash_lock); +return id; } -if (++sig->posix_timer_id <0 ) - sig->posix_timer_id =0 ; -if ((sig->posix_timer_id == first_free_id) && (ret == -ENOENT )) -/* Loop over all possible ids completed */ - ret = -EAGAIN ;spin_unlock (&hash_lock); - }while (ret == -ENOENT ); -return ret; + } +/* POSIX return code when no timer ID could be allocated */ +return -EAGAIN ; }static inline void unlock_timer (struct k_itimer *timr,unsigned long flags)
PATCH 3/20 posix-timers: Clarify timer_wait_running() comment
In reply to Thomas GleixnerExplain it better and add the CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y aspect for completeness.
--- kernel/time/posix-timers.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
kernel/time/posix-timers.c +12 -4
@@ -835,10 +835,18 @@ static void common_timer_wait_running(st }/* -* On PREEMPT_RT this prevent priority inversion against softirq kthread in -* case it gets preempted while executing a timer callback. See comments in -* hrtimer_cancel_wait_running. For PREEMPT_RT=n this just results in a -* cpu_relax(). +* On PREEMPT_RT this prevents priority inversion and a potential livelock +* against the ksoftirqd thread in case that ksoftirqd gets preempted while +* executing a hrtimer callback. +* +* See the comments in hrtimer_cancel_wait_running(). For PREEMPT_RT=n this +* just results in a cpu_relax(). +* +* For POSIX CPU timers with CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n this is +* just a cpu_relax(). With CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y this +* prevents spinning on an eventually scheduled out task and a livelock +* when the task which tries to delete or disarm the timer has preempted +* the task which runs the expiry in task work context. */ static struct k_itimer *timer_wait_running (struct k_itimer *timer,unsigned long *flags)
Re: [patch 03/20] posix-timers: Clarify timer_wait_running() comment
Quoted 4 lines · Thomas Gleixner
Explain it better and add the
CONFIG_POSIX_CPU_TIMERS_TASK_WORK=yaspect for completeness.Signed-off-by Thomas Gleixner <[email protected]>
[tip: timers/core] posix-timers: Clarify timer_wait_running() comment
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 07ca14d623d8b0e6c4a0d3de4ca8a8ea35a85470 Gitweb: https://git.kernel.org/tip/07ca14d623d8b0e6c4a0d3de4ca8a8ea35a85470 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:00 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Mon, 05 Jun 2023 17:03:37 +02:00
posix-timers: Clarify timer_wait_running() comment
Explain it better and add the CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y aspect for completeness.
--- kernel/time/posix-timers.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
kernel/time/posix-timers.c +12 -4
@@ -836,10 +836,18 @@ static void common_timer_wait_running(struct k_itimer *timer) }/* -* On PREEMPT_RT this prevent priority inversion against softirq kthread in -* case it gets preempted while executing a timer callback. See comments in -* hrtimer_cancel_wait_running. For PREEMPT_RT=n this just results in a -* cpu_relax(). +* On PREEMPT_RT this prevents priority inversion and a potential livelock +* against the ksoftirqd thread in case that ksoftirqd gets preempted while +* executing a hrtimer callback. +* +* See the comments in hrtimer_cancel_wait_running(). For PREEMPT_RT=n this +* just results in a cpu_relax(). +* +* For POSIX CPU timers with CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n this is +* just a cpu_relax(). With CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y this +* prevents spinning on an eventually scheduled out task and a livelock +* when the task which tries to delete or disarm the timer has preempted +* the task which runs the expiry in task work context. */ static struct k_itimer *timer_wait_running (struct k_itimer *timer,unsigned long *flags)
[tip: timers/core] posix-timers: Clarify timer_wait_running() comment
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 7d9909026645064cd31b20cee5939a0f72282261 Gitweb: https://git.kernel.org/tip/7d9909026645064cd31b20cee5939a0f72282261 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:00 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Sun, 18 Jun 2023 22:41:48 +02:00
posix-timers: Clarify timer_wait_running() comment
Explain it better and add the CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y aspect for completeness.
--- kernel/time/posix-timers.c | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-)
kernel/time/posix-timers.c +12 -4
@@ -836,10 +836,18 @@ static void common_timer_wait_running(struct k_itimer *timer) }/* -* On PREEMPT_RT this prevent priority inversion against softirq kthread in -* case it gets preempted while executing a timer callback. See comments in -* hrtimer_cancel_wait_running. For PREEMPT_RT=n this just results in a -* cpu_relax(). +* On PREEMPT_RT this prevents priority inversion and a potential livelock +* against the ksoftirqd thread in case that ksoftirqd gets preempted while +* executing a hrtimer callback. +* +* See the comments in hrtimer_cancel_wait_running(). For PREEMPT_RT=n this +* just results in a cpu_relax(). +* +* For POSIX CPU timers with CONFIG_POSIX_CPU_TIMERS_TASK_WORK=n this is +* just a cpu_relax(). With CONFIG_POSIX_CPU_TIMERS_TASK_WORK=y this +* prevents spinning on an eventually scheduled out task and a livelock +* when the task which tries to delete or disarm the timer has preempted +* the task which runs the expiry in task work context. */ static struct k_itimer *timer_wait_running (struct k_itimer *timer,unsigned long *flags)
PATCH 4/20 posix-timers: Cleanup comments about timer ID tracking
In reply to Thomas GleixnerDescribe the hash table properly and remove the IDR leftover comments.
--- kernel/time/posix-timers.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-)
kernel/time/posix-timers.c +8 -20
@@ -35,20 +35,17 @@#include "timekeeping.h" #include "posix-timers.h" -/* -* Management arrays for POSIX timers. Timers are now kept in static hash table -* with 512 entries. -* Timer ids are allocated by local routine, which selects proper hash head by -* key, constructed from current->signal address and per signal struct counter. -* This keeps timer ids unique per process, but now they can intersect between -* processes. -*/ +static struct kmem_cache *posix_timers_cache;/* -* Lets keep our timers in a slab cache :-) +* Timers are managed in a hash table for lockless lookup. The hash key is +* constructed from current::signal and the timer ID and the timer is +* matched against current::signal and the timer ID when walking the hash +* bucket list. +* +* This allows checkpoint/restore to reconstruct the exact timer IDs for +* a process. */ -static struct kmem_cache *posix_timers_cache; - static DEFINE_HASHTABLE(posix_timers_hashtable, 9);static DEFINE_SPINLOCK (hash_lock);
@@ -66,15 +63,6 @@ static const struct k_clock clock_realti#endif /* -* The timer ID is turned into a timer address by idr_find(). -* Verifying a valid ID consists of: -* -* a) checking that idr_find() returns other than -1. -* b) checking that the timer id matches the one in the timer itself. -* c) that the timer owner is in the callers thread group. -*/ - -/* * CLOCKs: The POSIX standard calls for a couple of clocks and allows us * to implement others. This structure defines the various * clocks.
Re: [patch 04/20] posix-timers: Cleanup comments about timer ID tracking
Quoted 3 lines · Thomas Gleixner
Describe the hash table properly and remove the IDR leftover comments.
Signed-off-by Thomas Gleixner <[email protected]>
[tip: timers/core] posix-timers: Cleanup comments about timer ID tracking
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 10338fd15894827fefc2bf28ed75c81ba1dbfceb Gitweb: https://git.kernel.org/tip/10338fd15894827fefc2bf28ed75c81ba1dbfceb Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:01 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Mon, 05 Jun 2023 17:03:37 +02:00
posix-timers: Cleanup comments about timer ID tracking
Describe the hash table properly and remove the IDR leftover comments.
--- kernel/time/posix-timers.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-)
kernel/time/posix-timers.c +8 -20
@@ -35,20 +35,17 @@#include "timekeeping.h" #include "posix-timers.h" -/* -* Management arrays for POSIX timers. Timers are now kept in static hash table -* with 512 entries. -* Timer ids are allocated by local routine, which selects proper hash head by -* key, constructed from current->signal address and per signal struct counter. -* This keeps timer ids unique per process, but now they can intersect between -* processes. -*/ +static struct kmem_cache *posix_timers_cache;/* -* Lets keep our timers in a slab cache :-) +* Timers are managed in a hash table for lockless lookup. The hash key is +* constructed from current::signal and the timer ID and the timer is +* matched against current::signal and the timer ID when walking the hash +* bucket list. +* +* This allows checkpoint/restore to reconstruct the exact timer IDs for +* a process. */ -static struct kmem_cache *posix_timers_cache; - static DEFINE_HASHTABLE(posix_timers_hashtable, 9);static DEFINE_SPINLOCK (hash_lock);
@@ -66,15 +63,6 @@ static const struct k_clock clock_realtime, clock_monotonic;#endif /* -* The timer ID is turned into a timer address by idr_find(). -* Verifying a valid ID consists of: -* -* a) checking that idr_find() returns other than -1. -* b) checking that the timer id matches the one in the timer itself. -* c) that the timer owner is in the callers thread group. -*/ - -/* * CLOCKs: The POSIX standard calls for a couple of clocks and allows us * to implement others. This structure defines the various * clocks.
[tip: timers/core] posix-timers: Cleanup comments about timer ID tracking
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 8d44b958a1a088195524c884f0437660e0522380 Gitweb: https://git.kernel.org/tip/8d44b958a1a088195524c884f0437660e0522380 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:01 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Sun, 18 Jun 2023 22:41:48 +02:00
posix-timers: Cleanup comments about timer ID tracking
Describe the hash table properly and remove the IDR leftover comments.
--- kernel/time/posix-timers.c | 28 ++++++++-------------------- 1 file changed, 8 insertions(+), 20 deletions(-)
kernel/time/posix-timers.c +8 -20
@@ -35,20 +35,17 @@#include "timekeeping.h" #include "posix-timers.h" -/* -* Management arrays for POSIX timers. Timers are now kept in static hash table -* with 512 entries. -* Timer ids are allocated by local routine, which selects proper hash head by -* key, constructed from current->signal address and per signal struct counter. -* This keeps timer ids unique per process, but now they can intersect between -* processes. -*/ +static struct kmem_cache *posix_timers_cache;/* -* Lets keep our timers in a slab cache :-) +* Timers are managed in a hash table for lockless lookup. The hash key is +* constructed from current::signal and the timer ID and the timer is +* matched against current::signal and the timer ID when walking the hash +* bucket list. +* +* This allows checkpoint/restore to reconstruct the exact timer IDs for +* a process. */ -static struct kmem_cache *posix_timers_cache; - static DEFINE_HASHTABLE(posix_timers_hashtable, 9);static DEFINE_SPINLOCK (hash_lock);
@@ -66,15 +63,6 @@ static const struct k_clock clock_realtime, clock_monotonic;#endif /* -* The timer ID is turned into a timer address by idr_find(). -* Verifying a valid ID consists of: -* -* a) checking that idr_find() returns other than -1. -* b) checking that the timer id matches the one in the timer itself. -* c) that the timer owner is in the callers thread group. -*/ - -/* * CLOCKs: The POSIX standard calls for a couple of clocks and allows us * to implement others. This structure defines the various * clocks.
PATCH 5/20 posix-timers: Add comments about timer lookup
In reply to Thomas GleixnerDocument how the timer ID validation in the hash table works.
--- kernel/time/posix-timers.c | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-)
kernel/time/posix-timers.c +32 -7
@@ -505,6 +505,12 @@ static int do_timer_create(clockid_t whireturn -EAGAIN ;spin_lock_init (&new_timer->it_lock); + +/* +* Add the timer to the hash table. The timer is not yet valid +* because new_timer::it_signal is still NULL. The timer id is also +* not yet visible to user space. +*/ new_timer_id =posix_timer_add (new_timer);if (new_timer_id <0 ) { error = new_timer_id;
@@ -550,6 +556,7 @@ static int do_timer_create(clockid_t whi goto out;spin_lock_irq (¤t->sighand->siglock); +/* This makes the timer valid in the hash table */ new_timer->it_signal = current->signal;list_add (&new_timer->list, ¤t->signal->posix_timers);spin_unlock_irq (¤t->sighand->siglock);
@@ -596,13 +603,6 @@ COMPAT_SYSCALL_DEFINE3(timer_create, clo }#endif -/* -* Locking issues: We need to protect the result of the id look up until -* we get the timer locked down so it is not deleted under us. The -* removal is done under the idr spinlock so we use that here to bridge -* the find to the timer lock. To avoid a dead lock, the timer id MUST -* be release with out holding the timer lock. -*/ static struct k_itimer *__lock_timer (timer_t timer_id,unsigned long *flags) {struct k_itimer *timr;
@@ -614,10 +614,35 @@ static struct k_itimer *__lock_timer(timif ((unsigned long long )timer_id >INT_MAX )return NULL ; +/* +* The hash lookup and the timers are RCU protected. +* +* Timers are added to the hash in invalid state where +* timr::it_signal == NULL. timer::it_signal is only set after the +* rest of the initialization succeeded. +* +* Timer destruction happens in steps: +* 1) Set timr::it_signal to NULL with timr::it_lock held +* 2) Release timr::it_lock +* 3) Remove from the hash under hash_lock +* 4) Call RCU for removal after the grace period +* +* Holding rcu_read_lock() accross the lookup ensures that +* the timer cannot be freed. +* +* The lookup validates locklessly that timr::it_signal == +* current::it_signal and timr::it_id == @timer_id. timr::it_id +* can't change, but timr::it_signal becomes NULL during +* destruction. +*/ rcu_read_lock (); timr =posix_timer_by_id (timer_id);if (timr) {spin_lock_irqsave (&timr->it_lock, *flags); +/* +* Validate under timr::it_lock that timr::it_signal is +* still valid. Pairs with #1 above. +*/ if (timr->it_signal == current->signal) {rcu_read_unlock ();return timr;
Re: [patch 05/20] posix-timers: Add comments about timer lookup
Quoted 3 lines · Thomas Gleixner
Document how the timer ID validation in the hash table works.
Signed-off-by Thomas Gleixner <[email protected]>
[tip: timers/core] posix-timers: Add comments about timer lookup
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 46c7863e061f64c96745003f699912667c2a1bd6 Gitweb: https://git.kernel.org/tip/46c7863e061f64c96745003f699912667c2a1bd6 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:03 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Mon, 05 Jun 2023 17:03:37 +02:00
posix-timers: Add comments about timer lookup
Document how the timer ID validation in the hash table works.
--- kernel/time/posix-timers.c | 39 ++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-)
kernel/time/posix-timers.c +32 -7
@@ -506,6 +506,12 @@ static int do_timer_create(clockid_t which_clock, struct sigevent *event,return -EAGAIN ;spin_lock_init (&new_timer->it_lock); + +/* +* Add the timer to the hash table. The timer is not yet valid +* because new_timer::it_signal is still NULL. The timer id is also +* not yet visible to user space. +*/ new_timer_id =posix_timer_add (new_timer);if (new_timer_id <0 ) { error = new_timer_id;
@@ -551,6 +557,7 @@ static int do_timer_create(clockid_t which_clock, struct sigevent *event, goto out;spin_lock_irq (¤t->sighand->siglock); +/* This makes the timer valid in the hash table */ new_timer->it_signal = current->signal;list_add (&new_timer->list, ¤t->signal->posix_timers);spin_unlock_irq (¤t->sighand->siglock);
@@ -597,13 +604,6 @@ COMPAT_SYSCALL_DEFINE3(timer_create, clockid_t, which_clock, }#endif -/* -* Locking issues: We need to protect the result of the id look up until -* we get the timer locked down so it is not deleted under us. The -* removal is done under the idr spinlock so we use that here to bridge -* the find to the timer lock. To avoid a dead lock, the timer id MUST -* be release with out holding the timer lock. -*/ static struct k_itimer *__lock_timer (timer_t timer_id,unsigned long *flags) {struct k_itimer *timr;
@@ -615,10 +615,35 @@ static struct k_itimer *__lock_timer(timer_t timer_id, unsigned long *flags)if ((unsigned long long )timer_id >INT_MAX )return NULL ; +/* +* The hash lookup and the timers are RCU protected. +* +* Timers are added to the hash in invalid state where +* timr::it_signal == NULL. timer::it_signal is only set after the +* rest of the initialization succeeded. +* +* Timer destruction happens in steps: +* 1) Set timr::it_signal to NULL with timr::it_lock held +* 2) Release timr::it_lock +* 3) Remove from the hash under hash_lock +* 4) Call RCU for removal after the grace period +* +* Holding rcu_read_lock() accross the lookup ensures that +* the timer cannot be freed. +* +* The lookup validates locklessly that timr::it_signal == +* current::it_signal and timr::it_id == @timer_id. timr::it_id +* can't change, but timr::it_signal becomes NULL during +* destruction. +*/ rcu_read_lock (); timr =posix_timer_by_id (timer_id);if (timr) {spin_lock_irqsave (&timr->it_lock, *flags); +/* +* Validate under timr::it_lock that timr::it_signal is +* still valid. Pairs with #1 above. +*/ if (timr->it_signal == current->signal) {rcu_read_unlock ();return timr;
[tip: timers/core] posix-timers: Add comments about timer lookup
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: ae88967d71f1b4ffb6e48043993d37a106da8109 Gitweb: https://git.kernel.org/tip/ae88967d71f1b4ffb6e48043993d37a106da8109 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:03 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Sun, 18 Jun 2023 22:41:49 +02:00
posix-timers: Add comments about timer lookup
Document how the timer ID validation in the hash table works.
--- kernel/time/posix-timers.c | 39 ++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-)
kernel/time/posix-timers.c +32 -7
@@ -506,6 +506,12 @@ static int do_timer_create(clockid_t which_clock, struct sigevent *event,return -EAGAIN ;spin_lock_init (&new_timer->it_lock); + +/* +* Add the timer to the hash table. The timer is not yet valid +* because new_timer::it_signal is still NULL. The timer id is also +* not yet visible to user space. +*/ new_timer_id =posix_timer_add (new_timer);if (new_timer_id <0 ) { error = new_timer_id;
@@ -551,6 +557,7 @@ static int do_timer_create(clockid_t which_clock, struct sigevent *event, goto out;spin_lock_irq (¤t->sighand->siglock); +/* This makes the timer valid in the hash table */ new_timer->it_signal = current->signal;list_add (&new_timer->list, ¤t->signal->posix_timers);spin_unlock_irq (¤t->sighand->siglock);
@@ -597,13 +604,6 @@ COMPAT_SYSCALL_DEFINE3(timer_create, clockid_t, which_clock, }#endif -/* -* Locking issues: We need to protect the result of the id look up until -* we get the timer locked down so it is not deleted under us. The -* removal is done under the idr spinlock so we use that here to bridge -* the find to the timer lock. To avoid a dead lock, the timer id MUST -* be release with out holding the timer lock. -*/ static struct k_itimer *__lock_timer (timer_t timer_id,unsigned long *flags) {struct k_itimer *timr;
@@ -615,10 +615,35 @@ static struct k_itimer *__lock_timer(timer_t timer_id, unsigned long *flags)if ((unsigned long long )timer_id >INT_MAX )return NULL ; +/* +* The hash lookup and the timers are RCU protected. +* +* Timers are added to the hash in invalid state where +* timr::it_signal == NULL. timer::it_signal is only set after the +* rest of the initialization succeeded. +* +* Timer destruction happens in steps: +* 1) Set timr::it_signal to NULL with timr::it_lock held +* 2) Release timr::it_lock +* 3) Remove from the hash under hash_lock +* 4) Call RCU for removal after the grace period +* +* Holding rcu_read_lock() accross the lookup ensures that +* the timer cannot be freed. +* +* The lookup validates locklessly that timr::it_signal == +* current::it_signal and timr::it_id == @timer_id. timr::it_id +* can't change, but timr::it_signal becomes NULL during +* destruction. +*/ rcu_read_lock (); timr =posix_timer_by_id (timer_id);if (timr) {spin_lock_irqsave (&timr->it_lock, *flags); +/* +* Validate under timr::it_lock that timr::it_signal is +* still valid. Pairs with #1 above. +*/ if (timr->it_signal == current->signal) {rcu_read_unlock ();return timr;
PATCH 6/20 posix-timers: Annotate concurrent access to k_itimer::it_signal
In reply to Thomas Gleixnerk_itimer::it_signal is read lockless in the RCU protected hash lookup, but it can be written concurrently in the timer_create() and timer_delete() path. Annotate these places with READ_ONCE() and WRITE_ONCE()
--- kernel/time/posix-timers.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
kernel/time/posix-timers.c +7 -7
@@ -109,9 +109,9 @@ static struct k_itimer *__posix_timers_f {struct k_itimer *timer; -hlist_for_each_entry_rcu (timer, head, t_hash, -lockdep_is_held (&hash_lock)) { -if ((timer->it_signal == sig) && (timer->it_id == id)) +hlist_for_each_entry_rcu (timer, head, t_hash,lockdep_is_held (&hash_lock)) { +/* timer->it_signal can be set concurrently */ +if ((READ_ONCE (timer->it_signal) == sig) && (timer->it_id == id))return timer; }return NULL ;
@@ -557,7 +557,7 @@ static int do_timer_create(clockid_t whispin_lock_irq (¤t->sighand->siglock);/* This makes the timer valid in the hash table */ - new_timer->it_signal = current->signal; +WRITE_ONCE (new_timer->it_signal, current->signal);list_add (&new_timer->list, ¤t->signal->posix_timers);spin_unlock_irq (¤t->sighand->siglock);
@@ -1051,10 +1051,10 @@ SYSCALL_DEFINE1(timer_delete, timer_t, tlist_del (&timer->list);spin_unlock (¤t->sighand->siglock);/* -* This keeps any tasks waiting on the spin lock from thinking -* they got something (see the lock code above). +* A concurrent lookup could check timer::it_signal lockless. It +* will reevaluate with timer::it_lock held and observe the NULL. */ - timer->it_signal =NULL ; +WRITE_ONCE (timer->it_signal,NULL );unlock_timer (timer, flags);release_posix_timer (timer,IT_ID_SET );
Re: [patch 06/20] posix-timers: Annotate concurrent access to k_itimer::it_signal
Quoted 5 lines · Thomas Gleixner
k_itimer::it_signalis read lockless in the RCU protected hash lookup, but it can be written concurrently in thetimer_create()andtimer_delete()path. Annotate these places withREAD_ONCE()andWRITE_ONCE()Signed-off-by Thomas Gleixner <[email protected]>
[tip: timers/core] posix-timers: Annotate concurrent access to k_itimer:: It_signal
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: d69e873ee50459e3b77019263cf95236f063a97b Gitweb: https://git.kernel.org/tip/d69e873ee50459e3b77019263cf95236f063a97b Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:05 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Mon, 05 Jun 2023 17:03:37 +02:00
posix-timers: Annotate concurrent access to k_itimer:: It_signal
k_itimer::it_signal is read lockless in the RCU protected hash lookup, but it can be written concurrently in the timer_create() and timer_delete() path. Annotate these places with READ_ONCE() and WRITE_ONCE()
--- kernel/time/posix-timers.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
kernel/time/posix-timers.c +7 -7
@@ -109,9 +109,9 @@ static struct k_itimer *__posix_timers_find(struct hlist_head *head, {struct k_itimer *timer; -hlist_for_each_entry_rcu (timer, head, t_hash, -lockdep_is_held (&hash_lock)) { -if ((timer->it_signal == sig) && (timer->it_id == id)) +hlist_for_each_entry_rcu (timer, head, t_hash,lockdep_is_held (&hash_lock)) { +/* timer->it_signal can be set concurrently */ +if ((READ_ONCE (timer->it_signal) == sig) && (timer->it_id == id))return timer; }return NULL ;
@@ -558,7 +558,7 @@ static int do_timer_create(clockid_t which_clock, struct sigevent *event,spin_lock_irq (¤t->sighand->siglock);/* This makes the timer valid in the hash table */ - new_timer->it_signal = current->signal; +WRITE_ONCE (new_timer->it_signal, current->signal);list_add (&new_timer->list, ¤t->signal->posix_timers);spin_unlock_irq (¤t->sighand->siglock);
@@ -1052,10 +1052,10 @@ retry_delete:list_del (&timer->list);spin_unlock (¤t->sighand->siglock);/* -* This keeps any tasks waiting on the spin lock from thinking -* they got something (see the lock code above). +* A concurrent lookup could check timer::it_signal lockless. It +* will reevaluate with timer::it_lock held and observe the NULL. */ - timer->it_signal =NULL ; +WRITE_ONCE (timer->it_signal,NULL );unlock_timer (timer, flags);release_posix_timer (timer,IT_ID_SET );
[tip: timers/core] posix-timers: Annotate concurrent access to k_itimer:: It_signal
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 028cf5eaa12846c4e32104132ff70ca1cd6f5943 Gitweb: https://git.kernel.org/tip/028cf5eaa12846c4e32104132ff70ca1cd6f5943 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:05 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Sun, 18 Jun 2023 22:41:49 +02:00
posix-timers: Annotate concurrent access to k_itimer:: It_signal
k_itimer::it_signal is read lockless in the RCU protected hash lookup, but it can be written concurrently in the timer_create() and timer_delete() path. Annotate these places with READ_ONCE() and WRITE_ONCE()
--- kernel/time/posix-timers.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
kernel/time/posix-timers.c +7 -7
@@ -109,9 +109,9 @@ static struct k_itimer *__posix_timers_find(struct hlist_head *head, {struct k_itimer *timer; -hlist_for_each_entry_rcu (timer, head, t_hash, -lockdep_is_held (&hash_lock)) { -if ((timer->it_signal == sig) && (timer->it_id == id)) +hlist_for_each_entry_rcu (timer, head, t_hash,lockdep_is_held (&hash_lock)) { +/* timer->it_signal can be set concurrently */ +if ((READ_ONCE (timer->it_signal) == sig) && (timer->it_id == id))return timer; }return NULL ;
@@ -558,7 +558,7 @@ static int do_timer_create(clockid_t which_clock, struct sigevent *event,spin_lock_irq (¤t->sighand->siglock);/* This makes the timer valid in the hash table */ - new_timer->it_signal = current->signal; +WRITE_ONCE (new_timer->it_signal, current->signal);list_add (&new_timer->list, ¤t->signal->posix_timers);spin_unlock_irq (¤t->sighand->siglock);
@@ -1052,10 +1052,10 @@ retry_delete:list_del (&timer->list);spin_unlock (¤t->sighand->siglock);/* -* This keeps any tasks waiting on the spin lock from thinking -* they got something (see the lock code above). +* A concurrent lookup could check timer::it_signal lockless. It +* will reevaluate with timer::it_lock held and observe the NULL. */ - timer->it_signal =NULL ; +WRITE_ONCE (timer->it_signal,NULL );unlock_timer (timer, flags);release_posix_timer (timer,IT_ID_SET );
PATCH 7/20 posix-timers: Set k_itimer::it_signal to NULL on exit()
In reply to Thomas GleixnerTechnically it's not required to set k_itimer::it_signal to NULL on exit() because there is no other thread anymore which could lookup the timer concurrently.
Set it to NULL for consistency sake and add a comment to that effect.
--- kernel/time/posix-timers.c | 8 ++++++++ 1 file changed, 8 insertions(+)
kernel/time/posix-timers.c +8 -0
@@ -1107,6 +1107,14 @@ static void itimer_delete(struct k_itime }list_del (&timer->list); +/* +* Setting timer::it_signal to NULL is technically not required +* here as nothing can access the timer anymore legitimately via +* the hash table. Set it to NULL nevertheless so that all deletion +* paths are consistent. +*/ +WRITE_ONCE (timer->it_signal,NULL ); +spin_unlock_irqrestore (&timer->it_lock, flags);release_posix_timer (timer,IT_ID_SET ); }
Re: [patch 07/20] posix-timers: Set k_itimer::it_signal to NULL on exit()
Quoted 7 lines · Thomas Gleixner
Technically it's not required to set
k_itimer::it_signalto NULL onexit()because there is no other thread anymore which could lookup the timer concurrently.Set it to NULL for consistency sake and add a comment to that effect.
Signed-off-by Thomas Gleixner <[email protected]>
[tip: timers/core] posix-timers: Set k_itimer:: It_signal to NULL on exit()
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 515eeda177b797d9a7d0c496739f0bdc02c73093 Gitweb: https://git.kernel.org/tip/515eeda177b797d9a7d0c496739f0bdc02c73093 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:06 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Mon, 05 Jun 2023 17:03:37 +02:00
posix-timers: Set k_itimer:: It_signal to NULL on exit()
Technically it's not required to set k_itimer::it_signal to NULL on exit() because there is no other thread anymore which could lookup the timer concurrently.
Set it to NULL for consistency sake and add a comment to that effect.
--- kernel/time/posix-timers.c | 8 ++++++++ 1 file changed, 8 insertions(+)
kernel/time/posix-timers.c +8 -0
@@ -1101,6 +1101,14 @@ retry_delete: }list_del (&timer->list); +/* +* Setting timer::it_signal to NULL is technically not required +* here as nothing can access the timer anymore legitimately via +* the hash table. Set it to NULL nevertheless so that all deletion +* paths are consistent. +*/ +WRITE_ONCE (timer->it_signal,NULL ); +spin_unlock_irqrestore (&timer->it_lock, flags);release_posix_timer (timer,IT_ID_SET ); }
[tip: timers/core] posix-timers: Set k_itimer:: It_signal to NULL on exit()
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 72786ff23d5acb7bf3e2535831b2f1dc55c7f44e Gitweb: https://git.kernel.org/tip/72786ff23d5acb7bf3e2535831b2f1dc55c7f44e Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:06 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Sun, 18 Jun 2023 22:41:49 +02:00
posix-timers: Set k_itimer:: It_signal to NULL on exit()
Technically it's not required to set k_itimer::it_signal to NULL on exit() because there is no other thread anymore which could lookup the timer concurrently.
Set it to NULL for consistency sake and add a comment to that effect.
--- kernel/time/posix-timers.c | 8 ++++++++ 1 file changed, 8 insertions(+)
kernel/time/posix-timers.c +8 -0
@@ -1101,6 +1101,14 @@ retry_delete: }list_del (&timer->list); +/* +* Setting timer::it_signal to NULL is technically not required +* here as nothing can access the timer anymore legitimately via +* the hash table. Set it to NULL nevertheless so that all deletion +* paths are consistent. +*/ +WRITE_ONCE (timer->it_signal,NULL ); +spin_unlock_irqrestore (&timer->it_lock, flags);release_posix_timer (timer,IT_ID_SET ); }
PATCH 8/20 posix-timers: Remove pointless irqsafe from hash_lock
In reply to Thomas GleixnerAll usage of hash_lock is in thread context. No point in using spin_lock_irqsave()/irqrestore() for a single usage site.
--- kernel/time/posix-timers.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
kernel/time/posix-timers.c +2 -3
@@ -470,10 +470,9 @@ static void k_itimer_rcu_free(struct rcustatic void release_posix_timer (struct k_itimer *tmr,int it_id_set) {if (it_id_set) { -unsigned long flags; -spin_lock_irqsave (&hash_lock, flags); +spin_lock (&hash_lock, flags);hlist_del_rcu (&tmr->t_hash); -spin_unlock_irqrestore (&hash_lock, flags); +spin_unlock (&hash_lock, flags); }put_pid (tmr->it_pid);sigqueue_free (tmr->sigq);
Re: [patch 08/20] posix-timers: Remove pointless irqsafe from hash_lock
Quoted 4 lines · Thomas Gleixner
All usage of
hash_lockis in thread context. No point in using spin_lock_irqsave()/irqrestore() for a single usage site.Signed-off-by Thomas Gleixner <[email protected]>
[tip: timers/core] posix-timers: Remove pointless irqsafe from hash_lock
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 032c960ac9f3d64487423e0e01a0fb7327509595 Gitweb: https://git.kernel.org/tip/032c960ac9f3d64487423e0e01a0fb7327509595 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:08 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Mon, 05 Jun 2023 17:03:37 +02:00
posix-timers: Remove pointless irqsafe from hash_lock
All usage of hash_lock is in thread context. No point in using spin_lock_irqsave()/irqrestore() for a single usage site.
--- kernel/time/posix-timers.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
kernel/time/posix-timers.c +2 -3
@@ -471,10 +471,9 @@ static void k_itimer_rcu_free(struct rcu_head *head)static void release_posix_timer (struct k_itimer *tmr,int it_id_set) {if (it_id_set) { -unsigned long flags; -spin_lock_irqsave (&hash_lock, flags); +spin_lock (&hash_lock, flags);hlist_del_rcu (&tmr->t_hash); -spin_unlock_irqrestore (&hash_lock, flags); +spin_unlock (&hash_lock, flags); }put_pid (tmr->it_pid);sigqueue_free (tmr->sigq);
[tip: timers/core] posix-timers: Remove pointless irqsafe from hash_lock
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 11fbe6cd41210c7b5173257158a22e11e225622d Gitweb: https://git.kernel.org/tip/11fbe6cd41210c7b5173257158a22e11e225622d Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:08 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Sun, 18 Jun 2023 22:41:49 +02:00
posix-timers: Remove pointless irqsafe from hash_lock
All usage of hash_lock is in thread context. No point in using spin_lock_irqsave()/irqrestore() for a single usage site.
--- kernel/time/posix-timers.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
kernel/time/posix-timers.c +2 -3
@@ -471,10 +471,9 @@ static void k_itimer_rcu_free(struct rcu_head *head)static void release_posix_timer (struct k_itimer *tmr,int it_id_set) {if (it_id_set) { -unsigned long flags; -spin_lock_irqsave (&hash_lock, flags); +spin_lock (&hash_lock, flags);hlist_del_rcu (&tmr->t_hash); -spin_unlock_irqrestore (&hash_lock, flags); +spin_unlock (&hash_lock, flags); }put_pid (tmr->it_pid);sigqueue_free (tmr->sigq);
PATCH 9/20 posix-timers: Split release_posix_timers()
In reply to Thomas Gleixnerrelease_posix_timers() is called for cleaning up both hashed and unhashed timers. The cases are differentiated by an argument and the usage is hideous.
Seperate the actual free path out and use it for unhashed timers. Provide a function for hashed timers.
No functional change.
--- kernel/time/posix-timers.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-)
kernel/time/posix-timers.c +15 -16
@@ -465,20 +465,21 @@ static void k_itimer_rcu_free(struct rcukmem_cache_free (posix_timers_cache, tmr); } -#define IT_ID_SET 1 -#define IT_ID_NOT_SET 0 -static void release_posix_timer (struct k_itimer *tmr,int it_id_set) -{ -if (it_id_set) { -spin_lock (&hash_lock, flags); -hlist_del_rcu (&tmr->t_hash); -spin_unlock (&hash_lock, flags); - } +static void posix_timer_free (struct k_itimer *tmr) +{put_pid (tmr->it_pid);sigqueue_free (tmr->sigq);call_rcu (&tmr->rcu, k_itimer_rcu_free); } +static void posix_timer_unhash_and_free (struct k_itimer *tmr) +{ +spin_lock (&hash_lock); +hlist_del_rcu (&tmr->t_hash); +spin_unlock (&hash_lock); +posix_timer_free (tmr); +} +static int common_timer_create (struct k_itimer *new_timer) {hrtimer_init (&new_timer->it.real.timer, new_timer->it_clock,0 );
@@ -492,7 +493,6 @@ static int do_timer_create(clockid_t whiconst struct k_clock *kc =clockid_to_kclock (which_clock);struct k_itimer *new_timer;int error, new_timer_id; -int it_id_set =IT_ID_NOT_SET ;if (!kc)return -EINVAL ;
@@ -512,11 +512,10 @@ static int do_timer_create(clockid_t whi*/ new_timer_id =posix_timer_add (new_timer);if (new_timer_id <0 ) { - error = new_timer_id; - goto out; +posix_timer_free (new_timer); +return new_timer_id; } - it_id_set =IT_ID_SET ; new_timer->it_id = (timer_t ) new_timer_id; new_timer->it_clock = which_clock; new_timer->kclock = kc;
@@ -568,7 +567,7 @@ static int do_timer_create(clockid_t whi* new_timer after the unlock call. */ out: -release_posix_timer (new_timer, it_id_set); +posix_timer_unhash_and_free (new_timer);return error; }
@@ -1056,7 +1055,7 @@ SYSCALL_DEFINE1(timer_delete, timer_t, tWRITE_ONCE (timer->it_signal,NULL );unlock_timer (timer, flags); -release_posix_timer (timer,IT_ID_SET ); +posix_timer_unhash_and_free (timer);return 0 ; }
@@ -1115,7 +1114,7 @@ static void itimer_delete(struct k_itimeWRITE_ONCE (timer->it_signal,NULL );spin_unlock_irqrestore (&timer->it_lock, flags); -release_posix_timer (timer,IT_ID_SET ); +posix_timer_unhash_and_free (timer); }/*
Re: [patch 09/20] posix-timers: Split release_posix_timers()
Quoted 10 lines · Thomas Gleixner
release_posix_timers()is called for cleaning up both hashed and unhashed timers. The cases are differentiated by an argument and the usage is hideous.Seperate the actual free path out and use it for unhashed timers. Provide a function for hashed timers.
No functional change.
Signed-off-by Thomas Gleixner <[email protected]>
[tip: timers/core] posix-timers: Split release_posix_timers()
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: e7441aa344046cbdcb402ac173fb163613471097 Gitweb: https://git.kernel.org/tip/e7441aa344046cbdcb402ac173fb163613471097 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:09 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Mon, 05 Jun 2023 17:03:37 +02:00
posix-timers: Split release_posix_timers()
release_posix_timers() is called for cleaning up both hashed and unhashed timers. The cases are differentiated by an argument and the usage is hideous.
Seperate the actual free path out and use it for unhashed timers. Provide a function for hashed timers.
No functional change.
--- kernel/time/posix-timers.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-)
kernel/time/posix-timers.c +15 -16
@@ -466,20 +466,21 @@ static void k_itimer_rcu_free(struct rcu_head *head)kmem_cache_free (posix_timers_cache, tmr); } -#define IT_ID_SET 1 -#define IT_ID_NOT_SET 0 -static void release_posix_timer (struct k_itimer *tmr,int it_id_set) -{ -if (it_id_set) { -spin_lock (&hash_lock, flags); -hlist_del_rcu (&tmr->t_hash); -spin_unlock (&hash_lock, flags); - } +static void posix_timer_free (struct k_itimer *tmr) +{put_pid (tmr->it_pid);sigqueue_free (tmr->sigq);call_rcu (&tmr->rcu, k_itimer_rcu_free); } +static void posix_timer_unhash_and_free (struct k_itimer *tmr) +{ +spin_lock (&hash_lock); +hlist_del_rcu (&tmr->t_hash); +spin_unlock (&hash_lock); +posix_timer_free (tmr); +} +static int common_timer_create (struct k_itimer *new_timer) {hrtimer_init (&new_timer->it.real.timer, new_timer->it_clock,0 );
@@ -493,7 +494,6 @@ static int do_timer_create(clockid_t which_clock, struct sigevent *event,const struct k_clock *kc =clockid_to_kclock (which_clock);struct k_itimer *new_timer;int error, new_timer_id; -int it_id_set =IT_ID_NOT_SET ;if (!kc)return -EINVAL ;
@@ -513,11 +513,10 @@ static int do_timer_create(clockid_t which_clock, struct sigevent *event,*/ new_timer_id =posix_timer_add (new_timer);if (new_timer_id <0 ) { - error = new_timer_id; - goto out; +posix_timer_free (new_timer); +return new_timer_id; } - it_id_set =IT_ID_SET ; new_timer->it_id = (timer_t ) new_timer_id; new_timer->it_clock = which_clock; new_timer->kclock = kc;
@@ -569,7 +568,7 @@ static int do_timer_create(clockid_t which_clock, struct sigevent *event,* new_timer after the unlock call. */ out: -release_posix_timer (new_timer, it_id_set); +posix_timer_unhash_and_free (new_timer);return error; }
@@ -1057,7 +1056,7 @@ retry_delete:WRITE_ONCE (timer->it_signal,NULL );unlock_timer (timer, flags); -release_posix_timer (timer,IT_ID_SET ); +posix_timer_unhash_and_free (timer);return 0 ; }
@@ -1109,7 +1108,7 @@ retry_delete:WRITE_ONCE (timer->it_signal,NULL );spin_unlock_irqrestore (&timer->it_lock, flags); -release_posix_timer (timer,IT_ID_SET ); +posix_timer_unhash_and_free (timer); }/*
[tip: timers/core] posix-timers: Split release_posix_timers()
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 8cc96ca2c75f6da59de41321797c87562703c9e1 Gitweb: https://git.kernel.org/tip/8cc96ca2c75f6da59de41321797c87562703c9e1 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:09 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Sun, 18 Jun 2023 22:41:50 +02:00
posix-timers: Split release_posix_timers()
release_posix_timers() is called for cleaning up both hashed and unhashed timers. The cases are differentiated by an argument and the usage is hideous.
Seperate the actual free path out and use it for unhashed timers. Provide a function for hashed timers.
No functional change.
--- kernel/time/posix-timers.c | 31 +++++++++++++++---------------- 1 file changed, 15 insertions(+), 16 deletions(-)
kernel/time/posix-timers.c +15 -16
@@ -466,20 +466,21 @@ static void k_itimer_rcu_free(struct rcu_head *head)kmem_cache_free (posix_timers_cache, tmr); } -#define IT_ID_SET 1 -#define IT_ID_NOT_SET 0 -static void release_posix_timer (struct k_itimer *tmr,int it_id_set) -{ -if (it_id_set) { -spin_lock (&hash_lock, flags); -hlist_del_rcu (&tmr->t_hash); -spin_unlock (&hash_lock, flags); - } +static void posix_timer_free (struct k_itimer *tmr) +{put_pid (tmr->it_pid);sigqueue_free (tmr->sigq);call_rcu (&tmr->rcu, k_itimer_rcu_free); } +static void posix_timer_unhash_and_free (struct k_itimer *tmr) +{ +spin_lock (&hash_lock); +hlist_del_rcu (&tmr->t_hash); +spin_unlock (&hash_lock); +posix_timer_free (tmr); +} +static int common_timer_create (struct k_itimer *new_timer) {hrtimer_init (&new_timer->it.real.timer, new_timer->it_clock,0 );
@@ -493,7 +494,6 @@ static int do_timer_create(clockid_t which_clock, struct sigevent *event,const struct k_clock *kc =clockid_to_kclock (which_clock);struct k_itimer *new_timer;int error, new_timer_id; -int it_id_set =IT_ID_NOT_SET ;if (!kc)return -EINVAL ;
@@ -513,11 +513,10 @@ static int do_timer_create(clockid_t which_clock, struct sigevent *event,*/ new_timer_id =posix_timer_add (new_timer);if (new_timer_id <0 ) { - error = new_timer_id; - goto out; +posix_timer_free (new_timer); +return new_timer_id; } - it_id_set =IT_ID_SET ; new_timer->it_id = (timer_t ) new_timer_id; new_timer->it_clock = which_clock; new_timer->kclock = kc;
@@ -569,7 +568,7 @@ static int do_timer_create(clockid_t which_clock, struct sigevent *event,* new_timer after the unlock call. */ out: -release_posix_timer (new_timer, it_id_set); +posix_timer_unhash_and_free (new_timer);return error; }
@@ -1057,7 +1056,7 @@ retry_delete:WRITE_ONCE (timer->it_signal,NULL );unlock_timer (timer, flags); -release_posix_timer (timer,IT_ID_SET ); +posix_timer_unhash_and_free (timer);return 0 ; }
@@ -1109,7 +1108,7 @@ retry_delete:WRITE_ONCE (timer->it_signal,NULL );spin_unlock_irqrestore (&timer->it_lock, flags); -release_posix_timer (timer,IT_ID_SET ); +posix_timer_unhash_and_free (timer); }/*
PATCH 10/20 posix-timers: Document sys_clock_getres() correctly
In reply to Thomas GleixnerThe decades old comment about Posix clock resolution is confusing at best.
Remove it and add a proper explanation to sys_clock_getres().
--- kernel/time/posix-timers.c | 81 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 73 insertions(+), 8 deletions(-)
kernel/time/posix-timers.c +73 -8
@@ -67,14 +67,6 @@ static const struct k_clock clock_realti* to implement others. This structure defines the various * clocks. * -* RESOLUTION: Clock resolution is used to round up timer and interval -* times, NOT to report clock times, which are reported with as -* much resolution as the system can muster. In some cases this -* resolution may depend on the underlying clock hardware and -* may not be quantifiable until run time, and only then is the -* necessary code is written. The standard says we should say -* something about this issue in the documentation... -* * FUNCTIONS: The CLOCKs structure defines possible functions to * handle various clock functions. *
@@ -1204,6 +1196,79 @@ SYSCALL_DEFINE2(clock_adjtime, const cloreturn err; } +/** +* sys_clock_getres - Get the resolution of a clock +* @which_clock: The clock to get the resolution for +* @tp: Pointer to a a user space timespec64 for storage +* +* POSIX defines: +* +* "The clock_getres() function shall return the resolution of any +* clock. Clock resolutions are implementation-defined and cannot be set by +* a process. If the argument res is not NULL, the resolution of the +* specified clock shall be stored in the location pointed to by res. If +* res is NULL, the clock resolution is not returned. If the time argument +* of clock_settime() is not a multiple of res, then the value is truncated +* to a multiple of res." +* +* Due to the various hardware constraints the real resolution can vary +* wildly and even change during runtime when the underlying devices are +* replaced. The kernel also can use hardware devices with different +* resolutions for reading the time and for arming timers. +* +* The kernel therefore deviates from the POSIX spec in various aspects: +* +* 1) The resolution returned to user space +* +* For CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_BOOTTIME, CLOCK_TAI, +* CLOCK_REALTIME_ALARM, CLOCK_BOOTTIME_ALAREM and CLOCK_MONOTONIC_RAW +* the kernel differentiates only two cases: +* +* I) Low resolution mode: +* +* When high resolution timers are disabled at compile or runtime +* the resolution returned is nanoseconds per tick, which represents +* the precision at which timers expire. +* +* II) High resolution mode: +* +* When high resolution timers are enabled the resolution returned +* is always one nanosecond independent of the actual resolution of +* the underlying hardware devices. +* +* For CLOCK_*_ALARM the actual resolution depends on system +* state. When system is running the resolution is the same as the +* resolution of the other clocks. During suspend the actual +* resolution is the resolution of the underlying RTC device which +* might be way less precise than the clockevent device used during +* running state. +* +* For CLOCK_REALTIME_COARSE and CLOCK_MONOTONIC_COARSE the resolution +* returned is always nanoseconds per tick. +* +* For CLOCK_PROCESS_CPUTIME and CLOCK_THREAD_CPUTIME the resolution +* returned is always one nanosecond under the assumption that the +* underlying scheduler clock has a better resolution than nanoseconds +* per tick. +* +* For dynamic POSIX clocks (PTP devices) the resolution returned is +* always one nanosecond. +* +* 2) Affect on sys_clock_settime() +* +* The kernel does not truncate the time which is handed in to +* sys_clock_settime(). The kernel internal timekeeping is always using +* nanoseconds precision independent of the clocksource device which is +* used to read the time from. The resolution of that device only +* affects the presicion of the time returned by sys_clock_gettime(). +* +* Returns: +* 0 Success. @tp contains the resolution +* -EINVAL @which_clock is not a valid clock ID +* -EFAULT Copying the resolution to @tp faulted +* -ENODEV Dynamic POSIX clock is not backed by a device +* -EOPNOTSUPP Dynamic POSIX clock does not support getres() +*/ SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, struct __kernel_timespec __user *, tp) {
Re: [patch 10/20] posix-timers: Document sys_clock_getres() correctly
Quoted 4 lines · Thomas Gleixner
+/**
+ *sys_clock_getres- Get the resolution of a clock
+ * @which_clock: The clock to get the resolution for
+ * @tp: Pointer to a a user space timespec64 for storage
^^^
a_a
[tip: timers/core] posix-timers: Document sys_clock_getres() correctly
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 4898e5d912108c8a865ffb3fc0230559b40ca361 Gitweb: https://git.kernel.org/tip/4898e5d912108c8a865ffb3fc0230559b40ca361 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:11 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Mon, 05 Jun 2023 17:03:37 +02:00
posix-timers: Document sys_clock_getres() correctly
The decades old comment about Posix clock resolution is confusing at best.
Remove it and add a proper explanation to sys_clock_getres().
--- kernel/time/posix-timers.c | 81 +++++++++++++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 8 deletions(-)
kernel/time/posix-timers.c +73 -8
@@ -67,14 +67,6 @@ static const struct k_clock clock_realtime, clock_monotonic;* to implement others. This structure defines the various * clocks. * -* RESOLUTION: Clock resolution is used to round up timer and interval -* times, NOT to report clock times, which are reported with as -* much resolution as the system can muster. In some cases this -* resolution may depend on the underlying clock hardware and -* may not be quantifiable until run time, and only then is the -* necessary code is written. The standard says we should say -* something about this issue in the documentation... -* * FUNCTIONS: The CLOCKs structure defines possible functions to * handle various clock functions. *
@@ -1198,6 +1190,79 @@ SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock,return err; } +/** +* sys_clock_getres - Get the resolution of a clock +* @which_clock: The clock to get the resolution for +* @tp: Pointer to a a user space timespec64 for storage +* +* POSIX defines: +* +* "The clock_getres() function shall return the resolution of any +* clock. Clock resolutions are implementation-defined and cannot be set by +* a process. If the argument res is not NULL, the resolution of the +* specified clock shall be stored in the location pointed to by res. If +* res is NULL, the clock resolution is not returned. If the time argument +* of clock_settime() is not a multiple of res, then the value is truncated +* to a multiple of res." +* +* Due to the various hardware constraints the real resolution can vary +* wildly and even change during runtime when the underlying devices are +* replaced. The kernel also can use hardware devices with different +* resolutions for reading the time and for arming timers. +* +* The kernel therefore deviates from the POSIX spec in various aspects: +* +* 1) The resolution returned to user space +* +* For CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_BOOTTIME, CLOCK_TAI, +* CLOCK_REALTIME_ALARM, CLOCK_BOOTTIME_ALAREM and CLOCK_MONOTONIC_RAW +* the kernel differentiates only two cases: +* +* I) Low resolution mode: +* +* When high resolution timers are disabled at compile or runtime +* the resolution returned is nanoseconds per tick, which represents +* the precision at which timers expire. +* +* II) High resolution mode: +* +* When high resolution timers are enabled the resolution returned +* is always one nanosecond independent of the actual resolution of +* the underlying hardware devices. +* +* For CLOCK_*_ALARM the actual resolution depends on system +* state. When system is running the resolution is the same as the +* resolution of the other clocks. During suspend the actual +* resolution is the resolution of the underlying RTC device which +* might be way less precise than the clockevent device used during +* running state. +* +* For CLOCK_REALTIME_COARSE and CLOCK_MONOTONIC_COARSE the resolution +* returned is always nanoseconds per tick. +* +* For CLOCK_PROCESS_CPUTIME and CLOCK_THREAD_CPUTIME the resolution +* returned is always one nanosecond under the assumption that the +* underlying scheduler clock has a better resolution than nanoseconds +* per tick. +* +* For dynamic POSIX clocks (PTP devices) the resolution returned is +* always one nanosecond. +* +* 2) Affect on sys_clock_settime() +* +* The kernel does not truncate the time which is handed in to +* sys_clock_settime(). The kernel internal timekeeping is always using +* nanoseconds precision independent of the clocksource device which is +* used to read the time from. The resolution of that device only +* affects the presicion of the time returned by sys_clock_gettime(). +* +* Returns: +* 0 Success. @tp contains the resolution +* -EINVAL @which_clock is not a valid clock ID +* -EFAULT Copying the resolution to @tp faulted +* -ENODEV Dynamic POSIX clock is not backed by a device +* -EOPNOTSUPP Dynamic POSIX clock does not support getres() +*/ SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, struct __kernel_timespec __user *, tp) {
[tip: timers/core] posix-timers: Document sys_clock_getres() correctly
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 01679b5db7172b898be325ff272e10aebd412911 Gitweb: https://git.kernel.org/tip/01679b5db7172b898be325ff272e10aebd412911 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:11 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Sun, 18 Jun 2023 22:41:50 +02:00
posix-timers: Document sys_clock_getres() correctly
The decades old comment about Posix clock resolution is confusing at best.
Remove it and add a proper explanation to sys_clock_getres().
--- kernel/time/posix-timers.c | 81 +++++++++++++++++++++++++++++++++---- 1 file changed, 73 insertions(+), 8 deletions(-)
kernel/time/posix-timers.c +73 -8
@@ -67,14 +67,6 @@ static const struct k_clock clock_realtime, clock_monotonic;* to implement others. This structure defines the various * clocks. * -* RESOLUTION: Clock resolution is used to round up timer and interval -* times, NOT to report clock times, which are reported with as -* much resolution as the system can muster. In some cases this -* resolution may depend on the underlying clock hardware and -* may not be quantifiable until run time, and only then is the -* necessary code is written. The standard says we should say -* something about this issue in the documentation... -* * FUNCTIONS: The CLOCKs structure defines possible functions to * handle various clock functions. *
@@ -1198,6 +1190,79 @@ SYSCALL_DEFINE2(clock_adjtime, const clockid_t, which_clock,return err; } +/** +* sys_clock_getres - Get the resolution of a clock +* @which_clock: The clock to get the resolution for +* @tp: Pointer to a a user space timespec64 for storage +* +* POSIX defines: +* +* "The clock_getres() function shall return the resolution of any +* clock. Clock resolutions are implementation-defined and cannot be set by +* a process. If the argument res is not NULL, the resolution of the +* specified clock shall be stored in the location pointed to by res. If +* res is NULL, the clock resolution is not returned. If the time argument +* of clock_settime() is not a multiple of res, then the value is truncated +* to a multiple of res." +* +* Due to the various hardware constraints the real resolution can vary +* wildly and even change during runtime when the underlying devices are +* replaced. The kernel also can use hardware devices with different +* resolutions for reading the time and for arming timers. +* +* The kernel therefore deviates from the POSIX spec in various aspects: +* +* 1) The resolution returned to user space +* +* For CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_BOOTTIME, CLOCK_TAI, +* CLOCK_REALTIME_ALARM, CLOCK_BOOTTIME_ALAREM and CLOCK_MONOTONIC_RAW +* the kernel differentiates only two cases: +* +* I) Low resolution mode: +* +* When high resolution timers are disabled at compile or runtime +* the resolution returned is nanoseconds per tick, which represents +* the precision at which timers expire. +* +* II) High resolution mode: +* +* When high resolution timers are enabled the resolution returned +* is always one nanosecond independent of the actual resolution of +* the underlying hardware devices. +* +* For CLOCK_*_ALARM the actual resolution depends on system +* state. When system is running the resolution is the same as the +* resolution of the other clocks. During suspend the actual +* resolution is the resolution of the underlying RTC device which +* might be way less precise than the clockevent device used during +* running state. +* +* For CLOCK_REALTIME_COARSE and CLOCK_MONOTONIC_COARSE the resolution +* returned is always nanoseconds per tick. +* +* For CLOCK_PROCESS_CPUTIME and CLOCK_THREAD_CPUTIME the resolution +* returned is always one nanosecond under the assumption that the +* underlying scheduler clock has a better resolution than nanoseconds +* per tick. +* +* For dynamic POSIX clocks (PTP devices) the resolution returned is +* always one nanosecond. +* +* 2) Affect on sys_clock_settime() +* +* The kernel does not truncate the time which is handed in to +* sys_clock_settime(). The kernel internal timekeeping is always using +* nanoseconds precision independent of the clocksource device which is +* used to read the time from. The resolution of that device only +* affects the presicion of the time returned by sys_clock_gettime(). +* +* Returns: +* 0 Success. @tp contains the resolution +* -EINVAL @which_clock is not a valid clock ID +* -EFAULT Copying the resolution to @tp faulted +* -ENODEV Dynamic POSIX clock is not backed by a device +* -EOPNOTSUPP Dynamic POSIX clock does not support getres() +*/ SYSCALL_DEFINE2(clock_getres, const clockid_t, which_clock, struct __kernel_timespec __user *, tp) {
PATCH 11/20 posix-timers: Document common_clock_get() correctly
In reply to Thomas GleixnerReplace another confusing and inaccurate set of comments.
--- kernel/time/posix-timers.c | 50 +++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 20 deletions(-)
kernel/time/posix-timers.c +30 -20
@@ -659,20 +659,16 @@ static s64 common_hrtimer_forward(struct }/* -* Get the time remaining on a POSIX.1b interval timer. This function -* is ALWAYS called with spin_lock_irq on the timer, thus it must not -* mess with irq. +* Get the time remaining on a POSIX.1b interval timer. * -* We have a couple of messes to clean up here. First there is the case -* of a timer that has a requeue pending. These timers should appear to -* be in the timer list with an expiry as if we were to requeue them -* now. +* Two issues to handle here: * -* The second issue is the SIGEV_NONE timer which may be active but is -* not really ever put in the timer list (to save system resources). -* This timer may be expired, and if so, we will do it here. Otherwise -* it is the same as a requeue pending timer WRT to what we should -* report. +* 1) The timer has a requeue pending. The return value must appear as +* if the timer has been requeued right now. +* +* 2) The timer is a SIGEV_NONE timer. These timers are never enqueued +* into the hrtimer queue and therefore never expired. Emulate expiry +* here taking #1 into account. */ void common_timer_get (struct k_itimer *timr,struct itimerspec64 *cur_setting) {
@@ -688,8 +684,12 @@ void common_timer_get(struct k_itimer *t cur_setting->it_interval =ktime_to_timespec64 (iv); }else if (!timr->it_active) {/* -* SIGEV_NONE oneshot timers are never queued. Check them -* below. +* SIGEV_NONE oneshot timers are never queued and therefore +* timr->it_active is always false. The check below +* vs. remaining time will handle this case. +* +* For all other timers there is nothing to update here, so +* return. */ if (!sig_none)return ;
@@ -698,18 +698,29 @@ void common_timer_get(struct k_itimer *t now = kc->clock_get_ktime (timr->it_clock);/* -* When a requeue is pending or this is a SIGEV_NONE timer move the -* expiry time forward by intervals, so expiry is > now. +* If this is an interval timer and either has requeue pending or +* is a SIGEV_NONE timer move the expiry time forward by intervals, +* so expiry is > now. */ if (iv && (timr->it_requeue_pending &REQUEUE_PENDING || sig_none)) timr->it_overrun += kc->timer_forward (timr, now); remaining = kc->timer_remaining (timr, now); -/* Return 0 only, when the timer is expired and not pending */ +/* +* As @now is retrieved before a possible timer_forward() and +* cannot be reevaluated by the compiler @remaining is based on the +* same @now value. Therefore @remaining is consistent vs. @now. +* +* Consequently all interval timers, i.e. @iv > 0, cannot have a +* remaining time <= 0 because timer_forward() guarantees to move +* them forward so that the next timer expiry is > @now. +*/ if (remaining <=0 ) {/* -* A single shot SIGEV_NONE timer must return 0, when -* it is expired ! +* A single shot SIGEV_NONE timer must return 0, when it is +* expired! Timers which have a real signal delivery mode +* must return a remaining time greater than 0 because the +* signal has not yet been delivered. */ if (!sig_none) cur_setting->it_value.tv_nsec =1 ;
@@ -718,7 +729,6 @@ void common_timer_get(struct k_itimer *t } } -/* Get the time remaining on a POSIX.1b interval timer. */ static int do_timer_gettime (timer_t timer_id,struct itimerspec64 *setting) {struct k_itimer *timr;
Re: [patch 11/20] posix-timers: Document common_clock_get() correctly
Quoted 3 lines · Thomas Gleixner
Replace another confusing and inaccurate set of comments.
Signed-off-by Thomas Gleixner <[email protected]>
[tip: timers/core] posix-timers: Document common_clock_get() correctly
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 13a5dd88bb4c8aec6c3f808f75b73b1fe4705244 Gitweb: https://git.kernel.org/tip/13a5dd88bb4c8aec6c3f808f75b73b1fe4705244 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:12 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Mon, 05 Jun 2023 17:03:38 +02:00
posix-timers: Document common_clock_get() correctly
Replace another confusing and inaccurate set of comments.
--- kernel/time/posix-timers.c | 50 ++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 20 deletions(-)
kernel/time/posix-timers.c +30 -20
@@ -660,20 +660,16 @@ static s64 common_hrtimer_forward(struct k_itimer *timr, ktime_t now) }/* -* Get the time remaining on a POSIX.1b interval timer. This function -* is ALWAYS called with spin_lock_irq on the timer, thus it must not -* mess with irq. +* Get the time remaining on a POSIX.1b interval timer. * -* We have a couple of messes to clean up here. First there is the case -* of a timer that has a requeue pending. These timers should appear to -* be in the timer list with an expiry as if we were to requeue them -* now. +* Two issues to handle here: * -* The second issue is the SIGEV_NONE timer which may be active but is -* not really ever put in the timer list (to save system resources). -* This timer may be expired, and if so, we will do it here. Otherwise -* it is the same as a requeue pending timer WRT to what we should -* report. +* 1) The timer has a requeue pending. The return value must appear as +* if the timer has been requeued right now. +* +* 2) The timer is a SIGEV_NONE timer. These timers are never enqueued +* into the hrtimer queue and therefore never expired. Emulate expiry +* here taking #1 into account. */ void common_timer_get (struct k_itimer *timr,struct itimerspec64 *cur_setting) {
@@ -689,8 +685,12 @@ void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting) cur_setting->it_interval =ktime_to_timespec64 (iv); }else if (!timr->it_active) {/* -* SIGEV_NONE oneshot timers are never queued. Check them -* below. +* SIGEV_NONE oneshot timers are never queued and therefore +* timr->it_active is always false. The check below +* vs. remaining time will handle this case. +* +* For all other timers there is nothing to update here, so +* return. */ if (!sig_none)return ;
@@ -699,18 +699,29 @@ void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting) now = kc->clock_get_ktime (timr->it_clock);/* -* When a requeue is pending or this is a SIGEV_NONE timer move the -* expiry time forward by intervals, so expiry is > now. +* If this is an interval timer and either has requeue pending or +* is a SIGEV_NONE timer move the expiry time forward by intervals, +* so expiry is > now. */ if (iv && (timr->it_requeue_pending &REQUEUE_PENDING || sig_none)) timr->it_overrun += kc->timer_forward (timr, now); remaining = kc->timer_remaining (timr, now); -/* Return 0 only, when the timer is expired and not pending */ +/* +* As @now is retrieved before a possible timer_forward() and +* cannot be reevaluated by the compiler @remaining is based on the +* same @now value. Therefore @remaining is consistent vs. @now. +* +* Consequently all interval timers, i.e. @iv > 0, cannot have a +* remaining time <= 0 because timer_forward() guarantees to move +* them forward so that the next timer expiry is > @now. +*/ if (remaining <=0 ) {/* -* A single shot SIGEV_NONE timer must return 0, when -* it is expired ! +* A single shot SIGEV_NONE timer must return 0, when it is +* expired! Timers which have a real signal delivery mode +* must return a remaining time greater than 0 because the +* signal has not yet been delivered. */ if (!sig_none) cur_setting->it_value.tv_nsec =1 ;
@@ -719,7 +730,6 @@ void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting) } } -/* Get the time remaining on a POSIX.1b interval timer. */ static int do_timer_gettime (timer_t timer_id,struct itimerspec64 *setting) {struct k_itimer *timr;
[tip: timers/core] posix-timers: Document common_clock_get() correctly
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: a86e9284336729a8f79a65371eacd0c1c7fae142 Gitweb: https://git.kernel.org/tip/a86e9284336729a8f79a65371eacd0c1c7fae142 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:12 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Sun, 18 Jun 2023 22:41:50 +02:00
posix-timers: Document common_clock_get() correctly
Replace another confusing and inaccurate set of comments.
--- kernel/time/posix-timers.c | 50 ++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 20 deletions(-)
kernel/time/posix-timers.c +30 -20
@@ -660,20 +660,16 @@ static s64 common_hrtimer_forward(struct k_itimer *timr, ktime_t now) }/* -* Get the time remaining on a POSIX.1b interval timer. This function -* is ALWAYS called with spin_lock_irq on the timer, thus it must not -* mess with irq. +* Get the time remaining on a POSIX.1b interval timer. * -* We have a couple of messes to clean up here. First there is the case -* of a timer that has a requeue pending. These timers should appear to -* be in the timer list with an expiry as if we were to requeue them -* now. +* Two issues to handle here: * -* The second issue is the SIGEV_NONE timer which may be active but is -* not really ever put in the timer list (to save system resources). -* This timer may be expired, and if so, we will do it here. Otherwise -* it is the same as a requeue pending timer WRT to what we should -* report. +* 1) The timer has a requeue pending. The return value must appear as +* if the timer has been requeued right now. +* +* 2) The timer is a SIGEV_NONE timer. These timers are never enqueued +* into the hrtimer queue and therefore never expired. Emulate expiry +* here taking #1 into account. */ void common_timer_get (struct k_itimer *timr,struct itimerspec64 *cur_setting) {
@@ -689,8 +685,12 @@ void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting) cur_setting->it_interval =ktime_to_timespec64 (iv); }else if (!timr->it_active) {/* -* SIGEV_NONE oneshot timers are never queued. Check them -* below. +* SIGEV_NONE oneshot timers are never queued and therefore +* timr->it_active is always false. The check below +* vs. remaining time will handle this case. +* +* For all other timers there is nothing to update here, so +* return. */ if (!sig_none)return ;
@@ -699,18 +699,29 @@ void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting) now = kc->clock_get_ktime (timr->it_clock);/* -* When a requeue is pending or this is a SIGEV_NONE timer move the -* expiry time forward by intervals, so expiry is > now. +* If this is an interval timer and either has requeue pending or +* is a SIGEV_NONE timer move the expiry time forward by intervals, +* so expiry is > now. */ if (iv && (timr->it_requeue_pending &REQUEUE_PENDING || sig_none)) timr->it_overrun += kc->timer_forward (timr, now); remaining = kc->timer_remaining (timr, now); -/* Return 0 only, when the timer is expired and not pending */ +/* +* As @now is retrieved before a possible timer_forward() and +* cannot be reevaluated by the compiler @remaining is based on the +* same @now value. Therefore @remaining is consistent vs. @now. +* +* Consequently all interval timers, i.e. @iv > 0, cannot have a +* remaining time <= 0 because timer_forward() guarantees to move +* them forward so that the next timer expiry is > @now. +*/ if (remaining <=0 ) {/* -* A single shot SIGEV_NONE timer must return 0, when -* it is expired ! +* A single shot SIGEV_NONE timer must return 0, when it is +* expired! Timers which have a real signal delivery mode +* must return a remaining time greater than 0 because the +* signal has not yet been delivered. */ if (!sig_none) cur_setting->it_value.tv_nsec =1 ;
@@ -719,7 +730,6 @@ void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting) } } -/* Get the time remaining on a POSIX.1b interval timer. */ static int do_timer_gettime (timer_t timer_id,struct itimerspec64 *setting) {struct k_itimer *timr;
PATCH 12/20 posix-timers: Document sys_clock_getoverrun()
In reply to Thomas GleixnerDocument the syscall in detail and with coherent sentences.
--- kernel/time/posix-timers.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-)
kernel/time/posix-timers.c +17 -8
@@ -782,14 +782,23 @@ SYSCALL_DEFINE2(timer_gettime32, timer_t#endif -/* -* Get the number of overruns of a POSIX.1b interval timer. This is to -* be the overrun of the timer last delivered. At the same time we are -* accumulating overruns on the next timer. The overrun is frozen when -* the signal is delivered, either at the notify time (if the info block -* is not queued) or at the actual delivery time (as we are informed by -* the call back to posixtimer_rearm(). So all we need to do is -* to pick up the frozen overrun. +/** +* sys_timer_getoverrun - Get the number of overruns of a POSIX.1b interval timer +* @timer_id: The timer ID which identifies the timer +* +* The "overrun count" of a timer is one plus the number of expiration +* intervals which have elapsed between the first expiry, which queues the +* signal and the actual signal delivery. On signal delivery the "overrun +* count" is calculated and cached, so it can be returned directly here. +* +* As this is relative to the last queued signal the returned overrun count +* is meaningless outside of the signal delivery path and even there it +* does not accurately reflect the current state when user space evaluates +* it. +* +* Returns: +* -EINVAL @timer_id is invalid +* 1..INT_MAX The number of overruns related to the last delivered signal */ SYSCALL_DEFINE1(timer_getoverrun, timer_t, timer_id) {
Re: [patch 12/20] posix-timers: Document sys_clock_getoverrun()
Quoted 4 lines · Thomas Gleixner
Document the syscall in detail and with coherent sentences.
Signed-off-by Thomas Gleixner <[email protected]>Cc Michael Kerrisk <[email protected]>
[tip: timers/core] posix-timers: Document sys_clock_getoverrun()
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 1adc8de86737c3d134c2da5ed8e56c2de4729923 Gitweb: https://git.kernel.org/tip/1adc8de86737c3d134c2da5ed8e56c2de4729923 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:14 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Mon, 05 Jun 2023 17:03:38 +02:00
posix-timers: Document sys_clock_getoverrun()
Document the syscall in detail and with coherent sentences.
--- kernel/time/posix-timers.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-)
kernel/time/posix-timers.c +17 -8
@@ -783,14 +783,23 @@ SYSCALL_DEFINE2(timer_gettime32, timer_t, timer_id,#endif -/* -* Get the number of overruns of a POSIX.1b interval timer. This is to -* be the overrun of the timer last delivered. At the same time we are -* accumulating overruns on the next timer. The overrun is frozen when -* the signal is delivered, either at the notify time (if the info block -* is not queued) or at the actual delivery time (as we are informed by -* the call back to posixtimer_rearm(). So all we need to do is -* to pick up the frozen overrun. +/** +* sys_timer_getoverrun - Get the number of overruns of a POSIX.1b interval timer +* @timer_id: The timer ID which identifies the timer +* +* The "overrun count" of a timer is one plus the number of expiration +* intervals which have elapsed between the first expiry, which queues the +* signal and the actual signal delivery. On signal delivery the "overrun +* count" is calculated and cached, so it can be returned directly here. +* +* As this is relative to the last queued signal the returned overrun count +* is meaningless outside of the signal delivery path and even there it +* does not accurately reflect the current state when user space evaluates +* it. +* +* Returns: +* -EINVAL @timer_id is invalid +* 1..INT_MAX The number of overruns related to the last delivered signal */ SYSCALL_DEFINE1(timer_getoverrun, timer_t, timer_id) {
[tip: timers/core] posix-timers: Document sys_clock_getoverrun()
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 65cade468dee537885b51897ba41ba05a4dcf6ca Gitweb: https://git.kernel.org/tip/65cade468dee537885b51897ba41ba05a4dcf6ca Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:14 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Sun, 18 Jun 2023 22:41:50 +02:00
posix-timers: Document sys_clock_getoverrun()
Document the syscall in detail and with coherent sentences.
--- kernel/time/posix-timers.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-)
kernel/time/posix-timers.c +17 -8
@@ -783,14 +783,23 @@ SYSCALL_DEFINE2(timer_gettime32, timer_t, timer_id,#endif -/* -* Get the number of overruns of a POSIX.1b interval timer. This is to -* be the overrun of the timer last delivered. At the same time we are -* accumulating overruns on the next timer. The overrun is frozen when -* the signal is delivered, either at the notify time (if the info block -* is not queued) or at the actual delivery time (as we are informed by -* the call back to posixtimer_rearm(). So all we need to do is -* to pick up the frozen overrun. +/** +* sys_timer_getoverrun - Get the number of overruns of a POSIX.1b interval timer +* @timer_id: The timer ID which identifies the timer +* +* The "overrun count" of a timer is one plus the number of expiration +* intervals which have elapsed between the first expiry, which queues the +* signal and the actual signal delivery. On signal delivery the "overrun +* count" is calculated and cached, so it can be returned directly here. +* +* As this is relative to the last queued signal the returned overrun count +* is meaningless outside of the signal delivery path and even there it +* does not accurately reflect the current state when user space evaluates +* it. +* +* Returns: +* -EINVAL @timer_id is invalid +* 1..INT_MAX The number of overruns related to the last delivered signal */ SYSCALL_DEFINE1(timer_getoverrun, timer_t, timer_id) {
PATCH 13/20 posix-timers: Document sys_clock_settime() permissions in place
In reply to Thomas GleixnerThe documentation of sys_clock_settime() permissions is at a random place and mostly word salad.
Remove it and add a concise comment into sys_clock_settime().
--- kernel/time/posix-timers.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)
kernel/time/posix-timers.c +4 -7
@@ -74,13 +74,6 @@ static const struct k_clock clock_realti* following: 1.) The k_itimer struct (sched.h) is used for * the timer. 2.) The list, it_lock, it_clock, it_id and * it_pid fields are not modified by timer code. -* -* Permissions: It is assumed that the clock_settime() function defined -* for each clock will take care of permission checks. Some -* clocks may be set able by any user (i.e. local process -* clocks) others not. Currently the only set able clock we -* have is CLOCK_REALTIME and its high res counter part, both of -* which we beg off on and pass to do_sys_settimeofday(). */ static struct k_itimer *__lock_timer (timer_t timer_id,unsigned long *flags);
@@ -1165,6 +1158,10 @@ SYSCALL_DEFINE2(clock_settime, const cloif (get_timespec64 (&new_tp, tp))return -EFAULT ; +/* +* Permission checks have to be done inside the clock specific +* setter callback. +*/ return kc->clock_set (which_clock, &new_tp); }
Re: [patch 13/20] posix-timers: Document sys_clock_settime() permissions in place
Quoted 6 lines · Thomas Gleixner
The documentation of
sys_clock_settime()permissions is at a random place and mostly word salad.Remove it and add a concise comment into
sys_clock_settime().Signed-off-by Thomas Gleixner <[email protected]>
[tip: timers/core] posix-timers: Document sys_clock_settime() permissions in place
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 6a0fc851449cdcad42f96e00854af4ac36a4b357 Gitweb: https://git.kernel.org/tip/6a0fc851449cdcad42f96e00854af4ac36a4b357 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:16 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Mon, 05 Jun 2023 17:03:38 +02:00
posix-timers: Document sys_clock_settime() permissions in place
The documentation of sys_clock_settime() permissions is at a random place and mostly word salad.
Remove it and add a concise comment into sys_clock_settime().
--- kernel/time/posix-timers.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)
kernel/time/posix-timers.c +4 -7
@@ -74,13 +74,6 @@ static const struct k_clock clock_realtime, clock_monotonic;* following: 1.) The k_itimer struct (sched.h) is used for * the timer. 2.) The list, it_lock, it_clock, it_id and * it_pid fields are not modified by timer code. -* -* Permissions: It is assumed that the clock_settime() function defined -* for each clock will take care of permission checks. Some -* clocks may be set able by any user (i.e. local process -* clocks) others not. Currently the only set able clock we -* have is CLOCK_REALTIME and its high res counter part, both of -* which we beg off on and pass to do_sys_settimeofday(). */ static struct k_itimer *__lock_timer (timer_t timer_id,unsigned long *flags);
@@ -1159,6 +1152,10 @@ SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock,if (get_timespec64 (&new_tp, tp))return -EFAULT ; +/* +* Permission checks have to be done inside the clock specific +* setter callback. +*/ return kc->clock_set (which_clock, &new_tp); }
[tip: timers/core] posix-timers: Document sys_clock_settime() permissions in place
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 3561fcb402b7ab7fdb4c1746dae4995889506605 Gitweb: https://git.kernel.org/tip/3561fcb402b7ab7fdb4c1746dae4995889506605 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:16 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Sun, 18 Jun 2023 22:41:51 +02:00
posix-timers: Document sys_clock_settime() permissions in place
The documentation of sys_clock_settime() permissions is at a random place and mostly word salad.
Remove it and add a concise comment into sys_clock_settime().
--- kernel/time/posix-timers.c | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-)
kernel/time/posix-timers.c +4 -7
@@ -74,13 +74,6 @@ static const struct k_clock clock_realtime, clock_monotonic;* following: 1.) The k_itimer struct (sched.h) is used for * the timer. 2.) The list, it_lock, it_clock, it_id and * it_pid fields are not modified by timer code. -* -* Permissions: It is assumed that the clock_settime() function defined -* for each clock will take care of permission checks. Some -* clocks may be set able by any user (i.e. local process -* clocks) others not. Currently the only set able clock we -* have is CLOCK_REALTIME and its high res counter part, both of -* which we beg off on and pass to do_sys_settimeofday(). */ static struct k_itimer *__lock_timer (timer_t timer_id,unsigned long *flags);
@@ -1159,6 +1152,10 @@ SYSCALL_DEFINE2(clock_settime, const clockid_t, which_clock,if (get_timespec64 (&new_tp, tp))return -EFAULT ; +/* +* Permission checks have to be done inside the clock specific +* setter callback. +*/ return kc->clock_set (which_clock, &new_tp); }
PATCH 14/20 posix-timers: Document nanosleep() details
In reply to Thomas GleixnerThe descriptions for common_nsleep() is wrong and common_nsleep_timens() lacks any form of comment.
--- kernel/time/posix-timers.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
kernel/time/posix-timers.c +7 -2
@@ -1376,7 +1376,7 @@ SYSCALL_DEFINE2(clock_getres_time32, clo#endif /* -* nanosleep for monotonic and realtime clocks +* sys_clock_nanosleep() for CLOCK_REALTIME and CLOCK_TAI */ static int common_nsleep (const clockid_t which_clock,int flags,const struct timespec64 *rqtp)
@@ -1388,8 +1388,13 @@ static int common_nsleep(const clockid_t which_clock); } +/* +* sys_clock_nanosleep() for CLOCK_MONOTONIC and CLOCK_BOOTTIME +* +* Absolute nanosleeps for these clocks are time-namespace adjusted. +*/ static int common_nsleep_timens (const clockid_t which_clock,int flags, -const struct timespec64 *rqtp) +const struct timespec64 *rqtp) {ktime_t texp =timespec64_to_ktime (*rqtp);
Re: [patch 14/20] posix-timers: Document nanosleep() details
Quoted 4 lines · Thomas Gleixner
The descriptions for
common_nsleep()is wrong andcommon_nsleep_timens()lacks any form of comment.Signed-off-by Thomas Gleixner <[email protected]>
[tip: timers/core] posix-timers: Document nanosleep() details
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 13da885685d6ae339f2924d3c8a1f4fe16a904cc Gitweb: https://git.kernel.org/tip/13da885685d6ae339f2924d3c8a1f4fe16a904cc Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:17 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Mon, 05 Jun 2023 17:03:38 +02:00
posix-timers: Document nanosleep() details
The descriptions for common_nsleep() is wrong and common_nsleep_timens() lacks any form of comment.
--- kernel/time/posix-timers.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
kernel/time/posix-timers.c +7 -2
@@ -1370,7 +1370,7 @@ SYSCALL_DEFINE2(clock_getres_time32, clockid_t, which_clock,#endif /* -* nanosleep for monotonic and realtime clocks +* sys_clock_nanosleep() for CLOCK_REALTIME and CLOCK_TAI */ static int common_nsleep (const clockid_t which_clock,int flags,const struct timespec64 *rqtp)
@@ -1382,8 +1382,13 @@ static int common_nsleep(const clockid_t which_clock, int flags, which_clock); } +/* +* sys_clock_nanosleep() for CLOCK_MONOTONIC and CLOCK_BOOTTIME +* +* Absolute nanosleeps for these clocks are time-namespace adjusted. +*/ static int common_nsleep_timens (const clockid_t which_clock,int flags, -const struct timespec64 *rqtp) +const struct timespec64 *rqtp) {ktime_t texp =timespec64_to_ktime (*rqtp);
[tip: timers/core] posix-timers: Document nanosleep() details
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 640fe745d7d4b6e47f3b455cb5de99a08c6b6d23 Gitweb: https://git.kernel.org/tip/640fe745d7d4b6e47f3b455cb5de99a08c6b6d23 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:17 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Sun, 18 Jun 2023 22:41:51 +02:00
posix-timers: Document nanosleep() details
The descriptions for common_nsleep() is wrong and common_nsleep_timens() lacks any form of comment.
--- kernel/time/posix-timers.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
kernel/time/posix-timers.c +7 -2
@@ -1370,7 +1370,7 @@ SYSCALL_DEFINE2(clock_getres_time32, clockid_t, which_clock,#endif /* -* nanosleep for monotonic and realtime clocks +* sys_clock_nanosleep() for CLOCK_REALTIME and CLOCK_TAI */ static int common_nsleep (const clockid_t which_clock,int flags,const struct timespec64 *rqtp)
@@ -1382,8 +1382,13 @@ static int common_nsleep(const clockid_t which_clock, int flags, which_clock); } +/* +* sys_clock_nanosleep() for CLOCK_MONOTONIC and CLOCK_BOOTTIME +* +* Absolute nanosleeps for these clocks are time-namespace adjusted. +*/ static int common_nsleep_timens (const clockid_t which_clock,int flags, -const struct timespec64 *rqtp) +const struct timespec64 *rqtp) {ktime_t texp =timespec64_to_ktime (*rqtp);
PATCH 15/20 posix-timers: Add proper comments in do_timer_create()
In reply to Thomas GleixnerThe comment about timer lifetime at the end of the function is misplaced and uncomprehensible.
Make it understandable and put it at the right place. Add a new comment about the visibility of the new timer ID to user space.
--- kernel/time/posix-timers.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-)
kernel/time/posix-timers.c +11 -9
@@ -528,12 +528,17 @@ static int do_timer_create(clockid_t whi new_timer->sigq->info.si_tid = new_timer->it_id; new_timer->sigq->info.si_code =SI_TIMER ; -if (copy_to_user (created_timer_id, - &new_timer_id,sizeof (new_timer_id))) { +if (copy_to_user (created_timer_id, &new_timer_id,sizeof (new_timer_id))) { error = -EFAULT ; goto out; } - +/* +* After succesful copy out, the timer ID is visible to user space +* now but not yet valid because new_timer::signal is still NULL. +* +* Complete the initialization with the clock specific create +* callback. +*/ error = kc->timer_create (new_timer);if (error) goto out;
@@ -543,14 +548,11 @@ static int do_timer_create(clockid_t whiWRITE_ONCE (new_timer->it_signal, current->signal);list_add (&new_timer->list, ¤t->signal->posix_timers);spin_unlock_irq (¤t->sighand->siglock); - -return 0 ;/* -* In the case of the timer belonging to another task, after -* the task is unlocked, the timer is owned by the other task -* and may cease to exist at any time. Don't use or modify -* new_timer after the unlock call. +* After unlocking sighand::siglock @new_timer is subject to +* concurrent removal and cannot be touched anymore */ +return 0 ; out:posix_timer_unhash_and_free (new_timer);return error;
Re: [patch 15/20] posix-timers: Add proper comments in do_timer_create()
Quoted 7 lines · Thomas Gleixner
The comment about timer lifetime at the end of the function is misplaced and uncomprehensible.
Make it understandable and put it at the right place. Add a new comment about the visibility of the new timer ID to user space.
Signed-off-by Thomas Gleixner <[email protected]>
[tip: timers/core] posix-timers: Add proper comments in do_timer_create()
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 2ef6cf6d46b462a1ff7fb70ad8050a2b35077e19 Gitweb: https://git.kernel.org/tip/2ef6cf6d46b462a1ff7fb70ad8050a2b35077e19 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:19 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Mon, 05 Jun 2023 17:03:38 +02:00
posix-timers: Add proper comments in do_timer_create()
The comment about timer lifetime at the end of the function is misplaced and uncomprehensible.
Make it understandable and put it at the right place. Add a new comment about the visibility of the new timer ID to user space.
--- kernel/time/posix-timers.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-)
kernel/time/posix-timers.c +11 -9
@@ -529,12 +529,17 @@ static int do_timer_create(clockid_t which_clock, struct sigevent *event, new_timer->sigq->info.si_tid = new_timer->it_id; new_timer->sigq->info.si_code =SI_TIMER ; -if (copy_to_user (created_timer_id, - &new_timer_id,sizeof (new_timer_id))) { +if (copy_to_user (created_timer_id, &new_timer_id,sizeof (new_timer_id))) { error = -EFAULT ; goto out; } - +/* +* After succesful copy out, the timer ID is visible to user space +* now but not yet valid because new_timer::signal is still NULL. +* +* Complete the initialization with the clock specific create +* callback. +*/ error = kc->timer_create (new_timer);if (error) goto out;
@@ -544,14 +549,11 @@ static int do_timer_create(clockid_t which_clock, struct sigevent *event,WRITE_ONCE (new_timer->it_signal, current->signal);list_add (&new_timer->list, ¤t->signal->posix_timers);spin_unlock_irq (¤t->sighand->siglock); - -return 0 ;/* -* In the case of the timer belonging to another task, after -* the task is unlocked, the timer is owned by the other task -* and may cease to exist at any time. Don't use or modify -* new_timer after the unlock call. +* After unlocking sighand::siglock @new_timer is subject to +* concurrent removal and cannot be touched anymore */ +return 0 ; out:posix_timer_unhash_and_free (new_timer);return error;
[tip: timers/core] posix-timers: Add proper comments in do_timer_create()
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 52f090b164b59c06a4da87c0599424809a6bba16 Gitweb: https://git.kernel.org/tip/52f090b164b59c06a4da87c0599424809a6bba16 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:19 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Sun, 18 Jun 2023 22:41:51 +02:00
posix-timers: Add proper comments in do_timer_create()
The comment about timer lifetime at the end of the function is misplaced and uncomprehensible.
Make it understandable and put it at the right place. Add a new comment about the visibility of the new timer ID to user space.
--- kernel/time/posix-timers.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-)
kernel/time/posix-timers.c +11 -9
@@ -529,12 +529,17 @@ static int do_timer_create(clockid_t which_clock, struct sigevent *event, new_timer->sigq->info.si_tid = new_timer->it_id; new_timer->sigq->info.si_code =SI_TIMER ; -if (copy_to_user (created_timer_id, - &new_timer_id,sizeof (new_timer_id))) { +if (copy_to_user (created_timer_id, &new_timer_id,sizeof (new_timer_id))) { error = -EFAULT ; goto out; } - +/* +* After succesful copy out, the timer ID is visible to user space +* now but not yet valid because new_timer::signal is still NULL. +* +* Complete the initialization with the clock specific create +* callback. +*/ error = kc->timer_create (new_timer);if (error) goto out;
@@ -544,14 +549,11 @@ static int do_timer_create(clockid_t which_clock, struct sigevent *event,WRITE_ONCE (new_timer->it_signal, current->signal);list_add (&new_timer->list, ¤t->signal->posix_timers);spin_unlock_irq (¤t->sighand->siglock); - -return 0 ;/* -* In the case of the timer belonging to another task, after -* the task is unlocked, the timer is owned by the other task -* and may cease to exist at any time. Don't use or modify -* new_timer after the unlock call. +* After unlocking sighand::siglock @new_timer is subject to +* concurrent removal and cannot be touched anymore */ +return 0 ; out:posix_timer_unhash_and_free (new_timer);return error;
PATCH 16/20 posix-timers: Comment SIGEV_THREAD_ID properly
In reply to Thomas GleixnerReplace the word salad.
--- kernel/time/posix-timers.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
kernel/time/posix-timers.c +2 -5
@@ -53,12 +53,9 @@ static const struct k_clock * const posistatic const struct k_clock *clockid_to_kclock (const clockid_t id);static const struct k_clock clock_realtime, clock_monotonic; -/* -* we assume that the new SIGEV_THREAD_ID shares no bits with the other -* SIGEV values. Here we put out an error if this assumption fails. -*/ +/* SIGEV_THREAD_ID cannot share a bit with the other SIGEV values. */ #if SIGEV_THREAD_ID != (SIGEV_THREAD_ID & \ - ~(SIGEV_SIGNAL |SIGEV_NONE |SIGEV_THREAD )) + ~(SIGEV_SIGNAL |SIGEV_NONE |SIGEV_THREAD ))#error "SIGEV_THREAD_ID must not share bit with other SIGEV values!"#endif
Re: [patch 16/20] posix-timers: Comment SIGEV_THREAD_ID properly
Quoted 3 lines · Thomas Gleixner
Replace the word salad.
Signed-off-by Thomas Gleixner <[email protected]>
[tip: timers/core] posix-timers: Comment SIGEV_THREAD_ID properly
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: b73b3beb88c26d3d6c644920fa83460ec5f6a559 Gitweb: https://git.kernel.org/tip/b73b3beb88c26d3d6c644920fa83460ec5f6a559 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:20 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Mon, 05 Jun 2023 17:03:38 +02:00
posix-timers: Comment SIGEV_THREAD_ID properly
Replace the word salad.
--- kernel/time/posix-timers.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
kernel/time/posix-timers.c +2 -5
@@ -53,12 +53,9 @@ static const struct k_clock * const posix_clocks[];static const struct k_clock *clockid_to_kclock (const clockid_t id);static const struct k_clock clock_realtime, clock_monotonic; -/* -* we assume that the new SIGEV_THREAD_ID shares no bits with the other -* SIGEV values. Here we put out an error if this assumption fails. -*/ +/* SIGEV_THREAD_ID cannot share a bit with the other SIGEV values. */ #if SIGEV_THREAD_ID != (SIGEV_THREAD_ID & \ - ~(SIGEV_SIGNAL |SIGEV_NONE |SIGEV_THREAD )) + ~(SIGEV_SIGNAL |SIGEV_NONE |SIGEV_THREAD ))#error "SIGEV_THREAD_ID must not share bit with other SIGEV values!"#endif
[tip: timers/core] posix-timers: Comment SIGEV_THREAD_ID properly
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: c575689d66378611bb04137b96e67ebb3ac8482b Gitweb: https://git.kernel.org/tip/c575689d66378611bb04137b96e67ebb3ac8482b Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:20 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Sun, 18 Jun 2023 22:41:51 +02:00
posix-timers: Comment SIGEV_THREAD_ID properly
Replace the word salad.
--- kernel/time/posix-timers.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-)
kernel/time/posix-timers.c +2 -5
@@ -53,12 +53,9 @@ static const struct k_clock * const posix_clocks[];static const struct k_clock *clockid_to_kclock (const clockid_t id);static const struct k_clock clock_realtime, clock_monotonic; -/* -* we assume that the new SIGEV_THREAD_ID shares no bits with the other -* SIGEV values. Here we put out an error if this assumption fails. -*/ +/* SIGEV_THREAD_ID cannot share a bit with the other SIGEV values. */ #if SIGEV_THREAD_ID != (SIGEV_THREAD_ID & \ - ~(SIGEV_SIGNAL |SIGEV_NONE |SIGEV_THREAD )) + ~(SIGEV_SIGNAL |SIGEV_NONE |SIGEV_THREAD ))#error "SIGEV_THREAD_ID must not share bit with other SIGEV values!"#endif
PATCH 17/20 posix-timers: Clarify posix_timer_rearm() comment
In reply to Thomas GleixnerYet another incomprehensible piece of art.
--- kernel/time/posix-timers.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-)
kernel/time/posix-timers.c +3 -9
@@ -274,15 +274,9 @@ static void common_hrtimer_rearm(struct }/* -* This function is exported for use by the signal deliver code. It is -* called just prior to the info block being released and passes that -* block to us. It's function is to update the overrun entry AND to -* restart the timer. It should only be called if the timer is to be -* restarted (i.e. we have flagged this in the sys_private entry of the -* info block). -* -* To protect against the timer going away while the interrupt is queued, -* we require that the it_requeue_pending flag be set. +* This function is called from the signal delivery code if +* info->si_sys_private is not zero, which indicates that the timer has to +* be rearmed. Restart the timer and update info::si_overrun. */ void posixtimer_rearm (struct kernel_siginfo *info) {
Re: [patch 17/20] posix-timers: Clarify posix_timer_rearm() comment
Quoted 3 lines · Thomas Gleixner
Yet another incomprehensible piece of art.
Signed-off-by Thomas Gleixner <[email protected]>
[tip: timers/core] posix-timers: Clarify posix_timer_rearm() comment
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 93a62291070d2836b7cbaf20febadae6ae33934a Gitweb: https://git.kernel.org/tip/93a62291070d2836b7cbaf20febadae6ae33934a Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:22 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Mon, 05 Jun 2023 17:03:38 +02:00
posix-timers: Clarify posix_timer_rearm() comment
Yet another incomprehensible piece of art.
--- kernel/time/posix-timers.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-)
kernel/time/posix-timers.c +3 -9
@@ -275,15 +275,9 @@ static void common_hrtimer_rearm(struct k_itimer *timr) }/* -* This function is exported for use by the signal deliver code. It is -* called just prior to the info block being released and passes that -* block to us. It's function is to update the overrun entry AND to -* restart the timer. It should only be called if the timer is to be -* restarted (i.e. we have flagged this in the sys_private entry of the -* info block). -* -* To protect against the timer going away while the interrupt is queued, -* we require that the it_requeue_pending flag be set. +* This function is called from the signal delivery code if +* info->si_sys_private is not zero, which indicates that the timer has to +* be rearmed. Restart the timer and update info::si_overrun. */ void posixtimer_rearm (struct kernel_siginfo *info) {
[tip: timers/core] posix-timers: Clarify posix_timer_rearm() comment
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 02972d7955341b711d4c392f14faa9f9cd69d551 Gitweb: https://git.kernel.org/tip/02972d7955341b711d4c392f14faa9f9cd69d551 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:22 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Sun, 18 Jun 2023 22:41:52 +02:00
posix-timers: Clarify posix_timer_rearm() comment
Yet another incomprehensible piece of art.
--- kernel/time/posix-timers.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-)
kernel/time/posix-timers.c +3 -9
@@ -275,15 +275,9 @@ static void common_hrtimer_rearm(struct k_itimer *timr) }/* -* This function is exported for use by the signal deliver code. It is -* called just prior to the info block being released and passes that -* block to us. It's function is to update the overrun entry AND to -* restart the timer. It should only be called if the timer is to be -* restarted (i.e. we have flagged this in the sys_private entry of the -* info block). -* -* To protect against the timer going away while the interrupt is queued, -* we require that the it_requeue_pending flag be set. +* This function is called from the signal delivery code if +* info->si_sys_private is not zero, which indicates that the timer has to +* be rearmed. Restart the timer and update info::si_overrun. */ void posixtimer_rearm (struct kernel_siginfo *info) {
PATCH 18/20 posix-timers: Clarify posix_timer_fn() comments
In reply to Thomas GleixnerMake the issues vs. SIG_IGN understandable and remove the 15 years old promise that a proper solution is already on the horizon.
--- kernel/time/posix-timers.c | 56 +++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 29 deletions(-)
kernel/time/posix-timers.c +27 -29
@@ -325,11 +325,11 @@ int posix_timer_event(struct k_itimer *t }/* -* This function gets called when a POSIX.1b interval timer expires. It -* is used as a callback from the kernel internal timer. The -* run_timer_list code ALWAYS calls with interrupts on. - -* This code is for CLOCK_REALTIME* and CLOCK_MONOTONIC* timers. +* This function gets called when a POSIX.1b interval timer expires from +* the HRTIMER soft interrupt with interrupts enabled. +* +* Handles CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_BOOTTIME and CLOCK_TAI +* based timers. */ static enum hrtimer_restart posix_timer_fn (struct hrtimer *timer) {
@@ -347,9 +347,10 @@ static enum hrtimer_restart posix_timer_if (posix_timer_event (timr, si_private)) {/* -* signal was not sent because of sig_ignor -* we will not get a call back to restart it AND -* it should be restarted. +* The signal was not queued due to SIG_IGN. As a +* consequence the timer is not going to be rearmed from +* the signal delivery path. But as a real signal handler +* can be installed later the timer must be rearmed here. */ if (timr->it_interval !=0 ) {ktime_t now =hrtimer_cb_get_time (timer);
@@ -358,34 +359,31 @@ static enum hrtimer_restart posix_timer_* FIXME: What we really want, is to stop this * timer completely and restart it in case the * SIG_IGN is removed. This is a non trivial -* change which involves sighand locking -* (sigh !), which we don't want to do late in -* the release cycle. +* change to the signal handling code. +* +* For now let timers with an interval less than a +* jiffie expire every jiffie to avoid softirq +* starvation in case of SIG_IGN and a very small +* interval, which would put the timer right back +* on the softirq pending list. Moving now ahead of +* time tricks hrtimer_forward() to expire the +* timer later, while it still maintains the +* overrun accuracy for the price of a slightly +* inconsistency in the timer_gettime() case. This +* is at least better than a starved softirq. * -* For now we just let timers with an interval -* less than a jiffie expire every jiffie to -* avoid softirq starvation in case of SIG_IGN -* and a very small interval, which would put -* the timer right back on the softirq pending -* list. By moving now ahead of time we trick -* hrtimer_forward() to expire the timer -* later, while we still maintain the overrun -* accuracy, but have some inconsistency in -* the timer_gettime() case. This is at least -* better than a starved softirq. A more -* complex fix which solves also another related -* inconsistency is already in the pipeline. +* Only required when high resolution timers are +* enabled as the periodic tick based timers are +* automatically aligned to the next tick. */ -#ifdef CONFIG_HIGH_RES_TIMERS - { +if (IS_ENABLED (CONFIG_HIGHRES_TIMERS )) {ktime_t kj =NSEC_PER_SEC /HZ ;if (timr->it_interval < kj) now =ktime_add (now, kj); } -#endif - timr->it_overrun +=hrtimer_forward (timer, now, - timr->it_interval); + + timr->it_overrun +=hrtimer_forward (timer, now, timr->it_interval); ret =HRTIMER_RESTART ; ++timr->it_requeue_pending; timr->it_active =1 ;
Frederic Weisbecker
maintainerRe: [patch 18/20] posix-timers: Clarify posix_timer_fn() comments
Quoted 11 lines · Thomas Gleixner
Make the issues vs.
SIG_IGNunderstandable and remove the 15 years old promise that a proper solution is already on the horizon.Signed-off-by Thomas Gleixner <[email protected]>--- kernel/time/posix-timers.c | 56 +++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 29 deletions(-)
kernel/time/posix-timers.c int posix_timer_event(struct k_itimer *t · line 329
Quoted 10 lines
kernel/time/posix-timers.c +2
-5@@ -325,11 +325,11 @@ int posix_timer_event(struct k_itimer *t }/* -* This function gets called when a POSIX.1b interval timer expires. It -* is used as a callback from the kernel internal timer. The -* run_timer_list code ALWAYS calls with interrupts on. - -* This code is for CLOCK_REALTIME* and CLOCK_MONOTONIC* timers. +* This function gets called when a POSIX.1b interval timer expires from +* the HRTIMER soft interrupt with interrupts enabled.
BTW, what arranges for this to be called in softirq with interrupts enabled? The modes I see used here are HRTIMER_MODE_ABS or HRTIMER_MODE_REL and not their _SOFT counterparts.
Quoted 7 lines
kernel/time/posix-timers.c +3
-0+* +* Handles CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_BOOTTIME and CLOCK_TAI +* based timers. */ static enum hrtimer_restart posix_timer_fn (struct hrtimer *timer) {
kernel/time/posix-timers.c static enum hrtimer_restart posix_timer_ · line 365
Quoted 10 lines
kernel/time/posix-timers.c +4
-3@@ -358,34 +359,31 @@ static enum hrtimer_restart posix_timer_* FIXME: What we really want, is to stop this * timer completely and restart it in case the * SIG_IGN is removed. This is a non trivial -* change which involves sighand locking -* (sigh !), which we don't want to do late in -* the release cycle. +* change to the signal handling code. +* +* For now let timers with an interval less than a +* jiffie expire every jiffie to avoid softirq
Or rather at least to the next jiffie, right? Because then in the next jiffie it gets re-evaluated in case a real signal handler might have been set in-between.
Or it could be:
+ * For now let timers with an interval less than a
+ * jiffie expire every jiffie (until a real sig handler
+ * is found set) to avoid softirq...
Quoted 8 lines
kernel/time/posix-timers.c +8
-0+* starvation in case of SIG_IGN and a very small +* interval, which would put the timer right back +* on the softirq pending list. Moving now ahead of +* time tricks hrtimer_forward() to expire the +* timer later, while it still maintains the +* overrun accuracy for the price of a slightly +* inconsistency in the timer_gettime() case. This +* is at least better than a starved softirq.
[...]
kernel/time/posix-timers.c static enum hrtimer_restart posix_timer_ · line 380
Quoted 5 lines
kernel/time/posix-timers.c +1
-2*/ -#ifdef CONFIG_HIGH_RES_TIMERS - { +if (IS_ENABLED (CONFIG_HIGHRES_TIMERS )) {ktime_t kj =NSEC_PER_SEC /HZ ;
Could be TICK_NSECS?
Thanks!
Quoted 13 lines
kernel/time/posix-timers.c +2
-3if (timr->it_interval < kj) now =ktime_add (now, kj); } -#endif - timr->it_overrun +=hrtimer_forward (timer, now, - timr->it_interval); + + timr->it_overrun +=hrtimer_forward (timer, now, timr->it_interval); ret =HRTIMER_RESTART ; ++timr->it_requeue_pending; timr->it_active =1 ;
Re: [patch 18/20] posix-timers: Clarify posix_timer_fn() comments
Quoted 14 lines · Frederic Weisbecker
Quoted 13 lines · Thomas Gleixner
Make the issues vs.
SIG_IGNunderstandable and remove the 15 years old promise that a proper solution is already on the horizon.Signed-off-by Thomas Gleixner <[email protected]>--- kernel/time/posix-timers.c | 56 +++++++++++++++++++++------------------------ 1 file changed, 27 insertions(+), 29 deletions(-)kernel/time/posix-timers.c +0
-0@@ -325,11 +325,11 @@ int posix_timer_event(struct k_itimer *t }
Quoted 12 lines
kernel/time/posix-timers.c int posix_timer_event(struct k_itimer *t · line 329
Quoted 8 lines
kernel/time/posix-timers.c +2
-5/* -* This function gets called when a POSIX.1b interval timer expires. It -* is used as a callback from the kernel internal timer. The -* run_timer_list code ALWAYS calls with interrupts on. - -* This code is for CLOCK_REALTIME* and CLOCK_MONOTONIC* timers. +* This function gets called when a POSIX.1b interval timer expires from +* the HRTIMER soft interrupt with interrupts enabled. BTW, what arranges for this to be called in softirq with interrupts enabled? The modes I see used here are
HRTIMER_MODE_ABSorHRTIMER_MODE_RELand not their_SOFTcounterparts.
Duh. My RT biased brain tricked me.
Quoted 22 lines
Quoted 7 lines
kernel/time/posix-timers.c +3
-0+* +* Handles CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_BOOTTIME and CLOCK_TAI +* based timers. */ static enum hrtimer_restart posix_timer_fn (struct hrtimer *timer) {kernel/time/posix-timers.c static enum hrtimer_restart posix_timer_ · line 365
Quoted 10 lines
kernel/time/posix-timers.c +4
-3@@ -358,34 +359,31 @@ static enum hrtimer_restart posix_timer_* FIXME: What we really want, is to stop this * timer completely and restart it in case the * SIG_IGN is removed. This is a non trivial -* change which involves sighand locking -* (sigh !), which we don't want to do late in -* the release cycle. +* change to the signal handling code. +* +* For now let timers with an interval less than a +* jiffie expire every jiffie to avoid softirq Or rather at least to the next jiffie, right? Because then in the next jiffie it gets re-evaluated in case a real signal handler might have been set in-between.
Quoted 5 lines
Or it could be:
+ * For now let timers with an interval less than a
+ * jiffie expire every jiffie (until a real sig handler
+ * is found set) to avoid softirq...
Let me rephrase that.
Quoted 9 lines
Quoted 8 lines
kernel/time/posix-timers.c +8
-0+* starvation in case of SIG_IGN and a very small +* interval, which would put the timer right back +* on the softirq pending list. Moving now ahead of +* time tricks hrtimer_forward() to expire the +* timer later, while it still maintains the +* overrun accuracy for the price of a slightly +* inconsistency in the timer_gettime() case. This +* is at least better than a starved softirq. [...]
Quoted 7 lines
kernel/time/posix-timers.c static enum hrtimer_restart posix_timer_ · line 380
Quoted 5 lines
kernel/time/posix-timers.c +1
-2*/ -#ifdef CONFIG_HIGH_RES_TIMERS - { +if (IS_ENABLED (CONFIG_HIGHRES_TIMERS )) {ktime_t kj =NSEC_PER_SEC /HZ ;Could be
TICK_NSECS?
Yep. Fixed it up.
Re: [patch 18/20] posix-timers: Clarify posix_timer_fn() comments
In reply to Frederic WeisbeckerMake the issues vs. SIG_IGN understandable and remove the 15 years old promise that a proper solution is already on the horizon.
---
V2: Clarify comments and use TICK_NSECS - Frederic
--- kernel/time/posix-timers.c | 62 +++++++++++++++++++++++---------------------- 1 file changed, 32 insertions(+), 30 deletions(-)
kernel/time/posix-timers.c +32 -30
@@ -326,11 +326,11 @@ int posix_timer_event(struct k_itimer *t }/* -* This function gets called when a POSIX.1b interval timer expires. It -* is used as a callback from the kernel internal timer. The -* run_timer_list code ALWAYS calls with interrupts on. - -* This code is for CLOCK_REALTIME* and CLOCK_MONOTONIC* timers. +* This function gets called when a POSIX.1b interval timer expires from +* the HRTIMER interrupt (soft interrupt on RT kernels). +* +* Handles CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_BOOTTIME and CLOCK_TAI +* based timers. */ static enum hrtimer_restart posix_timer_fn (struct hrtimer *timer) {
@@ -348,9 +348,10 @@ static enum hrtimer_restart posix_timer_if (posix_timer_event (timr, si_private)) {/* -* signal was not sent because of sig_ignor -* we will not get a call back to restart it AND -* it should be restarted. +* The signal was not queued due to SIG_IGN. As a +* consequence the timer is not going to be rearmed from +* the signal delivery path. But as a real signal handler +* can be installed later the timer must be rearmed here. */ if (timr->it_interval !=0 ) {ktime_t now =hrtimer_cb_get_time (timer);
@@ -359,34 +360,35 @@ static enum hrtimer_restart posix_timer_* FIXME: What we really want, is to stop this * timer completely and restart it in case the * SIG_IGN is removed. This is a non trivial -* change which involves sighand locking -* (sigh !), which we don't want to do late in -* the release cycle. +* change to the signal handling code. +* +* For now let timers with an interval less than a +* jiffie expire every jiffie and recheck for a +* valid signal handler. +* +* This avoids interrupt starvation in case of a +* very small interval, which would expire the +* timer immediately again. * -* For now we just let timers with an interval -* less than a jiffie expire every jiffie to -* avoid softirq starvation in case of SIG_IGN -* and a very small interval, which would put -* the timer right back on the softirq pending -* list. By moving now ahead of time we trick -* hrtimer_forward() to expire the timer -* later, while we still maintain the overrun -* accuracy, but have some inconsistency in -* the timer_gettime() case. This is at least -* better than a starved softirq. A more -* complex fix which solves also another related -* inconsistency is already in the pipeline. +* Moving now ahead of time by one jiffie tricks +* hrtimer_forward() to expire the timer later, +* while it still maintains the overrun accuracy +* for the price of a slight inconsistency in the +* timer_gettime() case. This is at least better +* than a starved softirq. +* +* Only required when high resolution timers are +* enabled as the periodic tick based timers are +* automatically aligned to the next tick. */ -#ifdef CONFIG_HIGH_RES_TIMERS - { -ktime_t kj =NSEC_PER_SEC /HZ ; +if (IS_ENABLED (CONFIG_HIGHRES_TIMERS )) { +ktime_t kj =TICK_NSECS ;if (timr->it_interval < kj) now =ktime_add (now, kj); } -#endif - timr->it_overrun +=hrtimer_forward (timer, now, - timr->it_interval); + + timr->it_overrun +=hrtimer_forward (timer, now, timr->it_interval); ret =HRTIMER_RESTART ; ++timr->it_requeue_pending; timr->it_active =1 ;
Re: [patch 18/20] posix-timers: Clarify posix_timer_fn() comments
Quoted 26 lines · Thomas Gleixner
kernel/time/posix-timers.c +9
-12@@ -359,34 +360,35 @@ static enum hrtimer_restart posix_timer_* FIXME: What we really want, is to stop this * timer completely and restart it in case the * SIG_IGN is removed. This is a non trivial -* change which involves sighand locking -* (sigh !), which we don't want to do late in -* the release cycle. +* change to the signal handling code. +* +* For now let timers with an interval less than a +* jiffie expire every jiffie and recheck for a +* valid signal handler. +* +* This avoids interrupt starvation in case of a +* very small interval, which would expire the +* timer immediately again. * -* For now we just let timers with an interval -* less than a jiffie expire every jiffie to -* avoid softirq starvation in case of SIG_IGN -* and a very small interval, which would put -* the timer right back on the softirq pending -* list. By moving now ahead of time we trick -* hrtimer_forward() to expire the timer -* later, while we still maintain the overrun -* accuracy, but have some inconsistency in
kernel/time/posix-timers.c static enum hrtimer_restart posix_timer_ · line 378
Quoted 10 lines
kernel/time/posix-timers.c +6
-4-* the timer_gettime() case. This is at least -* better than a starved softirq. A more -* complex fix which solves also another related -* inconsistency is already in the pipeline. +* Moving now ahead of time by one jiffie tricks +* hrtimer_forward() to expire the timer later, +* while it still maintains the overrun accuracy +* for the price of a slight inconsistency in the +* timer_gettime() case. This is at least better +* than a starved softirq.
Could be hardirq. How about:
"This is at least better than a timer storm."
[tip: timers/core] posix-timers: Clarify posix_timer_fn() comments
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 63dede13d09850a8ace210f8e4227ac5a6b309ae Gitweb: https://git.kernel.org/tip/63dede13d09850a8ace210f8e4227ac5a6b309ae Author: Thomas Gleixner <[email protected]> AuthorDate: Thu, 01 Jun 2023 21:07:37 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Mon, 05 Jun 2023 17:03:38 +02:00
posix-timers: Clarify posix_timer_fn() comments
Make the issues vs. SIG_IGN understandable and remove the 15 years old promise that a proper solution is already on the horizon.
--- kernel/time/posix-timers.c | 62 +++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 30 deletions(-)
kernel/time/posix-timers.c +32 -30
@@ -326,11 +326,11 @@ int posix_timer_event(struct k_itimer *timr, int si_private) }/* -* This function gets called when a POSIX.1b interval timer expires. It -* is used as a callback from the kernel internal timer. The -* run_timer_list code ALWAYS calls with interrupts on. - -* This code is for CLOCK_REALTIME* and CLOCK_MONOTONIC* timers. +* This function gets called when a POSIX.1b interval timer expires from +* the HRTIMER interrupt (soft interrupt on RT kernels). +* +* Handles CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_BOOTTIME and CLOCK_TAI +* based timers. */ static enum hrtimer_restart posix_timer_fn (struct hrtimer *timer) {
@@ -348,9 +348,10 @@ static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer)if (posix_timer_event (timr, si_private)) {/* -* signal was not sent because of sig_ignor -* we will not get a call back to restart it AND -* it should be restarted. +* The signal was not queued due to SIG_IGN. As a +* consequence the timer is not going to be rearmed from +* the signal delivery path. But as a real signal handler +* can be installed later the timer must be rearmed here. */ if (timr->it_interval !=0 ) {ktime_t now =hrtimer_cb_get_time (timer);
@@ -359,34 +360,35 @@ static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer)* FIXME: What we really want, is to stop this * timer completely and restart it in case the * SIG_IGN is removed. This is a non trivial -* change which involves sighand locking -* (sigh !), which we don't want to do late in -* the release cycle. +* change to the signal handling code. +* +* For now let timers with an interval less than a +* jiffie expire every jiffie and recheck for a +* valid signal handler. +* +* This avoids interrupt starvation in case of a +* very small interval, which would expire the +* timer immediately again. * -* For now we just let timers with an interval -* less than a jiffie expire every jiffie to -* avoid softirq starvation in case of SIG_IGN -* and a very small interval, which would put -* the timer right back on the softirq pending -* list. By moving now ahead of time we trick -* hrtimer_forward() to expire the timer -* later, while we still maintain the overrun -* accuracy, but have some inconsistency in -* the timer_gettime() case. This is at least -* better than a starved softirq. A more -* complex fix which solves also another related -* inconsistency is already in the pipeline. +* Moving now ahead of time by one jiffie tricks +* hrtimer_forward() to expire the timer later, +* while it still maintains the overrun accuracy +* for the price of a slight inconsistency in the +* timer_gettime() case. This is at least better +* than a timer storm. +* +* Only required when high resolution timers are +* enabled as the periodic tick based timers are +* automatically aligned to the next tick. */ -#ifdef CONFIG_HIGH_RES_TIMERS - { -ktime_t kj =NSEC_PER_SEC /HZ ; +if (IS_ENABLED (CONFIG_HIGHRES_TIMERS )) { +ktime_t kj =TICK_NSECS ;if (timr->it_interval < kj) now =ktime_add (now, kj); } -#endif - timr->it_overrun +=hrtimer_forward (timer, now, - timr->it_interval); + + timr->it_overrun +=hrtimer_forward (timer, now, timr->it_interval); ret =HRTIMER_RESTART ; ++timr->it_requeue_pending; timr->it_active =1 ;
[tip: timers/core] posix-timers: Clarify posix_timer_fn() comments
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: c78f261e5dcb415b9e35a13876fbf7d5f134c810 Gitweb: https://git.kernel.org/tip/c78f261e5dcb415b9e35a13876fbf7d5f134c810 Author: Thomas Gleixner <[email protected]> AuthorDate: Thu, 01 Jun 2023 21:07:37 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Tue, 06 Jun 2023 00:12:55 +02:00
posix-timers: Clarify posix_timer_fn() comments
Make the issues vs. SIG_IGN understandable and remove the 15 years old promise that a proper solution is already on the horizon.
--- kernel/time/posix-timers.c | 62 +++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 30 deletions(-)
kernel/time/posix-timers.c +32 -30
@@ -326,11 +326,11 @@ int posix_timer_event(struct k_itimer *timr, int si_private) }/* -* This function gets called when a POSIX.1b interval timer expires. It -* is used as a callback from the kernel internal timer. The -* run_timer_list code ALWAYS calls with interrupts on. - -* This code is for CLOCK_REALTIME* and CLOCK_MONOTONIC* timers. +* This function gets called when a POSIX.1b interval timer expires from +* the HRTIMER interrupt (soft interrupt on RT kernels). +* +* Handles CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_BOOTTIME and CLOCK_TAI +* based timers. */ static enum hrtimer_restart posix_timer_fn (struct hrtimer *timer) {
@@ -348,9 +348,10 @@ static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer)if (posix_timer_event (timr, si_private)) {/* -* signal was not sent because of sig_ignor -* we will not get a call back to restart it AND -* it should be restarted. +* The signal was not queued due to SIG_IGN. As a +* consequence the timer is not going to be rearmed from +* the signal delivery path. But as a real signal handler +* can be installed later the timer must be rearmed here. */ if (timr->it_interval !=0 ) {ktime_t now =hrtimer_cb_get_time (timer);
@@ -359,34 +360,35 @@ static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer)* FIXME: What we really want, is to stop this * timer completely and restart it in case the * SIG_IGN is removed. This is a non trivial -* change which involves sighand locking -* (sigh !), which we don't want to do late in -* the release cycle. +* change to the signal handling code. +* +* For now let timers with an interval less than a +* jiffie expire every jiffie and recheck for a +* valid signal handler. +* +* This avoids interrupt starvation in case of a +* very small interval, which would expire the +* timer immediately again. * -* For now we just let timers with an interval -* less than a jiffie expire every jiffie to -* avoid softirq starvation in case of SIG_IGN -* and a very small interval, which would put -* the timer right back on the softirq pending -* list. By moving now ahead of time we trick -* hrtimer_forward() to expire the timer -* later, while we still maintain the overrun -* accuracy, but have some inconsistency in -* the timer_gettime() case. This is at least -* better than a starved softirq. A more -* complex fix which solves also another related -* inconsistency is already in the pipeline. +* Moving now ahead of time by one jiffie tricks +* hrtimer_forward() to expire the timer later, +* while it still maintains the overrun accuracy +* for the price of a slight inconsistency in the +* timer_gettime() case. This is at least better +* than a timer storm. +* +* Only required when high resolution timers are +* enabled as the periodic tick based timers are +* automatically aligned to the next tick. */ -#ifdef CONFIG_HIGH_RES_TIMERS - { -ktime_t kj =NSEC_PER_SEC /HZ ; +if (IS_ENABLED (CONFIG_HIGHRES_TIMERS )) { +ktime_t kj =TICK_NSEC ;if (timr->it_interval < kj) now =ktime_add (now, kj); } -#endif - timr->it_overrun +=hrtimer_forward (timer, now, - timr->it_interval); + + timr->it_overrun +=hrtimer_forward (timer, now, timr->it_interval); ret =HRTIMER_RESTART ; ++timr->it_requeue_pending; timr->it_active =1 ;
[tip: timers/core] posix-timers: Clarify posix_timer_fn() comments
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 84999b8bdb4969816c7bb7c14c3a55ed42aa4b94 Gitweb: https://git.kernel.org/tip/84999b8bdb4969816c7bb7c14c3a55ed42aa4b94 Author: Thomas Gleixner <[email protected]> AuthorDate: Thu, 01 Jun 2023 21:07:37 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Sun, 18 Jun 2023 22:41:52 +02:00
posix-timers: Clarify posix_timer_fn() comments
Make the issues vs. SIG_IGN understandable and remove the 15 years old promise that a proper solution is already on the horizon.
--- kernel/time/posix-timers.c | 62 +++++++++++++++++++------------------ 1 file changed, 32 insertions(+), 30 deletions(-)
kernel/time/posix-timers.c +32 -30
@@ -326,11 +326,11 @@ int posix_timer_event(struct k_itimer *timr, int si_private) }/* -* This function gets called when a POSIX.1b interval timer expires. It -* is used as a callback from the kernel internal timer. The -* run_timer_list code ALWAYS calls with interrupts on. - -* This code is for CLOCK_REALTIME* and CLOCK_MONOTONIC* timers. +* This function gets called when a POSIX.1b interval timer expires from +* the HRTIMER interrupt (soft interrupt on RT kernels). +* +* Handles CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_BOOTTIME and CLOCK_TAI +* based timers. */ static enum hrtimer_restart posix_timer_fn (struct hrtimer *timer) {
@@ -348,9 +348,10 @@ static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer)if (posix_timer_event (timr, si_private)) {/* -* signal was not sent because of sig_ignor -* we will not get a call back to restart it AND -* it should be restarted. +* The signal was not queued due to SIG_IGN. As a +* consequence the timer is not going to be rearmed from +* the signal delivery path. But as a real signal handler +* can be installed later the timer must be rearmed here. */ if (timr->it_interval !=0 ) {ktime_t now =hrtimer_cb_get_time (timer);
@@ -359,34 +360,35 @@ static enum hrtimer_restart posix_timer_fn(struct hrtimer *timer)* FIXME: What we really want, is to stop this * timer completely and restart it in case the * SIG_IGN is removed. This is a non trivial -* change which involves sighand locking -* (sigh !), which we don't want to do late in -* the release cycle. +* change to the signal handling code. +* +* For now let timers with an interval less than a +* jiffie expire every jiffie and recheck for a +* valid signal handler. +* +* This avoids interrupt starvation in case of a +* very small interval, which would expire the +* timer immediately again. * -* For now we just let timers with an interval -* less than a jiffie expire every jiffie to -* avoid softirq starvation in case of SIG_IGN -* and a very small interval, which would put -* the timer right back on the softirq pending -* list. By moving now ahead of time we trick -* hrtimer_forward() to expire the timer -* later, while we still maintain the overrun -* accuracy, but have some inconsistency in -* the timer_gettime() case. This is at least -* better than a starved softirq. A more -* complex fix which solves also another related -* inconsistency is already in the pipeline. +* Moving now ahead of time by one jiffie tricks +* hrtimer_forward() to expire the timer later, +* while it still maintains the overrun accuracy +* for the price of a slight inconsistency in the +* timer_gettime() case. This is at least better +* than a timer storm. +* +* Only required when high resolution timers are +* enabled as the periodic tick based timers are +* automatically aligned to the next tick. */ -#ifdef CONFIG_HIGH_RES_TIMERS - { -ktime_t kj =NSEC_PER_SEC /HZ ; +if (IS_ENABLED (CONFIG_HIGHRES_TIMERS )) { +ktime_t kj =TICK_NSEC ;if (timr->it_interval < kj) now =ktime_add (now, kj); } -#endif - timr->it_overrun +=hrtimer_forward (timer, now, - timr->it_interval); + + timr->it_overrun +=hrtimer_forward (timer, now, timr->it_interval); ret =HRTIMER_RESTART ; ++timr->it_requeue_pending; timr->it_active =1 ;
PATCH 19/20 posix-timers: Remove pointless comments
In reply to Thomas GleixnerDocumenting the obvious is just consuming space for no value.
--- kernel/time/posix-timers.c | 25 ------------------------- 1 file changed, 25 deletions(-)
kernel/time/posix-timers.c +0 -25
@@ -59,19 +59,6 @@ static const struct k_clock clock_realti#error "SIGEV_THREAD_ID must not share bit with other SIGEV values!"#endif -/* -* CLOCKs: The POSIX standard calls for a couple of clocks and allows us -* to implement others. This structure defines the various -* clocks. -* -* FUNCTIONS: The CLOCKs structure defines possible functions to -* handle various clock functions. -* -* The standard POSIX timer management code assumes the -* following: 1.) The k_itimer struct (sched.h) is used for -* the timer. 2.) The list, it_lock, it_clock, it_id and -* it_pid fields are not modified by timer code. -*/ static struct k_itimer *__lock_timer (timer_t timer_id,unsigned long *flags);#define lock_timer (tid, flags) \
@@ -140,7 +127,6 @@ static inline void unlock_timer(struct kspin_unlock_irqrestore (&timr->it_lock, flags); } -/* Get clock_realtime */ static int posix_get_realtime_timespec (clockid_t which_clock,struct timespec64 *tp) {ktime_get_real_ts64 (tp);
@@ -152,7 +138,6 @@ static ktime_t posix_get_realtime_ktime(return ktime_get_real (); } -/* Set clock_realtime */ static int posix_clock_realtime_set (const clockid_t which_clock,const struct timespec64 *tp) {
@@ -165,9 +150,6 @@ static int posix_clock_realtime_adj(consreturn do_adjtimex (t); } -/* -* Get monotonic time for posix timers -*/ static int posix_get_monotonic_timespec (clockid_t which_clock,struct timespec64 *tp) {ktime_get_ts64 (tp);
@@ -180,9 +162,6 @@ static ktime_t posix_get_monotonic_ktimereturn ktime_get (); } -/* -* Get monotonic-raw time for posix timers -*/ static int posix_get_monotonic_raw (clockid_t which_clock,struct timespec64 *tp) {ktime_get_raw_ts64 (tp);
@@ -190,7 +169,6 @@ static int posix_get_monotonic_raw(clockreturn 0 ; } -static int posix_get_realtime_coarse (clockid_t which_clock,struct timespec64 *tp) {ktime_get_coarse_real_ts64 (tp);
@@ -241,9 +219,6 @@ static int posix_get_hrtimer_res(clockidreturn 0 ; } -/* -* Initialize everything, well, just everything in Posix clocks/timers ;) -*/ static __init int init_posix_timers (void ) { posix_timers_cache = kmem_cache_create("posix_timers_cache",
Re: [patch 19/20] posix-timers: Remove pointless comments
Quoted 3 lines · Thomas Gleixner
Documenting the obvious is just consuming space for no value.
Signed-off-by Thomas Gleixner <[email protected]>
[tip: timers/core] posix-timers: Remove pointless comments
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 478a93ac9ed7da5e7cd98e00502b142e22dab4d7 Gitweb: https://git.kernel.org/tip/478a93ac9ed7da5e7cd98e00502b142e22dab4d7 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:25 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Mon, 05 Jun 2023 17:03:39 +02:00
posix-timers: Remove pointless comments
Documenting the obvious is just consuming space for no value.
--- kernel/time/posix-timers.c | 25 ------------------------- 1 file changed, 25 deletions(-)
kernel/time/posix-timers.c +0 -25
@@ -59,19 +59,6 @@ static const struct k_clock clock_realtime, clock_monotonic;#error "SIGEV_THREAD_ID must not share bit with other SIGEV values!"#endif -/* -* CLOCKs: The POSIX standard calls for a couple of clocks and allows us -* to implement others. This structure defines the various -* clocks. -* -* FUNCTIONS: The CLOCKs structure defines possible functions to -* handle various clock functions. -* -* The standard POSIX timer management code assumes the -* following: 1.) The k_itimer struct (sched.h) is used for -* the timer. 2.) The list, it_lock, it_clock, it_id and -* it_pid fields are not modified by timer code. -*/ static struct k_itimer *__lock_timer (timer_t timer_id,unsigned long *flags);#define lock_timer (tid, flags) \
@@ -141,7 +128,6 @@ static inline void unlock_timer(struct k_itimer *timr, unsigned long flags)spin_unlock_irqrestore (&timr->it_lock, flags); } -/* Get clock_realtime */ static int posix_get_realtime_timespec (clockid_t which_clock,struct timespec64 *tp) {ktime_get_real_ts64 (tp);
@@ -153,7 +139,6 @@ static ktime_t posix_get_realtime_ktime(clockid_t which_clock)return ktime_get_real (); } -/* Set clock_realtime */ static int posix_clock_realtime_set (const clockid_t which_clock,const struct timespec64 *tp) {
@@ -166,9 +151,6 @@ static int posix_clock_realtime_adj(const clockid_t which_clock,return do_adjtimex (t); } -/* -* Get monotonic time for posix timers -*/ static int posix_get_monotonic_timespec (clockid_t which_clock,struct timespec64 *tp) {ktime_get_ts64 (tp);
@@ -181,9 +163,6 @@ static ktime_t posix_get_monotonic_ktime(clockid_t which_clock)return ktime_get (); } -/* -* Get monotonic-raw time for posix timers -*/ static int posix_get_monotonic_raw (clockid_t which_clock,struct timespec64 *tp) {ktime_get_raw_ts64 (tp);
@@ -191,7 +170,6 @@ static int posix_get_monotonic_raw(clockid_t which_clock, struct timespec64 *tp)return 0 ; } -static int posix_get_realtime_coarse (clockid_t which_clock,struct timespec64 *tp) {ktime_get_coarse_real_ts64 (tp);
@@ -242,9 +220,6 @@ static int posix_get_hrtimer_res(clockid_t which_clock, struct timespec64 *tp)return 0 ; } -/* -* Initialize everything, well, just everything in Posix clocks/timers ;) -*/ static __init int init_posix_timers (void ) { posix_timers_cache = kmem_cache_create("posix_timers_cache",
[tip: timers/core] posix-timers: Remove pointless comments
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 298356a3c78198f44ba5df65547a9085334daa38 Gitweb: https://git.kernel.org/tip/298356a3c78198f44ba5df65547a9085334daa38 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:25 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Tue, 06 Jun 2023 00:12:55 +02:00
posix-timers: Remove pointless comments
Documenting the obvious is just consuming space for no value.
--- kernel/time/posix-timers.c | 25 ------------------------- 1 file changed, 25 deletions(-)
kernel/time/posix-timers.c +0 -25
@@ -59,19 +59,6 @@ static const struct k_clock clock_realtime, clock_monotonic;#error "SIGEV_THREAD_ID must not share bit with other SIGEV values!"#endif -/* -* CLOCKs: The POSIX standard calls for a couple of clocks and allows us -* to implement others. This structure defines the various -* clocks. -* -* FUNCTIONS: The CLOCKs structure defines possible functions to -* handle various clock functions. -* -* The standard POSIX timer management code assumes the -* following: 1.) The k_itimer struct (sched.h) is used for -* the timer. 2.) The list, it_lock, it_clock, it_id and -* it_pid fields are not modified by timer code. -*/ static struct k_itimer *__lock_timer (timer_t timer_id,unsigned long *flags);#define lock_timer (tid, flags) \
@@ -141,7 +128,6 @@ static inline void unlock_timer(struct k_itimer *timr, unsigned long flags)spin_unlock_irqrestore (&timr->it_lock, flags); } -/* Get clock_realtime */ static int posix_get_realtime_timespec (clockid_t which_clock,struct timespec64 *tp) {ktime_get_real_ts64 (tp);
@@ -153,7 +139,6 @@ static ktime_t posix_get_realtime_ktime(clockid_t which_clock)return ktime_get_real (); } -/* Set clock_realtime */ static int posix_clock_realtime_set (const clockid_t which_clock,const struct timespec64 *tp) {
@@ -166,9 +151,6 @@ static int posix_clock_realtime_adj(const clockid_t which_clock,return do_adjtimex (t); } -/* -* Get monotonic time for posix timers -*/ static int posix_get_monotonic_timespec (clockid_t which_clock,struct timespec64 *tp) {ktime_get_ts64 (tp);
@@ -181,9 +163,6 @@ static ktime_t posix_get_monotonic_ktime(clockid_t which_clock)return ktime_get (); } -/* -* Get monotonic-raw time for posix timers -*/ static int posix_get_monotonic_raw (clockid_t which_clock,struct timespec64 *tp) {ktime_get_raw_ts64 (tp);
@@ -191,7 +170,6 @@ static int posix_get_monotonic_raw(clockid_t which_clock, struct timespec64 *tp)return 0 ; } -static int posix_get_realtime_coarse (clockid_t which_clock,struct timespec64 *tp) {ktime_get_coarse_real_ts64 (tp);
@@ -242,9 +220,6 @@ static int posix_get_hrtimer_res(clockid_t which_clock, struct timespec64 *tp)return 0 ; } -/* -* Initialize everything, well, just everything in Posix clocks/timers ;) -*/ static __init int init_posix_timers (void ) { posix_timers_cache = kmem_cache_create("posix_timers_cache",
[tip: timers/core] posix-timers: Remove pointless comments
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 200dbd6d14e6a3b22162d78b4f7a253426dba7ee Gitweb: https://git.kernel.org/tip/200dbd6d14e6a3b22162d78b4f7a253426dba7ee Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:25 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Sun, 18 Jun 2023 22:41:52 +02:00
posix-timers: Remove pointless comments
Documenting the obvious is just consuming space for no value.
--- kernel/time/posix-timers.c | 25 ------------------------- 1 file changed, 25 deletions(-)
kernel/time/posix-timers.c +0 -25
@@ -59,19 +59,6 @@ static const struct k_clock clock_realtime, clock_monotonic;#error "SIGEV_THREAD_ID must not share bit with other SIGEV values!"#endif -/* -* CLOCKs: The POSIX standard calls for a couple of clocks and allows us -* to implement others. This structure defines the various -* clocks. -* -* FUNCTIONS: The CLOCKs structure defines possible functions to -* handle various clock functions. -* -* The standard POSIX timer management code assumes the -* following: 1.) The k_itimer struct (sched.h) is used for -* the timer. 2.) The list, it_lock, it_clock, it_id and -* it_pid fields are not modified by timer code. -*/ static struct k_itimer *__lock_timer (timer_t timer_id,unsigned long *flags);#define lock_timer (tid, flags) \
@@ -141,7 +128,6 @@ static inline void unlock_timer(struct k_itimer *timr, unsigned long flags)spin_unlock_irqrestore (&timr->it_lock, flags); } -/* Get clock_realtime */ static int posix_get_realtime_timespec (clockid_t which_clock,struct timespec64 *tp) {ktime_get_real_ts64 (tp);
@@ -153,7 +139,6 @@ static ktime_t posix_get_realtime_ktime(clockid_t which_clock)return ktime_get_real (); } -/* Set clock_realtime */ static int posix_clock_realtime_set (const clockid_t which_clock,const struct timespec64 *tp) {
@@ -166,9 +151,6 @@ static int posix_clock_realtime_adj(const clockid_t which_clock,return do_adjtimex (t); } -/* -* Get monotonic time for posix timers -*/ static int posix_get_monotonic_timespec (clockid_t which_clock,struct timespec64 *tp) {ktime_get_ts64 (tp);
@@ -181,9 +163,6 @@ static ktime_t posix_get_monotonic_ktime(clockid_t which_clock)return ktime_get (); } -/* -* Get monotonic-raw time for posix timers -*/ static int posix_get_monotonic_raw (clockid_t which_clock,struct timespec64 *tp) {ktime_get_raw_ts64 (tp);
@@ -191,7 +170,6 @@ static int posix_get_monotonic_raw(clockid_t which_clock, struct timespec64 *tp)return 0 ; } -static int posix_get_realtime_coarse (clockid_t which_clock,struct timespec64 *tp) {ktime_get_coarse_real_ts64 (tp);
@@ -242,9 +220,6 @@ static int posix_get_hrtimer_res(clockid_t which_clock, struct timespec64 *tp)return 0 ; } -/* -* Initialize everything, well, just everything in Posix clocks/timers ;) -*/ static __init int init_posix_timers (void ) { posix_timers_cache = kmem_cache_create("posix_timers_cache",
PATCH 20/20 posix-timers: Polish coding style in a few places
In reply to Thomas GleixnerMake it consistent with the TIP tree documentation.
--- kernel/time/posix-timers.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
kernel/time/posix-timers.c +7 -7
@@ -308,10 +308,10 @@ int posix_timer_event(struct k_itimer *t*/ static enum hrtimer_restart posix_timer_fn (struct hrtimer *timer) { +enum hrtimer_restart ret =HRTIMER_NORESTART ;struct k_itimer *timr;unsigned long flags;int si_private =0 ; -enum hrtimer_restart ret =HRTIMER_NORESTART ; timr = container_of(timer, struct k_itimer, it.real.timer);spin_lock_irqsave (&timr->it_lock, flags);
@@ -395,8 +395,8 @@ static struct pid *good_sigevent(sigevenstatic struct k_itimer *alloc_posix_timer (void ) { -struct k_itimer *tmr; - tmr =kmem_cache_zalloc (posix_timers_cache,GFP_KERNEL ); +struct k_itimer *tmr =kmem_cache_zalloc (posix_timers_cache,GFP_KERNEL ); +if (!tmr)return tmr;if (unlikely (!(tmr->sigq =sigqueue_alloc ()))) {
@@ -690,8 +690,8 @@ void common_timer_get(struct k_itimer *tstatic int do_timer_gettime (timer_t timer_id,struct itimerspec64 *setting) { -struct k_itimer *timr;const struct k_clock *kc; +struct k_itimer *timr;unsigned long flags;int ret =0 ;
@@ -762,8 +762,8 @@ SYSCALL_DEFINE2(timer_gettime32, timer_t SYSCALL_DEFINE1(timer_getoverrun, timer_t, timer_id) {struct k_itimer *timr; -int overrun;unsigned long flags; +int overrun; timr =lock_timer (timer_id, &flags);if (!timr)
@@ -936,8 +936,7 @@ SYSCALL_DEFINE4(timer_settime, timer_t, const struct __kernel_itimerspec __user *, new_setting, struct __kernel_itimerspec __user *, old_setting) { - struct itimerspec64 new_spec, old_spec; -struct itimerspec64 *rtn = old_setting ? &old_spec :NULL ; + struct itimerspec64 new_spec, old_spec, *rtn;int error =0 ;if (!new_setting)
@@ -946,6 +945,7 @@ SYSCALL_DEFINE4(timer_settime, timer_t,if (get_itimerspec64 (&new_spec, new_setting))return -EFAULT ; + rtn = old_setting ? &old_spec :NULL ; error =do_timer_settime (timer_id, flags, &new_spec, rtn);if (!error && old_setting) {if (put_itimerspec64 (&old_spec, old_setting))
Re: [patch 20/20] posix-timers: Polish coding style in a few places
Quoted 3 lines · Thomas Gleixner
Make it consistent with the TIP tree documentation.
Signed-off-by Thomas Gleixner <[email protected]>
[tip: timers/core] posix-timers: Polish coding style in a few places
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 1263a2a9d71bac5ffabf9603c36e36cb6edbcdcf Gitweb: https://git.kernel.org/tip/1263a2a9d71bac5ffabf9603c36e36cb6edbcdcf Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:27 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Mon, 05 Jun 2023 17:03:39 +02:00
posix-timers: Polish coding style in a few places
Make it consistent with the TIP tree documentation.
--- kernel/time/posix-timers.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
kernel/time/posix-timers.c +7 -7
@@ -309,10 +309,10 @@ int posix_timer_event(struct k_itimer *timr, int si_private)*/ static enum hrtimer_restart posix_timer_fn (struct hrtimer *timer) { +enum hrtimer_restart ret =HRTIMER_NORESTART ;struct k_itimer *timr;unsigned long flags;int si_private =0 ; -enum hrtimer_restart ret =HRTIMER_NORESTART ; timr = container_of(timer, struct k_itimer, it.real.timer);spin_lock_irqsave (&timr->it_lock, flags);
@@ -400,8 +400,8 @@ static struct pid *good_sigevent(sigevent_t * event)static struct k_itimer *alloc_posix_timer (void ) { -struct k_itimer *tmr; - tmr =kmem_cache_zalloc (posix_timers_cache,GFP_KERNEL ); +struct k_itimer *tmr =kmem_cache_zalloc (posix_timers_cache,GFP_KERNEL ); +if (!tmr)return tmr;if (unlikely (!(tmr->sigq =sigqueue_alloc ()))) {
@@ -695,8 +695,8 @@ void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting)static int do_timer_gettime (timer_t timer_id,struct itimerspec64 *setting) { -struct k_itimer *timr;const struct k_clock *kc; +struct k_itimer *timr;unsigned long flags;int ret =0 ;
@@ -767,8 +767,8 @@ SYSCALL_DEFINE2(timer_gettime32, timer_t, timer_id, SYSCALL_DEFINE1(timer_getoverrun, timer_t, timer_id) {struct k_itimer *timr; -int overrun;unsigned long flags; +int overrun; timr =lock_timer (timer_id, &flags);if (!timr)
@@ -941,8 +941,7 @@ SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, const struct __kernel_itimerspec __user *, new_setting, struct __kernel_itimerspec __user *, old_setting) { - struct itimerspec64 new_spec, old_spec; -struct itimerspec64 *rtn = old_setting ? &old_spec :NULL ; + struct itimerspec64 new_spec, old_spec, *rtn;int error =0 ;if (!new_setting)
@@ -951,6 +950,7 @@ SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags,if (get_itimerspec64 (&new_spec, new_setting))return -EFAULT ; + rtn = old_setting ? &old_spec :NULL ; error =do_timer_settime (timer_id, flags, &new_spec, rtn);if (!error && old_setting) {if (put_itimerspec64 (&old_spec, old_setting))
[tip: timers/core] posix-timers: Polish coding style in a few places
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: 6fbe3a3b4fa1fe5cf05f91193d81d930c6820eda Gitweb: https://git.kernel.org/tip/6fbe3a3b4fa1fe5cf05f91193d81d930c6820eda Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:27 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Tue, 06 Jun 2023 00:12:55 +02:00
posix-timers: Polish coding style in a few places
Make it consistent with the TIP tree documentation.
--- kernel/time/posix-timers.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
kernel/time/posix-timers.c +7 -7
@@ -309,10 +309,10 @@ int posix_timer_event(struct k_itimer *timr, int si_private)*/ static enum hrtimer_restart posix_timer_fn (struct hrtimer *timer) { +enum hrtimer_restart ret =HRTIMER_NORESTART ;struct k_itimer *timr;unsigned long flags;int si_private =0 ; -enum hrtimer_restart ret =HRTIMER_NORESTART ; timr = container_of(timer, struct k_itimer, it.real.timer);spin_lock_irqsave (&timr->it_lock, flags);
@@ -400,8 +400,8 @@ static struct pid *good_sigevent(sigevent_t * event)static struct k_itimer *alloc_posix_timer (void ) { -struct k_itimer *tmr; - tmr =kmem_cache_zalloc (posix_timers_cache,GFP_KERNEL ); +struct k_itimer *tmr =kmem_cache_zalloc (posix_timers_cache,GFP_KERNEL ); +if (!tmr)return tmr;if (unlikely (!(tmr->sigq =sigqueue_alloc ()))) {
@@ -695,8 +695,8 @@ void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting)static int do_timer_gettime (timer_t timer_id,struct itimerspec64 *setting) { -struct k_itimer *timr;const struct k_clock *kc; +struct k_itimer *timr;unsigned long flags;int ret =0 ;
@@ -767,8 +767,8 @@ SYSCALL_DEFINE2(timer_gettime32, timer_t, timer_id, SYSCALL_DEFINE1(timer_getoverrun, timer_t, timer_id) {struct k_itimer *timr; -int overrun;unsigned long flags; +int overrun; timr =lock_timer (timer_id, &flags);if (!timr)
@@ -941,8 +941,7 @@ SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, const struct __kernel_itimerspec __user *, new_setting, struct __kernel_itimerspec __user *, old_setting) { - struct itimerspec64 new_spec, old_spec; -struct itimerspec64 *rtn = old_setting ? &old_spec :NULL ; + struct itimerspec64 new_spec, old_spec, *rtn;int error =0 ;if (!new_setting)
@@ -951,6 +950,7 @@ SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags,if (get_itimerspec64 (&new_spec, new_setting))return -EFAULT ; + rtn = old_setting ? &old_spec :NULL ; error =do_timer_settime (timer_id, flags, &new_spec, rtn);if (!error && old_setting) {if (put_itimerspec64 (&old_spec, old_setting))
[tip: timers/core] posix-timers: Polish coding style in a few places
In reply to Thomas GleixnerThe following commit has been merged into the timers/core branch of tip:
The following commit has been merged into the timers/core branch of tip:
Commit-ID: b96ce4931fcd13d73e32c62c2df3fa8f9f467e33 Gitweb: https://git.kernel.org/tip/b96ce4931fcd13d73e32c62c2df3fa8f9f467e33 Author: Thomas Gleixner <[email protected]> AuthorDate: Tue, 25 Apr 2023 20:49:27 +02:00 Committer: Thomas Gleixner <[email protected]> CommitterDate: Sun, 18 Jun 2023 22:41:53 +02:00
posix-timers: Polish coding style in a few places
Make it consistent with the TIP tree documentation.
--- kernel/time/posix-timers.c | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-)
kernel/time/posix-timers.c +7 -7
@@ -309,10 +309,10 @@ int posix_timer_event(struct k_itimer *timr, int si_private)*/ static enum hrtimer_restart posix_timer_fn (struct hrtimer *timer) { +enum hrtimer_restart ret =HRTIMER_NORESTART ;struct k_itimer *timr;unsigned long flags;int si_private =0 ; -enum hrtimer_restart ret =HRTIMER_NORESTART ; timr = container_of(timer, struct k_itimer, it.real.timer);spin_lock_irqsave (&timr->it_lock, flags);
@@ -400,8 +400,8 @@ static struct pid *good_sigevent(sigevent_t * event)static struct k_itimer *alloc_posix_timer (void ) { -struct k_itimer *tmr; - tmr =kmem_cache_zalloc (posix_timers_cache,GFP_KERNEL ); +struct k_itimer *tmr =kmem_cache_zalloc (posix_timers_cache,GFP_KERNEL ); +if (!tmr)return tmr;if (unlikely (!(tmr->sigq =sigqueue_alloc ()))) {
@@ -695,8 +695,8 @@ void common_timer_get(struct k_itimer *timr, struct itimerspec64 *cur_setting)static int do_timer_gettime (timer_t timer_id,struct itimerspec64 *setting) { -struct k_itimer *timr;const struct k_clock *kc; +struct k_itimer *timr;unsigned long flags;int ret =0 ;
@@ -767,8 +767,8 @@ SYSCALL_DEFINE2(timer_gettime32, timer_t, timer_id, SYSCALL_DEFINE1(timer_getoverrun, timer_t, timer_id) {struct k_itimer *timr; -int overrun;unsigned long flags; +int overrun; timr =lock_timer (timer_id, &flags);if (!timr)
@@ -941,8 +941,7 @@ SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags, const struct __kernel_itimerspec __user *, new_setting, struct __kernel_itimerspec __user *, old_setting) { - struct itimerspec64 new_spec, old_spec; -struct itimerspec64 *rtn = old_setting ? &old_spec :NULL ; + struct itimerspec64 new_spec, old_spec, *rtn;int error =0 ;if (!new_setting)
@@ -951,6 +950,7 @@ SYSCALL_DEFINE4(timer_settime, timer_t, timer_id, int, flags,if (get_itimerspec64 (&new_spec, new_setting))return -EFAULT ; + rtn = old_setting ? &old_spec :NULL ; error =do_timer_settime (timer_id, flags, &new_spec, rtn);if (!error && old_setting) {if (put_itimerspec64 (&old_spec, old_setting))
Frederic Weisbecker
maintainerQuoted 19 lines · Thomas Gleixner
Hi!
A recent syzcaller/KCSAN report about a data race and an actually broken loop termination due to that race made me look deeper into the posix timer code.
Aside of the loop termination issue this unearthed another issue in the
exit()path where timer deletion might livelock on RT enabled kernels.While going through the code with a fine comb, I stumbled over another place which needs READ/WRITE_ONCE() annotations, tons of outdated and/or uncomprehensible comments and a bunch of silly code.
The series has therefore a larger set of cleanups on top of the two fixes.
It is based on
git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.gittimers/core
Quoted 7 lines
and also availble from git:
git://git.kernel.org/pub/scm/linux/kernel/git/tglx/devel.gittimers/posixThanks,
tglx
Thanks for this extremely useful series!