Commit 3c18d4de86e4a7f93815c081e50e0543fa27200f
1 parent
2a324ce7b7
Exists in
master
and in
39 other branches
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 |
lib/list_debug.c
... | ... | @@ -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 | } |