dir_index: error out instead of BUG on corrupt dx dirs
[deliverable/linux.git] / fs / ext3 / namei.c
index 49159f13cc1f900d4b514a265ea3e97cbaf811a4..9d4a89820e1ef3c3b90ce3cabf193a0f55f56cd0 100644 (file)
@@ -36,7 +36,6 @@
 #include <linux/quotaops.h>
 #include <linux/buffer_head.h>
 #include <linux/bio.h>
-#include <linux/smp_lock.h>
 
 #include "namei.h"
 #include "xattr.h"
@@ -380,13 +379,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 +438,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 +454,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;
 }
 
@@ -969,6 +994,7 @@ static struct buffer_head * ext3_dx_find_entry(struct dentry *dentry,
                                  (block<<EXT3_BLOCK_SIZE_BITS(sb))
                                          +((char *)de - bh->b_data))) {
                                brelse (bh);
+                               *err = ERR_BAD_DX_DIR;
                                goto errout;
                        }
                        *res_dir = de;
@@ -1019,6 +1045,11 @@ static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, str
 
                if (!inode)
                        return ERR_PTR(-EACCES);
+
+               if (is_bad_inode(inode)) {
+                       iput(inode);
+                       return ERR_PTR(-ENOENT);
+               }
        }
        return d_splice_alias(inode, dentry);
 }
@@ -1054,6 +1085,11 @@ struct dentry *ext3_get_parent(struct dentry *child)
        if (!inode)
                return ERR_PTR(-EACCES);
 
+       if (is_bad_inode(inode)) {
+               iput(inode);
+               return ERR_PTR(-ENOENT);
+       }
+
        parent = d_alloc_anon(inode);
        if (!parent) {
                iput(inode);
@@ -1134,9 +1170,9 @@ static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
        char *data1 = (*bh)->b_data, *data2;
        unsigned split;
        struct ext3_dir_entry_2 *de = NULL, *de2;
-       int     err;
+       int     err = 0;
 
-       bh2 = ext3_append (handle, dir, &newblock, error);
+       bh2 = ext3_append (handle, dir, &newblock, &err);
        if (!(bh2)) {
                brelse(*bh);
                *bh = NULL;
@@ -1145,14 +1181,9 @@ static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
 
        BUFFER_TRACE(*bh, "get_write_access");
        err = ext3_journal_get_write_access(handle, *bh);
-       if (err) {
-       journal_error:
-               brelse(*bh);
-               brelse(bh2);
-               *bh = NULL;
-               ext3_std_error(dir->i_sb, err);
-               goto errout;
-       }
+       if (err)
+               goto journal_error;
+
        BUFFER_TRACE(frame->bh, "get_write_access");
        err = ext3_journal_get_write_access(handle, frame->bh);
        if (err)
@@ -1195,8 +1226,16 @@ static struct ext3_dir_entry_2 *do_split(handle_t *handle, struct inode *dir,
                goto journal_error;
        brelse (bh2);
        dxtrace(dx_show_index ("frame", frame->entries));
-errout:
        return de;
+
+journal_error:
+       brelse(*bh);
+       brelse(bh2);
+       *bh = NULL;
+       ext3_std_error(dir->i_sb, err);
+errout:
+       *error = err;
+       return NULL;
 }
 #endif
 
This page took 0.028079 seconds and 5 git commands to generate.