]> www.infradead.org Git - linux-platform-drivers-x86.git/commitdiff
btrfs: abort the transaction if we fail to inc ref in btrfs_copy_root
authorJosef Bacik <josef@toxicpanda.com>
Thu, 14 Jan 2021 19:02:46 +0000 (14:02 -0500)
committerDavid Sterba <dsterba@suse.com>
Mon, 8 Feb 2021 21:58:56 +0000 (22:58 +0100)
While testing my error handling patches, I added a error injection site
at btrfs_inc_extent_ref, to validate the error handling I added was
doing the correct thing.  However I hit a pretty ugly corruption while
doing this check, with the following error injection stack trace:

btrfs_inc_extent_ref
  btrfs_copy_root
    create_reloc_root
      btrfs_init_reloc_root
btrfs_record_root_in_trans
  btrfs_start_transaction
    btrfs_update_inode
      btrfs_update_time
touch_atime
  file_accessed
    btrfs_file_mmap

This is because we do not catch the error from btrfs_inc_extent_ref,
which in practice would be ENOMEM, which means we lose the extent
references for a root that has already been allocated and inserted,
which is the problem.  Fix this by aborting the transaction if we fail
to do the reference modification.

CC: stable@vger.kernel.org # 4.4+
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
fs/btrfs/ctree.c

index 56e132d825a28883344d0a46cd59f2d4426eb6e8..95d9bae764abdf97da388e02d2e4639ed2a04b42 100644 (file)
@@ -221,9 +221,10 @@ int btrfs_copy_root(struct btrfs_trans_handle *trans,
                ret = btrfs_inc_ref(trans, root, cow, 1);
        else
                ret = btrfs_inc_ref(trans, root, cow, 0);
-
-       if (ret)
+       if (ret) {
+               btrfs_abort_transaction(trans, ret);
                return ret;
+       }
 
        btrfs_mark_buffer_dirty(cow);
        *cow_ret = cow;