Commit 6eecfa22 authored by Josef Bacik's avatar Josef Bacik Committed by David Sterba

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: default avatarGoldwyn Rodrigues <rgoldwyn@suse.com>
Signed-off-by: default avatarJosef Bacik <josef@toxicpanda.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent aa5ccf29
...@@ -614,14 +614,56 @@ static int insert_inline_extent(struct btrfs_trans_handle *trans, ...@@ -614,14 +614,56 @@ static int insert_inline_extent(struct btrfs_trans_handle *trans,
return ret; return ret;
} }
static bool can_cow_file_range_inline(struct btrfs_inode *inode,
u64 offset, u64 size,
size_t compressed_size)
{
struct btrfs_fs_info *fs_info = inode->root->fs_info;
u64 data_len = (compressed_size ?: size);
/* Inline extents must start at offset 0. */
if (offset != 0)
return false;
/*
* Due to the page size limit, for subpage we can only trigger the
* writeback for the dirty sectors of page, that means data writeback
* is doing more writeback than what we want.
*
* This is especially unexpected for some call sites like fallocate,
* where we only increase i_size after everything is done.
* This means we can trigger inline extent even if we didn't want to.
* So here we skip inline extent creation completely.
*/
if (fs_info->sectorsize != PAGE_SIZE)
return false;
/* Inline extents are limited to sectorsize. */
if (size > fs_info->sectorsize)
return false;
/* We cannot exceed the maximum inline data size. */
if (data_len > BTRFS_MAX_INLINE_DATA_SIZE(fs_info))
return false;
/* We cannot exceed the user specified max_inline size. */
if (data_len > fs_info->max_inline)
return false;
/* Inline extents must be the entirety of the file. */
if (size < i_size_read(&inode->vfs_inode))
return false;
return true;
}
/* /*
* conditionally insert an inline extent into the file. This * conditionally insert an inline extent into the file. This
* does the checks required to make sure the data is small enough * does the checks required to make sure the data is small enough
* to fit as an inline extent. * to fit as an inline extent.
*/ */
static noinline int cow_file_range_inline(struct btrfs_inode *inode, u64 size, static noinline int cow_file_range_inline(struct btrfs_inode *inode, u64 offset,
size_t compressed_size, u64 size, size_t compressed_size,
int compress_type, int compress_type,
struct folio *compressed_folio, struct folio *compressed_folio,
bool update_i_size) bool update_i_size)
...@@ -634,16 +676,7 @@ static noinline int cow_file_range_inline(struct btrfs_inode *inode, u64 size, ...@@ -634,16 +676,7 @@ static noinline int cow_file_range_inline(struct btrfs_inode *inode, u64 size,
int ret; int ret;
struct btrfs_path *path; struct btrfs_path *path;
/* if (!can_cow_file_range_inline(inode, offset, size, compressed_size))
* We can create an inline extent if it ends at or beyond the current
* i_size, is no larger than a sector (decompressed), and the (possibly
* compressed) data fits in a leaf and the configured maximum inline
* size.
*/
if (size < i_size_read(&inode->vfs_inode) ||
size > fs_info->sectorsize ||
data_len > BTRFS_MAX_INLINE_DATA_SIZE(fs_info) ||
data_len > fs_info->max_inline)
return 1; return 1;
path = btrfs_alloc_path(); path = btrfs_alloc_path();
...@@ -971,43 +1004,38 @@ static void compress_file_range(struct btrfs_work *work) ...@@ -971,43 +1004,38 @@ static void compress_file_range(struct btrfs_work *work)
* Check cow_file_range() for why we don't even try to create inline * Check cow_file_range() for why we don't even try to create inline
* extent for the subpage case. * extent for the subpage case.
*/ */
if (start == 0 && fs_info->sectorsize == PAGE_SIZE) { if (total_in < actual_end)
if (total_in < actual_end) { ret = cow_file_range_inline(inode, start, actual_end, 0,
ret = cow_file_range_inline(inode, actual_end, 0, BTRFS_COMPRESS_NONE, NULL, false);
BTRFS_COMPRESS_NONE, NULL, else
false); ret = cow_file_range_inline(inode, start, actual_end,
} else { total_compressed, compress_type,
ret = cow_file_range_inline(inode, actual_end, folios[0], false);
total_compressed, if (ret <= 0) {
compress_type, folios[0], unsigned long clear_flags = EXTENT_DELALLOC |
false); EXTENT_DELALLOC_NEW | EXTENT_DEFRAG |
} EXTENT_DO_ACCOUNTING;
if (ret <= 0) {
unsigned long clear_flags = EXTENT_DELALLOC |
EXTENT_DELALLOC_NEW | EXTENT_DEFRAG |
EXTENT_DO_ACCOUNTING;
if (ret < 0) if (ret < 0)
mapping_set_error(mapping, -EIO); mapping_set_error(mapping, -EIO);
/* /*
* inline extent creation worked or returned error, * inline extent creation worked or returned error,
* we don't need to create any more async work items. * we don't need to create any more async work items.
* Unlock and free up our temp pages. * Unlock and free up our temp pages.
* *
* We use DO_ACCOUNTING here because we need the * We use DO_ACCOUNTING here because we need the
* delalloc_release_metadata to be done _after_ we drop * delalloc_release_metadata to be done _after_ we drop
* our outstanding extent for clearing delalloc for this * our outstanding extent for clearing delalloc for this
* range. * range.
*/ */
extent_clear_unlock_delalloc(inode, start, end, extent_clear_unlock_delalloc(inode, start, end,
NULL, NULL,
clear_flags, clear_flags,
PAGE_UNLOCK | PAGE_UNLOCK |
PAGE_START_WRITEBACK | PAGE_START_WRITEBACK |
PAGE_END_WRITEBACK); PAGE_END_WRITEBACK);
goto free_pages; goto free_pages;
}
} }
/* /*
...@@ -1315,22 +1343,12 @@ static noinline int cow_file_range(struct btrfs_inode *inode, ...@@ -1315,22 +1343,12 @@ static noinline int cow_file_range(struct btrfs_inode *inode,
inode_should_defrag(inode, start, end, num_bytes, SZ_64K); inode_should_defrag(inode, start, end, num_bytes, SZ_64K);
/* if (!no_inline) {
* Due to the page size limit, for subpage we can only trigger the
* writeback for the dirty sectors of page, that means data writeback
* is doing more writeback than what we want.
*
* This is especially unexpected for some call sites like fallocate,
* where we only increase i_size after everything is done.
* This means we can trigger inline extent even if we didn't want to.
* So here we skip inline extent creation completely.
*/
if (start == 0 && fs_info->sectorsize == PAGE_SIZE && !no_inline) {
u64 actual_end = min_t(u64, i_size_read(&inode->vfs_inode), u64 actual_end = min_t(u64, i_size_read(&inode->vfs_inode),
end + 1); end + 1);
/* lets try to make an inline extent */ /* lets try to make an inline extent */
ret = cow_file_range_inline(inode, actual_end, 0, ret = cow_file_range_inline(inode, start, actual_end, 0,
BTRFS_COMPRESS_NONE, NULL, false); BTRFS_COMPRESS_NONE, NULL, false);
if (ret == 0) { if (ret == 0) {
/* /*
...@@ -10266,10 +10284,11 @@ ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from, ...@@ -10266,10 +10284,11 @@ ssize_t btrfs_do_encoded_write(struct kiocb *iocb, struct iov_iter *from,
goto out_qgroup_free_data; goto out_qgroup_free_data;
/* Try an inline extent first. */ /* Try an inline extent first. */
if (start == 0 && encoded->unencoded_len == encoded->len && if (encoded->unencoded_len == encoded->len &&
encoded->unencoded_offset == 0) { encoded->unencoded_offset == 0) {
ret = cow_file_range_inline(inode, encoded->len, orig_count, ret = cow_file_range_inline(inode, start, encoded->len,
compression, folios[0], true); orig_count, compression, folios[0],
true);
if (ret <= 0) { if (ret <= 0) {
if (ret == 0) if (ret == 0)
ret = orig_count; ret = orig_count;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment