@@ -506,6 +506,12 @@ static int do_timer_create(clockid_t which_clock, struct sigevent *event,
506
506
return - EAGAIN ;
507
507
508
508
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
+ */
509
515
new_timer_id = posix_timer_add (new_timer );
510
516
if (new_timer_id < 0 ) {
511
517
error = new_timer_id ;
@@ -551,6 +557,7 @@ static int do_timer_create(clockid_t which_clock, struct sigevent *event,
551
557
goto out ;
552
558
553
559
spin_lock_irq (& current -> sighand -> siglock );
560
+ /* This makes the timer valid in the hash table */
554
561
new_timer -> it_signal = current -> signal ;
555
562
list_add (& new_timer -> list , & current -> signal -> posix_timers );
556
563
spin_unlock_irq (& current -> sighand -> siglock );
@@ -597,13 +604,6 @@ COMPAT_SYSCALL_DEFINE3(timer_create, clockid_t, which_clock,
597
604
}
598
605
#endif
599
606
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
- */
607
607
static struct k_itimer * __lock_timer (timer_t timer_id , unsigned long * flags )
608
608
{
609
609
struct k_itimer * timr ;
@@ -615,10 +615,35 @@ static struct k_itimer *__lock_timer(timer_t timer_id, unsigned long *flags)
615
615
if ((unsigned long long )timer_id > INT_MAX )
616
616
return NULL ;
617
617
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
+ */
618
639
rcu_read_lock ();
619
640
timr = posix_timer_by_id (timer_id );
620
641
if (timr ) {
621
642
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
+ */
622
647
if (timr -> it_signal == current -> signal ) {
623
648
rcu_read_unlock ();
624
649
return timr ;
0 commit comments