lkml.org 
[lkml]   [2023]   [Apr]   [25]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[patch 05/20] posix-timers: Add comments about timer lookup
    Date
    Document how the timer ID validation in the hash table works.

    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    ---
    kernel/time/posix-timers.c | 39 ++++++++++++++++++++++++++++++++-------
    1 file changed, 32 insertions(+), 7 deletions(-)

    --- a/kernel/time/posix-timers.c
    +++ b/kernel/time/posix-timers.c
    @@ -505,6 +505,12 @@ static int do_timer_create(clockid_t whi
    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;
    @@ -550,6 +556,7 @@ static int do_timer_create(clockid_t whi
    goto out;

    spin_lock_irq(&current->sighand->siglock);
    + /* This makes the timer valid in the hash table */
    new_timer->it_signal = current->signal;
    list_add(&new_timer->list, &current->signal->posix_timers);
    spin_unlock_irq(&current->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(tim
    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;
    \
     
     \ /
      Last update: 2023-04-25 20:49    [W:3.126 / U:0.100 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site