]>
Commit | Line | Data |
---|---|---|
e46fb18b GKH |
1 | From 4df5b14f4bea734ff3d9c721eb331540ad142de3 Mon Sep 17 00:00:00 2001 |
2 | From: Theodore Ts'o <tytso@mit.edu> | |
3 | Date: Mon, 23 Nov 2009 07:25:49 -0500 | |
4 | Subject: [PATCH 01/30] ext4: fix potential buffer head leak when add_dirent_to_buf() returns ENOSPC | |
5 | ||
6 | (cherry picked from commit 2de770a406b06dfc619faabbf5d85c835ed3f2e1) | |
7 | ||
8 | Previously add_dirent_to_buf() did not free its passed-in buffer head | |
9 | in the case of ENOSPC, since in some cases the caller still needed it. | |
10 | However, this led to potential buffer head leaks since not all callers | |
11 | dealt with this correctly. Fix this by making simplifying the freeing | |
12 | convention; now add_dirent_to_buf() *never* frees the passed-in buffer | |
13 | head, and leaves that to the responsibility of its caller. This makes | |
14 | things cleaner and easier to prove that the code is neither leaking | |
15 | buffer heads or calling brelse() one time too many. | |
16 | ||
17 | Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> | |
18 | Cc: Curt Wohlgemuth <curtw@google.com> | |
19 | Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> | |
20 | --- | |
21 | fs/ext4/namei.c | 30 ++++++++++++------------------ | |
22 | 1 file changed, 12 insertions(+), 18 deletions(-) | |
23 | ||
24 | --- a/fs/ext4/namei.c | |
25 | +++ b/fs/ext4/namei.c | |
26 | @@ -1292,9 +1292,6 @@ errout: | |
27 | * add_dirent_to_buf will attempt search the directory block for | |
28 | * space. It will return -ENOSPC if no space is available, and -EIO | |
29 | * and -EEXIST if directory entry already exists. | |
30 | - * | |
31 | - * NOTE! bh is NOT released in the case where ENOSPC is returned. In | |
32 | - * all other cases bh is released. | |
33 | */ | |
34 | static int add_dirent_to_buf(handle_t *handle, struct dentry *dentry, | |
35 | struct inode *inode, struct ext4_dir_entry_2 *de, | |
36 | @@ -1315,14 +1312,10 @@ static int add_dirent_to_buf(handle_t *h | |
37 | top = bh->b_data + blocksize - reclen; | |
38 | while ((char *) de <= top) { | |
39 | if (!ext4_check_dir_entry("ext4_add_entry", dir, de, | |
40 | - bh, offset)) { | |
41 | - brelse(bh); | |
42 | + bh, offset)) | |
43 | return -EIO; | |
44 | - } | |
45 | - if (ext4_match(namelen, name, de)) { | |
46 | - brelse(bh); | |
47 | + if (ext4_match(namelen, name, de)) | |
48 | return -EEXIST; | |
49 | - } | |
50 | nlen = EXT4_DIR_REC_LEN(de->name_len); | |
51 | rlen = ext4_rec_len_from_disk(de->rec_len, blocksize); | |
52 | if ((de->inode? rlen - nlen: rlen) >= reclen) | |
53 | @@ -1337,7 +1330,6 @@ static int add_dirent_to_buf(handle_t *h | |
54 | err = ext4_journal_get_write_access(handle, bh); | |
55 | if (err) { | |
56 | ext4_std_error(dir->i_sb, err); | |
57 | - brelse(bh); | |
58 | return err; | |
59 | } | |
60 | ||
61 | @@ -1377,7 +1369,6 @@ static int add_dirent_to_buf(handle_t *h | |
62 | err = ext4_handle_dirty_metadata(handle, dir, bh); | |
63 | if (err) | |
64 | ext4_std_error(dir->i_sb, err); | |
65 | - brelse(bh); | |
66 | return 0; | |
67 | } | |
68 | ||
69 | @@ -1471,7 +1462,9 @@ static int make_indexed_dir(handle_t *ha | |
70 | if (!(de)) | |
71 | return retval; | |
72 | ||
73 | - return add_dirent_to_buf(handle, dentry, inode, de, bh); | |
74 | + retval = add_dirent_to_buf(handle, dentry, inode, de, bh); | |
75 | + brelse(bh); | |
76 | + return retval; | |
77 | } | |
78 | ||
79 | /* | |
80 | @@ -1514,8 +1507,10 @@ static int ext4_add_entry(handle_t *hand | |
81 | if(!bh) | |
82 | return retval; | |
83 | retval = add_dirent_to_buf(handle, dentry, inode, NULL, bh); | |
84 | - if (retval != -ENOSPC) | |
85 | + if (retval != -ENOSPC) { | |
86 | + brelse(bh); | |
87 | return retval; | |
88 | + } | |
89 | ||
90 | if (blocks == 1 && !dx_fallback && | |
91 | EXT4_HAS_COMPAT_FEATURE(sb, EXT4_FEATURE_COMPAT_DIR_INDEX)) | |
92 | @@ -1528,7 +1523,9 @@ static int ext4_add_entry(handle_t *hand | |
93 | de = (struct ext4_dir_entry_2 *) bh->b_data; | |
94 | de->inode = 0; | |
95 | de->rec_len = ext4_rec_len_to_disk(blocksize, blocksize); | |
96 | - return add_dirent_to_buf(handle, dentry, inode, de, bh); | |
97 | + retval = add_dirent_to_buf(handle, dentry, inode, de, bh); | |
98 | + brelse(bh); | |
99 | + return retval; | |
100 | } | |
101 | ||
102 | /* | |
103 | @@ -1561,10 +1558,8 @@ static int ext4_dx_add_entry(handle_t *h | |
104 | goto journal_error; | |
105 | ||
106 | err = add_dirent_to_buf(handle, dentry, inode, NULL, bh); | |
107 | - if (err != -ENOSPC) { | |
108 | - bh = NULL; | |
109 | + if (err != -ENOSPC) | |
110 | goto cleanup; | |
111 | - } | |
112 | ||
113 | /* Block full, should compress but for now just split */ | |
114 | dxtrace(printk(KERN_DEBUG "using %u of %u node entries\n", | |
115 | @@ -1657,7 +1652,6 @@ static int ext4_dx_add_entry(handle_t *h | |
116 | if (!de) | |
117 | goto cleanup; | |
118 | err = add_dirent_to_buf(handle, dentry, inode, de, bh); | |
119 | - bh = NULL; | |
120 | goto cleanup; | |
121 | ||
122 | journal_error: |