123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228 |
- /* SPDX-License-Identifier: GPL-2.0+ */
- /*
- * RCU segmented callback lists
- *
- * This seemingly RCU-private file must be available to SRCU users
- * because the size of the TREE SRCU srcu_struct structure depends
- * on these definitions.
- *
- * Copyright IBM Corporation, 2017
- *
- * Authors: Paul E. McKenney <[email protected]>
- */
- #ifndef __INCLUDE_LINUX_RCU_SEGCBLIST_H
- #define __INCLUDE_LINUX_RCU_SEGCBLIST_H
- #include <linux/types.h>
- #include <linux/atomic.h>
- /* Simple unsegmented callback lists. */
- struct rcu_cblist {
- struct rcu_head *head;
- struct rcu_head **tail;
- long len;
- };
- #define RCU_CBLIST_INITIALIZER(n) { .head = NULL, .tail = &n.head }
- /* Complicated segmented callback lists. ;-) */
- /*
- * Index values for segments in rcu_segcblist structure.
- *
- * The segments are as follows:
- *
- * [head, *tails[RCU_DONE_TAIL]):
- * Callbacks whose grace period has elapsed, and thus can be invoked.
- * [*tails[RCU_DONE_TAIL], *tails[RCU_WAIT_TAIL]):
- * Callbacks waiting for the current GP from the current CPU's viewpoint.
- * [*tails[RCU_WAIT_TAIL], *tails[RCU_NEXT_READY_TAIL]):
- * Callbacks that arrived before the next GP started, again from
- * the current CPU's viewpoint. These can be handled by the next GP.
- * [*tails[RCU_NEXT_READY_TAIL], *tails[RCU_NEXT_TAIL]):
- * Callbacks that might have arrived after the next GP started.
- * There is some uncertainty as to when a given GP starts and
- * ends, but a CPU knows the exact times if it is the one starting
- * or ending the GP. Other CPUs know that the previous GP ends
- * before the next one starts.
- *
- * Note that RCU_WAIT_TAIL cannot be empty unless RCU_NEXT_READY_TAIL is also
- * empty.
- *
- * The ->gp_seq[] array contains the grace-period number at which the
- * corresponding segment of callbacks will be ready to invoke. A given
- * element of this array is meaningful only when the corresponding segment
- * is non-empty, and it is never valid for RCU_DONE_TAIL (whose callbacks
- * are already ready to invoke) or for RCU_NEXT_TAIL (whose callbacks have
- * not yet been assigned a grace-period number).
- */
- #define RCU_DONE_TAIL 0 /* Also RCU_WAIT head. */
- #define RCU_WAIT_TAIL 1 /* Also RCU_NEXT_READY head. */
- #define RCU_NEXT_READY_TAIL 2 /* Also RCU_NEXT head. */
- #define RCU_NEXT_TAIL 3
- #define RCU_CBLIST_NSEGS 4
- /*
- * ==NOCB Offloading state machine==
- *
- *
- * ----------------------------------------------------------------------------
- * | SEGCBLIST_RCU_CORE |
- * | |
- * | Callbacks processed by rcu_core() from softirqs or local |
- * | rcuc kthread, without holding nocb_lock. |
- * ----------------------------------------------------------------------------
- * |
- * v
- * ----------------------------------------------------------------------------
- * | SEGCBLIST_RCU_CORE | SEGCBLIST_LOCKING | SEGCBLIST_OFFLOADED |
- * | |
- * | Callbacks processed by rcu_core() from softirqs or local |
- * | rcuc kthread, while holding nocb_lock. Waking up CB and GP kthreads, |
- * | allowing nocb_timer to be armed. |
- * ----------------------------------------------------------------------------
- * |
- * v
- * -----------------------------------
- * | |
- * v v
- * --------------------------------------- ----------------------------------|
- * | SEGCBLIST_RCU_CORE | | | SEGCBLIST_RCU_CORE | |
- * | SEGCBLIST_LOCKING | | | SEGCBLIST_LOCKING | |
- * | SEGCBLIST_OFFLOADED | | | SEGCBLIST_OFFLOADED | |
- * | SEGCBLIST_KTHREAD_CB | | SEGCBLIST_KTHREAD_GP |
- * | | | |
- * | | | |
- * | CB kthread woke up and | | GP kthread woke up and |
- * | acknowledged SEGCBLIST_OFFLOADED. | | acknowledged SEGCBLIST_OFFLOADED|
- * | Processes callbacks concurrently | | |
- * | with rcu_core(), holding | | |
- * | nocb_lock. | | |
- * --------------------------------------- -----------------------------------
- * | |
- * -----------------------------------
- * |
- * v
- * |--------------------------------------------------------------------------|
- * | SEGCBLIST_LOCKING | |
- * | SEGCBLIST_OFFLOADED | |
- * | SEGCBLIST_KTHREAD_GP | |
- * | SEGCBLIST_KTHREAD_CB |
- * | |
- * | Kthreads handle callbacks holding nocb_lock, local rcu_core() stops |
- * | handling callbacks. Enable bypass queueing. |
- * ----------------------------------------------------------------------------
- */
- /*
- * ==NOCB De-Offloading state machine==
- *
- *
- * |--------------------------------------------------------------------------|
- * | SEGCBLIST_LOCKING | |
- * | SEGCBLIST_OFFLOADED | |
- * | SEGCBLIST_KTHREAD_CB | |
- * | SEGCBLIST_KTHREAD_GP |
- * | |
- * | CB/GP kthreads handle callbacks holding nocb_lock, local rcu_core() |
- * | ignores callbacks. Bypass enqueue is enabled. |
- * ----------------------------------------------------------------------------
- * |
- * v
- * |--------------------------------------------------------------------------|
- * | SEGCBLIST_RCU_CORE | |
- * | SEGCBLIST_LOCKING | |
- * | SEGCBLIST_OFFLOADED | |
- * | SEGCBLIST_KTHREAD_CB | |
- * | SEGCBLIST_KTHREAD_GP |
- * | |
- * | CB/GP kthreads handle callbacks holding nocb_lock, local rcu_core() |
- * | handles callbacks concurrently. Bypass enqueue is enabled. |
- * | Invoke RCU core so we make sure not to preempt it in the middle with |
- * | leaving some urgent work unattended within a jiffy. |
- * ----------------------------------------------------------------------------
- * |
- * v
- * |--------------------------------------------------------------------------|
- * | SEGCBLIST_RCU_CORE | |
- * | SEGCBLIST_LOCKING | |
- * | SEGCBLIST_KTHREAD_CB | |
- * | SEGCBLIST_KTHREAD_GP |
- * | |
- * | CB/GP kthreads and local rcu_core() handle callbacks concurrently |
- * | holding nocb_lock. Wake up CB and GP kthreads if necessary. Disable |
- * | bypass enqueue. |
- * ----------------------------------------------------------------------------
- * |
- * v
- * -----------------------------------
- * | |
- * v v
- * ---------------------------------------------------------------------------|
- * | | |
- * | SEGCBLIST_RCU_CORE | | SEGCBLIST_RCU_CORE | |
- * | SEGCBLIST_LOCKING | | SEGCBLIST_LOCKING | |
- * | SEGCBLIST_KTHREAD_CB | SEGCBLIST_KTHREAD_GP |
- * | | |
- * | GP kthread woke up and | CB kthread woke up and |
- * | acknowledged the fact that | acknowledged the fact that |
- * | SEGCBLIST_OFFLOADED got cleared. | SEGCBLIST_OFFLOADED got cleared. |
- * | | The CB kthread goes to sleep |
- * | The callbacks from the target CPU | until it ever gets re-offloaded. |
- * | will be ignored from the GP kthread | |
- * | loop. | |
- * ----------------------------------------------------------------------------
- * | |
- * -----------------------------------
- * |
- * v
- * ----------------------------------------------------------------------------
- * | SEGCBLIST_RCU_CORE | SEGCBLIST_LOCKING |
- * | |
- * | Callbacks processed by rcu_core() from softirqs or local |
- * | rcuc kthread, while holding nocb_lock. Forbid nocb_timer to be armed. |
- * | Flush pending nocb_timer. Flush nocb bypass callbacks. |
- * ----------------------------------------------------------------------------
- * |
- * v
- * ----------------------------------------------------------------------------
- * | SEGCBLIST_RCU_CORE |
- * | |
- * | Callbacks processed by rcu_core() from softirqs or local |
- * | rcuc kthread, without holding nocb_lock. |
- * ----------------------------------------------------------------------------
- */
- #define SEGCBLIST_ENABLED BIT(0)
- #define SEGCBLIST_RCU_CORE BIT(1)
- #define SEGCBLIST_LOCKING BIT(2)
- #define SEGCBLIST_KTHREAD_CB BIT(3)
- #define SEGCBLIST_KTHREAD_GP BIT(4)
- #define SEGCBLIST_OFFLOADED BIT(5)
- struct rcu_segcblist {
- struct rcu_head *head;
- struct rcu_head **tails[RCU_CBLIST_NSEGS];
- unsigned long gp_seq[RCU_CBLIST_NSEGS];
- #ifdef CONFIG_RCU_NOCB_CPU
- atomic_long_t len;
- #else
- long len;
- #endif
- long seglen[RCU_CBLIST_NSEGS];
- u8 flags;
- };
- #define RCU_SEGCBLIST_INITIALIZER(n) \
- { \
- .head = NULL, \
- .tails[RCU_DONE_TAIL] = &n.head, \
- .tails[RCU_WAIT_TAIL] = &n.head, \
- .tails[RCU_NEXT_READY_TAIL] = &n.head, \
- .tails[RCU_NEXT_TAIL] = &n.head, \
- }
- #endif /* __INCLUDE_LINUX_RCU_SEGCBLIST_H */
|