Merge branch 'core-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip

* 'core-fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip:
  rcu: Make RCU lockdep check the lockdep_recursion variable
  rcu: Update docs for rcu_access_pointer and rcu_dereference_protected
  rcu: Better explain the condition parameter of rcu_dereference_check()
  rcu: Add rcu_access_pointer and rcu_dereference_protected
This commit is contained in:
Linus Torvalds 2010-04-19 08:35:47 -07:00
commit 85341c6136
6 changed files with 120 additions and 30 deletions

View File

@ -34,7 +34,7 @@ NMI handler.
cpu = smp_processor_id(); cpu = smp_processor_id();
++nmi_count(cpu); ++nmi_count(cpu);
if (!rcu_dereference(nmi_callback)(regs, cpu)) if (!rcu_dereference_sched(nmi_callback)(regs, cpu))
default_do_nmi(regs); default_do_nmi(regs);
nmi_exit(); nmi_exit();
@ -47,12 +47,13 @@ function pointer. If this handler returns zero, do_nmi() invokes the
default_do_nmi() function to handle a machine-specific NMI. Finally, default_do_nmi() function to handle a machine-specific NMI. Finally,
preemption is restored. preemption is restored.
Strictly speaking, rcu_dereference() is not needed, since this code runs In theory, rcu_dereference_sched() is not needed, since this code runs
only on i386, which does not need rcu_dereference() anyway. However, only on i386, which in theory does not need rcu_dereference_sched()
it is a good documentation aid, particularly for anyone attempting to anyway. However, in practice it is a good documentation aid, particularly
do something similar on Alpha. for anyone attempting to do something similar on Alpha or on systems
with aggressive optimizing compilers.
Quick Quiz: Why might the rcu_dereference() be necessary on Alpha, Quick Quiz: Why might the rcu_dereference_sched() be necessary on Alpha,
given that the code referenced by the pointer is read-only? given that the code referenced by the pointer is read-only?
@ -99,17 +100,21 @@ invoke irq_enter() and irq_exit() on NMI entry and exit, respectively.
Answer to Quick Quiz Answer to Quick Quiz
Why might the rcu_dereference() be necessary on Alpha, given Why might the rcu_dereference_sched() be necessary on Alpha, given
that the code referenced by the pointer is read-only? that the code referenced by the pointer is read-only?
Answer: The caller to set_nmi_callback() might well have Answer: The caller to set_nmi_callback() might well have
initialized some data that is to be used by the initialized some data that is to be used by the new NMI
new NMI handler. In this case, the rcu_dereference() handler. In this case, the rcu_dereference_sched() would
would be needed, because otherwise a CPU that received be needed, because otherwise a CPU that received an NMI
an NMI just after the new handler was set might see just after the new handler was set might see the pointer
the pointer to the new NMI handler, but the old to the new NMI handler, but the old pre-initialized
pre-initialized version of the handler's data. version of the handler's data.
More important, the rcu_dereference() makes it clear This same sad story can happen on other CPUs when using
to someone reading the code that the pointer is being a compiler with aggressive pointer-value speculation
protected by RCU. optimizations.
More important, the rcu_dereference_sched() makes it
clear to someone reading the code that the pointer is
being protected by RCU-sched.

View File

@ -260,7 +260,8 @@ over a rather long period of time, but improvements are always welcome!
The reason that it is permissible to use RCU list-traversal The reason that it is permissible to use RCU list-traversal
primitives when the update-side lock is held is that doing so primitives when the update-side lock is held is that doing so
can be quite helpful in reducing code bloat when common code is can be quite helpful in reducing code bloat when common code is
shared between readers and updaters. shared between readers and updaters. Additional primitives
are provided for this case, as discussed in lockdep.txt.
10. Conversely, if you are in an RCU read-side critical section, 10. Conversely, if you are in an RCU read-side critical section,
and you don't hold the appropriate update-side lock, you -must- and you don't hold the appropriate update-side lock, you -must-
@ -344,8 +345,8 @@ over a rather long period of time, but improvements are always welcome!
requiring SRCU's read-side deadlock immunity or low read-side requiring SRCU's read-side deadlock immunity or low read-side
realtime latency. realtime latency.
Note that, rcu_assign_pointer() and rcu_dereference() relate to Note that, rcu_assign_pointer() relates to SRCU just as they do
SRCU just as they do to other forms of RCU. to other forms of RCU.
15. The whole point of call_rcu(), synchronize_rcu(), and friends 15. The whole point of call_rcu(), synchronize_rcu(), and friends
is to wait until all pre-existing readers have finished before is to wait until all pre-existing readers have finished before

View File

@ -32,9 +32,20 @@ checking of rcu_dereference() primitives:
srcu_dereference(p, sp): srcu_dereference(p, sp):
Check for SRCU read-side critical section. Check for SRCU read-side critical section.
rcu_dereference_check(p, c): rcu_dereference_check(p, c):
Use explicit check expression "c". Use explicit check expression "c". This is useful in
code that is invoked by both 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):
Use explicit check expression "c", and omit all barriers
and compiler constraints. This is useful when the data
structure cannot change, for example, in code that is
invoked only by updaters.
rcu_access_pointer(p):
Return the value of the pointer and omit all barriers,
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.
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 one of the rcu_read_lock_held() expression, but would normally include one of the rcu_read_lock_held()
@ -59,7 +70,20 @@ In case (1), the pointer is picked up in an RCU-safe manner for vanilla
RCU read-side critical sections, in case (2) the ->file_lock prevents RCU read-side critical sections, in case (2) the ->file_lock prevents
any change from taking place, and finally, in case (3) the current task any change from taking place, and finally, in case (3) the current task
is the only task accessing the file_struct, again preventing any change is the only task accessing the file_struct, again preventing any change
from taking place. from taking place. If the above statement was invoked only from updater
code, it could instead be written as follows:
file = rcu_dereference_protected(fdt->fd[fd],
lockdep_is_held(&files->file_lock) ||
atomic_read(&files->count) == 1);
This would verify cases #2 and #3 above, and furthermore lockdep would
complain if this was used in an RCU read-side critical section unless one
of these two cases held. Because rcu_dereference_protected() omits all
barriers and compiler constraints, it generates better code than do the
other flavors of rcu_dereference(). On the other hand, it is illegal
to use rcu_dereference_protected() if either the RCU-protected pointer
or the RCU-protected data that it points to can change concurrently.
There are currently only "universal" versions of the rcu_assign_pointer() There are currently only "universal" versions of the rcu_assign_pointer()
and RCU list-/tree-traversal primitives, which do not (yet) check for and RCU list-/tree-traversal primitives, which do not (yet) check for

View File

@ -840,6 +840,12 @@ SRCU: Initialization/cleanup
init_srcu_struct init_srcu_struct
cleanup_srcu_struct cleanup_srcu_struct
All: lockdep-checked RCU-protected pointer access
rcu_dereference_check
rcu_dereference_protected
rcu_access_pointer
See the comment headers in the source code (or the docbook generated See the comment headers in the source code (or the docbook generated
from them) for more information. from them) for more information.

View File

@ -101,10 +101,7 @@ extern struct lockdep_map rcu_sched_lock_map;
# define rcu_read_release_sched() \ # define rcu_read_release_sched() \
lock_release(&rcu_sched_lock_map, 1, _THIS_IP_) lock_release(&rcu_sched_lock_map, 1, _THIS_IP_)
static inline int debug_lockdep_rcu_enabled(void) extern int debug_lockdep_rcu_enabled(void);
{
return likely(rcu_scheduler_active && debug_locks);
}
/** /**
* rcu_read_lock_held - might we be in RCU read-side critical section? * rcu_read_lock_held - might we be in RCU read-side critical section?
@ -195,12 +192,30 @@ static inline int rcu_read_lock_sched_held(void)
/** /**
* rcu_dereference_check - rcu_dereference with debug checking * rcu_dereference_check - rcu_dereference with debug checking
* @p: The pointer to read, prior to dereferencing
* @c: The conditions under which the dereference will take place
* *
* Do an rcu_dereference(), but check that the context is correct. * Do an rcu_dereference(), but check that the conditions under which the
* For example, rcu_dereference_check(gp, rcu_read_lock_held()) to * dereference will take place are correct. Typically the conditions indicate
* ensure that the rcu_dereference_check() executes within an RCU * the various locking conditions that should be held at that point. The check
* read-side critical section. It is also possible to check for * should return true if the conditions are satisfied.
* locks being held, for example, by using lockdep_is_held(). *
* For example:
*
* bar = rcu_dereference_check(foo->bar, rcu_read_lock_held() ||
* lockdep_is_held(&foo->lock));
*
* could be used to indicate to lockdep that foo->bar may only be dereferenced
* if either the RCU read lock is held, or that the lock required to replace
* the bar struct at foo->bar is held.
*
* Note that the list of conditions may also include indications of when a lock
* need not be held, for example during initialisation or destruction of the
* target struct:
*
* bar = rcu_dereference_check(foo->bar, rcu_read_lock_held() ||
* lockdep_is_held(&foo->lock) ||
* atomic_read(&foo->usage) == 0);
*/ */
#define rcu_dereference_check(p, c) \ #define rcu_dereference_check(p, c) \
({ \ ({ \
@ -209,12 +224,44 @@ static inline int rcu_read_lock_sched_held(void)
rcu_dereference_raw(p); \ rcu_dereference_raw(p); \
}) })
/**
* rcu_dereference_protected - fetch RCU pointer when updates prevented
*
* Return the value of the specified RCU-protected pointer, but omit
* both the smp_read_barrier_depends() and the ACCESS_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
* with other references, so it should not be used without protection
* of appropriate locks.
*/
#define rcu_dereference_protected(p, c) \
({ \
if (debug_lockdep_rcu_enabled() && !(c)) \
lockdep_rcu_dereference(__FILE__, __LINE__); \
(p); \
})
#else /* #ifdef CONFIG_PROVE_RCU */ #else /* #ifdef CONFIG_PROVE_RCU */
#define rcu_dereference_check(p, c) rcu_dereference_raw(p) #define rcu_dereference_check(p, c) rcu_dereference_raw(p)
#define rcu_dereference_protected(p, c) (p)
#endif /* #else #ifdef CONFIG_PROVE_RCU */ #endif /* #else #ifdef CONFIG_PROVE_RCU */
/**
* rcu_access_pointer - fetch RCU pointer with no dereferencing
*
* Return the value of the specified RCU-protected pointer, but omit the
* smp_read_barrier_depends() and keep the ACCESS_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. This may also be used in cases where update-side locks prevent
* the value of the pointer from changing, but rcu_dereference_protected()
* is a lighter-weight primitive for this use case.
*/
#define rcu_access_pointer(p) ACCESS_ONCE(p)
/** /**
* rcu_read_lock - mark the beginning of an RCU read-side critical section. * rcu_read_lock - mark the beginning of an RCU read-side critical section.
* *

View File

@ -69,6 +69,13 @@ EXPORT_SYMBOL_GPL(rcu_scheduler_active);
#ifdef CONFIG_DEBUG_LOCK_ALLOC #ifdef CONFIG_DEBUG_LOCK_ALLOC
int debug_lockdep_rcu_enabled(void)
{
return rcu_scheduler_active && debug_locks &&
current->lockdep_recursion == 0;
}
EXPORT_SYMBOL_GPL(debug_lockdep_rcu_enabled);
/** /**
* rcu_read_lock_bh_held - might we be in RCU-bh read-side critical section? * rcu_read_lock_bh_held - might we be in RCU-bh read-side critical section?
* *