posix-cpu-timers: Assert task sighand is locked while starting cputime counter
authorFrederic Weisbecker <frederic@kernel.org>
Mon, 26 Jul 2021 12:55:08 +0000 (14:55 +0200)
committerThomas Gleixner <tglx@linutronix.de>
Tue, 10 Aug 2021 15:09:58 +0000 (17:09 +0200)
Starting the process wide cputime counter needs to be done in the same
sighand locking sequence than actually arming the related timer otherwise
this races against concurrent timers setting/expiring in the same
threadgroup.

Detecting that the cputime counter is started without holding the sighand
lock is a first step toward debugging such situations.

Suggested-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Signed-off-by: Frederic Weisbecker <frederic@kernel.org>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://lore.kernel.org/r/20210726125513.271824-2-frederic@kernel.org
include/linux/sched/signal.h
kernel/signal.c
kernel/time/posix-cpu-timers.c

index b9126fe..0310a5a 100644 (file)
@@ -714,6 +714,12 @@ static inline void unlock_task_sighand(struct task_struct *task,
        spin_unlock_irqrestore(&task->sighand->siglock, *flags);
 }
 
+#ifdef CONFIG_LOCKDEP
+extern void lockdep_assert_task_sighand_held(struct task_struct *task);
+#else
+static inline void lockdep_assert_task_sighand_held(struct task_struct *task) { }
+#endif
+
 static inline unsigned long task_rlimit(const struct task_struct *task,
                unsigned int limit)
 {
index a3229ad..52b6abe 100644 (file)
@@ -1413,6 +1413,21 @@ struct sighand_struct *__lock_task_sighand(struct task_struct *tsk,
        return sighand;
 }
 
+#ifdef CONFIG_LOCKDEP
+void lockdep_assert_task_sighand_held(struct task_struct *task)
+{
+       struct sighand_struct *sighand;
+
+       rcu_read_lock();
+       sighand = rcu_dereference(task->sighand);
+       if (sighand)
+               lockdep_assert_held(&sighand->siglock);
+       else
+               WARN_ON_ONCE(1);
+       rcu_read_unlock();
+}
+#endif
+
 /*
  * send signal info to all the members of a group
  */
index 517be7f..4693d3c 100644 (file)
@@ -291,6 +291,8 @@ static void thread_group_start_cputime(struct task_struct *tsk, u64 *samples)
        struct thread_group_cputimer *cputimer = &tsk->signal->cputimer;
        struct posix_cputimers *pct = &tsk->signal->posix_cputimers;
 
+       lockdep_assert_task_sighand_held(tsk);
+
        /* Check if cputimer isn't running. This is accessed without locking. */
        if (!READ_ONCE(pct->timers_active)) {
                struct task_cputime sum;