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.

btrfs: extract inlined creation into a dedicated delalloc helper

Currently we call cow_file_range_inline() in different situations, from
regular cow_file_range() to compress_file_range().

This is because inline extent creation has different conditions based on
whether it's a compressed one or not.

But on the other hand, inline extent creation shouldn't be so
distributed, we can just have a dedicated branch in
btrfs_run_delalloc_range().

It will become more obvious for compressed inline cases, it makes no
sense to go through all the complex async extent mechanism just to
inline a single block.

So here we introduce a dedicated run_delalloc_inline() helper, and
remove all inline related handling from cow_file_range() and
compress_file_range().

There is a special update to inode_need_compress(), that a new
@check_inline parameter is introduced.
This is to allow inline specific checks to be done inside
run_delalloc_inline(), which allows single block compression, but
other call sites should always reject single block compression.

Reviewed-by: Boris Burkov <boris@bur.io>
Signed-off-by: Qu Wenruo <wqu@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>

authored by

Qu Wenruo and committed by
David Sterba
3eaf5f08 9d7db410

+110 -110
+110 -110
fs/btrfs/inode.c
··· 74 74 #include "delayed-inode.h" 75 75 76 76 #define COW_FILE_RANGE_KEEP_LOCKED (1UL << 0) 77 - #define COW_FILE_RANGE_NO_INLINE (1UL << 1) 78 77 79 78 struct btrfs_iget_args { 80 79 u64 ino; ··· 621 622 * 622 623 * If being used directly, you must have already checked we're allowed to cow 623 624 * the range by getting true from can_cow_file_range_inline(). 625 + * 626 + * Return 0 if the inlined extent is created successfully. 627 + * Return <0 for critical error, and should be considered as an writeback error. 628 + * Return >0 if can not create an inlined extent (mostly due to lack of meta space). 624 629 */ 625 630 static noinline int __cow_file_range_inline(struct btrfs_inode *inode, 626 631 u64 size, size_t compressed_size, ··· 706 703 return ret; 707 704 } 708 705 709 - static noinline int cow_file_range_inline(struct btrfs_inode *inode, 710 - struct folio *locked_folio, 711 - u64 offset, u64 end, 712 - size_t compressed_size, 713 - int compress_type, 714 - struct folio *compressed_folio, 715 - bool update_i_size) 716 - { 717 - struct extent_state *cached = NULL; 718 - unsigned long clear_flags = EXTENT_DELALLOC | EXTENT_DELALLOC_NEW | 719 - EXTENT_DEFRAG | EXTENT_DO_ACCOUNTING | EXTENT_LOCKED; 720 - u64 size = min_t(u64, i_size_read(&inode->vfs_inode), end + 1); 721 - int ret; 722 - 723 - if (!can_cow_file_range_inline(inode, offset, size, compressed_size)) 724 - return 1; 725 - 726 - btrfs_lock_extent(&inode->io_tree, offset, end, &cached); 727 - ret = __cow_file_range_inline(inode, size, compressed_size, 728 - compress_type, compressed_folio, 729 - update_i_size); 730 - if (ret > 0) { 731 - btrfs_unlock_extent(&inode->io_tree, offset, end, &cached); 732 - return ret; 733 - } 734 - 735 - /* 736 - * In the successful case (ret == 0 here), cow_file_range will return 1. 737 - * 738 - * Quite a bit further up the callstack in extent_writepage(), ret == 1 739 - * is treated as a short circuited success and does not unlock the folio, 740 - * so we must do it here. 741 - * 742 - * In the failure case, the locked_folio does get unlocked by 743 - * btrfs_folio_end_all_writers, which asserts that it is still locked 744 - * at that point, so we must *not* unlock it here. 745 - * 746 - * The other two callsites in compress_file_range do not have a 747 - * locked_folio, so they are not relevant to this logic. 748 - */ 749 - if (ret == 0) 750 - locked_folio = NULL; 751 - 752 - extent_clear_unlock_delalloc(inode, offset, end, locked_folio, &cached, 753 - clear_flags, PAGE_UNLOCK | 754 - PAGE_START_WRITEBACK | PAGE_END_WRITEBACK); 755 - return ret; 756 - } 757 - 758 706 struct async_extent { 759 707 u64 start; 760 708 u64 ram_size; ··· 751 797 * options, defragmentation, properties or heuristics. 752 798 */ 753 799 static inline int inode_need_compress(struct btrfs_inode *inode, u64 start, 754 - u64 end) 800 + u64 end, bool check_inline) 755 801 { 756 802 struct btrfs_fs_info *fs_info = inode->root->fs_info; 757 803 ··· 766 812 * and will always fallback to regular write later. 767 813 */ 768 814 if (end + 1 - start <= fs_info->sectorsize && 769 - (start > 0 || end + 1 < inode->disk_i_size)) 815 + (!check_inline || (start > 0 || end + 1 < inode->disk_i_size))) 770 816 return 0; 817 + 771 818 /* Defrag ioctl takes precedence over mount options and properties. */ 772 819 if (inode->defrag_compress == BTRFS_DEFRAG_DONT_COMPRESS) 773 820 return 0; ··· 883 928 container_of(work, struct async_chunk, work); 884 929 struct btrfs_inode *inode = async_chunk->inode; 885 930 struct btrfs_fs_info *fs_info = inode->root->fs_info; 886 - struct address_space *mapping = inode->vfs_inode.i_mapping; 887 931 struct compressed_bio *cb = NULL; 888 932 u64 blocksize = fs_info->sectorsize; 889 933 u64 start = async_chunk->start; ··· 954 1000 * been flagged as NOCOMPRESS. This flag can change at any time if we 955 1001 * discover bad compression ratios. 956 1002 */ 957 - if (!inode_need_compress(inode, start, end)) 1003 + if (!inode_need_compress(inode, start, end, false)) 958 1004 goto cleanup_and_bail_uncompressed; 959 1005 960 1006 if (0 < inode->defrag_compress && inode->defrag_compress < BTRFS_NR_COMPRESS_TYPES) { ··· 974 1020 975 1021 total_compressed = cb->bbio.bio.bi_iter.bi_size; 976 1022 total_in = cur_len; 977 - 978 - /* 979 - * Try to create an inline extent. 980 - * 981 - * If we didn't compress the entire range, try to create an uncompressed 982 - * inline extent, else a compressed one. 983 - * 984 - * Check cow_file_range() for why we don't even try to create inline 985 - * extent for the subpage case. 986 - */ 987 - if (total_in < actual_end) 988 - ret = cow_file_range_inline(inode, NULL, start, end, 0, 989 - BTRFS_COMPRESS_NONE, NULL, false); 990 - else 991 - ret = cow_file_range_inline(inode, NULL, start, end, total_compressed, 992 - compress_type, 993 - bio_first_folio_all(&cb->bbio.bio), false); 994 - if (ret <= 0) { 995 - cleanup_compressed_bio(cb); 996 - if (ret < 0) 997 - mapping_set_error(mapping, -EIO); 998 - return; 999 - } 1000 - /* 1001 - * If a single block at file offset 0 cannot be inlined, fall back to 1002 - * regular writes without marking the file incompressible. 1003 - */ 1004 - if (start == 0 && end <= blocksize) 1005 - goto cleanup_and_bail_uncompressed; 1006 1023 1007 1024 /* 1008 1025 * We aren't doing an inline extent. Round the compressed size up to a ··· 1352 1427 * 1353 1428 * When this function fails, it unlocks all folios except @locked_folio. 1354 1429 * 1355 - * When this function successfully creates an inline extent, it returns 1 and 1356 - * unlocks all folios including locked_folio and starts I/O on them. 1357 - * (In reality inline extents are limited to a single block, so locked_folio is 1358 - * the only folio handled anyway). 1359 - * 1360 1430 * When this function succeed and creates a normal extent, the folio locking 1361 1431 * status depends on the passed in flags: 1362 1432 * ··· 1395 1475 ASSERT(num_bytes <= btrfs_super_total_bytes(fs_info->super_copy)); 1396 1476 1397 1477 inode_should_defrag(inode, start, end, num_bytes, SZ_64K); 1398 - 1399 - if (!(flags & COW_FILE_RANGE_NO_INLINE)) { 1400 - /* lets try to make an inline extent */ 1401 - ret = cow_file_range_inline(inode, locked_folio, start, end, 0, 1402 - BTRFS_COMPRESS_NONE, NULL, false); 1403 - if (ret <= 0) { 1404 - /* 1405 - * We succeeded, return 1 so the caller knows we're done 1406 - * with this page and already handled the IO. 1407 - * 1408 - * If there was an error then cow_file_range_inline() has 1409 - * already done the cleanup. 1410 - */ 1411 - if (ret == 0) 1412 - ret = 1; 1413 - goto done; 1414 - } 1415 - } 1416 - 1417 1478 alloc_hint = btrfs_get_extent_allocation_hint(inode, start, num_bytes); 1418 1479 1419 1480 /* ··· 1472 1571 } 1473 1572 extent_clear_unlock_delalloc(inode, orig_start, end, locked_folio, &cached, 1474 1573 EXTENT_LOCKED | EXTENT_DELALLOC, page_ops); 1475 - done: 1476 1574 if (done_offset) 1477 1575 *done_offset = end; 1478 1576 return ret; ··· 1774 1874 * a locked folio, which can race with writeback. 1775 1875 */ 1776 1876 ret = cow_file_range(inode, locked_folio, start, end, NULL, 1777 - COW_FILE_RANGE_NO_INLINE | COW_FILE_RANGE_KEEP_LOCKED); 1877 + COW_FILE_RANGE_KEEP_LOCKED); 1778 1878 ASSERT(ret != 1); 1779 1879 return ret; 1780 1880 } ··· 2326 2426 } 2327 2427 2328 2428 /* 2429 + * Return 0 if an inlined extent is created successfully. 2430 + * Return <0 if critical error happened. 2431 + * Return >0 if an inline extent can not be created. 2432 + */ 2433 + static int run_delalloc_inline(struct btrfs_inode *inode, struct folio *locked_folio) 2434 + { 2435 + struct btrfs_fs_info *fs_info = inode->root->fs_info; 2436 + struct compressed_bio *cb = NULL; 2437 + struct extent_state *cached = NULL; 2438 + const u64 i_size = i_size_read(&inode->vfs_inode); 2439 + const u32 blocksize = fs_info->sectorsize; 2440 + int compress_type = fs_info->compress_type; 2441 + int compress_level = fs_info->compress_level; 2442 + u32 compressed_size = 0; 2443 + int ret; 2444 + 2445 + ASSERT(folio_pos(locked_folio) == 0); 2446 + 2447 + if (btrfs_inode_can_compress(inode) && 2448 + inode_need_compress(inode, 0, blocksize, true)) { 2449 + if (inode->defrag_compress > 0 && 2450 + inode->defrag_compress < BTRFS_NR_COMPRESS_TYPES) { 2451 + compress_type = inode->defrag_compress; 2452 + compress_level = inode->defrag_compress_level; 2453 + } else if (inode->prop_compress) { 2454 + compress_type = inode->prop_compress; 2455 + } 2456 + cb = btrfs_compress_bio(inode, 0, blocksize, compress_type, compress_level, 0); 2457 + if (IS_ERR(cb)) { 2458 + cb = NULL; 2459 + /* Just fall back to non-compressed case. */ 2460 + } else { 2461 + compressed_size = cb->bbio.bio.bi_iter.bi_size; 2462 + } 2463 + } 2464 + if (!can_cow_file_range_inline(inode, 0, i_size, compressed_size)) { 2465 + if (cb) 2466 + cleanup_compressed_bio(cb); 2467 + return 1; 2468 + } 2469 + 2470 + btrfs_lock_extent(&inode->io_tree, 0, blocksize - 1, &cached); 2471 + if (cb) { 2472 + ret = __cow_file_range_inline(inode, i_size, compressed_size, compress_type, 2473 + bio_first_folio_all(&cb->bbio.bio), false); 2474 + cleanup_compressed_bio(cb); 2475 + cb = NULL; 2476 + } else { 2477 + ret = __cow_file_range_inline(inode, i_size, 0, BTRFS_COMPRESS_NONE, 2478 + NULL, false); 2479 + } 2480 + /* 2481 + * We failed to insert inline extent due to lack of meta space. 2482 + * Just unlock the extent io range and fallback to regular COW/NOCOW path. 2483 + */ 2484 + if (ret > 0) { 2485 + btrfs_unlock_extent(&inode->io_tree, 0, blocksize - 1, &cached); 2486 + return ret; 2487 + } 2488 + 2489 + /* 2490 + * In the successful case (ret == 0 here), btrfs_run_delalloc_range() 2491 + * will return 1. 2492 + * 2493 + * Quite a bit further up the callstack in extent_writepage(), ret == 1 2494 + * is treated as a short circuited success and does not unlock the folio, 2495 + * so we must do it here. 2496 + * 2497 + * For failure case, the @locked_folio does get unlocked by 2498 + * btrfs_folio_end_lock_bitmap(), so we must *not* unlock it here. 2499 + * 2500 + * So if ret == 0, we let extent_clear_unlock_delalloc() to unlock the 2501 + * folio by passing NULL as @locked_folio. 2502 + * Otherwise pass @locked_folio as usual. 2503 + */ 2504 + if (ret == 0) 2505 + locked_folio = NULL; 2506 + extent_clear_unlock_delalloc(inode, 0, blocksize - 1, locked_folio, &cached, 2507 + EXTENT_DELALLOC | EXTENT_DELALLOC_NEW | EXTENT_DEFRAG | 2508 + EXTENT_DO_ACCOUNTING | EXTENT_LOCKED, 2509 + PAGE_UNLOCK | PAGE_START_WRITEBACK | PAGE_END_WRITEBACK); 2510 + return ret; 2511 + } 2512 + 2513 + /* 2329 2514 * Function to process delayed allocation (create CoW) for ranges which are 2330 2515 * being touched for the first time. 2331 2516 */ ··· 2426 2441 ASSERT(!(end <= folio_pos(locked_folio) || 2427 2442 start >= folio_next_pos(locked_folio))); 2428 2443 2444 + if (start == 0 && end + 1 <= inode->root->fs_info->sectorsize && 2445 + end + 1 >= inode->disk_i_size) { 2446 + int ret; 2447 + 2448 + ret = run_delalloc_inline(inode, locked_folio); 2449 + if (ret < 0) 2450 + return ret; 2451 + if (ret == 0) 2452 + return 1; 2453 + /* 2454 + * Continue regular handling if we can not create an 2455 + * inlined extent. 2456 + */ 2457 + } 2458 + 2429 2459 if (should_nocow(inode, start, end)) 2430 2460 return run_delalloc_nocow(inode, locked_folio, start, end); 2431 2461 2432 2462 if (btrfs_inode_can_compress(inode) && 2433 - inode_need_compress(inode, start, end) && 2463 + inode_need_compress(inode, start, end, false) && 2434 2464 run_delalloc_compressed(inode, locked_folio, start, end, wbc)) 2435 2465 return 1; 2436 2466