diff options
author | Filipe Manana <fdmanana@suse.com> | 2018-06-11 21:24:16 +0300 |
---|---|---|
committer | David Sterba <dsterba@suse.com> | 2018-06-22 13:59:08 +0300 |
commit | c5b4a50b74018b3677098151ec5f4fce07d5e6a0 (patch) | |
tree | 7f913f1c852140049b4b63efb073feb8469e75f4 /fs | |
parent | 22883ddc66df402f2fbc37fe1f4d2779238e4b2d (diff) | |
download | linux-c5b4a50b74018b3677098151ec5f4fce07d5e6a0.tar.xz |
Btrfs: fix return value on rename exchange failure
If we failed during a rename exchange operation after starting/joining a
transaction, we would end up replacing the return value, stored in the
local 'ret' variable, with the return value from btrfs_end_transaction().
So this could end up returning 0 (success) to user space despite the
operation having failed and aborted the transaction, because if there are
multiple tasks having a reference on the transaction at the time
btrfs_end_transaction() is called by the rename exchange, that function
returns 0 (otherwise it returns -EIO and not the original error value).
So fix this by not overwriting the return value on error after getting
a transaction handle.
Fixes: cdd1fedf8261 ("btrfs: add support for RENAME_EXCHANGE and RENAME_WHITEOUT")
CC: stable@vger.kernel.org # 4.9+
Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/btrfs/inode.c | 4 |
1 files changed, 3 insertions, 1 deletions
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index c12b7a6e534a..a6bf9e2ff68f 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -9443,6 +9443,7 @@ static int btrfs_rename_exchange(struct inode *old_dir, u64 new_idx = 0; u64 root_objectid; int ret; + int ret2; bool root_log_pinned = false; bool dest_log_pinned = false; @@ -9639,7 +9640,8 @@ out_fail: dest_log_pinned = false; } } - ret = btrfs_end_transaction(trans); + ret2 = btrfs_end_transaction(trans); + ret = ret ? ret : ret2; out_notrans: if (new_ino == BTRFS_FIRST_FREE_OBJECTID) up_read(&fs_info->subvol_sem); |