You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'core-rcu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull RCU updates from Ingo Molnar:
- Continued initialization/Kconfig updates: hide most Kconfig options
from unsuspecting users.
There's now a single high level configuration option:
*
* RCU Subsystem
*
Make expert-level adjustments to RCU configuration (RCU_EXPERT) [N/y/?] (NEW)
Which if answered in the negative, leaves us with a single
interactive configuration option:
Offload RCU callback processing from boot-selected CPUs (RCU_NOCB_CPU) [N/y/?] (NEW)
All the rest of the RCU options are configured automatically. Later
on we'll remove this single leftover configuration option as well.
- Remove all uses of RCU-protected array indexes: replace the
rcu_[access|dereference]_index_check() APIs with READ_ONCE() and
rcu_lockdep_assert()
- RCU CPU-hotplug cleanups
- Updates to Tiny RCU: a race fix and further code shrinkage.
- RCU torture-testing updates: fixes, speedups, cleanups and
documentation updates.
- Miscellaneous fixes
- Documentation updates
* 'core-rcu-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (60 commits)
rcutorture: Allow repetition factors in Kconfig-fragment lists
rcutorture: Display "make oldconfig" errors
rcutorture: Update TREE_RCU-kconfig.txt
rcutorture: Make rcutorture scripts force RCU_EXPERT
rcutorture: Update configuration fragments for rcutree.rcu_fanout_exact
rcutorture: TASKS_RCU set directly, so don't explicitly set it
rcutorture: Test SRCU cleanup code path
rcutorture: Replace barriers with smp_store_release() and smp_load_acquire()
locktorture: Change longdelay_us to longdelay_ms
rcutorture: Allow negative values of nreaders to oversubscribe
rcutorture: Exchange TREE03 and TREE08 NR_CPUS, speed up CPU hotplug
rcutorture: Exchange TREE03 and TREE04 geometries
locktorture: fix deadlock in 'rw_lock_irq' type
rcu: Correctly handle non-empty Tiny RCU callback list with none ready
rcutorture: Test both RCU-sched and RCU-bh for Tiny RCU
rcu: Further shrink Tiny RCU by making empty functions static inlines
rcu: Conditionally compile RCU's eqs warnings
rcu: Remove prompt for RCU implementation
rcu: Make RCU able to tolerate undefined CONFIG_RCU_KTHREAD_PRIO
rcu: Make RCU able to tolerate undefined CONFIG_RCU_FANOUT_LEAF
...
This commit is contained in:
@@ -10,7 +10,19 @@ also be used to protect arrays. Three situations are as follows:
|
||||
|
||||
3. Resizeable Arrays
|
||||
|
||||
Each of these situations are discussed below.
|
||||
Each of these three situations involves an RCU-protected pointer to an
|
||||
array that is separately indexed. It might be tempting to consider use
|
||||
of RCU to instead protect the index into an array, however, this use
|
||||
case is -not- supported. The problem with RCU-protected indexes into
|
||||
arrays is that compilers can play way too many optimization games with
|
||||
integers, which means that the rules governing handling of these indexes
|
||||
are far more trouble than they are worth. If RCU-protected indexes into
|
||||
arrays prove to be particularly valuable (which they have not thus far),
|
||||
explicit cooperation from the compiler will be required to permit them
|
||||
to be safely used.
|
||||
|
||||
That aside, each of the three RCU-protected pointer situations are
|
||||
described in the following sections.
|
||||
|
||||
|
||||
Situation 1: Hash Tables
|
||||
@@ -36,9 +48,9 @@ Quick Quiz: Why is it so important that updates be rare when
|
||||
Situation 3: Resizeable Arrays
|
||||
|
||||
Use of RCU for resizeable arrays is demonstrated by the grow_ary()
|
||||
function used by the System V IPC code. The array is used to map from
|
||||
semaphore, message-queue, and shared-memory IDs to the data structure
|
||||
that represents the corresponding IPC construct. The grow_ary()
|
||||
function formerly used by the System V IPC code. The array is used
|
||||
to map from semaphore, message-queue, and shared-memory IDs to the data
|
||||
structure that represents the corresponding IPC construct. The grow_ary()
|
||||
function does not acquire any locks; instead its caller must hold the
|
||||
ids->sem semaphore.
|
||||
|
||||
|
||||
@@ -47,11 +47,6 @@ checking of rcu_dereference() primitives:
|
||||
Use explicit check expression "c" along with
|
||||
srcu_read_lock_held()(). This is useful in code that
|
||||
is invoked by both SRCU readers and updaters.
|
||||
rcu_dereference_index_check(p, c):
|
||||
Use explicit check expression "c", but the caller
|
||||
must supply one of the rcu_read_lock_held() functions.
|
||||
This is useful in code that uses RCU-protected arrays
|
||||
that is invoked by both RCU readers and updaters.
|
||||
rcu_dereference_raw(p):
|
||||
Don't check. (Use sparingly, if at all.)
|
||||
rcu_dereference_protected(p, c):
|
||||
@@ -64,11 +59,6 @@ checking of rcu_dereference() primitives:
|
||||
but retain the compiler constraints that prevent duplicating
|
||||
or coalescsing. This is useful when when testing the
|
||||
value of the pointer itself, for example, against NULL.
|
||||
rcu_access_index(idx):
|
||||
Return the value of the index and omit all barriers, but
|
||||
retain the compiler constraints that prevent duplicating
|
||||
or coalescsing. This is useful when when testing the
|
||||
value of the index itself, for example, against -1.
|
||||
|
||||
The rcu_dereference_check() check expression can be any boolean
|
||||
expression, but would normally include a lockdep expression. However,
|
||||
|
||||
@@ -25,17 +25,6 @@ o You must use one of the rcu_dereference() family of primitives
|
||||
for an example where the compiler can in fact deduce the exact
|
||||
value of the pointer, and thus cause misordering.
|
||||
|
||||
o Do not use single-element RCU-protected arrays. The compiler
|
||||
is within its right to assume that the value of an index into
|
||||
such an array must necessarily evaluate to zero. The compiler
|
||||
could then substitute the constant zero for the computation, so
|
||||
that the array index no longer depended on the value returned
|
||||
by rcu_dereference(). If the array index no longer depends
|
||||
on rcu_dereference(), then both the compiler and the CPU
|
||||
are within their rights to order the array access before the
|
||||
rcu_dereference(), which can cause the array access to return
|
||||
garbage.
|
||||
|
||||
o Avoid cancellation when using the "+" and "-" infix arithmetic
|
||||
operators. For example, for a given variable "x", avoid
|
||||
"(x-x)". There are similar arithmetic pitfalls from other
|
||||
@@ -76,14 +65,15 @@ o Do not use the results from the boolean "&&" and "||" when
|
||||
dereferencing. For example, the following (rather improbable)
|
||||
code is buggy:
|
||||
|
||||
int a[2];
|
||||
int index;
|
||||
int force_zero_index = 1;
|
||||
int *p;
|
||||
int *q;
|
||||
|
||||
...
|
||||
|
||||
r1 = rcu_dereference(i1)
|
||||
r2 = a[r1 && force_zero_index]; /* BUGGY!!! */
|
||||
p = rcu_dereference(gp)
|
||||
q = &global_q;
|
||||
q += p != &oom_p1 && p != &oom_p2;
|
||||
r1 = *q; /* BUGGY!!! */
|
||||
|
||||
The reason this is buggy is that "&&" and "||" are often compiled
|
||||
using branches. While weak-memory machines such as ARM or PowerPC
|
||||
@@ -94,14 +84,15 @@ o Do not use the results from relational operators ("==", "!=",
|
||||
">", ">=", "<", or "<=") when dereferencing. For example,
|
||||
the following (quite strange) code is buggy:
|
||||
|
||||
int a[2];
|
||||
int index;
|
||||
int flip_index = 0;
|
||||
int *p;
|
||||
int *q;
|
||||
|
||||
...
|
||||
|
||||
r1 = rcu_dereference(i1)
|
||||
r2 = a[r1 != flip_index]; /* BUGGY!!! */
|
||||
p = rcu_dereference(gp)
|
||||
q = &global_q;
|
||||
q += p > &oom_p;
|
||||
r1 = *q; /* BUGGY!!! */
|
||||
|
||||
As before, the reason this is buggy is that relational operators
|
||||
are often compiled using branches. And as before, although
|
||||
@@ -193,6 +184,11 @@ o Be very careful about comparing pointers obtained from
|
||||
pointer. Note that the volatile cast in rcu_dereference()
|
||||
will normally prevent the compiler from knowing too much.
|
||||
|
||||
However, please note that if the compiler knows that the
|
||||
pointer takes on only one of two values, a not-equal
|
||||
comparison will provide exactly the information that the
|
||||
compiler needs to deduce the value of the pointer.
|
||||
|
||||
o Disable any value-speculation optimizations that your compiler
|
||||
might provide, especially if you are making use of feedback-based
|
||||
optimizations that take data collected from prior runs. Such
|
||||
|
||||
@@ -256,7 +256,9 @@ rcu_dereference()
|
||||
If you are going to be fetching multiple fields from the
|
||||
RCU-protected structure, using the local variable is of
|
||||
course preferred. Repeated rcu_dereference() calls look
|
||||
ugly and incur unnecessary overhead on Alpha CPUs.
|
||||
ugly, do not guarantee that the same pointer will be returned
|
||||
if an update happened while in the critical section, and incur
|
||||
unnecessary overhead on Alpha CPUs.
|
||||
|
||||
Note that the value returned by rcu_dereference() is valid
|
||||
only within the enclosing RCU read-side critical section.
|
||||
@@ -879,9 +881,7 @@ SRCU: Initialization/cleanup
|
||||
|
||||
All: lockdep-checked RCU-protected pointer access
|
||||
|
||||
rcu_access_index
|
||||
rcu_access_pointer
|
||||
rcu_dereference_index_check
|
||||
rcu_dereference_raw
|
||||
rcu_lockdep_assert
|
||||
rcu_sleep_check
|
||||
|
||||
@@ -2998,11 +2998,34 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||
Set maximum number of finished RCU callbacks to
|
||||
process in one batch.
|
||||
|
||||
rcutree.dump_tree= [KNL]
|
||||
Dump the structure of the rcu_node combining tree
|
||||
out at early boot. This is used for diagnostic
|
||||
purposes, to verify correct tree setup.
|
||||
|
||||
rcutree.gp_cleanup_delay= [KNL]
|
||||
Set the number of jiffies to delay each step of
|
||||
RCU grace-period cleanup. This only has effect
|
||||
when CONFIG_RCU_TORTURE_TEST_SLOW_CLEANUP is set.
|
||||
|
||||
rcutree.gp_init_delay= [KNL]
|
||||
Set the number of jiffies to delay each step of
|
||||
RCU grace-period initialization. This only has
|
||||
effect when CONFIG_RCU_TORTURE_TEST_SLOW_INIT is
|
||||
set.
|
||||
effect when CONFIG_RCU_TORTURE_TEST_SLOW_INIT
|
||||
is set.
|
||||
|
||||
rcutree.gp_preinit_delay= [KNL]
|
||||
Set the number of jiffies to delay each step of
|
||||
RCU grace-period pre-initialization, that is,
|
||||
the propagation of recent CPU-hotplug changes up
|
||||
the rcu_node combining tree. This only has effect
|
||||
when CONFIG_RCU_TORTURE_TEST_SLOW_PREINIT is set.
|
||||
|
||||
rcutree.rcu_fanout_exact= [KNL]
|
||||
Disable autobalancing of the rcu_node combining
|
||||
tree. This is used by rcutorture, and might
|
||||
possibly be useful for architectures having high
|
||||
cache-to-cache transfer latencies.
|
||||
|
||||
rcutree.rcu_fanout_leaf= [KNL]
|
||||
Increase the number of CPUs assigned to each
|
||||
@@ -3107,7 +3130,11 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
||||
test, hence the "fake".
|
||||
|
||||
rcutorture.nreaders= [KNL]
|
||||
Set number of RCU readers.
|
||||
Set number of RCU readers. The value -1 selects
|
||||
N-1, where N is the number of CPUs. A value
|
||||
"n" less than -1 selects N-n-2, where N is again
|
||||
the number of CPUs. For example, -2 selects N
|
||||
(the number of CPUs), -3 selects N+1, and so on.
|
||||
|
||||
rcutorture.object_debug= [KNL]
|
||||
Enable debug-object double-call_rcu() testing.
|
||||
|
||||
@@ -617,16 +617,16 @@ case what's actually required is:
|
||||
However, stores are not speculated. This means that ordering -is- provided
|
||||
for load-store control dependencies, as in the following example:
|
||||
|
||||
q = ACCESS_ONCE(a);
|
||||
q = READ_ONCE_CTRL(a);
|
||||
if (q) {
|
||||
ACCESS_ONCE(b) = p;
|
||||
}
|
||||
|
||||
Control dependencies pair normally with other types of barriers.
|
||||
That said, please note that ACCESS_ONCE() is not optional! Without the
|
||||
ACCESS_ONCE(), might combine the load from 'a' with other loads from
|
||||
'a', and the store to 'b' with other stores to 'b', with possible highly
|
||||
counterintuitive effects on ordering.
|
||||
Control dependencies pair normally with other types of barriers. That
|
||||
said, please note that READ_ONCE_CTRL() is not optional! Without the
|
||||
READ_ONCE_CTRL(), the compiler might combine the load from 'a' with
|
||||
other loads from 'a', and the store to 'b' with other stores to 'b',
|
||||
with possible highly counterintuitive effects on ordering.
|
||||
|
||||
Worse yet, if the compiler is able to prove (say) that the value of
|
||||
variable 'a' is always non-zero, it would be well within its rights
|
||||
@@ -636,12 +636,15 @@ as follows:
|
||||
q = a;
|
||||
b = p; /* BUG: Compiler and CPU can both reorder!!! */
|
||||
|
||||
So don't leave out the ACCESS_ONCE().
|
||||
Finally, the READ_ONCE_CTRL() includes an smp_read_barrier_depends()
|
||||
that DEC Alpha needs in order to respect control depedencies.
|
||||
|
||||
So don't leave out the READ_ONCE_CTRL().
|
||||
|
||||
It is tempting to try to enforce ordering on identical stores on both
|
||||
branches of the "if" statement as follows:
|
||||
|
||||
q = ACCESS_ONCE(a);
|
||||
q = READ_ONCE_CTRL(a);
|
||||
if (q) {
|
||||
barrier();
|
||||
ACCESS_ONCE(b) = p;
|
||||
@@ -655,7 +658,7 @@ branches of the "if" statement as follows:
|
||||
Unfortunately, current compilers will transform this as follows at high
|
||||
optimization levels:
|
||||
|
||||
q = ACCESS_ONCE(a);
|
||||
q = READ_ONCE_CTRL(a);
|
||||
barrier();
|
||||
ACCESS_ONCE(b) = p; /* BUG: No ordering vs. load from a!!! */
|
||||
if (q) {
|
||||
@@ -685,7 +688,7 @@ memory barriers, for example, smp_store_release():
|
||||
In contrast, without explicit memory barriers, two-legged-if control
|
||||
ordering is guaranteed only when the stores differ, for example:
|
||||
|
||||
q = ACCESS_ONCE(a);
|
||||
q = READ_ONCE_CTRL(a);
|
||||
if (q) {
|
||||
ACCESS_ONCE(b) = p;
|
||||
do_something();
|
||||
@@ -694,14 +697,14 @@ ordering is guaranteed only when the stores differ, for example:
|
||||
do_something_else();
|
||||
}
|
||||
|
||||
The initial ACCESS_ONCE() is still required to prevent the compiler from
|
||||
proving the value of 'a'.
|
||||
The initial READ_ONCE_CTRL() is still required to prevent the compiler
|
||||
from proving the value of 'a'.
|
||||
|
||||
In addition, you need to be careful what you do with the local variable 'q',
|
||||
otherwise the compiler might be able to guess the value and again remove
|
||||
the needed conditional. For example:
|
||||
|
||||
q = ACCESS_ONCE(a);
|
||||
q = READ_ONCE_CTRL(a);
|
||||
if (q % MAX) {
|
||||
ACCESS_ONCE(b) = p;
|
||||
do_something();
|
||||
@@ -714,7 +717,7 @@ If MAX is defined to be 1, then the compiler knows that (q % MAX) is
|
||||
equal to zero, in which case the compiler is within its rights to
|
||||
transform the above code into the following:
|
||||
|
||||
q = ACCESS_ONCE(a);
|
||||
q = READ_ONCE_CTRL(a);
|
||||
ACCESS_ONCE(b) = p;
|
||||
do_something_else();
|
||||
|
||||
@@ -725,7 +728,7 @@ is gone, and the barrier won't bring it back. Therefore, if you are
|
||||
relying on this ordering, you should make sure that MAX is greater than
|
||||
one, perhaps as follows:
|
||||
|
||||
q = ACCESS_ONCE(a);
|
||||
q = READ_ONCE_CTRL(a);
|
||||
BUILD_BUG_ON(MAX <= 1); /* Order load from a with store to b. */
|
||||
if (q % MAX) {
|
||||
ACCESS_ONCE(b) = p;
|
||||
@@ -742,14 +745,15 @@ of the 'if' statement.
|
||||
You must also be careful not to rely too much on boolean short-circuit
|
||||
evaluation. Consider this example:
|
||||
|
||||
q = ACCESS_ONCE(a);
|
||||
q = READ_ONCE_CTRL(a);
|
||||
if (a || 1 > 0)
|
||||
ACCESS_ONCE(b) = 1;
|
||||
|
||||
Because the second condition is always true, the compiler can transform
|
||||
this example as following, defeating control dependency:
|
||||
Because the first condition cannot fault and the second condition is
|
||||
always true, the compiler can transform this example as following,
|
||||
defeating control dependency:
|
||||
|
||||
q = ACCESS_ONCE(a);
|
||||
q = READ_ONCE_CTRL(a);
|
||||
ACCESS_ONCE(b) = 1;
|
||||
|
||||
This example underscores the need to ensure that the compiler cannot
|
||||
@@ -762,8 +766,8 @@ demonstrated by two related examples, with the initial values of
|
||||
x and y both being zero:
|
||||
|
||||
CPU 0 CPU 1
|
||||
===================== =====================
|
||||
r1 = ACCESS_ONCE(x); r2 = ACCESS_ONCE(y);
|
||||
======================= =======================
|
||||
r1 = READ_ONCE_CTRL(x); r2 = READ_ONCE_CTRL(y);
|
||||
if (r1 > 0) if (r2 > 0)
|
||||
ACCESS_ONCE(y) = 1; ACCESS_ONCE(x) = 1;
|
||||
|
||||
@@ -783,7 +787,8 @@ But because control dependencies do -not- provide transitivity, the above
|
||||
assertion can fail after the combined three-CPU example completes. If you
|
||||
need the three-CPU example to provide ordering, you will need smp_mb()
|
||||
between the loads and stores in the CPU 0 and CPU 1 code fragments,
|
||||
that is, just before or just after the "if" statements.
|
||||
that is, just before or just after the "if" statements. Furthermore,
|
||||
the original two-CPU example is very fragile and should be avoided.
|
||||
|
||||
These two examples are the LB and WWC litmus tests from this paper:
|
||||
http://www.cl.cam.ac.uk/users/pes20/ppc-supplemental/test6.pdf and this
|
||||
@@ -791,6 +796,12 @@ site: https://www.cl.cam.ac.uk/~pes20/ppcmem/index.html.
|
||||
|
||||
In summary:
|
||||
|
||||
(*) Control dependencies must be headed by READ_ONCE_CTRL().
|
||||
Or, as a much less preferable alternative, interpose
|
||||
be headed by READ_ONCE() or an ACCESS_ONCE() read and must
|
||||
have smp_read_barrier_depends() between this read and the
|
||||
control-dependent write.
|
||||
|
||||
(*) Control dependencies can order prior loads against later stores.
|
||||
However, they do -not- guarantee any other sort of ordering:
|
||||
Not prior loads against later loads, nor prior stores against
|
||||
@@ -1784,10 +1795,9 @@ for each construct. These operations all imply certain barriers:
|
||||
|
||||
Memory operations issued before the ACQUIRE may be completed after
|
||||
the ACQUIRE operation has completed. An smp_mb__before_spinlock(),
|
||||
combined with a following ACQUIRE, orders prior loads against
|
||||
subsequent loads and stores and also orders prior stores against
|
||||
subsequent stores. Note that this is weaker than smp_mb()! The
|
||||
smp_mb__before_spinlock() primitive is free on many architectures.
|
||||
combined with a following ACQUIRE, orders prior stores against
|
||||
subsequent loads and stores. Note that this is weaker than smp_mb()!
|
||||
The smp_mb__before_spinlock() primitive is free on many architectures.
|
||||
|
||||
(2) RELEASE operation implication:
|
||||
|
||||
|
||||
@@ -89,5 +89,6 @@ do { \
|
||||
|
||||
#define smp_mb__before_atomic() smp_mb()
|
||||
#define smp_mb__after_atomic() smp_mb()
|
||||
#define smp_mb__before_spinlock() smp_mb()
|
||||
|
||||
#endif /* _ASM_POWERPC_BARRIER_H */
|
||||
|
||||
@@ -53,9 +53,12 @@
|
||||
static DEFINE_MUTEX(mce_chrdev_read_mutex);
|
||||
|
||||
#define rcu_dereference_check_mce(p) \
|
||||
rcu_dereference_index_check((p), \
|
||||
rcu_read_lock_sched_held() || \
|
||||
lockdep_is_held(&mce_chrdev_read_mutex))
|
||||
({ \
|
||||
rcu_lockdep_assert(rcu_read_lock_sched_held() || \
|
||||
lockdep_is_held(&mce_chrdev_read_mutex), \
|
||||
"suspicious rcu_dereference_check_mce() usage"); \
|
||||
smp_load_acquire(&(p)); \
|
||||
})
|
||||
|
||||
#define CREATE_TRACE_POINTS
|
||||
#include <trace/events/mce.h>
|
||||
@@ -1887,7 +1890,7 @@ out:
|
||||
static unsigned int mce_chrdev_poll(struct file *file, poll_table *wait)
|
||||
{
|
||||
poll_wait(file, &mce_chrdev_wait, wait);
|
||||
if (rcu_access_index(mcelog.next))
|
||||
if (READ_ONCE(mcelog.next))
|
||||
return POLLIN | POLLRDNORM;
|
||||
if (!mce_apei_read_done && apei_check_mce())
|
||||
return POLLIN | POLLRDNORM;
|
||||
@@ -1932,8 +1935,8 @@ void register_mce_write_callback(ssize_t (*fn)(struct file *filp,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(register_mce_write_callback);
|
||||
|
||||
ssize_t mce_chrdev_write(struct file *filp, const char __user *ubuf,
|
||||
size_t usize, loff_t *off)
|
||||
static ssize_t mce_chrdev_write(struct file *filp, const char __user *ubuf,
|
||||
size_t usize, loff_t *off)
|
||||
{
|
||||
if (mce_write)
|
||||
return mce_write(filp, ubuf, usize, off);
|
||||
|
||||
@@ -252,6 +252,22 @@ static __always_inline void __write_once_size(volatile void *p, void *res, int s
|
||||
#define WRITE_ONCE(x, val) \
|
||||
({ typeof(x) __val = (val); __write_once_size(&(x), &__val, sizeof(__val)); __val; })
|
||||
|
||||
/**
|
||||
* READ_ONCE_CTRL - Read a value heading a control dependency
|
||||
* @x: The value to be read, heading the control dependency
|
||||
*
|
||||
* Control dependencies are tricky. See Documentation/memory-barriers.txt
|
||||
* for important information on how to use them. Note that in many cases,
|
||||
* use of smp_load_acquire() will be much simpler. Control dependencies
|
||||
* should be avoided except on the hottest of hotpaths.
|
||||
*/
|
||||
#define READ_ONCE_CTRL(x) \
|
||||
({ \
|
||||
typeof(x) __val = READ_ONCE(x); \
|
||||
smp_read_barrier_depends(); /* Enforce control dependency. */ \
|
||||
__val; \
|
||||
})
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
#endif /* __ASSEMBLY__ */
|
||||
|
||||
@@ -29,8 +29,8 @@
|
||||
*/
|
||||
static inline void INIT_LIST_HEAD_RCU(struct list_head *list)
|
||||
{
|
||||
ACCESS_ONCE(list->next) = list;
|
||||
ACCESS_ONCE(list->prev) = list;
|
||||
WRITE_ONCE(list->next, list);
|
||||
WRITE_ONCE(list->prev, list);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -288,7 +288,7 @@ static inline void list_splice_init_rcu(struct list_head *list,
|
||||
#define list_first_or_null_rcu(ptr, type, member) \
|
||||
({ \
|
||||
struct list_head *__ptr = (ptr); \
|
||||
struct list_head *__next = ACCESS_ONCE(__ptr->next); \
|
||||
struct list_head *__next = READ_ONCE(__ptr->next); \
|
||||
likely(__ptr != __next) ? list_entry_rcu(__next, type, member) : NULL; \
|
||||
})
|
||||
|
||||
@@ -549,8 +549,8 @@ static inline void hlist_add_behind_rcu(struct hlist_node *n,
|
||||
*/
|
||||
#define hlist_for_each_entry_from_rcu(pos, member) \
|
||||
for (; pos; \
|
||||
pos = hlist_entry_safe(rcu_dereference((pos)->member.next),\
|
||||
typeof(*(pos)), member))
|
||||
pos = hlist_entry_safe(rcu_dereference_raw(hlist_next_rcu( \
|
||||
&(pos)->member)), typeof(*(pos)), member))
|
||||
|
||||
#endif /* __KERNEL__ */
|
||||
#endif
|
||||
|
||||
@@ -292,10 +292,6 @@ void rcu_sched_qs(void);
|
||||
void rcu_bh_qs(void);
|
||||
void rcu_check_callbacks(int user);
|
||||
struct notifier_block;
|
||||
void rcu_idle_enter(void);
|
||||
void rcu_idle_exit(void);
|
||||
void rcu_irq_enter(void);
|
||||
void rcu_irq_exit(void);
|
||||
int rcu_cpu_notify(struct notifier_block *self,
|
||||
unsigned long action, void *hcpu);
|
||||
|
||||
@@ -364,8 +360,8 @@ extern struct srcu_struct tasks_rcu_exit_srcu;
|
||||
#define rcu_note_voluntary_context_switch(t) \
|
||||
do { \
|
||||
rcu_all_qs(); \
|
||||
if (ACCESS_ONCE((t)->rcu_tasks_holdout)) \
|
||||
ACCESS_ONCE((t)->rcu_tasks_holdout) = false; \
|
||||
if (READ_ONCE((t)->rcu_tasks_holdout)) \
|
||||
WRITE_ONCE((t)->rcu_tasks_holdout, false); \
|
||||
} while (0)
|
||||
#else /* #ifdef CONFIG_TASKS_RCU */
|
||||
#define TASKS_RCU(x) do { } while (0)
|
||||
@@ -609,7 +605,7 @@ static inline void rcu_preempt_sleep_check(void)
|
||||
|
||||
#define __rcu_access_pointer(p, space) \
|
||||
({ \
|
||||
typeof(*p) *_________p1 = (typeof(*p) *__force)ACCESS_ONCE(p); \
|
||||
typeof(*p) *_________p1 = (typeof(*p) *__force)READ_ONCE(p); \
|
||||
rcu_dereference_sparse(p, space); \
|
||||
((typeof(*p) __force __kernel *)(_________p1)); \
|
||||
})
|
||||
@@ -628,21 +624,6 @@ static inline void rcu_preempt_sleep_check(void)
|
||||
((typeof(*p) __force __kernel *)(p)); \
|
||||
})
|
||||
|
||||
#define __rcu_access_index(p, space) \
|
||||
({ \
|
||||
typeof(p) _________p1 = ACCESS_ONCE(p); \
|
||||
rcu_dereference_sparse(p, space); \
|
||||
(_________p1); \
|
||||
})
|
||||
#define __rcu_dereference_index_check(p, c) \
|
||||
({ \
|
||||
/* Dependency order vs. p above. */ \
|
||||
typeof(p) _________p1 = lockless_dereference(p); \
|
||||
rcu_lockdep_assert(c, \
|
||||
"suspicious rcu_dereference_index_check() usage"); \
|
||||
(_________p1); \
|
||||
})
|
||||
|
||||
/**
|
||||
* RCU_INITIALIZER() - statically initialize an RCU-protected global variable
|
||||
* @v: The value to statically initialize with.
|
||||
@@ -659,7 +640,7 @@ static inline void rcu_preempt_sleep_check(void)
|
||||
*/
|
||||
#define lockless_dereference(p) \
|
||||
({ \
|
||||
typeof(p) _________p1 = ACCESS_ONCE(p); \
|
||||
typeof(p) _________p1 = READ_ONCE(p); \
|
||||
smp_read_barrier_depends(); /* Dependency order vs. p above. */ \
|
||||
(_________p1); \
|
||||
})
|
||||
@@ -702,7 +683,7 @@ static inline void rcu_preempt_sleep_check(void)
|
||||
* @p: The pointer to read
|
||||
*
|
||||
* Return the value of the specified RCU-protected pointer, but omit the
|
||||
* smp_read_barrier_depends() and keep the ACCESS_ONCE(). This is useful
|
||||
* smp_read_barrier_depends() and keep the READ_ONCE(). This is useful
|
||||
* when the value of this pointer is accessed, but the pointer is not
|
||||
* dereferenced, for example, when testing an RCU-protected pointer against
|
||||
* NULL. Although rcu_access_pointer() may also be used in cases where
|
||||
@@ -786,48 +767,13 @@ static inline void rcu_preempt_sleep_check(void)
|
||||
*/
|
||||
#define rcu_dereference_raw_notrace(p) __rcu_dereference_check((p), 1, __rcu)
|
||||
|
||||
/**
|
||||
* rcu_access_index() - fetch RCU index with no dereferencing
|
||||
* @p: The index to read
|
||||
*
|
||||
* Return the value of the specified RCU-protected index, but omit the
|
||||
* smp_read_barrier_depends() and keep the ACCESS_ONCE(). This is useful
|
||||
* when the value of this index is accessed, but the index is not
|
||||
* dereferenced, for example, when testing an RCU-protected index against
|
||||
* -1. Although rcu_access_index() may also be used in cases where
|
||||
* update-side locks prevent the value of the index from changing, you
|
||||
* should instead use rcu_dereference_index_protected() for this use case.
|
||||
*/
|
||||
#define rcu_access_index(p) __rcu_access_index((p), __rcu)
|
||||
|
||||
/**
|
||||
* rcu_dereference_index_check() - rcu_dereference for indices with debug checking
|
||||
* @p: The pointer to read, prior to dereferencing
|
||||
* @c: The conditions under which the dereference will take place
|
||||
*
|
||||
* Similar to rcu_dereference_check(), but omits the sparse checking.
|
||||
* This allows rcu_dereference_index_check() to be used on integers,
|
||||
* which can then be used as array indices. Attempting to use
|
||||
* rcu_dereference_check() on an integer will give compiler warnings
|
||||
* because the sparse address-space mechanism relies on dereferencing
|
||||
* the RCU-protected pointer. Dereferencing integers is not something
|
||||
* that even gcc will put up with.
|
||||
*
|
||||
* Note that this function does not implicitly check for RCU read-side
|
||||
* critical sections. If this function gains lots of uses, it might
|
||||
* make sense to provide versions for each flavor of RCU, but it does
|
||||
* not make sense as of early 2010.
|
||||
*/
|
||||
#define rcu_dereference_index_check(p, c) \
|
||||
__rcu_dereference_index_check((p), (c))
|
||||
|
||||
/**
|
||||
* rcu_dereference_protected() - fetch RCU pointer when updates prevented
|
||||
* @p: The pointer to read, prior to dereferencing
|
||||
* @c: The conditions under which the dereference will take place
|
||||
*
|
||||
* Return the value of the specified RCU-protected pointer, but omit
|
||||
* both the smp_read_barrier_depends() and the ACCESS_ONCE(). This
|
||||
* both the smp_read_barrier_depends() and the READ_ONCE(). This
|
||||
* is useful in cases where update-side locks prevent the value of the
|
||||
* pointer from changing. Please note that this primitive does -not-
|
||||
* prevent the compiler from repeating this reference or combining it
|
||||
@@ -1153,13 +1099,13 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
|
||||
#define kfree_rcu(ptr, rcu_head) \
|
||||
__kfree_rcu(&((ptr)->rcu_head), offsetof(typeof(*(ptr)), rcu_head))
|
||||
|
||||
#if defined(CONFIG_TINY_RCU) || defined(CONFIG_RCU_NOCB_CPU_ALL)
|
||||
#ifdef CONFIG_TINY_RCU
|
||||
static inline int rcu_needs_cpu(unsigned long *delta_jiffies)
|
||||
{
|
||||
*delta_jiffies = ULONG_MAX;
|
||||
return 0;
|
||||
}
|
||||
#endif /* #if defined(CONFIG_TINY_RCU) || defined(CONFIG_RCU_NOCB_CPU_ALL) */
|
||||
#endif /* #ifdef CONFIG_TINY_RCU */
|
||||
|
||||
#if defined(CONFIG_RCU_NOCB_CPU_ALL)
|
||||
static inline bool rcu_is_nocb_cpu(int cpu) { return true; }
|
||||
|
||||
@@ -159,6 +159,22 @@ static inline void rcu_cpu_stall_reset(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rcu_idle_enter(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rcu_idle_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rcu_irq_enter(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void rcu_irq_exit(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void exit_rcu(void)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -31,9 +31,7 @@
|
||||
#define __LINUX_RCUTREE_H
|
||||
|
||||
void rcu_note_context_switch(void);
|
||||
#ifndef CONFIG_RCU_NOCB_CPU_ALL
|
||||
int rcu_needs_cpu(unsigned long *delta_jiffies);
|
||||
#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */
|
||||
void rcu_cpu_stall_reset(void);
|
||||
|
||||
/*
|
||||
@@ -93,6 +91,11 @@ void rcu_force_quiescent_state(void);
|
||||
void rcu_bh_force_quiescent_state(void);
|
||||
void rcu_sched_force_quiescent_state(void);
|
||||
|
||||
void rcu_idle_enter(void);
|
||||
void rcu_idle_exit(void);
|
||||
void rcu_irq_enter(void);
|
||||
void rcu_irq_exit(void);
|
||||
|
||||
void exit_rcu(void);
|
||||
|
||||
void rcu_scheduler_starting(void);
|
||||
|
||||
@@ -120,7 +120,7 @@ do { \
|
||||
/*
|
||||
* Despite its name it doesn't necessarily has to be a full barrier.
|
||||
* It should only guarantee that a STORE before the critical section
|
||||
* can not be reordered with a LOAD inside this section.
|
||||
* can not be reordered with LOADs and STOREs inside this section.
|
||||
* spin_lock() is the one-way barrier, this LOAD can not escape out
|
||||
* of the region. So the default implementation simply ensures that
|
||||
* a STORE can not move into the critical section, smp_wmb() should
|
||||
|
||||
+29
-43
@@ -465,13 +465,9 @@ endmenu # "CPU/Task time and stats accounting"
|
||||
|
||||
menu "RCU Subsystem"
|
||||
|
||||
choice
|
||||
prompt "RCU Implementation"
|
||||
default TREE_RCU
|
||||
|
||||
config TREE_RCU
|
||||
bool "Tree-based hierarchical RCU"
|
||||
depends on !PREEMPT && SMP
|
||||
bool
|
||||
default y if !PREEMPT && SMP
|
||||
help
|
||||
This option selects the RCU implementation that is
|
||||
designed for very large SMP system with hundreds or
|
||||
@@ -479,8 +475,8 @@ config TREE_RCU
|
||||
smaller systems.
|
||||
|
||||
config PREEMPT_RCU
|
||||
bool "Preemptible tree-based hierarchical RCU"
|
||||
depends on PREEMPT
|
||||
bool
|
||||
default y if PREEMPT
|
||||
help
|
||||
This option selects the RCU implementation that is
|
||||
designed for very large SMP systems with hundreds or
|
||||
@@ -491,15 +487,28 @@ config PREEMPT_RCU
|
||||
Select this option if you are unsure.
|
||||
|
||||
config TINY_RCU
|
||||
bool "UP-only small-memory-footprint RCU"
|
||||
depends on !PREEMPT && !SMP
|
||||
bool
|
||||
default y if !PREEMPT && !SMP
|
||||
help
|
||||
This option selects the RCU implementation that is
|
||||
designed for UP systems from which real-time response
|
||||
is not required. This option greatly reduces the
|
||||
memory footprint of RCU.
|
||||
|
||||
endchoice
|
||||
config RCU_EXPERT
|
||||
bool "Make expert-level adjustments to RCU configuration"
|
||||
default n
|
||||
help
|
||||
This option needs to be enabled if you wish to make
|
||||
expert-level adjustments to RCU configuration. By default,
|
||||
no such adjustments can be made, which has the often-beneficial
|
||||
side-effect of preventing "make oldconfig" from asking you all
|
||||
sorts of detailed questions about how you would like numerous
|
||||
obscure RCU options to be set up.
|
||||
|
||||
Say Y if you need to make expert-level adjustments to RCU.
|
||||
|
||||
Say N if you are unsure.
|
||||
|
||||
config SRCU
|
||||
bool
|
||||
@@ -509,7 +518,7 @@ config SRCU
|
||||
sections.
|
||||
|
||||
config TASKS_RCU
|
||||
bool "Task_based RCU implementation using voluntary context switch"
|
||||
bool
|
||||
default n
|
||||
select SRCU
|
||||
help
|
||||
@@ -517,8 +526,6 @@ config TASKS_RCU
|
||||
only voluntary context switch (not preemption!), idle, and
|
||||
user-mode execution as quiescent states.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config RCU_STALL_COMMON
|
||||
def_bool ( TREE_RCU || PREEMPT_RCU || RCU_TRACE )
|
||||
help
|
||||
@@ -531,9 +538,7 @@ config CONTEXT_TRACKING
|
||||
bool
|
||||
|
||||
config RCU_USER_QS
|
||||
bool "Consider userspace as in RCU extended quiescent state"
|
||||
depends on HAVE_CONTEXT_TRACKING && SMP
|
||||
select CONTEXT_TRACKING
|
||||
bool
|
||||
help
|
||||
This option sets hooks on kernel / userspace boundaries and
|
||||
puts RCU in extended quiescent state when the CPU runs in
|
||||
@@ -541,12 +546,6 @@ config RCU_USER_QS
|
||||
excluded from the global RCU state machine and thus doesn't
|
||||
try to keep the timer tick on for RCU.
|
||||
|
||||
Unless you want to hack and help the development of the full
|
||||
dynticks mode, you shouldn't enable this option. It also
|
||||
adds unnecessary overhead.
|
||||
|
||||
If unsure say N
|
||||
|
||||
config CONTEXT_TRACKING_FORCE
|
||||
bool "Force context tracking"
|
||||
depends on CONTEXT_TRACKING
|
||||
@@ -578,7 +577,7 @@ config RCU_FANOUT
|
||||
int "Tree-based hierarchical RCU fanout value"
|
||||
range 2 64 if 64BIT
|
||||
range 2 32 if !64BIT
|
||||
depends on TREE_RCU || PREEMPT_RCU
|
||||
depends on (TREE_RCU || PREEMPT_RCU) && RCU_EXPERT
|
||||
default 64 if 64BIT
|
||||
default 32 if !64BIT
|
||||
help
|
||||
@@ -596,9 +595,9 @@ config RCU_FANOUT
|
||||
|
||||
config RCU_FANOUT_LEAF
|
||||
int "Tree-based hierarchical RCU leaf-level fanout value"
|
||||
range 2 RCU_FANOUT if 64BIT
|
||||
range 2 RCU_FANOUT if !64BIT
|
||||
depends on TREE_RCU || PREEMPT_RCU
|
||||
range 2 64 if 64BIT
|
||||
range 2 32 if !64BIT
|
||||
depends on (TREE_RCU || PREEMPT_RCU) && RCU_EXPERT
|
||||
default 16
|
||||
help
|
||||
This option controls the leaf-level fanout of hierarchical
|
||||
@@ -621,23 +620,9 @@ config RCU_FANOUT_LEAF
|
||||
|
||||
Take the default if unsure.
|
||||
|
||||
config RCU_FANOUT_EXACT
|
||||
bool "Disable tree-based hierarchical RCU auto-balancing"
|
||||
depends on TREE_RCU || PREEMPT_RCU
|
||||
default n
|
||||
help
|
||||
This option forces use of the exact RCU_FANOUT value specified,
|
||||
regardless of imbalances in the hierarchy. This is useful for
|
||||
testing RCU itself, and might one day be useful on systems with
|
||||
strong NUMA behavior.
|
||||
|
||||
Without RCU_FANOUT_EXACT, the code will balance the hierarchy.
|
||||
|
||||
Say N if unsure.
|
||||
|
||||
config RCU_FAST_NO_HZ
|
||||
bool "Accelerate last non-dyntick-idle CPU's grace periods"
|
||||
depends on NO_HZ_COMMON && SMP
|
||||
depends on NO_HZ_COMMON && SMP && RCU_EXPERT
|
||||
default n
|
||||
help
|
||||
This option permits CPUs to enter dynticks-idle state even if
|
||||
@@ -663,7 +648,7 @@ config TREE_RCU_TRACE
|
||||
|
||||
config RCU_BOOST
|
||||
bool "Enable RCU priority boosting"
|
||||
depends on RT_MUTEXES && PREEMPT_RCU
|
||||
depends on RT_MUTEXES && PREEMPT_RCU && RCU_EXPERT
|
||||
default n
|
||||
help
|
||||
This option boosts the priority of preempted RCU readers that
|
||||
@@ -680,6 +665,7 @@ config RCU_KTHREAD_PRIO
|
||||
range 0 99 if !RCU_BOOST
|
||||
default 1 if RCU_BOOST
|
||||
default 0 if !RCU_BOOST
|
||||
depends on RCU_EXPERT
|
||||
help
|
||||
This option specifies the SCHED_FIFO priority value that will be
|
||||
assigned to the rcuc/n and rcub/n threads and is also the value
|
||||
|
||||
+2
-2
@@ -398,7 +398,6 @@ static int __ref _cpu_down(unsigned int cpu, int tasks_frozen)
|
||||
err = __stop_machine(take_cpu_down, &tcd_param, cpumask_of(cpu));
|
||||
if (err) {
|
||||
/* CPU didn't die: tell everyone. Can't complain. */
|
||||
smpboot_unpark_threads(cpu);
|
||||
cpu_notify_nofail(CPU_DOWN_FAILED | mod, hcpu);
|
||||
goto out_release;
|
||||
}
|
||||
@@ -463,6 +462,7 @@ static int smpboot_thread_call(struct notifier_block *nfb,
|
||||
|
||||
switch (action & ~CPU_TASKS_FROZEN) {
|
||||
|
||||
case CPU_DOWN_FAILED:
|
||||
case CPU_ONLINE:
|
||||
smpboot_unpark_threads(cpu);
|
||||
break;
|
||||
@@ -479,7 +479,7 @@ static struct notifier_block smpboot_thread_notifier = {
|
||||
.priority = CPU_PRI_SMPBOOT,
|
||||
};
|
||||
|
||||
void __cpuinit smpboot_thread_init(void)
|
||||
void smpboot_thread_init(void)
|
||||
{
|
||||
register_cpu_notifier(&smpboot_thread_notifier);
|
||||
}
|
||||
|
||||
@@ -141,7 +141,7 @@ int perf_output_begin(struct perf_output_handle *handle,
|
||||
perf_output_get_handle(handle);
|
||||
|
||||
do {
|
||||
tail = ACCESS_ONCE(rb->user_page->data_tail);
|
||||
tail = READ_ONCE_CTRL(rb->user_page->data_tail);
|
||||
offset = head = local_read(&rb->head);
|
||||
if (!rb->overwrite &&
|
||||
unlikely(CIRC_SPACE(head, tail, perf_data_size(rb)) < size))
|
||||
|
||||
@@ -122,12 +122,12 @@ static int torture_lock_busted_write_lock(void)
|
||||
|
||||
static void torture_lock_busted_write_delay(struct torture_random_state *trsp)
|
||||
{
|
||||
const unsigned long longdelay_us = 100;
|
||||
const unsigned long longdelay_ms = 100;
|
||||
|
||||
/* We want a long delay occasionally to force massive contention. */
|
||||
if (!(torture_random(trsp) %
|
||||
(cxt.nrealwriters_stress * 2000 * longdelay_us)))
|
||||
mdelay(longdelay_us);
|
||||
(cxt.nrealwriters_stress * 2000 * longdelay_ms)))
|
||||
mdelay(longdelay_ms);
|
||||
#ifdef CONFIG_PREEMPT
|
||||
if (!(torture_random(trsp) % (cxt.nrealwriters_stress * 20000)))
|
||||
preempt_schedule(); /* Allow test to be preempted. */
|
||||
@@ -160,14 +160,14 @@ static int torture_spin_lock_write_lock(void) __acquires(torture_spinlock)
|
||||
static void torture_spin_lock_write_delay(struct torture_random_state *trsp)
|
||||
{
|
||||
const unsigned long shortdelay_us = 2;
|
||||
const unsigned long longdelay_us = 100;
|
||||
const unsigned long longdelay_ms = 100;
|
||||
|
||||
/* We want a short delay mostly to emulate likely code, and
|
||||
* we want a long delay occasionally to force massive contention.
|
||||
*/
|
||||
if (!(torture_random(trsp) %
|
||||
(cxt.nrealwriters_stress * 2000 * longdelay_us)))
|
||||
mdelay(longdelay_us);
|
||||
(cxt.nrealwriters_stress * 2000 * longdelay_ms)))
|
||||
mdelay(longdelay_ms);
|
||||
if (!(torture_random(trsp) %
|
||||
(cxt.nrealwriters_stress * 2 * shortdelay_us)))
|
||||
udelay(shortdelay_us);
|
||||
@@ -309,7 +309,7 @@ static int torture_rwlock_read_lock_irq(void) __acquires(torture_rwlock)
|
||||
static void torture_rwlock_read_unlock_irq(void)
|
||||
__releases(torture_rwlock)
|
||||
{
|
||||
write_unlock_irqrestore(&torture_rwlock, cxt.cur_ops->flags);
|
||||
read_unlock_irqrestore(&torture_rwlock, cxt.cur_ops->flags);
|
||||
}
|
||||
|
||||
static struct lock_torture_ops rw_lock_irq_ops = {
|
||||
|
||||
+72
-31
@@ -241,6 +241,7 @@ rcu_torture_free(struct rcu_torture *p)
|
||||
struct rcu_torture_ops {
|
||||
int ttype;
|
||||
void (*init)(void);
|
||||
void (*cleanup)(void);
|
||||
int (*readlock)(void);
|
||||
void (*read_delay)(struct torture_random_state *rrsp);
|
||||
void (*readunlock)(int idx);
|
||||
@@ -477,10 +478,12 @@ static struct rcu_torture_ops rcu_busted_ops = {
|
||||
*/
|
||||
|
||||
DEFINE_STATIC_SRCU(srcu_ctl);
|
||||
static struct srcu_struct srcu_ctld;
|
||||
static struct srcu_struct *srcu_ctlp = &srcu_ctl;
|
||||
|
||||
static int srcu_torture_read_lock(void) __acquires(&srcu_ctl)
|
||||
static int srcu_torture_read_lock(void) __acquires(srcu_ctlp)
|
||||
{
|
||||
return srcu_read_lock(&srcu_ctl);
|
||||
return srcu_read_lock(srcu_ctlp);
|
||||
}
|
||||
|
||||
static void srcu_read_delay(struct torture_random_state *rrsp)
|
||||
@@ -499,49 +502,49 @@ static void srcu_read_delay(struct torture_random_state *rrsp)
|
||||
rcu_read_delay(rrsp);
|
||||
}
|
||||
|
||||
static void srcu_torture_read_unlock(int idx) __releases(&srcu_ctl)
|
||||
static void srcu_torture_read_unlock(int idx) __releases(srcu_ctlp)
|
||||
{
|
||||
srcu_read_unlock(&srcu_ctl, idx);
|
||||
srcu_read_unlock(srcu_ctlp, idx);
|
||||
}
|
||||
|
||||
static unsigned long srcu_torture_completed(void)
|
||||
{
|
||||
return srcu_batches_completed(&srcu_ctl);
|
||||
return srcu_batches_completed(srcu_ctlp);
|
||||
}
|
||||
|
||||
static void srcu_torture_deferred_free(struct rcu_torture *rp)
|
||||
{
|
||||
call_srcu(&srcu_ctl, &rp->rtort_rcu, rcu_torture_cb);
|
||||
call_srcu(srcu_ctlp, &rp->rtort_rcu, rcu_torture_cb);
|
||||
}
|
||||
|
||||
static void srcu_torture_synchronize(void)
|
||||
{
|
||||
synchronize_srcu(&srcu_ctl);
|
||||
synchronize_srcu(srcu_ctlp);
|
||||
}
|
||||
|
||||
static void srcu_torture_call(struct rcu_head *head,
|
||||
void (*func)(struct rcu_head *head))
|
||||
{
|
||||
call_srcu(&srcu_ctl, head, func);
|
||||
call_srcu(srcu_ctlp, head, func);
|
||||
}
|
||||
|
||||
static void srcu_torture_barrier(void)
|
||||
{
|
||||
srcu_barrier(&srcu_ctl);
|
||||
srcu_barrier(srcu_ctlp);
|
||||
}
|
||||
|
||||
static void srcu_torture_stats(void)
|
||||
{
|
||||
int cpu;
|
||||
int idx = srcu_ctl.completed & 0x1;
|
||||
int idx = srcu_ctlp->completed & 0x1;
|
||||
|
||||
pr_alert("%s%s per-CPU(idx=%d):",
|
||||
torture_type, TORTURE_FLAG, idx);
|
||||
for_each_possible_cpu(cpu) {
|
||||
long c0, c1;
|
||||
|
||||
c0 = (long)per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[!idx];
|
||||
c1 = (long)per_cpu_ptr(srcu_ctl.per_cpu_ref, cpu)->c[idx];
|
||||
c0 = (long)per_cpu_ptr(srcu_ctlp->per_cpu_ref, cpu)->c[!idx];
|
||||
c1 = (long)per_cpu_ptr(srcu_ctlp->per_cpu_ref, cpu)->c[idx];
|
||||
pr_cont(" %d(%ld,%ld)", cpu, c0, c1);
|
||||
}
|
||||
pr_cont("\n");
|
||||
@@ -549,7 +552,7 @@ static void srcu_torture_stats(void)
|
||||
|
||||
static void srcu_torture_synchronize_expedited(void)
|
||||
{
|
||||
synchronize_srcu_expedited(&srcu_ctl);
|
||||
synchronize_srcu_expedited(srcu_ctlp);
|
||||
}
|
||||
|
||||
static struct rcu_torture_ops srcu_ops = {
|
||||
@@ -569,6 +572,38 @@ static struct rcu_torture_ops srcu_ops = {
|
||||
.name = "srcu"
|
||||
};
|
||||
|
||||
static void srcu_torture_init(void)
|
||||
{
|
||||
rcu_sync_torture_init();
|
||||
WARN_ON(init_srcu_struct(&srcu_ctld));
|
||||
srcu_ctlp = &srcu_ctld;
|
||||
}
|
||||
|
||||
static void srcu_torture_cleanup(void)
|
||||
{
|
||||
cleanup_srcu_struct(&srcu_ctld);
|
||||
srcu_ctlp = &srcu_ctl; /* In case of a later rcutorture run. */
|
||||
}
|
||||
|
||||
/* As above, but dynamically allocated. */
|
||||
static struct rcu_torture_ops srcud_ops = {
|
||||
.ttype = SRCU_FLAVOR,
|
||||
.init = srcu_torture_init,
|
||||
.cleanup = srcu_torture_cleanup,
|
||||
.readlock = srcu_torture_read_lock,
|
||||
.read_delay = srcu_read_delay,
|
||||
.readunlock = srcu_torture_read_unlock,
|
||||
.started = NULL,
|
||||
.completed = srcu_torture_completed,
|
||||
.deferred_free = srcu_torture_deferred_free,
|
||||
.sync = srcu_torture_synchronize,
|
||||
.exp_sync = srcu_torture_synchronize_expedited,
|
||||
.call = srcu_torture_call,
|
||||
.cb_barrier = srcu_torture_barrier,
|
||||
.stats = srcu_torture_stats,
|
||||
.name = "srcud"
|
||||
};
|
||||
|
||||
/*
|
||||
* Definitions for sched torture testing.
|
||||
*/
|
||||
@@ -672,8 +707,8 @@ static void rcu_torture_boost_cb(struct rcu_head *head)
|
||||
struct rcu_boost_inflight *rbip =
|
||||
container_of(head, struct rcu_boost_inflight, rcu);
|
||||
|
||||
smp_mb(); /* Ensure RCU-core accesses precede clearing ->inflight */
|
||||
rbip->inflight = 0;
|
||||
/* Ensure RCU-core accesses precede clearing ->inflight */
|
||||
smp_store_release(&rbip->inflight, 0);
|
||||
}
|
||||
|
||||
static int rcu_torture_boost(void *arg)
|
||||
@@ -710,9 +745,9 @@ static int rcu_torture_boost(void *arg)
|
||||
call_rcu_time = jiffies;
|
||||
while (ULONG_CMP_LT(jiffies, endtime)) {
|
||||
/* If we don't have a callback in flight, post one. */
|
||||
if (!rbi.inflight) {
|
||||
smp_mb(); /* RCU core before ->inflight = 1. */
|
||||
rbi.inflight = 1;
|
||||
if (!smp_load_acquire(&rbi.inflight)) {
|
||||
/* RCU core before ->inflight = 1. */
|
||||
smp_store_release(&rbi.inflight, 1);
|
||||
call_rcu(&rbi.rcu, rcu_torture_boost_cb);
|
||||
if (jiffies - call_rcu_time >
|
||||
test_boost_duration * HZ - HZ / 2) {
|
||||
@@ -751,11 +786,10 @@ checkwait: stutter_wait("rcu_torture_boost");
|
||||
} while (!torture_must_stop());
|
||||
|
||||
/* Clean up and exit. */
|
||||
while (!kthread_should_stop() || rbi.inflight) {
|
||||
while (!kthread_should_stop() || smp_load_acquire(&rbi.inflight)) {
|
||||
torture_shutdown_absorb("rcu_torture_boost");
|
||||
schedule_timeout_uninterruptible(1);
|
||||
}
|
||||
smp_mb(); /* order accesses to ->inflight before stack-frame death. */
|
||||
destroy_rcu_head_on_stack(&rbi.rcu);
|
||||
torture_kthread_stopping("rcu_torture_boost");
|
||||
return 0;
|
||||
@@ -1054,7 +1088,7 @@ static void rcu_torture_timer(unsigned long unused)
|
||||
p = rcu_dereference_check(rcu_torture_current,
|
||||
rcu_read_lock_bh_held() ||
|
||||
rcu_read_lock_sched_held() ||
|
||||
srcu_read_lock_held(&srcu_ctl));
|
||||
srcu_read_lock_held(srcu_ctlp));
|
||||
if (p == NULL) {
|
||||
/* Leave because rcu_torture_writer is not yet underway */
|
||||
cur_ops->readunlock(idx);
|
||||
@@ -1128,7 +1162,7 @@ rcu_torture_reader(void *arg)
|
||||
p = rcu_dereference_check(rcu_torture_current,
|
||||
rcu_read_lock_bh_held() ||
|
||||
rcu_read_lock_sched_held() ||
|
||||
srcu_read_lock_held(&srcu_ctl));
|
||||
srcu_read_lock_held(srcu_ctlp));
|
||||
if (p == NULL) {
|
||||
/* Wait for rcu_torture_writer to get underway */
|
||||
cur_ops->readunlock(idx);
|
||||
@@ -1413,12 +1447,15 @@ static int rcu_torture_barrier_cbs(void *arg)
|
||||
do {
|
||||
wait_event(barrier_cbs_wq[myid],
|
||||
(newphase =
|
||||
ACCESS_ONCE(barrier_phase)) != lastphase ||
|
||||
smp_load_acquire(&barrier_phase)) != lastphase ||
|
||||
torture_must_stop());
|
||||
lastphase = newphase;
|
||||
smp_mb(); /* ensure barrier_phase load before ->call(). */
|
||||
if (torture_must_stop())
|
||||
break;
|
||||
/*
|
||||
* The above smp_load_acquire() ensures barrier_phase load
|
||||
* is ordered before the folloiwng ->call().
|
||||
*/
|
||||
cur_ops->call(&rcu, rcu_torture_barrier_cbf);
|
||||
if (atomic_dec_and_test(&barrier_cbs_count))
|
||||
wake_up(&barrier_wq);
|
||||
@@ -1439,8 +1476,8 @@ static int rcu_torture_barrier(void *arg)
|
||||
do {
|
||||
atomic_set(&barrier_cbs_invoked, 0);
|
||||
atomic_set(&barrier_cbs_count, n_barrier_cbs);
|
||||
smp_mb(); /* Ensure barrier_phase after prior assignments. */
|
||||
barrier_phase = !barrier_phase;
|
||||
/* Ensure barrier_phase ordered after prior assignments. */
|
||||
smp_store_release(&barrier_phase, !barrier_phase);
|
||||
for (i = 0; i < n_barrier_cbs; i++)
|
||||
wake_up(&barrier_cbs_wq[i]);
|
||||
wait_event(barrier_wq,
|
||||
@@ -1588,10 +1625,14 @@ rcu_torture_cleanup(void)
|
||||
rcutorture_booster_cleanup(i);
|
||||
}
|
||||
|
||||
/* Wait for all RCU callbacks to fire. */
|
||||
|
||||
/*
|
||||
* Wait for all RCU callbacks to fire, then do flavor-specific
|
||||
* cleanup operations.
|
||||
*/
|
||||
if (cur_ops->cb_barrier != NULL)
|
||||
cur_ops->cb_barrier();
|
||||
if (cur_ops->cleanup != NULL)
|
||||
cur_ops->cleanup();
|
||||
|
||||
rcu_torture_stats_print(); /* -After- the stats thread is stopped! */
|
||||
|
||||
@@ -1668,8 +1709,8 @@ rcu_torture_init(void)
|
||||
int cpu;
|
||||
int firsterr = 0;
|
||||
static struct rcu_torture_ops *torture_ops[] = {
|
||||
&rcu_ops, &rcu_bh_ops, &rcu_busted_ops, &srcu_ops, &sched_ops,
|
||||
RCUTORTURE_TASKS_OPS
|
||||
&rcu_ops, &rcu_bh_ops, &rcu_busted_ops, &srcu_ops, &srcud_ops,
|
||||
&sched_ops, RCUTORTURE_TASKS_OPS
|
||||
};
|
||||
|
||||
if (!torture_init_begin(torture_type, verbose, &torture_runnable))
|
||||
@@ -1701,7 +1742,7 @@ rcu_torture_init(void)
|
||||
if (nreaders >= 0) {
|
||||
nrealreaders = nreaders;
|
||||
} else {
|
||||
nrealreaders = num_online_cpus() - 1;
|
||||
nrealreaders = num_online_cpus() - 2 - nreaders;
|
||||
if (nrealreaders <= 0)
|
||||
nrealreaders = 1;
|
||||
}
|
||||
|
||||
+5
-5
@@ -151,7 +151,7 @@ static unsigned long srcu_readers_seq_idx(struct srcu_struct *sp, int idx)
|
||||
unsigned long t;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
t = ACCESS_ONCE(per_cpu_ptr(sp->per_cpu_ref, cpu)->seq[idx]);
|
||||
t = READ_ONCE(per_cpu_ptr(sp->per_cpu_ref, cpu)->seq[idx]);
|
||||
sum += t;
|
||||
}
|
||||
return sum;
|
||||
@@ -168,7 +168,7 @@ static unsigned long srcu_readers_active_idx(struct srcu_struct *sp, int idx)
|
||||
unsigned long t;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
t = ACCESS_ONCE(per_cpu_ptr(sp->per_cpu_ref, cpu)->c[idx]);
|
||||
t = READ_ONCE(per_cpu_ptr(sp->per_cpu_ref, cpu)->c[idx]);
|
||||
sum += t;
|
||||
}
|
||||
return sum;
|
||||
@@ -265,8 +265,8 @@ static int srcu_readers_active(struct srcu_struct *sp)
|
||||
unsigned long sum = 0;
|
||||
|
||||
for_each_possible_cpu(cpu) {
|
||||
sum += ACCESS_ONCE(per_cpu_ptr(sp->per_cpu_ref, cpu)->c[0]);
|
||||
sum += ACCESS_ONCE(per_cpu_ptr(sp->per_cpu_ref, cpu)->c[1]);
|
||||
sum += READ_ONCE(per_cpu_ptr(sp->per_cpu_ref, cpu)->c[0]);
|
||||
sum += READ_ONCE(per_cpu_ptr(sp->per_cpu_ref, cpu)->c[1]);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
@@ -296,7 +296,7 @@ int __srcu_read_lock(struct srcu_struct *sp)
|
||||
{
|
||||
int idx;
|
||||
|
||||
idx = ACCESS_ONCE(sp->completed) & 0x1;
|
||||
idx = READ_ONCE(sp->completed) & 0x1;
|
||||
preempt_disable();
|
||||
__this_cpu_inc(sp->per_cpu_ref->c[idx]);
|
||||
smp_mb(); /* B */ /* Avoid leaking the critical section. */
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user