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>

+35 -16
+9 -3
include/linux/list.h
··· 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); ··· 108 103 entry->prev = LIST_POISON2; 109 104 } 110 105 #else 106 + extern void __list_del_entry(struct list_head *entry); 111 107 extern void list_del(struct list_head *entry); 112 108 #endif 113 109 ··· 141 135 */ 142 136 static inline void list_del_init(struct list_head *entry) 143 137 { 144 - __list_del(entry->prev, entry->next); 138 + __list_del_entry(entry); 145 139 INIT_LIST_HEAD(entry); 146 140 } 147 141 ··· 152 146 */ 153 147 static inline void list_move(struct list_head *list, struct list_head *head) 154 148 { 155 - __list_del(list->prev, list->next); 149 + __list_del_entry(list); 156 150 list_add(list, head); 157 151 } 158 152 ··· 164 158 static inline void list_move_tail(struct list_head *list, 165 159 struct list_head *head) 166 160 { 167 - __list_del(list->prev, list->next); 161 + __list_del_entry(list); 168 162 list_add_tail(list, head); 169 163 } 170 164
+26 -13
lib/list_debug.c
··· 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. ··· 68 43 */ 69 44 void list_del(struct list_head *entry) 70 45 { 71 - WARN(entry->next == LIST_POISON1, 72 - "list_del corruption, next is LIST_POISON1 (%p)\n", 73 - LIST_POISON1); 74 - WARN(entry->next != LIST_POISON1 && entry->prev == LIST_POISON2, 75 - "list_del corruption, prev is LIST_POISON2 (%p)\n", 76 - LIST_POISON2); 77 - WARN(entry->prev->next != entry, 78 - "list_del corruption. prev->next should be %p, " 79 - "but was %p\n", entry, entry->prev->next); 80 - WARN(entry->next->prev != entry, 81 - "list_del corruption. next->prev should be %p, " 82 - "but was %p\n", entry, entry->next->prev); 83 - __list_del(entry->prev, entry->next); 46 + __list_del_entry(entry); 84 47 entry->next = LIST_POISON1; 85 48 entry->prev = LIST_POISON2; 86 49 }