Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

rcu-tasks: Make Tasks RCU wait idly for grace-period delays

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>

authored by

Paul E. McKenney and committed by
Uladzislau Rezki (Sony)
c342b42f 39cd87c4

+16 -12
+9 -9
include/linux/rcupdate_wait.h
··· 19 19 }; 20 20 void wakeme_after_rcu(struct rcu_head *head); 21 21 22 - void __wait_rcu_gp(bool checktiny, int n, call_rcu_func_t *crcu_array, 22 + void __wait_rcu_gp(bool checktiny, unsigned int state, int n, call_rcu_func_t *crcu_array, 23 23 struct rcu_synchronize *rs_array); 24 24 25 - #define _wait_rcu_gp(checktiny, ...) \ 26 - do { \ 27 - call_rcu_func_t __crcu_array[] = { __VA_ARGS__ }; \ 28 - struct rcu_synchronize __rs_array[ARRAY_SIZE(__crcu_array)]; \ 29 - __wait_rcu_gp(checktiny, ARRAY_SIZE(__crcu_array), \ 30 - __crcu_array, __rs_array); \ 25 + #define _wait_rcu_gp(checktiny, state, ...) \ 26 + do { \ 27 + call_rcu_func_t __crcu_array[] = { __VA_ARGS__ }; \ 28 + struct rcu_synchronize __rs_array[ARRAY_SIZE(__crcu_array)]; \ 29 + __wait_rcu_gp(checktiny, state, ARRAY_SIZE(__crcu_array), __crcu_array, __rs_array); \ 31 30 } while (0) 32 31 33 - #define wait_rcu_gp(...) _wait_rcu_gp(false, __VA_ARGS__) 32 + #define wait_rcu_gp(...) _wait_rcu_gp(false, TASK_UNINTERRUPTIBLE, __VA_ARGS__) 33 + #define wait_rcu_gp_state(state, ...) _wait_rcu_gp(false, state, __VA_ARGS__) 34 34 35 35 /** 36 36 * synchronize_rcu_mult - Wait concurrently for multiple grace periods ··· 54 54 * grace period. 55 55 */ 56 56 #define synchronize_rcu_mult(...) \ 57 - _wait_rcu_gp(IS_ENABLED(CONFIG_TINY_RCU), __VA_ARGS__) 57 + _wait_rcu_gp(IS_ENABLED(CONFIG_TINY_RCU), TASK_UNINTERRUPTIBLE, __VA_ARGS__) 58 58 59 59 static inline void cond_resched_rcu(void) 60 60 {
+5 -1
kernel/rcu/tasks.h
··· 74 74 * @holdouts_func: This flavor's holdout-list scan function (optional). 75 75 * @postgp_func: This flavor's post-grace-period function (optional). 76 76 * @call_func: This flavor's call_rcu()-equivalent function. 77 + * @wait_state: Task state for synchronous grace-period waits (default TASK_UNINTERRUPTIBLE). 77 78 * @rtpcpu: This flavor's rcu_tasks_percpu structure. 78 79 * @percpu_enqueue_shift: Shift down CPU ID this much when enqueuing callbacks. 79 80 * @percpu_enqueue_lim: Number of per-CPU callback queues in use for enqueuing. ··· 108 107 holdouts_func_t holdouts_func; 109 108 postgp_func_t postgp_func; 110 109 call_rcu_func_t call_func; 110 + unsigned int wait_state; 111 111 struct rcu_tasks_percpu __percpu *rtpcpu; 112 112 int percpu_enqueue_shift; 113 113 int percpu_enqueue_lim; ··· 136 134 .tasks_gp_mutex = __MUTEX_INITIALIZER(rt_name.tasks_gp_mutex), \ 137 135 .gp_func = gp, \ 138 136 .call_func = call, \ 137 + .wait_state = TASK_UNINTERRUPTIBLE, \ 139 138 .rtpcpu = &rt_name ## __percpu, \ 140 139 .lazy_jiffies = DIV_ROUND_UP(HZ, 4), \ 141 140 .name = n, \ ··· 641 638 642 639 // If the grace-period kthread is running, use it. 643 640 if (READ_ONCE(rtp->kthread_ptr)) { 644 - wait_rcu_gp(rtp->call_func); 641 + wait_rcu_gp_state(rtp->wait_state, rtp->call_func); 645 642 return; 646 643 } 647 644 rcu_tasks_one_gp(rtp, true); ··· 1163 1160 rcu_tasks.postscan_func = rcu_tasks_postscan; 1164 1161 rcu_tasks.holdouts_func = check_all_holdout_tasks; 1165 1162 rcu_tasks.postgp_func = rcu_tasks_postgp; 1163 + rcu_tasks.wait_state = TASK_IDLE; 1166 1164 rcu_spawn_tasks_kthread_generic(&rcu_tasks); 1167 1165 return 0; 1168 1166 }
+2 -2
kernel/rcu/update.c
··· 408 408 } 409 409 EXPORT_SYMBOL_GPL(wakeme_after_rcu); 410 410 411 - void __wait_rcu_gp(bool checktiny, int n, call_rcu_func_t *crcu_array, 411 + void __wait_rcu_gp(bool checktiny, unsigned int state, int n, call_rcu_func_t *crcu_array, 412 412 struct rcu_synchronize *rs_array) 413 413 { 414 414 int i; ··· 440 440 if (crcu_array[j] == crcu_array[i]) 441 441 break; 442 442 if (j == i) { 443 - wait_for_completion(&rs_array[i].completion); 443 + wait_for_completion_state(&rs_array[i].completion, state); 444 444 destroy_rcu_head_on_stack(&rs_array[i].head); 445 445 } 446 446 }