summaryrefslogtreecommitdiffstats
path: root/fs/btrfs
diff options
context:
space:
mode:
authorChristoph Hellwig <hch@lst.de>2023-07-24 16:22:39 +0200
committerDavid Sterba <dsterba@suse.com>2023-08-21 14:54:47 +0200
commit18f62b86c4ea943256f8962ecd0cb013c97b4e0f (patch)
tree3dceed925c52163a1877a7c3406cb672ccb7764a /fs/btrfs
parentbtrfs: fix error handling when in a COW window in run_delalloc_nocow (diff)
downloadlinux-18f62b86c4ea943256f8962ecd0cb013c97b4e0f.tar.xz
linux-18f62b86c4ea943256f8962ecd0cb013c97b4e0f.zip
btrfs: cleanup the COW fallback logic in run_delalloc_nocow
Use the block group pointer used to track the outstanding NOCOW writes as a boolean to remove the duplicate nocow variable, and keep it contained in the main loop to simplify the logic. Reviewed-by: Boris Burkov <boris@bur.io> Signed-off-by: Christoph Hellwig <hch@lst.de> Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs/btrfs')
-rw-r--r--fs/btrfs/inode.c47
1 files changed, 22 insertions, 25 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 0d973a959559..1fb1e4ac4a8c 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -1974,8 +1974,6 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
int ret;
bool check_prev = true;
u64 ino = btrfs_ino(inode);
- struct btrfs_block_group *bg;
- bool nocow = false;
struct can_nocow_file_extent_args nocow_args = { 0 };
path = btrfs_alloc_path();
@@ -1993,6 +1991,7 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
nocow_args.writeback_path = true;
while (1) {
+ struct btrfs_block_group *nocow_bg = NULL;
struct btrfs_ordered_extent *ordered;
struct btrfs_key found_key;
struct btrfs_file_extent_item *fi;
@@ -2003,8 +2002,6 @@ static noinline int run_delalloc_nocow(struct btrfs_inode *inode,
int extent_type;
bool is_prealloc;
- nocow = false;
-
ret = btrfs_lookup_file_extent(NULL, root, path, ino,
cur_offset, 0);
if (ret < 0)
@@ -2063,7 +2060,7 @@ next_slot:
if (found_key.offset > cur_offset) {
extent_end = found_key.offset;
extent_type = 0;
- goto out_check;
+ goto must_cow;
}
/*
@@ -2096,18 +2093,19 @@ next_slot:
if (ret < 0)
goto error;
if (ret == 0)
- goto out_check;
+ goto must_cow;
ret = 0;
- bg = btrfs_inc_nocow_writers(fs_info, nocow_args.disk_bytenr);
- if (bg)
- nocow = true;
-out_check:
- /*
- * If nocow is false then record the beginning of the range
- * that needs to be COWed
- */
- if (!nocow) {
+ nocow_bg = btrfs_inc_nocow_writers(fs_info, nocow_args.disk_bytenr);
+ if (!nocow_bg) {
+must_cow:
+ /*
+ * If we can't perform NOCOW writeback for the range,
+ * then record the beginning of the range that needs to
+ * be COWed. It will be written out before the next
+ * NOCOW range if we find one, or when exiting this
+ * loop.
+ */
if (cow_start == (u64)-1)
cow_start = cur_offset;
cur_offset = extent_end;
@@ -2128,8 +2126,10 @@ out_check:
ret = fallback_to_cow(inode, locked_page,
cow_start, found_key.offset - 1);
cow_start = (u64)-1;
- if (ret)
+ if (ret) {
+ btrfs_dec_nocow_writers(nocow_bg);
goto error;
+ }
}
nocow_end = cur_offset + nocow_args.num_bytes - 1;
@@ -2146,6 +2146,7 @@ out_check:
ram_bytes, BTRFS_COMPRESS_NONE,
BTRFS_ORDERED_PREALLOC);
if (IS_ERR(em)) {
+ btrfs_dec_nocow_writers(nocow_bg);
ret = PTR_ERR(em);
goto error;
}
@@ -2159,6 +2160,7 @@ out_check:
? (1 << BTRFS_ORDERED_PREALLOC)
: (1 << BTRFS_ORDERED_NOCOW),
BTRFS_COMPRESS_NONE);
+ btrfs_dec_nocow_writers(nocow_bg);
if (IS_ERR(ordered)) {
if (is_prealloc) {
btrfs_drop_extent_map_range(inode, cur_offset,
@@ -2168,11 +2170,6 @@ out_check:
goto error;
}
- if (nocow) {
- btrfs_dec_nocow_writers(bg);
- nocow = false;
- }
-
if (btrfs_is_data_reloc_root(root))
/*
* Error handled later, as we must prevent
@@ -2213,10 +2210,10 @@ out_check:
goto error;
}
-error:
- if (nocow)
- btrfs_dec_nocow_writers(bg);
+ btrfs_free_path(path);
+ return 0;
+error:
/*
* If an error happened while a COW region is outstanding, cur_offset
* needs to be reset to cow_start to ensure the COW region is unlocked
@@ -2224,7 +2221,7 @@ error:
*/
if (cow_start != (u64)-1)
cur_offset = cow_start;
- if (ret && cur_offset < end)
+ if (cur_offset < end)
extent_clear_unlock_delalloc(inode, cur_offset, end,
locked_page, EXTENT_LOCKED |
EXTENT_DELALLOC | EXTENT_DEFRAG |