Skip to content

Commit

Permalink
Expand CONFIG_DEBUG_LIST to several other list operations
Browse files Browse the repository at this point in the history
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 <[email protected]>
  • Loading branch information
torvalds committed Feb 18, 2011
1 parent 2a324ce commit 3c18d4d
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 16 deletions.
12 changes: 9 additions & 3 deletions include/linux/list.h
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,19 @@ static inline void __list_del(struct list_head * prev, struct list_head * next)
* in an undefined state.
*/
#ifndef CONFIG_DEBUG_LIST
static inline void __list_del_entry(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
}

static inline void list_del(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
entry->next = LIST_POISON1;
entry->prev = LIST_POISON2;
}
#else
extern void __list_del_entry(struct list_head *entry);
extern void list_del(struct list_head *entry);
#endif

Expand Down Expand Up @@ -135,7 +141,7 @@ static inline void list_replace_init(struct list_head *old,
*/
static inline void list_del_init(struct list_head *entry)
{
__list_del(entry->prev, entry->next);
__list_del_entry(entry);
INIT_LIST_HEAD(entry);
}

Expand All @@ -146,7 +152,7 @@ static inline void list_del_init(struct list_head *entry)
*/
static inline void list_move(struct list_head *list, struct list_head *head)
{
__list_del(list->prev, list->next);
__list_del_entry(list);
list_add(list, head);
}

Expand All @@ -158,7 +164,7 @@ static inline void list_move(struct list_head *list, struct list_head *head)
static inline void list_move_tail(struct list_head *list,
struct list_head *head)
{
__list_del(list->prev, list->next);
__list_del_entry(list);
list_add_tail(list, head);
}

Expand Down
39 changes: 26 additions & 13 deletions lib/list_debug.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,31 @@ void __list_add(struct list_head *new,
}
EXPORT_SYMBOL(__list_add);

void __list_del_entry(struct list_head *entry)
{
struct list_head *prev, *next;

prev = entry->prev;
next = entry->next;

if (WARN(next == LIST_POISON1,
"list_del corruption, %p->next is LIST_POISON1 (%p)\n",
entry, LIST_POISON1) ||
WARN(prev == LIST_POISON2,
"list_del corruption, %p->prev is LIST_POISON2 (%p)\n",
entry, LIST_POISON2) ||
WARN(prev->next != entry,
"list_del corruption. prev->next should be %p, "
"but was %p\n", entry, prev->next) ||
WARN(next->prev != entry,
"list_del corruption. next->prev should be %p, "
"but was %p\n", entry, next->prev))
return;

__list_del(prev, next);
}
EXPORT_SYMBOL(__list_del_entry);

/**
* list_del - deletes entry from list.
* @entry: the element to delete from the list.
Expand All @@ -43,19 +68,7 @@ EXPORT_SYMBOL(__list_add);
*/
void list_del(struct list_head *entry)
{
WARN(entry->next == LIST_POISON1,
"list_del corruption, next is LIST_POISON1 (%p)\n",
LIST_POISON1);
WARN(entry->next != LIST_POISON1 && entry->prev == LIST_POISON2,
"list_del corruption, prev is LIST_POISON2 (%p)\n",
LIST_POISON2);
WARN(entry->prev->next != entry,
"list_del corruption. prev->next should be %p, "
"but was %p\n", entry, entry->prev->next);
WARN(entry->next->prev != entry,
"list_del corruption. next->prev should be %p, "
"but was %p\n", entry, entry->next->prev);
__list_del(entry->prev, entry->next);
__list_del_entry(entry);
entry->next = LIST_POISON1;
entry->prev = LIST_POISON2;
}
Expand Down

0 comments on commit 3c18d4d

Please sign in to comment.