Skip to content

Commit 6eecfa2

Browse files
josefbacikkdave
authored andcommitted
btrfs: push all inline logic into cow_file_range
Currently we have a lot of duplicated checks of if (start == 0 && fs_info->sectorsize == PAGE_SIZE) cow_file_range_inline(); Instead of duplicating this check everywhere, consolidate all of the inline extent logic into a helper which documents all of the checks and then use that helper inside of cow_file_range_inline(). With this we can clean up all of the calls to either unconditionally call cow_file_range_inline(), or at least reduce the checks we're doing before we call cow_file_range_inline(); Reviewed-by: Goldwyn Rodrigues <rgoldwyn@suse.com> Signed-off-by: Josef Bacik <josef@toxicpanda.com> Signed-off-by: David Sterba <dsterba@suse.com>
1 parent aa5ccf2 commit 6eecfa2

1 file changed

Lines changed: 81 additions & 62 deletions

File tree

fs/btrfs/inode.c

Lines changed: 81 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -614,14 +614,56 @@ static int insert_inline_extent(struct btrfs_trans_handle *trans,
614614
return ret;
615615
}
616616

617+
static bool can_cow_file_range_inline(struct btrfs_inode *inode,
618+
u64 offset, u64 size,
619+
size_t compressed_size)
620+
{
621+
struct btrfs_fs_info *fs_info = inode->root->fs_info;
622+
u64 data_len = (compressed_size ?: size);
623+
624+
/* Inline extents must start at offset 0. */
625+
if (offset != 0)
626+
return false;
627+
628+
/*
629+
* Due to the page size limit, for subpage we can only trigger the
630+
* writeback for the dirty sectors of page, that means data writeback
631+
* is doing more writeback than what we want.
632+
*
633+
* This is especially unexpected for some call sites like fallocate,
634+
* where we only increase i_size after everything is done.
635+
* This means we can trigger inline extent even if we didn't want to.
636+
* So here we skip inline extent creation completely.
637+
*/
638+
if (fs_info->sectorsize != PAGE_SIZE)
639+
return false;
640+
641+
/* Inline extents are limited to sectorsize. */
642+
if (size > fs_info->sectorsize)
643+
return false;
644+
645+
/* We cannot exceed the maximum inline data size. */
646+
if (data_len > BTRFS_MAX_INLINE_DATA_SIZE(fs_info))
647+
return false;
648+
649+
/* We cannot exceed the user specified max_inline size. */
650+
if (data_len > fs_info->max_inline)
651+
return false;
652+
653+
/* Inline extents must be the entirety of the file. */
654+
if (size < i_size_read(&inode->vfs_inode))
655+
return false;
656+
657+
return true;
658+
}
617659

618660
/*
619661
* conditionally insert an inline extent into the file. This
620662
* does the checks required to make sure the data is small enough
621663
* to fit as an inline extent.
622664
*/
623-
static noinline int cow_file_range_inline(struct btrfs_inode *inode, u64 size,
624-
size_t compressed_size,
665+
static noinline int cow_file_range_inline(struct btrfs_inode *inode, u64 offset,
666+
u64 size, size_t compressed_size,
625667
int compress_type,
626668
struct folio *compressed_folio,
627669
bool update_i_size)
@@ -634,16 +676,7 @@ static noinline int cow_file_range_inline(struct btrfs_inode *inode, u64 size,
634676
int ret;
635677
struct btrfs_path *path;
636678

637-
/*
638-
* We can create an inline extent if it ends at or beyond the current
639-
* i_size, is no larger than a sector (decompressed), and the (possibly
640-
* compressed) data fits in a leaf and the configured maximum inline
641-
* size.
642-
*/
643-
if (size < i_size_read(&inode->vfs_inode) ||
644-
size > fs_info->sectorsize ||
645-
data_len > BTRFS_MAX_INLINE_DATA_SIZE(fs_info) ||
646-
data_len > fs_info->max_inline)
679+
if (!can_cow_file_range_inline(inode, offset, size, compressed_size))
647680
return 1;
648681

649682
path = btrfs_alloc_path();
@@ -971,43 +1004,38 @@ static void compress_file_range(struct btrfs_work *work)
9711004
* Check cow_file_range() for why we don't even try to create inline
9721005
* extent for the subpage case.
9731006
*/
974-
if (start == 0 && fs_info->sectorsize == PAGE_SIZE) {
975-
if (total_in < actual_end) {
976-
ret = cow_file_range_inline(inode, actual_end, 0,
977-
BTRFS_COMPRESS_NONE, NULL,
978-
false);
979-
} else {
980-
ret = cow_file_range_inline(inode, actual_end,
981-
total_compressed,
982-
compress_type, folios[0],
983-
false);
984-
}
985-
if (ret <= 0) {
986-
unsigned long clear_flags = EXTENT_DELALLOC |
987-
EXTENT_DELALLOC_NEW | EXTENT_DEFRAG |
988-
EXTENT_DO_ACCOUNTING;
1007+
if (total_in < actual_end)
1008+
ret = cow_file_range_inline(inode, start, actual_end, 0,
1009+
BTRFS_COMPRESS_NONE, NULL, false);
1010+
else
1011+
ret = cow_file_range_inline(inode, start, actual_end,
1012+
total_compressed, compress_type,
1013+
folios[0], false);
1014+
if (ret <= 0) {
1015+
unsigned long clear_flags = EXTENT_DELALLOC |
1016+
EXTENT_DELALLOC_NEW | EXTENT_DEFRAG |
1017+
EXTENT_DO_ACCOUNTING;
9891018

990-
if (ret < 0)
991-
mapping_set_error(mapping, -EIO);
1019+
if (ret < 0)
1020+
mapping_set_error(mapping, -EIO);
9921021

993-
/*
994-
* inline extent creation worked or returned error,
995-
* we don't need to create any more async work items.
996-
* Unlock and free up our temp pages.
997-
*
998-
* We use DO_ACCOUNTING here because we need the
999-
* delalloc_release_metadata to be done _after_ we drop
1000-
* our outstanding extent for clearing delalloc for this
1001-
* range.
1002-
*/
1003-
extent_clear_unlock_delalloc(inode, start, end,
1004-
NULL,
1005-
clear_flags,
1006-
PAGE_UNLOCK |
1007-
PAGE_START_WRITEBACK |
1008-
PAGE_END_WRITEBACK);
1009-
goto free_pages;
1010-
}
1022+
/*
1023+
* inline extent creation worked or returned error,
1024+
* we don't need to create any more async work items.
1025+
* Unlock and free up our temp pages.
1026+
*
1027+
* We use DO_ACCOUNTING here because we need the
1028+
* delalloc_release_metadata to be done _after_ we drop
1029+
* our outstanding extent for clearing delalloc for this
1030+
* range.
1031+
*/
1032+
extent_clear_unlock_delalloc(inode, start, end,
1033+
NULL,
1034+
clear_flags,
1035+
PAGE_UNLOCK |
1036+
PAGE_START_WRITEBACK |
1037+
PAGE_END_WRITEBACK);
1038+
goto free_pages;
10111039
}
10121040

10131041
/*
@@ -1315,22 +1343,12 @@ static noinline int cow_file_range(struct btrfs_inode *inode,
13151343

13161344
inode_should_defrag(inode, start, end, num_bytes, SZ_64K);
13171345

1318-
/*
1319-
* Due to the page size limit, for subpage we can only trigger the
1320-
* writeback for the dirty sectors of page, that means data writeback
1321-
* is doing more writeback than what we want.
1322-
*
1323-
* This is especially unexpected for some call sites like fallocate,
1324-
* where we only increase i_size after everything is done.
1325-
* This means we can trigger inline extent even if we didn't want to.
1326-
* So here we skip inline extent creation completely.
1327-
*/
1328-
if (start == 0 && fs_info->sectorsize == PAGE_SIZE && !no_inline) {
1346+
if (!no_inline) {
13291347
u64 actual_end = min_t(u64, i_size_read(&inode->vfs_inode),
13301348
end + 1);
13311349

13321350
/* lets try to make an inline extent */
1333-
ret = cow_file_range_inline(inode, actual_end, 0,
1351+
ret = cow_file_range_inline(inode, start, actual_end, 0,
13341352
BTRFS_COMPRESS_NONE, NULL, false);
13351353
if (ret == 0) {
13361354
/*
@@ -10266,10 +10284,11 @@ ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from,
1026610284
goto out_qgroup_free_data;
1026710285

1026810286
/* Try an inline extent first. */
10269-
if (start == 0 && encoded->unencoded_len == encoded->len &&
10287+
if (encoded->unencoded_len == encoded->len &&
1027010288
encoded->unencoded_offset == 0) {
10271-
ret = cow_file_range_inline(inode, encoded->len, orig_count,
10272-
compression, folios[0], true);
10289+
ret = cow_file_range_inline(inode, start, encoded->len,
10290+
orig_count, compression, folios[0],
10291+
true);
1027310292
if (ret <= 0) {
1027410293
if (ret == 0)
1027510294
ret = orig_count;

0 commit comments

Comments
 (0)