Commit 3c18d4de86e4a7f93815c081e50e0543fa27200f

Authored by Linus Torvalds
1 parent 2a324ce7b7

Expand CONFIG_DEBUG_LIST to several other list operations

When list debugging is enabled, we aim to readably show list corruption
errors, and the basic list_add/list_del operations end up having extra
debugging code in them to do some basic validation of the list entries.

However, "list_del_init()" and "list_move[_tail]()" ended up avoiding
the debug code due to how they were written. This fixes that.

So the _next_ time we have list_move() problems with stale list entries,
we'll hopefully have an easier time finding them..

Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

Showing 2 changed files with 35 additions and 16 deletions Side-by-side Diff

include/linux/list.h
... ... @@ -96,6 +96,11 @@
96 96 * in an undefined state.
97 97 */
98 98 #ifndef CONFIG_DEBUG_LIST
  99 +static inline void __list_del_entry(struct list_head *entry)
  100 +{
  101 + __list_del(entry->prev, entry->next);
  102 +}
  103 +
99 104 static inline void list_del(struct list_head *entry)
100 105 {
101 106 __list_del(entry->prev, entry->next);
... ... @@ -103,6 +108,7 @@
103 108 entry->prev = LIST_POISON2;
104 109 }
105 110 #else
  111 +extern void __list_del_entry(struct list_head *entry);
106 112 extern void list_del(struct list_head *entry);
107 113 #endif
108 114  
... ... @@ -135,7 +141,7 @@
135 141 */
136 142 static inline void list_del_init(struct list_head *entry)
137 143 {
138   - __list_del(entry->prev, entry->next);
  144 + __list_del_entry(entry);
139 145 INIT_LIST_HEAD(entry);
140 146 }
141 147  
... ... @@ -146,7 +152,7 @@
146 152 */
147 153 static inline void list_move(struct list_head *list, struct list_head *head)
148 154 {
149   - __list_del(list->prev, list->next);
  155 + __list_del_entry(list);
150 156 list_add(list, head);
151 157 }
152 158  
... ... @@ -158,7 +164,7 @@
158 164 static inline void list_move_tail(struct list_head *list,
159 165 struct list_head *head)
160 166 {
161   - __list_del(list->prev, list->next);
  167 + __list_del_entry(list);
162 168 list_add_tail(list, head);
163 169 }
164 170  
... ... @@ -35,6 +35,31 @@
35 35 }
36 36 EXPORT_SYMBOL(__list_add);
37 37  
  38 +void __list_del_entry(struct list_head *entry)
  39 +{
  40 + struct list_head *prev, *next;
  41 +
  42 + prev = entry->prev;
  43 + next = entry->next;
  44 +
  45 + if (WARN(next == LIST_POISON1,
  46 + "list_del corruption, %p->next is LIST_POISON1 (%p)\n",
  47 + entry, LIST_POISON1) ||
  48 + WARN(prev == LIST_POISON2,
  49 + "list_del corruption, %p->prev is LIST_POISON2 (%p)\n",
  50 + entry, LIST_POISON2) ||
  51 + WARN(prev->next != entry,
  52 + "list_del corruption. prev->next should be %p, "
  53 + "but was %p\n", entry, prev->next) ||
  54 + WARN(next->prev != entry,
  55 + "list_del corruption. next->prev should be %p, "
  56 + "but was %p\n", entry, next->prev))
  57 + return;
  58 +
  59 + __list_del(prev, next);
  60 +}
  61 +EXPORT_SYMBOL(__list_del_entry);
  62 +
38 63 /**
39 64 * list_del - deletes entry from list.
40 65 * @entry: the element to delete from the list.
... ... @@ -43,19 +68,7 @@
43 68 */
44 69 void list_del(struct list_head *entry)
45 70 {
46   - WARN(entry->next == LIST_POISON1,
47   - "list_del corruption, next is LIST_POISON1 (%p)\n",
48   - LIST_POISON1);
49   - WARN(entry->next != LIST_POISON1 && entry->prev == LIST_POISON2,
50   - "list_del corruption, prev is LIST_POISON2 (%p)\n",
51   - LIST_POISON2);
52   - WARN(entry->prev->next != entry,
53   - "list_del corruption. prev->next should be %p, "
54   - "but was %p\n", entry, entry->prev->next);
55   - WARN(entry->next->prev != entry,
56   - "list_del corruption. next->prev should be %p, "
57   - "but was %p\n", entry, entry->next->prev);
58   - __list_del(entry->prev, entry->next);
  71 + __list_del_entry(entry);
59 72 entry->next = LIST_POISON1;
60 73 entry->prev = LIST_POISON2;
61 74 }