ext4: bail out from make_indexed_dir() on first error
authorJan Kara <jack@suse.cz>
Thu, 30 Oct 2014 14:53:17 +0000 (10:53 -0400)
committerZefan Li <lizefan@huawei.com>
Mon, 2 Feb 2015 09:05:09 +0000 (17:05 +0800)
commit 6050d47adcadbb53582434d919ed7f038d936712 upstream.

When ext4_handle_dirty_dx_node() or ext4_handle_dirty_dirent_node()
fail, there's really something wrong with the fs and there's no point in
continuing further. Just return error from make_indexed_dir() in that
case. Also initialize frames array so that if we return early due to
error, dx_release() doesn't try to dereference uninitialized memory
(which could happen also due to error in do_split()).

Coverity-id: 741300
Signed-off-by: Jan Kara <jack@suse.cz>
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
[lizf: Backported to 3.4:
 - adjust context
 - replace ext4_handle_dirty_{dx,dirent}_node() with
   ext4_handle_dirty_metadata()]
Signed-off-by: Zefan Li <lizefan@huawei.com>
fs/ext4/namei.c

index c6dd936..dc58523 100644 (file)
@@ -1421,31 +1421,38 @@ 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, bh);
+       if (retval)
+               goto out_frames;
 
        de = do_split(handle,dir, &bh, 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);
        return retval;
+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.
+        */
+       ext4_mark_inode_dirty(handle, dir);
+       dx_release(frames);
+       return retval;
 }
 
 /*