[PATCH] RCU documentation fixes (January 2006 update)
[linux-3.10.git] / Documentation / RCU / listRCU.txt
index bda6ead..1fd1753 100644 (file)
@@ -32,6 +32,7 @@ implementation of audit_filter_task() might be as follows:
                enum audit_state   state;
 
                read_lock(&auditsc_lock);
+               /* Note: audit_netlink_sem held by caller. */
                list_for_each_entry(e, &audit_tsklist, list) {
                        if (audit_filter_rules(tsk, &e->rule, NULL, &state)) {
                                read_unlock(&auditsc_lock);
@@ -55,6 +56,7 @@ This means that RCU can be easily applied to the read side, as follows:
                enum audit_state   state;
 
                rcu_read_lock();
+               /* Note: audit_netlink_sem held by caller. */
                list_for_each_entry_rcu(e, &audit_tsklist, list) {
                        if (audit_filter_rules(tsk, &e->rule, NULL, &state)) {
                                rcu_read_unlock();
@@ -139,12 +141,15 @@ Normally, the write_lock() and write_unlock() would be replaced by
 a spin_lock() and a spin_unlock(), but in this case, all callers hold
 audit_netlink_sem, so no additional locking is required.  The auditsc_lock
 can therefore be eliminated, since use of RCU eliminates the need for
-writers to exclude readers.
+writers to exclude readers.  Normally, the write_lock() calls would
+be converted into spin_lock() calls.
 
 The list_del(), list_add(), and list_add_tail() primitives have been
 replaced by list_del_rcu(), list_add_rcu(), and list_add_tail_rcu().
 The _rcu() list-manipulation primitives add memory barriers that are
-needed on weakly ordered CPUs (most of them!).
+needed on weakly ordered CPUs (most of them!).  The list_del_rcu()
+primitive omits the pointer poisoning debug-assist code that would
+otherwise cause concurrent readers to fail spectacularly.
 
 So, when readers can tolerate stale data and when entries are either added
 or deleted, without in-place modification, it is very easy to use RCU!
@@ -166,6 +171,7 @@ otherwise, the added fields would need to be filled in):
                struct audit_newentry *ne;
 
                write_lock(&auditsc_lock);
+               /* Note: audit_netlink_sem held by caller. */
                list_for_each_entry(e, list, list) {
                        if (!audit_compare_rule(rule, &e->rule)) {
                                e->rule.action = newaction;
@@ -199,8 +205,7 @@ RCU ("read-copy update") its name.  The RCU code is as follows:
                                audit_copy_rule(&ne->rule, &e->rule);
                                ne->rule.action = newaction;
                                ne->rule.file_count = newfield_count;
-                               list_add_rcu(ne, e);
-                               list_del(e);
+                               list_replace_rcu(e, ne);
                                call_rcu(&e->rcu, audit_free_rule, e);
                                return 0;
                        }
@@ -227,7 +232,7 @@ entry does not exist.  For this to be helpful, the search function must
 return holding the per-entry spinlock, as ipc_lock() does in fact do.
 
 Quick Quiz:  Why does the search function need to return holding the
-per-entry lock for this deleted-flag technique to be helpful?
+       per-entry lock for this deleted-flag technique to be helpful?
 
 If the system-call audit module were to ever need to reject stale data,
 one way to accomplish this would be to add a "deleted" flag and a "lock"
@@ -270,8 +275,8 @@ flag under the spinlock as follows:
        {
                struct audit_entry  *e;
 
-               /* Do not use the _rcu iterator here, since this is the only
-                * deletion routine. */
+               /* Do not need to use the _rcu iterator here, since this
+                * is the only deletion routine. */
                list_for_each_entry(e, list, list) {
                        if (!audit_compare_rule(rule, &e->rule)) {
                                spin_lock(&e->lock);
@@ -299,9 +304,12 @@ function to reject newly deleted data.
 
 
 Answer to Quick Quiz
-
-If the search function drops the per-entry lock before returning, then
-the caller will be processing stale data in any case.  If it is really
-OK to be processing stale data, then you don't need a "deleted" flag.
-If processing stale data really is a problem, then you need to hold the
-per-entry lock across all of the code that uses the value looked up.
+       Why does the search function need to return holding the per-entry
+       lock for this deleted-flag technique to be helpful?
+
+       If the search function drops the per-entry lock before returning,
+       then the caller will be processing stale data in any case.  If it
+       is really OK to be processing stale data, then you don't need a
+       "deleted" flag.  If processing stale data really is a problem,
+       then you need to hold the per-entry lock across all of the code
+       that uses the value that was returned.