| .. | .. |
|---|
| 1 | +/* SPDX-License-Identifier: GPL-2.0+ */ |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Read-Copy Update definitions shared among RCU implementations. |
|---|
| 3 | 4 | * |
|---|
| 4 | | - * This program is free software; you can redistribute it and/or modify |
|---|
| 5 | | - * it under the terms of the GNU General Public License as published by |
|---|
| 6 | | - * the Free Software Foundation; either version 2 of the License, or |
|---|
| 7 | | - * (at your option) any later version. |
|---|
| 8 | | - * |
|---|
| 9 | | - * This program is distributed in the hope that it will be useful, |
|---|
| 10 | | - * but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 11 | | - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 12 | | - * GNU General Public License for more details. |
|---|
| 13 | | - * |
|---|
| 14 | | - * You should have received a copy of the GNU General Public License |
|---|
| 15 | | - * along with this program; if not, you can access it online at |
|---|
| 16 | | - * http://www.gnu.org/licenses/gpl-2.0.html. |
|---|
| 17 | | - * |
|---|
| 18 | 5 | * Copyright IBM Corporation, 2011 |
|---|
| 19 | 6 | * |
|---|
| 20 | | - * Author: Paul E. McKenney <paulmck@linux.vnet.ibm.com> |
|---|
| 7 | + * Author: Paul E. McKenney <paulmck@linux.ibm.com> |
|---|
| 21 | 8 | */ |
|---|
| 22 | 9 | |
|---|
| 23 | 10 | #ifndef __LINUX_RCU_H |
|---|
| 24 | 11 | #define __LINUX_RCU_H |
|---|
| 25 | 12 | |
|---|
| 26 | 13 | #include <trace/events/rcu.h> |
|---|
| 27 | | -#ifdef CONFIG_RCU_TRACE |
|---|
| 28 | | -#define RCU_TRACE(stmt) stmt |
|---|
| 29 | | -#else /* #ifdef CONFIG_RCU_TRACE */ |
|---|
| 30 | | -#define RCU_TRACE(stmt) |
|---|
| 31 | | -#endif /* #else #ifdef CONFIG_RCU_TRACE */ |
|---|
| 32 | 14 | |
|---|
| 33 | | -/* Offset to allow for unmatched rcu_irq_{enter,exit}(). */ |
|---|
| 15 | +/* Offset to allow distinguishing irq vs. task-based idle entry/exit. */ |
|---|
| 34 | 16 | #define DYNTICK_IRQ_NONIDLE ((LONG_MAX / 2) + 1) |
|---|
| 35 | 17 | |
|---|
| 36 | 18 | |
|---|
| .. | .. |
|---|
| 176 | 158 | |
|---|
| 177 | 159 | /* |
|---|
| 178 | 160 | * debug_rcu_head_queue()/debug_rcu_head_unqueue() are used internally |
|---|
| 179 | | - * by call_rcu() and rcu callback execution, and are therefore not part of the |
|---|
| 180 | | - * RCU API. Leaving in rcupdate.h because they are used by all RCU flavors. |
|---|
| 161 | + * by call_rcu() and rcu callback execution, and are therefore not part |
|---|
| 162 | + * of the RCU API. These are in rcupdate.h because they are used by all |
|---|
| 163 | + * RCU implementations. |
|---|
| 181 | 164 | */ |
|---|
| 182 | 165 | |
|---|
| 183 | 166 | #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD |
|---|
| 184 | 167 | # define STATE_RCU_HEAD_READY 0 |
|---|
| 185 | 168 | # define STATE_RCU_HEAD_QUEUED 1 |
|---|
| 186 | 169 | |
|---|
| 187 | | -extern struct debug_obj_descr rcuhead_debug_descr; |
|---|
| 170 | +extern const struct debug_obj_descr rcuhead_debug_descr; |
|---|
| 188 | 171 | |
|---|
| 189 | 172 | static inline int debug_rcu_head_queue(struct rcu_head *head) |
|---|
| 190 | 173 | { |
|---|
| .. | .. |
|---|
| 215 | 198 | } |
|---|
| 216 | 199 | #endif /* #else !CONFIG_DEBUG_OBJECTS_RCU_HEAD */ |
|---|
| 217 | 200 | |
|---|
| 218 | | -void kfree(const void *); |
|---|
| 201 | +extern int rcu_cpu_stall_suppress_at_boot; |
|---|
| 219 | 202 | |
|---|
| 220 | | -/* |
|---|
| 221 | | - * Reclaim the specified callback, either by invoking it (non-lazy case) |
|---|
| 222 | | - * or freeing it directly (lazy case). Return true if lazy, false otherwise. |
|---|
| 223 | | - */ |
|---|
| 224 | | -static inline bool __rcu_reclaim(const char *rn, struct rcu_head *head) |
|---|
| 203 | +static inline bool rcu_stall_is_suppressed_at_boot(void) |
|---|
| 225 | 204 | { |
|---|
| 226 | | - unsigned long offset = (unsigned long)head->func; |
|---|
| 227 | | - |
|---|
| 228 | | - rcu_lock_acquire(&rcu_callback_map); |
|---|
| 229 | | - if (__is_kfree_rcu_offset(offset)) { |
|---|
| 230 | | - RCU_TRACE(trace_rcu_invoke_kfree_callback(rn, head, offset);) |
|---|
| 231 | | - kfree((void *)head - offset); |
|---|
| 232 | | - rcu_lock_release(&rcu_callback_map); |
|---|
| 233 | | - return true; |
|---|
| 234 | | - } else { |
|---|
| 235 | | - RCU_TRACE(trace_rcu_invoke_callback(rn, head);) |
|---|
| 236 | | - head->func(head); |
|---|
| 237 | | - rcu_lock_release(&rcu_callback_map); |
|---|
| 238 | | - return false; |
|---|
| 239 | | - } |
|---|
| 205 | + return rcu_cpu_stall_suppress_at_boot && !rcu_inkernel_boot_has_ended(); |
|---|
| 240 | 206 | } |
|---|
| 241 | 207 | |
|---|
| 242 | 208 | #ifdef CONFIG_RCU_STALL_COMMON |
|---|
| 243 | 209 | |
|---|
| 210 | +extern int rcu_cpu_stall_ftrace_dump; |
|---|
| 244 | 211 | extern int rcu_cpu_stall_suppress; |
|---|
| 212 | +extern int rcu_cpu_stall_timeout; |
|---|
| 245 | 213 | int rcu_jiffies_till_stall_check(void); |
|---|
| 214 | + |
|---|
| 215 | +static inline bool rcu_stall_is_suppressed(void) |
|---|
| 216 | +{ |
|---|
| 217 | + return rcu_stall_is_suppressed_at_boot() || rcu_cpu_stall_suppress; |
|---|
| 218 | +} |
|---|
| 246 | 219 | |
|---|
| 247 | 220 | #define rcu_ftrace_dump_stall_suppress() \ |
|---|
| 248 | 221 | do { \ |
|---|
| .. | .. |
|---|
| 257 | 230 | } while (0) |
|---|
| 258 | 231 | |
|---|
| 259 | 232 | #else /* #endif #ifdef CONFIG_RCU_STALL_COMMON */ |
|---|
| 233 | + |
|---|
| 234 | +static inline bool rcu_stall_is_suppressed(void) |
|---|
| 235 | +{ |
|---|
| 236 | + return rcu_stall_is_suppressed_at_boot(); |
|---|
| 237 | +} |
|---|
| 260 | 238 | #define rcu_ftrace_dump_stall_suppress() |
|---|
| 261 | 239 | #define rcu_ftrace_dump_stall_unsuppress() |
|---|
| 262 | 240 | #endif /* #ifdef CONFIG_RCU_STALL_COMMON */ |
|---|
| .. | .. |
|---|
| 293 | 271 | */ |
|---|
| 294 | 272 | extern void resched_cpu(int cpu); |
|---|
| 295 | 273 | |
|---|
| 296 | | -#if defined(SRCU) || !defined(TINY_RCU) |
|---|
| 274 | +#if defined(CONFIG_SRCU) || !defined(CONFIG_TINY_RCU) |
|---|
| 297 | 275 | |
|---|
| 298 | 276 | #include <linux/rcu_node_tree.h> |
|---|
| 299 | 277 | |
|---|
| .. | .. |
|---|
| 311 | 289 | { |
|---|
| 312 | 290 | int i; |
|---|
| 313 | 291 | |
|---|
| 292 | + for (i = 0; i < RCU_NUM_LVLS; i++) |
|---|
| 293 | + levelspread[i] = INT_MIN; |
|---|
| 314 | 294 | if (rcu_fanout_exact) { |
|---|
| 315 | 295 | levelspread[rcu_num_lvls - 1] = rcu_fanout_leaf; |
|---|
| 316 | 296 | for (i = rcu_num_lvls - 2; i >= 0; i--) |
|---|
| .. | .. |
|---|
| 328 | 308 | } |
|---|
| 329 | 309 | } |
|---|
| 330 | 310 | |
|---|
| 331 | | -/* Returns first leaf rcu_node of the specified RCU flavor. */ |
|---|
| 332 | | -#define rcu_first_leaf_node(rsp) ((rsp)->level[rcu_num_lvls - 1]) |
|---|
| 311 | +extern void rcu_init_geometry(void); |
|---|
| 312 | + |
|---|
| 313 | +/* Returns a pointer to the first leaf rcu_node structure. */ |
|---|
| 314 | +#define rcu_first_leaf_node() (rcu_state.level[rcu_num_lvls - 1]) |
|---|
| 333 | 315 | |
|---|
| 334 | 316 | /* Is this rcu_node a leaf? */ |
|---|
| 335 | 317 | #define rcu_is_leaf_node(rnp) ((rnp)->level == rcu_num_lvls - 1) |
|---|
| 336 | 318 | |
|---|
| 337 | 319 | /* Is this rcu_node the last leaf? */ |
|---|
| 338 | | -#define rcu_is_last_leaf_node(rsp, rnp) ((rnp) == &(rsp)->node[rcu_num_nodes - 1]) |
|---|
| 320 | +#define rcu_is_last_leaf_node(rnp) ((rnp) == &rcu_state.node[rcu_num_nodes - 1]) |
|---|
| 339 | 321 | |
|---|
| 340 | 322 | /* |
|---|
| 341 | | - * Do a full breadth-first scan of the rcu_node structures for the |
|---|
| 342 | | - * specified rcu_state structure. |
|---|
| 323 | + * Do a full breadth-first scan of the {s,}rcu_node structures for the |
|---|
| 324 | + * specified state structure (for SRCU) or the only rcu_state structure |
|---|
| 325 | + * (for RCU). |
|---|
| 343 | 326 | */ |
|---|
| 344 | | -#define rcu_for_each_node_breadth_first(rsp, rnp) \ |
|---|
| 345 | | - for ((rnp) = &(rsp)->node[0]; \ |
|---|
| 346 | | - (rnp) < &(rsp)->node[rcu_num_nodes]; (rnp)++) |
|---|
| 327 | +#define srcu_for_each_node_breadth_first(sp, rnp) \ |
|---|
| 328 | + for ((rnp) = &(sp)->node[0]; \ |
|---|
| 329 | + (rnp) < &(sp)->node[rcu_num_nodes]; (rnp)++) |
|---|
| 330 | +#define rcu_for_each_node_breadth_first(rnp) \ |
|---|
| 331 | + srcu_for_each_node_breadth_first(&rcu_state, rnp) |
|---|
| 347 | 332 | |
|---|
| 348 | 333 | /* |
|---|
| 349 | | - * Do a breadth-first scan of the non-leaf rcu_node structures for the |
|---|
| 350 | | - * specified rcu_state structure. Note that if there is a singleton |
|---|
| 351 | | - * rcu_node tree with but one rcu_node structure, this loop is a no-op. |
|---|
| 334 | + * Scan the leaves of the rcu_node hierarchy for the rcu_state structure. |
|---|
| 335 | + * Note that if there is a singleton rcu_node tree with but one rcu_node |
|---|
| 336 | + * structure, this loop -will- visit the rcu_node structure. It is still |
|---|
| 337 | + * a leaf node, even if it is also the root node. |
|---|
| 352 | 338 | */ |
|---|
| 353 | | -#define rcu_for_each_nonleaf_node_breadth_first(rsp, rnp) \ |
|---|
| 354 | | - for ((rnp) = &(rsp)->node[0]; !rcu_is_leaf_node(rsp, rnp); (rnp)++) |
|---|
| 355 | | - |
|---|
| 356 | | -/* |
|---|
| 357 | | - * Scan the leaves of the rcu_node hierarchy for the specified rcu_state |
|---|
| 358 | | - * structure. Note that if there is a singleton rcu_node tree with but |
|---|
| 359 | | - * one rcu_node structure, this loop -will- visit the rcu_node structure. |
|---|
| 360 | | - * It is still a leaf node, even if it is also the root node. |
|---|
| 361 | | - */ |
|---|
| 362 | | -#define rcu_for_each_leaf_node(rsp, rnp) \ |
|---|
| 363 | | - for ((rnp) = rcu_first_leaf_node(rsp); \ |
|---|
| 364 | | - (rnp) < &(rsp)->node[rcu_num_nodes]; (rnp)++) |
|---|
| 339 | +#define rcu_for_each_leaf_node(rnp) \ |
|---|
| 340 | + for ((rnp) = rcu_first_leaf_node(); \ |
|---|
| 341 | + (rnp) < &rcu_state.node[rcu_num_nodes]; (rnp)++) |
|---|
| 365 | 342 | |
|---|
| 366 | 343 | /* |
|---|
| 367 | 344 | * Iterate over all possible CPUs in a leaf RCU node. |
|---|
| 368 | 345 | */ |
|---|
| 369 | 346 | #define for_each_leaf_node_possible_cpu(rnp, cpu) \ |
|---|
| 370 | | - for ((cpu) = cpumask_next((rnp)->grplo - 1, cpu_possible_mask); \ |
|---|
| 347 | + for (WARN_ON_ONCE(!rcu_is_leaf_node(rnp)), \ |
|---|
| 348 | + (cpu) = cpumask_next((rnp)->grplo - 1, cpu_possible_mask); \ |
|---|
| 371 | 349 | (cpu) <= rnp->grphi; \ |
|---|
| 372 | 350 | (cpu) = cpumask_next((cpu), cpu_possible_mask)) |
|---|
| 373 | 351 | |
|---|
| .. | .. |
|---|
| 377 | 355 | #define rcu_find_next_bit(rnp, cpu, mask) \ |
|---|
| 378 | 356 | ((rnp)->grplo + find_next_bit(&(mask), BITS_PER_LONG, (cpu))) |
|---|
| 379 | 357 | #define for_each_leaf_node_cpu_mask(rnp, cpu, mask) \ |
|---|
| 380 | | - for ((cpu) = rcu_find_next_bit((rnp), 0, (mask)); \ |
|---|
| 358 | + for (WARN_ON_ONCE(!rcu_is_leaf_node(rnp)), \ |
|---|
| 359 | + (cpu) = rcu_find_next_bit((rnp), 0, (mask)); \ |
|---|
| 381 | 360 | (cpu) <= rnp->grphi; \ |
|---|
| 382 | 361 | (cpu) = rcu_find_next_bit((rnp), (cpu) + 1 - (rnp->grplo), (mask))) |
|---|
| 383 | 362 | |
|---|
| .. | .. |
|---|
| 433 | 412 | #define raw_lockdep_assert_held_rcu_node(p) \ |
|---|
| 434 | 413 | lockdep_assert_held(&ACCESS_PRIVATE(p, lock)) |
|---|
| 435 | 414 | |
|---|
| 436 | | -#endif /* #if defined(SRCU) || !defined(TINY_RCU) */ |
|---|
| 415 | +#endif /* #if defined(CONFIG_SRCU) || !defined(CONFIG_TINY_RCU) */ |
|---|
| 416 | + |
|---|
| 417 | +#ifdef CONFIG_SRCU |
|---|
| 418 | +void srcu_init(void); |
|---|
| 419 | +#else /* #ifdef CONFIG_SRCU */ |
|---|
| 420 | +static inline void srcu_init(void) { } |
|---|
| 421 | +#endif /* #else #ifdef CONFIG_SRCU */ |
|---|
| 437 | 422 | |
|---|
| 438 | 423 | #ifdef CONFIG_TINY_RCU |
|---|
| 439 | 424 | /* Tiny RCU doesn't expedite, as its purpose in life is instead to be tiny. */ |
|---|
| .. | .. |
|---|
| 448 | 433 | void rcu_expedite_gp(void); |
|---|
| 449 | 434 | void rcu_unexpedite_gp(void); |
|---|
| 450 | 435 | void rcupdate_announce_bootup_oddness(void); |
|---|
| 436 | +void show_rcu_tasks_gp_kthreads(void); |
|---|
| 451 | 437 | void rcu_request_urgent_qs_task(struct task_struct *t); |
|---|
| 452 | 438 | #endif /* #else #ifdef CONFIG_TINY_RCU */ |
|---|
| 453 | 439 | |
|---|
| .. | .. |
|---|
| 457 | 443 | |
|---|
| 458 | 444 | enum rcutorture_type { |
|---|
| 459 | 445 | RCU_FLAVOR, |
|---|
| 460 | | - RCU_BH_FLAVOR, |
|---|
| 461 | | - RCU_SCHED_FLAVOR, |
|---|
| 462 | 446 | RCU_TASKS_FLAVOR, |
|---|
| 447 | + RCU_TASKS_RUDE_FLAVOR, |
|---|
| 448 | + RCU_TASKS_TRACING_FLAVOR, |
|---|
| 449 | + RCU_TRIVIAL_FLAVOR, |
|---|
| 463 | 450 | SRCU_FLAVOR, |
|---|
| 464 | 451 | INVALID_RCU_FLAVOR |
|---|
| 465 | 452 | }; |
|---|
| 466 | 453 | |
|---|
| 467 | | -#if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU) |
|---|
| 454 | +#if defined(CONFIG_TREE_RCU) |
|---|
| 468 | 455 | void rcutorture_get_gp_data(enum rcutorture_type test_type, int *flags, |
|---|
| 469 | 456 | unsigned long *gp_seq); |
|---|
| 470 | | -void rcutorture_record_progress(unsigned long vernum); |
|---|
| 471 | 457 | void do_trace_rcu_torture_read(const char *rcutorturename, |
|---|
| 472 | 458 | struct rcu_head *rhp, |
|---|
| 473 | 459 | unsigned long secs, |
|---|
| 474 | 460 | unsigned long c_old, |
|---|
| 475 | 461 | unsigned long c); |
|---|
| 462 | +void rcu_gp_set_torture_wait(int duration); |
|---|
| 476 | 463 | #else |
|---|
| 477 | 464 | static inline void rcutorture_get_gp_data(enum rcutorture_type test_type, |
|---|
| 478 | 465 | int *flags, unsigned long *gp_seq) |
|---|
| .. | .. |
|---|
| 480 | 467 | *flags = 0; |
|---|
| 481 | 468 | *gp_seq = 0; |
|---|
| 482 | 469 | } |
|---|
| 483 | | -static inline void rcutorture_record_progress(unsigned long vernum) { } |
|---|
| 484 | 470 | #ifdef CONFIG_RCU_TRACE |
|---|
| 485 | 471 | void do_trace_rcu_torture_read(const char *rcutorturename, |
|---|
| 486 | 472 | struct rcu_head *rhp, |
|---|
| .. | .. |
|---|
| 491 | 477 | #define do_trace_rcu_torture_read(rcutorturename, rhp, secs, c_old, c) \ |
|---|
| 492 | 478 | do { } while (0) |
|---|
| 493 | 479 | #endif |
|---|
| 480 | +static inline void rcu_gp_set_torture_wait(int duration) { } |
|---|
| 481 | +#endif |
|---|
| 482 | + |
|---|
| 483 | +#if IS_ENABLED(CONFIG_RCU_TORTURE_TEST) || IS_MODULE(CONFIG_RCU_TORTURE_TEST) |
|---|
| 484 | +long rcutorture_sched_setaffinity(pid_t pid, const struct cpumask *in_mask); |
|---|
| 494 | 485 | #endif |
|---|
| 495 | 486 | |
|---|
| 496 | 487 | #ifdef CONFIG_TINY_SRCU |
|---|
| .. | .. |
|---|
| 514 | 505 | #endif |
|---|
| 515 | 506 | |
|---|
| 516 | 507 | #ifdef CONFIG_TINY_RCU |
|---|
| 508 | +static inline bool rcu_dynticks_zero_in_eqs(int cpu, int *vp) { return false; } |
|---|
| 517 | 509 | static inline unsigned long rcu_get_gp_seq(void) { return 0; } |
|---|
| 518 | | -static inline unsigned long rcu_bh_get_gp_seq(void) { return 0; } |
|---|
| 519 | | -static inline unsigned long rcu_sched_get_gp_seq(void) { return 0; } |
|---|
| 520 | 510 | static inline unsigned long rcu_exp_batches_completed(void) { return 0; } |
|---|
| 521 | | -static inline unsigned long rcu_exp_batches_completed_sched(void) { return 0; } |
|---|
| 522 | 511 | static inline unsigned long |
|---|
| 523 | 512 | srcu_batches_completed(struct srcu_struct *sp) { return 0; } |
|---|
| 524 | 513 | static inline void rcu_force_quiescent_state(void) { } |
|---|
| 525 | | -static inline void rcu_bh_force_quiescent_state(void) { } |
|---|
| 526 | | -static inline void rcu_sched_force_quiescent_state(void) { } |
|---|
| 527 | 514 | static inline void show_rcu_gp_kthreads(void) { } |
|---|
| 528 | 515 | static inline int rcu_get_gp_kthreads_prio(void) { return 0; } |
|---|
| 516 | +static inline void rcu_fwd_progress_check(unsigned long j) { } |
|---|
| 529 | 517 | #else /* #ifdef CONFIG_TINY_RCU */ |
|---|
| 518 | +bool rcu_dynticks_zero_in_eqs(int cpu, int *vp); |
|---|
| 530 | 519 | unsigned long rcu_get_gp_seq(void); |
|---|
| 531 | | -unsigned long rcu_bh_get_gp_seq(void); |
|---|
| 532 | | -unsigned long rcu_sched_get_gp_seq(void); |
|---|
| 533 | 520 | unsigned long rcu_exp_batches_completed(void); |
|---|
| 534 | | -unsigned long rcu_exp_batches_completed_sched(void); |
|---|
| 535 | 521 | unsigned long srcu_batches_completed(struct srcu_struct *sp); |
|---|
| 536 | 522 | void show_rcu_gp_kthreads(void); |
|---|
| 537 | 523 | int rcu_get_gp_kthreads_prio(void); |
|---|
| 524 | +void rcu_fwd_progress_check(unsigned long j); |
|---|
| 538 | 525 | void rcu_force_quiescent_state(void); |
|---|
| 539 | | -void rcu_bh_force_quiescent_state(void); |
|---|
| 540 | | -void rcu_sched_force_quiescent_state(void); |
|---|
| 541 | 526 | extern struct workqueue_struct *rcu_gp_wq; |
|---|
| 542 | 527 | extern struct workqueue_struct *rcu_par_gp_wq; |
|---|
| 543 | 528 | #endif /* #else #ifdef CONFIG_TINY_RCU */ |
|---|
| 544 | 529 | |
|---|
| 545 | 530 | #ifdef CONFIG_RCU_NOCB_CPU |
|---|
| 546 | 531 | bool rcu_is_nocb_cpu(int cpu); |
|---|
| 532 | +void rcu_bind_current_to_nocb(void); |
|---|
| 547 | 533 | #else |
|---|
| 548 | 534 | static inline bool rcu_is_nocb_cpu(int cpu) { return false; } |
|---|
| 535 | +static inline void rcu_bind_current_to_nocb(void) { } |
|---|
| 549 | 536 | #endif |
|---|
| 550 | 537 | |
|---|
| 551 | 538 | #endif /* __LINUX_RCU_H */ |
|---|