lkml.org 
[lkml]   [2010]   [Feb]   [17]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH tip/core/rcu 13/18] rcu: documentation update for CONFIG_PROVE_RCU
    Date
    Adds a lockdep.txt file and updates checklist.txt and whatisRCU.txt
    to reflect the new lockdep-enabled capabilities of RCU.

    Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
    ---
    Documentation/RCU/00-INDEX | 2 +
    Documentation/RCU/checklist.txt | 34 +++++++++++--------
    Documentation/RCU/lockdep.txt | 67 +++++++++++++++++++++++++++++++++++++++
    Documentation/RCU/whatisRCU.txt | 13 +++++---
    4 files changed, 97 insertions(+), 19 deletions(-)
    create mode 100644 Documentation/RCU/lockdep.txt
    diff --git a/Documentation/RCU/00-INDEX b/Documentation/RCU/00-INDEX
    index 0a27ea9..71b6f50 100644
    --- a/Documentation/RCU/00-INDEX
    +++ b/Documentation/RCU/00-INDEX
    @@ -6,6 +6,8 @@ checklist.txt
    - Review Checklist for RCU Patches
    listRCU.txt
    - Using RCU to Protect Read-Mostly Linked Lists
    +lockdep.txt
    + - RCU and lockdep checking
    NMI-RCU.txt
    - Using RCU to Protect Dynamic NMI Handlers
    rcubarrier.txt
    diff --git a/Documentation/RCU/checklist.txt b/Documentation/RCU/checklist.txt
    index 767cf06..cbc180f 100644
    --- a/Documentation/RCU/checklist.txt
    +++ b/Documentation/RCU/checklist.txt
    @@ -127,10 +127,14 @@ over a rather long period of time, but improvements are always welcome!
    perfectly legal (if redundant) for update-side code to
    use rcu_dereference() and the "_rcu()" list-traversal
    primitives. This is particularly useful in code that
    - is common to readers and updaters. However, neither
    - rcu_dereference() nor the "_rcu()" list-traversal
    - primitives can substitute for a good concurrency design
    - coordinating among multiple updaters.
    + is common to readers and updaters. However, lockdep
    + will complain if you access rcu_dereference() outside
    + of an RCU read-side critical section. See lockdep.txt
    + to learn what to do about this.
    +
    + Of course, neither rcu_dereference() nor the "_rcu()"
    + list-traversal primitives can substitute for a good
    + concurrency design coordinating among multiple updaters.

    b. If the list macros are being used, the list_add_tail_rcu()
    and list_add_rcu() primitives must be used in order
    @@ -249,7 +253,9 @@ over a rather long period of time, but improvements are always welcome!
    must be protected by appropriate update-side locks. RCU
    read-side critical sections are delimited by rcu_read_lock()
    and rcu_read_unlock(), or by similar primitives such as
    - rcu_read_lock_bh() and rcu_read_unlock_bh().
    + rcu_read_lock_bh() and rcu_read_unlock_bh(), in which case
    + the matching rcu_dereference() primitive must be used in order
    + to keep lockdep happy, in this case, rcu_dereference_bh().

    The reason that it is permissible to use RCU list-traversal
    primitives when the update-side lock is held is that doing so
    @@ -302,15 +308,15 @@ over a rather long period of time, but improvements are always welcome!
    not the case, a self-spawning RCU callback would prevent the
    victim CPU from ever going offline.)

    -14. SRCU (srcu_read_lock(), srcu_read_unlock(), synchronize_srcu(),
    - and synchronize_srcu_expedited()) may only be invoked from
    - process context. Unlike other forms of RCU, it -is- permissible
    - to block in an SRCU read-side critical section (demarked by
    - srcu_read_lock() and srcu_read_unlock()), hence the "SRCU":
    - "sleepable RCU". Please note that if you don't need to sleep
    - in read-side critical sections, you should be using RCU rather
    - than SRCU, because RCU is almost always faster and easier to
    - use than is SRCU.
    +14. SRCU (srcu_read_lock(), srcu_read_unlock(), srcu_dereference(),
    + synchronize_srcu(), and synchronize_srcu_expedited()) may only
    + be invoked from process context. Unlike other forms of RCU, it
    + -is- permissible to block in an SRCU read-side critical section
    + (demarked by srcu_read_lock() and srcu_read_unlock()), hence the
    + "SRCU": "sleepable RCU". Please note that if you don't need
    + to sleep in read-side critical sections, you should be using
    + RCU rather than SRCU, because RCU is almost always faster and
    + easier to use than is SRCU.

    Also unlike other forms of RCU, explicit initialization
    and cleanup is required via init_srcu_struct() and
    diff --git a/Documentation/RCU/lockdep.txt b/Documentation/RCU/lockdep.txt
    new file mode 100644
    index 0000000..fe24b58
    --- /dev/null
    +++ b/Documentation/RCU/lockdep.txt
    @@ -0,0 +1,67 @@
    +RCU and lockdep checking
    +
    +All flavors of RCU have lockdep checking available, so that lockdep is
    +aware of when each task enters and leaves any flavor of RCU read-side
    +critical section. Each flavor of RCU is tracked separately (but note
    +that this is not the case in 2.6.32 and earlier). This allows lockdep's
    +tracking to include RCU state, which can sometimes help when debugging
    +deadlocks and the like.
    +
    +In addition, RCU provides the following primitives that check lockdep's
    +state:
    +
    + rcu_read_lock_held() for normal RCU.
    + rcu_read_lock_bh_held() for RCU-bh.
    + rcu_read_lock_sched_held() for RCU-sched.
    + srcu_read_lock_held() for SRCU.
    +
    +These functions are conservative, and will therefore return 1 if they
    +aren't certain (for example, if CONFIG_DEBUG_LOCK_ALLOC is not set).
    +This prevents things like WARN_ON(!rcu_read_lock_held()) from giving false
    +positives when lockdep is disabled.
    +
    +In addition, a separate kernel config parameter CONFIG_PROVE_RCU enables
    +checking of rcu_dereference() primitives:
    +
    + rcu_dereference(p):
    + Check for RCU read-side critical section.
    + rcu_dereference_bh(p):
    + Check for RCU-bh read-side critical section.
    + rcu_dereference_sched(p):
    + Check for RCU-sched read-side critical section.
    + srcu_dereference(p, sp):
    + Check for SRCU read-side critical section.
    + rcu_dereference_check(p, c):
    + Use explicit check expression "c".
    + rcu_dereference_raw(p)
    + Don't check. (Use sparingly, if at all.)
    +
    +The rcu_dereference_check() check expression can be any boolean
    +expression, but would normally include one of the rcu_read_lock_held()
    +family of functions and a lockdep expression. However, any boolean
    +expression can be used. For a moderately ornate example, consider
    +the following:
    +
    + file = rcu_dereference_check(fdt->fd[fd],
    + rcu_read_lock_held() ||
    + lockdep_is_held(&files->file_lock) ||
    + atomic_read(&files->count) == 1);
    +
    +This expression picks up the pointer "fdt->fd[fd]" in an RCU-safe manner,
    +and, if CONFIG_PROVE_RCU is configured, verifies that this expression
    +is used in:
    +
    +1. An RCU read-side critical section, or
    +2. with files->file_lock held, or
    +3. on an unshared files_struct.
    +
    +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
    +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
    +from taking place.
    +
    +There are currently only "universal" versions of the rcu_assign_pointer()
    +and RCU list-/tree-traversal primitives, which do not (yet) check for
    +being in an RCU read-side critical section. In the future, separate
    +versions of these primitives might be created.
    diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt
    index 469a58b..1dc00ee 100644
    --- a/Documentation/RCU/whatisRCU.txt
    +++ b/Documentation/RCU/whatisRCU.txt
    @@ -323,15 +323,17 @@ used as follows:
    Defer Protect

    a. synchronize_rcu() rcu_read_lock() / rcu_read_unlock()
    - call_rcu()
    + call_rcu() rcu_dereference()

    b. call_rcu_bh() rcu_read_lock_bh() / rcu_read_unlock_bh()
    + rcu_dereference_bh()

    c. synchronize_sched() rcu_read_lock_sched() / rcu_read_unlock_sched()
    preempt_disable() / preempt_enable()
    local_irq_save() / local_irq_restore()
    hardirq enter / hardirq exit
    NMI enter / NMI exit
    + rcu_dereference_sched()

    These three mechanisms are used as follows:

    @@ -781,9 +783,8 @@ Linux-kernel source code, but it helps to have a full list of the
    APIs, since there does not appear to be a way to categorize them
    in docbook. Here is the list, by category.

    -RCU pointer/list traversal:
    +RCU list traversal:

    - rcu_dereference
    list_for_each_entry_rcu
    hlist_for_each_entry_rcu
    hlist_nulls_for_each_entry_rcu
    @@ -809,7 +810,7 @@ RCU: Critical sections Grace period Barrier

    rcu_read_lock synchronize_net rcu_barrier
    rcu_read_unlock synchronize_rcu
    - synchronize_rcu_expedited
    + rcu_dereference synchronize_rcu_expedited
    call_rcu


    @@ -817,7 +818,7 @@ bh: Critical sections Grace period Barrier

    rcu_read_lock_bh call_rcu_bh rcu_barrier_bh
    rcu_read_unlock_bh synchronize_rcu_bh
    - synchronize_rcu_bh_expedited
    + rcu_dereference_bh synchronize_rcu_bh_expedited


    sched: Critical sections Grace period Barrier
    @@ -826,12 +827,14 @@ sched: Critical sections Grace period Barrier
    rcu_read_unlock_sched call_rcu_sched
    [preempt_disable] synchronize_sched_expedited
    [and friends]
    + rcu_dereference_sched


    SRCU: Critical sections Grace period Barrier

    srcu_read_lock synchronize_srcu N/A
    srcu_read_unlock synchronize_srcu_expedited
    + srcu_dereference

    SRCU: Initialization/cleanup
    init_srcu_struct
    --
    1.6.6


    \
     
     \ /
      Last update: 2010-02-17 21:39    [from the cache]
    ©2003-2011 Jasper Spaans