Skip to content

Commit 83668e7

Browse files
committed
ext4: fix potential race when freeing ext4_io_page structures
Use an atomic_t and make sure we don't free the structure while we might still be submitting I/O for that page. Signed-off-by: "Theodore Ts'o" <[email protected]>
1 parent f7ad6d2 commit 83668e7

File tree

2 files changed

+16
-24
lines changed

2 files changed

+16
-24
lines changed

fs/ext4/ext4.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ struct mpage_da_data {
177177

178178
struct ext4_io_page {
179179
struct page *p_page;
180-
int p_count;
180+
atomic_t p_count;
181181
};
182182

183183
#define MAX_IO_PAGES 128

fs/ext4/page-io.c

Lines changed: 15 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,15 @@ void ext4_ioend_wait(struct inode *inode)
6767
wait_event(*wq, (atomic_read(&EXT4_I(inode)->i_ioend_count) == 0));
6868
}
6969

70+
static void put_io_page(struct ext4_io_page *io_page)
71+
{
72+
if (atomic_dec_and_test(&io_page->p_count)) {
73+
end_page_writeback(io_page->p_page);
74+
put_page(io_page->p_page);
75+
kmem_cache_free(io_page_cachep, io_page);
76+
}
77+
}
78+
7079
void ext4_free_io_end(ext4_io_end_t *io)
7180
{
7281
int i;
@@ -75,15 +84,8 @@ void ext4_free_io_end(ext4_io_end_t *io)
7584
BUG_ON(!io);
7685
if (io->page)
7786
put_page(io->page);
78-
for (i = 0; i < io->num_io_pages; i++) {
79-
if (--io->pages[i]->p_count == 0) {
80-
struct page *page = io->pages[i]->p_page;
81-
82-
end_page_writeback(page);
83-
put_page(page);
84-
kmem_cache_free(io_page_cachep, io->pages[i]);
85-
}
86-
}
87+
for (i = 0; i < io->num_io_pages; i++)
88+
put_io_page(io->pages[i]);
8789
io->num_io_pages = 0;
8890
wq = to_ioend_wq(io->inode);
8991
if (atomic_dec_and_test(&EXT4_I(io->inode)->i_ioend_count) &&
@@ -235,13 +237,7 @@ static void ext4_end_bio(struct bio *bio, int error)
235237
} while (bh != head);
236238
}
237239

238-
if (--io_end->pages[i]->p_count == 0) {
239-
struct page *page = io_end->pages[i]->p_page;
240-
241-
end_page_writeback(page);
242-
put_page(page);
243-
kmem_cache_free(io_page_cachep, io_end->pages[i]);
244-
}
240+
put_io_page(io_end->pages[i]);
245241

246242
/*
247243
* If this is a partial write which happened to make
@@ -369,7 +365,7 @@ static int io_submit_add_bh(struct ext4_io_submit *io,
369365
if ((io_end->num_io_pages == 0) ||
370366
(io_end->pages[io_end->num_io_pages-1] != io_page)) {
371367
io_end->pages[io_end->num_io_pages++] = io_page;
372-
io_page->p_count++;
368+
atomic_inc(&io_page->p_count);
373369
}
374370
return 0;
375371
}
@@ -398,7 +394,7 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
398394
return -ENOMEM;
399395
}
400396
io_page->p_page = page;
401-
io_page->p_count = 0;
397+
atomic_set(&io_page->p_count, 1);
402398
get_page(page);
403399

404400
for (bh = head = page_buffers(page), block_start = 0;
@@ -430,10 +426,6 @@ int ext4_bio_write_page(struct ext4_io_submit *io,
430426
* PageWriteback bit from the page to prevent the system from
431427
* wedging later on.
432428
*/
433-
if (io_page->p_count == 0) {
434-
put_page(page);
435-
end_page_writeback(page);
436-
kmem_cache_free(io_page_cachep, io_page);
437-
}
429+
put_io_page(io_page);
438430
return ret;
439431
}

0 commit comments

Comments
 (0)