]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
rcu-tasks: Make Tasks RCU wait idly for grace-period delays
authorPaul E. McKenney <paulmck@kernel.org>
Fri, 23 Feb 2024 23:16:20 +0000 (15:16 -0800)
committerUladzislau Rezki (Sony) <urezki@gmail.com>
Tue, 9 Apr 2024 13:11:49 +0000 (15:11 +0200)
Currently, all waits for grace periods sleep at TASK_UNINTERRUPTIBLE,
regardless of RCU flavor.  This has worked well, but there have been
cases where a longer-than-average Tasks RCU grace period has triggered
softlockup splats, many of them, before the Tasks RCU CPU stall warning
appears.  These softlockup splats unnecessarily consume console bandwidth
and complicate diagnosis of the underlying problem.  Plus a long but not
pathologically long Tasks RCU grace period might trigger a few softlockup
splats before completing normally, which generates noise for no good
reason.

This commit therefore causes Tasks RCU grace periods to sleep at TASK_IDLE
priority.  If there really is a persistent problem, the eventual Tasks
RCU CPU stall warning will flag it, and without the extra noise.

Reported-by: Breno Leitao <leitao@debian.org>
Signed-off-by: Paul E. McKenney <paulmck@kernel.org>
Signed-off-by: Uladzislau Rezki (Sony) <urezki@gmail.com>
include/linux/rcupdate_wait.h
kernel/rcu/tasks.h
kernel/rcu/update.c

index d07f0848802e58c650371f0faf3288c3cc35f4b1..303ab9bee15520c4710dec99f4d5df7258f531d8 100644 (file)
@@ -19,18 +19,18 @@ struct rcu_synchronize {
 };
 void wakeme_after_rcu(struct rcu_head *head);
 
-void __wait_rcu_gp(bool checktiny, int n, call_rcu_func_t *crcu_array,
+void __wait_rcu_gp(bool checktiny, unsigned int state, int n, call_rcu_func_t *crcu_array,
                   struct rcu_synchronize *rs_array);
 
-#define _wait_rcu_gp(checktiny, ...) \
-do {                                                                   \
-       call_rcu_func_t __crcu_array[] = { __VA_ARGS__ };               \
-       struct rcu_synchronize __rs_array[ARRAY_SIZE(__crcu_array)];    \
-       __wait_rcu_gp(checktiny, ARRAY_SIZE(__crcu_array),              \
-                       __crcu_array, __rs_array);                      \
+#define _wait_rcu_gp(checktiny, state, ...) \
+do {                                                                                           \
+       call_rcu_func_t __crcu_array[] = { __VA_ARGS__ };                                       \
+       struct rcu_synchronize __rs_array[ARRAY_SIZE(__crcu_array)];                            \
+       __wait_rcu_gp(checktiny, state, ARRAY_SIZE(__crcu_array), __crcu_array, __rs_array);    \
 } while (0)
 
-#define wait_rcu_gp(...) _wait_rcu_gp(false, __VA_ARGS__)
+#define wait_rcu_gp(...) _wait_rcu_gp(false, TASK_UNINTERRUPTIBLE, __VA_ARGS__)
+#define wait_rcu_gp_state(state, ...) _wait_rcu_gp(false, state, __VA_ARGS__)
 
 /**
  * synchronize_rcu_mult - Wait concurrently for multiple grace periods
@@ -54,7 +54,7 @@ do {                                                                  \
  * grace period.
  */
 #define synchronize_rcu_mult(...) \
-       _wait_rcu_gp(IS_ENABLED(CONFIG_TINY_RCU), __VA_ARGS__)
+       _wait_rcu_gp(IS_ENABLED(CONFIG_TINY_RCU), TASK_UNINTERRUPTIBLE, __VA_ARGS__)
 
 static inline void cond_resched_rcu(void)
 {
index 147b5945d67a046dd568e6df586881f8c1a0c25f..82e458ea07287e0606d51bbdcf47b807a593bef2 100644 (file)
@@ -74,6 +74,7 @@ struct rcu_tasks_percpu {
  * @holdouts_func: This flavor's holdout-list scan function (optional).
  * @postgp_func: This flavor's post-grace-period function (optional).
  * @call_func: This flavor's call_rcu()-equivalent function.
+ * @wait_state: Task state for synchronous grace-period waits (default TASK_UNINTERRUPTIBLE).
  * @rtpcpu: This flavor's rcu_tasks_percpu structure.
  * @percpu_enqueue_shift: Shift down CPU ID this much when enqueuing callbacks.
  * @percpu_enqueue_lim: Number of per-CPU callback queues in use for enqueuing.
@@ -107,6 +108,7 @@ struct rcu_tasks {
        holdouts_func_t holdouts_func;
        postgp_func_t postgp_func;
        call_rcu_func_t call_func;
+       unsigned int wait_state;
        struct rcu_tasks_percpu __percpu *rtpcpu;
        int percpu_enqueue_shift;
        int percpu_enqueue_lim;
@@ -134,6 +136,7 @@ static struct rcu_tasks rt_name =                                                   \
        .tasks_gp_mutex = __MUTEX_INITIALIZER(rt_name.tasks_gp_mutex),                  \
        .gp_func = gp,                                                                  \
        .call_func = call,                                                              \
+       .wait_state = TASK_UNINTERRUPTIBLE,                                             \
        .rtpcpu = &rt_name ## __percpu,                                                 \
        .lazy_jiffies = DIV_ROUND_UP(HZ, 4),                                            \
        .name = n,                                                                      \
@@ -638,7 +641,7 @@ static void synchronize_rcu_tasks_generic(struct rcu_tasks *rtp)
 
        // If the grace-period kthread is running, use it.
        if (READ_ONCE(rtp->kthread_ptr)) {
-               wait_rcu_gp(rtp->call_func);
+               wait_rcu_gp_state(rtp->wait_state, rtp->call_func);
                return;
        }
        rcu_tasks_one_gp(rtp, true);
@@ -1160,6 +1163,7 @@ static int __init rcu_spawn_tasks_kthread(void)
        rcu_tasks.postscan_func = rcu_tasks_postscan;
        rcu_tasks.holdouts_func = check_all_holdout_tasks;
        rcu_tasks.postgp_func = rcu_tasks_postgp;
+       rcu_tasks.wait_state = TASK_IDLE;
        rcu_spawn_tasks_kthread_generic(&rcu_tasks);
        return 0;
 }
index 46aaaa9fe33907b0eddb70e2b1c5d6a2419c13c8..f8436969e0c89e221b6f07743fe845969d2e6fa4 100644 (file)
@@ -408,7 +408,7 @@ void wakeme_after_rcu(struct rcu_head *head)
 }
 EXPORT_SYMBOL_GPL(wakeme_after_rcu);
 
-void __wait_rcu_gp(bool checktiny, int n, call_rcu_func_t *crcu_array,
+void __wait_rcu_gp(bool checktiny, unsigned int state, int n, call_rcu_func_t *crcu_array,
                   struct rcu_synchronize *rs_array)
 {
        int i;
@@ -440,7 +440,7 @@ void __wait_rcu_gp(bool checktiny, int n, call_rcu_func_t *crcu_array,
                        if (crcu_array[j] == crcu_array[i])
                                break;
                if (j == i) {
-                       wait_for_completion(&rs_array[i].completion);
+                       wait_for_completion_state(&rs_array[i].completion, state);
                        destroy_rcu_head_on_stack(&rs_array[i].head);
                }
        }