diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c index b044b1d910de..54b607a3cc3f 100644 --- a/fs/btrfs/inode.c +++ b/fs/btrfs/inode.c @@ -9702,8 +9702,14 @@ static int btrfs_rename_exchange(struct inode *old_dir, bool root_log_pinned = false; bool dest_log_pinned = false; - /* we only allow rename subvolume link between subvolumes */ - if (old_ino != BTRFS_FIRST_FREE_OBJECTID && root != dest) + /* + * For non-subvolumes allow exchange only within one subvolume, in the + * same inode namespace. Two subvolumes (represented as directory) can + * be exchanged as they're a logical link and have a fixed inode number. + */ + if (root != dest && + (old_ino != BTRFS_FIRST_FREE_OBJECTID || + new_ino != BTRFS_FIRST_FREE_OBJECTID)) return -EXDEV; /* close the race window with snapshot create/destroy ioctl */