Skip to content

Commit ae88967

Browse files
committed
posix-timers: Add comments about timer lookup
Document how the timer ID validation in the hash table works. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Frederic Weisbecker <frederic@kernel.org> Link: https://lore.kernel.org/r/20230425183313.091081515@linutronix.de
1 parent 8d44b95 commit ae88967

File tree

1 file changed

+32
-7
lines changed

1 file changed

+32
-7
lines changed

kernel/time/posix-timers.c

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,12 @@ static int do_timer_create(clockid_t which_clock, struct sigevent *event,
506506
return -EAGAIN;
507507

508508
spin_lock_init(&new_timer->it_lock);
509+
510+
/*
511+
* Add the timer to the hash table. The timer is not yet valid
512+
* because new_timer::it_signal is still NULL. The timer id is also
513+
* not yet visible to user space.
514+
*/
509515
new_timer_id = posix_timer_add(new_timer);
510516
if (new_timer_id < 0) {
511517
error = new_timer_id;
@@ -551,6 +557,7 @@ static int do_timer_create(clockid_t which_clock, struct sigevent *event,
551557
goto out;
552558

553559
spin_lock_irq(&current->sighand->siglock);
560+
/* This makes the timer valid in the hash table */
554561
new_timer->it_signal = current->signal;
555562
list_add(&new_timer->list, &current->signal->posix_timers);
556563
spin_unlock_irq(&current->sighand->siglock);
@@ -597,13 +604,6 @@ COMPAT_SYSCALL_DEFINE3(timer_create, clockid_t, which_clock,
597604
}
598605
#endif
599606

600-
/*
601-
* Locking issues: We need to protect the result of the id look up until
602-
* we get the timer locked down so it is not deleted under us. The
603-
* removal is done under the idr spinlock so we use that here to bridge
604-
* the find to the timer lock. To avoid a dead lock, the timer id MUST
605-
* be release with out holding the timer lock.
606-
*/
607607
static struct k_itimer *__lock_timer(timer_t timer_id, unsigned long *flags)
608608
{
609609
struct k_itimer *timr;
@@ -615,10 +615,35 @@ static struct k_itimer *__lock_timer(timer_t timer_id, unsigned long *flags)
615615
if ((unsigned long long)timer_id > INT_MAX)
616616
return NULL;
617617

618+
/*
619+
* The hash lookup and the timers are RCU protected.
620+
*
621+
* Timers are added to the hash in invalid state where
622+
* timr::it_signal == NULL. timer::it_signal is only set after the
623+
* rest of the initialization succeeded.
624+
*
625+
* Timer destruction happens in steps:
626+
* 1) Set timr::it_signal to NULL with timr::it_lock held
627+
* 2) Release timr::it_lock
628+
* 3) Remove from the hash under hash_lock
629+
* 4) Call RCU for removal after the grace period
630+
*
631+
* Holding rcu_read_lock() accross the lookup ensures that
632+
* the timer cannot be freed.
633+
*
634+
* The lookup validates locklessly that timr::it_signal ==
635+
* current::it_signal and timr::it_id == @timer_id. timr::it_id
636+
* can't change, but timr::it_signal becomes NULL during
637+
* destruction.
638+
*/
618639
rcu_read_lock();
619640
timr = posix_timer_by_id(timer_id);
620641
if (timr) {
621642
spin_lock_irqsave(&timr->it_lock, *flags);
643+
/*
644+
* Validate under timr::it_lock that timr::it_signal is
645+
* still valid. Pairs with #1 above.
646+
*/
622647
if (timr->it_signal == current->signal) {
623648
rcu_read_unlock();
624649
return timr;

0 commit comments

Comments
 (0)