Skip to content

Commit 822dbba

Browse files
jankaratytso
authored andcommitted
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 <[email protected]> Tested-by: Guenter Roeck <[email protected]> Signed-off-by: Jan Kara <[email protected]> Signed-off-by: "Theodore Ts'o" <[email protected]>
1 parent 960fd85 commit 822dbba

File tree

1 file changed

+19
-13
lines changed

1 file changed

+19
-13
lines changed

fs/ext4/page-io.c

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,7 @@ ext4_io_end_t *ext4_get_io_end(ext4_io_end_t *io_end)
308308
return io_end;
309309
}
310310

311+
/* BIO completion function for page writeback */
311312
static void ext4_end_bio(struct bio *bio, int error)
312313
{
313314
ext4_io_end_t *io_end = bio->bi_private;
@@ -318,18 +319,6 @@ static void ext4_end_bio(struct bio *bio, int error)
318319
if (test_bit(BIO_UPTODATE, &bio->bi_flags))
319320
error = 0;
320321

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-
333322
if (error) {
334323
struct inode *inode = io_end->inode;
335324

@@ -341,7 +330,24 @@ static void ext4_end_bio(struct bio *bio, int error)
341330
(unsigned long long)
342331
bi_sector >> (inode->i_blkbits - 9));
343332
}
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+
}
345351
}
346352

347353
void ext4_io_submit(struct ext4_io_submit *io)

0 commit comments

Comments
 (0)