btrfs: improve error handling in run_delalloc_nocow
authorNikolay Borisov <nborisov@suse.com>
Thu, 22 Aug 2019 14:24:20 +0000 (17:24 +0300)
committerDavid Sterba <dsterba@suse.com>
Mon, 9 Sep 2019 12:59:14 +0000 (14:59 +0200)
Correctly handle failure cases when adding an ordered extents in case
of REGULAR or PREALLOC extents. Remove the BUG_ON.

Signed-off-by: Nikolay Borisov <nborisov@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/inode.c

index 90c6a4813a197f5236d0e7129c857fc66b65ab74..b52282df8c4d3a9272d7f90c1faffc73da7a44c7 100644 (file)
@@ -1314,6 +1314,8 @@ static noinline int run_delalloc_nocow(struct inode *inode,
        bool check_prev = true;
        const bool freespace_inode = btrfs_is_free_space_inode(BTRFS_I(inode));
        u64 ino = btrfs_ino(BTRFS_I(inode));
+       bool nocow = false;
+       u64 disk_bytenr = 0;
 
        path = btrfs_alloc_path();
        if (!path) {
@@ -1333,12 +1335,12 @@ static noinline int run_delalloc_nocow(struct inode *inode,
                struct extent_buffer *leaf;
                u64 extent_end;
                u64 extent_offset;
-               u64 disk_bytenr = 0;
                u64 num_bytes = 0;
                u64 disk_num_bytes;
                u64 ram_bytes;
                int extent_type;
-               bool nocow = false;
+
+               nocow = false;
 
                ret = btrfs_lookup_file_extent(NULL, root, path, ino,
                                               cur_offset, 0);
@@ -1572,16 +1574,25 @@ out_check:
                                                       disk_bytenr, num_bytes,
                                                       num_bytes,
                                                       BTRFS_ORDERED_PREALLOC);
+                       if (ret) {
+                               btrfs_drop_extent_cache(BTRFS_I(inode),
+                                                       cur_offset,
+                                                       cur_offset + num_bytes - 1,
+                                                       0);
+                               goto error;
+                       }
                } else {
                        ret = btrfs_add_ordered_extent(inode, cur_offset,
                                                       disk_bytenr, num_bytes,
                                                       num_bytes,
                                                       BTRFS_ORDERED_NOCOW);
+                       if (ret)
+                               goto error;
                }
 
                if (nocow)
                        btrfs_dec_nocow_writers(fs_info, disk_bytenr);
-               BUG_ON(ret); /* -ENOMEM */
+               nocow = false;
 
                if (root->root_key.objectid ==
                    BTRFS_DATA_RELOC_TREE_OBJECTID)
@@ -1626,6 +1637,9 @@ out_check:
        }
 
 error:
+       if (nocow)
+               btrfs_dec_nocow_writers(fs_info, disk_bytenr);
+
        if (ret && cur_offset < end)
                extent_clear_unlock_delalloc(inode, cur_offset, end,
                                             locked_page, EXTENT_LOCKED |