Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

posix-timers: Add a refcount to struct k_itimer

To cure the SIG_IGN handling for posix interval timers, the preallocated
sigqueue needs to be embedded into struct k_itimer to prevent life time
races of all sorts.

To make that work correctly it needs reference counting so that timer
deletion does not free the timer prematuraly when there is a signal queued
or delivered concurrently.

Add a rcuref to the posix timer part.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Reviewed-by: Frederic Weisbecker <frederic@kernel.org>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/all/20241105064213.304756440@linutronix.de


+18 -3
+14
include/linux/posix-timers.h
··· 6 6 #include <linux/list.h> 7 7 #include <linux/mutex.h> 8 8 #include <linux/posix-timers_types.h> 9 + #include <linux/rcuref.h> 9 10 #include <linux/spinlock.h> 10 11 #include <linux/timerqueue.h> 11 12 12 13 struct kernel_siginfo; 13 14 struct task_struct; 15 + struct k_itimer; 14 16 15 17 static inline clockid_t make_process_cpuclock(const unsigned int pid, 16 18 const clockid_t clock) ··· 107 105 108 106 void posixtimer_rearm_itimer(struct task_struct *p); 109 107 bool posixtimer_deliver_signal(struct kernel_siginfo *info); 108 + void posixtimer_free_timer(struct k_itimer *timer); 110 109 111 110 /* Init task static initializer */ 112 111 #define INIT_CPU_TIMERBASE(b) { \ ··· 132 129 u64 cpu_limit) { } 133 130 static inline void posixtimer_rearm_itimer(struct task_struct *p) { } 134 131 static inline bool posixtimer_deliver_signal(struct kernel_siginfo *info) { return false; } 132 + static inline void posixtimer_free_timer(struct k_itimer *timer) { } 135 133 #endif 136 134 137 135 #ifdef CONFIG_POSIX_CPU_TIMERS_TASK_WORK ··· 160 156 * @it_signal: Pointer to the creators signal struct 161 157 * @it_pid: The pid of the process/task targeted by the signal 162 158 * @it_process: The task to wakeup on clock_nanosleep (CPU timers) 159 + * @rcuref: Reference count for life time management 163 160 * @sigq: Pointer to preallocated sigqueue 164 161 * @it: Union representing the various posix timer type 165 162 * internals. ··· 185 180 struct task_struct *it_process; 186 181 }; 187 182 struct sigqueue *sigq; 183 + rcuref_t rcuref; 188 184 union { 189 185 struct { 190 186 struct hrtimer timer; ··· 205 199 u64 *newval, u64 *oldval); 206 200 207 201 int update_rlimit_cpu(struct task_struct *task, unsigned long rlim_new); 202 + 203 + #ifdef CONFIG_POSIX_TIMERS 204 + static inline void posixtimer_putref(struct k_itimer *tmr) 205 + { 206 + if (rcuref_put(&tmr->rcuref)) 207 + posixtimer_free_timer(tmr); 208 + } 209 + #endif /* !CONFIG_POSIX_TIMERS */ 208 210 209 211 #endif
+4 -3
kernel/time/posix-timers.c
··· 417 417 return NULL; 418 418 } 419 419 clear_siginfo(&tmr->sigq->info); 420 + rcuref_init(&tmr->rcuref, 1); 420 421 return tmr; 421 422 } 422 423 423 - static void posix_timer_free(struct k_itimer *tmr) 424 + void posixtimer_free_timer(struct k_itimer *tmr) 424 425 { 425 426 put_pid(tmr->it_pid); 426 427 sigqueue_free(tmr->sigq); ··· 433 432 spin_lock(&hash_lock); 434 433 hlist_del_rcu(&tmr->t_hash); 435 434 spin_unlock(&hash_lock); 436 - posix_timer_free(tmr); 435 + posixtimer_putref(tmr); 437 436 } 438 437 439 438 static int common_timer_create(struct k_itimer *new_timer) ··· 468 467 */ 469 468 new_timer_id = posix_timer_add(new_timer); 470 469 if (new_timer_id < 0) { 471 - posix_timer_free(new_timer); 470 + posixtimer_free_timer(new_timer); 472 471 return new_timer_id; 473 472 } 474 473