Sophie

Sophie

distrib > Scientific%20Linux > 5x > x86_64 > by-pkgid > 27922b4260f65d317aabda37e42bbbff > files > 993

kernel-2.6.18-238.el5.src.rpm

From: Josef Bacik <jbacik@redhat.com>
Date: Mon, 20 Apr 2009 15:43:11 -0400
Subject: [fs] ext3: dir_index: error out on corrupt dx dirs
Message-id: 1240256591-27409-1-git-send-email-jbacik@redhat.com
O-Subject: [PATCH] [RHEL5.4] dir_index: error out instead of BUG on corrupt dx dirs
Bugzilla: 454942
RH-Acked-by: Peter Staubach <staubach@redhat.com>
RH-Acked-by: Eric Sandeen <sandeen@redhat.com>

This is in reference to bz 454942, and is a backport of commit

commit 3d82abae9523c33d4a16fdfdfd2bdde316d7b56a
Author: Eric Sandeen <sandeen@redhat.com>
Date:   Tue Sep 18 22:46:38 2007 -0700

    dir_index: error out instead of BUG on corrupt dx dirs

    Convert asserts (BUGs) in dx_probe from bad on-disk data to recoverable
    errors with helpful warnings.  With help catching other asserts from Duane
    Griffin <duaneg@dghda.com>

    Signed-off-by: Eric Sandeen <sandeen@redhat.com>
    Acked-by: Duane Griffin <duaneg@dghda.com>
    Acked-by: Theodore Ts'o <tytso@mit.edu>
    Cc: <stable@kernel.org>
    Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
    Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>

This was tested with the corrupted image provided in the bz and it fixed the
problem.
Signed-off-by: Josef Bacik <jbacik@redhat.com>

diff --git a/fs/ext3/namei.c b/fs/ext3/namei.c
index 35590db..0bb4924 100644
--- a/fs/ext3/namei.c
+++ b/fs/ext3/namei.c
@@ -380,13 +380,28 @@ dx_probe(struct dentry *dentry, struct inode *dir,
 
 	entries = (struct dx_entry *) (((char *)&root->info) +
 				       root->info.info_length);
-	assert(dx_get_limit(entries) == dx_root_limit(dir,
-						      root->info.info_length));
+
+	if (dx_get_limit(entries) != dx_root_limit(dir,
+						   root->info.info_length)) {
+		ext3_warning(dir->i_sb, __FUNCTION__,
+			     "dx entry: limit != root limit");
+		brelse(bh);
+		*err = ERR_BAD_DX_DIR;
+		goto fail;
+	}
+
 	dxtrace (printk("Look up %x", hash));
 	while (1)
 	{
 		count = dx_get_count(entries);
-		assert (count && count <= dx_get_limit(entries));
+		if (!count || count > dx_get_limit(entries)) {
+			ext3_warning(dir->i_sb, __FUNCTION__,
+				     "dx entry: no count or count > limit");
+			brelse(bh);
+			*err = ERR_BAD_DX_DIR;
+			goto fail2;
+		}
+
 		p = entries + 1;
 		q = entries + count - 1;
 		while (p <= q)
@@ -424,8 +439,15 @@ dx_probe(struct dentry *dentry, struct inode *dir,
 		if (!(bh = ext3_bread (NULL,dir, dx_get_block(at), 0, err)))
 			goto fail2;
 		at = entries = ((struct dx_node *) bh->b_data)->entries;
-		assert (dx_get_limit(entries) == dx_node_limit (dir));
+		if (dx_get_limit(entries) != dx_node_limit (dir)) {
+			ext3_warning(dir->i_sb, __FUNCTION__,
+				     "dx entry: limit != node limit");
+			brelse(bh);
+			*err = ERR_BAD_DX_DIR;
+			goto fail2;
+		}
 		frame++;
+		frame->bh = NULL;
 	}
 fail2:
 	while (frame >= frame_in) {
@@ -433,6 +455,10 @@ fail2:
 		frame--;
 	}
 fail:
+	if (*err == ERR_BAD_DX_DIR)
+		ext3_warning(dir->i_sb, __FUNCTION__,
+			     "Corrupt dir inode %ld, running e2fsck is "
+			     "recommended.", dir->i_ino);
 	return NULL;
 }