aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorJan Kara <jack@suse.cz>2013-07-10 21:31:04 -0400
committerTheodore Ts'o <tytso@mit.edu>2013-07-10 21:31:04 -0400
commit822dbba33458cd6ad0e715f3f4a57ebc99d54d1b (patch)
treec1fdc94004905dba9fd3ad72d7611d10b6f7c308 /fs
parent960fd856fdc3b08b3638f3f9b6b4bfceb77660c7 (diff)
ext4: fix warning in ext4_evict_inode()
The following race can lead to ext4_evict_inode() seeing i_ioend_count > 0 and thus triggering a sanity check warning: CPU1 CPU2 ext4_end_bio() ext4_evict_inode() ext4_finish_bio() end_page_writeback(); truncate_inode_pages() evict page WARN_ON(i_ioend_count > 0); ext4_put_io_end_defer() ext4_release_io_end() dec i_ioend_count This is possible use-after-free bug since we decrement i_ioend_count in possibly released inode. Since i_ioend_count is used only for sanity checks one possible solution would be to just remove it but for now I'd like to keep those sanity checks to help debugging the new ext4 writeback code. This patch changes ext4_end_bio() to call ext4_put_io_end_defer() before ext4_finish_bio() in the shortcut case when unwritten extent conversion isn't needed. In that case we don't need the io_end so we are safe to drop it early. Reported-by: Guenter Roeck <linux@roeck-us.net> Tested-by: Guenter Roeck <linux@roeck-us.net> Signed-off-by: Jan Kara <jack@suse.cz> Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
Diffstat (limited to 'fs')
-rw-r--r--fs/ext4/page-io.c32
1 files changed, 19 insertions, 13 deletions
diff --git a/fs/ext4/page-io.c b/fs/ext4/page-io.c
index 48786cdb5e6c..d63cc5e9d3b5 100644
--- a/fs/ext4/page-io.c
+++ b/fs/ext4/page-io.c
@@ -308,6 +308,7 @@ ext4_io_end_t *ext4_get_io_end(ext4_io_end_t *io_end)
308 return io_end; 308 return io_end;
309} 309}
310 310
311/* BIO completion function for page writeback */
311static void ext4_end_bio(struct bio *bio, int error) 312static void ext4_end_bio(struct bio *bio, int error)
312{ 313{
313 ext4_io_end_t *io_end = bio->bi_private; 314 ext4_io_end_t *io_end = bio->bi_private;
@@ -318,18 +319,6 @@ static void ext4_end_bio(struct bio *bio, int error)
318 if (test_bit(BIO_UPTODATE, &bio->bi_flags)) 319 if (test_bit(BIO_UPTODATE, &bio->bi_flags))
319 error = 0; 320 error = 0;
320 321
321 if (io_end->flag & EXT4_IO_END_UNWRITTEN) {
322 /*
323 * Link bio into list hanging from io_end. We have to do it
324 * atomically as bio completions can be racing against each
325 * other.
326 */
327 bio->bi_private = xchg(&io_end->bio, bio);
328 } else {
329 ext4_finish_bio(bio);
330 bio_put(bio);
331 }
332
333 if (error) { 322 if (error) {
334 struct inode *inode = io_end->inode; 323 struct inode *inode = io_end->inode;
335 324
@@ -341,7 +330,24 @@ static void ext4_end_bio(struct bio *bio, int error)
341 (unsigned long long) 330 (unsigned long long)
342 bi_sector >> (inode->i_blkbits - 9)); 331 bi_sector >> (inode->i_blkbits - 9));
343 } 332 }
344 ext4_put_io_end_defer(io_end); 333
334 if (io_end->flag & EXT4_IO_END_UNWRITTEN) {
335 /*
336 * Link bio into list hanging from io_end. We have to do it
337 * atomically as bio completions can be racing against each
338 * other.
339 */
340 bio->bi_private = xchg(&io_end->bio, bio);
341 ext4_put_io_end_defer(io_end);
342 } else {
343 /*
344 * Drop io_end reference early. Inode can get freed once
345 * we finish the bio.
346 */
347 ext4_put_io_end_defer(io_end);
348 ext4_finish_bio(bio);
349 bio_put(bio);
350 }
345} 351}
346 352
347void ext4_io_submit(struct ext4_io_submit *io) 353void ext4_io_submit(struct ext4_io_submit *io)