mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-15 00:04:15 +08:00
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
This commit is contained in:
parent
8d44b958a1
commit
ae88967d71
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user