public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* Re: memory corruptor in .18rc1-git
@ 2006-07-15 19:54 Chuck Ebbert
  2006-07-15 20:04 ` Dave Jones
  0 siblings, 1 reply; 9+ messages in thread
From: Chuck Ebbert @ 2006-07-15 19:54 UTC (permalink / raw)
  To: Dave Jones; +Cc: linux-kernel, Andrew Morton, Linus Torvalds, Willy Tarreau

In-Reply-To: <20060714043112.GA20478@redhat.com>

On Fri, 14 Jul 2006 00:31:12 -0400, Dave Jones wrote:

> +/**
> + * list_add - add a new entry
> + * @new: new entry to be added
> + * @head: list head to add it after
> + *
> + * Insert a new entry after the specified head.
> + * This is good for implementing stacks.
> + */
> +void list_add(struct list_head *new, struct list_head *head)
> +{
> +     if (head->next->prev != head) {
> +             printk("List corruption. next->prev should be %p, but was %p\n",
> +                     head, head->next->prev);
> +             BUG();
> +     }
> +     if (head->prev->next != head) {
> +             printk("List corruption. prev->next should be %p, but was %p\n",
> +                     head, head->prev->next);
> +             BUG();
> +     }
> +
> +     __list_add(new, head, head->next);
> +}
> +EXPORT_SYMBOL(list_add);
> +
> +/**
> + * list_del - deletes entry from list.
> + * @entry: the element to delete from the list.
> + * Note: list_empty on entry does not return true after this, the entry is
> + * in an undefined state.
> + */
> +void list_del(struct list_head *entry)
> +{
> +     if (entry->prev->next != entry) {
> +             printk("List corruption. prev->next should be %p, but was %p\n",
> +                     entry, entry->prev->next);
> +             BUG();
> +     }
> +     if (entry->next->prev != entry) {
> +             printk("List corruption. next->prev should be %p, but was %p\n",
> +                     entry, entry->next->prev);
> +             BUG();
> +     }
> +     __list_del(entry->prev, entry->next);
> +     entry->next = LIST_POISON1;
> +     entry->prev = LIST_POISON2;
> +}
> +EXPORT_SYMBOL(list_del);
> +
>

Shouldn't those four 'if' statements use unlikely()?  There's no sense
causing more slowdown than necessary, even in debug code.

And I'd change the messages slightly, e.g.:

        "list_add: corruption: next->prev should be %p, was %p\n"

Some people build (accidentally?) without verbose debug info and
don't get line numbers.

-- 
Chuck
 "You can't read a newspaper if you can't read."  --George W. Bush

^ permalink raw reply	[flat|nested] 9+ messages in thread
* memory corruptor in .18rc1-git
@ 2006-07-13 22:13 Dave Jones
  2006-07-13 22:24 ` Andrew Morton
  0 siblings, 1 reply; 9+ messages in thread
From: Dave Jones @ 2006-07-13 22:13 UTC (permalink / raw)
  To: Linux Kernel; +Cc: Linus Torvalds, Andrew Morton

Three times in the last week, I've had a box running the -git-du-jour
spontaneously reboot.  It just happened again, this time I had a serial
console hooked up, but it rebooted before transferring much data.
The one thing it did spew however was "List corruption. prev->ne",
which came from the patch below which I had in my tree.
(The latter half is likely irrelevant, and came from chasing a different bug)

Things in common at all three times it happened..
reading email, and listening to oggs with rhythmbox.
Another ALSA bug maybe ?

I've up'd the speed of the serial console, in the hope that more chars
make it over the wire before reboot should this happen again.

		Dave


--- linux-2.6/include/linux/list.h~	2005-08-08 15:34:50.000000000 -0400
+++ linux-2.6/include/linux/list.h	2005-08-08 15:35:22.000000000 -0400
@@ -5,7 +5,9 @@
 
 #include <linux/stddef.h>
 #include <linux/prefetch.h>
+#include <linux/kernel.h>
 #include <asm/system.h>
+#include <asm/bug.h>
 
 /*
  * These are non-NULL pointers that will result in page faults
@@ -52,6 +52,16 @@ static inline void __list_add(struct lis
 			      struct list_head *prev,
 			      struct list_head *next)
 {
+	if (next->prev != prev) {
+		printk("List corruption. next->prev should be %p, but was %p\n",
+				prev, next->prev);
+		BUG();
+	}
+	if (prev->next != next) {
+		printk("List corruption. prev->next should be %p, but was %p\n",
+				next, prev->next);
+		BUG();
+	}
 	next->prev = new;
 	new->next = next;
 	new->prev = prev;
@@ -162,6 +162,16 @@ static inline void __list_del(struct lis
  */
 static inline void list_del(struct list_head *entry)
 {
+	if (entry->prev->next != entry) {
+		printk("List corruption. prev->next should be %p, but was %p\n",
+				entry, entry->prev->next);
+		BUG();
+	}
+	if (entry->next->prev != entry) {
+		printk("List corruption. next->prev should be %p, but was %p\n",
+				entry, entry->next->prev);
+		BUG();
+	}
 	__list_del(entry->prev, entry->next);
 	entry->next = LIST_POISON1;
 	entry->prev = LIST_POISON2;



It _may_ give more information about exactly which wait-queue (or rather, 
what the poll function that was related to that wait-queue) seems to be 
corrupted. 

		Linus

---
diff --git a/fs/select.c b/fs/select.c
index a8109ba..8cd6dc3 100644
--- a/fs/select.c
+++ b/fs/select.c
@@ -23,6 +23,7 @@ #include <linux/personality.h> /* for ST
 #include <linux/file.h>
 #include <linux/fs.h>
 #include <linux/rcupdate.h>
+#include <linux/kallsyms.h>
 
 #include <asm/uaccess.h>
 
@@ -65,7 +66,8 @@ EXPORT_SYMBOL(poll_initwait);
 
 static void free_poll_entry(struct poll_table_entry *entry)
 {
-	remove_wait_queue(entry->wait_address,&entry->wait);
+	if (remove_wait_queue(entry->wait_address,&entry->wait) < 0)
+		print_symbol("bad poll-entry for %s", (unsigned long) entry->filp->f_op->poll);
 	fput(entry->filp);
 }
 
diff --git a/include/linux/wait.h b/include/linux/wait.h
index d285182..4c1d74e 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -115,7 +115,7 @@ #define is_sync_wait(wait)	(!(wait) || (
 
 extern void FASTCALL(add_wait_queue(wait_queue_head_t *q, wait_queue_t * wait));
 extern void FASTCALL(add_wait_queue_exclusive(wait_queue_head_t *q, wait_queue_t * wait));
-extern void FASTCALL(remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait));
+extern int FASTCALL(remove_wait_queue(wait_queue_head_t *q, wait_queue_t * wait));
 
 static inline void __add_wait_queue(wait_queue_head_t *head, wait_queue_t *new)
 {
diff --git a/kernel/wait.c b/kernel/wait.c
index 791681c..5cdf169 100644
--- a/kernel/wait.c
+++ b/kernel/wait.c
@@ -33,13 +33,35 @@ void fastcall add_wait_queue_exclusive(w
 }
 EXPORT_SYMBOL(add_wait_queue_exclusive);
 
-void fastcall remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
+int fastcall remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
 {
 	unsigned long flags;
+	struct list_head *list;
+	int seen, retval;
 
 	spin_lock_irqsave(&q->lock, flags);
-	__remove_wait_queue(q, wait);
+	list = &q->task_list;
+	seen = 0;
+	retval = -1;
+
+	do {
+		struct list_head *next;
+		if (list == &wait->task_list)
+			seen++;
+		next = list->next;
+		if (next->prev != list) {
+			seen += 2;
+			break;
+		}
+		list = next;
+	} while (list != &q->task_list);
+
+	if (seen == 1) {
+		__remove_wait_queue(q, wait);
+		retval = 0;
+	}
 	spin_unlock_irqrestore(&q->lock, flags);
+	return retval;
 }
 EXPORT_SYMBOL(remove_wait_queue);
 

-- 
http://www.codemonkey.org.uk

^ permalink raw reply related	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2006-07-15 20:04 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-07-15 19:54 memory corruptor in .18rc1-git Chuck Ebbert
2006-07-15 20:04 ` Dave Jones
  -- strict thread matches above, loose matches on Subject: below --
2006-07-13 22:13 Dave Jones
2006-07-13 22:24 ` Andrew Morton
2006-07-13 22:30   ` Dave Jones
2006-07-14  4:12     ` Willy Tarreau
2006-07-14  4:20       ` Dave Jones
2006-07-14  4:25         ` Willy Tarreau
2006-07-14  4:31           ` Dave Jones

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox