Skip to content

Commit cf76c78

Browse files
Changwei Getorvalds
authored andcommitted
ocfs2: don't put and assigning null to bh allocated outside
ocfs2_read_blocks() and ocfs2_read_blocks_sync() are both used to read several blocks from disk. Currently, the input argument *bhs* can be NULL or NOT. It depends on the caller's behavior. If the function fails in reading blocks from disk, the corresponding bh will be assigned to NULL and put. Obviously, above process for non-NULL input bh is not appropriate. Because the caller doesn't even know its bhs are put and re-assigned. If buffer head is managed by caller, ocfs2_read_blocks and ocfs2_read_blocks_sync() should not evaluate it to NULL. It will cause caller accessing illegal memory, thus crash. Link: http://lkml.kernel.org/r/HK2PR06MB045285E0F4FBB561F9F2F9B3D5680@HK2PR06MB0452.apcprd06.prod.outlook.com Signed-off-by: Changwei Ge <[email protected]> Reviewed-by: Guozhonghua <[email protected]> Cc: Mark Fasheh <[email protected]> Cc: Joel Becker <[email protected]> Cc: Junxiao Bi <[email protected]> Cc: Joseph Qi <[email protected]> Cc: Changwei Ge <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
1 parent 29aa301 commit cf76c78

File tree

1 file changed

+59
-18
lines changed

1 file changed

+59
-18
lines changed

fs/ocfs2/buffer_head_io.c

Lines changed: 59 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -99,25 +99,34 @@ int ocfs2_write_block(struct ocfs2_super *osb, struct buffer_head *bh,
9999
return ret;
100100
}
101101

102+
/* Caller must provide a bhs[] with all NULL or non-NULL entries, so it
103+
* will be easier to handle read failure.
104+
*/
102105
int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block,
103106
unsigned int nr, struct buffer_head *bhs[])
104107
{
105108
int status = 0;
106109
unsigned int i;
107110
struct buffer_head *bh;
111+
int new_bh = 0;
108112

109113
trace_ocfs2_read_blocks_sync((unsigned long long)block, nr);
110114

111115
if (!nr)
112116
goto bail;
113117

118+
/* Don't put buffer head and re-assign it to NULL if it is allocated
119+
* outside since the caller can't be aware of this alternation!
120+
*/
121+
new_bh = (bhs[0] == NULL);
122+
114123
for (i = 0 ; i < nr ; i++) {
115124
if (bhs[i] == NULL) {
116125
bhs[i] = sb_getblk(osb->sb, block++);
117126
if (bhs[i] == NULL) {
118127
status = -ENOMEM;
119128
mlog_errno(status);
120-
goto bail;
129+
break;
121130
}
122131
}
123132
bh = bhs[i];
@@ -158,9 +167,26 @@ int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block,
158167
submit_bh(REQ_OP_READ, 0, bh);
159168
}
160169

170+
read_failure:
161171
for (i = nr; i > 0; i--) {
162172
bh = bhs[i - 1];
163173

174+
if (unlikely(status)) {
175+
if (new_bh && bh) {
176+
/* If middle bh fails, let previous bh
177+
* finish its read and then put it to
178+
* aovoid bh leak
179+
*/
180+
if (!buffer_jbd(bh))
181+
wait_on_buffer(bh);
182+
put_bh(bh);
183+
bhs[i - 1] = NULL;
184+
} else if (bh && buffer_uptodate(bh)) {
185+
clear_buffer_uptodate(bh);
186+
}
187+
continue;
188+
}
189+
164190
/* No need to wait on the buffer if it's managed by JBD. */
165191
if (!buffer_jbd(bh))
166192
wait_on_buffer(bh);
@@ -170,15 +196,17 @@ int ocfs2_read_blocks_sync(struct ocfs2_super *osb, u64 block,
170196
* so we can safely record this and loop back
171197
* to cleanup the other buffers. */
172198
status = -EIO;
173-
put_bh(bh);
174-
bhs[i - 1] = NULL;
199+
goto read_failure;
175200
}
176201
}
177202

178203
bail:
179204
return status;
180205
}
181206

207+
/* Caller must provide a bhs[] with all NULL or non-NULL entries, so it
208+
* will be easier to handle read failure.
209+
*/
182210
int ocfs2_read_blocks(struct ocfs2_caching_info *ci, u64 block, int nr,
183211
struct buffer_head *bhs[], int flags,
184212
int (*validate)(struct super_block *sb,
@@ -188,6 +216,7 @@ int ocfs2_read_blocks(struct ocfs2_caching_info *ci, u64 block, int nr,
188216
int i, ignore_cache = 0;
189217
struct buffer_head *bh;
190218
struct super_block *sb = ocfs2_metadata_cache_get_super(ci);
219+
int new_bh = 0;
191220

192221
trace_ocfs2_read_blocks_begin(ci, (unsigned long long)block, nr, flags);
193222

@@ -213,6 +242,11 @@ int ocfs2_read_blocks(struct ocfs2_caching_info *ci, u64 block, int nr,
213242
goto bail;
214243
}
215244

245+
/* Don't put buffer head and re-assign it to NULL if it is allocated
246+
* outside since the caller can't be aware of this alternation!
247+
*/
248+
new_bh = (bhs[0] == NULL);
249+
216250
ocfs2_metadata_cache_io_lock(ci);
217251
for (i = 0 ; i < nr ; i++) {
218252
if (bhs[i] == NULL) {
@@ -221,7 +255,8 @@ int ocfs2_read_blocks(struct ocfs2_caching_info *ci, u64 block, int nr,
221255
ocfs2_metadata_cache_io_unlock(ci);
222256
status = -ENOMEM;
223257
mlog_errno(status);
224-
goto bail;
258+
/* Don't forget to put previous bh! */
259+
break;
225260
}
226261
}
227262
bh = bhs[i];
@@ -316,16 +351,27 @@ int ocfs2_read_blocks(struct ocfs2_caching_info *ci, u64 block, int nr,
316351
}
317352
}
318353

319-
status = 0;
320-
354+
read_failure:
321355
for (i = (nr - 1); i >= 0; i--) {
322356
bh = bhs[i];
323357

324358
if (!(flags & OCFS2_BH_READAHEAD)) {
325-
if (status) {
326-
/* Clear the rest of the buffers on error */
327-
put_bh(bh);
328-
bhs[i] = NULL;
359+
if (unlikely(status)) {
360+
/* Clear the buffers on error including those
361+
* ever succeeded in reading
362+
*/
363+
if (new_bh && bh) {
364+
/* If middle bh fails, let previous bh
365+
* finish its read and then put it to
366+
* aovoid bh leak
367+
*/
368+
if (!buffer_jbd(bh))
369+
wait_on_buffer(bh);
370+
put_bh(bh);
371+
bhs[i] = NULL;
372+
} else if (bh && buffer_uptodate(bh)) {
373+
clear_buffer_uptodate(bh);
374+
}
329375
continue;
330376
}
331377
/* We know this can't have changed as we hold the
@@ -343,9 +389,7 @@ int ocfs2_read_blocks(struct ocfs2_caching_info *ci, u64 block, int nr,
343389
* uptodate. */
344390
status = -EIO;
345391
clear_buffer_needs_validate(bh);
346-
put_bh(bh);
347-
bhs[i] = NULL;
348-
continue;
392+
goto read_failure;
349393
}
350394

351395
if (buffer_needs_validate(bh)) {
@@ -355,11 +399,8 @@ int ocfs2_read_blocks(struct ocfs2_caching_info *ci, u64 block, int nr,
355399
BUG_ON(buffer_jbd(bh));
356400
clear_buffer_needs_validate(bh);
357401
status = validate(sb, bh);
358-
if (status) {
359-
put_bh(bh);
360-
bhs[i] = NULL;
361-
continue;
362-
}
402+
if (status)
403+
goto read_failure;
363404
}
364405
}
365406

0 commit comments

Comments
 (0)