Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

ext4: Fix mmap/truncate race when blocksize < pagesize && delayed allocation

It is possible to see buffer_heads which are not mapped in the
writepage callback in the following scneario (where the fs blocksize
is 1k and the page size is 4k):

1) truncate(f, 1024)
2) mmap(f, 0, 4096)
3) a[0] = 'a'
4) truncate(f, 4096)
5) writepage(...)

Now if we get a writepage callback immediately after (4) and before an
attempt to write at any other offset via mmap address (which implies we
are yet to get a pagefault and do a get_block) what we would have is the
page which is dirty have first block allocated and the other three
buffer_heads unmapped.

In the above case the writepage should go ahead and try to write the
first blocks and clear the page_dirty flag. Further attempts to write
to the page will again create a fault and result in allocating blocks
and marking page dirty. If we don't write any other offset via mmap
address we would still have written the first block to the disk and
rest of the space will be considered as a hole.

So to address this, we change all of the places where we look for
delayed, unmapped, or unwritten buffer heads, and only check for
delayed or unwritten buffer heads instead.

Signed-off-by: Aneesh Kumar K.V <aneesh.kumar@linux.vnet.ibm.com>
Acked-by: Jan Kara <jack@suse.cz>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>

authored by

Aneesh Kumar K.V and committed by
Theodore Ts'o
c364b22c b767e78a

+8 -15
+8 -15
fs/ext4/inode.c
··· 2305 2305 return; 2306 2306 } 2307 2307 2308 - static int ext4_bh_unmapped_or_delay(handle_t *handle, struct buffer_head *bh) 2308 + static int ext4_bh_delay_or_unwritten(handle_t *handle, struct buffer_head *bh) 2309 2309 { 2310 - /* 2311 - * unmapped buffer is possible for holes. 2312 - * delay buffer is possible with delayed allocation. 2313 - * We also need to consider unwritten buffer as unmapped. 2314 - */ 2315 - return (!buffer_mapped(bh) || buffer_delay(bh) || 2316 - buffer_unwritten(bh)) && buffer_dirty(bh); 2310 + return (buffer_delay(bh) || buffer_unwritten(bh)) && buffer_dirty(bh); 2317 2311 } 2318 2312 2319 2313 /* ··· 2394 2400 * Otherwise we won't make progress 2395 2401 * with the page in ext4_da_writepage 2396 2402 */ 2397 - if (ext4_bh_unmapped_or_delay(NULL, bh)) { 2403 + if (ext4_bh_delay_or_unwritten(NULL, bh)) { 2398 2404 mpage_add_bh_to_extent(mpd, logical, 2399 2405 bh->b_size, 2400 2406 bh->b_state); ··· 2511 2517 * so call get_block_wrap with create = 0 2512 2518 */ 2513 2519 ret = ext4_get_blocks(NULL, inode, iblock, max_blocks, bh_result, 0); 2514 - BUG_ON(create && ret == 0); 2515 2520 if (ret > 0) { 2516 2521 bh_result->b_size = (ret << inode->i_blkbits); 2517 2522 ret = 0; ··· 2526 2533 * - grab_page_cache when doing write_begin (have journal handle) 2527 2534 */ 2528 2535 static int ext4_da_writepage(struct page *page, 2529 - struct writeback_control *wbc) 2536 + struct writeback_control *wbc) 2530 2537 { 2531 2538 int ret = 0; 2532 2539 loff_t size; ··· 2544 2551 if (page_has_buffers(page)) { 2545 2552 page_bufs = page_buffers(page); 2546 2553 if (walk_page_buffers(NULL, page_bufs, 0, len, NULL, 2547 - ext4_bh_unmapped_or_delay)) { 2554 + ext4_bh_delay_or_unwritten)) { 2548 2555 /* 2549 2556 * We don't want to do block allocation 2550 2557 * So redirty the page and return ··· 2577 2584 page_bufs = page_buffers(page); 2578 2585 /* check whether all are mapped and non delay */ 2579 2586 if (walk_page_buffers(NULL, page_bufs, 0, len, NULL, 2580 - ext4_bh_unmapped_or_delay)) { 2587 + ext4_bh_delay_or_unwritten)) { 2581 2588 redirty_page_for_writepage(wbc, page); 2582 2589 unlock_page(page); 2583 2590 return 0; ··· 3225 3232 * happily proceed with mapping them and writing the page. 3226 3233 */ 3227 3234 BUG_ON(walk_page_buffers(NULL, page_buffers(page), 0, len, NULL, 3228 - ext4_bh_unmapped_or_delay)); 3235 + ext4_bh_delay_or_unwritten)); 3229 3236 } 3230 3237 3231 3238 if (!ext4_journal_current_handle()) ··· 3315 3322 * happily proceed with mapping them and writing the page. 3316 3323 */ 3317 3324 BUG_ON(walk_page_buffers(NULL, page_buffers(page), 0, len, NULL, 3318 - ext4_bh_unmapped_or_delay)); 3325 + ext4_bh_delay_or_unwritten)); 3319 3326 } 3320 3327 3321 3328 if (ext4_journal_current_handle())