aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2011-02-18 14:32:28 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2011-02-18 14:32:28 -0500
commit3c18d4de86e4a7f93815c081e50e0543fa27200f (patch)
treeadea22bccd076266bf94cbda3ed6d9a98eea1206
parent2a324ce7b79a3a90cc2d4ade5d5f960a99000caa (diff)
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>
-rw-r--r--include/linux/list.h12
-rw-r--r--lib/list_debug.c39
2 files changed, 35 insertions, 16 deletions
diff --git a/include/linux/list.h b/include/linux/list.h
index 9a5f8a71810..3a54266a1e8 100644
--- a/include/linux/list.h
+++ b/include/linux/list.h
@@ -96,6 +96,11 @@ static inline void __list_del(struct list_head * prev, struct list_head * next)
96 * in an undefined state. 96 * in an undefined state.
97 */ 97 */
98#ifndef CONFIG_DEBUG_LIST 98#ifndef CONFIG_DEBUG_LIST
99static inline void __list_del_entry(struct list_head *entry)
100{
101 __list_del(entry->prev, entry->next);
102}
103
99static inline void list_del(struct list_head *entry) 104static inline void list_del(struct list_head *entry)
100{ 105{
101 __list_del(entry->prev, entry->next); 106 __list_del(entry->prev, entry->next);
@@ -103,6 +108,7 @@ static inline void list_del(struct list_head *entry)
103 entry->prev = LIST_POISON2; 108 entry->prev = LIST_POISON2;
104} 109}
105#else 110#else
111extern void __list_del_entry(struct list_head *entry);
106extern void list_del(struct list_head *entry); 112extern void list_del(struct list_head *entry);
107#endif 113#endif
108 114
@@ -135,7 +141,7 @@ static inline void list_replace_init(struct list_head *old,
135 */ 141 */
136static inline void list_del_init(struct list_head *entry) 142static inline void list_del_init(struct list_head *entry)
137{ 143{
138 __list_del(entry->prev, entry->next); 144 __list_del_entry(entry);
139 INIT_LIST_HEAD(entry); 145 INIT_LIST_HEAD(entry);
140} 146}
141 147
@@ -146,7 +152,7 @@ static inline void list_del_init(struct list_head *entry)
146 */ 152 */
147static inline void list_move(struct list_head *list, struct list_head *head) 153static 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 list_add(list, head); 156 list_add(list, head);
151} 157}
152 158
@@ -158,7 +164,7 @@ static inline void list_move(struct list_head *list, struct list_head *head)
158static inline void list_move_tail(struct list_head *list, 164static inline void list_move_tail(struct list_head *list,
159 struct list_head *head) 165 struct list_head *head)
160{ 166{
161 __list_del(list->prev, list->next); 167 __list_del_entry(list);
162 list_add_tail(list, head); 168 list_add_tail(list, head);
163} 169}
164 170
diff --git a/lib/list_debug.c b/lib/list_debug.c
index 344c710d16c..b8029a5583f 100644
--- a/lib/list_debug.c
+++ b/lib/list_debug.c
@@ -35,6 +35,31 @@ void __list_add(struct list_head *new,
35} 35}
36EXPORT_SYMBOL(__list_add); 36EXPORT_SYMBOL(__list_add);
37 37
38void __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}
61EXPORT_SYMBOL(__list_del_entry);
62
38/** 63/**
39 * list_del - deletes entry from list. 64 * list_del - deletes entry from list.
40 * @entry: the element to delete from the list. 65 * @entry: the element to delete from the list.
@@ -43,19 +68,7 @@ EXPORT_SYMBOL(__list_add);
43 */ 68 */
44void list_del(struct list_head *entry) 69void list_del(struct list_head *entry)
45{ 70{
46 WARN(entry->next == LIST_POISON1, 71 __list_del_entry(entry);
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);
59 entry->next = LIST_POISON1; 72 entry->next = LIST_POISON1;
60 entry->prev = LIST_POISON2; 73 entry->prev = LIST_POISON2;
61} 74}