lkml.org 
[lkml]   [2019]   [Jul]   [30]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[patch 6/7] posix-timers: Move rcu_head out of it union
    Timer deletion on PREEMPT_RT is prone to priority inversion and live
    locks. The hrtimer code has a synchronization mechanism for this. Posix CPU
    timers will grow one.

    But that mechanism cannot be invoked while holding the k_itimer lock
    because that can deadlock against the running timer callback. So the lock
    must be dropped which allows the timer to be freed.

    The timer free can be prevented by taking RCU readlock before dropping the
    lock, but because the rcu_head is part of the 'it' union a concurrent free
    will overwrite the hrtimer on which the task is trying to synchronize.

    Move the rcu_head out of the union to prevent this.

    [ tglx: Fixed up kernel-doc. Rewrote changelog ]

    Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
    ---
    include/linux/posix-timers.h | 5 +++--
    kernel/time/posix-timers.c | 4 ++--
    2 files changed, 5 insertions(+), 4 deletions(-)

    --- a/include/linux/posix-timers.h
    +++ b/include/linux/posix-timers.h
    @@ -85,7 +85,8 @@ static inline int clockid_to_fd(const cl
    * @it_process: The task to wakeup on clock_nanosleep (CPU timers)
    * @sigq: Pointer to preallocated sigqueue
    * @it: Union representing the various posix timer type
    - * internals. Also used for rcu freeing the timer.
    + * internals.
    + * @rcu: RCU head for freeing the timer.
    */
    struct k_itimer {
    struct list_head list;
    @@ -114,8 +115,8 @@ struct k_itimer {
    struct {
    struct alarm alarmtimer;
    } alarm;
    - struct rcu_head rcu;
    } it;
    + struct rcu_head rcu;
    };

    void run_posix_cpu_timers(struct task_struct *task);
    --- a/kernel/time/posix-timers.c
    +++ b/kernel/time/posix-timers.c
    @@ -442,7 +442,7 @@ static struct k_itimer * alloc_posix_tim

    static void k_itimer_rcu_free(struct rcu_head *head)
    {
    - struct k_itimer *tmr = container_of(head, struct k_itimer, it.rcu);
    + struct k_itimer *tmr = container_of(head, struct k_itimer, rcu);

    kmem_cache_free(posix_timers_cache, tmr);
    }
    @@ -459,7 +459,7 @@ static void release_posix_timer(struct k
    }
    put_pid(tmr->it_pid);
    sigqueue_free(tmr->sigq);
    - call_rcu(&tmr->it.rcu, k_itimer_rcu_free);
    + call_rcu(&tmr->rcu, k_itimer_rcu_free);
    }

    static int common_timer_create(struct k_itimer *new_timer)

    \
     
     \ /
      Last update: 2019-07-31 00:42    [W:4.493 / U:0.024 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site