1eacd6f04SPaul E. McKenney /* SPDX-License-Identifier: GPL-2.0+ */ 2eacd6f04SPaul E. McKenney /* 3eacd6f04SPaul E. McKenney * Task-based RCU implementations. 4eacd6f04SPaul E. McKenney * 5eacd6f04SPaul E. McKenney * Copyright (C) 2020 Paul E. McKenney 6eacd6f04SPaul E. McKenney */ 7eacd6f04SPaul E. McKenney 88fd8ca38SPaul E. McKenney #ifdef CONFIG_TASKS_RCU_GENERIC 95873b8a9SPaul E. McKenney 105873b8a9SPaul E. McKenney //////////////////////////////////////////////////////////////////////// 115873b8a9SPaul E. McKenney // 125873b8a9SPaul E. McKenney // Generic data structures. 135873b8a9SPaul E. McKenney 145873b8a9SPaul E. McKenney struct rcu_tasks; 155873b8a9SPaul E. McKenney typedef void (*rcu_tasks_gp_func_t)(struct rcu_tasks *rtp); 16e4fe5dd6SPaul E. McKenney typedef void (*pregp_func_t)(void); 17e4fe5dd6SPaul E. McKenney typedef void (*pertask_func_t)(struct task_struct *t, struct list_head *hop); 189796e1aeSPaul E. McKenney typedef void (*postscan_func_t)(struct list_head *hop); 19e4fe5dd6SPaul E. McKenney typedef void (*holdouts_func_t)(struct list_head *hop, bool ndrpt, bool *frptp); 20af051ca4SPaul E. McKenney typedef void (*postgp_func_t)(struct rcu_tasks *rtp); 21eacd6f04SPaul E. McKenney 2207e10515SPaul E. McKenney /** 2385b86994SLukas Bulwahn * struct rcu_tasks - Definition for a Tasks-RCU-like mechanism. 2407e10515SPaul E. McKenney * @cbs_head: Head of callback list. 2507e10515SPaul E. McKenney * @cbs_tail: Tail pointer for callback list. 26a616aec9SIngo Molnar * @cbs_wq: Wait queue allowing new callback to get kthread's attention. 2707e10515SPaul E. McKenney * @cbs_lock: Lock protecting callback list. 2807e10515SPaul E. McKenney * @kthread_ptr: This flavor's grace-period/callback-invocation kthread. 295873b8a9SPaul E. McKenney * @gp_func: This flavor's grace-period-wait function. 30af051ca4SPaul E. McKenney * @gp_state: Grace period's most recent state transition (debugging). 314fe192dfSPaul E. McKenney * @gp_sleep: Per-grace-period sleep to prevent CPU-bound looping. 322393a613SPaul E. McKenney * @init_fract: Initial backoff sleep interval. 33af051ca4SPaul E. McKenney * @gp_jiffies: Time of last @gp_state transition. 34af051ca4SPaul E. McKenney * @gp_start: Most recent grace-period start in jiffies. 35238dbce3SPaul E. McKenney * @n_gps: Number of grace periods completed since boot. 36238dbce3SPaul E. McKenney * @n_ipis: Number of IPIs sent to encourage grace periods to end. 377e0669c3SPaul E. McKenney * @n_ipis_fails: Number of IPI-send failures. 38e4fe5dd6SPaul E. McKenney * @pregp_func: This flavor's pre-grace-period function (optional). 39e4fe5dd6SPaul E. McKenney * @pertask_func: This flavor's per-task scan function (optional). 40e4fe5dd6SPaul E. McKenney * @postscan_func: This flavor's post-task scan function (optional). 4185b86994SLukas Bulwahn * @holdouts_func: This flavor's holdout-list scan function (optional). 42e4fe5dd6SPaul E. McKenney * @postgp_func: This flavor's post-grace-period function (optional). 435873b8a9SPaul E. McKenney * @call_func: This flavor's call_rcu()-equivalent function. 44c97d12a6SPaul E. McKenney * @name: This flavor's textual name. 45c97d12a6SPaul E. McKenney * @kname: This flavor's kthread name. 4607e10515SPaul E. McKenney */ 4707e10515SPaul E. McKenney struct rcu_tasks { 4807e10515SPaul E. McKenney struct rcu_head *cbs_head; 4907e10515SPaul E. McKenney struct rcu_head **cbs_tail; 5007e10515SPaul E. McKenney struct wait_queue_head cbs_wq; 5107e10515SPaul E. McKenney raw_spinlock_t cbs_lock; 52af051ca4SPaul E. McKenney int gp_state; 534fe192dfSPaul E. McKenney int gp_sleep; 542393a613SPaul E. McKenney int init_fract; 55af051ca4SPaul E. McKenney unsigned long gp_jiffies; 5688092d0cSPaul E. McKenney unsigned long gp_start; 57238dbce3SPaul E. McKenney unsigned long n_gps; 58238dbce3SPaul E. McKenney unsigned long n_ipis; 597e0669c3SPaul E. McKenney unsigned long n_ipis_fails; 6007e10515SPaul E. McKenney struct task_struct *kthread_ptr; 615873b8a9SPaul E. McKenney rcu_tasks_gp_func_t gp_func; 62e4fe5dd6SPaul E. McKenney pregp_func_t pregp_func; 63e4fe5dd6SPaul E. McKenney pertask_func_t pertask_func; 64e4fe5dd6SPaul E. McKenney postscan_func_t postscan_func; 65e4fe5dd6SPaul E. McKenney holdouts_func_t holdouts_func; 66e4fe5dd6SPaul E. McKenney postgp_func_t postgp_func; 675873b8a9SPaul E. McKenney call_rcu_func_t call_func; 68c97d12a6SPaul E. McKenney char *name; 69c97d12a6SPaul E. McKenney char *kname; 7007e10515SPaul E. McKenney }; 7107e10515SPaul E. McKenney 72c97d12a6SPaul E. McKenney #define DEFINE_RCU_TASKS(rt_name, gp, call, n) \ 73c97d12a6SPaul E. McKenney static struct rcu_tasks rt_name = \ 7407e10515SPaul E. McKenney { \ 75c97d12a6SPaul E. McKenney .cbs_tail = &rt_name.cbs_head, \ 76c97d12a6SPaul E. McKenney .cbs_wq = __WAIT_QUEUE_HEAD_INITIALIZER(rt_name.cbs_wq), \ 77c97d12a6SPaul E. McKenney .cbs_lock = __RAW_SPIN_LOCK_UNLOCKED(rt_name.cbs_lock), \ 785873b8a9SPaul E. McKenney .gp_func = gp, \ 795873b8a9SPaul E. McKenney .call_func = call, \ 80c97d12a6SPaul E. McKenney .name = n, \ 81c97d12a6SPaul E. McKenney .kname = #rt_name, \ 8207e10515SPaul E. McKenney } 8307e10515SPaul E. McKenney 84eacd6f04SPaul E. McKenney /* Track exiting tasks in order to allow them to be waited for. */ 85eacd6f04SPaul E. McKenney DEFINE_STATIC_SRCU(tasks_rcu_exit_srcu); 86eacd6f04SPaul E. McKenney 87b0afa0f0SPaul E. McKenney /* Avoid IPIing CPUs early in the grace period. */ 88574de876SPaul E. McKenney #define RCU_TASK_IPI_DELAY (IS_ENABLED(CONFIG_TASKS_TRACE_RCU_READ_MB) ? HZ / 2 : 0) 89b0afa0f0SPaul E. McKenney static int rcu_task_ipi_delay __read_mostly = RCU_TASK_IPI_DELAY; 90b0afa0f0SPaul E. McKenney module_param(rcu_task_ipi_delay, int, 0644); 91b0afa0f0SPaul E. McKenney 92eacd6f04SPaul E. McKenney /* Control stall timeouts. Disable with <= 0, otherwise jiffies till stall. */ 93eacd6f04SPaul E. McKenney #define RCU_TASK_STALL_TIMEOUT (HZ * 60 * 10) 94eacd6f04SPaul E. McKenney static int rcu_task_stall_timeout __read_mostly = RCU_TASK_STALL_TIMEOUT; 95eacd6f04SPaul E. McKenney module_param(rcu_task_stall_timeout, int, 0644); 96eacd6f04SPaul E. McKenney 97af051ca4SPaul E. McKenney /* RCU tasks grace-period state for debugging. */ 98af051ca4SPaul E. McKenney #define RTGS_INIT 0 99af051ca4SPaul E. McKenney #define RTGS_WAIT_WAIT_CBS 1 100af051ca4SPaul E. McKenney #define RTGS_WAIT_GP 2 101af051ca4SPaul E. McKenney #define RTGS_PRE_WAIT_GP 3 102af051ca4SPaul E. McKenney #define RTGS_SCAN_TASKLIST 4 103af051ca4SPaul E. McKenney #define RTGS_POST_SCAN_TASKLIST 5 104af051ca4SPaul E. McKenney #define RTGS_WAIT_SCAN_HOLDOUTS 6 105af051ca4SPaul E. McKenney #define RTGS_SCAN_HOLDOUTS 7 106af051ca4SPaul E. McKenney #define RTGS_POST_GP 8 107af051ca4SPaul E. McKenney #define RTGS_WAIT_READERS 9 108af051ca4SPaul E. McKenney #define RTGS_INVOKE_CBS 10 109af051ca4SPaul E. McKenney #define RTGS_WAIT_CBS 11 1108344496eSPaul E. McKenney #ifndef CONFIG_TINY_RCU 111af051ca4SPaul E. McKenney static const char * const rcu_tasks_gp_state_names[] = { 112af051ca4SPaul E. McKenney "RTGS_INIT", 113af051ca4SPaul E. McKenney "RTGS_WAIT_WAIT_CBS", 114af051ca4SPaul E. McKenney "RTGS_WAIT_GP", 115af051ca4SPaul E. McKenney "RTGS_PRE_WAIT_GP", 116af051ca4SPaul E. McKenney "RTGS_SCAN_TASKLIST", 117af051ca4SPaul E. McKenney "RTGS_POST_SCAN_TASKLIST", 118af051ca4SPaul E. McKenney "RTGS_WAIT_SCAN_HOLDOUTS", 119af051ca4SPaul E. McKenney "RTGS_SCAN_HOLDOUTS", 120af051ca4SPaul E. McKenney "RTGS_POST_GP", 121af051ca4SPaul E. McKenney "RTGS_WAIT_READERS", 122af051ca4SPaul E. McKenney "RTGS_INVOKE_CBS", 123af051ca4SPaul E. McKenney "RTGS_WAIT_CBS", 124af051ca4SPaul E. McKenney }; 1258344496eSPaul E. McKenney #endif /* #ifndef CONFIG_TINY_RCU */ 126af051ca4SPaul E. McKenney 1275873b8a9SPaul E. McKenney //////////////////////////////////////////////////////////////////////// 1285873b8a9SPaul E. McKenney // 1295873b8a9SPaul E. McKenney // Generic code. 1305873b8a9SPaul E. McKenney 131af051ca4SPaul E. McKenney /* Record grace-period phase and time. */ 132af051ca4SPaul E. McKenney static void set_tasks_gp_state(struct rcu_tasks *rtp, int newstate) 133af051ca4SPaul E. McKenney { 134af051ca4SPaul E. McKenney rtp->gp_state = newstate; 135af051ca4SPaul E. McKenney rtp->gp_jiffies = jiffies; 136af051ca4SPaul E. McKenney } 137af051ca4SPaul E. McKenney 1388344496eSPaul E. McKenney #ifndef CONFIG_TINY_RCU 139af051ca4SPaul E. McKenney /* Return state name. */ 140af051ca4SPaul E. McKenney static const char *tasks_gp_state_getname(struct rcu_tasks *rtp) 141af051ca4SPaul E. McKenney { 142af051ca4SPaul E. McKenney int i = data_race(rtp->gp_state); // Let KCSAN detect update races 143af051ca4SPaul E. McKenney int j = READ_ONCE(i); // Prevent the compiler from reading twice 144af051ca4SPaul E. McKenney 145af051ca4SPaul E. McKenney if (j >= ARRAY_SIZE(rcu_tasks_gp_state_names)) 146af051ca4SPaul E. McKenney return "???"; 147af051ca4SPaul E. McKenney return rcu_tasks_gp_state_names[j]; 148af051ca4SPaul E. McKenney } 1498344496eSPaul E. McKenney #endif /* #ifndef CONFIG_TINY_RCU */ 150af051ca4SPaul E. McKenney 1515873b8a9SPaul E. McKenney // Enqueue a callback for the specified flavor of Tasks RCU. 1525873b8a9SPaul E. McKenney static void call_rcu_tasks_generic(struct rcu_head *rhp, rcu_callback_t func, 1535873b8a9SPaul E. McKenney struct rcu_tasks *rtp) 154eacd6f04SPaul E. McKenney { 155eacd6f04SPaul E. McKenney unsigned long flags; 156eacd6f04SPaul E. McKenney bool needwake; 157eacd6f04SPaul E. McKenney 158eacd6f04SPaul E. McKenney rhp->next = NULL; 159eacd6f04SPaul E. McKenney rhp->func = func; 16007e10515SPaul E. McKenney raw_spin_lock_irqsave(&rtp->cbs_lock, flags); 16107e10515SPaul E. McKenney needwake = !rtp->cbs_head; 16207e10515SPaul E. McKenney WRITE_ONCE(*rtp->cbs_tail, rhp); 16307e10515SPaul E. McKenney rtp->cbs_tail = &rhp->next; 16407e10515SPaul E. McKenney raw_spin_unlock_irqrestore(&rtp->cbs_lock, flags); 165eacd6f04SPaul E. McKenney /* We can't create the thread unless interrupts are enabled. */ 16607e10515SPaul E. McKenney if (needwake && READ_ONCE(rtp->kthread_ptr)) 16707e10515SPaul E. McKenney wake_up(&rtp->cbs_wq); 168eacd6f04SPaul E. McKenney } 169eacd6f04SPaul E. McKenney 1705873b8a9SPaul E. McKenney // Wait for a grace period for the specified flavor of Tasks RCU. 1715873b8a9SPaul E. McKenney static void synchronize_rcu_tasks_generic(struct rcu_tasks *rtp) 172eacd6f04SPaul E. McKenney { 173eacd6f04SPaul E. McKenney /* Complain if the scheduler has not started. */ 174eacd6f04SPaul E. McKenney RCU_LOCKDEP_WARN(rcu_scheduler_active == RCU_SCHEDULER_INACTIVE, 175eacd6f04SPaul E. McKenney "synchronize_rcu_tasks called too soon"); 176eacd6f04SPaul E. McKenney 177eacd6f04SPaul E. McKenney /* Wait for the grace period. */ 1785873b8a9SPaul E. McKenney wait_rcu_gp(rtp->call_func); 179eacd6f04SPaul E. McKenney } 180eacd6f04SPaul E. McKenney 1815873b8a9SPaul E. McKenney /* RCU-tasks kthread that detects grace periods and invokes callbacks. */ 1825873b8a9SPaul E. McKenney static int __noreturn rcu_tasks_kthread(void *arg) 183eacd6f04SPaul E. McKenney { 1845873b8a9SPaul E. McKenney unsigned long flags; 1855873b8a9SPaul E. McKenney struct rcu_head *list; 1865873b8a9SPaul E. McKenney struct rcu_head *next; 1875873b8a9SPaul E. McKenney struct rcu_tasks *rtp = arg; 1885873b8a9SPaul E. McKenney 1895873b8a9SPaul E. McKenney /* Run on housekeeping CPUs by default. Sysadm can move if desired. */ 1905873b8a9SPaul E. McKenney housekeeping_affine(current, HK_FLAG_RCU); 1915873b8a9SPaul E. McKenney WRITE_ONCE(rtp->kthread_ptr, current); // Let GPs start! 1925873b8a9SPaul E. McKenney 1935873b8a9SPaul E. McKenney /* 1945873b8a9SPaul E. McKenney * Each pass through the following loop makes one check for 1955873b8a9SPaul E. McKenney * newly arrived callbacks, and, if there are some, waits for 1965873b8a9SPaul E. McKenney * one RCU-tasks grace period and then invokes the callbacks. 1975873b8a9SPaul E. McKenney * This loop is terminated by the system going down. ;-) 1985873b8a9SPaul E. McKenney */ 1995873b8a9SPaul E. McKenney for (;;) { 2005873b8a9SPaul E. McKenney 2015873b8a9SPaul E. McKenney /* Pick up any new callbacks. */ 2025873b8a9SPaul E. McKenney raw_spin_lock_irqsave(&rtp->cbs_lock, flags); 20343766c3eSPaul E. McKenney smp_mb__after_spinlock(); // Order updates vs. GP. 2045873b8a9SPaul E. McKenney list = rtp->cbs_head; 2055873b8a9SPaul E. McKenney rtp->cbs_head = NULL; 2065873b8a9SPaul E. McKenney rtp->cbs_tail = &rtp->cbs_head; 2075873b8a9SPaul E. McKenney raw_spin_unlock_irqrestore(&rtp->cbs_lock, flags); 2085873b8a9SPaul E. McKenney 2095873b8a9SPaul E. McKenney /* If there were none, wait a bit and start over. */ 2105873b8a9SPaul E. McKenney if (!list) { 2115873b8a9SPaul E. McKenney wait_event_interruptible(rtp->cbs_wq, 2125873b8a9SPaul E. McKenney READ_ONCE(rtp->cbs_head)); 2135873b8a9SPaul E. McKenney if (!rtp->cbs_head) { 2145873b8a9SPaul E. McKenney WARN_ON(signal_pending(current)); 215af051ca4SPaul E. McKenney set_tasks_gp_state(rtp, RTGS_WAIT_WAIT_CBS); 216ea6eed9fSPaul E. McKenney schedule_timeout_idle(HZ/10); 217eacd6f04SPaul E. McKenney } 2185873b8a9SPaul E. McKenney continue; 2195873b8a9SPaul E. McKenney } 2205873b8a9SPaul E. McKenney 2215873b8a9SPaul E. McKenney // Wait for one grace period. 222af051ca4SPaul E. McKenney set_tasks_gp_state(rtp, RTGS_WAIT_GP); 22388092d0cSPaul E. McKenney rtp->gp_start = jiffies; 2245873b8a9SPaul E. McKenney rtp->gp_func(rtp); 225238dbce3SPaul E. McKenney rtp->n_gps++; 2265873b8a9SPaul E. McKenney 2275873b8a9SPaul E. McKenney /* Invoke the callbacks. */ 228af051ca4SPaul E. McKenney set_tasks_gp_state(rtp, RTGS_INVOKE_CBS); 2295873b8a9SPaul E. McKenney while (list) { 2305873b8a9SPaul E. McKenney next = list->next; 2315873b8a9SPaul E. McKenney local_bh_disable(); 2325873b8a9SPaul E. McKenney list->func(list); 2335873b8a9SPaul E. McKenney local_bh_enable(); 2345873b8a9SPaul E. McKenney list = next; 2355873b8a9SPaul E. McKenney cond_resched(); 2365873b8a9SPaul E. McKenney } 2375873b8a9SPaul E. McKenney /* Paranoid sleep to keep this from entering a tight loop */ 2384fe192dfSPaul E. McKenney schedule_timeout_idle(rtp->gp_sleep); 239af051ca4SPaul E. McKenney 240af051ca4SPaul E. McKenney set_tasks_gp_state(rtp, RTGS_WAIT_CBS); 2415873b8a9SPaul E. McKenney } 2425873b8a9SPaul E. McKenney } 2435873b8a9SPaul E. McKenney 2441b04fa99SUladzislau Rezki (Sony) /* Spawn RCU-tasks grace-period kthread. */ 2455873b8a9SPaul E. McKenney static void __init rcu_spawn_tasks_kthread_generic(struct rcu_tasks *rtp) 2465873b8a9SPaul E. McKenney { 2475873b8a9SPaul E. McKenney struct task_struct *t; 2485873b8a9SPaul E. McKenney 249c97d12a6SPaul E. McKenney t = kthread_run(rcu_tasks_kthread, rtp, "%s_kthread", rtp->kname); 250c97d12a6SPaul E. McKenney if (WARN_ONCE(IS_ERR(t), "%s: Could not start %s grace-period kthread, OOM is now expected behavior\n", __func__, rtp->name)) 2515873b8a9SPaul E. McKenney return; 2525873b8a9SPaul E. McKenney smp_mb(); /* Ensure others see full kthread. */ 2535873b8a9SPaul E. McKenney } 2545873b8a9SPaul E. McKenney 2555873b8a9SPaul E. McKenney #ifndef CONFIG_TINY_RCU 2565873b8a9SPaul E. McKenney 2575873b8a9SPaul E. McKenney /* 2585873b8a9SPaul E. McKenney * Print any non-default Tasks RCU settings. 2595873b8a9SPaul E. McKenney */ 2605873b8a9SPaul E. McKenney static void __init rcu_tasks_bootup_oddness(void) 2615873b8a9SPaul E. McKenney { 262d5f177d3SPaul E. McKenney #if defined(CONFIG_TASKS_RCU) || defined(CONFIG_TASKS_TRACE_RCU) 2635873b8a9SPaul E. McKenney if (rcu_task_stall_timeout != RCU_TASK_STALL_TIMEOUT) 2645873b8a9SPaul E. McKenney pr_info("\tTasks-RCU CPU stall warnings timeout set to %d (rcu_task_stall_timeout).\n", rcu_task_stall_timeout); 265d5f177d3SPaul E. McKenney #endif /* #ifdef CONFIG_TASKS_RCU */ 266d5f177d3SPaul E. McKenney #ifdef CONFIG_TASKS_RCU 267d5f177d3SPaul E. McKenney pr_info("\tTrampoline variant of Tasks RCU enabled.\n"); 2685873b8a9SPaul E. McKenney #endif /* #ifdef CONFIG_TASKS_RCU */ 269c84aad76SPaul E. McKenney #ifdef CONFIG_TASKS_RUDE_RCU 270c84aad76SPaul E. McKenney pr_info("\tRude variant of Tasks RCU enabled.\n"); 271c84aad76SPaul E. McKenney #endif /* #ifdef CONFIG_TASKS_RUDE_RCU */ 272d5f177d3SPaul E. McKenney #ifdef CONFIG_TASKS_TRACE_RCU 273d5f177d3SPaul E. McKenney pr_info("\tTracing variant of Tasks RCU enabled.\n"); 274d5f177d3SPaul E. McKenney #endif /* #ifdef CONFIG_TASKS_TRACE_RCU */ 2755873b8a9SPaul E. McKenney } 2765873b8a9SPaul E. McKenney 2775873b8a9SPaul E. McKenney #endif /* #ifndef CONFIG_TINY_RCU */ 2785873b8a9SPaul E. McKenney 2798344496eSPaul E. McKenney #ifndef CONFIG_TINY_RCU 280e21408ceSPaul E. McKenney /* Dump out rcutorture-relevant state common to all RCU-tasks flavors. */ 281e21408ceSPaul E. McKenney static void show_rcu_tasks_generic_gp_kthread(struct rcu_tasks *rtp, char *s) 282e21408ceSPaul E. McKenney { 2837e0669c3SPaul E. McKenney pr_info("%s: %s(%d) since %lu g:%lu i:%lu/%lu %c%c %s\n", 284e21408ceSPaul E. McKenney rtp->kname, 2857e0669c3SPaul E. McKenney tasks_gp_state_getname(rtp), data_race(rtp->gp_state), 286af051ca4SPaul E. McKenney jiffies - data_race(rtp->gp_jiffies), 2877e0669c3SPaul E. McKenney data_race(rtp->n_gps), 2887e0669c3SPaul E. McKenney data_race(rtp->n_ipis_fails), data_race(rtp->n_ipis), 289e21408ceSPaul E. McKenney ".k"[!!data_race(rtp->kthread_ptr)], 290e21408ceSPaul E. McKenney ".C"[!!data_race(rtp->cbs_head)], 291e21408ceSPaul E. McKenney s); 292e21408ceSPaul E. McKenney } 29327c0f144SPaul E. McKenney #endif // #ifndef CONFIG_TINY_RCU 294e21408ceSPaul E. McKenney 29525246fc8SPaul E. McKenney static void exit_tasks_rcu_finish_trace(struct task_struct *t); 29625246fc8SPaul E. McKenney 29725246fc8SPaul E. McKenney #if defined(CONFIG_TASKS_RCU) || defined(CONFIG_TASKS_TRACE_RCU) 2985873b8a9SPaul E. McKenney 2995873b8a9SPaul E. McKenney //////////////////////////////////////////////////////////////////////// 3005873b8a9SPaul E. McKenney // 301d01aa263SPaul E. McKenney // Shared code between task-list-scanning variants of Tasks RCU. 302d01aa263SPaul E. McKenney 303d01aa263SPaul E. McKenney /* Wait for one RCU-tasks grace period. */ 304d01aa263SPaul E. McKenney static void rcu_tasks_wait_gp(struct rcu_tasks *rtp) 305d01aa263SPaul E. McKenney { 306d01aa263SPaul E. McKenney struct task_struct *g, *t; 307d01aa263SPaul E. McKenney unsigned long lastreport; 308d01aa263SPaul E. McKenney LIST_HEAD(holdouts); 309d01aa263SPaul E. McKenney int fract; 310d01aa263SPaul E. McKenney 311af051ca4SPaul E. McKenney set_tasks_gp_state(rtp, RTGS_PRE_WAIT_GP); 312d01aa263SPaul E. McKenney rtp->pregp_func(); 313d01aa263SPaul E. McKenney 314d01aa263SPaul E. McKenney /* 315d01aa263SPaul E. McKenney * There were callbacks, so we need to wait for an RCU-tasks 316d01aa263SPaul E. McKenney * grace period. Start off by scanning the task list for tasks 317d01aa263SPaul E. McKenney * that are not already voluntarily blocked. Mark these tasks 318d01aa263SPaul E. McKenney * and make a list of them in holdouts. 319d01aa263SPaul E. McKenney */ 320af051ca4SPaul E. McKenney set_tasks_gp_state(rtp, RTGS_SCAN_TASKLIST); 321d01aa263SPaul E. McKenney rcu_read_lock(); 322d01aa263SPaul E. McKenney for_each_process_thread(g, t) 323d01aa263SPaul E. McKenney rtp->pertask_func(t, &holdouts); 324d01aa263SPaul E. McKenney rcu_read_unlock(); 325d01aa263SPaul E. McKenney 326af051ca4SPaul E. McKenney set_tasks_gp_state(rtp, RTGS_POST_SCAN_TASKLIST); 3279796e1aeSPaul E. McKenney rtp->postscan_func(&holdouts); 328d01aa263SPaul E. McKenney 329d01aa263SPaul E. McKenney /* 330d01aa263SPaul E. McKenney * Each pass through the following loop scans the list of holdout 331d01aa263SPaul E. McKenney * tasks, removing any that are no longer holdouts. When the list 332d01aa263SPaul E. McKenney * is empty, we are done. 333d01aa263SPaul E. McKenney */ 334d01aa263SPaul E. McKenney lastreport = jiffies; 335d01aa263SPaul E. McKenney 3362393a613SPaul E. McKenney // Start off with initial wait and slowly back off to 1 HZ wait. 3372393a613SPaul E. McKenney fract = rtp->init_fract; 338d01aa263SPaul E. McKenney 33977dc1741SPaul E. McKenney while (!list_empty(&holdouts)) { 340d01aa263SPaul E. McKenney bool firstreport; 341d01aa263SPaul E. McKenney bool needreport; 342d01aa263SPaul E. McKenney int rtst; 343d01aa263SPaul E. McKenney 344d01aa263SPaul E. McKenney /* Slowly back off waiting for holdouts */ 345af051ca4SPaul E. McKenney set_tasks_gp_state(rtp, RTGS_WAIT_SCAN_HOLDOUTS); 34675dc2da5SPaul E. McKenney schedule_timeout_idle(fract); 347d01aa263SPaul E. McKenney 34875dc2da5SPaul E. McKenney if (fract < HZ) 34975dc2da5SPaul E. McKenney fract++; 350d01aa263SPaul E. McKenney 351d01aa263SPaul E. McKenney rtst = READ_ONCE(rcu_task_stall_timeout); 352d01aa263SPaul E. McKenney needreport = rtst > 0 && time_after(jiffies, lastreport + rtst); 353d01aa263SPaul E. McKenney if (needreport) 354d01aa263SPaul E. McKenney lastreport = jiffies; 355d01aa263SPaul E. McKenney firstreport = true; 356d01aa263SPaul E. McKenney WARN_ON(signal_pending(current)); 357af051ca4SPaul E. McKenney set_tasks_gp_state(rtp, RTGS_SCAN_HOLDOUTS); 358d01aa263SPaul E. McKenney rtp->holdouts_func(&holdouts, needreport, &firstreport); 359d01aa263SPaul E. McKenney } 360d01aa263SPaul E. McKenney 361af051ca4SPaul E. McKenney set_tasks_gp_state(rtp, RTGS_POST_GP); 362af051ca4SPaul E. McKenney rtp->postgp_func(rtp); 363d01aa263SPaul E. McKenney } 364d01aa263SPaul E. McKenney 36525246fc8SPaul E. McKenney #endif /* #if defined(CONFIG_TASKS_RCU) || defined(CONFIG_TASKS_TRACE_RCU) */ 36625246fc8SPaul E. McKenney 36725246fc8SPaul E. McKenney #ifdef CONFIG_TASKS_RCU 36825246fc8SPaul E. McKenney 369d01aa263SPaul E. McKenney //////////////////////////////////////////////////////////////////////// 370d01aa263SPaul E. McKenney // 3715873b8a9SPaul E. McKenney // Simple variant of RCU whose quiescent states are voluntary context 3725873b8a9SPaul E. McKenney // switch, cond_resched_rcu_qs(), user-space execution, and idle. 3735873b8a9SPaul E. McKenney // As such, grace periods can take one good long time. There are no 3745873b8a9SPaul E. McKenney // read-side primitives similar to rcu_read_lock() and rcu_read_unlock() 3755873b8a9SPaul E. McKenney // because this implementation is intended to get the system into a safe 3765873b8a9SPaul E. McKenney // state for some of the manipulations involved in tracing and the like. 3775873b8a9SPaul E. McKenney // Finally, this implementation does not support high call_rcu_tasks() 3785873b8a9SPaul E. McKenney // rates from multiple CPUs. If this is required, per-CPU callback lists 3795873b8a9SPaul E. McKenney // will be needed. 38006a3ec92SPaul E. McKenney // 38106a3ec92SPaul E. McKenney // The implementation uses rcu_tasks_wait_gp(), which relies on function 38206a3ec92SPaul E. McKenney // pointers in the rcu_tasks structure. The rcu_spawn_tasks_kthread() 38306a3ec92SPaul E. McKenney // function sets these function pointers up so that rcu_tasks_wait_gp() 38406a3ec92SPaul E. McKenney // invokes these functions in this order: 38506a3ec92SPaul E. McKenney // 38606a3ec92SPaul E. McKenney // rcu_tasks_pregp_step(): 38706a3ec92SPaul E. McKenney // Invokes synchronize_rcu() in order to wait for all in-flight 38806a3ec92SPaul E. McKenney // t->on_rq and t->nvcsw transitions to complete. This works because 38906a3ec92SPaul E. McKenney // all such transitions are carried out with interrupts disabled. 39006a3ec92SPaul E. McKenney // rcu_tasks_pertask(), invoked on every non-idle task: 39106a3ec92SPaul E. McKenney // For every runnable non-idle task other than the current one, use 39206a3ec92SPaul E. McKenney // get_task_struct() to pin down that task, snapshot that task's 39306a3ec92SPaul E. McKenney // number of voluntary context switches, and add that task to the 39406a3ec92SPaul E. McKenney // holdout list. 39506a3ec92SPaul E. McKenney // rcu_tasks_postscan(): 39606a3ec92SPaul E. McKenney // Invoke synchronize_srcu() to ensure that all tasks that were 39706a3ec92SPaul E. McKenney // in the process of exiting (and which thus might not know to 39806a3ec92SPaul E. McKenney // synchronize with this RCU Tasks grace period) have completed 39906a3ec92SPaul E. McKenney // exiting. 40006a3ec92SPaul E. McKenney // check_all_holdout_tasks(), repeatedly until holdout list is empty: 40106a3ec92SPaul E. McKenney // Scans the holdout list, attempting to identify a quiescent state 40206a3ec92SPaul E. McKenney // for each task on the list. If there is a quiescent state, the 40306a3ec92SPaul E. McKenney // corresponding task is removed from the holdout list. 40406a3ec92SPaul E. McKenney // rcu_tasks_postgp(): 40506a3ec92SPaul E. McKenney // Invokes synchronize_rcu() in order to ensure that all prior 40606a3ec92SPaul E. McKenney // t->on_rq and t->nvcsw transitions are seen by all CPUs and tasks 40706a3ec92SPaul E. McKenney // to have happened before the end of this RCU Tasks grace period. 40806a3ec92SPaul E. McKenney // Again, this works because all such transitions are carried out 40906a3ec92SPaul E. McKenney // with interrupts disabled. 41006a3ec92SPaul E. McKenney // 41106a3ec92SPaul E. McKenney // For each exiting task, the exit_tasks_rcu_start() and 41206a3ec92SPaul E. McKenney // exit_tasks_rcu_finish() functions begin and end, respectively, the SRCU 41306a3ec92SPaul E. McKenney // read-side critical sections waited for by rcu_tasks_postscan(). 41406a3ec92SPaul E. McKenney // 41506a3ec92SPaul E. McKenney // Pre-grace-period update-side code is ordered before the grace via the 41606a3ec92SPaul E. McKenney // ->cbs_lock and the smp_mb__after_spinlock(). Pre-grace-period read-side 41706a3ec92SPaul E. McKenney // code is ordered before the grace period via synchronize_rcu() call 41806a3ec92SPaul E. McKenney // in rcu_tasks_pregp_step() and by the scheduler's locks and interrupt 41906a3ec92SPaul E. McKenney // disabling. 420eacd6f04SPaul E. McKenney 421e4fe5dd6SPaul E. McKenney /* Pre-grace-period preparation. */ 422e4fe5dd6SPaul E. McKenney static void rcu_tasks_pregp_step(void) 423e4fe5dd6SPaul E. McKenney { 424e4fe5dd6SPaul E. McKenney /* 425e4fe5dd6SPaul E. McKenney * Wait for all pre-existing t->on_rq and t->nvcsw transitions 426e4fe5dd6SPaul E. McKenney * to complete. Invoking synchronize_rcu() suffices because all 427e4fe5dd6SPaul E. McKenney * these transitions occur with interrupts disabled. Without this 428e4fe5dd6SPaul E. McKenney * synchronize_rcu(), a read-side critical section that started 429e4fe5dd6SPaul E. McKenney * before the grace period might be incorrectly seen as having 430e4fe5dd6SPaul E. McKenney * started after the grace period. 431e4fe5dd6SPaul E. McKenney * 432e4fe5dd6SPaul E. McKenney * This synchronize_rcu() also dispenses with the need for a 433e4fe5dd6SPaul E. McKenney * memory barrier on the first store to t->rcu_tasks_holdout, 434e4fe5dd6SPaul E. McKenney * as it forces the store to happen after the beginning of the 435e4fe5dd6SPaul E. McKenney * grace period. 436e4fe5dd6SPaul E. McKenney */ 437e4fe5dd6SPaul E. McKenney synchronize_rcu(); 438e4fe5dd6SPaul E. McKenney } 439e4fe5dd6SPaul E. McKenney 440e4fe5dd6SPaul E. McKenney /* Per-task initial processing. */ 441e4fe5dd6SPaul E. McKenney static void rcu_tasks_pertask(struct task_struct *t, struct list_head *hop) 442e4fe5dd6SPaul E. McKenney { 443e4fe5dd6SPaul E. McKenney if (t != current && READ_ONCE(t->on_rq) && !is_idle_task(t)) { 444e4fe5dd6SPaul E. McKenney get_task_struct(t); 445e4fe5dd6SPaul E. McKenney t->rcu_tasks_nvcsw = READ_ONCE(t->nvcsw); 446e4fe5dd6SPaul E. McKenney WRITE_ONCE(t->rcu_tasks_holdout, true); 447e4fe5dd6SPaul E. McKenney list_add(&t->rcu_tasks_holdout_list, hop); 448e4fe5dd6SPaul E. McKenney } 449e4fe5dd6SPaul E. McKenney } 450e4fe5dd6SPaul E. McKenney 451e4fe5dd6SPaul E. McKenney /* Processing between scanning taskslist and draining the holdout list. */ 45204a3c5aaSPaul E. McKenney static void rcu_tasks_postscan(struct list_head *hop) 453e4fe5dd6SPaul E. McKenney { 454e4fe5dd6SPaul E. McKenney /* 455e4fe5dd6SPaul E. McKenney * Wait for tasks that are in the process of exiting. This 456e4fe5dd6SPaul E. McKenney * does only part of the job, ensuring that all tasks that were 457e4fe5dd6SPaul E. McKenney * previously exiting reach the point where they have disabled 458e4fe5dd6SPaul E. McKenney * preemption, allowing the later synchronize_rcu() to finish 459e4fe5dd6SPaul E. McKenney * the job. 460e4fe5dd6SPaul E. McKenney */ 461e4fe5dd6SPaul E. McKenney synchronize_srcu(&tasks_rcu_exit_srcu); 462e4fe5dd6SPaul E. McKenney } 463e4fe5dd6SPaul E. McKenney 464eacd6f04SPaul E. McKenney /* See if tasks are still holding out, complain if so. */ 465eacd6f04SPaul E. McKenney static void check_holdout_task(struct task_struct *t, 466eacd6f04SPaul E. McKenney bool needreport, bool *firstreport) 467eacd6f04SPaul E. McKenney { 468eacd6f04SPaul E. McKenney int cpu; 469eacd6f04SPaul E. McKenney 470eacd6f04SPaul E. McKenney if (!READ_ONCE(t->rcu_tasks_holdout) || 471eacd6f04SPaul E. McKenney t->rcu_tasks_nvcsw != READ_ONCE(t->nvcsw) || 472eacd6f04SPaul E. McKenney !READ_ONCE(t->on_rq) || 473eacd6f04SPaul E. McKenney (IS_ENABLED(CONFIG_NO_HZ_FULL) && 474eacd6f04SPaul E. McKenney !is_idle_task(t) && t->rcu_tasks_idle_cpu >= 0)) { 475eacd6f04SPaul E. McKenney WRITE_ONCE(t->rcu_tasks_holdout, false); 476eacd6f04SPaul E. McKenney list_del_init(&t->rcu_tasks_holdout_list); 477eacd6f04SPaul E. McKenney put_task_struct(t); 478eacd6f04SPaul E. McKenney return; 479eacd6f04SPaul E. McKenney } 480eacd6f04SPaul E. McKenney rcu_request_urgent_qs_task(t); 481eacd6f04SPaul E. McKenney if (!needreport) 482eacd6f04SPaul E. McKenney return; 483eacd6f04SPaul E. McKenney if (*firstreport) { 484eacd6f04SPaul E. McKenney pr_err("INFO: rcu_tasks detected stalls on tasks:\n"); 485eacd6f04SPaul E. McKenney *firstreport = false; 486eacd6f04SPaul E. McKenney } 487eacd6f04SPaul E. McKenney cpu = task_cpu(t); 488eacd6f04SPaul E. McKenney pr_alert("%p: %c%c nvcsw: %lu/%lu holdout: %d idle_cpu: %d/%d\n", 489eacd6f04SPaul E. McKenney t, ".I"[is_idle_task(t)], 490eacd6f04SPaul E. McKenney "N."[cpu < 0 || !tick_nohz_full_cpu(cpu)], 491eacd6f04SPaul E. McKenney t->rcu_tasks_nvcsw, t->nvcsw, t->rcu_tasks_holdout, 492eacd6f04SPaul E. McKenney t->rcu_tasks_idle_cpu, cpu); 493eacd6f04SPaul E. McKenney sched_show_task(t); 494eacd6f04SPaul E. McKenney } 495eacd6f04SPaul E. McKenney 496e4fe5dd6SPaul E. McKenney /* Scan the holdout lists for tasks no longer holding out. */ 497e4fe5dd6SPaul E. McKenney static void check_all_holdout_tasks(struct list_head *hop, 498e4fe5dd6SPaul E. McKenney bool needreport, bool *firstreport) 499eacd6f04SPaul E. McKenney { 500e4fe5dd6SPaul E. McKenney struct task_struct *t, *t1; 501eacd6f04SPaul E. McKenney 502e4fe5dd6SPaul E. McKenney list_for_each_entry_safe(t, t1, hop, rcu_tasks_holdout_list) { 503e4fe5dd6SPaul E. McKenney check_holdout_task(t, needreport, firstreport); 504eacd6f04SPaul E. McKenney cond_resched(); 505eacd6f04SPaul E. McKenney } 506eacd6f04SPaul E. McKenney } 507eacd6f04SPaul E. McKenney 508e4fe5dd6SPaul E. McKenney /* Finish off the Tasks-RCU grace period. */ 509af051ca4SPaul E. McKenney static void rcu_tasks_postgp(struct rcu_tasks *rtp) 510e4fe5dd6SPaul E. McKenney { 511eacd6f04SPaul E. McKenney /* 5125873b8a9SPaul E. McKenney * Because ->on_rq and ->nvcsw are not guaranteed to have a full 5135873b8a9SPaul E. McKenney * memory barriers prior to them in the schedule() path, memory 5145873b8a9SPaul E. McKenney * reordering on other CPUs could cause their RCU-tasks read-side 5155873b8a9SPaul E. McKenney * critical sections to extend past the end of the grace period. 5165873b8a9SPaul E. McKenney * However, because these ->nvcsw updates are carried out with 5175873b8a9SPaul E. McKenney * interrupts disabled, we can use synchronize_rcu() to force the 5185873b8a9SPaul E. McKenney * needed ordering on all such CPUs. 519eacd6f04SPaul E. McKenney * 5205873b8a9SPaul E. McKenney * This synchronize_rcu() also confines all ->rcu_tasks_holdout 5215873b8a9SPaul E. McKenney * accesses to be within the grace period, avoiding the need for 5225873b8a9SPaul E. McKenney * memory barriers for ->rcu_tasks_holdout accesses. 523eacd6f04SPaul E. McKenney * 5245873b8a9SPaul E. McKenney * In addition, this synchronize_rcu() waits for exiting tasks 5255873b8a9SPaul E. McKenney * to complete their final preempt_disable() region of execution, 5265873b8a9SPaul E. McKenney * cleaning up after the synchronize_srcu() above. 527eacd6f04SPaul E. McKenney */ 528eacd6f04SPaul E. McKenney synchronize_rcu(); 529eacd6f04SPaul E. McKenney } 530eacd6f04SPaul E. McKenney 5315873b8a9SPaul E. McKenney void call_rcu_tasks(struct rcu_head *rhp, rcu_callback_t func); 532c97d12a6SPaul E. McKenney DEFINE_RCU_TASKS(rcu_tasks, rcu_tasks_wait_gp, call_rcu_tasks, "RCU Tasks"); 5335873b8a9SPaul E. McKenney 5345873b8a9SPaul E. McKenney /** 5355873b8a9SPaul E. McKenney * call_rcu_tasks() - Queue an RCU for invocation task-based grace period 5365873b8a9SPaul E. McKenney * @rhp: structure to be used for queueing the RCU updates. 5375873b8a9SPaul E. McKenney * @func: actual callback function to be invoked after the grace period 5385873b8a9SPaul E. McKenney * 5395873b8a9SPaul E. McKenney * The callback function will be invoked some time after a full grace 5405873b8a9SPaul E. McKenney * period elapses, in other words after all currently executing RCU 5415873b8a9SPaul E. McKenney * read-side critical sections have completed. call_rcu_tasks() assumes 5425873b8a9SPaul E. McKenney * that the read-side critical sections end at a voluntary context 5435873b8a9SPaul E. McKenney * switch (not a preemption!), cond_resched_rcu_qs(), entry into idle, 5445873b8a9SPaul E. McKenney * or transition to usermode execution. As such, there are no read-side 5455873b8a9SPaul E. McKenney * primitives analogous to rcu_read_lock() and rcu_read_unlock() because 5465873b8a9SPaul E. McKenney * this primitive is intended to determine that all tasks have passed 547a616aec9SIngo Molnar * through a safe state, not so much for data-structure synchronization. 5485873b8a9SPaul E. McKenney * 5495873b8a9SPaul E. McKenney * See the description of call_rcu() for more detailed information on 5505873b8a9SPaul E. McKenney * memory ordering guarantees. 5515873b8a9SPaul E. McKenney */ 5525873b8a9SPaul E. McKenney void call_rcu_tasks(struct rcu_head *rhp, rcu_callback_t func) 5535873b8a9SPaul E. McKenney { 5545873b8a9SPaul E. McKenney call_rcu_tasks_generic(rhp, func, &rcu_tasks); 5555873b8a9SPaul E. McKenney } 5565873b8a9SPaul E. McKenney EXPORT_SYMBOL_GPL(call_rcu_tasks); 5575873b8a9SPaul E. McKenney 5585873b8a9SPaul E. McKenney /** 5595873b8a9SPaul E. McKenney * synchronize_rcu_tasks - wait until an rcu-tasks grace period has elapsed. 5605873b8a9SPaul E. McKenney * 5615873b8a9SPaul E. McKenney * Control will return to the caller some time after a full rcu-tasks 5625873b8a9SPaul E. McKenney * grace period has elapsed, in other words after all currently 5635873b8a9SPaul E. McKenney * executing rcu-tasks read-side critical sections have elapsed. These 5645873b8a9SPaul E. McKenney * read-side critical sections are delimited by calls to schedule(), 5655873b8a9SPaul E. McKenney * cond_resched_tasks_rcu_qs(), idle execution, userspace execution, calls 5665873b8a9SPaul E. McKenney * to synchronize_rcu_tasks(), and (in theory, anyway) cond_resched(). 5675873b8a9SPaul E. McKenney * 5685873b8a9SPaul E. McKenney * This is a very specialized primitive, intended only for a few uses in 5695873b8a9SPaul E. McKenney * tracing and other situations requiring manipulation of function 5705873b8a9SPaul E. McKenney * preambles and profiling hooks. The synchronize_rcu_tasks() function 5715873b8a9SPaul E. McKenney * is not (yet) intended for heavy use from multiple CPUs. 5725873b8a9SPaul E. McKenney * 5735873b8a9SPaul E. McKenney * See the description of synchronize_rcu() for more detailed information 5745873b8a9SPaul E. McKenney * on memory ordering guarantees. 5755873b8a9SPaul E. McKenney */ 5765873b8a9SPaul E. McKenney void synchronize_rcu_tasks(void) 5775873b8a9SPaul E. McKenney { 5785873b8a9SPaul E. McKenney synchronize_rcu_tasks_generic(&rcu_tasks); 5795873b8a9SPaul E. McKenney } 5805873b8a9SPaul E. McKenney EXPORT_SYMBOL_GPL(synchronize_rcu_tasks); 5815873b8a9SPaul E. McKenney 5825873b8a9SPaul E. McKenney /** 5835873b8a9SPaul E. McKenney * rcu_barrier_tasks - Wait for in-flight call_rcu_tasks() callbacks. 5845873b8a9SPaul E. McKenney * 5855873b8a9SPaul E. McKenney * Although the current implementation is guaranteed to wait, it is not 5865873b8a9SPaul E. McKenney * obligated to, for example, if there are no pending callbacks. 5875873b8a9SPaul E. McKenney */ 5885873b8a9SPaul E. McKenney void rcu_barrier_tasks(void) 5895873b8a9SPaul E. McKenney { 5905873b8a9SPaul E. McKenney /* There is only one callback queue, so this is easy. ;-) */ 5915873b8a9SPaul E. McKenney synchronize_rcu_tasks(); 5925873b8a9SPaul E. McKenney } 5935873b8a9SPaul E. McKenney EXPORT_SYMBOL_GPL(rcu_barrier_tasks); 5945873b8a9SPaul E. McKenney 595eacd6f04SPaul E. McKenney static int __init rcu_spawn_tasks_kthread(void) 596eacd6f04SPaul E. McKenney { 5974fe192dfSPaul E. McKenney rcu_tasks.gp_sleep = HZ / 10; 59875dc2da5SPaul E. McKenney rcu_tasks.init_fract = HZ / 10; 599e4fe5dd6SPaul E. McKenney rcu_tasks.pregp_func = rcu_tasks_pregp_step; 600e4fe5dd6SPaul E. McKenney rcu_tasks.pertask_func = rcu_tasks_pertask; 601e4fe5dd6SPaul E. McKenney rcu_tasks.postscan_func = rcu_tasks_postscan; 602e4fe5dd6SPaul E. McKenney rcu_tasks.holdouts_func = check_all_holdout_tasks; 603e4fe5dd6SPaul E. McKenney rcu_tasks.postgp_func = rcu_tasks_postgp; 6045873b8a9SPaul E. McKenney rcu_spawn_tasks_kthread_generic(&rcu_tasks); 605eacd6f04SPaul E. McKenney return 0; 606eacd6f04SPaul E. McKenney } 607eacd6f04SPaul E. McKenney 60827c0f144SPaul E. McKenney #if !defined(CONFIG_TINY_RCU) 60927c0f144SPaul E. McKenney void show_rcu_tasks_classic_gp_kthread(void) 610e21408ceSPaul E. McKenney { 611e21408ceSPaul E. McKenney show_rcu_tasks_generic_gp_kthread(&rcu_tasks, ""); 612e21408ceSPaul E. McKenney } 61327c0f144SPaul E. McKenney EXPORT_SYMBOL_GPL(show_rcu_tasks_classic_gp_kthread); 61427c0f144SPaul E. McKenney #endif // !defined(CONFIG_TINY_RCU) 615e21408ceSPaul E. McKenney 61625246fc8SPaul E. McKenney /* Do the srcu_read_lock() for the above synchronize_srcu(). */ 61725246fc8SPaul E. McKenney void exit_tasks_rcu_start(void) __acquires(&tasks_rcu_exit_srcu) 61825246fc8SPaul E. McKenney { 61925246fc8SPaul E. McKenney preempt_disable(); 62025246fc8SPaul E. McKenney current->rcu_tasks_idx = __srcu_read_lock(&tasks_rcu_exit_srcu); 62125246fc8SPaul E. McKenney preempt_enable(); 62225246fc8SPaul E. McKenney } 62325246fc8SPaul E. McKenney 62425246fc8SPaul E. McKenney /* Do the srcu_read_unlock() for the above synchronize_srcu(). */ 62525246fc8SPaul E. McKenney void exit_tasks_rcu_finish(void) __releases(&tasks_rcu_exit_srcu) 62625246fc8SPaul E. McKenney { 62725246fc8SPaul E. McKenney struct task_struct *t = current; 62825246fc8SPaul E. McKenney 62925246fc8SPaul E. McKenney preempt_disable(); 63025246fc8SPaul E. McKenney __srcu_read_unlock(&tasks_rcu_exit_srcu, t->rcu_tasks_idx); 63125246fc8SPaul E. McKenney preempt_enable(); 63225246fc8SPaul E. McKenney exit_tasks_rcu_finish_trace(t); 63325246fc8SPaul E. McKenney } 63425246fc8SPaul E. McKenney 635e21408ceSPaul E. McKenney #else /* #ifdef CONFIG_TASKS_RCU */ 63625246fc8SPaul E. McKenney void exit_tasks_rcu_start(void) { } 63725246fc8SPaul E. McKenney void exit_tasks_rcu_finish(void) { exit_tasks_rcu_finish_trace(current); } 638e21408ceSPaul E. McKenney #endif /* #else #ifdef CONFIG_TASKS_RCU */ 639c84aad76SPaul E. McKenney 640c84aad76SPaul E. McKenney #ifdef CONFIG_TASKS_RUDE_RCU 641c84aad76SPaul E. McKenney 642c84aad76SPaul E. McKenney //////////////////////////////////////////////////////////////////////// 643c84aad76SPaul E. McKenney // 644c84aad76SPaul E. McKenney // "Rude" variant of Tasks RCU, inspired by Steve Rostedt's trick of 645c84aad76SPaul E. McKenney // passing an empty function to schedule_on_each_cpu(). This approach 646c84aad76SPaul E. McKenney // provides an asynchronous call_rcu_tasks_rude() API and batching 647c84aad76SPaul E. McKenney // of concurrent calls to the synchronous synchronize_rcu_rude() API. 6489fc98e31SPaul E. McKenney // This invokes schedule_on_each_cpu() in order to send IPIs far and wide 6499fc98e31SPaul E. McKenney // and induces otherwise unnecessary context switches on all online CPUs, 6509fc98e31SPaul E. McKenney // whether idle or not. 6519fc98e31SPaul E. McKenney // 6529fc98e31SPaul E. McKenney // Callback handling is provided by the rcu_tasks_kthread() function. 6539fc98e31SPaul E. McKenney // 6549fc98e31SPaul E. McKenney // Ordering is provided by the scheduler's context-switch code. 655c84aad76SPaul E. McKenney 656c84aad76SPaul E. McKenney // Empty function to allow workqueues to force a context switch. 657c84aad76SPaul E. McKenney static void rcu_tasks_be_rude(struct work_struct *work) 658c84aad76SPaul E. McKenney { 659c84aad76SPaul E. McKenney } 660c84aad76SPaul E. McKenney 661c84aad76SPaul E. McKenney // Wait for one rude RCU-tasks grace period. 662c84aad76SPaul E. McKenney static void rcu_tasks_rude_wait_gp(struct rcu_tasks *rtp) 663c84aad76SPaul E. McKenney { 664238dbce3SPaul E. McKenney rtp->n_ipis += cpumask_weight(cpu_online_mask); 665c84aad76SPaul E. McKenney schedule_on_each_cpu(rcu_tasks_be_rude); 666c84aad76SPaul E. McKenney } 667c84aad76SPaul E. McKenney 668c84aad76SPaul E. McKenney void call_rcu_tasks_rude(struct rcu_head *rhp, rcu_callback_t func); 669c97d12a6SPaul E. McKenney DEFINE_RCU_TASKS(rcu_tasks_rude, rcu_tasks_rude_wait_gp, call_rcu_tasks_rude, 670c97d12a6SPaul E. McKenney "RCU Tasks Rude"); 671c84aad76SPaul E. McKenney 672c84aad76SPaul E. McKenney /** 673c84aad76SPaul E. McKenney * call_rcu_tasks_rude() - Queue a callback rude task-based grace period 674c84aad76SPaul E. McKenney * @rhp: structure to be used for queueing the RCU updates. 675c84aad76SPaul E. McKenney * @func: actual callback function to be invoked after the grace period 676c84aad76SPaul E. McKenney * 677c84aad76SPaul E. McKenney * The callback function will be invoked some time after a full grace 678c84aad76SPaul E. McKenney * period elapses, in other words after all currently executing RCU 679c84aad76SPaul E. McKenney * read-side critical sections have completed. call_rcu_tasks_rude() 680c84aad76SPaul E. McKenney * assumes that the read-side critical sections end at context switch, 681c84aad76SPaul E. McKenney * cond_resched_rcu_qs(), or transition to usermode execution. As such, 682c84aad76SPaul E. McKenney * there are no read-side primitives analogous to rcu_read_lock() and 683c84aad76SPaul E. McKenney * rcu_read_unlock() because this primitive is intended to determine 684c84aad76SPaul E. McKenney * that all tasks have passed through a safe state, not so much for 685a616aec9SIngo Molnar * data-structure synchronization. 686c84aad76SPaul E. McKenney * 687c84aad76SPaul E. McKenney * See the description of call_rcu() for more detailed information on 688c84aad76SPaul E. McKenney * memory ordering guarantees. 689c84aad76SPaul E. McKenney */ 690c84aad76SPaul E. McKenney void call_rcu_tasks_rude(struct rcu_head *rhp, rcu_callback_t func) 691c84aad76SPaul E. McKenney { 692c84aad76SPaul E. McKenney call_rcu_tasks_generic(rhp, func, &rcu_tasks_rude); 693c84aad76SPaul E. McKenney } 694c84aad76SPaul E. McKenney EXPORT_SYMBOL_GPL(call_rcu_tasks_rude); 695c84aad76SPaul E. McKenney 696c84aad76SPaul E. McKenney /** 697c84aad76SPaul E. McKenney * synchronize_rcu_tasks_rude - wait for a rude rcu-tasks grace period 698c84aad76SPaul E. McKenney * 699c84aad76SPaul E. McKenney * Control will return to the caller some time after a rude rcu-tasks 700c84aad76SPaul E. McKenney * grace period has elapsed, in other words after all currently 701c84aad76SPaul E. McKenney * executing rcu-tasks read-side critical sections have elapsed. These 702c84aad76SPaul E. McKenney * read-side critical sections are delimited by calls to schedule(), 703c84aad76SPaul E. McKenney * cond_resched_tasks_rcu_qs(), userspace execution, and (in theory, 704c84aad76SPaul E. McKenney * anyway) cond_resched(). 705c84aad76SPaul E. McKenney * 706c84aad76SPaul E. McKenney * This is a very specialized primitive, intended only for a few uses in 707c84aad76SPaul E. McKenney * tracing and other situations requiring manipulation of function preambles 708c84aad76SPaul E. McKenney * and profiling hooks. The synchronize_rcu_tasks_rude() function is not 709c84aad76SPaul E. McKenney * (yet) intended for heavy use from multiple CPUs. 710c84aad76SPaul E. McKenney * 711c84aad76SPaul E. McKenney * See the description of synchronize_rcu() for more detailed information 712c84aad76SPaul E. McKenney * on memory ordering guarantees. 713c84aad76SPaul E. McKenney */ 714c84aad76SPaul E. McKenney void synchronize_rcu_tasks_rude(void) 715c84aad76SPaul E. McKenney { 716c84aad76SPaul E. McKenney synchronize_rcu_tasks_generic(&rcu_tasks_rude); 717c84aad76SPaul E. McKenney } 718c84aad76SPaul E. McKenney EXPORT_SYMBOL_GPL(synchronize_rcu_tasks_rude); 719c84aad76SPaul E. McKenney 720c84aad76SPaul E. McKenney /** 721c84aad76SPaul E. McKenney * rcu_barrier_tasks_rude - Wait for in-flight call_rcu_tasks_rude() callbacks. 722c84aad76SPaul E. McKenney * 723c84aad76SPaul E. McKenney * Although the current implementation is guaranteed to wait, it is not 724c84aad76SPaul E. McKenney * obligated to, for example, if there are no pending callbacks. 725c84aad76SPaul E. McKenney */ 726c84aad76SPaul E. McKenney void rcu_barrier_tasks_rude(void) 727c84aad76SPaul E. McKenney { 728c84aad76SPaul E. McKenney /* There is only one callback queue, so this is easy. ;-) */ 729c84aad76SPaul E. McKenney synchronize_rcu_tasks_rude(); 730c84aad76SPaul E. McKenney } 731c84aad76SPaul E. McKenney EXPORT_SYMBOL_GPL(rcu_barrier_tasks_rude); 732c84aad76SPaul E. McKenney 733c84aad76SPaul E. McKenney static int __init rcu_spawn_tasks_rude_kthread(void) 734c84aad76SPaul E. McKenney { 7354fe192dfSPaul E. McKenney rcu_tasks_rude.gp_sleep = HZ / 10; 736c84aad76SPaul E. McKenney rcu_spawn_tasks_kthread_generic(&rcu_tasks_rude); 737c84aad76SPaul E. McKenney return 0; 738c84aad76SPaul E. McKenney } 739c84aad76SPaul E. McKenney 74027c0f144SPaul E. McKenney #if !defined(CONFIG_TINY_RCU) 74127c0f144SPaul E. McKenney void show_rcu_tasks_rude_gp_kthread(void) 742e21408ceSPaul E. McKenney { 743e21408ceSPaul E. McKenney show_rcu_tasks_generic_gp_kthread(&rcu_tasks_rude, ""); 744e21408ceSPaul E. McKenney } 74527c0f144SPaul E. McKenney EXPORT_SYMBOL_GPL(show_rcu_tasks_rude_gp_kthread); 74627c0f144SPaul E. McKenney #endif // !defined(CONFIG_TINY_RCU) 74727c0f144SPaul E. McKenney #endif /* #ifdef CONFIG_TASKS_RUDE_RCU */ 748d5f177d3SPaul E. McKenney 749d5f177d3SPaul E. McKenney //////////////////////////////////////////////////////////////////////// 750d5f177d3SPaul E. McKenney // 751d5f177d3SPaul E. McKenney // Tracing variant of Tasks RCU. This variant is designed to be used 752d5f177d3SPaul E. McKenney // to protect tracing hooks, including those of BPF. This variant 753d5f177d3SPaul E. McKenney // therefore: 754d5f177d3SPaul E. McKenney // 755d5f177d3SPaul E. McKenney // 1. Has explicit read-side markers to allow finite grace periods 756d5f177d3SPaul E. McKenney // in the face of in-kernel loops for PREEMPT=n builds. 757d5f177d3SPaul E. McKenney // 758d5f177d3SPaul E. McKenney // 2. Protects code in the idle loop, exception entry/exit, and 759d5f177d3SPaul E. McKenney // CPU-hotplug code paths, similar to the capabilities of SRCU. 760d5f177d3SPaul E. McKenney // 761d5f177d3SPaul E. McKenney // 3. Avoids expensive read-side instruction, having overhead similar 762d5f177d3SPaul E. McKenney // to that of Preemptible RCU. 763d5f177d3SPaul E. McKenney // 764d5f177d3SPaul E. McKenney // There are of course downsides. The grace-period code can send IPIs to 765d5f177d3SPaul E. McKenney // CPUs, even when those CPUs are in the idle loop or in nohz_full userspace. 766d5f177d3SPaul E. McKenney // It is necessary to scan the full tasklist, much as for Tasks RCU. There 767d5f177d3SPaul E. McKenney // is a single callback queue guarded by a single lock, again, much as for 768d5f177d3SPaul E. McKenney // Tasks RCU. If needed, these downsides can be at least partially remedied. 769d5f177d3SPaul E. McKenney // 770d5f177d3SPaul E. McKenney // Perhaps most important, this variant of RCU does not affect the vanilla 771d5f177d3SPaul E. McKenney // flavors, rcu_preempt and rcu_sched. The fact that RCU Tasks Trace 772d5f177d3SPaul E. McKenney // readers can operate from idle, offline, and exception entry/exit in no 773d5f177d3SPaul E. McKenney // way allows rcu_preempt and rcu_sched readers to also do so. 774a434dd10SPaul E. McKenney // 775a434dd10SPaul E. McKenney // The implementation uses rcu_tasks_wait_gp(), which relies on function 776a434dd10SPaul E. McKenney // pointers in the rcu_tasks structure. The rcu_spawn_tasks_trace_kthread() 777a434dd10SPaul E. McKenney // function sets these function pointers up so that rcu_tasks_wait_gp() 778a434dd10SPaul E. McKenney // invokes these functions in this order: 779a434dd10SPaul E. McKenney // 780a434dd10SPaul E. McKenney // rcu_tasks_trace_pregp_step(): 781a434dd10SPaul E. McKenney // Initialize the count of readers and block CPU-hotplug operations. 782a434dd10SPaul E. McKenney // rcu_tasks_trace_pertask(), invoked on every non-idle task: 783a434dd10SPaul E. McKenney // Initialize per-task state and attempt to identify an immediate 784a434dd10SPaul E. McKenney // quiescent state for that task, or, failing that, attempt to 785a434dd10SPaul E. McKenney // set that task's .need_qs flag so that task's next outermost 786a434dd10SPaul E. McKenney // rcu_read_unlock_trace() will report the quiescent state (in which 787a434dd10SPaul E. McKenney // case the count of readers is incremented). If both attempts fail, 788a434dd10SPaul E. McKenney // the task is added to a "holdout" list. 789a434dd10SPaul E. McKenney // rcu_tasks_trace_postscan(): 790a434dd10SPaul E. McKenney // Initialize state and attempt to identify an immediate quiescent 791a434dd10SPaul E. McKenney // state as above (but only for idle tasks), unblock CPU-hotplug 792a434dd10SPaul E. McKenney // operations, and wait for an RCU grace period to avoid races with 793a434dd10SPaul E. McKenney // tasks that are in the process of exiting. 794a434dd10SPaul E. McKenney // check_all_holdout_tasks_trace(), repeatedly until holdout list is empty: 795a434dd10SPaul E. McKenney // Scans the holdout list, attempting to identify a quiescent state 796a434dd10SPaul E. McKenney // for each task on the list. If there is a quiescent state, the 797a434dd10SPaul E. McKenney // corresponding task is removed from the holdout list. 798a434dd10SPaul E. McKenney // rcu_tasks_trace_postgp(): 799a434dd10SPaul E. McKenney // Wait for the count of readers do drop to zero, reporting any stalls. 800a434dd10SPaul E. McKenney // Also execute full memory barriers to maintain ordering with code 801a434dd10SPaul E. McKenney // executing after the grace period. 802a434dd10SPaul E. McKenney // 803a434dd10SPaul E. McKenney // The exit_tasks_rcu_finish_trace() synchronizes with exiting tasks. 804a434dd10SPaul E. McKenney // 805a434dd10SPaul E. McKenney // Pre-grace-period update-side code is ordered before the grace 806a434dd10SPaul E. McKenney // period via the ->cbs_lock and barriers in rcu_tasks_kthread(). 807a434dd10SPaul E. McKenney // Pre-grace-period read-side code is ordered before the grace period by 808a434dd10SPaul E. McKenney // atomic_dec_and_test() of the count of readers (for IPIed readers) and by 809a434dd10SPaul E. McKenney // scheduler context-switch ordering (for locked-down non-running readers). 810d5f177d3SPaul E. McKenney 811d5f177d3SPaul E. McKenney // The lockdep state must be outside of #ifdef to be useful. 812d5f177d3SPaul E. McKenney #ifdef CONFIG_DEBUG_LOCK_ALLOC 813d5f177d3SPaul E. McKenney static struct lock_class_key rcu_lock_trace_key; 814d5f177d3SPaul E. McKenney struct lockdep_map rcu_trace_lock_map = 815d5f177d3SPaul E. McKenney STATIC_LOCKDEP_MAP_INIT("rcu_read_lock_trace", &rcu_lock_trace_key); 816d5f177d3SPaul E. McKenney EXPORT_SYMBOL_GPL(rcu_trace_lock_map); 817d5f177d3SPaul E. McKenney #endif /* #ifdef CONFIG_DEBUG_LOCK_ALLOC */ 818d5f177d3SPaul E. McKenney 819d5f177d3SPaul E. McKenney #ifdef CONFIG_TASKS_TRACE_RCU 820d5f177d3SPaul E. McKenney 82130d8aa51SPaul E. McKenney static atomic_t trc_n_readers_need_end; // Number of waited-for readers. 82230d8aa51SPaul E. McKenney static DECLARE_WAIT_QUEUE_HEAD(trc_wait); // List of holdout tasks. 823d5f177d3SPaul E. McKenney 824d5f177d3SPaul E. McKenney // Record outstanding IPIs to each CPU. No point in sending two... 825d5f177d3SPaul E. McKenney static DEFINE_PER_CPU(bool, trc_ipi_to_cpu); 826d5f177d3SPaul E. McKenney 82740471509SPaul E. McKenney // The number of detections of task quiescent state relying on 82840471509SPaul E. McKenney // heavyweight readers executing explicit memory barriers. 8296731da9eSPaul E. McKenney static unsigned long n_heavy_reader_attempts; 8306731da9eSPaul E. McKenney static unsigned long n_heavy_reader_updates; 8316731da9eSPaul E. McKenney static unsigned long n_heavy_reader_ofl_updates; 83240471509SPaul E. McKenney 833b0afa0f0SPaul E. McKenney void call_rcu_tasks_trace(struct rcu_head *rhp, rcu_callback_t func); 834b0afa0f0SPaul E. McKenney DEFINE_RCU_TASKS(rcu_tasks_trace, rcu_tasks_wait_gp, call_rcu_tasks_trace, 835b0afa0f0SPaul E. McKenney "RCU Tasks Trace"); 836b0afa0f0SPaul E. McKenney 837b38f57c1SPaul E. McKenney /* 838b38f57c1SPaul E. McKenney * This irq_work handler allows rcu_read_unlock_trace() to be invoked 839b38f57c1SPaul E. McKenney * while the scheduler locks are held. 840b38f57c1SPaul E. McKenney */ 841b38f57c1SPaul E. McKenney static void rcu_read_unlock_iw(struct irq_work *iwp) 842b38f57c1SPaul E. McKenney { 843b38f57c1SPaul E. McKenney wake_up(&trc_wait); 844b38f57c1SPaul E. McKenney } 845b38f57c1SPaul E. McKenney static DEFINE_IRQ_WORK(rcu_tasks_trace_iw, rcu_read_unlock_iw); 846b38f57c1SPaul E. McKenney 847d5f177d3SPaul E. McKenney /* If we are the last reader, wake up the grace-period kthread. */ 848276c4104SPaul E. McKenney void rcu_read_unlock_trace_special(struct task_struct *t, int nesting) 849d5f177d3SPaul E. McKenney { 850276c4104SPaul E. McKenney int nq = t->trc_reader_special.b.need_qs; 851276c4104SPaul E. McKenney 8529ae58d7bSPaul E. McKenney if (IS_ENABLED(CONFIG_TASKS_TRACE_RCU_READ_MB) && 8539ae58d7bSPaul E. McKenney t->trc_reader_special.b.need_mb) 854276c4104SPaul E. McKenney smp_mb(); // Pairs with update-side barriers. 855276c4104SPaul E. McKenney // Update .need_qs before ->trc_reader_nesting for irq/NMI handlers. 856276c4104SPaul E. McKenney if (nq) 857276c4104SPaul E. McKenney WRITE_ONCE(t->trc_reader_special.b.need_qs, false); 858276c4104SPaul E. McKenney WRITE_ONCE(t->trc_reader_nesting, nesting); 859276c4104SPaul E. McKenney if (nq && atomic_dec_and_test(&trc_n_readers_need_end)) 860b38f57c1SPaul E. McKenney irq_work_queue(&rcu_tasks_trace_iw); 861d5f177d3SPaul E. McKenney } 862d5f177d3SPaul E. McKenney EXPORT_SYMBOL_GPL(rcu_read_unlock_trace_special); 863d5f177d3SPaul E. McKenney 864d5f177d3SPaul E. McKenney /* Add a task to the holdout list, if it is not already on the list. */ 865d5f177d3SPaul E. McKenney static void trc_add_holdout(struct task_struct *t, struct list_head *bhp) 866d5f177d3SPaul E. McKenney { 867d5f177d3SPaul E. McKenney if (list_empty(&t->trc_holdout_list)) { 868d5f177d3SPaul E. McKenney get_task_struct(t); 869d5f177d3SPaul E. McKenney list_add(&t->trc_holdout_list, bhp); 870d5f177d3SPaul E. McKenney } 871d5f177d3SPaul E. McKenney } 872d5f177d3SPaul E. McKenney 873d5f177d3SPaul E. McKenney /* Remove a task from the holdout list, if it is in fact present. */ 874d5f177d3SPaul E. McKenney static void trc_del_holdout(struct task_struct *t) 875d5f177d3SPaul E. McKenney { 876d5f177d3SPaul E. McKenney if (!list_empty(&t->trc_holdout_list)) { 877d5f177d3SPaul E. McKenney list_del_init(&t->trc_holdout_list); 878d5f177d3SPaul E. McKenney put_task_struct(t); 879d5f177d3SPaul E. McKenney } 880d5f177d3SPaul E. McKenney } 881d5f177d3SPaul E. McKenney 882d5f177d3SPaul E. McKenney /* IPI handler to check task state. */ 883d5f177d3SPaul E. McKenney static void trc_read_check_handler(void *t_in) 884d5f177d3SPaul E. McKenney { 885d5f177d3SPaul E. McKenney struct task_struct *t = current; 886d5f177d3SPaul E. McKenney struct task_struct *texp = t_in; 887d5f177d3SPaul E. McKenney 888d5f177d3SPaul E. McKenney // If the task is no longer running on this CPU, leave. 889d5f177d3SPaul E. McKenney if (unlikely(texp != t)) { 890d5f177d3SPaul E. McKenney if (WARN_ON_ONCE(atomic_dec_and_test(&trc_n_readers_need_end))) 891d5f177d3SPaul E. McKenney wake_up(&trc_wait); 892d5f177d3SPaul E. McKenney goto reset_ipi; // Already on holdout list, so will check later. 893d5f177d3SPaul E. McKenney } 894d5f177d3SPaul E. McKenney 895d5f177d3SPaul E. McKenney // If the task is not in a read-side critical section, and 896d5f177d3SPaul E. McKenney // if this is the last reader, awaken the grace-period kthread. 897d5f177d3SPaul E. McKenney if (likely(!t->trc_reader_nesting)) { 898d5f177d3SPaul E. McKenney if (WARN_ON_ONCE(atomic_dec_and_test(&trc_n_readers_need_end))) 899d5f177d3SPaul E. McKenney wake_up(&trc_wait); 900d5f177d3SPaul E. McKenney // Mark as checked after decrement to avoid false 901d5f177d3SPaul E. McKenney // positives on the above WARN_ON_ONCE(). 902d5f177d3SPaul E. McKenney WRITE_ONCE(t->trc_reader_checked, true); 903d5f177d3SPaul E. McKenney goto reset_ipi; 904d5f177d3SPaul E. McKenney } 905ba3a86e4SPaul E. McKenney // If we are racing with an rcu_read_unlock_trace(), try again later. 906ba3a86e4SPaul E. McKenney if (unlikely(t->trc_reader_nesting < 0)) { 907ba3a86e4SPaul E. McKenney if (WARN_ON_ONCE(atomic_dec_and_test(&trc_n_readers_need_end))) 908ba3a86e4SPaul E. McKenney wake_up(&trc_wait); 909ba3a86e4SPaul E. McKenney goto reset_ipi; 910ba3a86e4SPaul E. McKenney } 911d5f177d3SPaul E. McKenney WRITE_ONCE(t->trc_reader_checked, true); 912d5f177d3SPaul E. McKenney 913d5f177d3SPaul E. McKenney // Get here if the task is in a read-side critical section. Set 914d5f177d3SPaul E. McKenney // its state so that it will awaken the grace-period kthread upon 915d5f177d3SPaul E. McKenney // exit from that critical section. 916276c4104SPaul E. McKenney WARN_ON_ONCE(t->trc_reader_special.b.need_qs); 917276c4104SPaul E. McKenney WRITE_ONCE(t->trc_reader_special.b.need_qs, true); 918d5f177d3SPaul E. McKenney 919d5f177d3SPaul E. McKenney reset_ipi: 920d5f177d3SPaul E. McKenney // Allow future IPIs to be sent on CPU and for task. 921d5f177d3SPaul E. McKenney // Also order this IPI handler against any later manipulations of 922d5f177d3SPaul E. McKenney // the intended task. 923d5f177d3SPaul E. McKenney smp_store_release(&per_cpu(trc_ipi_to_cpu, smp_processor_id()), false); // ^^^ 924d5f177d3SPaul E. McKenney smp_store_release(&texp->trc_ipi_to_cpu, -1); // ^^^ 925d5f177d3SPaul E. McKenney } 926d5f177d3SPaul E. McKenney 927d5f177d3SPaul E. McKenney /* Callback function for scheduler to check locked-down task. */ 928d5f177d3SPaul E. McKenney static bool trc_inspect_reader(struct task_struct *t, void *arg) 929d5f177d3SPaul E. McKenney { 9307d0c9c50SPaul E. McKenney int cpu = task_cpu(t); 9317d0c9c50SPaul E. McKenney bool in_qs = false; 9327e3b70e0SPaul E. McKenney bool ofl = cpu_is_offline(cpu); 9337d0c9c50SPaul E. McKenney 9347d0c9c50SPaul E. McKenney if (task_curr(t)) { 93530d8aa51SPaul E. McKenney WARN_ON_ONCE(ofl && !is_idle_task(t)); 9367e3b70e0SPaul E. McKenney 9377d0c9c50SPaul E. McKenney // If no chance of heavyweight readers, do it the hard way. 9387e3b70e0SPaul E. McKenney if (!ofl && !IS_ENABLED(CONFIG_TASKS_TRACE_RCU_READ_MB)) 9397d0c9c50SPaul E. McKenney return false; 9407d0c9c50SPaul E. McKenney 9417d0c9c50SPaul E. McKenney // If heavyweight readers are enabled on the remote task, 9427d0c9c50SPaul E. McKenney // we can inspect its state despite its currently running. 9437d0c9c50SPaul E. McKenney // However, we cannot safely change its state. 94440471509SPaul E. McKenney n_heavy_reader_attempts++; 9457e3b70e0SPaul E. McKenney if (!ofl && // Check for "running" idle tasks on offline CPUs. 9467e3b70e0SPaul E. McKenney !rcu_dynticks_zero_in_eqs(cpu, &t->trc_reader_nesting)) 9477d0c9c50SPaul E. McKenney return false; // No quiescent state, do it the hard way. 94840471509SPaul E. McKenney n_heavy_reader_updates++; 949edf3775fSPaul E. McKenney if (ofl) 950edf3775fSPaul E. McKenney n_heavy_reader_ofl_updates++; 9517d0c9c50SPaul E. McKenney in_qs = true; 9527d0c9c50SPaul E. McKenney } else { 9537d0c9c50SPaul E. McKenney in_qs = likely(!t->trc_reader_nesting); 9547d0c9c50SPaul E. McKenney } 955d5f177d3SPaul E. McKenney 956*1d10bf55SPaul E. McKenney // Mark as checked so that the grace-period kthread will 957*1d10bf55SPaul E. McKenney // remove it from the holdout list. 958d5f177d3SPaul E. McKenney t->trc_reader_checked = true; 959d5f177d3SPaul E. McKenney 9607d0c9c50SPaul E. McKenney if (in_qs) 9617d0c9c50SPaul E. McKenney return true; // Already in quiescent state, done!!! 9627d0c9c50SPaul E. McKenney 9637d0c9c50SPaul E. McKenney // The task is in a read-side critical section, so set up its 9647d0c9c50SPaul E. McKenney // state so that it will awaken the grace-period kthread upon exit 9657d0c9c50SPaul E. McKenney // from that critical section. 966d5f177d3SPaul E. McKenney atomic_inc(&trc_n_readers_need_end); // One more to wait on. 967276c4104SPaul E. McKenney WARN_ON_ONCE(t->trc_reader_special.b.need_qs); 968276c4104SPaul E. McKenney WRITE_ONCE(t->trc_reader_special.b.need_qs, true); 969d5f177d3SPaul E. McKenney return true; 970d5f177d3SPaul E. McKenney } 971d5f177d3SPaul E. McKenney 972d5f177d3SPaul E. McKenney /* Attempt to extract the state for the specified task. */ 973d5f177d3SPaul E. McKenney static void trc_wait_for_one_reader(struct task_struct *t, 974d5f177d3SPaul E. McKenney struct list_head *bhp) 975d5f177d3SPaul E. McKenney { 976d5f177d3SPaul E. McKenney int cpu; 977d5f177d3SPaul E. McKenney 978d5f177d3SPaul E. McKenney // If a previous IPI is still in flight, let it complete. 979d5f177d3SPaul E. McKenney if (smp_load_acquire(&t->trc_ipi_to_cpu) != -1) // Order IPI 980d5f177d3SPaul E. McKenney return; 981d5f177d3SPaul E. McKenney 982d5f177d3SPaul E. McKenney // The current task had better be in a quiescent state. 983d5f177d3SPaul E. McKenney if (t == current) { 984d5f177d3SPaul E. McKenney t->trc_reader_checked = true; 985d5f177d3SPaul E. McKenney WARN_ON_ONCE(t->trc_reader_nesting); 986d5f177d3SPaul E. McKenney return; 987d5f177d3SPaul E. McKenney } 988d5f177d3SPaul E. McKenney 989d5f177d3SPaul E. McKenney // Attempt to nail down the task for inspection. 990d5f177d3SPaul E. McKenney get_task_struct(t); 991d5f177d3SPaul E. McKenney if (try_invoke_on_locked_down_task(t, trc_inspect_reader, NULL)) { 992d5f177d3SPaul E. McKenney put_task_struct(t); 993d5f177d3SPaul E. McKenney return; 994d5f177d3SPaul E. McKenney } 995d5f177d3SPaul E. McKenney put_task_struct(t); 996d5f177d3SPaul E. McKenney 997d5f177d3SPaul E. McKenney // If currently running, send an IPI, either way, add to list. 998d5f177d3SPaul E. McKenney trc_add_holdout(t, bhp); 999574de876SPaul E. McKenney if (task_curr(t) && 1000574de876SPaul E. McKenney time_after(jiffies + 1, rcu_tasks_trace.gp_start + rcu_task_ipi_delay)) { 1001d5f177d3SPaul E. McKenney // The task is currently running, so try IPIing it. 1002d5f177d3SPaul E. McKenney cpu = task_cpu(t); 1003d5f177d3SPaul E. McKenney 1004d5f177d3SPaul E. McKenney // If there is already an IPI outstanding, let it happen. 1005d5f177d3SPaul E. McKenney if (per_cpu(trc_ipi_to_cpu, cpu) || t->trc_ipi_to_cpu >= 0) 1006d5f177d3SPaul E. McKenney return; 1007d5f177d3SPaul E. McKenney 1008d5f177d3SPaul E. McKenney atomic_inc(&trc_n_readers_need_end); 1009d5f177d3SPaul E. McKenney per_cpu(trc_ipi_to_cpu, cpu) = true; 1010d5f177d3SPaul E. McKenney t->trc_ipi_to_cpu = cpu; 1011238dbce3SPaul E. McKenney rcu_tasks_trace.n_ipis++; 1012d5f177d3SPaul E. McKenney if (smp_call_function_single(cpu, 1013d5f177d3SPaul E. McKenney trc_read_check_handler, t, 0)) { 1014d5f177d3SPaul E. McKenney // Just in case there is some other reason for 1015d5f177d3SPaul E. McKenney // failure than the target CPU being offline. 10167e0669c3SPaul E. McKenney rcu_tasks_trace.n_ipis_fails++; 1017d5f177d3SPaul E. McKenney per_cpu(trc_ipi_to_cpu, cpu) = false; 1018d5f177d3SPaul E. McKenney t->trc_ipi_to_cpu = cpu; 1019d5f177d3SPaul E. McKenney if (atomic_dec_and_test(&trc_n_readers_need_end)) { 1020d5f177d3SPaul E. McKenney WARN_ON_ONCE(1); 1021d5f177d3SPaul E. McKenney wake_up(&trc_wait); 1022d5f177d3SPaul E. McKenney } 1023d5f177d3SPaul E. McKenney } 1024d5f177d3SPaul E. McKenney } 1025d5f177d3SPaul E. McKenney } 1026d5f177d3SPaul E. McKenney 1027d5f177d3SPaul E. McKenney /* Initialize for a new RCU-tasks-trace grace period. */ 1028d5f177d3SPaul E. McKenney static void rcu_tasks_trace_pregp_step(void) 1029d5f177d3SPaul E. McKenney { 1030d5f177d3SPaul E. McKenney int cpu; 1031d5f177d3SPaul E. McKenney 1032d5f177d3SPaul E. McKenney // Allow for fast-acting IPIs. 1033d5f177d3SPaul E. McKenney atomic_set(&trc_n_readers_need_end, 1); 1034d5f177d3SPaul E. McKenney 1035d5f177d3SPaul E. McKenney // There shouldn't be any old IPIs, but... 1036d5f177d3SPaul E. McKenney for_each_possible_cpu(cpu) 1037d5f177d3SPaul E. McKenney WARN_ON_ONCE(per_cpu(trc_ipi_to_cpu, cpu)); 103881b4a7bcSPaul E. McKenney 103981b4a7bcSPaul E. McKenney // Disable CPU hotplug across the tasklist scan. 104081b4a7bcSPaul E. McKenney // This also waits for all readers in CPU-hotplug code paths. 104181b4a7bcSPaul E. McKenney cpus_read_lock(); 1042d5f177d3SPaul E. McKenney } 1043d5f177d3SPaul E. McKenney 1044d5f177d3SPaul E. McKenney /* Do first-round processing for the specified task. */ 1045d5f177d3SPaul E. McKenney static void rcu_tasks_trace_pertask(struct task_struct *t, 1046d5f177d3SPaul E. McKenney struct list_head *hop) 1047d5f177d3SPaul E. McKenney { 10481b04fa99SUladzislau Rezki (Sony) // During early boot when there is only the one boot CPU, there 10491b04fa99SUladzislau Rezki (Sony) // is no idle task for the other CPUs. Just return. 10501b04fa99SUladzislau Rezki (Sony) if (unlikely(t == NULL)) 10511b04fa99SUladzislau Rezki (Sony) return; 10521b04fa99SUladzislau Rezki (Sony) 1053276c4104SPaul E. McKenney WRITE_ONCE(t->trc_reader_special.b.need_qs, false); 105443766c3eSPaul E. McKenney WRITE_ONCE(t->trc_reader_checked, false); 1055d5f177d3SPaul E. McKenney t->trc_ipi_to_cpu = -1; 1056d5f177d3SPaul E. McKenney trc_wait_for_one_reader(t, hop); 1057d5f177d3SPaul E. McKenney } 1058d5f177d3SPaul E. McKenney 10599796e1aeSPaul E. McKenney /* 10609796e1aeSPaul E. McKenney * Do intermediate processing between task and holdout scans and 10619796e1aeSPaul E. McKenney * pick up the idle tasks. 10629796e1aeSPaul E. McKenney */ 10639796e1aeSPaul E. McKenney static void rcu_tasks_trace_postscan(struct list_head *hop) 1064d5f177d3SPaul E. McKenney { 10659796e1aeSPaul E. McKenney int cpu; 10669796e1aeSPaul E. McKenney 10679796e1aeSPaul E. McKenney for_each_possible_cpu(cpu) 10689796e1aeSPaul E. McKenney rcu_tasks_trace_pertask(idle_task(cpu), hop); 10699796e1aeSPaul E. McKenney 107081b4a7bcSPaul E. McKenney // Re-enable CPU hotplug now that the tasklist scan has completed. 107181b4a7bcSPaul E. McKenney cpus_read_unlock(); 107281b4a7bcSPaul E. McKenney 1073d5f177d3SPaul E. McKenney // Wait for late-stage exiting tasks to finish exiting. 1074d5f177d3SPaul E. McKenney // These might have passed the call to exit_tasks_rcu_finish(). 1075d5f177d3SPaul E. McKenney synchronize_rcu(); 1076d5f177d3SPaul E. McKenney // Any tasks that exit after this point will set ->trc_reader_checked. 1077d5f177d3SPaul E. McKenney } 1078d5f177d3SPaul E. McKenney 10794593e772SPaul E. McKenney /* Show the state of a task stalling the current RCU tasks trace GP. */ 10804593e772SPaul E. McKenney static void show_stalled_task_trace(struct task_struct *t, bool *firstreport) 10814593e772SPaul E. McKenney { 10824593e772SPaul E. McKenney int cpu; 10834593e772SPaul E. McKenney 10844593e772SPaul E. McKenney if (*firstreport) { 10854593e772SPaul E. McKenney pr_err("INFO: rcu_tasks_trace detected stalls on tasks:\n"); 10864593e772SPaul E. McKenney *firstreport = false; 10874593e772SPaul E. McKenney } 10884593e772SPaul E. McKenney // FIXME: This should attempt to use try_invoke_on_nonrunning_task(). 10894593e772SPaul E. McKenney cpu = task_cpu(t); 10904593e772SPaul E. McKenney pr_alert("P%d: %c%c%c nesting: %d%c cpu: %d\n", 10914593e772SPaul E. McKenney t->pid, 10924593e772SPaul E. McKenney ".I"[READ_ONCE(t->trc_ipi_to_cpu) > 0], 10934593e772SPaul E. McKenney ".i"[is_idle_task(t)], 10944593e772SPaul E. McKenney ".N"[cpu > 0 && tick_nohz_full_cpu(cpu)], 10954593e772SPaul E. McKenney t->trc_reader_nesting, 1096276c4104SPaul E. McKenney " N"[!!t->trc_reader_special.b.need_qs], 10974593e772SPaul E. McKenney cpu); 10984593e772SPaul E. McKenney sched_show_task(t); 10994593e772SPaul E. McKenney } 11004593e772SPaul E. McKenney 11014593e772SPaul E. McKenney /* List stalled IPIs for RCU tasks trace. */ 11024593e772SPaul E. McKenney static void show_stalled_ipi_trace(void) 11034593e772SPaul E. McKenney { 11044593e772SPaul E. McKenney int cpu; 11054593e772SPaul E. McKenney 11064593e772SPaul E. McKenney for_each_possible_cpu(cpu) 11074593e772SPaul E. McKenney if (per_cpu(trc_ipi_to_cpu, cpu)) 11084593e772SPaul E. McKenney pr_alert("\tIPI outstanding to CPU %d\n", cpu); 11094593e772SPaul E. McKenney } 11104593e772SPaul E. McKenney 1111d5f177d3SPaul E. McKenney /* Do one scan of the holdout list. */ 1112d5f177d3SPaul E. McKenney static void check_all_holdout_tasks_trace(struct list_head *hop, 11134593e772SPaul E. McKenney bool needreport, bool *firstreport) 1114d5f177d3SPaul E. McKenney { 1115d5f177d3SPaul E. McKenney struct task_struct *g, *t; 1116d5f177d3SPaul E. McKenney 111781b4a7bcSPaul E. McKenney // Disable CPU hotplug across the holdout list scan. 111881b4a7bcSPaul E. McKenney cpus_read_lock(); 111981b4a7bcSPaul E. McKenney 1120d5f177d3SPaul E. McKenney list_for_each_entry_safe(t, g, hop, trc_holdout_list) { 1121d5f177d3SPaul E. McKenney // If safe and needed, try to check the current task. 1122d5f177d3SPaul E. McKenney if (READ_ONCE(t->trc_ipi_to_cpu) == -1 && 1123d5f177d3SPaul E. McKenney !READ_ONCE(t->trc_reader_checked)) 1124d5f177d3SPaul E. McKenney trc_wait_for_one_reader(t, hop); 1125d5f177d3SPaul E. McKenney 1126d5f177d3SPaul E. McKenney // If check succeeded, remove this task from the list. 1127d5f177d3SPaul E. McKenney if (READ_ONCE(t->trc_reader_checked)) 1128d5f177d3SPaul E. McKenney trc_del_holdout(t); 11294593e772SPaul E. McKenney else if (needreport) 11304593e772SPaul E. McKenney show_stalled_task_trace(t, firstreport); 11314593e772SPaul E. McKenney } 113281b4a7bcSPaul E. McKenney 113381b4a7bcSPaul E. McKenney // Re-enable CPU hotplug now that the holdout list scan has completed. 113481b4a7bcSPaul E. McKenney cpus_read_unlock(); 113581b4a7bcSPaul E. McKenney 11364593e772SPaul E. McKenney if (needreport) { 11374593e772SPaul E. McKenney if (firstreport) 11384593e772SPaul E. McKenney pr_err("INFO: rcu_tasks_trace detected stalls? (Late IPI?)\n"); 11394593e772SPaul E. McKenney show_stalled_ipi_trace(); 1140d5f177d3SPaul E. McKenney } 1141d5f177d3SPaul E. McKenney } 1142d5f177d3SPaul E. McKenney 1143d5f177d3SPaul E. McKenney /* Wait for grace period to complete and provide ordering. */ 1144af051ca4SPaul E. McKenney static void rcu_tasks_trace_postgp(struct rcu_tasks *rtp) 1145d5f177d3SPaul E. McKenney { 11464593e772SPaul E. McKenney bool firstreport; 11474593e772SPaul E. McKenney struct task_struct *g, *t; 11484593e772SPaul E. McKenney LIST_HEAD(holdouts); 11494593e772SPaul E. McKenney long ret; 11504593e772SPaul E. McKenney 1151d5f177d3SPaul E. McKenney // Remove the safety count. 1152d5f177d3SPaul E. McKenney smp_mb__before_atomic(); // Order vs. earlier atomics 1153d5f177d3SPaul E. McKenney atomic_dec(&trc_n_readers_need_end); 1154d5f177d3SPaul E. McKenney smp_mb__after_atomic(); // Order vs. later atomics 1155d5f177d3SPaul E. McKenney 1156d5f177d3SPaul E. McKenney // Wait for readers. 1157af051ca4SPaul E. McKenney set_tasks_gp_state(rtp, RTGS_WAIT_READERS); 11584593e772SPaul E. McKenney for (;;) { 11594593e772SPaul E. McKenney ret = wait_event_idle_exclusive_timeout( 11604593e772SPaul E. McKenney trc_wait, 11614593e772SPaul E. McKenney atomic_read(&trc_n_readers_need_end) == 0, 11624593e772SPaul E. McKenney READ_ONCE(rcu_task_stall_timeout)); 11634593e772SPaul E. McKenney if (ret) 11644593e772SPaul E. McKenney break; // Count reached zero. 1165af051ca4SPaul E. McKenney // Stall warning time, so make a list of the offenders. 1166f747c7e1SPaul E. McKenney rcu_read_lock(); 11674593e772SPaul E. McKenney for_each_process_thread(g, t) 1168276c4104SPaul E. McKenney if (READ_ONCE(t->trc_reader_special.b.need_qs)) 11694593e772SPaul E. McKenney trc_add_holdout(t, &holdouts); 1170f747c7e1SPaul E. McKenney rcu_read_unlock(); 11714593e772SPaul E. McKenney firstreport = true; 1172592031ccSPaul E. McKenney list_for_each_entry_safe(t, g, &holdouts, trc_holdout_list) { 1173592031ccSPaul E. McKenney if (READ_ONCE(t->trc_reader_special.b.need_qs)) 11744593e772SPaul E. McKenney show_stalled_task_trace(t, &firstreport); 1175592031ccSPaul E. McKenney trc_del_holdout(t); // Release task_struct reference. 11764593e772SPaul E. McKenney } 11774593e772SPaul E. McKenney if (firstreport) 11784593e772SPaul E. McKenney pr_err("INFO: rcu_tasks_trace detected stalls? (Counter/taskslist mismatch?)\n"); 11794593e772SPaul E. McKenney show_stalled_ipi_trace(); 11804593e772SPaul E. McKenney pr_err("\t%d holdouts\n", atomic_read(&trc_n_readers_need_end)); 11814593e772SPaul E. McKenney } 1182d5f177d3SPaul E. McKenney smp_mb(); // Caller's code must be ordered after wakeup. 118343766c3eSPaul E. McKenney // Pairs with pretty much every ordering primitive. 1184d5f177d3SPaul E. McKenney } 1185d5f177d3SPaul E. McKenney 1186d5f177d3SPaul E. McKenney /* Report any needed quiescent state for this exiting task. */ 118725246fc8SPaul E. McKenney static void exit_tasks_rcu_finish_trace(struct task_struct *t) 1188d5f177d3SPaul E. McKenney { 1189d5f177d3SPaul E. McKenney WRITE_ONCE(t->trc_reader_checked, true); 1190d5f177d3SPaul E. McKenney WARN_ON_ONCE(t->trc_reader_nesting); 1191d5f177d3SPaul E. McKenney WRITE_ONCE(t->trc_reader_nesting, 0); 1192276c4104SPaul E. McKenney if (WARN_ON_ONCE(READ_ONCE(t->trc_reader_special.b.need_qs))) 1193276c4104SPaul E. McKenney rcu_read_unlock_trace_special(t, 0); 1194d5f177d3SPaul E. McKenney } 1195d5f177d3SPaul E. McKenney 1196d5f177d3SPaul E. McKenney /** 1197d5f177d3SPaul E. McKenney * call_rcu_tasks_trace() - Queue a callback trace task-based grace period 1198d5f177d3SPaul E. McKenney * @rhp: structure to be used for queueing the RCU updates. 1199d5f177d3SPaul E. McKenney * @func: actual callback function to be invoked after the grace period 1200d5f177d3SPaul E. McKenney * 1201d5f177d3SPaul E. McKenney * The callback function will be invoked some time after a full grace 1202d5f177d3SPaul E. McKenney * period elapses, in other words after all currently executing RCU 1203d5f177d3SPaul E. McKenney * read-side critical sections have completed. call_rcu_tasks_trace() 1204d5f177d3SPaul E. McKenney * assumes that the read-side critical sections end at context switch, 1205d5f177d3SPaul E. McKenney * cond_resched_rcu_qs(), or transition to usermode execution. As such, 1206d5f177d3SPaul E. McKenney * there are no read-side primitives analogous to rcu_read_lock() and 1207d5f177d3SPaul E. McKenney * rcu_read_unlock() because this primitive is intended to determine 1208d5f177d3SPaul E. McKenney * that all tasks have passed through a safe state, not so much for 1209a616aec9SIngo Molnar * data-structure synchronization. 1210d5f177d3SPaul E. McKenney * 1211d5f177d3SPaul E. McKenney * See the description of call_rcu() for more detailed information on 1212d5f177d3SPaul E. McKenney * memory ordering guarantees. 1213d5f177d3SPaul E. McKenney */ 1214d5f177d3SPaul E. McKenney void call_rcu_tasks_trace(struct rcu_head *rhp, rcu_callback_t func) 1215d5f177d3SPaul E. McKenney { 1216d5f177d3SPaul E. McKenney call_rcu_tasks_generic(rhp, func, &rcu_tasks_trace); 1217d5f177d3SPaul E. McKenney } 1218d5f177d3SPaul E. McKenney EXPORT_SYMBOL_GPL(call_rcu_tasks_trace); 1219d5f177d3SPaul E. McKenney 1220d5f177d3SPaul E. McKenney /** 1221d5f177d3SPaul E. McKenney * synchronize_rcu_tasks_trace - wait for a trace rcu-tasks grace period 1222d5f177d3SPaul E. McKenney * 1223d5f177d3SPaul E. McKenney * Control will return to the caller some time after a trace rcu-tasks 1224c7dcf810SPaul E. McKenney * grace period has elapsed, in other words after all currently executing 1225c7dcf810SPaul E. McKenney * rcu-tasks read-side critical sections have elapsed. These read-side 1226c7dcf810SPaul E. McKenney * critical sections are delimited by calls to rcu_read_lock_trace() 1227c7dcf810SPaul E. McKenney * and rcu_read_unlock_trace(). 1228d5f177d3SPaul E. McKenney * 1229d5f177d3SPaul E. McKenney * This is a very specialized primitive, intended only for a few uses in 1230d5f177d3SPaul E. McKenney * tracing and other situations requiring manipulation of function preambles 1231d5f177d3SPaul E. McKenney * and profiling hooks. The synchronize_rcu_tasks_trace() function is not 1232d5f177d3SPaul E. McKenney * (yet) intended for heavy use from multiple CPUs. 1233d5f177d3SPaul E. McKenney * 1234d5f177d3SPaul E. McKenney * See the description of synchronize_rcu() for more detailed information 1235d5f177d3SPaul E. McKenney * on memory ordering guarantees. 1236d5f177d3SPaul E. McKenney */ 1237d5f177d3SPaul E. McKenney void synchronize_rcu_tasks_trace(void) 1238d5f177d3SPaul E. McKenney { 1239d5f177d3SPaul E. McKenney RCU_LOCKDEP_WARN(lock_is_held(&rcu_trace_lock_map), "Illegal synchronize_rcu_tasks_trace() in RCU Tasks Trace read-side critical section"); 1240d5f177d3SPaul E. McKenney synchronize_rcu_tasks_generic(&rcu_tasks_trace); 1241d5f177d3SPaul E. McKenney } 1242d5f177d3SPaul E. McKenney EXPORT_SYMBOL_GPL(synchronize_rcu_tasks_trace); 1243d5f177d3SPaul E. McKenney 1244d5f177d3SPaul E. McKenney /** 1245d5f177d3SPaul E. McKenney * rcu_barrier_tasks_trace - Wait for in-flight call_rcu_tasks_trace() callbacks. 1246d5f177d3SPaul E. McKenney * 1247d5f177d3SPaul E. McKenney * Although the current implementation is guaranteed to wait, it is not 1248d5f177d3SPaul E. McKenney * obligated to, for example, if there are no pending callbacks. 1249d5f177d3SPaul E. McKenney */ 1250d5f177d3SPaul E. McKenney void rcu_barrier_tasks_trace(void) 1251d5f177d3SPaul E. McKenney { 1252d5f177d3SPaul E. McKenney /* There is only one callback queue, so this is easy. ;-) */ 1253d5f177d3SPaul E. McKenney synchronize_rcu_tasks_trace(); 1254d5f177d3SPaul E. McKenney } 1255d5f177d3SPaul E. McKenney EXPORT_SYMBOL_GPL(rcu_barrier_tasks_trace); 1256d5f177d3SPaul E. McKenney 1257d5f177d3SPaul E. McKenney static int __init rcu_spawn_tasks_trace_kthread(void) 1258d5f177d3SPaul E. McKenney { 12592393a613SPaul E. McKenney if (IS_ENABLED(CONFIG_TASKS_TRACE_RCU_READ_MB)) { 12604fe192dfSPaul E. McKenney rcu_tasks_trace.gp_sleep = HZ / 10; 126175dc2da5SPaul E. McKenney rcu_tasks_trace.init_fract = HZ / 10; 12622393a613SPaul E. McKenney } else { 12634fe192dfSPaul E. McKenney rcu_tasks_trace.gp_sleep = HZ / 200; 12644fe192dfSPaul E. McKenney if (rcu_tasks_trace.gp_sleep <= 0) 12654fe192dfSPaul E. McKenney rcu_tasks_trace.gp_sleep = 1; 126675dc2da5SPaul E. McKenney rcu_tasks_trace.init_fract = HZ / 200; 12672393a613SPaul E. McKenney if (rcu_tasks_trace.init_fract <= 0) 12682393a613SPaul E. McKenney rcu_tasks_trace.init_fract = 1; 12692393a613SPaul E. McKenney } 1270d5f177d3SPaul E. McKenney rcu_tasks_trace.pregp_func = rcu_tasks_trace_pregp_step; 1271d5f177d3SPaul E. McKenney rcu_tasks_trace.pertask_func = rcu_tasks_trace_pertask; 1272d5f177d3SPaul E. McKenney rcu_tasks_trace.postscan_func = rcu_tasks_trace_postscan; 1273d5f177d3SPaul E. McKenney rcu_tasks_trace.holdouts_func = check_all_holdout_tasks_trace; 1274d5f177d3SPaul E. McKenney rcu_tasks_trace.postgp_func = rcu_tasks_trace_postgp; 1275d5f177d3SPaul E. McKenney rcu_spawn_tasks_kthread_generic(&rcu_tasks_trace); 1276d5f177d3SPaul E. McKenney return 0; 1277d5f177d3SPaul E. McKenney } 1278d5f177d3SPaul E. McKenney 127927c0f144SPaul E. McKenney #if !defined(CONFIG_TINY_RCU) 128027c0f144SPaul E. McKenney void show_rcu_tasks_trace_gp_kthread(void) 1281e21408ceSPaul E. McKenney { 128240471509SPaul E. McKenney char buf[64]; 1283e21408ceSPaul E. McKenney 1284edf3775fSPaul E. McKenney sprintf(buf, "N%d h:%lu/%lu/%lu", atomic_read(&trc_n_readers_need_end), 1285edf3775fSPaul E. McKenney data_race(n_heavy_reader_ofl_updates), 128640471509SPaul E. McKenney data_race(n_heavy_reader_updates), 128740471509SPaul E. McKenney data_race(n_heavy_reader_attempts)); 1288e21408ceSPaul E. McKenney show_rcu_tasks_generic_gp_kthread(&rcu_tasks_trace, buf); 1289e21408ceSPaul E. McKenney } 129027c0f144SPaul E. McKenney EXPORT_SYMBOL_GPL(show_rcu_tasks_trace_gp_kthread); 129127c0f144SPaul E. McKenney #endif // !defined(CONFIG_TINY_RCU) 1292e21408ceSPaul E. McKenney 1293d5f177d3SPaul E. McKenney #else /* #ifdef CONFIG_TASKS_TRACE_RCU */ 129425246fc8SPaul E. McKenney static void exit_tasks_rcu_finish_trace(struct task_struct *t) { } 1295d5f177d3SPaul E. McKenney #endif /* #else #ifdef CONFIG_TASKS_TRACE_RCU */ 12968fd8ca38SPaul E. McKenney 12978344496eSPaul E. McKenney #ifndef CONFIG_TINY_RCU 1298e21408ceSPaul E. McKenney void show_rcu_tasks_gp_kthreads(void) 1299e21408ceSPaul E. McKenney { 1300e21408ceSPaul E. McKenney show_rcu_tasks_classic_gp_kthread(); 1301e21408ceSPaul E. McKenney show_rcu_tasks_rude_gp_kthread(); 1302e21408ceSPaul E. McKenney show_rcu_tasks_trace_gp_kthread(); 1303e21408ceSPaul E. McKenney } 13048344496eSPaul E. McKenney #endif /* #ifndef CONFIG_TINY_RCU */ 1305e21408ceSPaul E. McKenney 1306bfba7ed0SUladzislau Rezki (Sony) #ifdef CONFIG_PROVE_RCU 1307bfba7ed0SUladzislau Rezki (Sony) struct rcu_tasks_test_desc { 1308bfba7ed0SUladzislau Rezki (Sony) struct rcu_head rh; 1309bfba7ed0SUladzislau Rezki (Sony) const char *name; 1310bfba7ed0SUladzislau Rezki (Sony) bool notrun; 1311bfba7ed0SUladzislau Rezki (Sony) }; 1312bfba7ed0SUladzislau Rezki (Sony) 1313bfba7ed0SUladzislau Rezki (Sony) static struct rcu_tasks_test_desc tests[] = { 1314bfba7ed0SUladzislau Rezki (Sony) { 1315bfba7ed0SUladzislau Rezki (Sony) .name = "call_rcu_tasks()", 1316bfba7ed0SUladzislau Rezki (Sony) /* If not defined, the test is skipped. */ 1317bfba7ed0SUladzislau Rezki (Sony) .notrun = !IS_ENABLED(CONFIG_TASKS_RCU), 1318bfba7ed0SUladzislau Rezki (Sony) }, 1319bfba7ed0SUladzislau Rezki (Sony) { 1320bfba7ed0SUladzislau Rezki (Sony) .name = "call_rcu_tasks_rude()", 1321bfba7ed0SUladzislau Rezki (Sony) /* If not defined, the test is skipped. */ 1322bfba7ed0SUladzislau Rezki (Sony) .notrun = !IS_ENABLED(CONFIG_TASKS_RUDE_RCU), 1323bfba7ed0SUladzislau Rezki (Sony) }, 1324bfba7ed0SUladzislau Rezki (Sony) { 1325bfba7ed0SUladzislau Rezki (Sony) .name = "call_rcu_tasks_trace()", 1326bfba7ed0SUladzislau Rezki (Sony) /* If not defined, the test is skipped. */ 1327bfba7ed0SUladzislau Rezki (Sony) .notrun = !IS_ENABLED(CONFIG_TASKS_TRACE_RCU) 1328bfba7ed0SUladzislau Rezki (Sony) } 1329bfba7ed0SUladzislau Rezki (Sony) }; 1330bfba7ed0SUladzislau Rezki (Sony) 1331bfba7ed0SUladzislau Rezki (Sony) static void test_rcu_tasks_callback(struct rcu_head *rhp) 1332bfba7ed0SUladzislau Rezki (Sony) { 1333bfba7ed0SUladzislau Rezki (Sony) struct rcu_tasks_test_desc *rttd = 1334bfba7ed0SUladzislau Rezki (Sony) container_of(rhp, struct rcu_tasks_test_desc, rh); 1335bfba7ed0SUladzislau Rezki (Sony) 1336bfba7ed0SUladzislau Rezki (Sony) pr_info("Callback from %s invoked.\n", rttd->name); 1337bfba7ed0SUladzislau Rezki (Sony) 1338bfba7ed0SUladzislau Rezki (Sony) rttd->notrun = true; 1339bfba7ed0SUladzislau Rezki (Sony) } 1340bfba7ed0SUladzislau Rezki (Sony) 1341bfba7ed0SUladzislau Rezki (Sony) static void rcu_tasks_initiate_self_tests(void) 1342bfba7ed0SUladzislau Rezki (Sony) { 1343bfba7ed0SUladzislau Rezki (Sony) pr_info("Running RCU-tasks wait API self tests\n"); 1344bfba7ed0SUladzislau Rezki (Sony) #ifdef CONFIG_TASKS_RCU 1345bfba7ed0SUladzislau Rezki (Sony) synchronize_rcu_tasks(); 1346bfba7ed0SUladzislau Rezki (Sony) call_rcu_tasks(&tests[0].rh, test_rcu_tasks_callback); 1347bfba7ed0SUladzislau Rezki (Sony) #endif 1348bfba7ed0SUladzislau Rezki (Sony) 1349bfba7ed0SUladzislau Rezki (Sony) #ifdef CONFIG_TASKS_RUDE_RCU 1350bfba7ed0SUladzislau Rezki (Sony) synchronize_rcu_tasks_rude(); 1351bfba7ed0SUladzislau Rezki (Sony) call_rcu_tasks_rude(&tests[1].rh, test_rcu_tasks_callback); 1352bfba7ed0SUladzislau Rezki (Sony) #endif 1353bfba7ed0SUladzislau Rezki (Sony) 1354bfba7ed0SUladzislau Rezki (Sony) #ifdef CONFIG_TASKS_TRACE_RCU 1355bfba7ed0SUladzislau Rezki (Sony) synchronize_rcu_tasks_trace(); 1356bfba7ed0SUladzislau Rezki (Sony) call_rcu_tasks_trace(&tests[2].rh, test_rcu_tasks_callback); 1357bfba7ed0SUladzislau Rezki (Sony) #endif 1358bfba7ed0SUladzislau Rezki (Sony) } 1359bfba7ed0SUladzislau Rezki (Sony) 1360bfba7ed0SUladzislau Rezki (Sony) static int rcu_tasks_verify_self_tests(void) 1361bfba7ed0SUladzislau Rezki (Sony) { 1362bfba7ed0SUladzislau Rezki (Sony) int ret = 0; 1363bfba7ed0SUladzislau Rezki (Sony) int i; 1364bfba7ed0SUladzislau Rezki (Sony) 1365bfba7ed0SUladzislau Rezki (Sony) for (i = 0; i < ARRAY_SIZE(tests); i++) { 1366bfba7ed0SUladzislau Rezki (Sony) if (!tests[i].notrun) { // still hanging. 1367bfba7ed0SUladzislau Rezki (Sony) pr_err("%s has been failed.\n", tests[i].name); 1368bfba7ed0SUladzislau Rezki (Sony) ret = -1; 1369bfba7ed0SUladzislau Rezki (Sony) } 1370bfba7ed0SUladzislau Rezki (Sony) } 1371bfba7ed0SUladzislau Rezki (Sony) 1372bfba7ed0SUladzislau Rezki (Sony) if (ret) 1373bfba7ed0SUladzislau Rezki (Sony) WARN_ON(1); 1374bfba7ed0SUladzislau Rezki (Sony) 1375bfba7ed0SUladzislau Rezki (Sony) return ret; 1376bfba7ed0SUladzislau Rezki (Sony) } 1377bfba7ed0SUladzislau Rezki (Sony) late_initcall(rcu_tasks_verify_self_tests); 1378bfba7ed0SUladzislau Rezki (Sony) #else /* #ifdef CONFIG_PROVE_RCU */ 1379bfba7ed0SUladzislau Rezki (Sony) static void rcu_tasks_initiate_self_tests(void) { } 1380bfba7ed0SUladzislau Rezki (Sony) #endif /* #else #ifdef CONFIG_PROVE_RCU */ 1381bfba7ed0SUladzislau Rezki (Sony) 13821b04fa99SUladzislau Rezki (Sony) void __init rcu_init_tasks_generic(void) 13831b04fa99SUladzislau Rezki (Sony) { 13841b04fa99SUladzislau Rezki (Sony) #ifdef CONFIG_TASKS_RCU 13851b04fa99SUladzislau Rezki (Sony) rcu_spawn_tasks_kthread(); 13861b04fa99SUladzislau Rezki (Sony) #endif 13871b04fa99SUladzislau Rezki (Sony) 13881b04fa99SUladzislau Rezki (Sony) #ifdef CONFIG_TASKS_RUDE_RCU 13891b04fa99SUladzislau Rezki (Sony) rcu_spawn_tasks_rude_kthread(); 13901b04fa99SUladzislau Rezki (Sony) #endif 13911b04fa99SUladzislau Rezki (Sony) 13921b04fa99SUladzislau Rezki (Sony) #ifdef CONFIG_TASKS_TRACE_RCU 13931b04fa99SUladzislau Rezki (Sony) rcu_spawn_tasks_trace_kthread(); 13941b04fa99SUladzislau Rezki (Sony) #endif 1395bfba7ed0SUladzislau Rezki (Sony) 1396bfba7ed0SUladzislau Rezki (Sony) // Run the self-tests. 1397bfba7ed0SUladzislau Rezki (Sony) rcu_tasks_initiate_self_tests(); 13981b04fa99SUladzislau Rezki (Sony) } 13991b04fa99SUladzislau Rezki (Sony) 14008fd8ca38SPaul E. McKenney #else /* #ifdef CONFIG_TASKS_RCU_GENERIC */ 14018fd8ca38SPaul E. McKenney static inline void rcu_tasks_bootup_oddness(void) {} 14028fd8ca38SPaul E. McKenney #endif /* #else #ifdef CONFIG_TASKS_RCU_GENERIC */ 1403