rcu: List-debug variants of rcu list routines.
authorDave Jones <davej@redhat.com>
Thu, 15 Mar 2012 02:17:39 +0000 (22:17 -0400)
committerPaul E. McKenney <paulmck@linux.vnet.ibm.com>
Wed, 25 Apr 2012 03:54:49 +0000 (20:54 -0700)
* Make __list_add_rcu check the next->prev and prev->next pointers
  just like __list_add does.
* Make list_del_rcu use __list_del_entry, which does the same checking
  at deletion time.

Has been running for a week here without anything being tripped up,
but it seems worth adding for completeness just in case something
ever does corrupt those lists.

Signed-off-by: Dave Jones <davej@redhat.com>
Signed-off-by: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
include/linux/rculist.h
lib/list_debug.c

index d079290..a20c050 100644 (file)
@@ -30,6 +30,7 @@
  * This is only for internal list manipulation where we know
  * the prev/next entries already!
  */
+#ifndef CONFIG_DEBUG_LIST
 static inline void __list_add_rcu(struct list_head *new,
                struct list_head *prev, struct list_head *next)
 {
@@ -38,6 +39,10 @@ static inline void __list_add_rcu(struct list_head *new,
        rcu_assign_pointer(list_next_rcu(prev), new);
        next->prev = new;
 }
+#else
+extern void __list_add_rcu(struct list_head *new,
+               struct list_head *prev, struct list_head *next);
+#endif
 
 /**
  * list_add_rcu - add a new entry to rcu-protected list
@@ -108,7 +113,7 @@ static inline void list_add_tail_rcu(struct list_head *new,
  */
 static inline void list_del_rcu(struct list_head *entry)
 {
-       __list_del(entry->prev, entry->next);
+       __list_del_entry(entry);
        entry->prev = LIST_POISON2;
 }
 
index 982b850..3810b48 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/list.h>
 #include <linux/bug.h>
 #include <linux/kernel.h>
+#include <linux/rculist.h>
 
 /*
  * Insert a new entry between two known consecutive entries.
@@ -75,3 +76,24 @@ void list_del(struct list_head *entry)
        entry->prev = LIST_POISON2;
 }
 EXPORT_SYMBOL(list_del);
+
+/*
+ * RCU variants.
+ */
+void __list_add_rcu(struct list_head *new,
+                   struct list_head *prev, struct list_head *next)
+{
+       WARN(next->prev != prev,
+               "list_add_rcu corruption. next->prev should be "
+               "prev (%p), but was %p. (next=%p).\n",
+               prev, next->prev, next);
+       WARN(prev->next != next,
+               "list_add_rcu corruption. prev->next should be "
+               "next (%p), but was %p. (prev=%p).\n",
+               next, prev->next, prev);
+       new->next = next;
+       new->prev = prev;
+       rcu_assign_pointer(list_next_rcu(prev), new);
+       next->prev = new;
+}
+EXPORT_SYMBOL(__list_add_rcu);