18c366db0SPaul E. McKenney /* SPDX-License-Identifier: GPL-2.0+ */ 2d8be8173SPaul E. McKenney /* 3d8be8173SPaul E. McKenney * Sleepable Read-Copy Update mechanism for mutual exclusion, 4d8be8173SPaul E. McKenney * tree variant. 5d8be8173SPaul E. McKenney * 6d8be8173SPaul E. McKenney * Copyright (C) IBM Corporation, 2017 7d8be8173SPaul E. McKenney * 88c366db0SPaul E. McKenney * Author: Paul McKenney <paulmck@linux.ibm.com> 9d8be8173SPaul E. McKenney */ 10d8be8173SPaul E. McKenney 11d8be8173SPaul E. McKenney #ifndef _LINUX_SRCU_TREE_H 12d8be8173SPaul E. McKenney #define _LINUX_SRCU_TREE_H 13d8be8173SPaul E. McKenney 14da915ad5SPaul E. McKenney #include <linux/rcu_node_tree.h> 15da915ad5SPaul E. McKenney #include <linux/completion.h> 16da915ad5SPaul E. McKenney 17da915ad5SPaul E. McKenney struct srcu_node; 18da915ad5SPaul E. McKenney struct srcu_struct; 19da915ad5SPaul E. McKenney 20da915ad5SPaul E. McKenney /* 21da915ad5SPaul E. McKenney * Per-CPU structure feeding into leaf srcu_node, similar in function 22da915ad5SPaul E. McKenney * to rcu_node. 23da915ad5SPaul E. McKenney */ 24da915ad5SPaul E. McKenney struct srcu_data { 25da915ad5SPaul E. McKenney /* Read-side state. */ 265d0f5953SPaul E. McKenney atomic_long_t srcu_lock_count[2]; /* Locks per CPU. */ 275d0f5953SPaul E. McKenney atomic_long_t srcu_unlock_count[2]; /* Unlocks per CPU. */ 2827120e7dSPaul E. McKenney int srcu_nmi_safety; /* NMI-safe srcu_struct structure? */ 29da915ad5SPaul E. McKenney 30da915ad5SPaul E. McKenney /* Update-side state. */ 31d6331980SPaul E. McKenney spinlock_t __private lock ____cacheline_internodealigned_in_smp; 32da915ad5SPaul E. McKenney struct rcu_segcblist srcu_cblist; /* List of callbacks.*/ 33da915ad5SPaul E. McKenney unsigned long srcu_gp_seq_needed; /* Furthest future GP needed. */ 341e9a038bSPaul E. McKenney unsigned long srcu_gp_seq_needed_exp; /* Furthest future exp GP. */ 35da915ad5SPaul E. McKenney bool srcu_cblist_invoking; /* Invoking these CBs? */ 36e81baf4cSSebastian Andrzej Siewior struct timer_list delay_work; /* Delay for CB invoking */ 37e81baf4cSSebastian Andrzej Siewior struct work_struct work; /* Context for CB invoking. */ 38da915ad5SPaul E. McKenney struct rcu_head srcu_barrier_head; /* For srcu_barrier() use. */ 39da915ad5SPaul E. McKenney struct srcu_node *mynode; /* Leaf srcu_node. */ 40c7e88067SPaul E. McKenney unsigned long grpmask; /* Mask for leaf srcu_node */ 41c7e88067SPaul E. McKenney /* ->srcu_data_have_cbs[]. */ 42da915ad5SPaul E. McKenney int cpu; 43aacb5d91SPaul E. McKenney struct srcu_struct *ssp; 44d8be8173SPaul E. McKenney }; 45d8be8173SPaul E. McKenney 46da915ad5SPaul E. McKenney /* 47da915ad5SPaul E. McKenney * Node in SRCU combining tree, similar in function to rcu_data. 48da915ad5SPaul E. McKenney */ 49da915ad5SPaul E. McKenney struct srcu_node { 50d6331980SPaul E. McKenney spinlock_t __private lock; 5195ebe80dSPaul E. McKenney unsigned long srcu_have_cbs[4]; /* GP seq for children having CBs, but only */ 52aa5210f5SPingfan Liu /* if greater than ->srcu_gp_seq. */ 5395ebe80dSPaul E. McKenney unsigned long srcu_data_have_cbs[4]; /* Which srcu_data structs have CBs for given GP? */ 541e9a038bSPaul E. McKenney unsigned long srcu_gp_seq_needed_exp; /* Furthest future exp GP. */ 55da915ad5SPaul E. McKenney struct srcu_node *srcu_parent; /* Next up in tree. */ 56da915ad5SPaul E. McKenney int grplo; /* Least CPU for node. */ 57da915ad5SPaul E. McKenney int grphi; /* Biggest CPU for node. */ 58da915ad5SPaul E. McKenney }; 59da915ad5SPaul E. McKenney 60da915ad5SPaul E. McKenney /* 6195433f72SPaul E. McKenney * Per-SRCU-domain structure, update-side data linked from srcu_struct. 62da915ad5SPaul E. McKenney */ 6395433f72SPaul E. McKenney struct srcu_usage { 642ec30311SPaul E. McKenney struct srcu_node *node; /* Combining tree. */ 65da915ad5SPaul E. McKenney struct srcu_node *level[RCU_NUM_LVLS + 1]; 66da915ad5SPaul E. McKenney /* First node at each level. */ 67994f7068SPaul E. McKenney int srcu_size_state; /* Small-to-big transition state. */ 68da915ad5SPaul E. McKenney struct mutex srcu_cb_mutex; /* Serialize CB preparation. */ 69994f7068SPaul E. McKenney spinlock_t __private lock; /* Protect counters and size state. */ 70da915ad5SPaul E. McKenney struct mutex srcu_gp_mutex; /* Serialize GP work. */ 71da915ad5SPaul E. McKenney unsigned long srcu_gp_seq; /* Grace-period seq #. */ 72da915ad5SPaul E. McKenney unsigned long srcu_gp_seq_needed; /* Latest gp_seq needed. */ 731e9a038bSPaul E. McKenney unsigned long srcu_gp_seq_needed_exp; /* Furthest future exp GP. */ 74282d8998SPaul E. McKenney unsigned long srcu_gp_start; /* Last GP start timestamp (jiffies) */ 7522607d66SPaul E. McKenney unsigned long srcu_last_gp_end; /* Last GP end timestamp (ns) */ 769f2e91d9SPaul E. McKenney unsigned long srcu_size_jiffies; /* Current contention-measurement interval. */ 779f2e91d9SPaul E. McKenney unsigned long srcu_n_lock_retries; /* Contention events in current interval. */ 78282d8998SPaul E. McKenney unsigned long srcu_n_exp_nodelay; /* # expedited no-delays in current GP phase. */ 7946470cf8SPaul E. McKenney bool sda_is_static; /* May ->sda be passed to free_percpu()? */ 80da915ad5SPaul E. McKenney unsigned long srcu_barrier_seq; /* srcu_barrier seq #. */ 81da915ad5SPaul E. McKenney struct mutex srcu_barrier_mutex; /* Serialize barrier ops. */ 82da915ad5SPaul E. McKenney struct completion srcu_barrier_completion; 83da915ad5SPaul E. McKenney /* Awaken barrier rq at end. */ 84da915ad5SPaul E. McKenney atomic_t srcu_barrier_cpu_cnt; /* # CPUs not yet posting a */ 85da915ad5SPaul E. McKenney /* callback for the barrier */ 86da915ad5SPaul E. McKenney /* operation. */ 87282d8998SPaul E. McKenney unsigned long reschedule_jiffies; 88282d8998SPaul E. McKenney unsigned long reschedule_count; 89d8be8173SPaul E. McKenney struct delayed_work work; 90fd1b3f8eSPaul E. McKenney struct srcu_struct *srcu_ssp; 91d8be8173SPaul E. McKenney }; 92d8be8173SPaul E. McKenney 9395433f72SPaul E. McKenney /* 94d8be8173SPaul E. McKenney * Per-SRCU-domain structure, similar in function to rcu_state. 95d8be8173SPaul E. McKenney */ 96d8be8173SPaul E. McKenney struct srcu_struct { 97d8be8173SPaul E. McKenney unsigned int srcu_idx; /* Current rdr array element. */ 98d8be8173SPaul E. McKenney struct srcu_data __percpu *sda; /* Per-CPU srcu_data array. */ 99d8be8173SPaul E. McKenney struct lockdep_map dep_map; 10095433f72SPaul E. McKenney struct srcu_usage *srcu_sup; /* Update-side data. */ 101d8be8173SPaul E. McKenney }; 102d8be8173SPaul E. McKenney 103*e15a1930SPingfan Liu // Values for size state variable (->srcu_size_state). Once the state 104*e15a1930SPingfan Liu // has been set to SRCU_SIZE_ALLOC, the grace-period code advances through 105*e15a1930SPingfan Liu // this state machine one step per grace period until the SRCU_SIZE_BIG state 106*e15a1930SPingfan Liu // is reached. Otherwise, the state machine remains in the SRCU_SIZE_SMALL 107*e15a1930SPingfan Liu // state indefinitely. 108*e15a1930SPingfan Liu #define SRCU_SIZE_SMALL 0 // No srcu_node combining tree, ->node == NULL 109*e15a1930SPingfan Liu #define SRCU_SIZE_ALLOC 1 // An srcu_node tree is being allocated, initialized, 110*e15a1930SPingfan Liu // and then referenced by ->node. It will not be used. 111*e15a1930SPingfan Liu #define SRCU_SIZE_WAIT_BARRIER 2 // The srcu_node tree starts being used by everything 112*e15a1930SPingfan Liu // except call_srcu(), especially by srcu_barrier(). 113*e15a1930SPingfan Liu // By the end of this state, all CPUs and threads 114*e15a1930SPingfan Liu // are aware of this tree's existence. 115*e15a1930SPingfan Liu #define SRCU_SIZE_WAIT_CALL 3 // The srcu_node tree starts being used by call_srcu(). 116*e15a1930SPingfan Liu // By the end of this state, all of the call_srcu() 117*e15a1930SPingfan Liu // invocations that were running on a non-boot CPU 118*e15a1930SPingfan Liu // and using the boot CPU's callback queue will have 119*e15a1930SPingfan Liu // completed. 120*e15a1930SPingfan Liu #define SRCU_SIZE_WAIT_CBS1 4 // Don't trust the ->srcu_have_cbs[] grace-period 121*e15a1930SPingfan Liu #define SRCU_SIZE_WAIT_CBS2 5 // sequence elements or the ->srcu_data_have_cbs[] 122*e15a1930SPingfan Liu #define SRCU_SIZE_WAIT_CBS3 6 // CPU-bitmask elements until all four elements of 123*e15a1930SPingfan Liu #define SRCU_SIZE_WAIT_CBS4 7 // each array have been initialized. 124*e15a1930SPingfan Liu #define SRCU_SIZE_BIG 8 // The srcu_node combining tree is fully initialized 125*e15a1930SPingfan Liu // and all aspects of it are being put to use. 126994f7068SPaul E. McKenney 127da915ad5SPaul E. McKenney /* Values for state variable (bottom bits of ->srcu_gp_seq). */ 128d8be8173SPaul E. McKenney #define SRCU_STATE_IDLE 0 129d8be8173SPaul E. McKenney #define SRCU_STATE_SCAN1 1 130d8be8173SPaul E. McKenney #define SRCU_STATE_SCAN2 2 131d8be8173SPaul E. McKenney 13203200b5cSPaul E. McKenney #define __SRCU_USAGE_INIT(name) \ 133d8be8173SPaul E. McKenney { \ 134d6331980SPaul E. McKenney .lock = __SPIN_LOCK_UNLOCKED(name.lock), \ 135e0fcba9aSPaul E. McKenney .srcu_gp_seq_needed = -1UL, \ 1364e6ea4efSPaul E. McKenney .work = __DELAYED_WORK_INITIALIZER(name.work, NULL, 0), \ 13703200b5cSPaul E. McKenney } 13803200b5cSPaul E. McKenney 13903200b5cSPaul E. McKenney #define __SRCU_STRUCT_INIT_COMMON(name, usage_name) \ 14095433f72SPaul E. McKenney .srcu_sup = &usage_name, \ 141f4d01a25SPaul E. McKenney __SRCU_DEP_MAP_INIT(name) 142f4d01a25SPaul E. McKenney 14395433f72SPaul E. McKenney #define __SRCU_STRUCT_INIT_MODULE(name, usage_name) \ 144f4d01a25SPaul E. McKenney { \ 14595433f72SPaul E. McKenney __SRCU_STRUCT_INIT_COMMON(name, usage_name) \ 146d8be8173SPaul E. McKenney } 147d8be8173SPaul E. McKenney 14895433f72SPaul E. McKenney #define __SRCU_STRUCT_INIT(name, usage_name, pcpu_name) \ 149f4d01a25SPaul E. McKenney { \ 150f4d01a25SPaul E. McKenney .sda = &pcpu_name, \ 15195433f72SPaul E. McKenney __SRCU_STRUCT_INIT_COMMON(name, usage_name) \ 152d8be8173SPaul E. McKenney } 153d8be8173SPaul E. McKenney 154d8be8173SPaul E. McKenney /* 155d8be8173SPaul E. McKenney * Define and initialize a srcu struct at build time. 156d8be8173SPaul E. McKenney * Do -not- call init_srcu_struct() nor cleanup_srcu_struct() on it. 157d8be8173SPaul E. McKenney * 158d8be8173SPaul E. McKenney * Note that although DEFINE_STATIC_SRCU() hides the name from other 159d8be8173SPaul E. McKenney * files, the per-CPU variable rules nevertheless require that the 160d8be8173SPaul E. McKenney * chosen name be globally unique. These rules also prohibit use of 161d8be8173SPaul E. McKenney * DEFINE_STATIC_SRCU() within a function. If these rules are too 162d8be8173SPaul E. McKenney * restrictive, declare the srcu_struct manually. For example, in 163d8be8173SPaul E. McKenney * each file: 164d8be8173SPaul E. McKenney * 165d8be8173SPaul E. McKenney * static struct srcu_struct my_srcu; 166d8be8173SPaul E. McKenney * 167d8be8173SPaul E. McKenney * Then, before the first use of each my_srcu, manually initialize it: 168d8be8173SPaul E. McKenney * 169d8be8173SPaul E. McKenney * init_srcu_struct(&my_srcu); 170d8be8173SPaul E. McKenney * 171d8be8173SPaul E. McKenney * See include/linux/percpu-defs.h for the rules on per-CPU variables. 172d8be8173SPaul E. McKenney */ 173fe15b50cSPaul E. McKenney #ifdef MODULE 174fe15b50cSPaul E. McKenney # define __DEFINE_SRCU(name, is_static) \ 17503200b5cSPaul E. McKenney static struct srcu_usage name##_srcu_usage = __SRCU_USAGE_INIT(name##_srcu_usage); \ 17695433f72SPaul E. McKenney is_static struct srcu_struct name = __SRCU_STRUCT_INIT_MODULE(name, name##_srcu_usage); \ 177db8f1471SAlexander Aring extern struct srcu_struct * const __srcu_struct_##name; \ 178056b89e7SJoel Fernandes (Google) struct srcu_struct * const __srcu_struct_##name \ 179fe15b50cSPaul E. McKenney __section("___srcu_struct_ptrs") = &name 180fe15b50cSPaul E. McKenney #else 181d8be8173SPaul E. McKenney # define __DEFINE_SRCU(name, is_static) \ 182da915ad5SPaul E. McKenney static DEFINE_PER_CPU(struct srcu_data, name##_srcu_data); \ 18303200b5cSPaul E. McKenney static struct srcu_usage name##_srcu_usage = __SRCU_USAGE_INIT(name##_srcu_usage); \ 184fe15b50cSPaul E. McKenney is_static struct srcu_struct name = \ 18595433f72SPaul E. McKenney __SRCU_STRUCT_INIT(name, name##_srcu_usage, name##_srcu_data) 186fe15b50cSPaul E. McKenney #endif 187d8be8173SPaul E. McKenney #define DEFINE_SRCU(name) __DEFINE_SRCU(name, /* not static */) 188d8be8173SPaul E. McKenney #define DEFINE_STATIC_SRCU(name) __DEFINE_SRCU(name, static) 189d8be8173SPaul E. McKenney 190aacb5d91SPaul E. McKenney void synchronize_srcu_expedited(struct srcu_struct *ssp); 191aacb5d91SPaul E. McKenney void srcu_barrier(struct srcu_struct *ssp); 192aacb5d91SPaul E. McKenney void srcu_torture_stats_print(struct srcu_struct *ssp, char *tt, char *tf); 193d8be8173SPaul E. McKenney 194d8be8173SPaul E. McKenney #endif 195