Commit cf9fbf80 authored by Paul E. McKenney's avatar Paul E. McKenney

documentation: RCU-protected array indexes no longer supported

Signed-off-by: default avatarPaul E. McKenney <paulmck@linux.vnet.ibm.com>
parent 1ebee801
...@@ -10,7 +10,19 @@ also be used to protect arrays. Three situations are as follows: ...@@ -10,7 +10,19 @@ also be used to protect arrays. Three situations are as follows:
3. Resizeable Arrays 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 Situation 1: Hash Tables
...@@ -36,9 +48,9 @@ Quick Quiz: Why is it so important that updates be rare when ...@@ -36,9 +48,9 @@ Quick Quiz: Why is it so important that updates be rare when
Situation 3: Resizeable Arrays Situation 3: Resizeable Arrays
Use of RCU for resizeable arrays is demonstrated by the grow_ary() 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 function formerly used by the System V IPC code. The array is used
semaphore, message-queue, and shared-memory IDs to the data structure to map from semaphore, message-queue, and shared-memory IDs to the data
that represents the corresponding IPC construct. The grow_ary() structure that represents the corresponding IPC construct. The grow_ary()
function does not acquire any locks; instead its caller must hold the function does not acquire any locks; instead its caller must hold the
ids->sem semaphore. ids->sem semaphore.
......
...@@ -47,11 +47,6 @@ checking of rcu_dereference() primitives: ...@@ -47,11 +47,6 @@ checking of rcu_dereference() primitives:
Use explicit check expression "c" along with Use explicit check expression "c" along with
srcu_read_lock_held()(). This is useful in code that srcu_read_lock_held()(). This is useful in code that
is invoked by both SRCU readers and updaters. 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): rcu_dereference_raw(p):
Don't check. (Use sparingly, if at all.) Don't check. (Use sparingly, if at all.)
rcu_dereference_protected(p, c): rcu_dereference_protected(p, c):
...@@ -64,11 +59,6 @@ checking of rcu_dereference() primitives: ...@@ -64,11 +59,6 @@ checking of rcu_dereference() primitives:
but retain the compiler constraints that prevent duplicating but retain the compiler constraints that prevent duplicating
or coalescsing. This is useful when when testing the or coalescsing. This is useful when when testing the
value of the pointer itself, for example, against NULL. 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 The rcu_dereference_check() check expression can be any boolean
expression, but would normally include a lockdep expression. However, 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 ...@@ -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 for an example where the compiler can in fact deduce the exact
value of the pointer, and thus cause misordering. 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 o Avoid cancellation when using the "+" and "-" infix arithmetic
operators. For example, for a given variable "x", avoid operators. For example, for a given variable "x", avoid
"(x-x)". There are similar arithmetic pitfalls from other "(x-x)". There are similar arithmetic pitfalls from other
...@@ -76,14 +65,15 @@ o Do not use the results from the boolean "&&" and "||" when ...@@ -76,14 +65,15 @@ o Do not use the results from the boolean "&&" and "||" when
dereferencing. For example, the following (rather improbable) dereferencing. For example, the following (rather improbable)
code is buggy: code is buggy:
int a[2]; int *p;
int index; int *q;
int force_zero_index = 1;
... ...
r1 = rcu_dereference(i1) p = rcu_dereference(gp)
r2 = a[r1 && force_zero_index]; /* BUGGY!!! */ q = &global_q;
q += p != &oom_p1 && p != &oom_p2;
r1 = *q; /* BUGGY!!! */
The reason this is buggy is that "&&" and "||" are often compiled The reason this is buggy is that "&&" and "||" are often compiled
using branches. While weak-memory machines such as ARM or PowerPC using branches. While weak-memory machines such as ARM or PowerPC
...@@ -94,14 +84,15 @@ o Do not use the results from relational operators ("==", "!=", ...@@ -94,14 +84,15 @@ o Do not use the results from relational operators ("==", "!=",
">", ">=", "<", or "<=") when dereferencing. For example, ">", ">=", "<", or "<=") when dereferencing. For example,
the following (quite strange) code is buggy: the following (quite strange) code is buggy:
int a[2]; int *p;
int index; int *q;
int flip_index = 0;
... ...
r1 = rcu_dereference(i1) p = rcu_dereference(gp)
r2 = a[r1 != flip_index]; /* BUGGY!!! */ q = &global_q;
q += p > &oom_p;
r1 = *q; /* BUGGY!!! */
As before, the reason this is buggy is that relational operators As before, the reason this is buggy is that relational operators
are often compiled using branches. And as before, although are often compiled using branches. And as before, although
......
...@@ -879,9 +879,7 @@ SRCU: Initialization/cleanup ...@@ -879,9 +879,7 @@ SRCU: Initialization/cleanup
All: lockdep-checked RCU-protected pointer access All: lockdep-checked RCU-protected pointer access
rcu_access_index
rcu_access_pointer rcu_access_pointer
rcu_dereference_index_check
rcu_dereference_raw rcu_dereference_raw
rcu_lockdep_assert rcu_lockdep_assert
rcu_sleep_check rcu_sleep_check
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment