ext4: release bh in make_indexed_dir
[pandora-kernel.git] / fs / ext4 / namei.c
index aa4c782..ede3a33 100644 (file)
@@ -585,11 +585,8 @@ static int htree_dirblock_to_tree(struct file *dir_file,
                if (ext4_check_dir_entry(dir, NULL, de, bh,
                                (block<<EXT4_BLOCK_SIZE_BITS(dir->i_sb))
                                         + ((char *)de - bh->b_data))) {
-                       /* On error, skip the f_pos to the next block. */
-                       dir_file->f_pos = (dir_file->f_pos |
-                                       (dir->i_sb->s_blocksize - 1)) + 1;
-                       brelse(bh);
-                       return count;
+                       /* silently ignore the rest of the block */
+                       break;
                }
                ext4fs_dirhash(de->name, de->name_len, hinfo);
                if ((hinfo->hash < start_hash) ||
@@ -1037,7 +1034,13 @@ static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, stru
                        EXT4_ERROR_INODE(dir, "bad inode number: %u", ino);
                        return ERR_PTR(-EIO);
                }
-               inode = ext4_iget(dir->i_sb, ino);
+               if (unlikely(ino == dir->i_ino)) {
+                       EXT4_ERROR_INODE(dir, "'%.*s' linked to parent dir",
+                                        dentry->d_name.len,
+                                        dentry->d_name.name);
+                       return ERR_PTR(-EIO);
+               }
+               inode = ext4_iget_normal(dir->i_sb, ino);
                if (inode == ERR_PTR(-ESTALE)) {
                        EXT4_ERROR_INODE(dir,
                                         "deleted inode referenced: %u",
@@ -1071,7 +1074,7 @@ struct dentry *ext4_get_parent(struct dentry *child)
                return ERR_PTR(-EIO);
        }
 
-       return d_obtain_alias(ext4_iget(child->d_inode->i_sb, ino));
+       return d_obtain_alias(ext4_iget_normal(child->d_inode->i_sb, ino));
 }
 
 #define S_SHIFT 12
@@ -1405,30 +1408,35 @@ static int make_indexed_dir(handle_t *handle, struct dentry *dentry,
                hinfo.hash_version += EXT4_SB(dir->i_sb)->s_hash_unsigned;
        hinfo.seed = EXT4_SB(dir->i_sb)->s_hash_seed;
        ext4fs_dirhash(name, namelen, &hinfo);
+       memset(frames, 0, sizeof(frames));
        frame = frames;
        frame->entries = entries;
        frame->at = entries;
        frame->bh = bh;
-       bh = bh2;
 
-       ext4_handle_dirty_metadata(handle, dir, frame->bh);
-       ext4_handle_dirty_metadata(handle, dir, bh);
+       retval = ext4_handle_dirty_metadata(handle, dir, frame->bh);
+       if (retval)
+               goto out_frames;        
+       retval = ext4_handle_dirty_metadata(handle, dir, bh2);
+       if (retval)
+               goto out_frames;        
 
-       de = do_split(handle,dir, &bh, frame, &hinfo, &retval);
+       de = do_split(handle,dir, &bh2, frame, &hinfo, &retval);
        if (!de) {
-               /*
-                * Even if the block split failed, we have to properly write
-                * out all the changes we did so far. Otherwise we can end up
-                * with corrupted filesystem.
-                */
-               ext4_mark_inode_dirty(handle, dir);
-               dx_release(frames);
-               return retval;
+               goto out_frames;
        }
-       dx_release(frames);
 
-       retval = add_dirent_to_buf(handle, dentry, inode, de, bh);
-       brelse(bh);
+       retval = add_dirent_to_buf(handle, dentry, inode, de, bh2);
+out_frames:
+       /*
+        * Even if the block split failed, we have to properly write
+        * out all the changes we did so far. Otherwise we can end up
+        * with corrupted filesystem.
+        */
+       if (retval)
+               ext4_mark_inode_dirty(handle, dir);
+       dx_release(frames);
+       brelse(bh2);
        return retval;
 }
 
@@ -1446,7 +1454,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
                          struct inode *inode)
 {
        struct inode *dir = dentry->d_parent->d_inode;
-       struct buffer_head *bh;
+       struct buffer_head *bh = NULL;
        struct ext4_dir_entry_2 *de;
        struct super_block *sb;
        int     retval;
@@ -1461,7 +1469,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
        if (is_dx(dir)) {
                retval = ext4_dx_add_entry(handle, dentry, inode);
                if (!retval || (retval != ERR_BAD_DX_DIR))
-                       return retval;
+                       goto out;
                ext4_clear_inode_flag(dir, EXT4_INODE_INDEX);
                dx_fallback++;
                ext4_mark_inode_dirty(handle, dir);
@@ -1472,14 +1480,15 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
                if(!bh)
                        return retval;
                retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh);
-               if (retval != -ENOSPC) {
-                       brelse(bh);
-                       return retval;
-               }
+               if (retval != -ENOSPC)
+                       goto out;
 
                if (blocks == 1 && !dx_fallback &&
-                   EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX))
-                       return make_indexed_dir(handle, dentry, inode, bh);
+                   EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) {
+                       retval = make_indexed_dir(handle, dentry, inode, bh);
+                       bh = NULL; /* make_indexed_dir releases bh */
+                       goto out;
+               }
                brelse(bh);
        }
        bh = ext4_append(handle, dir, &block, &retval);
@@ -1489,6 +1498,7 @@ static int ext4_add_entry(handle_t *handle, struct dentry *dentry,
        de->inode = 0;
        de->rec_len = ext4_rec_len_to_disk(blocksize, blocksize);
        retval = add_dirent_to_buf(handle, dentry, inode, de, bh);
+out:
        brelse(bh);
        if (retval == 0)
                ext4_set_inode_state(inode, EXT4_STATE_NEWENTRY);
@@ -1795,9 +1805,7 @@ retry:
        err = PTR_ERR(inode);
        if (!IS_ERR(inode)) {
                init_special_inode(inode, inode->i_mode, rdev);
-#ifdef CONFIG_EXT4_FS_XATTR
                inode->i_op = &ext4_special_inode_operations;
-#endif
                err = ext4_add_nondir(handle, dentry, inode);
        }
        ext4_journal_stop(handle);
@@ -1978,7 +1986,7 @@ int ext4_orphan_add(handle_t *handle, struct inode *inode)
        struct ext4_iloc iloc;
        int err = 0, rc;
 
-       if (!ext4_handle_valid(handle))
+       if (!EXT4_SB(sb)->s_journal || is_bad_inode(inode))
                return 0;
 
        mutex_lock(&EXT4_SB(sb)->s_orphan_lock);
@@ -2052,8 +2060,8 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)
        struct ext4_iloc iloc;
        int err = 0;
 
-       /* ext4_handle_valid() assumes a valid handle_t pointer */
-       if (handle && !ext4_handle_valid(handle))
+       if (!EXT4_SB(inode->i_sb)->s_journal &&
+           !(EXT4_SB(inode->i_sb)->s_mount_state & EXT4_ORPHAN_FS))
                return 0;
 
        mutex_lock(&EXT4_SB(inode->i_sb)->s_orphan_lock);
@@ -2072,7 +2080,7 @@ int ext4_orphan_del(handle_t *handle, struct inode *inode)
         * transaction handle with which to update the orphan list on
         * disk, but we still need to remove the inode from the linked
         * list in memory. */
-       if (sbi->s_journal && !handle)
+       if (!handle)
                goto out;
 
        err = ext4_reserve_inode_write(handle, inode, &iloc);