summaryrefslogtreecommitdiff
path: root/include/linux/list.h
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@home.transmeta.com>2003-06-11 19:31:26 -0700
committerLinus Torvalds <torvalds@home.transmeta.com>2003-06-11 19:31:26 -0700
commitf8cef8c2a2b142da9a447ad1d1f7538d0f056b33 (patch)
tree74fe012e283dce8e04b9580e28b1b8bdd60f26a8 /include/linux/list.h
parent58acfd93e36e774916b768646740a34bc5980283 (diff)
Fix rcu list poisoning - since another CPU may be traversing the list
as we delete the entry, we can only poison the back pointer, not the traversal pointer (rcu traversal only ever walks forward). Make __d_drop() take this into account.
Diffstat (limited to 'include/linux/list.h')
-rw-r--r--include/linux/list.h22
1 files changed, 20 insertions, 2 deletions
diff --git a/include/linux/list.h b/include/linux/list.h
index eed55ea5860a..ff4109f01a72 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -152,14 +152,17 @@ static inline void list_del(struct list_head *entry)
/**
* list_del_rcu - deletes entry from list without re-initialization
* @entry: the element to delete from the list.
+ *
* Note: list_empty on entry does not return true after this,
* the entry is in an undefined state. It is useful for RCU based
* lockfree traversal.
+ *
+ * In particular, it means that we can not poison the forward
+ * pointers that may still be used for walking the list.
*/
static inline void list_del_rcu(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
- entry->next = LIST_POISON1;
entry->prev = LIST_POISON2;
}
@@ -431,7 +434,22 @@ static __inline__ void hlist_del(struct hlist_node *n)
n->pprev = LIST_POISON2;
}
-#define hlist_del_rcu hlist_del /* list_del_rcu is identical too? */
+/**
+ * hlist_del_rcu - deletes entry from hash list without re-initialization
+ * @entry: the element to delete from the hash list.
+ *
+ * Note: list_unhashed() on entry does not return true after this,
+ * the entry is in an undefined state. It is useful for RCU based
+ * lockfree traversal.
+ *
+ * In particular, it means that we can not poison the forward
+ * pointers that may still be used for walking the hash list.
+ */
+static inline void hlist_del_rcu(struct hlist_node *n)
+{
+ __hlist_del(n);
+ n->pprev = LIST_POISON2;
+}
static __inline__ void hlist_del_init(struct hlist_node *n)
{