btrfs: don't double lock the subvol_sem for rename exchange
authorJosef Bacik <josef@toxicpanda.com>
Tue, 19 Nov 2019 18:59:20 +0000 (13:59 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Sat, 4 Jan 2020 12:40:12 +0000 (13:40 +0100)
[ Upstream commit 943eb3bf25f4a7b745dd799e031be276aa104d82 ]

If we're rename exchanging two subvols we'll try to lock this lock
twice, which is bad.  Just lock once if either of the ino's are subvols.

Fixes: cdd1fedf8261 ("btrfs: add support for RENAME_EXCHANGE and RENAME_WHITEOUT")
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>
Signed-off-by: Sasha Levin <sashal@kernel.org>
fs/btrfs/inode.c

index 80937c5ca4775706fb34bc3a248723a834b98a98..bb8863958ac0ff4d032deb8da0509357a5edfb81 100644 (file)
@@ -9597,9 +9597,8 @@ static int btrfs_rename_exchange(struct inode *old_dir,
                return -EXDEV;
 
        /* close the race window with snapshot create/destroy ioctl */
-       if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
-               down_read(&root->fs_info->subvol_sem);
-       if (new_ino == BTRFS_FIRST_FREE_OBJECTID)
+       if (old_ino == BTRFS_FIRST_FREE_OBJECTID ||
+           new_ino == BTRFS_FIRST_FREE_OBJECTID)
                down_read(&dest->fs_info->subvol_sem);
 
        /*
@@ -9785,9 +9784,8 @@ out_fail:
        ret2 = btrfs_end_transaction(trans, root);
        ret = ret ? ret : ret2;
 out_notrans:
-       if (new_ino == BTRFS_FIRST_FREE_OBJECTID)
-               up_read(&dest->fs_info->subvol_sem);
-       if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
+       if (new_ino == BTRFS_FIRST_FREE_OBJECTID ||
+           old_ino == BTRFS_FIRST_FREE_OBJECTID)
                up_read(&root->fs_info->subvol_sem);
 
        return ret;