lkml.org 
[lkml]   [1998]   [Jan]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
Date
From
Subjectdentry list checker patch
The attached patch performs consistency checks on the dentry list at
periodic intervals in an attempt to catch an elusive bug causing dcache
corruption. So far only a couple of people have reported triggering the
messages, but no clear pattern of failures has emerged yet. My hope is
that if more people have the patch in place, we may be able to correlate
the failures and find the problem. (There were many oops reports related
to this dcache corruption problem in 2.1.6x, but for some reason they
have become much less frequent.)

I've added a compile flag so the patch can be easily disabled once we've
found the problem, or if someone doesn't want to run it. It doesn't slow
the system down very much anyway though.

I'd also like to ask for suggestions of a better way to track down stray
pointers (or whatever) that cause problems of this sort. Anyone have an
idea of how to protect a dynamic list like the dentry list? Or if we
detect corruption at address xxxx, any idea on how to find the pointer
that trashed it?

Regards,
Bill--- fs/dcache.c.old Tue Jan 6 11:39:05 1998
+++ fs/dcache.c Wed Jan 7 14:06:56 1998
@@ -19,6 +19,7 @@
#include <linux/malloc.h>
#include <linux/init.h>

+#define DCACHE_VERIFY 1
#define DCACHE_PARANOIA 1
/* #define DCACHE_DEBUG 1 */

@@ -412,6 +421,65 @@
prune_dcache(found);
}

+#ifdef DCACHE_VERIFY
+/*
+ * Check that the unused dentry list is valid.
+ */
+void verify_list(void)
+{
+ struct list_head *tmp, *next, *prev;
+ struct dentry *dentry;
+ struct inode *inode;
+ unsigned long memstart = PAGE_OFFSET;
+ unsigned long memmax = PAGE_OFFSET + (num_physpages << PAGE_SHIFT);
+ unsigned long align_mask = ~0x3;
+ unsigned long addr;
+
+ prev = &dentry_unused;
+ for (tmp = dentry_unused.next; tmp != &dentry_unused; tmp = next) {
+
+ addr = (unsigned long) tmp;
+ if (addr < memstart || addr > memmax)
+ goto bad;
+ if ((addr & align_mask) != addr)
+ goto bad;
+ if (prev != tmp->prev)
+ goto bad_prev;
+ next = tmp->next;
+ prev = tmp;
+ dentry = list_entry(tmp, struct dentry, d_lru);
+ inode = dentry->d_inode;
+ if (!inode)
+ continue;
+ addr = (unsigned long) inode;
+ if (addr < memstart || addr > memmax)
+ goto bad_inode;
+ if ((addr & align_mask) != addr)
+ goto bad_inode;
+ if (inode->i_sb != dentry->d_sb)
+ goto bad_sb;
+ if (!inode->i_count || inode->i_count > 50)
+ goto bad_count;
+ }
+ return;
+bad:
+ printk("VFS: dentry list corrupt, addr=%08lx\n", addr);
+ return;
+bad_prev:
+ printk("VFS: bad prev pointer in dentry list, prev=%p\n", prev);
+ return;
+bad_inode:
+ printk("VFS: dentry has bad inode pointer, addr=%08lx\n", addr);
+ return;
+bad_sb:
+ printk("VFS: dentry superblock mismatch\n");
+ return;
+bad_count:
+ printk("VFS: bad count for in-use inode, count=%d\n", inode->i_count);
+ return;
+}
+#endif
+
/*
* This is called from do_try_to_free_page() to indicate
* that we should reduce the dcache and inode cache memory.
@@ -426,6 +494,15 @@
*/
void check_dcache_memory()
{
+#ifdef DCACHE_VERIFY
+ static unsigned long next_check = 0;
+
+ if (jiffies > next_check) {
+ next_check = jiffies + 2*HZ;
+ verify_list();
+ }
+#endif
+
if (dentry_stat.want_pages) {
unsigned int count, goal = 0;
/*
\
 
 \ /
  Last update: 2005-03-22 13:41    [W:0.019 / U:0.392 seconds]
©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site