Commit 53ffb30a authored by Christoph Hellwig's avatar Christoph Hellwig Committed by David Sterba

btrfs: don't create inline extents in fallback_to_cow

For NOCOW files, run_delalloc_nocow can still fall back to COW
allocations when required and calls to fallback_to_cow helper for
that.  For such an allocation we can have multiple ordered_extents
for existing extents that NOCOW overwrites and new allocations that
fallback_to_cow creates.  If one of the new extents is an inline
extent, the writepages could would have to avoid normal page writeback
for them as indicated by the page_started return argument, which
run_delalloc_nocow can't return.   Fix this by never creating inline
extents from fallback_to_cow.
Reviewed-by: default avatarJosef Bacik <josef@toxicpanda.com>
Signed-off-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent ba9145ad
...@@ -129,7 +129,7 @@ static noinline int cow_file_range(struct btrfs_inode *inode, ...@@ -129,7 +129,7 @@ static noinline int cow_file_range(struct btrfs_inode *inode,
struct page *locked_page, struct page *locked_page,
u64 start, u64 end, int *page_started, u64 start, u64 end, int *page_started,
unsigned long *nr_written, u64 *done_offset, unsigned long *nr_written, u64 *done_offset,
bool keep_locked); bool keep_locked, bool no_inline);
static struct extent_map *create_io_em(struct btrfs_inode *inode, u64 start, static struct extent_map *create_io_em(struct btrfs_inode *inode, u64 start,
u64 len, u64 orig_start, u64 block_start, u64 len, u64 orig_start, u64 block_start,
u64 block_len, u64 orig_block_len, u64 block_len, u64 orig_block_len,
...@@ -1149,7 +1149,7 @@ static int submit_uncompressed_range(struct btrfs_inode *inode, ...@@ -1149,7 +1149,7 @@ static int submit_uncompressed_range(struct btrfs_inode *inode,
* can directly submit them without interruption. * can directly submit them without interruption.
*/ */
ret = cow_file_range(inode, locked_page, start, end, &page_started, ret = cow_file_range(inode, locked_page, start, end, &page_started,
&nr_written, NULL, true); &nr_written, NULL, true, false);
/* Inline extent inserted, page gets unlocked and everything is done */ /* Inline extent inserted, page gets unlocked and everything is done */
if (page_started) if (page_started)
return 0; return 0;
...@@ -1385,7 +1385,7 @@ static noinline int cow_file_range(struct btrfs_inode *inode, ...@@ -1385,7 +1385,7 @@ static noinline int cow_file_range(struct btrfs_inode *inode,
struct page *locked_page, struct page *locked_page,
u64 start, u64 end, int *page_started, u64 start, u64 end, int *page_started,
unsigned long *nr_written, u64 *done_offset, unsigned long *nr_written, u64 *done_offset,
bool keep_locked) bool keep_locked, bool no_inline)
{ {
struct btrfs_root *root = inode->root; struct btrfs_root *root = inode->root;
struct btrfs_fs_info *fs_info = root->fs_info; struct btrfs_fs_info *fs_info = root->fs_info;
...@@ -1424,7 +1424,7 @@ static noinline int cow_file_range(struct btrfs_inode *inode, ...@@ -1424,7 +1424,7 @@ static noinline int cow_file_range(struct btrfs_inode *inode,
* This means we can trigger inline extent even if we didn't want to. * This means we can trigger inline extent even if we didn't want to.
* So here we skip inline extent creation completely. * So here we skip inline extent creation completely.
*/ */
if (start == 0 && fs_info->sectorsize == PAGE_SIZE) { 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);
...@@ -1829,7 +1829,7 @@ static noinline int run_delalloc_zoned(struct btrfs_inode *inode, ...@@ -1829,7 +1829,7 @@ static noinline int run_delalloc_zoned(struct btrfs_inode *inode,
while (start <= end) { while (start <= end) {
ret = cow_file_range(inode, locked_page, start, end, page_started, ret = cow_file_range(inode, locked_page, start, end, page_started,
nr_written, &done_offset, true); nr_written, &done_offset, true, false);
if (ret && ret != -EAGAIN) if (ret && ret != -EAGAIN)
return ret; return ret;
...@@ -1887,15 +1887,17 @@ static noinline int csum_exist_in_range(struct btrfs_fs_info *fs_info, ...@@ -1887,15 +1887,17 @@ static noinline int csum_exist_in_range(struct btrfs_fs_info *fs_info,
} }
static int fallback_to_cow(struct btrfs_inode *inode, struct page *locked_page, static int fallback_to_cow(struct btrfs_inode *inode, struct page *locked_page,
const u64 start, const u64 end, const u64 start, const u64 end)
int *page_started, unsigned long *nr_written)
{ {
const bool is_space_ino = btrfs_is_free_space_inode(inode); const bool is_space_ino = btrfs_is_free_space_inode(inode);
const bool is_reloc_ino = btrfs_is_data_reloc_root(inode->root); const bool is_reloc_ino = btrfs_is_data_reloc_root(inode->root);
const u64 range_bytes = end + 1 - start; const u64 range_bytes = end + 1 - start;
struct extent_io_tree *io_tree = &inode->io_tree; struct extent_io_tree *io_tree = &inode->io_tree;
int page_started = 0;
unsigned long nr_written;
u64 range_start = start; u64 range_start = start;
u64 count; u64 count;
int ret;
/* /*
* If EXTENT_NORESERVE is set it means that when the buffered write was * If EXTENT_NORESERVE is set it means that when the buffered write was
...@@ -1948,8 +1950,15 @@ static int fallback_to_cow(struct btrfs_inode *inode, struct page *locked_page, ...@@ -1948,8 +1950,15 @@ static int fallback_to_cow(struct btrfs_inode *inode, struct page *locked_page,
NULL); NULL);
} }
return cow_file_range(inode, locked_page, start, end, page_started, /*
nr_written, NULL, false); * Don't try to create inline extents, as a mix of inline extent that
* is written out and unlocked directly and a normal NOCOW extent
* doesn't work.
*/
ret = cow_file_range(inode, locked_page, start, end, &page_started,
&nr_written, NULL, false, true);
ASSERT(!page_started);
return ret;
} }
struct can_nocow_file_extent_args { struct can_nocow_file_extent_args {
...@@ -2098,9 +2107,7 @@ static int can_nocow_file_extent(struct btrfs_path *path, ...@@ -2098,9 +2107,7 @@ static int can_nocow_file_extent(struct btrfs_path *path,
*/ */
static noinline int run_delalloc_nocow(struct btrfs_inode *inode, static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
struct page *locked_page, struct page *locked_page,
const u64 start, const u64 end, const u64 start, const u64 end)
int *page_started,
unsigned long *nr_written)
{ {
struct btrfs_fs_info *fs_info = inode->root->fs_info; struct btrfs_fs_info *fs_info = inode->root->fs_info;
struct btrfs_root *root = inode->root; struct btrfs_root *root = inode->root;
...@@ -2268,8 +2275,7 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode, ...@@ -2268,8 +2275,7 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
*/ */
if (cow_start != (u64)-1) { if (cow_start != (u64)-1) {
ret = fallback_to_cow(inode, locked_page, ret = fallback_to_cow(inode, locked_page,
cow_start, found_key.offset - 1, cow_start, found_key.offset - 1);
page_started, nr_written);
if (ret) if (ret)
goto error; goto error;
cow_start = (u64)-1; cow_start = (u64)-1;
...@@ -2350,8 +2356,7 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode, ...@@ -2350,8 +2356,7 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
if (cow_start != (u64)-1) { if (cow_start != (u64)-1) {
cur_offset = end; cur_offset = end;
ret = fallback_to_cow(inode, locked_page, cow_start, end, ret = fallback_to_cow(inode, locked_page, cow_start, end);
page_started, nr_written);
if (ret) if (ret)
goto error; goto error;
} }
...@@ -2410,8 +2415,7 @@ int btrfs_run_delalloc_range(struct btrfs_inode *inode, struct page *locked_page ...@@ -2410,8 +2415,7 @@ int btrfs_run_delalloc_range(struct btrfs_inode *inode, struct page *locked_page
* preallocated inodes. * preallocated inodes.
*/ */
ASSERT(!zoned || btrfs_is_data_reloc_root(inode->root)); ASSERT(!zoned || btrfs_is_data_reloc_root(inode->root));
ret = run_delalloc_nocow(inode, locked_page, start, end, ret = run_delalloc_nocow(inode, locked_page, start, end);
page_started, nr_written);
goto out; goto out;
} }
...@@ -2426,7 +2430,7 @@ int btrfs_run_delalloc_range(struct btrfs_inode *inode, struct page *locked_page ...@@ -2426,7 +2430,7 @@ int btrfs_run_delalloc_range(struct btrfs_inode *inode, struct page *locked_page
page_started, nr_written, wbc); page_started, nr_written, wbc);
else else
ret = cow_file_range(inode, locked_page, start, end, ret = cow_file_range(inode, locked_page, start, end,
page_started, nr_written, NULL, false); page_started, nr_written, NULL, false, false);
out: out:
ASSERT(ret <= 0); ASSERT(ret <= 0);
......
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