--- /dev/null
+From 3cf4bda4673838c6267b85f71721f4c91b30d1c4 Mon Sep 17 00:00:00 2001
+From: Sasha Levin <sashal@kernel.org>
+Date: Wed, 18 Dec 2019 17:20:27 -0500
+Subject: btrfs: rework arguments of btrfs_unlink_subvol
+
+From: Josef Bacik <josef@toxicpanda.com>
+
+[ Upstream commit 045d3967b6920b663fc010ad414ade1b24143bd1 ]
+
+btrfs_unlink_subvol takes the name of the dentry and the root objectid
+based on what kind of inode this is, either a real subvolume link or a
+empty one that we inherited as a snapshot. We need to fix how we unlink
+in the case for BTRFS_EMPTY_SUBVOL_DIR_OBJECTID in the future, so rework
+btrfs_unlink_subvol to just take the dentry and handle getting the right
+objectid given the type of inode this is. There is no functional change
+here, simply pushing the work into btrfs_unlink_subvol() proper.
+
+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 | 46 ++++++++++++++++++++--------------------------
+ 1 file changed, 20 insertions(+), 26 deletions(-)
+
+diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
+index 9e2a9b5449d9..6f0568fb5899 100644
+--- a/fs/btrfs/inode.c
++++ b/fs/btrfs/inode.c
+@@ -4215,18 +4215,30 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
+ }
+
+ static int btrfs_unlink_subvol(struct btrfs_trans_handle *trans,
+- struct inode *dir, u64 objectid,
+- const char *name, int name_len)
++ struct inode *dir, struct dentry *dentry)
+ {
+ struct btrfs_root *root = BTRFS_I(dir)->root;
++ struct btrfs_inode *inode = BTRFS_I(d_inode(dentry));
+ struct btrfs_path *path;
+ struct extent_buffer *leaf;
+ struct btrfs_dir_item *di;
+ struct btrfs_key key;
++ const char *name = dentry->d_name.name;
++ int name_len = dentry->d_name.len;
+ u64 index;
+ int ret;
++ u64 objectid;
+ u64 dir_ino = btrfs_ino(BTRFS_I(dir));
+
++ if (btrfs_ino(inode) == BTRFS_FIRST_FREE_OBJECTID) {
++ objectid = inode->root->root_key.objectid;
++ } else if (btrfs_ino(inode) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID) {
++ objectid = inode->location.objectid;
++ } else {
++ WARN_ON(1);
++ return -EINVAL;
++ }
++
+ path = btrfs_alloc_path();
+ if (!path)
+ return -ENOMEM;
+@@ -4475,8 +4487,7 @@ int btrfs_delete_subvolume(struct inode *dir, struct dentry *dentry)
+
+ btrfs_record_snapshot_destroy(trans, BTRFS_I(dir));
+
+- ret = btrfs_unlink_subvol(trans, dir, dest->root_key.objectid,
+- dentry->d_name.name, dentry->d_name.len);
++ ret = btrfs_unlink_subvol(trans, dir, dentry);
+ if (ret) {
+ err = ret;
+ btrfs_abort_transaction(trans, ret);
+@@ -4571,10 +4582,7 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
+ return PTR_ERR(trans);
+
+ if (unlikely(btrfs_ino(BTRFS_I(inode)) == BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)) {
+- err = btrfs_unlink_subvol(trans, dir,
+- BTRFS_I(inode)->location.objectid,
+- dentry->d_name.name,
+- dentry->d_name.len);
++ err = btrfs_unlink_subvol(trans, dir, dentry);
+ goto out;
+ }
+
+@@ -9530,7 +9538,6 @@ static int btrfs_rename_exchange(struct inode *old_dir,
+ u64 new_ino = btrfs_ino(BTRFS_I(new_inode));
+ u64 old_idx = 0;
+ u64 new_idx = 0;
+- u64 root_objectid;
+ int ret;
+ bool root_log_pinned = false;
+ bool dest_log_pinned = false;
+@@ -9636,10 +9643,7 @@ static int btrfs_rename_exchange(struct inode *old_dir,
+
+ /* src is a subvolume */
+ if (old_ino == BTRFS_FIRST_FREE_OBJECTID) {
+- root_objectid = BTRFS_I(old_inode)->root->root_key.objectid;
+- ret = btrfs_unlink_subvol(trans, old_dir, root_objectid,
+- old_dentry->d_name.name,
+- old_dentry->d_name.len);
++ ret = btrfs_unlink_subvol(trans, old_dir, old_dentry);
+ } else { /* src is an inode */
+ ret = __btrfs_unlink_inode(trans, root, BTRFS_I(old_dir),
+ BTRFS_I(old_dentry->d_inode),
+@@ -9655,10 +9659,7 @@ static int btrfs_rename_exchange(struct inode *old_dir,
+
+ /* dest is a subvolume */
+ if (new_ino == BTRFS_FIRST_FREE_OBJECTID) {
+- root_objectid = BTRFS_I(new_inode)->root->root_key.objectid;
+- ret = btrfs_unlink_subvol(trans, new_dir, root_objectid,
+- new_dentry->d_name.name,
+- new_dentry->d_name.len);
++ ret = btrfs_unlink_subvol(trans, new_dir, new_dentry);
+ } else { /* dest is an inode */
+ ret = __btrfs_unlink_inode(trans, dest, BTRFS_I(new_dir),
+ BTRFS_I(new_dentry->d_inode),
+@@ -9856,7 +9857,6 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+ struct inode *new_inode = d_inode(new_dentry);
+ struct inode *old_inode = d_inode(old_dentry);
+ u64 index = 0;
+- u64 root_objectid;
+ int ret;
+ u64 old_ino = btrfs_ino(BTRFS_I(old_inode));
+ bool log_pinned = false;
+@@ -9964,10 +9964,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+ BTRFS_I(old_inode), 1);
+
+ if (unlikely(old_ino == BTRFS_FIRST_FREE_OBJECTID)) {
+- root_objectid = BTRFS_I(old_inode)->root->root_key.objectid;
+- ret = btrfs_unlink_subvol(trans, old_dir, root_objectid,
+- old_dentry->d_name.name,
+- old_dentry->d_name.len);
++ ret = btrfs_unlink_subvol(trans, old_dir, old_dentry);
+ } else {
+ ret = __btrfs_unlink_inode(trans, root, BTRFS_I(old_dir),
+ BTRFS_I(d_inode(old_dentry)),
+@@ -9986,10 +9983,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+ new_inode->i_ctime = current_time(new_inode);
+ if (unlikely(btrfs_ino(BTRFS_I(new_inode)) ==
+ BTRFS_EMPTY_SUBVOL_DIR_OBJECTID)) {
+- root_objectid = BTRFS_I(new_inode)->location.objectid;
+- ret = btrfs_unlink_subvol(trans, new_dir, root_objectid,
+- new_dentry->d_name.name,
+- new_dentry->d_name.len);
++ ret = btrfs_unlink_subvol(trans, new_dir, new_dentry);
+ BUG_ON(new_inode->i_nlink == 0);
+ } else {
+ ret = btrfs_unlink_inode(trans, dest, BTRFS_I(new_dir),
+--
+2.20.1
+