| 1 |
|
| 2 | |
| 3 | * Sleepable Read-Copy Update mechanism for mutual exclusion,
|
| 4 | * tree variant.
|
| 5 | *
|
| 6 | * Copyright (C) IBM Corporation, 2017
|
| 7 | *
|
| 8 | * Author: Paul McKenney <[email protected]>
|
| 9 |
|
| 10 |
|
| 11 | #ifndef _LINUX_SRCU_TREE_H
|
| 12 | #define _LINUX_SRCU_TREE_H
|
| 13 |
|
| 14 | #include <linux/rcu_node_tree.h>
|
| 15 | #include <linux/completion.h>
|
| 16 |
|
| 17 | struct srcu_node;
|
| 18 | struct srcu_struct;
|
| 19 |
|
| 20 | |
| 21 | * Per-CPU structure feeding into leaf srcu_node, similar in function
|
| 22 | * to rcu_node.
|
| 23 |
|
| 24 | struct srcu_data {
|
| 25 |
|
| 26 | atomic_long_t srcu_lock_count[2];
|
| 27 | atomic_long_t srcu_unlock_count[2];
|
| 28 | int srcu_nmi_safety;
|
| 29 |
|
| 30 |
|
| 31 | spinlock_t __private lock ____cacheline_internodealigned_in_smp;
|
| 32 | struct rcu_segcblist srcu_cblist;
|
| 33 | unsigned long srcu_gp_seq_needed;
|
| 34 | unsigned long srcu_gp_seq_needed_exp;
|
| 35 | bool srcu_cblist_invoking;
|
| 36 | struct timer_list delay_work;
|
| 37 | struct work_struct work;
|
| 38 | struct rcu_head srcu_barrier_head;
|
| 39 | struct srcu_node *mynode;
|
| 40 | unsigned long grpmask;
|
| 41 |
|
| 42 | int cpu;
|
| 43 | struct srcu_struct *ssp;
|
| 44 | };
|
| 45 |
|
| 46 | |
| 47 | * Node in SRCU combining tree, similar in function to rcu_data.
|
| 48 |
|
| 49 | struct srcu_node {
|
| 50 | spinlock_t __private lock;
|
| 51 | unsigned long srcu_have_cbs[4];
|
| 52 |
|
| 53 | unsigned long srcu_data_have_cbs[4];
|
| 54 | unsigned long srcu_gp_seq_needed_exp;
|
| 55 | struct srcu_node *srcu_parent;
|
| 56 | int grplo;
|
| 57 | int grphi;
|
| 58 | };
|
| 59 |
|
| 60 | |
| 61 | * Per-SRCU-domain structure, similar in function to rcu_state.
|
| 62 |
|
| 63 | struct srcu_struct {
|
| 64 | struct srcu_node *node;
|
| 65 | struct srcu_node *level[RCU_NUM_LVLS + 1];
|
| 66 |
|
| 67 | int srcu_size_state;
|
| 68 | struct mutex srcu_cb_mutex;
|
| 69 | spinlock_t __private lock;
|
| 70 | struct mutex srcu_gp_mutex;
|
| 71 | unsigned int srcu_idx;
|
| 72 | unsigned long srcu_gp_seq;
|
| 73 | unsigned long srcu_gp_seq_needed;
|
| 74 | unsigned long srcu_gp_seq_needed_exp;
|
| 75 | unsigned long srcu_gp_start;
|
| 76 | unsigned long srcu_last_gp_end;
|
| 77 | unsigned long srcu_size_jiffies;
|
| 78 | unsigned long srcu_n_lock_retries;
|
| 79 | unsigned long srcu_n_exp_nodelay;
|
| 80 | struct srcu_data __percpu *sda;
|
| 81 | bool sda_is_static;
|
| 82 | unsigned long srcu_barrier_seq;
|
| 83 | struct mutex srcu_barrier_mutex;
|
| 84 | struct completion srcu_barrier_completion;
|
| 85 |
|
| 86 | atomic_t srcu_barrier_cpu_cnt;
|
| 87 |
|
| 88 |
|
| 89 | unsigned long reschedule_jiffies;
|
| 90 | unsigned long reschedule_count;
|
| 91 | struct delayed_work work;
|
| 92 | struct lockdep_map dep_map;
|
| 93 | };
|
| 94 |
|
| 95 |
|
| 96 | #define SRCU_SIZE_SMALL 0
|
| 97 | #define SRCU_SIZE_ALLOC 1
|
| 98 | #define SRCU_SIZE_WAIT_BARRIER 2
|
| 99 | #define SRCU_SIZE_WAIT_CALL 3
|
| 100 | #define SRCU_SIZE_WAIT_CBS1 4
|
| 101 | #define SRCU_SIZE_WAIT_CBS2 5
|
| 102 | #define SRCU_SIZE_WAIT_CBS3 6
|
| 103 | #define SRCU_SIZE_WAIT_CBS4 7
|
| 104 | #define SRCU_SIZE_BIG 8
|
| 105 |
|
| 106 |
|
| 107 | #define SRCU_STATE_IDLE 0
|
| 108 | #define SRCU_STATE_SCAN1 1
|
| 109 | #define SRCU_STATE_SCAN2 2
|
| 110 |
|
| 111 | #define __SRCU_STRUCT_INIT(name, pcpu_name) \
|
| 112 | { \
|
| 113 | .sda = &pcpu_name, \
|
| 114 | .lock = __SPIN_LOCK_UNLOCKED(name.lock), \
|
| 115 | .srcu_gp_seq_needed = -1UL, \
|
| 116 | .work = __DELAYED_WORK_INITIALIZER(name.work, NULL, 0), \
|
| 117 | __SRCU_DEP_MAP_INIT(name) \
|
| 118 | }
|
| 119 |
|
| 120 | |
| 121 | * Define and initialize a srcu struct at build time.
|
| 122 | * Do -not- call init_srcu_struct() nor cleanup_srcu_struct() on it.
|
| 123 | *
|
| 124 | * Note that although DEFINE_STATIC_SRCU() hides the name from other
|
| 125 | * files, the per-CPU variable rules nevertheless require that the
|
| 126 | * chosen name be globally unique. These rules also prohibit use of
|
| 127 | * DEFINE_STATIC_SRCU() within a function. If these rules are too
|
| 128 | * restrictive, declare the srcu_struct manually. For example, in
|
| 129 | * each file:
|
| 130 | *
|
| 131 | * static struct srcu_struct my_srcu;
|
| 132 | *
|
| 133 | * Then, before the first use of each my_srcu, manually initialize it:
|
| 134 | *
|
| 135 | * init_srcu_struct(&my_srcu);
|
| 136 | *
|
| 137 | * See include/linux/percpu-defs.h for the rules on per-CPU variables.
|
| 138 |
|
| 139 | #ifdef MODULE
|
| 140 | # define __DEFINE_SRCU(name, is_static) \
|
| 141 | is_static struct srcu_struct name; \
|
| 142 | extern struct srcu_struct * const __srcu_struct_##name; \
|
| 143 | struct srcu_struct * const __srcu_struct_##name \
|
| 144 | __section("___srcu_struct_ptrs") = &name
|
| 145 | #else
|
| 146 | # define __DEFINE_SRCU(name, is_static) \
|
| 147 | static DEFINE_PER_CPU(struct srcu_data, name##_srcu_data); \
|
| 148 | is_static struct srcu_struct name = \
|
| 149 | __SRCU_STRUCT_INIT(name, name##_srcu_data)
|
| 150 | #endif
|
| 151 | #define DEFINE_SRCU(name) __DEFINE_SRCU(name, )
|
| 152 | #define DEFINE_STATIC_SRCU(name) __DEFINE_SRCU(name, static)
|
| 153 |
|
| 154 | void synchronize_srcu_expedited(struct srcu_struct *ssp);
|
| 155 | void srcu_barrier(struct srcu_struct *ssp);
|
| 156 | void srcu_torture_stats_print(struct srcu_struct *ssp, char *tt, char *tf);
|
| 157 |
|
| 158 | #endif
|