| From 217fe01d91370e4748409f76f5aae0081085b140 Mon Sep 17 00:00:00 2001 |
| From: Theodore Ts'o <tytso@mit.edu> |
| Date: Mon, 23 Nov 2009 07:25:49 -0500 |
| Subject: [PATCH 57/85] ext4: fix potential buffer head leak when add_dirent_to_buf() returns ENOSPC |
| |
| (cherry picked from commit 2de770a406b06dfc619faabbf5d85c835ed3f2e1) |
| |
| Previously add_dirent_to_buf() did not free its passed-in buffer head |
| in the case of ENOSPC, since in some cases the caller still needed it. |
| However, this led to potential buffer head leaks since not all callers |
| dealt with this correctly. Fix this by making simplifying the freeing |
| convention; now add_dirent_to_buf() *never* frees the passed-in buffer |
| head, and leaves that to the responsibility of its caller. This makes |
| things cleaner and easier to prove that the code is neither leaking |
| buffer heads or calling brelse() one time too many. |
| |
| Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> |
| Cc: Curt Wohlgemuth <curtw@google.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> |
| --- |
| fs/ext4/namei.c | 30 ++++++++++++------------------ |
| 1 file changed, 12 insertions(+), 18 deletions(-) |
| |
| --- a/fs/ext4/namei.c |
| +++ b/fs/ext4/namei.c |
| @@ -1292,9 +1292,6 @@ errout: |
| * add_dirent_to_buf will attempt search the directory block for |
| * space. It will return -ENOSPC if no space is available, and -EIO |
| * and -EEXIST if directory entry already exists. |
| - * |
| - * NOTE! bh is NOT released in the case where ENOSPC is returned. In |
| - * all other cases bh is released. |
| */ |
| static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, |
| struct inode *inode, struct ext4_dir_entry_2 *de, |
| @@ -1315,14 +1312,10 @@ static int add_dirent_to_buf(handle_t *h |
| top = bh->b_data + blocksize - reclen; |
| while ((char *) de <= top) { |
| if (!ext4_check_dir_entry("ext4_add_entry", dir, de, |
| - bh, offset)) { |
| - brelse(bh); |
| + bh, offset)) |
| return -EIO; |
| - } |
| - if (ext4_match(namelen, name, de)) { |
| - brelse(bh); |
| + if (ext4_match(namelen, name, de)) |
| return -EEXIST; |
| - } |
| nlen = EXT4_DIR_REC_LEN(de->name_len); |
| rlen = ext4_rec_len_from_disk(de->rec_len, blocksize); |
| if ((de->inode? rlen - nlen: rlen) >= reclen) |
| @@ -1337,7 +1330,6 @@ static int add_dirent_to_buf(handle_t *h |
| err = ext4_journal_get_write_access(handle, bh); |
| if (err) { |
| ext4_std_error(dir->i_sb, err); |
| - brelse(bh); |
| return err; |
| } |
| |
| @@ -1377,7 +1369,6 @@ static int add_dirent_to_buf(handle_t *h |
| err = ext4_handle_dirty_metadata(handle, dir, bh); |
| if (err) |
| ext4_std_error(dir->i_sb, err); |
| - brelse(bh); |
| return 0; |
| } |
| |
| @@ -1471,7 +1462,9 @@ static int make_indexed_dir(handle_t *ha |
| if (!(de)) |
| return retval; |
| |
| - return add_dirent_to_buf(handle, dentry, inode, de, bh); |
| + retval = add_dirent_to_buf(handle, dentry, inode, de, bh); |
| + brelse(bh); |
| + return retval; |
| } |
| |
| /* |
| @@ -1514,8 +1507,10 @@ static int ext4_add_entry(handle_t *hand |
| if(!bh) |
| return retval; |
| retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh); |
| - if (retval != -ENOSPC) |
| + if (retval != -ENOSPC) { |
| + brelse(bh); |
| return retval; |
| + } |
| |
| if (blocks == 1 && !dx_fallback && |
| EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) |
| @@ -1528,7 +1523,9 @@ static int ext4_add_entry(handle_t *hand |
| de = (struct ext4_dir_entry_2 *) bh->b_data; |
| de->inode = 0; |
| de->rec_len = ext4_rec_len_to_disk(blocksize, blocksize); |
| - return add_dirent_to_buf(handle, dentry, inode, de, bh); |
| + retval = add_dirent_to_buf(handle, dentry, inode, de, bh); |
| + brelse(bh); |
| + return retval; |
| } |
| |
| /* |
| @@ -1561,10 +1558,8 @@ static int ext4_dx_add_entry(handle_t *h |
| goto journal_error; |
| |
| err = add_dirent_to_buf(handle, dentry, inode, NULL, bh); |
| - if (err != -ENOSPC) { |
| - bh = NULL; |
| + if (err != -ENOSPC) |
| goto cleanup; |
| - } |
| |
| /* Block full, should compress but for now just split */ |
| dxtrace(printk(KERN_DEBUG "using %u of %u node entries\n", |
| @@ -1657,7 +1652,6 @@ static int ext4_dx_add_entry(handle_t *h |
| if (!de) |
| goto cleanup; |
| err = add_dirent_to_buf(handle, dentry, inode, de, bh); |
| - bh = NULL; |
| goto cleanup; |
| |
| journal_error: |