| 1 | |
| 2 | |
| 3 | * Sleepable Read-Copy Update mechanism for mutual exclusion,
|
| 4 | * tiny version for non-preemptible single-CPU use.
|
| 5 | *
|
| 6 | * Copyright (C) IBM Corporation, 2017
|
| 7 | *
|
| 8 | * Author: Paul McKenney <[email protected]>
|
| 9 |
|
| 10 |
|
| 11 | #include <linux/export.h>
|
| 12 | #include <linux/irq_work.h>
|
| 13 | #include <linux/mutex.h>
|
| 14 | #include <linux/preempt.h>
|
| 15 | #include <linux/rcupdate_wait.h>
|
| 16 | #include <linux/sched.h>
|
| 17 | #include <linux/delay.h>
|
| 18 | #include <linux/srcu.h>
|
| 19 |
|
| 20 | #include <linux/rcu_node_tree.h>
|
| 21 | #include "rcu_segcblist.h"
|
| 22 | #include "rcu.h"
|
| 23 |
|
| 24 | #ifndef CONFIG_TREE_RCU
|
| 25 | int rcu_scheduler_active __read_mostly;
|
| 26 | #else
|
| 27 | extern int rcu_scheduler_active;
|
| 28 | #endif |
| 29 | static LIST_HEAD(srcu_boot_list);
|
| 30 | static bool srcu_init_done;
|
| 31 |
|
| 32 | static int init_srcu_struct_fields(struct srcu_struct *ssp)
|
| 33 | {
|
| 34 | ssp->srcu_lock_nesting[0] = 0;
|
| 35 | ssp->srcu_lock_nesting[1] = 0;
|
| 36 | init_swait_queue_head(&ssp->srcu_wq);
|
| 37 | ssp->srcu_cb_head = NULL;
|
| 38 | ssp->srcu_cb_tail = &ssp->srcu_cb_head;
|
| 39 | ssp->srcu_gp_running = false;
|
| 40 | ssp->srcu_gp_waiting = false;
|
| 41 | ssp->srcu_idx = 0;
|
| 42 | ssp->srcu_idx_max = 0;
|
| 43 | INIT_WORK(&ssp->srcu_work, srcu_drive_gp);
|
| 44 | INIT_LIST_HEAD(&ssp->srcu_work.entry);
|
| 45 | init_irq_work(&ssp->srcu_irq_work, srcu_tiny_irq_work);
|
| 46 | return 0;
|
| 47 | }
|
| 48 |
|
| 49 | #ifdef CONFIG_DEBUG_LOCK_ALLOC
|
| 50 |
|
| 51 | int init_srcu_struct_lockdep(struct srcu_struct *ssp, const char *name,
|
| 52 | struct lock_class_key *key)
|
| 53 | {
|
| 54 |
|
| 55 | debug_check_no_locks_freed((void *)ssp, sizeof(*ssp));
|
| 56 | lockdep_init_map(&ssp->dep_map, name, key, 0);
|
| 57 | return init_srcu_struct_fields(ssp);
|
| 58 | }
|
| 59 | EXPORT_SYMBOL_GPL(init_srcu_struct_lockdep);
|
| 60 |
|
| 61 | #else
|
| 62 |
|
| 63 | |
| 64 | * init_srcu_struct_generic - initialize a sleep-RCU structure
|
| 65 | * @ssp: structure to initialize.
|
| 66 | *
|
| 67 | * Must invoke this on a given srcu_struct before passing that srcu_struct
|
| 68 | * to any other function. Each srcu_struct represents a separate domain
|
| 69 | * of SRCU protection.
|
| 70 |
|
| 71 | int init_srcu_struct_generic(struct srcu_struct *ssp)
|
| 72 | {
|
| 73 | return init_srcu_struct_fields(ssp);
|
| 74 | }
|
| 75 | EXPORT_SYMBOL_GPL(init_srcu_struct_generic);
|
| 76 |
|
| 77 | #endif
|
| 78 |
|
| 79 | |
| 80 | * cleanup_srcu_struct - deconstruct a sleep-RCU structure
|
| 81 | * @ssp: structure to clean up.
|
| 82 | *
|
| 83 | * Must invoke this after you are finished using a given srcu_struct that
|
| 84 | * was initialized via init_srcu_struct(), else you leak memory.
|
| 85 |
|
| 86 | void cleanup_srcu_struct(struct srcu_struct *ssp)
|
| 87 | {
|
| 88 | WARN_ON(srcu_readers_active(ssp));
|
| 89 | irq_work_sync(&ssp->srcu_irq_work);
|
| 90 | flush_work(&ssp->srcu_work);
|
| 91 | WARN_ON(ssp->srcu_gp_running);
|
| 92 | WARN_ON(ssp->srcu_gp_waiting);
|
| 93 | WARN_ON(ssp->srcu_cb_head);
|
| 94 | WARN_ON(&ssp->srcu_cb_head != ssp->srcu_cb_tail);
|
| 95 | WARN_ON(ssp->srcu_idx != ssp->srcu_idx_max);
|
| 96 | WARN_ON(ssp->srcu_idx & 0x1);
|
| 97 | }
|
| 98 | EXPORT_SYMBOL_GPL(cleanup_srcu_struct);
|
| 99 |
|
| 100 | |
| 101 | * Removes the count for the old reader from the appropriate element of
|
| 102 | * the srcu_struct.
|
| 103 |
|
| 104 | void __srcu_read_unlock(struct srcu_struct *ssp, int idx)
|
| 105 | {
|
| 106 | int newval;
|
| 107 |
|
| 108 | preempt_disable(); |
| 109 | newval = READ_ONCE(ssp->srcu_lock_nesting[idx]) - 1;
|
| 110 | WRITE_ONCE(ssp->srcu_lock_nesting[idx], newval);
|
| 111 | preempt_enable();
|
| 112 | if (!newval && READ_ONCE(ssp->srcu_gp_waiting) && in_task() && !irqs_disabled())
|
| 113 | swake_up_one(&ssp->srcu_wq);
|
| 114 | }
|
| 115 | EXPORT_SYMBOL_GPL(__srcu_read_unlock);
|
| 116 |
|
| 117 | |
| 118 | * Workqueue handler to drive one grace period and invoke any callbacks
|
| 119 | * that become ready as a result. Single-CPU operation and preemption
|
| 120 | * disabling mean that we get away with murder on synchronization. ;-)
|
| 121 |
|
| 122 | void srcu_drive_gp(struct work_struct *wp)
|
| 123 | {
|
| 124 | int idx;
|
| 125 | struct rcu_head *lh;
|
| 126 | struct rcu_head *rhp;
|
| 127 | struct srcu_struct *ssp;
|
| 128 |
|
| 129 | ssp = container_of(wp, struct srcu_struct, srcu_work);
|
| 130 | preempt_disable(); |
| 131 | if (ssp->srcu_gp_running || ULONG_CMP_GE(ssp->srcu_idx, READ_ONCE(ssp->srcu_idx_max))) {
|
| 132 | preempt_enable();
|
| 133 | return;
|
| 134 | }
|
| 135 |
|
| 136 |
|
| 137 | WRITE_ONCE(ssp->srcu_gp_running, true);
|
| 138 | local_irq_disable();
|
| 139 | lh = ssp->srcu_cb_head;
|
| 140 | ssp->srcu_cb_head = NULL;
|
| 141 | ssp->srcu_cb_tail = &ssp->srcu_cb_head;
|
| 142 | local_irq_enable();
|
| 143 | idx = (ssp->srcu_idx & 0x2) / 2;
|
| 144 | WRITE_ONCE(ssp->srcu_idx, ssp->srcu_idx + 1);
|
| 145 | WRITE_ONCE(ssp->srcu_gp_waiting, true);
|
| 146 | preempt_enable();
|
| 147 | do {
|
| 148 | |
| 149 | |
| 150 | swait_event_timeout_exclusive(ssp->srcu_wq,
|
| 151 | !READ_ONCE(ssp->srcu_lock_nesting[idx]), HZ / 10);
|
| 152 | } while (READ_ONCE(ssp->srcu_lock_nesting[idx]));
|
| 153 | preempt_disable(); |
| 154 | WRITE_ONCE(ssp->srcu_gp_waiting, false);
|
| 155 | WRITE_ONCE(ssp->srcu_idx, ssp->srcu_idx + 1);
|
| 156 | preempt_enable();
|
| 157 |
|
| 158 |
|
| 159 | while (lh) {
|
| 160 | rhp = lh;
|
| 161 | lh = lh->next;
|
| 162 | debug_rcu_head_callback(rhp);
|
| 163 | local_bh_disable();
|
| 164 | rhp->func(rhp);
|
| 165 | local_bh_enable();
|
| 166 | }
|
| 167 |
|
| 168 | |
| 169 | * Enable rescheduling, and if there are more callbacks,
|
| 170 | * reschedule ourselves. This can race with a call_srcu()
|
| 171 | * at interrupt level, but the ->srcu_gp_running checks will
|
| 172 | * straighten that out.
|
| 173 |
|
| 174 | preempt_disable(); |
| 175 | WRITE_ONCE(ssp->srcu_gp_running, false);
|
| 176 | idx = ULONG_CMP_LT(ssp->srcu_idx, READ_ONCE(ssp->srcu_idx_max));
|
| 177 | preempt_enable();
|
| 178 | if (idx)
|
| 179 | schedule_work(&ssp->srcu_work);
|
| 180 | }
|
| 181 | EXPORT_SYMBOL_GPL(srcu_drive_gp);
|
| 182 |
|
| 183 | |
| 184 | * Use an irq_work to defer schedule_work() to avoid acquiring the workqueue
|
| 185 | * pool->lock while the caller might hold scheduler locks, causing lockdep
|
| 186 | * splats due to workqueue_init() doing a wakeup.
|
| 187 |
|
| 188 | void srcu_tiny_irq_work(struct irq_work *irq_work)
|
| 189 | {
|
| 190 | struct srcu_struct *ssp;
|
| 191 |
|
| 192 | ssp = container_of(irq_work, struct srcu_struct, srcu_irq_work);
|
| 193 | schedule_work(&ssp->srcu_work);
|
| 194 | }
|
| 195 | EXPORT_SYMBOL_GPL(srcu_tiny_irq_work);
|
| 196 |
|
| 197 | static void srcu_gp_start_if_needed(struct srcu_struct *ssp)
|
| 198 | {
|
| 199 | unsigned long cookie;
|
| 200 |
|
| 201 | lockdep_assert_preemption_disabled(); |
| 202 | cookie = get_state_synchronize_srcu(ssp);
|
| 203 | if (ULONG_CMP_GE(READ_ONCE(ssp->srcu_idx_max), cookie)) {
|
| 204 | return;
|
| 205 | }
|
| 206 | WRITE_ONCE(ssp->srcu_idx_max, cookie);
|
| 207 | if (!READ_ONCE(ssp->srcu_gp_running)) {
|
| 208 | if (likely(srcu_init_done))
|
| 209 | irq_work_queue(&ssp->srcu_irq_work);
|
| 210 | else if (list_empty(&ssp->srcu_work.entry))
|
| 211 | list_add(&ssp->srcu_work.entry, &srcu_boot_list);
|
| 212 | }
|
| 213 | }
|
| 214 |
|
| 215 | |
| 216 | * Enqueue an SRCU callback on the specified srcu_struct structure,
|
| 217 | * initiating grace-period processing if it is not already running.
|
| 218 |
|
| 219 | void call_srcu(struct srcu_struct *ssp, struct rcu_head *rhp,
|
| 220 | rcu_callback_t func)
|
| 221 | {
|
| 222 | unsigned long flags;
|
| 223 |
|
| 224 | rhp->func = func;
|
| 225 | rhp->next = NULL;
|
| 226 | preempt_disable(); |
| 227 | local_irq_save(flags);
|
| 228 | *ssp->srcu_cb_tail = rhp;
|
| 229 | ssp->srcu_cb_tail = &rhp->next;
|
| 230 | local_irq_restore(flags);
|
| 231 | srcu_gp_start_if_needed(ssp);
|
| 232 | preempt_enable();
|
| 233 | }
|
| 234 | EXPORT_SYMBOL_GPL(call_srcu);
|
| 235 |
|
| 236 | |
| 237 | * synchronize_srcu - wait for prior SRCU read-side critical-section completion
|
| 238 |
|
| 239 | void synchronize_srcu(struct srcu_struct *ssp)
|
| 240 | {
|
| 241 | struct rcu_synchronize rs;
|
| 242 |
|
| 243 | srcu_lock_sync(&ssp->dep_map);
|
| 244 |
|
| 245 | RCU_LOCKDEP_WARN(lockdep_is_held(ssp) ||
|
| 246 | lock_is_held(&rcu_bh_lock_map) ||
|
| 247 | lock_is_held(&rcu_lock_map) ||
|
| 248 | lock_is_held(&rcu_sched_lock_map),
|
| 249 | "Illegal synchronize_srcu() in same-type SRCU (or in RCU) read-side critical section");
|
| 250 |
|
| 251 | if (rcu_scheduler_active == RCU_SCHEDULER_INACTIVE)
|
| 252 | return;
|
| 253 |
|
| 254 | might_sleep();
|
| 255 | init_rcu_head_on_stack(&rs.head);
|
| 256 | init_completion(&rs.completion);
|
| 257 | call_srcu(ssp, &rs.head, wakeme_after_rcu);
|
| 258 | wait_for_completion(&rs.completion);
|
| 259 | destroy_rcu_head_on_stack(&rs.head);
|
| 260 | }
|
| 261 | EXPORT_SYMBOL_GPL(synchronize_srcu);
|
| 262 |
|
| 263 | |
| 264 | * get_state_synchronize_srcu - Provide an end-of-grace-period cookie
|
| 265 |
|
| 266 | unsigned long get_state_synchronize_srcu(struct srcu_struct *ssp)
|
| 267 | {
|
| 268 | unsigned long ret;
|
| 269 |
|
| 270 | barrier();
|
| 271 | ret = (READ_ONCE(ssp->srcu_idx) + 3) & ~0x1;
|
| 272 | barrier();
|
| 273 | return ret;
|
| 274 | }
|
| 275 | EXPORT_SYMBOL_GPL(get_state_synchronize_srcu);
|
| 276 |
|
| 277 | |
| 278 | * start_poll_synchronize_srcu - Provide cookie and start grace period
|
| 279 | *
|
| 280 | * The difference between this and get_state_synchronize_srcu() is that
|
| 281 | * this function ensures that the poll_state_synchronize_srcu() will
|
| 282 | * eventually return the value true.
|
| 283 |
|
| 284 | unsigned long start_poll_synchronize_srcu(struct srcu_struct *ssp)
|
| 285 | {
|
| 286 | unsigned long ret;
|
| 287 |
|
| 288 | preempt_disable(); |
| 289 | ret = get_state_synchronize_srcu(ssp);
|
| 290 | srcu_gp_start_if_needed(ssp);
|
| 291 | preempt_enable();
|
| 292 | return ret;
|
| 293 | }
|
| 294 | EXPORT_SYMBOL_GPL(start_poll_synchronize_srcu);
|
| 295 |
|
| 296 | |
| 297 | * poll_state_synchronize_srcu - Has cookie's grace period ended?
|
| 298 |
|
| 299 | bool poll_state_synchronize_srcu(struct srcu_struct *ssp, unsigned long cookie)
|
| 300 | {
|
| 301 | unsigned long cur_s = READ_ONCE(ssp->srcu_idx);
|
| 302 |
|
| 303 | barrier();
|
| 304 | return cookie == SRCU_GET_STATE_COMPLETED ||
|
| 305 | ULONG_CMP_GE(cur_s, cookie) || ULONG_CMP_LT(cur_s, cookie - 3);
|
| 306 | }
|
| 307 | EXPORT_SYMBOL_GPL(poll_state_synchronize_srcu);
|
| 308 |
|
| 309 | #ifndef CONFIG_TREE_RCU
|
| 310 |
|
| 311 | void __init rcu_scheduler_starting(void)
|
| 312 | {
|
| 313 | rcu_scheduler_active = RCU_SCHEDULER_RUNNING;
|
| 314 | }
|
| 315 | #endif |
| 316 |
|
| 317 | |
| 318 | * Queue work for srcu_struct structures with early boot callbacks.
|
| 319 | * The work won't actually execute until the workqueue initialization
|
| 320 | * phase that takes place after the scheduler starts.
|
| 321 |
|
| 322 | void __init srcu_init(void)
|
| 323 | {
|
| 324 | struct srcu_struct *ssp;
|
| 325 |
|
| 326 | srcu_init_done = true;
|
| 327 | while (!list_empty(&srcu_boot_list)) {
|
| 328 | ssp = list_first_entry(&srcu_boot_list,
|
| 329 | struct srcu_struct, srcu_work.entry);
|
| 330 | list_del_init(&ssp->srcu_work.entry);
|
| 331 | schedule_work(&ssp->srcu_work);
|
| 332 | }
|
| 333 | }
|