mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-12 05:48:40 +00:00
btrfs: don't fail writeback when allocating the compression context fails
If cow_file_range_async fails to allocate the asynchronous writeback context, it currently returns an error and entirely fails the writeback. This is not a good idea as a writeback failure is a non-temporary error condition that will make the file system unusable. Just fall back to synchronous uncompressed writeback instead. This requires us to delay setting the BTRFS_INODE_HAS_ASYNC_EXTENT flag until we've committed to the async writeback. The compression checks INODE_NOCOMPRESS and FORCE_COMPRESS are moved from cow_file_range_async to the preceding checks btrfs_run_delalloc_range(). Reviewed-by: Josef Bacik <josef@toxicpanda.com> Signed-off-by: Christoph Hellwig <hch@lst.de> Reviewed-by: David Sterba <dsterba@suse.com> Signed-off-by: David Sterba <dsterba@suse.com>
This commit is contained in:
parent
57201dddd6
commit
973fb26e81
1 changed files with 28 additions and 46 deletions
|
@ -1720,58 +1720,36 @@ static noinline void async_cow_free(struct btrfs_work *work)
|
|||
kvfree(async_cow);
|
||||
}
|
||||
|
||||
static int cow_file_range_async(struct btrfs_inode *inode,
|
||||
struct writeback_control *wbc,
|
||||
struct page *locked_page,
|
||||
u64 start, u64 end, int *page_started,
|
||||
unsigned long *nr_written)
|
||||
static bool cow_file_range_async(struct btrfs_inode *inode,
|
||||
struct writeback_control *wbc,
|
||||
struct page *locked_page,
|
||||
u64 start, u64 end, int *page_started,
|
||||
unsigned long *nr_written)
|
||||
{
|
||||
struct btrfs_fs_info *fs_info = inode->root->fs_info;
|
||||
struct cgroup_subsys_state *blkcg_css = wbc_blkcg_css(wbc);
|
||||
struct async_cow *ctx;
|
||||
struct async_chunk *async_chunk;
|
||||
unsigned long nr_pages;
|
||||
u64 cur_end;
|
||||
u64 num_chunks = DIV_ROUND_UP(end - start, SZ_512K);
|
||||
int i;
|
||||
bool should_compress;
|
||||
unsigned nofs_flag;
|
||||
const blk_opf_t write_flags = wbc_to_write_flags(wbc);
|
||||
|
||||
unlock_extent(&inode->io_tree, start, end, NULL);
|
||||
|
||||
if (inode->flags & BTRFS_INODE_NOCOMPRESS &&
|
||||
!btrfs_test_opt(fs_info, FORCE_COMPRESS)) {
|
||||
num_chunks = 1;
|
||||
should_compress = false;
|
||||
} else {
|
||||
should_compress = true;
|
||||
}
|
||||
|
||||
nofs_flag = memalloc_nofs_save();
|
||||
ctx = kvmalloc(struct_size(ctx, chunks, num_chunks), GFP_KERNEL);
|
||||
memalloc_nofs_restore(nofs_flag);
|
||||
if (!ctx)
|
||||
return false;
|
||||
|
||||
if (!ctx) {
|
||||
unsigned clear_bits = EXTENT_LOCKED | EXTENT_DELALLOC |
|
||||
EXTENT_DELALLOC_NEW | EXTENT_DEFRAG |
|
||||
EXTENT_DO_ACCOUNTING;
|
||||
unsigned long page_ops = PAGE_UNLOCK | PAGE_START_WRITEBACK |
|
||||
PAGE_END_WRITEBACK | PAGE_SET_ERROR;
|
||||
|
||||
extent_clear_unlock_delalloc(inode, start, end, locked_page,
|
||||
clear_bits, page_ops);
|
||||
return -ENOMEM;
|
||||
}
|
||||
unlock_extent(&inode->io_tree, start, end, NULL);
|
||||
set_bit(BTRFS_INODE_HAS_ASYNC_EXTENT, &inode->runtime_flags);
|
||||
|
||||
async_chunk = ctx->chunks;
|
||||
atomic_set(&ctx->num_chunks, num_chunks);
|
||||
|
||||
for (i = 0; i < num_chunks; i++) {
|
||||
if (should_compress)
|
||||
cur_end = min(end, start + SZ_512K - 1);
|
||||
else
|
||||
cur_end = end;
|
||||
u64 cur_end = min(end, start + SZ_512K - 1);
|
||||
|
||||
/*
|
||||
* igrab is called higher up in the call chain, take only the
|
||||
|
@ -1832,7 +1810,7 @@ static int cow_file_range_async(struct btrfs_inode *inode,
|
|||
start = cur_end + 1;
|
||||
}
|
||||
*page_started = 1;
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static noinline int run_delalloc_zoned(struct btrfs_inode *inode,
|
||||
|
@ -2413,7 +2391,7 @@ int btrfs_run_delalloc_range(struct btrfs_inode *inode, struct page *locked_page
|
|||
u64 start, u64 end, int *page_started, unsigned long *nr_written,
|
||||
struct writeback_control *wbc)
|
||||
{
|
||||
int ret;
|
||||
int ret = 0;
|
||||
const bool zoned = btrfs_is_zoned(inode->root->fs_info);
|
||||
|
||||
/*
|
||||
|
@ -2434,19 +2412,23 @@ int btrfs_run_delalloc_range(struct btrfs_inode *inode, struct page *locked_page
|
|||
ASSERT(!zoned || btrfs_is_data_reloc_root(inode->root));
|
||||
ret = run_delalloc_nocow(inode, locked_page, start, end,
|
||||
page_started, nr_written);
|
||||
} else if (!btrfs_inode_can_compress(inode) ||
|
||||
!inode_need_compress(inode, start, end)) {
|
||||
if (zoned)
|
||||
ret = run_delalloc_zoned(inode, locked_page, start, end,
|
||||
page_started, nr_written);
|
||||
else
|
||||
ret = cow_file_range(inode, locked_page, start, end,
|
||||
page_started, nr_written, 1, NULL);
|
||||
} else {
|
||||
set_bit(BTRFS_INODE_HAS_ASYNC_EXTENT, &inode->runtime_flags);
|
||||
ret = cow_file_range_async(inode, wbc, locked_page, start, end,
|
||||
page_started, nr_written);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (btrfs_inode_can_compress(inode) &&
|
||||
inode_need_compress(inode, start, end) &&
|
||||
cow_file_range_async(inode, wbc, locked_page, start,
|
||||
end, page_started, nr_written))
|
||||
goto out;
|
||||
|
||||
if (zoned)
|
||||
ret = run_delalloc_zoned(inode, locked_page, start, end,
|
||||
page_started, nr_written);
|
||||
else
|
||||
ret = cow_file_range(inode, locked_page, start, end,
|
||||
page_started, nr_written, 1, NULL);
|
||||
|
||||
out:
|
||||
ASSERT(ret <= 0);
|
||||
if (ret)
|
||||
btrfs_cleanup_ordered_extents(inode, locked_page, start,
|
||||
|
|
Loading…
Reference in a new issue