All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v2 00/16] btrfs: inode creation cleanups and fixes
@ 2022-03-10  1:31 Omar Sandoval
  2022-03-10  1:31 ` [PATCH v2 01/16] btrfs: reserve correct number of items for unlink and rmdir Omar Sandoval
                   ` (16 more replies)
  0 siblings, 17 replies; 35+ messages in thread
From: Omar Sandoval @ 2022-03-10  1:31 UTC (permalink / raw)
  To: linux-btrfs; +Cc: kernel-team

From: Omar Sandoval <osandov@fb.com>

This series contains several cleanups and fixes for our inode creation
codepaths. The main motivation for this is preparation for fscrypt
support (in particular, setting up the fscrypt context and encrypted
names at inode creation time). But, it also reduces a lot of code
duplication and fixes some minor bugs, so it's worth getting in ahead of
time.

Patches 1-3 are small fixes. Patches 5-12 are small cleanups. Patches
13-16 are the bulk of the change.

Based on misc-next.

Changes since v1 [1]:

- Split the big final patch into patches 3 and 13-16.
- Added Sweet Tea's reviewed-by to the remaining patches.
- Rebased on latest misc-next.

Thanks!

1: https://lore.kernel.org/linux-btrfs/cover.1646348486.git.osandov@fb.com/

Omar Sandoval (16):
  btrfs: reserve correct number of items for unlink and rmdir
  btrfs: reserve correct number of items for rename
  btrfs: fix anon_dev leak in create_subvol()
  btrfs: get rid of btrfs_add_nondir()
  btrfs: remove unnecessary btrfs_i_size_write(0) calls
  btrfs: remove unnecessary inode_set_bytes(0) call
  btrfs: remove unnecessary set_nlink() in btrfs_create_subvol_root()
  btrfs: remove unused mnt_userns parameter from __btrfs_set_acl
  btrfs: remove redundant name and name_len parameters to create_subvol
  btrfs: don't pass parent objectid to btrfs_new_inode() explicitly
  btrfs: move btrfs_get_free_objectid() call into btrfs_new_inode()
  btrfs: set inode flags earlier in btrfs_new_inode()
  btrfs: allocate inode outside of btrfs_new_inode()
  btrfs: factor out common part of btrfs_{mknod,create,mkdir}()
  btrfs: reserve correct number of items for inode creation
  btrfs: move common inode creation code into btrfs_create_new_inode()

 fs/btrfs/acl.c   |  39 +-
 fs/btrfs/ctree.h |  37 +-
 fs/btrfs/inode.c | 942 +++++++++++++++++++++++------------------------
 fs/btrfs/ioctl.c | 176 ++++-----
 fs/btrfs/props.c |  40 +-
 fs/btrfs/props.h |   4 -
 6 files changed, 579 insertions(+), 659 deletions(-)

-- 
2.35.1


^ permalink raw reply	[flat|nested] 35+ messages in thread

* [PATCH v2 01/16] btrfs: reserve correct number of items for unlink and rmdir
  2022-03-10  1:31 [PATCH v2 00/16] btrfs: inode creation cleanups and fixes Omar Sandoval
@ 2022-03-10  1:31 ` Omar Sandoval
  2022-03-10  1:31 ` [PATCH v2 02/16] btrfs: reserve correct number of items for rename Omar Sandoval
                   ` (15 subsequent siblings)
  16 siblings, 0 replies; 35+ messages in thread
From: Omar Sandoval @ 2022-03-10  1:31 UTC (permalink / raw)
  To: linux-btrfs; +Cc: kernel-team

From: Omar Sandoval <osandov@fb.com>

__btrfs_unlink_inode() calls btrfs_update_inode() on the parent
directory in order to update its size and sequence number. Make sure we
account for it.

Reviewed-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Signed-off-by: Omar Sandoval <osandov@fb.com>
---
 fs/btrfs/inode.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 2e7143ff5523..2fb8aa36a9ac 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -4212,8 +4212,9 @@ static struct btrfs_trans_handle *__unlink_start_trans(struct inode *dir)
 	 * 1 for the dir index
 	 * 1 for the inode ref
 	 * 1 for the inode
+	 * 1 for the parent inode
 	 */
-	return btrfs_start_transaction_fallback_global_rsv(root, 5);
+	return btrfs_start_transaction_fallback_global_rsv(root, 6);
 }
 
 static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 02/16] btrfs: reserve correct number of items for rename
  2022-03-10  1:31 [PATCH v2 00/16] btrfs: inode creation cleanups and fixes Omar Sandoval
  2022-03-10  1:31 ` [PATCH v2 01/16] btrfs: reserve correct number of items for unlink and rmdir Omar Sandoval
@ 2022-03-10  1:31 ` Omar Sandoval
  2022-03-10  1:31 ` [PATCH v2 03/16] btrfs: fix anon_dev leak in create_subvol() Omar Sandoval
                   ` (14 subsequent siblings)
  16 siblings, 0 replies; 35+ messages in thread
From: Omar Sandoval @ 2022-03-10  1:31 UTC (permalink / raw)
  To: linux-btrfs; +Cc: kernel-team

From: Omar Sandoval <osandov@fb.com>

btrfs_rename() and btrfs_rename_exchange() don't account for enough
items. Replace the incorrect explanations with a specific breakdown of
the number of items and account them accurately.

Note that this glosses over RENAME_WHITEOUT because the next commit is
going to rework that, too.

Reviewed-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Signed-off-by: Omar Sandoval <osandov@fb.com>
---
 fs/btrfs/inode.c | 86 +++++++++++++++++++++++++++++++++++++-----------
 1 file changed, 67 insertions(+), 19 deletions(-)

diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 2fb8aa36a9ac..be51630160f5 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -9058,6 +9058,7 @@ static int btrfs_rename_exchange(struct inode *old_dir,
 {
 	struct btrfs_fs_info *fs_info = btrfs_sb(old_dir->i_sb);
 	struct btrfs_trans_handle *trans;
+	unsigned int trans_num_items;
 	struct btrfs_root *root = BTRFS_I(old_dir)->root;
 	struct btrfs_root *dest = BTRFS_I(new_dir)->root;
 	struct inode *new_inode = new_dentry->d_inode;
@@ -9089,14 +9090,37 @@ static int btrfs_rename_exchange(struct inode *old_dir,
 		down_read(&fs_info->subvol_sem);
 
 	/*
-	 * We want to reserve the absolute worst case amount of items.  So if
-	 * both inodes are subvols and we need to unlink them then that would
-	 * require 4 item modifications, but if they are both normal inodes it
-	 * would require 5 item modifications, so we'll assume their normal
-	 * inodes.  So 5 * 2 is 10, plus 2 for the new links, so 12 total items
-	 * should cover the worst case number of items we'll modify.
+	 * For each inode:
+	 * 1 to remove old dir item
+	 * 1 to remove old dir index
+	 * 1 to add new dir item
+	 * 1 to add new dir index
+	 * 1 to update parent inode
+	 *
+	 * If the parents are the same, we only need to account for one
 	 */
-	trans = btrfs_start_transaction(root, 12);
+	trans_num_items = old_dir == new_dir ? 9 : 10;
+	if (old_ino == BTRFS_FIRST_FREE_OBJECTID) {
+		/*
+		 * 1 to remove old root ref
+		 * 1 to remove old root backref
+		 * 1 to add new root ref
+		 * 1 to add new root backref
+		 */
+		trans_num_items += 4;
+	} else {
+		/*
+		 * 1 to update inode item
+		 * 1 to remove old inode ref
+		 * 1 to add new inode ref
+		 */
+		trans_num_items += 3;
+	}
+	if (new_ino == BTRFS_FIRST_FREE_OBJECTID)
+		trans_num_items += 4;
+	else
+		trans_num_items += 3;
+	trans = btrfs_start_transaction(root, trans_num_items);
 	if (IS_ERR(trans)) {
 		ret = PTR_ERR(trans);
 		goto out_notrans;
@@ -9375,21 +9399,45 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
 	if (new_inode && S_ISREG(old_inode->i_mode) && new_inode->i_size)
 		filemap_flush(old_inode->i_mapping);
 
-	/* close the racy window with snapshot create/destroy ioctl */
-	if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
+	if (old_ino == BTRFS_FIRST_FREE_OBJECTID) {
+		/* close the racy window with snapshot create/destroy ioctl */
 		down_read(&fs_info->subvol_sem);
+		/*
+		 * 1 to remove old root ref
+		 * 1 to remove old root backref
+		 * 1 to add new root ref
+		 * 1 to add new root backref
+		 */
+		trans_num_items = 4;
+	} else {
+		/*
+		 * 1 to update inode
+		 * 1 to remove old inode ref
+		 * 1 to add new inode ref
+		 */
+		trans_num_items = 3;
+	}
 	/*
-	 * We want to reserve the absolute worst case amount of items.  So if
-	 * both inodes are subvols and we need to unlink them then that would
-	 * require 4 item modifications, but if they are both normal inodes it
-	 * would require 5 item modifications, so we'll assume they are normal
-	 * inodes.  So 5 * 2 is 10, plus 1 for the new link, so 11 total items
-	 * should cover the worst case number of items we'll modify.
-	 * If our rename has the whiteout flag, we need more 5 units for the
-	 * new inode (1 inode item, 1 inode ref, 2 dir items and 1 xattr item
-	 * when selinux is enabled).
+	 * 1 to remove old dir item
+	 * 1 to remove old dir index
+	 * 1 to update old parent inode
+	 * 1 to add new dir item
+	 * 1 to add new dir index
+	 * 1 to update new parent inode (if it's not the same as the old parent)
 	 */
-	trans_num_items = 11;
+	trans_num_items += 6;
+	if (new_dir != old_dir)
+		trans_num_items++;
+	if (new_inode) {
+		/*
+		 * 1 to update inode
+		 * 1 to remove inode ref
+		 * 1 to remove dir item
+		 * 1 to remove dir index
+		 * 1 to possibly add orphan item
+		 */
+		trans_num_items += 5;
+	}
 	if (flags & RENAME_WHITEOUT)
 		trans_num_items += 5;
 	trans = btrfs_start_transaction(root, trans_num_items);
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 03/16] btrfs: fix anon_dev leak in create_subvol()
  2022-03-10  1:31 [PATCH v2 00/16] btrfs: inode creation cleanups and fixes Omar Sandoval
  2022-03-10  1:31 ` [PATCH v2 01/16] btrfs: reserve correct number of items for unlink and rmdir Omar Sandoval
  2022-03-10  1:31 ` [PATCH v2 02/16] btrfs: reserve correct number of items for rename Omar Sandoval
@ 2022-03-10  1:31 ` Omar Sandoval
  2022-03-11 15:42   ` Sweet Tea Dorminy
  2022-03-10  1:31 ` [PATCH v2 04/16] btrfs: get rid of btrfs_add_nondir() Omar Sandoval
                   ` (13 subsequent siblings)
  16 siblings, 1 reply; 35+ messages in thread
From: Omar Sandoval @ 2022-03-10  1:31 UTC (permalink / raw)
  To: linux-btrfs; +Cc: kernel-team

From: Omar Sandoval <osandov@fb.com>

When btrfs_qgroup_inherit(), btrfs_alloc_tree_block, or
btrfs_insert_root() fail in create_subvol(), we return without freeing
anon_dev. Reorganize the error handling in create_subvol() to fix this.

Signed-off-by: Omar Sandoval <osandov@fb.com>
---
 fs/btrfs/ioctl.c | 49 +++++++++++++++++++++++-------------------------
 1 file changed, 23 insertions(+), 26 deletions(-)

diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 238cee5b5254..d04870ea6a21 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -561,7 +561,7 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
 	struct timespec64 cur_time = current_time(dir);
 	struct inode *inode;
 	int ret;
-	dev_t anon_dev = 0;
+	dev_t anon_dev;
 	u64 objectid;
 	u64 index = 0;
 
@@ -571,11 +571,7 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
 
 	ret = btrfs_get_free_objectid(fs_info->tree_root, &objectid);
 	if (ret)
-		goto fail_free;
-
-	ret = get_anon_bdev(&anon_dev);
-	if (ret < 0)
-		goto fail_free;
+		goto out_root_item;
 
 	/*
 	 * Don't create subvolume whose level is not zero. Or qgroup will be
@@ -583,9 +579,13 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
 	 */
 	if (btrfs_qgroup_level(objectid)) {
 		ret = -ENOSPC;
-		goto fail_free;
+		goto out_root_item;
 	}
 
+	ret = get_anon_bdev(&anon_dev);
+	if (ret < 0)
+		goto out_root_item;
+
 	btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP);
 	/*
 	 * The same as the snapshot creation, please see the comment
@@ -593,26 +593,26 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
 	 */
 	ret = btrfs_subvolume_reserve_metadata(root, &block_rsv, 8, false);
 	if (ret)
-		goto fail_free;
+		goto out_anon_dev;
 
 	trans = btrfs_start_transaction(root, 0);
 	if (IS_ERR(trans)) {
 		ret = PTR_ERR(trans);
 		btrfs_subvolume_release_metadata(root, &block_rsv);
-		goto fail_free;
+		goto out_anon_dev;
 	}
 	trans->block_rsv = &block_rsv;
 	trans->bytes_reserved = block_rsv.size;
 
 	ret = btrfs_qgroup_inherit(trans, 0, objectid, inherit);
 	if (ret)
-		goto fail;
+		goto out;
 
 	leaf = btrfs_alloc_tree_block(trans, root, 0, objectid, NULL, 0, 0, 0,
 				      BTRFS_NESTING_NORMAL);
 	if (IS_ERR(leaf)) {
 		ret = PTR_ERR(leaf);
-		goto fail;
+		goto out;
 	}
 
 	btrfs_mark_buffer_dirty(leaf);
@@ -667,7 +667,7 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
 		btrfs_tree_unlock(leaf);
 		btrfs_free_tree_block(trans, objectid, leaf, 0, 1);
 		free_extent_buffer(leaf);
-		goto fail;
+		goto out;
 	}
 
 	free_extent_buffer(leaf);
@@ -676,19 +676,18 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
 	key.offset = (u64)-1;
 	new_root = btrfs_get_new_fs_root(fs_info, objectid, anon_dev);
 	if (IS_ERR(new_root)) {
-		free_anon_bdev(anon_dev);
 		ret = PTR_ERR(new_root);
 		btrfs_abort_transaction(trans, ret);
-		goto fail;
+		goto out;
 	}
-	/* Freeing will be done in btrfs_put_root() of new_root */
+	/* anon_dev is owned by new_root now. */
 	anon_dev = 0;
 
 	ret = btrfs_record_root_in_trans(trans, new_root);
 	if (ret) {
 		btrfs_put_root(new_root);
 		btrfs_abort_transaction(trans, ret);
-		goto fail;
+		goto out;
 	}
 
 	ret = btrfs_create_subvol_root(trans, new_root, root, mnt_userns);
@@ -696,7 +695,7 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
 	if (ret) {
 		/* We potentially lose an unused inode item here */
 		btrfs_abort_transaction(trans, ret);
-		goto fail;
+		goto out;
 	}
 
 	/*
@@ -705,28 +704,28 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
 	ret = btrfs_set_inode_index(BTRFS_I(dir), &index);
 	if (ret) {
 		btrfs_abort_transaction(trans, ret);
-		goto fail;
+		goto out;
 	}
 
 	ret = btrfs_insert_dir_item(trans, name, namelen, BTRFS_I(dir), &key,
 				    BTRFS_FT_DIR, index);
 	if (ret) {
 		btrfs_abort_transaction(trans, ret);
-		goto fail;
+		goto out;
 	}
 
 	btrfs_i_size_write(BTRFS_I(dir), dir->i_size + namelen * 2);
 	ret = btrfs_update_inode(trans, root, BTRFS_I(dir));
 	if (ret) {
 		btrfs_abort_transaction(trans, ret);
-		goto fail;
+		goto out;
 	}
 
 	ret = btrfs_add_root_ref(trans, objectid, root->root_key.objectid,
 				 btrfs_ino(BTRFS_I(dir)), index, name, namelen);
 	if (ret) {
 		btrfs_abort_transaction(trans, ret);
-		goto fail;
+		goto out;
 	}
 
 	ret = btrfs_uuid_tree_add(trans, root_item->uuid,
@@ -734,8 +733,7 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
 	if (ret)
 		btrfs_abort_transaction(trans, ret);
 
-fail:
-	kfree(root_item);
+out:
 	trans->block_rsv = NULL;
 	trans->bytes_reserved = 0;
 	btrfs_subvolume_release_metadata(root, &block_rsv);
@@ -751,11 +749,10 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
 			return PTR_ERR(inode);
 		d_instantiate(dentry, inode);
 	}
-	return ret;
-
-fail_free:
+out_anon_dev:
 	if (anon_dev)
 		free_anon_bdev(anon_dev);
+out_root_item:
 	kfree(root_item);
 	return ret;
 }
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 04/16] btrfs: get rid of btrfs_add_nondir()
  2022-03-10  1:31 [PATCH v2 00/16] btrfs: inode creation cleanups and fixes Omar Sandoval
                   ` (2 preceding siblings ...)
  2022-03-10  1:31 ` [PATCH v2 03/16] btrfs: fix anon_dev leak in create_subvol() Omar Sandoval
@ 2022-03-10  1:31 ` Omar Sandoval
  2022-03-10  1:31 ` [PATCH v2 05/16] btrfs: remove unnecessary btrfs_i_size_write(0) calls Omar Sandoval
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 35+ messages in thread
From: Omar Sandoval @ 2022-03-10  1:31 UTC (permalink / raw)
  To: linux-btrfs; +Cc: kernel-team

From: Omar Sandoval <osandov@fb.com>

This is a trivial wrapper around btrfs_add_link(). The only thing it
does other than moving arguments around is translating a > 0 return
value to -EEXIST. As far as I can tell, btrfs_add_link() won't return >
0 (and if it did, the existing callsites in, e.g., btrfs_mkdir() would
be broken). The check itself dates back to commit 2c90e5d65842 ("Btrfs:
still corruption hunting"), so it's probably left over from debugging.
Let's just get rid of btrfs_add_nondir().

Reviewed-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Signed-off-by: Omar Sandoval <osandov@fb.com>
---
 fs/btrfs/inode.c | 33 +++++++++++----------------------
 1 file changed, 11 insertions(+), 22 deletions(-)

diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index be51630160f5..9c838bdd51cc 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -6355,18 +6355,6 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
 	return ret;
 }
 
-static int btrfs_add_nondir(struct btrfs_trans_handle *trans,
-			    struct btrfs_inode *dir, struct dentry *dentry,
-			    struct btrfs_inode *inode, int backref, u64 index)
-{
-	int err = btrfs_add_link(trans, dir, inode,
-				 dentry->d_name.name, dentry->d_name.len,
-				 backref, index);
-	if (err > 0)
-		err = -EEXIST;
-	return err;
-}
-
 static int btrfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
 		       struct dentry *dentry, umode_t mode, dev_t rdev)
 {
@@ -6413,8 +6401,8 @@ static int btrfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
 	if (err)
 		goto out_unlock;
 
-	err = btrfs_add_nondir(trans, BTRFS_I(dir), dentry, BTRFS_I(inode),
-			0, index);
+	err = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode),
+			     dentry->d_name.name, dentry->d_name.len, 0, index);
 	if (err)
 		goto out_unlock;
 
@@ -6481,8 +6469,8 @@ static int btrfs_create(struct user_namespace *mnt_userns, struct inode *dir,
 	if (err)
 		goto out_unlock;
 
-	err = btrfs_add_nondir(trans, BTRFS_I(dir), dentry, BTRFS_I(inode),
-			0, index);
+	err = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode),
+			     dentry->d_name.name, dentry->d_name.len, 0, index);
 	if (err)
 		goto out_unlock;
 
@@ -6541,8 +6529,8 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
 	ihold(inode);
 	set_bit(BTRFS_INODE_COPY_EVERYTHING, &BTRFS_I(inode)->runtime_flags);
 
-	err = btrfs_add_nondir(trans, BTRFS_I(dir), dentry, BTRFS_I(inode),
-			1, index);
+	err = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode),
+			     dentry->d_name.name, dentry->d_name.len, 1, index);
 
 	if (err) {
 		drop_inode = 1;
@@ -9324,8 +9312,8 @@ static int btrfs_whiteout_for_rename(struct btrfs_trans_handle *trans,
 	if (ret)
 		goto out;
 
-	ret = btrfs_add_nondir(trans, BTRFS_I(dir), dentry,
-				BTRFS_I(inode), 0, index);
+	ret = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode),
+			     dentry->d_name.name, dentry->d_name.len, 0, index);
 	if (ret)
 		goto out;
 
@@ -9863,8 +9851,9 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
 	 * elsewhere above.
 	 */
 	if (!err)
-		err = btrfs_add_nondir(trans, BTRFS_I(dir), dentry,
-				BTRFS_I(inode), 0, index);
+		err = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode),
+				     dentry->d_name.name, dentry->d_name.len, 0,
+				     index);
 	if (err)
 		goto out_unlock;
 
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 05/16] btrfs: remove unnecessary btrfs_i_size_write(0) calls
  2022-03-10  1:31 [PATCH v2 00/16] btrfs: inode creation cleanups and fixes Omar Sandoval
                   ` (3 preceding siblings ...)
  2022-03-10  1:31 ` [PATCH v2 04/16] btrfs: get rid of btrfs_add_nondir() Omar Sandoval
@ 2022-03-10  1:31 ` Omar Sandoval
  2022-03-10  1:31 ` [PATCH v2 06/16] btrfs: remove unnecessary inode_set_bytes(0) call Omar Sandoval
                   ` (11 subsequent siblings)
  16 siblings, 0 replies; 35+ messages in thread
From: Omar Sandoval @ 2022-03-10  1:31 UTC (permalink / raw)
  To: linux-btrfs; +Cc: kernel-team

From: Omar Sandoval <osandov@fb.com>

btrfs_new_inode() always returns an inode with i_size and disk_i_size
set to 0 (via inode_init_always() and btrfs_alloc_inode(),
respectively). Remove the unnecessary calls to btrfs_i_size_write() in
btrfs_mkdir() and btrfs_create_subvol_root().

Reviewed-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Signed-off-by: Omar Sandoval <osandov@fb.com>
---
 fs/btrfs/inode.c | 2 --
 1 file changed, 2 deletions(-)

diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 9c838bdd51cc..244e8d6ed5e4 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -6606,7 +6606,6 @@ static int btrfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
 	if (err)
 		goto out_fail;
 
-	btrfs_i_size_write(BTRFS_I(inode), 0);
 	err = btrfs_update_inode(trans, root, BTRFS_I(inode));
 	if (err)
 		goto out_fail;
@@ -8787,7 +8786,6 @@ int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
 	inode->i_fop = &btrfs_dir_file_operations;
 
 	set_nlink(inode, 1);
-	btrfs_i_size_write(BTRFS_I(inode), 0);
 	unlock_new_inode(inode);
 
 	err = btrfs_subvol_inherit_props(trans, new_root, parent_root);
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 06/16] btrfs: remove unnecessary inode_set_bytes(0) call
  2022-03-10  1:31 [PATCH v2 00/16] btrfs: inode creation cleanups and fixes Omar Sandoval
                   ` (4 preceding siblings ...)
  2022-03-10  1:31 ` [PATCH v2 05/16] btrfs: remove unnecessary btrfs_i_size_write(0) calls Omar Sandoval
@ 2022-03-10  1:31 ` Omar Sandoval
  2022-03-10  1:31 ` [PATCH v2 07/16] btrfs: remove unnecessary set_nlink() in btrfs_create_subvol_root() Omar Sandoval
                   ` (10 subsequent siblings)
  16 siblings, 0 replies; 35+ messages in thread
From: Omar Sandoval @ 2022-03-10  1:31 UTC (permalink / raw)
  To: linux-btrfs; +Cc: kernel-team

From: Omar Sandoval <osandov@fb.com>

new_inode() always returns an inode with i_blocks and i_bytes set to 0
(via inode_init_always()). Remove the unnecessary call to
inode_set_bytes() in btrfs_new_inode().

Reviewed-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Signed-off-by: Omar Sandoval <osandov@fb.com>
---
 fs/btrfs/inode.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 244e8d6ed5e4..b7d54b0b2fb5 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -6207,7 +6207,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 		goto fail_unlock;
 
 	inode_init_owner(mnt_userns, inode, dir, mode);
-	inode_set_bytes(inode, 0);
 
 	inode->i_mtime = current_time(inode);
 	inode->i_atime = inode->i_mtime;
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 07/16] btrfs: remove unnecessary set_nlink() in btrfs_create_subvol_root()
  2022-03-10  1:31 [PATCH v2 00/16] btrfs: inode creation cleanups and fixes Omar Sandoval
                   ` (5 preceding siblings ...)
  2022-03-10  1:31 ` [PATCH v2 06/16] btrfs: remove unnecessary inode_set_bytes(0) call Omar Sandoval
@ 2022-03-10  1:31 ` Omar Sandoval
  2022-03-10  1:31 ` [PATCH v2 08/16] btrfs: remove unused mnt_userns parameter from __btrfs_set_acl Omar Sandoval
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 35+ messages in thread
From: Omar Sandoval @ 2022-03-10  1:31 UTC (permalink / raw)
  To: linux-btrfs; +Cc: kernel-team

From: Omar Sandoval <osandov@fb.com>

btrfs_new_inode() already returns an inode with nlink set to 1 (via
inode_init_always()). Get rid of the unnecessary set.

Reviewed-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Signed-off-by: Omar Sandoval <osandov@fb.com>
---
 fs/btrfs/inode.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index b7d54b0b2fb5..a9dabe9e5500 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -8784,7 +8784,6 @@ int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
 	inode->i_op = &btrfs_dir_inode_operations;
 	inode->i_fop = &btrfs_dir_file_operations;
 
-	set_nlink(inode, 1);
 	unlock_new_inode(inode);
 
 	err = btrfs_subvol_inherit_props(trans, new_root, parent_root);
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 08/16] btrfs: remove unused mnt_userns parameter from __btrfs_set_acl
  2022-03-10  1:31 [PATCH v2 00/16] btrfs: inode creation cleanups and fixes Omar Sandoval
                   ` (6 preceding siblings ...)
  2022-03-10  1:31 ` [PATCH v2 07/16] btrfs: remove unnecessary set_nlink() in btrfs_create_subvol_root() Omar Sandoval
@ 2022-03-10  1:31 ` Omar Sandoval
  2022-03-10  1:31 ` [PATCH v2 09/16] btrfs: remove redundant name and name_len parameters to create_subvol Omar Sandoval
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 35+ messages in thread
From: Omar Sandoval @ 2022-03-10  1:31 UTC (permalink / raw)
  To: linux-btrfs; +Cc: kernel-team

From: Omar Sandoval <osandov@fb.com>

Commit 4a8b34afa9c9 ("btrfs: handle ACLs on idmapped mounts") added this
parameter but didn't use it. __btrfs_set_acl() is the low-level helper
that writes an ACL to disk. The higher-level btrfs_set_acl() is the one
that translates the ACL based on the user namespace.

Reviewed-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Signed-off-by: Omar Sandoval <osandov@fb.com>
---
 fs/btrfs/acl.c | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c
index 0a0d0eccee4e..a6909ec9bc38 100644
--- a/fs/btrfs/acl.c
+++ b/fs/btrfs/acl.c
@@ -56,7 +56,6 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu)
 }
 
 static int __btrfs_set_acl(struct btrfs_trans_handle *trans,
-			   struct user_namespace *mnt_userns,
 			   struct inode *inode, struct posix_acl *acl, int type)
 {
 	int ret, size = 0;
@@ -123,7 +122,7 @@ int btrfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
 		if (ret)
 			return ret;
 	}
-	ret = __btrfs_set_acl(NULL, mnt_userns, inode, acl, type);
+	ret = __btrfs_set_acl(NULL, inode, acl, type);
 	if (ret)
 		inode->i_mode = old_mode;
 	return ret;
@@ -144,14 +143,14 @@ int btrfs_init_acl(struct btrfs_trans_handle *trans,
 		return ret;
 
 	if (default_acl) {
-		ret = __btrfs_set_acl(trans, &init_user_ns, inode, default_acl,
+		ret = __btrfs_set_acl(trans, inode, default_acl,
 				      ACL_TYPE_DEFAULT);
 		posix_acl_release(default_acl);
 	}
 
 	if (acl) {
 		if (!ret)
-			ret = __btrfs_set_acl(trans, &init_user_ns, inode, acl,
+			ret = __btrfs_set_acl(trans, inode, acl,
 					      ACL_TYPE_ACCESS);
 		posix_acl_release(acl);
 	}
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 09/16] btrfs: remove redundant name and name_len parameters to create_subvol
  2022-03-10  1:31 [PATCH v2 00/16] btrfs: inode creation cleanups and fixes Omar Sandoval
                   ` (7 preceding siblings ...)
  2022-03-10  1:31 ` [PATCH v2 08/16] btrfs: remove unused mnt_userns parameter from __btrfs_set_acl Omar Sandoval
@ 2022-03-10  1:31 ` Omar Sandoval
  2022-03-10  1:31 ` [PATCH v2 10/16] btrfs: don't pass parent objectid to btrfs_new_inode() explicitly Omar Sandoval
                   ` (7 subsequent siblings)
  16 siblings, 0 replies; 35+ messages in thread
From: Omar Sandoval @ 2022-03-10  1:31 UTC (permalink / raw)
  To: linux-btrfs; +Cc: kernel-team

From: Omar Sandoval <osandov@fb.com>

The passed dentry already contains the name.

Reviewed-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Signed-off-by: Omar Sandoval <osandov@fb.com>
---
 fs/btrfs/ioctl.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index d04870ea6a21..891352fd6d0f 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -546,9 +546,10 @@ int __pure btrfs_is_empty_uuid(u8 *uuid)
 
 static noinline int create_subvol(struct user_namespace *mnt_userns,
 				  struct inode *dir, struct dentry *dentry,
-				  const char *name, int namelen,
 				  struct btrfs_qgroup_inherit *inherit)
 {
+	const char *name = dentry->d_name.name;
+	int namelen = dentry->d_name.len;
 	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
 	struct btrfs_trans_handle *trans;
 	struct btrfs_key key;
@@ -980,7 +981,7 @@ static noinline int btrfs_mksubvol(const struct path *parent,
 	if (snap_src)
 		error = create_snapshot(snap_src, dir, dentry, readonly, inherit);
 	else
-		error = create_subvol(mnt_userns, dir, dentry, name, namelen, inherit);
+		error = create_subvol(mnt_userns, dir, dentry, inherit);
 
 	if (!error)
 		fsnotify_mkdir(dir, dentry);
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 10/16] btrfs: don't pass parent objectid to btrfs_new_inode() explicitly
  2022-03-10  1:31 [PATCH v2 00/16] btrfs: inode creation cleanups and fixes Omar Sandoval
                   ` (8 preceding siblings ...)
  2022-03-10  1:31 ` [PATCH v2 09/16] btrfs: remove redundant name and name_len parameters to create_subvol Omar Sandoval
@ 2022-03-10  1:31 ` Omar Sandoval
  2022-03-10  1:31 ` [PATCH v2 11/16] btrfs: move btrfs_get_free_objectid() call into btrfs_new_inode() Omar Sandoval
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 35+ messages in thread
From: Omar Sandoval @ 2022-03-10  1:31 UTC (permalink / raw)
  To: linux-btrfs; +Cc: kernel-team

From: Omar Sandoval <osandov@fb.com>

For everything other than a subvolume root inode, we get the parent
objectid from the parent directory. For the subvolume root inode, the
parent objectid is the same as the inode's objectid. We can find this
within btrfs_new_inode() instead of passing it.

Reviewed-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Signed-off-by: Omar Sandoval <osandov@fb.com>
---
 fs/btrfs/inode.c | 21 +++++++++++----------
 1 file changed, 11 insertions(+), 10 deletions(-)

diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index a9dabe9e5500..9c845c67421a 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -6095,8 +6095,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 				     struct user_namespace *mnt_userns,
 				     struct inode *dir,
 				     const char *name, int name_len,
-				     u64 ref_objectid, u64 objectid,
-				     umode_t mode, u64 *index)
+				     u64 objectid, umode_t mode, u64 *index)
 {
 	struct btrfs_fs_info *fs_info = root->fs_info;
 	struct inode *inode;
@@ -6182,7 +6181,10 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 		 */
 		key[1].objectid = objectid;
 		key[1].type = BTRFS_INODE_REF_KEY;
-		key[1].offset = ref_objectid;
+		if (dir)
+			key[1].offset = btrfs_ino(BTRFS_I(dir));
+		else
+			key[1].offset = objectid;
 
 		sizes[1] = name_len + sizeof(*ref);
 	}
@@ -6380,7 +6382,7 @@ static int btrfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
 
 	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
 			dentry->d_name.name, dentry->d_name.len,
-			btrfs_ino(BTRFS_I(dir)), objectid, mode, &index);
+			objectid, mode, &index);
 	if (IS_ERR(inode)) {
 		err = PTR_ERR(inode);
 		inode = NULL;
@@ -6444,7 +6446,7 @@ static int btrfs_create(struct user_namespace *mnt_userns, struct inode *dir,
 
 	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
 			dentry->d_name.name, dentry->d_name.len,
-			btrfs_ino(BTRFS_I(dir)), objectid, mode, &index);
+			objectid, mode, &index);
 	if (IS_ERR(inode)) {
 		err = PTR_ERR(inode);
 		inode = NULL;
@@ -6589,7 +6591,7 @@ static int btrfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
 
 	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
 			dentry->d_name.name, dentry->d_name.len,
-			btrfs_ino(BTRFS_I(dir)), objectid,
+			objectid,
 			S_IFDIR | mode, &index);
 	if (IS_ERR(inode)) {
 		err = PTR_ERR(inode);
@@ -8776,7 +8778,7 @@ int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
 		return err;
 
 	inode = btrfs_new_inode(trans, new_root, mnt_userns, NULL, "..", 2,
-				ino, ino,
+				ino,
 				S_IFDIR | (~current_umask() & S_IRWXUGO),
 				&index);
 	if (IS_ERR(inode))
@@ -9289,7 +9291,6 @@ static int btrfs_whiteout_for_rename(struct btrfs_trans_handle *trans,
 	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
 				dentry->d_name.name,
 				dentry->d_name.len,
-				btrfs_ino(BTRFS_I(dir)),
 				objectid,
 				S_IFCHR | WHITEOUT_MODE,
 				&index);
@@ -9783,7 +9784,7 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
 
 	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
 				dentry->d_name.name, dentry->d_name.len,
-				btrfs_ino(BTRFS_I(dir)), objectid,
+				objectid,
 				S_IFLNK | S_IRWXUGO, &index);
 	if (IS_ERR(inode)) {
 		err = PTR_ERR(inode);
@@ -10134,7 +10135,7 @@ static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
 		goto out;
 
 	inode = btrfs_new_inode(trans, root, mnt_userns, dir, NULL, 0,
-			btrfs_ino(BTRFS_I(dir)), objectid, mode, &index);
+			objectid, mode, &index);
 	if (IS_ERR(inode)) {
 		ret = PTR_ERR(inode);
 		inode = NULL;
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 11/16] btrfs: move btrfs_get_free_objectid() call into btrfs_new_inode()
  2022-03-10  1:31 [PATCH v2 00/16] btrfs: inode creation cleanups and fixes Omar Sandoval
                   ` (9 preceding siblings ...)
  2022-03-10  1:31 ` [PATCH v2 10/16] btrfs: don't pass parent objectid to btrfs_new_inode() explicitly Omar Sandoval
@ 2022-03-10  1:31 ` Omar Sandoval
  2022-03-10  1:31 ` [PATCH v2 12/16] btrfs: set inode flags earlier in btrfs_new_inode() Omar Sandoval
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 35+ messages in thread
From: Omar Sandoval @ 2022-03-10  1:31 UTC (permalink / raw)
  To: linux-btrfs; +Cc: kernel-team

From: Omar Sandoval <osandov@fb.com>

Every call of btrfs_new_inode() is immediately preceded by a call to
btrfs_get_free_objectid(). Since getting an inode number is part of
creating a new inode, this is better off being moved into
btrfs_new_inode(). While we're here, get rid of the comment about
reclaiming inode numbers, since we only did that when using the ino
cache, which was removed by commit 5297199a8bca ("btrfs: remove inode
number cache feature").

Reviewed-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Signed-off-by: Omar Sandoval <osandov@fb.com>
---
 fs/btrfs/inode.c | 58 +++++++++---------------------------------------
 1 file changed, 11 insertions(+), 47 deletions(-)

diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 9c845c67421a..289bb5176e09 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -6095,13 +6095,14 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 				     struct user_namespace *mnt_userns,
 				     struct inode *dir,
 				     const char *name, int name_len,
-				     u64 objectid, umode_t mode, u64 *index)
+				     umode_t mode, u64 *index)
 {
 	struct btrfs_fs_info *fs_info = root->fs_info;
 	struct inode *inode;
 	struct btrfs_inode_item *inode_item;
 	struct btrfs_key *location;
 	struct btrfs_path *path;
+	u64 objectid;
 	struct btrfs_inode_ref *ref;
 	struct btrfs_key key[2];
 	u32 sizes[2];
@@ -6129,10 +6130,12 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 	if (!name)
 		set_nlink(inode, 0);
 
-	/*
-	 * we have to initialize this early, so we can reclaim the inode
-	 * number if we fail afterwards in this function.
-	 */
+	ret = btrfs_get_free_objectid(root, &objectid);
+	if (ret) {
+		btrfs_free_path(path);
+		iput(inode);
+		return ERR_PTR(ret);
+	}
 	inode->i_ino = objectid;
 
 	if (dir && name) {
@@ -6364,7 +6367,6 @@ static int btrfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
 	struct btrfs_root *root = BTRFS_I(dir)->root;
 	struct inode *inode = NULL;
 	int err;
-	u64 objectid;
 	u64 index = 0;
 
 	/*
@@ -6376,13 +6378,9 @@ static int btrfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
 	if (IS_ERR(trans))
 		return PTR_ERR(trans);
 
-	err = btrfs_get_free_objectid(root, &objectid);
-	if (err)
-		goto out_unlock;
-
 	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
 			dentry->d_name.name, dentry->d_name.len,
-			objectid, mode, &index);
+			mode, &index);
 	if (IS_ERR(inode)) {
 		err = PTR_ERR(inode);
 		inode = NULL;
@@ -6428,7 +6426,6 @@ static int btrfs_create(struct user_namespace *mnt_userns, struct inode *dir,
 	struct btrfs_root *root = BTRFS_I(dir)->root;
 	struct inode *inode = NULL;
 	int err;
-	u64 objectid;
 	u64 index = 0;
 
 	/*
@@ -6440,13 +6437,9 @@ static int btrfs_create(struct user_namespace *mnt_userns, struct inode *dir,
 	if (IS_ERR(trans))
 		return PTR_ERR(trans);
 
-	err = btrfs_get_free_objectid(root, &objectid);
-	if (err)
-		goto out_unlock;
-
 	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
 			dentry->d_name.name, dentry->d_name.len,
-			objectid, mode, &index);
+			mode, &index);
 	if (IS_ERR(inode)) {
 		err = PTR_ERR(inode);
 		inode = NULL;
@@ -6573,7 +6566,6 @@ static int btrfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
 	struct btrfs_trans_handle *trans;
 	struct btrfs_root *root = BTRFS_I(dir)->root;
 	int err = 0;
-	u64 objectid = 0;
 	u64 index = 0;
 
 	/*
@@ -6585,13 +6577,8 @@ static int btrfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
 	if (IS_ERR(trans))
 		return PTR_ERR(trans);
 
-	err = btrfs_get_free_objectid(root, &objectid);
-	if (err)
-		goto out_fail;
-
 	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
 			dentry->d_name.name, dentry->d_name.len,
-			objectid,
 			S_IFDIR | mode, &index);
 	if (IS_ERR(inode)) {
 		err = PTR_ERR(inode);
@@ -8771,14 +8758,8 @@ int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
 	struct inode *inode;
 	int err;
 	u64 index = 0;
-	u64 ino;
-
-	err = btrfs_get_free_objectid(new_root, &ino);
-	if (err < 0)
-		return err;
 
 	inode = btrfs_new_inode(trans, new_root, mnt_userns, NULL, "..", 2,
-				ino,
 				S_IFDIR | (~current_umask() & S_IRWXUGO),
 				&index);
 	if (IS_ERR(inode))
@@ -9281,17 +9262,11 @@ static int btrfs_whiteout_for_rename(struct btrfs_trans_handle *trans,
 {
 	int ret;
 	struct inode *inode;
-	u64 objectid;
 	u64 index;
 
-	ret = btrfs_get_free_objectid(root, &objectid);
-	if (ret)
-		return ret;
-
 	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
 				dentry->d_name.name,
 				dentry->d_name.len,
-				objectid,
 				S_IFCHR | WHITEOUT_MODE,
 				&index);
 
@@ -9755,7 +9730,6 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
 	struct btrfs_key key;
 	struct inode *inode = NULL;
 	int err;
-	u64 objectid;
 	u64 index = 0;
 	int name_len;
 	int datasize;
@@ -9778,13 +9752,8 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
 	if (IS_ERR(trans))
 		return PTR_ERR(trans);
 
-	err = btrfs_get_free_objectid(root, &objectid);
-	if (err)
-		goto out_unlock;
-
 	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
 				dentry->d_name.name, dentry->d_name.len,
-				objectid,
 				S_IFLNK | S_IRWXUGO, &index);
 	if (IS_ERR(inode)) {
 		err = PTR_ERR(inode);
@@ -10119,7 +10088,6 @@ static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
 	struct btrfs_trans_handle *trans;
 	struct btrfs_root *root = BTRFS_I(dir)->root;
 	struct inode *inode = NULL;
-	u64 objectid;
 	u64 index;
 	int ret = 0;
 
@@ -10130,12 +10098,8 @@ static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
 	if (IS_ERR(trans))
 		return PTR_ERR(trans);
 
-	ret = btrfs_get_free_objectid(root, &objectid);
-	if (ret)
-		goto out;
-
 	inode = btrfs_new_inode(trans, root, mnt_userns, dir, NULL, 0,
-			objectid, mode, &index);
+			mode, &index);
 	if (IS_ERR(inode)) {
 		ret = PTR_ERR(inode);
 		inode = NULL;
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 12/16] btrfs: set inode flags earlier in btrfs_new_inode()
  2022-03-10  1:31 [PATCH v2 00/16] btrfs: inode creation cleanups and fixes Omar Sandoval
                   ` (10 preceding siblings ...)
  2022-03-10  1:31 ` [PATCH v2 11/16] btrfs: move btrfs_get_free_objectid() call into btrfs_new_inode() Omar Sandoval
@ 2022-03-10  1:31 ` Omar Sandoval
  2022-03-10  1:31 ` [PATCH v2 13/16] btrfs: allocate inode outside of btrfs_new_inode() Omar Sandoval
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 35+ messages in thread
From: Omar Sandoval @ 2022-03-10  1:31 UTC (permalink / raw)
  To: linux-btrfs; +Cc: kernel-team

From: Omar Sandoval <osandov@fb.com>

btrfs_new_inode() inherits the inode flags from the parent directory and
the mount options _after_ we fill the inode item. This works because all
of the callers of btrfs_new_inode() make further changes to the inode
and then call btrfs_update_inode(). It'd be better to fully initialize
the inode once to avoid the extra update, so as a first step, set the
inode flags _before_ filling the inode item.

Reviewed-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
Signed-off-by: Omar Sandoval <osandov@fb.com>
---
 fs/btrfs/inode.c | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 289bb5176e09..c47bdada2440 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -6161,6 +6161,16 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 	BTRFS_I(inode)->generation = trans->transid;
 	inode->i_generation = BTRFS_I(inode)->generation;
 
+	btrfs_inherit_iflags(inode, dir);
+
+	if (S_ISREG(mode)) {
+		if (btrfs_test_opt(fs_info, NODATASUM))
+			BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM;
+		if (btrfs_test_opt(fs_info, NODATACOW))
+			BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW |
+				BTRFS_INODE_NODATASUM;
+	}
+
 	/*
 	 * We could have gotten an inode number from somebody who was fsynced
 	 * and then removed in this same transaction, so let's just set full
@@ -6236,16 +6246,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 	btrfs_mark_buffer_dirty(path->nodes[0]);
 	btrfs_free_path(path);
 
-	btrfs_inherit_iflags(inode, dir);
-
-	if (S_ISREG(mode)) {
-		if (btrfs_test_opt(fs_info, NODATASUM))
-			BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM;
-		if (btrfs_test_opt(fs_info, NODATACOW))
-			BTRFS_I(inode)->flags |= BTRFS_INODE_NODATACOW |
-				BTRFS_INODE_NODATASUM;
-	}
-
 	inode_tree_add(inode);
 
 	trace_btrfs_inode_new(inode);
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 13/16] btrfs: allocate inode outside of btrfs_new_inode()
  2022-03-10  1:31 [PATCH v2 00/16] btrfs: inode creation cleanups and fixes Omar Sandoval
                   ` (11 preceding siblings ...)
  2022-03-10  1:31 ` [PATCH v2 12/16] btrfs: set inode flags earlier in btrfs_new_inode() Omar Sandoval
@ 2022-03-10  1:31 ` Omar Sandoval
  2022-03-11 17:11   ` Sweet Tea Dorminy
  2022-03-14 23:33   ` Filipe Manana
  2022-03-10  1:31 ` [PATCH v2 14/16] btrfs: factor out common part of btrfs_{mknod,create,mkdir}() Omar Sandoval
                   ` (3 subsequent siblings)
  16 siblings, 2 replies; 35+ messages in thread
From: Omar Sandoval @ 2022-03-10  1:31 UTC (permalink / raw)
  To: linux-btrfs; +Cc: kernel-team

From: Omar Sandoval <osandov@fb.com>

Instead of calling new_inode() and inode_init_owner() inside of
btrfs_new_inode(), do it in the callers. This allows us to pass in just
the inode instead of the mnt_userns and mode and removes the need for
memalloc_nofs_{save,restores}() since we do it before starting a
transaction. This also paves the way for some more cleanups in later
patches.

This also removes the comments about Smack checking i_op, which are no
longer true since commit 5d6c31910bc0 ("xattr: Add
__vfs_{get,set,remove}xattr helpers"). Now it checks inode->i_opflags &
IOP_XATTR, which is set based on sb->s_xattr.

Signed-off-by: Omar Sandoval <osandov@fb.com>
---
 fs/btrfs/ctree.h |   5 +-
 fs/btrfs/inode.c | 284 +++++++++++++++++++++++++----------------------
 fs/btrfs/ioctl.c |  22 ++--
 3 files changed, 167 insertions(+), 144 deletions(-)

diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 4db17bd05a21..f39730420e8a 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -3254,10 +3254,11 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, long nr,
 int btrfs_set_extent_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
 			      unsigned int extra_bits,
 			      struct extent_state **cached_state);
+struct inode *btrfs_new_subvol_inode(struct user_namespace *mnt_userns,
+				     struct inode *dir);
 int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
-			     struct btrfs_root *new_root,
 			     struct btrfs_root *parent_root,
-			     struct user_namespace *mnt_userns);
+			     struct inode *inode);
  void btrfs_set_delalloc_extent(struct inode *inode, struct extent_state *state,
 			       unsigned *bits);
 void btrfs_clear_delalloc_extent(struct inode *inode,
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index c47bdada2440..ff780256c936 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -6090,15 +6090,12 @@ static void btrfs_inherit_iflags(struct inode *inode, struct inode *dir)
 	btrfs_sync_inode_flags_to_i_flags(inode);
 }
 
-static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
-				     struct btrfs_root *root,
-				     struct user_namespace *mnt_userns,
-				     struct inode *dir,
-				     const char *name, int name_len,
-				     umode_t mode, u64 *index)
+static int btrfs_new_inode(struct btrfs_trans_handle *trans,
+			   struct btrfs_root *root, struct inode *inode,
+			   struct inode *dir, const char *name, int name_len,
+			   u64 *index)
 {
 	struct btrfs_fs_info *fs_info = root->fs_info;
-	struct inode *inode;
 	struct btrfs_inode_item *inode_item;
 	struct btrfs_key *location;
 	struct btrfs_path *path;
@@ -6108,20 +6105,11 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 	u32 sizes[2];
 	struct btrfs_item_batch batch;
 	unsigned long ptr;
-	unsigned int nofs_flag;
 	int ret;
 
 	path = btrfs_alloc_path();
 	if (!path)
-		return ERR_PTR(-ENOMEM);
-
-	nofs_flag = memalloc_nofs_save();
-	inode = new_inode(fs_info->sb);
-	memalloc_nofs_restore(nofs_flag);
-	if (!inode) {
-		btrfs_free_path(path);
-		return ERR_PTR(-ENOMEM);
-	}
+		return -ENOMEM;
 
 	/*
 	 * O_TMPFILE, set link count to 0, so that after this point,
@@ -6133,8 +6121,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 	ret = btrfs_get_free_objectid(root, &objectid);
 	if (ret) {
 		btrfs_free_path(path);
-		iput(inode);
-		return ERR_PTR(ret);
+		return ret;
 	}
 	inode->i_ino = objectid;
 
@@ -6144,8 +6131,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 		ret = btrfs_set_inode_index(BTRFS_I(dir), index);
 		if (ret) {
 			btrfs_free_path(path);
-			iput(inode);
-			return ERR_PTR(ret);
+			return ret;
 		}
 	} else if (dir) {
 		*index = 0;
@@ -6163,7 +6149,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 
 	btrfs_inherit_iflags(inode, dir);
 
-	if (S_ISREG(mode)) {
+	if (S_ISREG(inode->i_mode)) {
 		if (btrfs_test_opt(fs_info, NODATASUM))
 			BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM;
 		if (btrfs_test_opt(fs_info, NODATACOW))
@@ -6208,10 +6194,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 	location->type = BTRFS_INODE_ITEM_KEY;
 
 	ret = btrfs_insert_inode_locked(inode);
-	if (ret < 0) {
-		iput(inode);
+	if (ret < 0)
 		goto fail;
-	}
 
 	batch.keys = &key[0];
 	batch.data_sizes = &sizes[0];
@@ -6221,8 +6205,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 	if (ret != 0)
 		goto fail_unlock;
 
-	inode_init_owner(mnt_userns, inode, dir, mode);
-
 	inode->i_mtime = current_time(inode);
 	inode->i_atime = inode->i_mtime;
 	inode->i_ctime = inode->i_mtime;
@@ -6259,15 +6241,20 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
 			  "error inheriting props for ino %llu (root %llu): %d",
 			btrfs_ino(BTRFS_I(inode)), root->root_key.objectid, ret);
 
-	return inode;
+	return 0;
 
 fail_unlock:
+	/*
+	 * discard_new_inode() calls iput(), but the caller owns the reference
+	 * to the inode.
+	 */
+	ihold(inode);
 	discard_new_inode(inode);
 fail:
 	if (dir && name)
 		BTRFS_I(dir)->index_cnt--;
 	btrfs_free_path(path);
-	return ERR_PTR(ret);
+	return ret;
 }
 
 /*
@@ -6365,37 +6352,36 @@ static int btrfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
 	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
 	struct btrfs_trans_handle *trans;
 	struct btrfs_root *root = BTRFS_I(dir)->root;
-	struct inode *inode = NULL;
+	struct inode *inode;
 	int err;
 	u64 index = 0;
 
+	inode = new_inode(dir->i_sb);
+	if (!inode)
+		return -ENOMEM;
+	inode_init_owner(mnt_userns, inode, dir, mode);
+	inode->i_op = &btrfs_special_inode_operations;
+	init_special_inode(inode, inode->i_mode, rdev);
+
 	/*
 	 * 2 for inode item and ref
 	 * 2 for dir items
 	 * 1 for xattr if selinux is on
 	 */
 	trans = btrfs_start_transaction(root, 5);
-	if (IS_ERR(trans))
+	if (IS_ERR(trans)) {
+		iput(inode);
 		return PTR_ERR(trans);
+	}
 
-	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
-			dentry->d_name.name, dentry->d_name.len,
-			mode, &index);
-	if (IS_ERR(inode)) {
-		err = PTR_ERR(inode);
+	err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
+			      dentry->d_name.len, &index);
+	if (err) {
+		iput(inode);
 		inode = NULL;
 		goto out_unlock;
 	}
 
-	/*
-	* If the active LSM wants to access the inode during
-	* d_instantiate it needs these. Smack checks to see
-	* if the filesystem supports xattrs by looking at the
-	* ops vector.
-	*/
-	inode->i_op = &btrfs_special_inode_operations;
-	init_special_inode(inode, inode->i_mode, rdev);
-
 	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
 	if (err)
 		goto out_unlock;
@@ -6424,36 +6410,36 @@ static int btrfs_create(struct user_namespace *mnt_userns, struct inode *dir,
 	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
 	struct btrfs_trans_handle *trans;
 	struct btrfs_root *root = BTRFS_I(dir)->root;
-	struct inode *inode = NULL;
+	struct inode *inode;
 	int err;
 	u64 index = 0;
 
+	inode = new_inode(dir->i_sb);
+	if (!inode)
+		return -ENOMEM;
+	inode_init_owner(mnt_userns, inode, dir, mode);
+	inode->i_fop = &btrfs_file_operations;
+	inode->i_op = &btrfs_file_inode_operations;
+	inode->i_mapping->a_ops = &btrfs_aops;
+
 	/*
 	 * 2 for inode item and ref
 	 * 2 for dir items
 	 * 1 for xattr if selinux is on
 	 */
 	trans = btrfs_start_transaction(root, 5);
-	if (IS_ERR(trans))
+	if (IS_ERR(trans)) {
+		iput(inode);
 		return PTR_ERR(trans);
+	}
 
-	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
-			dentry->d_name.name, dentry->d_name.len,
-			mode, &index);
-	if (IS_ERR(inode)) {
-		err = PTR_ERR(inode);
+	err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
+			      dentry->d_name.len, &index);
+	if (err) {
+		iput(inode);
 		inode = NULL;
 		goto out_unlock;
 	}
-	/*
-	* If the active LSM wants to access the inode during
-	* d_instantiate it needs these. Smack checks to see
-	* if the filesystem supports xattrs by looking at the
-	* ops vector.
-	*/
-	inode->i_fop = &btrfs_file_operations;
-	inode->i_op = &btrfs_file_inode_operations;
-	inode->i_mapping->a_ops = &btrfs_aops;
 
 	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
 	if (err)
@@ -6562,34 +6548,38 @@ static int btrfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
 		       struct dentry *dentry, umode_t mode)
 {
 	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
-	struct inode *inode = NULL;
+	struct inode *inode;
 	struct btrfs_trans_handle *trans;
 	struct btrfs_root *root = BTRFS_I(dir)->root;
-	int err = 0;
+	int err;
 	u64 index = 0;
 
+	inode = new_inode(dir->i_sb);
+	if (!inode)
+		return -ENOMEM;
+	inode_init_owner(mnt_userns, inode, dir, S_IFDIR | mode);
+	inode->i_op = &btrfs_dir_inode_operations;
+	inode->i_fop = &btrfs_dir_file_operations;
+
 	/*
 	 * 2 items for inode and ref
 	 * 2 items for dir items
 	 * 1 for xattr if selinux is on
 	 */
 	trans = btrfs_start_transaction(root, 5);
-	if (IS_ERR(trans))
+	if (IS_ERR(trans)) {
+		iput(inode);
 		return PTR_ERR(trans);
+	}
 
-	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
-			dentry->d_name.name, dentry->d_name.len,
-			S_IFDIR | mode, &index);
-	if (IS_ERR(inode)) {
-		err = PTR_ERR(inode);
+	err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
+			      dentry->d_name.len, &index);
+	if (err) {
+		iput(inode);
 		inode = NULL;
 		goto out_fail;
 	}
 
-	/* these must be set before we unlock the inode */
-	inode->i_op = &btrfs_dir_inode_operations;
-	inode->i_fop = &btrfs_dir_file_operations;
-
 	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
 	if (err)
 		goto out_fail;
@@ -8747,25 +8737,39 @@ static int btrfs_truncate(struct inode *inode, bool skip_writeback)
 	return ret;
 }
 
+struct inode *btrfs_new_subvol_inode(struct user_namespace *mnt_userns,
+				     struct inode *dir)
+{
+	struct inode *inode;
+
+	inode = new_inode(dir->i_sb);
+	if (inode) {
+		/*
+		 * Subvolumes don't inherit the sgid bit or the parent's gid if
+		 * the parent's sgid bit is set. This is probably a bug.
+		 */
+		inode_init_owner(mnt_userns, inode, NULL,
+				 S_IFDIR | (~current_umask() & S_IRWXUGO));
+		inode->i_op = &btrfs_dir_inode_operations;
+		inode->i_fop = &btrfs_dir_file_operations;
+	}
+	return inode;
+}
+
 /*
  * create a new subvolume directory/inode (helper for the ioctl).
  */
 int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
-			     struct btrfs_root *new_root,
 			     struct btrfs_root *parent_root,
-			     struct user_namespace *mnt_userns)
+			     struct inode *inode)
 {
-	struct inode *inode;
+	struct btrfs_root *new_root = BTRFS_I(inode)->root;
 	int err;
 	u64 index = 0;
 
-	inode = btrfs_new_inode(trans, new_root, mnt_userns, NULL, "..", 2,
-				S_IFDIR | (~current_umask() & S_IRWXUGO),
-				&index);
-	if (IS_ERR(inode))
-		return PTR_ERR(inode);
-	inode->i_op = &btrfs_dir_inode_operations;
-	inode->i_fop = &btrfs_dir_file_operations;
+	err = btrfs_new_inode(trans, new_root, inode, NULL, "..", 2, &index);
+	if (err)
+		return err;
 
 	unlock_new_inode(inode);
 
@@ -8776,8 +8780,6 @@ int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
 			  new_root->root_key.objectid, err);
 
 	err = btrfs_update_inode(trans, new_root, BTRFS_I(inode));
-
-	iput(inode);
 	return err;
 }
 
@@ -9254,31 +9256,36 @@ static int btrfs_rename_exchange(struct inode *old_dir,
 	return ret;
 }
 
+static struct inode *new_whiteout_inode(struct user_namespace *mnt_userns,
+					struct inode *dir)
+{
+	struct inode *inode;
+
+	inode = new_inode(dir->i_sb);
+	if (inode) {
+		inode_init_owner(mnt_userns, inode, dir,
+				 S_IFCHR | WHITEOUT_MODE);
+		inode->i_op = &btrfs_special_inode_operations;
+		init_special_inode(inode, inode->i_mode, WHITEOUT_DEV);
+	}
+	return inode;
+}
+
 static int btrfs_whiteout_for_rename(struct btrfs_trans_handle *trans,
 				     struct btrfs_root *root,
-				     struct user_namespace *mnt_userns,
-				     struct inode *dir,
+				     struct inode *inode, struct inode *dir,
 				     struct dentry *dentry)
 {
 	int ret;
-	struct inode *inode;
 	u64 index;
 
-	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
-				dentry->d_name.name,
-				dentry->d_name.len,
-				S_IFCHR | WHITEOUT_MODE,
-				&index);
-
-	if (IS_ERR(inode)) {
-		ret = PTR_ERR(inode);
+	ret = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
+			      dentry->d_name.len, &index);
+	if (ret) {
+		iput(inode);
 		return ret;
 	}
 
-	inode->i_op = &btrfs_special_inode_operations;
-	init_special_inode(inode, inode->i_mode,
-		WHITEOUT_DEV);
-
 	ret = btrfs_init_inode_security(trans, inode, dir,
 				&dentry->d_name);
 	if (ret)
@@ -9305,6 +9312,7 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
 			unsigned int flags)
 {
 	struct btrfs_fs_info *fs_info = btrfs_sb(old_dir->i_sb);
+	struct inode *whiteout_inode;
 	struct btrfs_trans_handle *trans;
 	unsigned int trans_num_items;
 	struct btrfs_root *root = BTRFS_I(old_dir)->root;
@@ -9359,6 +9367,12 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
 	if (new_inode && S_ISREG(old_inode->i_mode) && new_inode->i_size)
 		filemap_flush(old_inode->i_mapping);
 
+	if (flags & RENAME_WHITEOUT) {
+		whiteout_inode = new_whiteout_inode(mnt_userns, old_dir);
+		if (!whiteout_inode)
+			return -ENOMEM;
+	}
+
 	if (old_ino == BTRFS_FIRST_FREE_OBJECTID) {
 		/* close the racy window with snapshot create/destroy ioctl */
 		down_read(&fs_info->subvol_sem);
@@ -9495,9 +9509,9 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
 				   rename_ctx.index, new_dentry->d_parent);
 
 	if (flags & RENAME_WHITEOUT) {
-		ret = btrfs_whiteout_for_rename(trans, root, mnt_userns,
+		ret = btrfs_whiteout_for_rename(trans, root, whiteout_inode,
 						old_dir, old_dentry);
-
+		whiteout_inode = NULL;
 		if (ret) {
 			btrfs_abort_transaction(trans, ret);
 			goto out_fail;
@@ -9509,7 +9523,8 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
 out_notrans:
 	if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
 		up_read(&fs_info->subvol_sem);
-
+	if (flags & RENAME_WHITEOUT)
+		iput(whiteout_inode);
 	return ret;
 }
 
@@ -9728,7 +9743,7 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
 	struct btrfs_root *root = BTRFS_I(dir)->root;
 	struct btrfs_path *path;
 	struct btrfs_key key;
-	struct inode *inode = NULL;
+	struct inode *inode;
 	int err;
 	u64 index = 0;
 	int name_len;
@@ -9741,6 +9756,14 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
 	if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(fs_info))
 		return -ENAMETOOLONG;
 
+	inode = new_inode(dir->i_sb);
+	if (!inode)
+		return -ENOMEM;
+	inode_init_owner(mnt_userns, inode, dir, S_IFLNK | S_IRWXUGO);
+	inode->i_op = &btrfs_symlink_inode_operations;
+	inode_nohighmem(inode);
+	inode->i_mapping->a_ops = &btrfs_aops;
+
 	/*
 	 * 2 items for inode item and ref
 	 * 2 items for dir items
@@ -9749,28 +9772,19 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
 	 * 1 item for xattr if selinux is on
 	 */
 	trans = btrfs_start_transaction(root, 7);
-	if (IS_ERR(trans))
+	if (IS_ERR(trans)) {
+		iput(inode);
 		return PTR_ERR(trans);
+	}
 
-	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
-				dentry->d_name.name, dentry->d_name.len,
-				S_IFLNK | S_IRWXUGO, &index);
-	if (IS_ERR(inode)) {
-		err = PTR_ERR(inode);
+	err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
+			      dentry->d_name.len, &index);
+	if (err) {
+		iput(inode);
 		inode = NULL;
 		goto out_unlock;
 	}
 
-	/*
-	* If the active LSM wants to access the inode during
-	* d_instantiate it needs these. Smack checks to see
-	* if the filesystem supports xattrs by looking at the
-	* ops vector.
-	*/
-	inode->i_fop = &btrfs_file_operations;
-	inode->i_op = &btrfs_file_inode_operations;
-	inode->i_mapping->a_ops = &btrfs_aops;
-
 	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
 	if (err)
 		goto out_unlock;
@@ -9806,8 +9820,6 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
 	btrfs_mark_buffer_dirty(leaf);
 	btrfs_free_path(path);
 
-	inode->i_op = &btrfs_symlink_inode_operations;
-	inode_nohighmem(inode);
 	inode_set_bytes(inode, name_len);
 	btrfs_i_size_write(BTRFS_I(inode), name_len);
 	err = btrfs_update_inode(trans, root, BTRFS_I(inode));
@@ -10087,30 +10099,34 @@ static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
 	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
 	struct btrfs_trans_handle *trans;
 	struct btrfs_root *root = BTRFS_I(dir)->root;
-	struct inode *inode = NULL;
+	struct inode *inode;
 	u64 index;
-	int ret = 0;
+	int ret;
+
+	inode = new_inode(dir->i_sb);
+	if (!inode)
+		return -ENOMEM;
+	inode_init_owner(mnt_userns, inode, dir, mode);
+	inode->i_fop = &btrfs_file_operations;
+	inode->i_op = &btrfs_file_inode_operations;
+	inode->i_mapping->a_ops = &btrfs_aops;
 
 	/*
 	 * 5 units required for adding orphan entry
 	 */
 	trans = btrfs_start_transaction(root, 5);
-	if (IS_ERR(trans))
+	if (IS_ERR(trans)) {
+		iput(inode);
 		return PTR_ERR(trans);
+	}
 
-	inode = btrfs_new_inode(trans, root, mnt_userns, dir, NULL, 0,
-			mode, &index);
-	if (IS_ERR(inode)) {
-		ret = PTR_ERR(inode);
+	ret = btrfs_new_inode(trans, root, inode, dir, NULL, 0, &index);
+	if (ret) {
+		iput(inode);
 		inode = NULL;
 		goto out;
 	}
 
-	inode->i_fop = &btrfs_file_operations;
-	inode->i_op = &btrfs_file_inode_operations;
-
-	inode->i_mapping->a_ops = &btrfs_aops;
-
 	ret = btrfs_init_inode_security(trans, inode, dir, NULL);
 	if (ret)
 		goto out;
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 891352fd6d0f..60c907b14547 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -587,6 +587,12 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
 	if (ret < 0)
 		goto out_root_item;
 
+	inode = btrfs_new_subvol_inode(mnt_userns, dir);
+	if (!inode) {
+		ret = -ENOMEM;
+		goto out_anon_dev;
+	}
+
 	btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP);
 	/*
 	 * The same as the snapshot creation, please see the comment
@@ -594,13 +600,13 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
 	 */
 	ret = btrfs_subvolume_reserve_metadata(root, &block_rsv, 8, false);
 	if (ret)
-		goto out_anon_dev;
+		goto out_inode;
 
 	trans = btrfs_start_transaction(root, 0);
 	if (IS_ERR(trans)) {
 		ret = PTR_ERR(trans);
 		btrfs_subvolume_release_metadata(root, &block_rsv);
-		goto out_anon_dev;
+		goto out_inode;
 	}
 	trans->block_rsv = &block_rsv;
 	trans->bytes_reserved = block_rsv.size;
@@ -683,16 +689,16 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
 	}
 	/* anon_dev is owned by new_root now. */
 	anon_dev = 0;
+	BTRFS_I(inode)->root = new_root;
+	/* ... and new_root is owned by inode now. */
 
 	ret = btrfs_record_root_in_trans(trans, new_root);
 	if (ret) {
-		btrfs_put_root(new_root);
 		btrfs_abort_transaction(trans, ret);
 		goto out;
 	}
 
-	ret = btrfs_create_subvol_root(trans, new_root, root, mnt_userns);
-	btrfs_put_root(new_root);
+	ret = btrfs_create_subvol_root(trans, root, inode);
 	if (ret) {
 		/* We potentially lose an unused inode item here */
 		btrfs_abort_transaction(trans, ret);
@@ -745,11 +751,11 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
 		ret = btrfs_commit_transaction(trans);
 
 	if (!ret) {
-		inode = btrfs_lookup_dentry(dir, dentry);
-		if (IS_ERR(inode))
-			return PTR_ERR(inode);
 		d_instantiate(dentry, inode);
+		inode = NULL;
 	}
+out_inode:
+	iput(inode);
 out_anon_dev:
 	if (anon_dev)
 		free_anon_bdev(anon_dev);
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 14/16] btrfs: factor out common part of btrfs_{mknod,create,mkdir}()
  2022-03-10  1:31 [PATCH v2 00/16] btrfs: inode creation cleanups and fixes Omar Sandoval
                   ` (12 preceding siblings ...)
  2022-03-10  1:31 ` [PATCH v2 13/16] btrfs: allocate inode outside of btrfs_new_inode() Omar Sandoval
@ 2022-03-10  1:31 ` Omar Sandoval
  2022-03-11 17:43   ` Sweet Tea Dorminy
  2022-03-10  1:31 ` [PATCH v2 15/16] btrfs: reserve correct number of items for inode creation Omar Sandoval
                   ` (2 subsequent siblings)
  16 siblings, 1 reply; 35+ messages in thread
From: Omar Sandoval @ 2022-03-10  1:31 UTC (permalink / raw)
  To: linux-btrfs; +Cc: kernel-team

From: Omar Sandoval <osandov@fb.com>

btrfs_{mknod,create,mkdir}() are now identical other than the inode
initialization and some inconsequential function call order differences.
Factor out the common code to reduce code duplication.

Signed-off-by: Omar Sandoval <osandov@fb.com>
---
 fs/btrfs/inode.c | 152 ++++++++++-------------------------------------
 1 file changed, 33 insertions(+), 119 deletions(-)

diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index ff780256c936..bea2cb2d90a5 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -6346,82 +6346,15 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
 	return ret;
 }
 
-static int btrfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
-		       struct dentry *dentry, umode_t mode, dev_t rdev)
+static int btrfs_create_common(struct inode *dir, struct dentry *dentry,
+			       struct inode *inode)
 {
 	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
-	struct btrfs_trans_handle *trans;
 	struct btrfs_root *root = BTRFS_I(dir)->root;
-	struct inode *inode;
+	struct btrfs_trans_handle *trans;
 	int err;
 	u64 index = 0;
 
-	inode = new_inode(dir->i_sb);
-	if (!inode)
-		return -ENOMEM;
-	inode_init_owner(mnt_userns, inode, dir, mode);
-	inode->i_op = &btrfs_special_inode_operations;
-	init_special_inode(inode, inode->i_mode, rdev);
-
-	/*
-	 * 2 for inode item and ref
-	 * 2 for dir items
-	 * 1 for xattr if selinux is on
-	 */
-	trans = btrfs_start_transaction(root, 5);
-	if (IS_ERR(trans)) {
-		iput(inode);
-		return PTR_ERR(trans);
-	}
-
-	err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
-			      dentry->d_name.len, &index);
-	if (err) {
-		iput(inode);
-		inode = NULL;
-		goto out_unlock;
-	}
-
-	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
-	if (err)
-		goto out_unlock;
-
-	err = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode),
-			     dentry->d_name.name, dentry->d_name.len, 0, index);
-	if (err)
-		goto out_unlock;
-
-	btrfs_update_inode(trans, root, BTRFS_I(inode));
-	d_instantiate_new(dentry, inode);
-
-out_unlock:
-	btrfs_end_transaction(trans);
-	btrfs_btree_balance_dirty(fs_info);
-	if (err && inode) {
-		inode_dec_link_count(inode);
-		discard_new_inode(inode);
-	}
-	return err;
-}
-
-static int btrfs_create(struct user_namespace *mnt_userns, struct inode *dir,
-			struct dentry *dentry, umode_t mode, bool excl)
-{
-	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
-	struct btrfs_trans_handle *trans;
-	struct btrfs_root *root = BTRFS_I(dir)->root;
-	struct inode *inode;
-	int err;
-	u64 index = 0;
-
-	inode = new_inode(dir->i_sb);
-	if (!inode)
-		return -ENOMEM;
-	inode_init_owner(mnt_userns, inode, dir, mode);
-	inode->i_fop = &btrfs_file_operations;
-	inode->i_op = &btrfs_file_inode_operations;
-	inode->i_mapping->a_ops = &btrfs_aops;
-
 	/*
 	 * 2 for inode item and ref
 	 * 2 for dir items
@@ -6466,6 +6399,35 @@ static int btrfs_create(struct user_namespace *mnt_userns, struct inode *dir,
 	return err;
 }
 
+static int btrfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
+		       struct dentry *dentry, umode_t mode, dev_t rdev)
+{
+	struct inode *inode;
+
+	inode = new_inode(dir->i_sb);
+	if (!inode)
+		return -ENOMEM;
+	inode_init_owner(mnt_userns, inode, dir, mode);
+	inode->i_op = &btrfs_special_inode_operations;
+	init_special_inode(inode, inode->i_mode, rdev);
+	return btrfs_create_common(dir, dentry, inode);
+}
+
+static int btrfs_create(struct user_namespace *mnt_userns, struct inode *dir,
+			struct dentry *dentry, umode_t mode, bool excl)
+{
+	struct inode *inode;
+
+	inode = new_inode(dir->i_sb);
+	if (!inode)
+		return -ENOMEM;
+	inode_init_owner(mnt_userns, inode, dir, mode);
+	inode->i_fop = &btrfs_file_operations;
+	inode->i_op = &btrfs_file_inode_operations;
+	inode->i_mapping->a_ops = &btrfs_aops;
+	return btrfs_create_common(dir, dentry, inode);
+}
+
 static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
 		      struct dentry *dentry)
 {
@@ -6547,12 +6509,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
 static int btrfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
 		       struct dentry *dentry, umode_t mode)
 {
-	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
 	struct inode *inode;
-	struct btrfs_trans_handle *trans;
-	struct btrfs_root *root = BTRFS_I(dir)->root;
-	int err;
-	u64 index = 0;
 
 	inode = new_inode(dir->i_sb);
 	if (!inode)
@@ -6560,50 +6517,7 @@ static int btrfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
 	inode_init_owner(mnt_userns, inode, dir, S_IFDIR | mode);
 	inode->i_op = &btrfs_dir_inode_operations;
 	inode->i_fop = &btrfs_dir_file_operations;
-
-	/*
-	 * 2 items for inode and ref
-	 * 2 items for dir items
-	 * 1 for xattr if selinux is on
-	 */
-	trans = btrfs_start_transaction(root, 5);
-	if (IS_ERR(trans)) {
-		iput(inode);
-		return PTR_ERR(trans);
-	}
-
-	err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
-			      dentry->d_name.len, &index);
-	if (err) {
-		iput(inode);
-		inode = NULL;
-		goto out_fail;
-	}
-
-	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
-	if (err)
-		goto out_fail;
-
-	err = btrfs_update_inode(trans, root, BTRFS_I(inode));
-	if (err)
-		goto out_fail;
-
-	err = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode),
-			dentry->d_name.name,
-			dentry->d_name.len, 0, index);
-	if (err)
-		goto out_fail;
-
-	d_instantiate_new(dentry, inode);
-
-out_fail:
-	btrfs_end_transaction(trans);
-	if (err && inode) {
-		inode_dec_link_count(inode);
-		discard_new_inode(inode);
-	}
-	btrfs_btree_balance_dirty(fs_info);
-	return err;
+	return btrfs_create_common(dir, dentry, inode);
 }
 
 static noinline int uncompress_inline(struct btrfs_path *path,
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 15/16] btrfs: reserve correct number of items for inode creation
  2022-03-10  1:31 [PATCH v2 00/16] btrfs: inode creation cleanups and fixes Omar Sandoval
                   ` (13 preceding siblings ...)
  2022-03-10  1:31 ` [PATCH v2 14/16] btrfs: factor out common part of btrfs_{mknod,create,mkdir}() Omar Sandoval
@ 2022-03-10  1:31 ` Omar Sandoval
  2022-03-11 17:56   ` Sweet Tea Dorminy
  2022-03-10  1:31 ` [PATCH v2 16/16] btrfs: move common inode creation code into btrfs_create_new_inode() Omar Sandoval
  2022-03-14 12:50 ` [PATCH v2 00/16] btrfs: inode creation cleanups and fixes David Sterba
  16 siblings, 1 reply; 35+ messages in thread
From: Omar Sandoval @ 2022-03-10  1:31 UTC (permalink / raw)
  To: linux-btrfs; +Cc: kernel-team

From: Omar Sandoval <osandov@fb.com>

The various inode creation code paths do not account for the compression
property, POSIX ACLs, or the parent inode item when starting a
transaction. Fix it by refactoring all of these code paths to use a new
function, btrfs_new_inode_prepare(), which computes the correct number
of items. To do so, it needs to know whether POSIX ACLs will be created,
so move the ACL creation into that function. To reduce the number of
arguments that need to be passed around for inode creation, define
struct btrfs_new_inode_args containing all of the relevant information.

btrfs_new_inode_prepare() will also be a good place to set up the
fscrypt context and encrypted filename in the future.

Signed-off-by: Omar Sandoval <osandov@fb.com>
---
 fs/btrfs/acl.c   |  36 +------
 fs/btrfs/ctree.h |  34 +++++--
 fs/btrfs/inode.c | 256 ++++++++++++++++++++++++++++++++++-------------
 fs/btrfs/ioctl.c |  83 ++++++++++-----
 4 files changed, 277 insertions(+), 132 deletions(-)

diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c
index a6909ec9bc38..548d6a5477b4 100644
--- a/fs/btrfs/acl.c
+++ b/fs/btrfs/acl.c
@@ -55,8 +55,8 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu)
 	return acl;
 }
 
-static int __btrfs_set_acl(struct btrfs_trans_handle *trans,
-			   struct inode *inode, struct posix_acl *acl, int type)
+int __btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode,
+		    struct posix_acl *acl, int type)
 {
 	int ret, size = 0;
 	const char *name;
@@ -127,35 +127,3 @@ int btrfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
 		inode->i_mode = old_mode;
 	return ret;
 }
-
-int btrfs_init_acl(struct btrfs_trans_handle *trans,
-		   struct inode *inode, struct inode *dir)
-{
-	struct posix_acl *default_acl, *acl;
-	int ret = 0;
-
-	/* this happens with subvols */
-	if (!dir)
-		return 0;
-
-	ret = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
-	if (ret)
-		return ret;
-
-	if (default_acl) {
-		ret = __btrfs_set_acl(trans, inode, default_acl,
-				      ACL_TYPE_DEFAULT);
-		posix_acl_release(default_acl);
-	}
-
-	if (acl) {
-		if (!ret)
-			ret = __btrfs_set_acl(trans, inode, acl,
-					      ACL_TYPE_ACCESS);
-		posix_acl_release(acl);
-	}
-
-	if (!default_acl && !acl)
-		cache_no_acl(inode);
-	return ret;
-}
diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index f39730420e8a..322c02610e9e 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -3254,11 +3254,32 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, long nr,
 int btrfs_set_extent_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
 			      unsigned int extra_bits,
 			      struct extent_state **cached_state);
+struct btrfs_new_inode_args {
+	/* Input */
+	struct inode *dir;
+	struct dentry *dentry;
+	struct inode *inode;
+	bool orphan;
+	bool subvol;
+
+	/*
+	 * Output from btrfs_new_inode_prepare(), input to
+	 * btrfs_create_new_inode().
+	 */
+	struct posix_acl *default_acl;
+	struct posix_acl *acl;
+};
+int btrfs_new_inode_prepare(struct btrfs_new_inode_args *args,
+			    unsigned int *trans_num_items);
+int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
+			   struct btrfs_new_inode_args *args,
+			   u64 *index);
+void btrfs_new_inode_args_destroy(struct btrfs_new_inode_args *args);
 struct inode *btrfs_new_subvol_inode(struct user_namespace *mnt_userns,
 				     struct inode *dir);
 int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
 			     struct btrfs_root *parent_root,
-			     struct inode *inode);
+			     struct btrfs_new_inode_args *args);
  void btrfs_set_delalloc_extent(struct inode *inode, struct extent_state *state,
 			       unsigned *bits);
 void btrfs_clear_delalloc_extent(struct inode *inode,
@@ -3816,15 +3837,16 @@ static inline int __btrfs_fs_compat_ro(struct btrfs_fs_info *fs_info, u64 flag)
 struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu);
 int btrfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
 		  struct posix_acl *acl, int type);
-int btrfs_init_acl(struct btrfs_trans_handle *trans,
-		   struct inode *inode, struct inode *dir);
+int __btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode,
+		    struct posix_acl *acl, int type);
 #else
 #define btrfs_get_acl NULL
 #define btrfs_set_acl NULL
-static inline int btrfs_init_acl(struct btrfs_trans_handle *trans,
-				 struct inode *inode, struct inode *dir)
+static inline int __btrfs_set_acl(struct btrfs_trans_handle *trans,
+				  struct inode *inode, struct posix_acl *acl,
+				  int type)
 {
-	return 0;
+	return -EOPNOTSUPP;
 }
 #endif
 
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index bea2cb2d90a5..e2b1b1969d0b 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -223,14 +223,26 @@ static int btrfs_dirty_inode(struct inode *inode);
 
 static int btrfs_init_inode_security(struct btrfs_trans_handle *trans,
 				     struct inode *inode,  struct inode *dir,
-				     const struct qstr *qstr)
+				     const struct qstr *qstr,
+				     struct posix_acl *default_acl,
+				     struct posix_acl *acl)
 {
 	int err;
 
-	err = btrfs_init_acl(trans, inode, dir);
-	if (!err)
-		err = btrfs_xattr_security_init(trans, inode, dir, qstr);
-	return err;
+	if (default_acl) {
+		err = __btrfs_set_acl(trans, inode, default_acl,
+				      ACL_TYPE_DEFAULT);
+		if (err)
+			return err;
+	}
+	if (acl) {
+		err = __btrfs_set_acl(trans, inode, acl, ACL_TYPE_ACCESS);
+		if (err)
+			return err;
+	}
+	if (!default_acl && !acl)
+		cache_no_acl(inode);
+	return btrfs_xattr_security_init(trans, inode, dir, qstr);
 }
 
 /*
@@ -6059,6 +6071,49 @@ static int btrfs_insert_inode_locked(struct inode *inode)
 		   btrfs_find_actor, &args);
 }
 
+int btrfs_new_inode_prepare(struct btrfs_new_inode_args *args,
+			    unsigned int *trans_num_items)
+{
+	struct inode *dir = args->dir;
+	struct inode *inode = args->inode;
+	int ret;
+
+	ret = posix_acl_create(dir, &inode->i_mode, &args->default_acl,
+			       &args->acl);
+	if (ret)
+		return ret;
+
+	*trans_num_items = 1; /* 1 to add inode item */
+	if (BTRFS_I(dir)->prop_compress)
+		(*trans_num_items)++; /* 1 to add compression property */
+	if (args->default_acl)
+		(*trans_num_items)++; /* 1 to add default ACL xattr */
+	if (args->acl)
+		(*trans_num_items)++; /* 1 to add access ACL xattr */
+#ifdef CONFIG_SECURITY
+	if (dir->i_security)
+		(*trans_num_items)++; /* 1 to add LSM xattr */
+#endif
+	if (args->orphan) {
+		(*trans_num_items)++; /* 1 to add orphan item */
+	} else {
+		/*
+		 * 1 to add inode ref
+		 * 1 to add dir item
+		 * 1 to add dir index
+		 * 1 to update parent inode item
+		 */
+		*trans_num_items += 4;
+	}
+	return 0;
+}
+
+void btrfs_new_inode_args_destroy(struct btrfs_new_inode_args *args)
+{
+	posix_acl_release(args->acl);
+	posix_acl_release(args->default_acl);
+}
+
 /*
  * Inherit flags from the parent inode.
  *
@@ -6090,12 +6145,16 @@ static void btrfs_inherit_iflags(struct inode *inode, struct inode *dir)
 	btrfs_sync_inode_flags_to_i_flags(inode);
 }
 
-static int btrfs_new_inode(struct btrfs_trans_handle *trans,
-			   struct btrfs_root *root, struct inode *inode,
-			   struct inode *dir, const char *name, int name_len,
+int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
+			   struct btrfs_new_inode_args *args,
 			   u64 *index)
 {
-	struct btrfs_fs_info *fs_info = root->fs_info;
+	struct inode *dir = args->subvol ? NULL : args->dir;
+	struct inode *inode = args->inode;
+	const char *name;
+	int name_len;
+	struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+	struct btrfs_root *root;
 	struct btrfs_inode_item *inode_item;
 	struct btrfs_key *location;
 	struct btrfs_path *path;
@@ -6107,6 +6166,17 @@ static int btrfs_new_inode(struct btrfs_trans_handle *trans,
 	unsigned long ptr;
 	int ret;
 
+	if (args->subvol) {
+		name = "..";
+		name_len = 2;
+	} else if (args->orphan) {
+		name = NULL;
+		name_len = 0;
+	} else {
+		name = args->dentry->d_name.name;
+		name_len = args->dentry->d_name.len;
+	}
+
 	path = btrfs_alloc_path();
 	if (!path)
 		return -ENOMEM;
@@ -6118,6 +6188,10 @@ static int btrfs_new_inode(struct btrfs_trans_handle *trans,
 	if (!name)
 		set_nlink(inode, 0);
 
+	if (!args->subvol)
+		BTRFS_I(inode)->root = btrfs_grab_root(BTRFS_I(dir)->root);
+	root = BTRFS_I(inode)->root;
+
 	ret = btrfs_get_free_objectid(root, &objectid);
 	if (ret) {
 		btrfs_free_path(path);
@@ -6143,7 +6217,6 @@ static int btrfs_new_inode(struct btrfs_trans_handle *trans,
 	 */
 	BTRFS_I(inode)->index_cnt = 2;
 	BTRFS_I(inode)->dir_index = *index;
-	BTRFS_I(inode)->root = btrfs_grab_root(root);
 	BTRFS_I(inode)->generation = trans->transid;
 	inode->i_generation = BTRFS_I(inode)->generation;
 
@@ -6351,30 +6424,39 @@ static int btrfs_create_common(struct inode *dir, struct dentry *dentry,
 {
 	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
 	struct btrfs_root *root = BTRFS_I(dir)->root;
+	struct btrfs_new_inode_args new_inode_args = {
+		.dir = dir,
+		.dentry = dentry,
+		.inode = inode,
+	};
+	unsigned int trans_num_items;
 	struct btrfs_trans_handle *trans;
 	int err;
 	u64 index = 0;
 
-	/*
-	 * 2 for inode item and ref
-	 * 2 for dir items
-	 * 1 for xattr if selinux is on
-	 */
-	trans = btrfs_start_transaction(root, 5);
-	if (IS_ERR(trans)) {
+	err = btrfs_new_inode_prepare(&new_inode_args, &trans_num_items);
+	if (err) {
 		iput(inode);
-		return PTR_ERR(trans);
+		return err;
 	}
 
-	err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
-			      dentry->d_name.len, &index);
+	trans = btrfs_start_transaction(root, trans_num_items);
+	if (IS_ERR(trans)) {
+		iput(inode);
+		err = PTR_ERR(trans);
+		goto out_new_inode_args;
+	}
+
+	err = btrfs_create_new_inode(trans, &new_inode_args, &index);
 	if (err) {
 		iput(inode);
 		inode = NULL;
 		goto out_unlock;
 	}
 
-	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
+	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name,
+					new_inode_args.default_acl,
+					new_inode_args.acl);
 	if (err)
 		goto out_unlock;
 
@@ -6396,6 +6478,8 @@ static int btrfs_create_common(struct inode *dir, struct dentry *dentry,
 		discard_new_inode(inode);
 	}
 	btrfs_btree_balance_dirty(fs_info);
+out_new_inode_args:
+	btrfs_new_inode_args_destroy(&new_inode_args);
 	return err;
 }
 
@@ -8675,13 +8759,14 @@ struct inode *btrfs_new_subvol_inode(struct user_namespace *mnt_userns,
  */
 int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
 			     struct btrfs_root *parent_root,
-			     struct inode *inode)
+			     struct btrfs_new_inode_args *args)
 {
+	struct inode *inode = args->inode;
 	struct btrfs_root *new_root = BTRFS_I(inode)->root;
 	int err;
 	u64 index = 0;
 
-	err = btrfs_new_inode(trans, new_root, inode, NULL, "..", 2, &index);
+	err = btrfs_create_new_inode(trans, args, &index);
 	if (err)
 		return err;
 
@@ -9186,22 +9271,23 @@ static struct inode *new_whiteout_inode(struct user_namespace *mnt_userns,
 }
 
 static int btrfs_whiteout_for_rename(struct btrfs_trans_handle *trans,
-				     struct btrfs_root *root,
-				     struct inode *inode, struct inode *dir,
-				     struct dentry *dentry)
+				     struct btrfs_new_inode_args *args)
 {
+	struct inode *inode = args->inode;
+	struct inode *dir = args->dir;
+	struct btrfs_root *root = BTRFS_I(dir)->root;
+	struct dentry *dentry = args->dentry;
 	int ret;
 	u64 index;
 
-	ret = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
-			      dentry->d_name.len, &index);
+	ret = btrfs_create_new_inode(trans, args, &index);
 	if (ret) {
 		iput(inode);
 		return ret;
 	}
 
-	ret = btrfs_init_inode_security(trans, inode, dir,
-				&dentry->d_name);
+	ret = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name,
+					args->default_acl, args->acl);
 	if (ret)
 		goto out;
 
@@ -9226,7 +9312,10 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
 			unsigned int flags)
 {
 	struct btrfs_fs_info *fs_info = btrfs_sb(old_dir->i_sb);
-	struct inode *whiteout_inode;
+	struct btrfs_new_inode_args whiteout_args = {
+		.dir = old_dir,
+		.dentry = old_dentry,
+	};
 	struct btrfs_trans_handle *trans;
 	unsigned int trans_num_items;
 	struct btrfs_root *root = BTRFS_I(old_dir)->root;
@@ -9282,9 +9371,15 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
 		filemap_flush(old_inode->i_mapping);
 
 	if (flags & RENAME_WHITEOUT) {
-		whiteout_inode = new_whiteout_inode(mnt_userns, old_dir);
-		if (!whiteout_inode)
+		whiteout_args.inode = new_whiteout_inode(mnt_userns, old_dir);
+		if (!whiteout_args.inode)
 			return -ENOMEM;
+		ret = btrfs_new_inode_prepare(&whiteout_args, &trans_num_items);
+		if (ret)
+			goto out_whiteout_inode;
+	} else {
+		/* 1 to update the old parent inode. */
+		trans_num_items = 1;
 	}
 
 	if (old_ino == BTRFS_FIRST_FREE_OBJECTID) {
@@ -9296,24 +9391,25 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
 		 * 1 to add new root ref
 		 * 1 to add new root backref
 		 */
-		trans_num_items = 4;
+		trans_num_items += 4;
 	} else {
 		/*
 		 * 1 to update inode
 		 * 1 to remove old inode ref
 		 * 1 to add new inode ref
 		 */
-		trans_num_items = 3;
+		trans_num_items += 3;
 	}
 	/*
 	 * 1 to remove old dir item
 	 * 1 to remove old dir index
-	 * 1 to update old parent inode
 	 * 1 to add new dir item
 	 * 1 to add new dir index
-	 * 1 to update new parent inode (if it's not the same as the old parent)
 	 */
-	trans_num_items += 6;
+	trans_num_items += 4;
+	/*
+	 * 1 to update new parent inode if it's not the same as the old parent
+	 */
 	if (new_dir != old_dir)
 		trans_num_items++;
 	if (new_inode) {
@@ -9326,8 +9422,6 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
 		 */
 		trans_num_items += 5;
 	}
-	if (flags & RENAME_WHITEOUT)
-		trans_num_items += 5;
 	trans = btrfs_start_transaction(root, trans_num_items);
 	if (IS_ERR(trans)) {
 		ret = PTR_ERR(trans);
@@ -9423,9 +9517,8 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
 				   rename_ctx.index, new_dentry->d_parent);
 
 	if (flags & RENAME_WHITEOUT) {
-		ret = btrfs_whiteout_for_rename(trans, root, whiteout_inode,
-						old_dir, old_dentry);
-		whiteout_inode = NULL;
+		ret = btrfs_whiteout_for_rename(trans, &whiteout_args);
+		whiteout_args.inode = NULL;
 		if (ret) {
 			btrfs_abort_transaction(trans, ret);
 			goto out_fail;
@@ -9438,7 +9531,10 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
 	if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
 		up_read(&fs_info->subvol_sem);
 	if (flags & RENAME_WHITEOUT)
-		iput(whiteout_inode);
+		btrfs_new_inode_args_destroy(&whiteout_args);
+out_whiteout_inode:
+	if (flags & RENAME_WHITEOUT)
+		iput(whiteout_args.inode);
 	return ret;
 }
 
@@ -9658,6 +9754,11 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
 	struct btrfs_path *path;
 	struct btrfs_key key;
 	struct inode *inode;
+	struct btrfs_new_inode_args new_inode_args = {
+		.dir = dir,
+		.dentry = dentry,
+	};
+	unsigned int trans_num_items;
 	int err;
 	u64 index = 0;
 	int name_len;
@@ -9678,28 +9779,32 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
 	inode_nohighmem(inode);
 	inode->i_mapping->a_ops = &btrfs_aops;
 
-	/*
-	 * 2 items for inode item and ref
-	 * 2 items for dir items
-	 * 1 item for updating parent inode item
-	 * 1 item for the inline extent item
-	 * 1 item for xattr if selinux is on
-	 */
-	trans = btrfs_start_transaction(root, 7);
+	new_inode_args.inode = inode;
+	err = btrfs_new_inode_prepare(&new_inode_args, &trans_num_items);
+	if (err) {
+		iput(inode);
+		return err;
+	}
+	/* 1 additional item for the inline extent */
+	trans_num_items++;
+
+	trans = btrfs_start_transaction(root, trans_num_items);
 	if (IS_ERR(trans)) {
 		iput(inode);
-		return PTR_ERR(trans);
+		err = PTR_ERR(trans);
+		goto out_new_inode_args;
 	}
 
-	err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
-			      dentry->d_name.len, &index);
+	err = btrfs_create_new_inode(trans, &new_inode_args, &index);
 	if (err) {
 		iput(inode);
 		inode = NULL;
 		goto out_unlock;
 	}
 
-	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
+	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name,
+					new_inode_args.default_acl,
+					new_inode_args.acl);
 	if (err)
 		goto out_unlock;
 
@@ -9758,6 +9863,8 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
 		discard_new_inode(inode);
 	}
 	btrfs_btree_balance_dirty(fs_info);
+out_new_inode_args:
+	btrfs_new_inode_args_destroy(&new_inode_args);
 	return err;
 }
 
@@ -10014,6 +10121,12 @@ static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
 	struct btrfs_trans_handle *trans;
 	struct btrfs_root *root = BTRFS_I(dir)->root;
 	struct inode *inode;
+	struct btrfs_new_inode_args new_inode_args = {
+		.dir = dir,
+		.dentry = dentry,
+		.orphan = true,
+	};
+	unsigned int trans_num_items;
 	u64 index;
 	int ret;
 
@@ -10025,23 +10138,30 @@ static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
 	inode->i_op = &btrfs_file_inode_operations;
 	inode->i_mapping->a_ops = &btrfs_aops;
 
-	/*
-	 * 5 units required for adding orphan entry
-	 */
-	trans = btrfs_start_transaction(root, 5);
-	if (IS_ERR(trans)) {
+	new_inode_args.inode = inode;
+	ret = btrfs_new_inode_prepare(&new_inode_args, &trans_num_items);
+	if (ret) {
 		iput(inode);
-		return PTR_ERR(trans);
+		return ret;
 	}
 
-	ret = btrfs_new_inode(trans, root, inode, dir, NULL, 0, &index);
+	trans = btrfs_start_transaction(root, trans_num_items);
+	if (IS_ERR(trans)) {
+		iput(inode);
+		ret = PTR_ERR(trans);
+		goto out_new_inode_args;
+	}
+
+	ret = btrfs_create_new_inode(trans, &new_inode_args, &index);
 	if (ret) {
 		iput(inode);
 		inode = NULL;
 		goto out;
 	}
 
-	ret = btrfs_init_inode_security(trans, inode, dir, NULL);
+	ret = btrfs_init_inode_security(trans, inode, dir, NULL,
+					new_inode_args.default_acl,
+					new_inode_args.acl);
 	if (ret)
 		goto out;
 
@@ -10053,9 +10173,9 @@ static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
 		goto out;
 
 	/*
-	 * We set number of links to 0 in btrfs_new_inode(), and here we set
-	 * it to 1 because d_tmpfile() will issue a warning if the count is 0,
-	 * through:
+	 * We set number of links to 0 in btrfs_create_new_inode(), and here we
+	 * set it to 1 because d_tmpfile() will issue a warning if the count is
+	 * 0, through:
 	 *
 	 *    d_tmpfile() -> inode_dec_link_count() -> drop_nlink()
 	 */
@@ -10068,6 +10188,8 @@ static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
 	if (ret && inode)
 		discard_new_inode(inode);
 	btrfs_btree_balance_dirty(fs_info);
+out_new_inode_args:
+	btrfs_new_inode_args_destroy(&new_inode_args);
 	return ret;
 }
 
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 60c907b14547..07a74bbe3d84 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -544,6 +544,32 @@ int __pure btrfs_is_empty_uuid(u8 *uuid)
 	return 1;
 }
 
+/*
+ * Calculate the number of transaction items to reserve for creating a subvolume
+ * or snapshot, not including the inode, directory entries, or parent directory.
+ */
+static unsigned int create_subvol_num_items(struct btrfs_qgroup_inherit *inherit)
+{
+	/*
+	 * 1 to add root block
+	 * 1 to add root item
+	 * 1 to add root ref
+	 * 1 to add root backref
+	 * 1 to add UUID item
+	 * 1 to add qgroup info
+	 * 1 to add qgroup limit
+	 * (Ideally the last two would only be accounted if qgroups are enabled,
+	 * but that can change between now and the time we would insert them)
+	 */
+	unsigned int num_items = 7;
+
+	if (inherit) {
+		/* 2 to add qgroup relations for each inherited qgroup */
+		num_items += 2 * inherit->num_qgroups;
+	}
+	return num_items;
+}
+
 static noinline int create_subvol(struct user_namespace *mnt_userns,
 				  struct inode *dir, struct dentry *dentry,
 				  struct btrfs_qgroup_inherit *inherit)
@@ -560,7 +586,12 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
 	struct btrfs_root *new_root;
 	struct btrfs_block_rsv block_rsv;
 	struct timespec64 cur_time = current_time(dir);
-	struct inode *inode;
+	struct btrfs_new_inode_args new_inode_args = {
+		.dir = dir,
+		.dentry = dentry,
+		.subvol = true,
+	};
+	unsigned int trans_num_items;
 	int ret;
 	dev_t anon_dev;
 	u64 objectid;
@@ -587,26 +618,27 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
 	if (ret < 0)
 		goto out_root_item;
 
-	inode = btrfs_new_subvol_inode(mnt_userns, dir);
-	if (!inode) {
+	new_inode_args.inode = btrfs_new_subvol_inode(mnt_userns, dir);
+	if (!new_inode_args.inode) {
 		ret = -ENOMEM;
 		goto out_anon_dev;
 	}
-
-	btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP);
-	/*
-	 * The same as the snapshot creation, please see the comment
-	 * of create_snapshot().
-	 */
-	ret = btrfs_subvolume_reserve_metadata(root, &block_rsv, 8, false);
+	ret = btrfs_new_inode_prepare(&new_inode_args, &trans_num_items);
 	if (ret)
 		goto out_inode;
+	trans_num_items += create_subvol_num_items(inherit);
+
+	btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP);
+	ret = btrfs_subvolume_reserve_metadata(root, &block_rsv,
+					       trans_num_items, false);
+	if (ret)
+		goto out_new_inode_args;
 
 	trans = btrfs_start_transaction(root, 0);
 	if (IS_ERR(trans)) {
 		ret = PTR_ERR(trans);
 		btrfs_subvolume_release_metadata(root, &block_rsv);
-		goto out_inode;
+		goto out_new_inode_args;
 	}
 	trans->block_rsv = &block_rsv;
 	trans->bytes_reserved = block_rsv.size;
@@ -689,8 +721,8 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
 	}
 	/* anon_dev is owned by new_root now. */
 	anon_dev = 0;
-	BTRFS_I(inode)->root = new_root;
-	/* ... and new_root is owned by inode now. */
+	BTRFS_I(new_inode_args.inode)->root = new_root;
+	/* ... and new_root is owned by new_inode_args.inode now. */
 
 	ret = btrfs_record_root_in_trans(trans, new_root);
 	if (ret) {
@@ -698,7 +730,7 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
 		goto out;
 	}
 
-	ret = btrfs_create_subvol_root(trans, root, inode);
+	ret = btrfs_create_subvol_root(trans, root, &new_inode_args);
 	if (ret) {
 		/* We potentially lose an unused inode item here */
 		btrfs_abort_transaction(trans, ret);
@@ -751,11 +783,13 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
 		ret = btrfs_commit_transaction(trans);
 
 	if (!ret) {
-		d_instantiate(dentry, inode);
-		inode = NULL;
+		d_instantiate(dentry, new_inode_args.inode);
+		new_inode_args.inode = NULL;
 	}
+out_new_inode_args:
+	btrfs_new_inode_args_destroy(&new_inode_args);
 out_inode:
-	iput(inode);
+	iput(new_inode_args.inode);
 out_anon_dev:
 	if (anon_dev)
 		free_anon_bdev(anon_dev);
@@ -771,6 +805,7 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
 	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
 	struct inode *inode;
 	struct btrfs_pending_snapshot *pending_snapshot;
+	unsigned int trans_num_items;
 	struct btrfs_trans_handle *trans;
 	int ret;
 
@@ -808,16 +843,14 @@ static int create_snapshot(struct btrfs_root *root, struct inode *dir,
 	btrfs_init_block_rsv(&pending_snapshot->block_rsv,
 			     BTRFS_BLOCK_RSV_TEMP);
 	/*
-	 * 1 - parent dir inode
-	 * 2 - dir entries
-	 * 1 - root item
-	 * 2 - root ref/backref
-	 * 1 - root of snapshot
-	 * 1 - UUID item
+	 * 1 to add dir item
+	 * 1 to add dir index
+	 * 1 to update parent inode item
 	 */
+	trans_num_items = create_subvol_num_items(inherit) + 3;
 	ret = btrfs_subvolume_reserve_metadata(BTRFS_I(dir)->root,
-					&pending_snapshot->block_rsv, 8,
-					false);
+					       &pending_snapshot->block_rsv,
+					       trans_num_items, false);
 	if (ret)
 		goto free_pending;
 
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* [PATCH v2 16/16] btrfs: move common inode creation code into btrfs_create_new_inode()
  2022-03-10  1:31 [PATCH v2 00/16] btrfs: inode creation cleanups and fixes Omar Sandoval
                   ` (14 preceding siblings ...)
  2022-03-10  1:31 ` [PATCH v2 15/16] btrfs: reserve correct number of items for inode creation Omar Sandoval
@ 2022-03-10  1:31 ` Omar Sandoval
  2022-03-11 18:04   ` Sweet Tea Dorminy
  2022-03-14 12:50 ` [PATCH v2 00/16] btrfs: inode creation cleanups and fixes David Sterba
  16 siblings, 1 reply; 35+ messages in thread
From: Omar Sandoval @ 2022-03-10  1:31 UTC (permalink / raw)
  To: linux-btrfs; +Cc: kernel-team

From: Omar Sandoval <osandov@fb.com>

All of our inode creation code paths duplicate the calls to
btrfs_init_inode_security() and btrfs_add_link(). Subvolume creation
additionally duplicates property inheritance and the call to
btrfs_set_inode_index(). Fix this by moving the common code into
btrfs_create_new_inode(). This accomplishes a few things at once:

1. It reduces code duplication.
2. It allows us to set up the inode completely before inserting the
   inode item, removing calls to btrfs_update_inode().
3. It fixes a leak of an inode on disk in some error cases. For example,
   in btrfs_create(), if btrfs_new_inode() succeeds, then we have
   inserted an inode item and its inode ref. However, if something after
   that fails (e.g., btrfs_init_inode_security()), then we end the
   transaction and then decrement the link count on the inode. If the
   transaction is committed and the system crashes before the failed
   inode is deleted, then we leak that inode on disk. Instead, this
   refactoring aborts the transaction when we can't recover more
   gracefully.
4. It exposes various ways that subvolume creation diverges from mkdir
   in terms of inheriting flags, properties, permissions, and POSIX
   ACLs, a lot of which appears to be accidental. This patch explicitly
   does _not_ change the existing non-standard behavior, but it makes
   those differences more clear in the code and documents them so that
   we can discuss whether they should be changed.

Signed-off-by: Omar Sandoval <osandov@fb.com>
---
 fs/btrfs/ctree.h |   6 +-
 fs/btrfs/inode.c | 413 +++++++++++++++++++----------------------------
 fs/btrfs/ioctl.c |  59 ++-----
 fs/btrfs/props.c |  40 +----
 fs/btrfs/props.h |   4 -
 5 files changed, 182 insertions(+), 340 deletions(-)

diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
index 322c02610e9e..3a348b26df57 100644
--- a/fs/btrfs/ctree.h
+++ b/fs/btrfs/ctree.h
@@ -3272,14 +3272,10 @@ struct btrfs_new_inode_args {
 int btrfs_new_inode_prepare(struct btrfs_new_inode_args *args,
 			    unsigned int *trans_num_items);
 int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
-			   struct btrfs_new_inode_args *args,
-			   u64 *index);
+			   struct btrfs_new_inode_args *args);
 void btrfs_new_inode_args_destroy(struct btrfs_new_inode_args *args);
 struct inode *btrfs_new_subvol_inode(struct user_namespace *mnt_userns,
 				     struct inode *dir);
-int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
-			     struct btrfs_root *parent_root,
-			     struct btrfs_new_inode_args *args);
  void btrfs_set_delalloc_extent(struct inode *inode, struct extent_state *state,
 			       unsigned *bits);
 void btrfs_clear_delalloc_extent(struct inode *inode,
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index e2b1b1969d0b..ff2a7404ba86 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -6123,9 +6123,6 @@ static void btrfs_inherit_iflags(struct inode *inode, struct inode *dir)
 {
 	unsigned int flags;
 
-	if (!dir)
-		return;
-
 	flags = BTRFS_I(dir)->flags;
 
 	if (flags & BTRFS_INODE_NOCOMPRESS) {
@@ -6146,14 +6143,13 @@ static void btrfs_inherit_iflags(struct inode *inode, struct inode *dir)
 }
 
 int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
-			   struct btrfs_new_inode_args *args,
-			   u64 *index)
+			   struct btrfs_new_inode_args *args)
 {
-	struct inode *dir = args->subvol ? NULL : args->dir;
+	struct inode *dir = args->dir;
 	struct inode *inode = args->inode;
-	const char *name;
-	int name_len;
-	struct btrfs_fs_info *fs_info = btrfs_sb(inode->i_sb);
+	const char *name = args->orphan ? NULL : args->dentry->d_name.name;
+	int name_len = args->orphan ? 0 : args->dentry->d_name.len;
+	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
 	struct btrfs_root *root;
 	struct btrfs_inode_item *inode_item;
 	struct btrfs_key *location;
@@ -6166,49 +6162,32 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
 	unsigned long ptr;
 	int ret;
 
-	if (args->subvol) {
-		name = "..";
-		name_len = 2;
-	} else if (args->orphan) {
-		name = NULL;
-		name_len = 0;
-	} else {
-		name = args->dentry->d_name.name;
-		name_len = args->dentry->d_name.len;
-	}
-
 	path = btrfs_alloc_path();
 	if (!path)
 		return -ENOMEM;
 
-	/*
-	 * O_TMPFILE, set link count to 0, so that after this point,
-	 * we fill in an inode item with the correct link count.
-	 */
-	if (!name)
-		set_nlink(inode, 0);
-
 	if (!args->subvol)
 		BTRFS_I(inode)->root = btrfs_grab_root(BTRFS_I(dir)->root);
 	root = BTRFS_I(inode)->root;
 
 	ret = btrfs_get_free_objectid(root, &objectid);
-	if (ret) {
-		btrfs_free_path(path);
-		return ret;
-	}
+	if (ret)
+		goto out;
 	inode->i_ino = objectid;
 
-	if (dir && name) {
+	if (args->orphan) {
+		/*
+		 * O_TMPFILE, set link count to 0, so that after this point, we
+		 * fill in an inode item with the correct link count.
+		 */
+		set_nlink(inode, 0);
+	} else {
 		trace_btrfs_inode_request(dir);
 
-		ret = btrfs_set_inode_index(BTRFS_I(dir), index);
-		if (ret) {
-			btrfs_free_path(path);
-			return ret;
-		}
-	} else if (dir) {
-		*index = 0;
+		ret = btrfs_set_inode_index(BTRFS_I(dir),
+					    &BTRFS_I(inode)->dir_index);
+		if (ret)
+			goto out;
 	}
 	/*
 	 * index_cnt is ignored for everything but a dir,
@@ -6216,11 +6195,16 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
 	 * number
 	 */
 	BTRFS_I(inode)->index_cnt = 2;
-	BTRFS_I(inode)->dir_index = *index;
 	BTRFS_I(inode)->generation = trans->transid;
 	inode->i_generation = BTRFS_I(inode)->generation;
 
-	btrfs_inherit_iflags(inode, dir);
+	/*
+	 * Subvolumes don't inherit flags from their parent directory.
+	 * Originally this was probably by accident, but we probably can't
+	 * change it now.
+	 */
+	if (!args->subvol)
+		btrfs_inherit_iflags(inode, dir);
 
 	if (S_ISREG(inode->i_mode)) {
 		if (btrfs_test_opt(fs_info, NODATASUM))
@@ -6230,6 +6214,57 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
 				BTRFS_INODE_NODATASUM;
 	}
 
+	location = &BTRFS_I(inode)->location;
+	location->objectid = objectid;
+	location->offset = 0;
+	location->type = BTRFS_INODE_ITEM_KEY;
+
+	ret = btrfs_insert_inode_locked(inode);
+	if (ret < 0) {
+		if (!args->orphan)
+			BTRFS_I(dir)->index_cnt--;
+		goto out;
+	}
+
+	if (args->subvol) {
+		struct inode *parent;
+
+		/*
+		 * Subvolumes inherit properties from their parent subvolume,
+		 * not the directory they were created in.
+		 */
+		parent = btrfs_iget(fs_info->sb, BTRFS_FIRST_FREE_OBJECTID,
+				    BTRFS_I(dir)->root);
+		if (IS_ERR(parent)) {
+			ret = PTR_ERR(parent);
+		} else {
+			ret = btrfs_inode_inherit_props(trans, inode, parent);
+			iput(parent);
+		}
+	} else {
+		ret = btrfs_inode_inherit_props(trans, inode, dir);
+	}
+	if (ret) {
+		btrfs_err(fs_info,
+			  "error inheriting props for ino %llu (root %llu): %d",
+			  btrfs_ino(BTRFS_I(inode)), root->root_key.objectid,
+			  ret);
+	}
+
+	/*
+	 * Subvolumes don't inherit ACLs or get passed to the LSM. This is
+	 * probably a bug.
+	 */
+	if (!args->subvol) {
+		ret = btrfs_init_inode_security(trans, inode, dir,
+						&args->dentry->d_name,
+						args->default_acl, args->acl);
+		if (ret) {
+			btrfs_abort_transaction(trans, ret);
+			goto discard;
+		}
+	}
+
 	/*
 	 * We could have gotten an inode number from somebody who was fsynced
 	 * and then removed in this same transaction, so let's just set full
@@ -6244,7 +6279,7 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
 
 	sizes[0] = sizeof(struct btrfs_inode_item);
 
-	if (name) {
+	if (!args->orphan) {
 		/*
 		 * Start new inodes with an inode_ref. This is slightly more
 		 * efficient for small numbers of hard links since they will
@@ -6253,53 +6288,61 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
 		 */
 		key[1].objectid = objectid;
 		key[1].type = BTRFS_INODE_REF_KEY;
-		if (dir)
-			key[1].offset = btrfs_ino(BTRFS_I(dir));
-		else
+		if (args->subvol) {
 			key[1].offset = objectid;
-
-		sizes[1] = name_len + sizeof(*ref);
+			sizes[1] = 2 + sizeof(*ref);
+		} else {
+			key[1].offset = btrfs_ino(BTRFS_I(dir));
+			sizes[1] = name_len + sizeof(*ref);
+		}
 	}
 
-	location = &BTRFS_I(inode)->location;
-	location->objectid = objectid;
-	location->offset = 0;
-	location->type = BTRFS_INODE_ITEM_KEY;
-
-	ret = btrfs_insert_inode_locked(inode);
-	if (ret < 0)
-		goto fail;
-
 	batch.keys = &key[0];
 	batch.data_sizes = &sizes[0];
-	batch.total_data_size = sizes[0] + (name ? sizes[1] : 0);
-	batch.nr = name ? 2 : 1;
+	batch.total_data_size = sizes[0] + (args->orphan ? 0 : sizes[1]);
+	batch.nr = args->orphan ? 1 : 2;
 	ret = btrfs_insert_empty_items(trans, root, path, &batch);
-	if (ret != 0)
-		goto fail_unlock;
+	if (ret != 0) {
+		btrfs_abort_transaction(trans, ret);
+		goto discard;
+	}
 
 	inode->i_mtime = current_time(inode);
 	inode->i_atime = inode->i_mtime;
 	inode->i_ctime = inode->i_mtime;
 	BTRFS_I(inode)->i_otime = inode->i_mtime;
 
+	/*
+	 * We're going to fill the inode item now, so at this point the inode
+	 * must be fully initialized.
+	 */
+
 	inode_item = btrfs_item_ptr(path->nodes[0], path->slots[0],
 				  struct btrfs_inode_item);
 	memzero_extent_buffer(path->nodes[0], (unsigned long)inode_item,
 			     sizeof(*inode_item));
 	fill_inode_item(trans, path->nodes[0], inode_item, inode);
 
-	if (name) {
+	if (!args->orphan) {
 		ref = btrfs_item_ptr(path->nodes[0], path->slots[0] + 1,
 				     struct btrfs_inode_ref);
-		btrfs_set_inode_ref_name_len(path->nodes[0], ref, name_len);
-		btrfs_set_inode_ref_index(path->nodes[0], ref, *index);
 		ptr = (unsigned long)(ref + 1);
-		write_extent_buffer(path->nodes[0], name, ptr, name_len);
+		if (args->subvol) {
+			btrfs_set_inode_ref_name_len(path->nodes[0], ref, 2);
+			btrfs_set_inode_ref_index(path->nodes[0], ref, 0);
+			write_extent_buffer(path->nodes[0], "..", ptr, 2);
+		} else {
+			btrfs_set_inode_ref_name_len(path->nodes[0], ref,
+						     name_len);
+			btrfs_set_inode_ref_index(path->nodes[0], ref,
+						  BTRFS_I(inode)->dir_index);
+			write_extent_buffer(path->nodes[0], name, ptr,
+					    name_len);
+		}
 	}
 
 	btrfs_mark_buffer_dirty(path->nodes[0]);
-	btrfs_free_path(path);
+	btrfs_release_path(path);
 
 	inode_tree_add(inode);
 
@@ -6308,24 +6351,28 @@ int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
 
 	btrfs_update_root_times(trans, root);
 
-	ret = btrfs_inode_inherit_props(trans, inode, dir);
-	if (ret)
-		btrfs_err(fs_info,
-			  "error inheriting props for ino %llu (root %llu): %d",
-			btrfs_ino(BTRFS_I(inode)), root->root_key.objectid, ret);
+	if (args->orphan) {
+		ret = btrfs_orphan_add(trans, BTRFS_I(inode));
+	} else {
+		ret = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode), name,
+				     name_len, 0, BTRFS_I(inode)->dir_index);
+	}
+	if (ret) {
+		btrfs_abort_transaction(trans, ret);
+		goto discard;
+	}
 
-	return 0;
+	ret = 0;
+	goto out;
 
-fail_unlock:
+discard:
 	/*
 	 * discard_new_inode() calls iput(), but the caller owns the reference
 	 * to the inode.
 	 */
 	ihold(inode);
 	discard_new_inode(inode);
-fail:
-	if (dir && name)
-		BTRFS_I(dir)->index_cnt--;
+out:
 	btrfs_free_path(path);
 	return ret;
 }
@@ -6432,54 +6479,28 @@ static int btrfs_create_common(struct inode *dir, struct dentry *dentry,
 	unsigned int trans_num_items;
 	struct btrfs_trans_handle *trans;
 	int err;
-	u64 index = 0;
 
 	err = btrfs_new_inode_prepare(&new_inode_args, &trans_num_items);
-	if (err) {
-		iput(inode);
-		return err;
-	}
+	if (err)
+		goto out_inode;
 
 	trans = btrfs_start_transaction(root, trans_num_items);
 	if (IS_ERR(trans)) {
-		iput(inode);
 		err = PTR_ERR(trans);
 		goto out_new_inode_args;
 	}
 
-	err = btrfs_create_new_inode(trans, &new_inode_args, &index);
-	if (err) {
-		iput(inode);
-		inode = NULL;
-		goto out_unlock;
-	}
+	err = btrfs_create_new_inode(trans, &new_inode_args);
+	if (!err)
+		d_instantiate_new(dentry, inode);
 
-	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name,
-					new_inode_args.default_acl,
-					new_inode_args.acl);
-	if (err)
-		goto out_unlock;
-
-	err = btrfs_update_inode(trans, root, BTRFS_I(inode));
-	if (err)
-		goto out_unlock;
-
-	err = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode),
-			     dentry->d_name.name, dentry->d_name.len, 0, index);
-	if (err)
-		goto out_unlock;
-
-	d_instantiate_new(dentry, inode);
-
-out_unlock:
 	btrfs_end_transaction(trans);
-	if (err && inode) {
-		inode_dec_link_count(inode);
-		discard_new_inode(inode);
-	}
 	btrfs_btree_balance_dirty(fs_info);
 out_new_inode_args:
 	btrfs_new_inode_args_destroy(&new_inode_args);
+out_inode:
+	if (err)
+		iput(inode);
 	return err;
 }
 
@@ -8754,34 +8775,6 @@ struct inode *btrfs_new_subvol_inode(struct user_namespace *mnt_userns,
 	return inode;
 }
 
-/*
- * create a new subvolume directory/inode (helper for the ioctl).
- */
-int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
-			     struct btrfs_root *parent_root,
-			     struct btrfs_new_inode_args *args)
-{
-	struct inode *inode = args->inode;
-	struct btrfs_root *new_root = BTRFS_I(inode)->root;
-	int err;
-	u64 index = 0;
-
-	err = btrfs_create_new_inode(trans, args, &index);
-	if (err)
-		return err;
-
-	unlock_new_inode(inode);
-
-	err = btrfs_subvol_inherit_props(trans, new_root, parent_root);
-	if (err)
-		btrfs_err(new_root->fs_info,
-			  "error inheriting subvolume %llu properties: %d",
-			  new_root->root_key.objectid, err);
-
-	err = btrfs_update_inode(trans, new_root, BTRFS_I(inode));
-	return err;
-}
-
 struct inode *btrfs_alloc_inode(struct super_block *sb)
 {
 	struct btrfs_fs_info *fs_info = btrfs_sb(sb);
@@ -9270,42 +9263,6 @@ static struct inode *new_whiteout_inode(struct user_namespace *mnt_userns,
 	return inode;
 }
 
-static int btrfs_whiteout_for_rename(struct btrfs_trans_handle *trans,
-				     struct btrfs_new_inode_args *args)
-{
-	struct inode *inode = args->inode;
-	struct inode *dir = args->dir;
-	struct btrfs_root *root = BTRFS_I(dir)->root;
-	struct dentry *dentry = args->dentry;
-	int ret;
-	u64 index;
-
-	ret = btrfs_create_new_inode(trans, args, &index);
-	if (ret) {
-		iput(inode);
-		return ret;
-	}
-
-	ret = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name,
-					args->default_acl, args->acl);
-	if (ret)
-		goto out;
-
-	ret = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode),
-			     dentry->d_name.name, dentry->d_name.len, 0, index);
-	if (ret)
-		goto out;
-
-	ret = btrfs_update_inode(trans, root, BTRFS_I(inode));
-out:
-	unlock_new_inode(inode);
-	if (ret)
-		inode_dec_link_count(inode);
-	iput(inode);
-
-	return ret;
-}
-
 static int btrfs_rename(struct user_namespace *mnt_userns,
 			struct inode *old_dir, struct dentry *old_dentry,
 			struct inode *new_dir, struct dentry *new_dentry,
@@ -9517,11 +9474,14 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
 				   rename_ctx.index, new_dentry->d_parent);
 
 	if (flags & RENAME_WHITEOUT) {
-		ret = btrfs_whiteout_for_rename(trans, &whiteout_args);
-		whiteout_args.inode = NULL;
+		ret = btrfs_create_new_inode(trans, &whiteout_args);
 		if (ret) {
 			btrfs_abort_transaction(trans, ret);
 			goto out_fail;
+		} else {
+			unlock_new_inode(whiteout_args.inode);
+			iput(whiteout_args.inode);
+			whiteout_args.inode = NULL;
 		}
 	}
 out_fail:
@@ -9760,7 +9720,6 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
 	};
 	unsigned int trans_num_items;
 	int err;
-	u64 index = 0;
 	int name_len;
 	int datasize;
 	unsigned long ptr;
@@ -9778,40 +9737,33 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
 	inode->i_op = &btrfs_symlink_inode_operations;
 	inode_nohighmem(inode);
 	inode->i_mapping->a_ops = &btrfs_aops;
+	btrfs_i_size_write(BTRFS_I(inode), name_len);
+	inode_set_bytes(inode, name_len);
 
 	new_inode_args.inode = inode;
 	err = btrfs_new_inode_prepare(&new_inode_args, &trans_num_items);
-	if (err) {
-		iput(inode);
-		return err;
-	}
+	if (err)
+		goto out_inode;
 	/* 1 additional item for the inline extent */
 	trans_num_items++;
 
 	trans = btrfs_start_transaction(root, trans_num_items);
 	if (IS_ERR(trans)) {
-		iput(inode);
 		err = PTR_ERR(trans);
 		goto out_new_inode_args;
 	}
 
-	err = btrfs_create_new_inode(trans, &new_inode_args, &index);
-	if (err) {
-		iput(inode);
-		inode = NULL;
-		goto out_unlock;
-	}
-
-	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name,
-					new_inode_args.default_acl,
-					new_inode_args.acl);
+	err = btrfs_create_new_inode(trans, &new_inode_args);
 	if (err)
-		goto out_unlock;
+		goto out;
 
 	path = btrfs_alloc_path();
 	if (!path) {
 		err = -ENOMEM;
-		goto out_unlock;
+		btrfs_abort_transaction(trans, err);
+		discard_new_inode(inode);
+		inode = NULL;
+		goto out;
 	}
 	key.objectid = btrfs_ino(BTRFS_I(inode));
 	key.offset = 0;
@@ -9820,8 +9772,11 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
 	err = btrfs_insert_empty_item(trans, root, path, &key,
 				      datasize);
 	if (err) {
+		btrfs_abort_transaction(trans, err);
 		btrfs_free_path(path);
-		goto out_unlock;
+		discard_new_inode(inode);
+		inode = NULL;
+		goto out;
 	}
 	leaf = path->nodes[0];
 	ei = btrfs_item_ptr(leaf, path->slots[0],
@@ -9839,32 +9794,16 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
 	btrfs_mark_buffer_dirty(leaf);
 	btrfs_free_path(path);
 
-	inode_set_bytes(inode, name_len);
-	btrfs_i_size_write(BTRFS_I(inode), name_len);
-	err = btrfs_update_inode(trans, root, BTRFS_I(inode));
-	/*
-	 * Last step, add directory indexes for our symlink inode. This is the
-	 * last step to avoid extra cleanup of these indexes if an error happens
-	 * elsewhere above.
-	 */
-	if (!err)
-		err = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode),
-				     dentry->d_name.name, dentry->d_name.len, 0,
-				     index);
-	if (err)
-		goto out_unlock;
-
 	d_instantiate_new(dentry, inode);
-
-out_unlock:
+	err = 0;
+out:
 	btrfs_end_transaction(trans);
-	if (err && inode) {
-		inode_dec_link_count(inode);
-		discard_new_inode(inode);
-	}
 	btrfs_btree_balance_dirty(fs_info);
 out_new_inode_args:
 	btrfs_new_inode_args_destroy(&new_inode_args);
+out_inode:
+	if (err)
+		iput(inode);
 	return err;
 }
 
@@ -10127,7 +10066,6 @@ static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
 		.orphan = true,
 	};
 	unsigned int trans_num_items;
-	u64 index;
 	int ret;
 
 	inode = new_inode(dir->i_sb);
@@ -10140,37 +10078,16 @@ static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
 
 	new_inode_args.inode = inode;
 	ret = btrfs_new_inode_prepare(&new_inode_args, &trans_num_items);
-	if (ret) {
-		iput(inode);
-		return ret;
-	}
+	if (ret)
+		goto out_inode;
 
 	trans = btrfs_start_transaction(root, trans_num_items);
 	if (IS_ERR(trans)) {
-		iput(inode);
 		ret = PTR_ERR(trans);
 		goto out_new_inode_args;
 	}
 
-	ret = btrfs_create_new_inode(trans, &new_inode_args, &index);
-	if (ret) {
-		iput(inode);
-		inode = NULL;
-		goto out;
-	}
-
-	ret = btrfs_init_inode_security(trans, inode, dir, NULL,
-					new_inode_args.default_acl,
-					new_inode_args.acl);
-	if (ret)
-		goto out;
-
-	ret = btrfs_update_inode(trans, root, BTRFS_I(inode));
-	if (ret)
-		goto out;
-	ret = btrfs_orphan_add(trans, BTRFS_I(inode));
-	if (ret)
-		goto out;
+	ret = btrfs_create_new_inode(trans, &new_inode_args);
 
 	/*
 	 * We set number of links to 0 in btrfs_create_new_inode(), and here we
@@ -10180,16 +10097,20 @@ static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
 	 *    d_tmpfile() -> inode_dec_link_count() -> drop_nlink()
 	 */
 	set_nlink(inode, 1);
-	d_tmpfile(dentry, inode);
-	unlock_new_inode(inode);
-	mark_inode_dirty(inode);
-out:
+
+	if (!ret) {
+		d_tmpfile(dentry, inode);
+		unlock_new_inode(inode);
+		mark_inode_dirty(inode);
+	}
+
 	btrfs_end_transaction(trans);
-	if (ret && inode)
-		discard_new_inode(inode);
 	btrfs_btree_balance_dirty(fs_info);
 out_new_inode_args:
 	btrfs_new_inode_args_destroy(&new_inode_args);
+out_inode:
+	if (ret)
+		iput(inode);
 	return ret;
 }
 
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 07a74bbe3d84..24b3e384aa8f 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -574,8 +574,6 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
 				  struct inode *dir, struct dentry *dentry,
 				  struct btrfs_qgroup_inherit *inherit)
 {
-	const char *name = dentry->d_name.name;
-	int namelen = dentry->d_name.len;
 	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
 	struct btrfs_trans_handle *trans;
 	struct btrfs_key key;
@@ -595,7 +593,6 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
 	int ret;
 	dev_t anon_dev;
 	u64 objectid;
-	u64 index = 0;
 
 	root_item = kzalloc(sizeof(*root_item), GFP_KERNEL);
 	if (!root_item)
@@ -712,7 +709,6 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
 	free_extent_buffer(leaf);
 	leaf = NULL;
 
-	key.offset = (u64)-1;
 	new_root = btrfs_get_new_fs_root(fs_info, objectid, anon_dev);
 	if (IS_ERR(new_root)) {
 		ret = PTR_ERR(new_root);
@@ -730,47 +726,21 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
 		goto out;
 	}
 
-	ret = btrfs_create_subvol_root(trans, root, &new_inode_args);
-	if (ret) {
-		/* We potentially lose an unused inode item here */
-		btrfs_abort_transaction(trans, ret);
-		goto out;
-	}
-
-	/*
-	 * insert the directory item
-	 */
-	ret = btrfs_set_inode_index(BTRFS_I(dir), &index);
-	if (ret) {
-		btrfs_abort_transaction(trans, ret);
-		goto out;
-	}
-
-	ret = btrfs_insert_dir_item(trans, name, namelen, BTRFS_I(dir), &key,
-				    BTRFS_FT_DIR, index);
-	if (ret) {
-		btrfs_abort_transaction(trans, ret);
-		goto out;
-	}
-
-	btrfs_i_size_write(BTRFS_I(dir), dir->i_size + namelen * 2);
-	ret = btrfs_update_inode(trans, root, BTRFS_I(dir));
-	if (ret) {
-		btrfs_abort_transaction(trans, ret);
-		goto out;
-	}
-
-	ret = btrfs_add_root_ref(trans, objectid, root->root_key.objectid,
-				 btrfs_ino(BTRFS_I(dir)), index, name, namelen);
-	if (ret) {
-		btrfs_abort_transaction(trans, ret);
-		goto out;
-	}
-
 	ret = btrfs_uuid_tree_add(trans, root_item->uuid,
 				  BTRFS_UUID_KEY_SUBVOL, objectid);
-	if (ret)
+	if (ret) {
 		btrfs_abort_transaction(trans, ret);
+		goto out;
+	}
+
+	ret = btrfs_create_new_inode(trans, &new_inode_args);
+	if (ret) {
+		btrfs_abort_transaction(trans, ret);
+		goto out;
+	}
+
+	d_instantiate_new(dentry, new_inode_args.inode);
+	new_inode_args.inode = NULL;
 
 out:
 	trans->block_rsv = NULL;
@@ -781,11 +751,6 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
 		btrfs_end_transaction(trans);
 	else
 		ret = btrfs_commit_transaction(trans);
-
-	if (!ret) {
-		d_instantiate(dentry, new_inode_args.inode);
-		new_inode_args.inode = NULL;
-	}
 out_new_inode_args:
 	btrfs_new_inode_args_destroy(&new_inode_args);
 out_inode:
diff --git a/fs/btrfs/props.c b/fs/btrfs/props.c
index 1a6d2d5b4b33..f5565c296898 100644
--- a/fs/btrfs/props.c
+++ b/fs/btrfs/props.c
@@ -334,9 +334,8 @@ static struct prop_handler prop_handlers[] = {
 	},
 };
 
-static int inherit_props(struct btrfs_trans_handle *trans,
-			 struct inode *inode,
-			 struct inode *parent)
+int btrfs_inode_inherit_props(struct btrfs_trans_handle *trans,
+			      struct inode *inode, struct inode *parent)
 {
 	struct btrfs_root *root = BTRFS_I(inode)->root;
 	struct btrfs_fs_info *fs_info = root->fs_info;
@@ -408,41 +407,6 @@ static int inherit_props(struct btrfs_trans_handle *trans,
 	return 0;
 }
 
-int btrfs_inode_inherit_props(struct btrfs_trans_handle *trans,
-			      struct inode *inode,
-			      struct inode *dir)
-{
-	if (!dir)
-		return 0;
-
-	return inherit_props(trans, inode, dir);
-}
-
-int btrfs_subvol_inherit_props(struct btrfs_trans_handle *trans,
-			       struct btrfs_root *root,
-			       struct btrfs_root *parent_root)
-{
-	struct super_block *sb = root->fs_info->sb;
-	struct inode *parent_inode, *child_inode;
-	int ret;
-
-	parent_inode = btrfs_iget(sb, BTRFS_FIRST_FREE_OBJECTID, parent_root);
-	if (IS_ERR(parent_inode))
-		return PTR_ERR(parent_inode);
-
-	child_inode = btrfs_iget(sb, BTRFS_FIRST_FREE_OBJECTID, root);
-	if (IS_ERR(child_inode)) {
-		iput(parent_inode);
-		return PTR_ERR(child_inode);
-	}
-
-	ret = inherit_props(trans, child_inode, parent_inode);
-	iput(child_inode);
-	iput(parent_inode);
-
-	return ret;
-}
-
 void __init btrfs_props_init(void)
 {
 	int i;
diff --git a/fs/btrfs/props.h b/fs/btrfs/props.h
index 40b2c65b518c..1dcd5daa3b22 100644
--- a/fs/btrfs/props.h
+++ b/fs/btrfs/props.h
@@ -21,8 +21,4 @@ int btrfs_inode_inherit_props(struct btrfs_trans_handle *trans,
 			      struct inode *inode,
 			      struct inode *dir);
 
-int btrfs_subvol_inherit_props(struct btrfs_trans_handle *trans,
-			       struct btrfs_root *root,
-			       struct btrfs_root *parent_root);
-
 #endif
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 03/16] btrfs: fix anon_dev leak in create_subvol()
  2022-03-10  1:31 ` [PATCH v2 03/16] btrfs: fix anon_dev leak in create_subvol() Omar Sandoval
@ 2022-03-11 15:42   ` Sweet Tea Dorminy
  2022-03-12  0:29     ` Omar Sandoval
  0 siblings, 1 reply; 35+ messages in thread
From: Sweet Tea Dorminy @ 2022-03-11 15:42 UTC (permalink / raw)
  To: Omar Sandoval, linux-btrfs; +Cc: kernel-team


> +out_anon_dev:
>   	if (anon_dev)
>   		free_anon_bdev(anon_dev);

It looks to me as though the finer-grained cleanup means 
free_anon_bdev() can always be called with no conditional; if the code 
reaches this point in cleanup, anon_dev was populated by get_anon_bdev() 
(which must have returned zero, indicating successfully populating 
anon_dev).


Otherwise,

Reviewed-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>

and thanks.


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 13/16] btrfs: allocate inode outside of btrfs_new_inode()
  2022-03-10  1:31 ` [PATCH v2 13/16] btrfs: allocate inode outside of btrfs_new_inode() Omar Sandoval
@ 2022-03-11 17:11   ` Sweet Tea Dorminy
  2022-03-12  0:41     ` Omar Sandoval
  2022-03-14 23:33   ` Filipe Manana
  1 sibling, 1 reply; 35+ messages in thread
From: Sweet Tea Dorminy @ 2022-03-11 17:11 UTC (permalink / raw)
  To: Omar Sandoval, linux-btrfs; +Cc: kernel-team

On 3/9/22 20:31, Omar Sandoval wrote:
> From: Omar Sandoval <osandov@fb.com>
>
> Instead of calling new_inode() and inode_init_owner() inside of
> btrfs_new_inode(), do it in the callers. This allows us to pass in just
> the inode instead of the mnt_userns and mode and removes the need for
> memalloc_nofs_{save,restores}() since we do it before starting a
> transaction. This also paves the way for some more cleanups in later
> patches.
>
> This also removes the comments about Smack checking i_op, which are no
> longer true since commit 5d6c31910bc0 ("xattr: Add
> __vfs_{get,set,remove}xattr helpers"). Now it checks inode->i_opflags &
> IOP_XATTR, which is set based on sb->s_xattr.
>
> Signed-off-by: Omar Sandoval <osandov@fb.com>
> ---
>   fs/btrfs/ctree.h |   5 +-
>   fs/btrfs/inode.c | 284 +++++++++++++++++++++++++----------------------
>   fs/btrfs/ioctl.c |  22 ++--
>   3 files changed, 167 insertions(+), 144 deletions(-)
>
> diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
> index 4db17bd05a21..f39730420e8a 100644
> --- a/fs/btrfs/ctree.h
> +++ b/fs/btrfs/ctree.h
> @@ -3254,10 +3254,11 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, long nr,
>   int btrfs_set_extent_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
>   			      unsigned int extra_bits,
>   			      struct extent_state **cached_state);
> +struct inode *btrfs_new_subvol_inode(struct user_namespace *mnt_userns,
> +				     struct inode *dir);
>   int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
> -			     struct btrfs_root *new_root,
>   			     struct btrfs_root *parent_root,
> -			     struct user_namespace *mnt_userns);
> +			     struct inode *inode);
>    void btrfs_set_delalloc_extent(struct inode *inode, struct extent_state *state,
>   			       unsigned *bits);
>   void btrfs_clear_delalloc_extent(struct inode *inode,
> diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
> index c47bdada2440..ff780256c936 100644
> --- a/fs/btrfs/inode.c
> +++ b/fs/btrfs/inode.c
> @@ -6090,15 +6090,12 @@ static void btrfs_inherit_iflags(struct inode *inode, struct inode *dir)
>   	btrfs_sync_inode_flags_to_i_flags(inode);
>   }
>   
> -static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
> -				     struct btrfs_root *root,
> -				     struct user_namespace *mnt_userns,
> -				     struct inode *dir,
> -				     const char *name, int name_len,
> -				     umode_t mode, u64 *index)
> +static int btrfs_new_inode(struct btrfs_trans_handle *trans,
> +			   struct btrfs_root *root, struct inode *inode,
> +			   struct inode *dir, const char *name, int name_len,
> +			   u64 *index)


This is a triviality, but now that it doesn't allocate a new inode, I'm 
not sure it deserves the word 'new' in its name -- new_inode() does the 
allocation, and then inode_init_owner() initializes some part of the new 
inode, and then btrfs_new_inode() initializes the rest. Might it be 
worth renaming it something that emphasizes that it initializes a 
preallocated inode, btrfs_prepare/init/init_new/etc_inode()?

>   {
>   	struct btrfs_fs_info *fs_info = root->fs_info;
> -	struct inode *inode;
>   	struct btrfs_inode_item *inode_item;
>   	struct btrfs_key *location;
>   	struct btrfs_path *path;
> @@ -6108,20 +6105,11 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
>   	u32 sizes[2];
>   	struct btrfs_item_batch batch;
>   	unsigned long ptr;
> -	unsigned int nofs_flag;
>   	int ret;
>   
>   	path = btrfs_alloc_path();
>   	if (!path)
> -		return ERR_PTR(-ENOMEM);
> -
> -	nofs_flag = memalloc_nofs_save();
> -	inode = new_inode(fs_info->sb);
> -	memalloc_nofs_restore(nofs_flag);
> -	if (!inode) {
> -		btrfs_free_path(path);
> -		return ERR_PTR(-ENOMEM);
> -	}
> +		return -ENOMEM;
>   
>   	/*
>   	 * O_TMPFILE, set link count to 0, so that after this point,
> @@ -6133,8 +6121,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
>   	ret = btrfs_get_free_objectid(root, &objectid);
>   	if (ret) {
>   		btrfs_free_path(path);
> -		iput(inode);
> -		return ERR_PTR(ret);
> +		return ret;
>   	}
>   	inode->i_ino = objectid;
>   
> @@ -6144,8 +6131,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
>   		ret = btrfs_set_inode_index(BTRFS_I(dir), index);
>   		if (ret) {
>   			btrfs_free_path(path);
> -			iput(inode);
> -			return ERR_PTR(ret);
> +			return ret;
>   		}
>   	} else if (dir) {
>   		*index = 0;
> @@ -6163,7 +6149,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
>   
>   	btrfs_inherit_iflags(inode, dir);
>   
> -	if (S_ISREG(mode)) {
> +	if (S_ISREG(inode->i_mode)) {
>   		if (btrfs_test_opt(fs_info, NODATASUM))
>   			BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM;
>   		if (btrfs_test_opt(fs_info, NODATACOW))
> @@ -6208,10 +6194,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
>   	location->type = BTRFS_INODE_ITEM_KEY;
>   
>   	ret = btrfs_insert_inode_locked(inode);
> -	if (ret < 0) {
> -		iput(inode);
> +	if (ret < 0)
>   		goto fail;
> -	}
>   
>   	batch.keys = &key[0];
>   	batch.data_sizes = &sizes[0];
> @@ -6221,8 +6205,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
>   	if (ret != 0)
>   		goto fail_unlock;
>   
> -	inode_init_owner(mnt_userns, inode, dir, mode);
> -
>   	inode->i_mtime = current_time(inode);
>   	inode->i_atime = inode->i_mtime;
>   	inode->i_ctime = inode->i_mtime;
> @@ -6259,15 +6241,20 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
>   			  "error inheriting props for ino %llu (root %llu): %d",
>   			btrfs_ino(BTRFS_I(inode)), root->root_key.objectid, ret);
>   
> -	return inode;
> +	return 0;
>   
>   fail_unlock:
> +	/*
> +	 * discard_new_inode() calls iput(), but the caller owns the reference
> +	 * to the inode.
> +	 */
> +	ihold(inode);
>   	discard_new_inode(inode);
>   fail:
>   	if (dir && name)
>   		BTRFS_I(dir)->index_cnt--;
>   	btrfs_free_path(path);
> -	return ERR_PTR(ret);
> +	return ret;
>   }
>   
>   /*
> @@ -6365,37 +6352,36 @@ static int btrfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
>   	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
>   	struct btrfs_trans_handle *trans;
>   	struct btrfs_root *root = BTRFS_I(dir)->root;
> -	struct inode *inode = NULL;
> +	struct inode *inode;
>   	int err;
>   	u64 index = 0;
>   
> +	inode = new_inode(dir->i_sb);
> +	if (!inode)
> +		return -ENOMEM;
> +	inode_init_owner(mnt_userns, inode, dir, mode);
> +	inode->i_op = &btrfs_special_inode_operations;
> +	init_special_inode(inode, inode->i_mode, rdev);
> +
>   	/*
>   	 * 2 for inode item and ref
>   	 * 2 for dir items
>   	 * 1 for xattr if selinux is on
>   	 */
>   	trans = btrfs_start_transaction(root, 5);
> -	if (IS_ERR(trans))
> +	if (IS_ERR(trans)) {
> +		iput(inode);
>   		return PTR_ERR(trans);
> +	}
>   
> -	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
> -			dentry->d_name.name, dentry->d_name.len,
> -			mode, &index);
> -	if (IS_ERR(inode)) {
> -		err = PTR_ERR(inode);
> +	err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
> +			      dentry->d_name.len, &index);
> +	if (err) {
> +		iput(inode);
>   		inode = NULL;
>   		goto out_unlock;
>   	}
>   
> -	/*
> -	* If the active LSM wants to access the inode during
> -	* d_instantiate it needs these. Smack checks to see
> -	* if the filesystem supports xattrs by looking at the
> -	* ops vector.
> -	*/
> -	inode->i_op = &btrfs_special_inode_operations;
> -	init_special_inode(inode, inode->i_mode, rdev);
> -
>   	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
>   	if (err)
>   		goto out_unlock;
> @@ -6424,36 +6410,36 @@ static int btrfs_create(struct user_namespace *mnt_userns, struct inode *dir,
>   	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
>   	struct btrfs_trans_handle *trans;
>   	struct btrfs_root *root = BTRFS_I(dir)->root;
> -	struct inode *inode = NULL;
> +	struct inode *inode;
>   	int err;
>   	u64 index = 0;
>   
> +	inode = new_inode(dir->i_sb);
> +	if (!inode)
> +		return -ENOMEM;
> +	inode_init_owner(mnt_userns, inode, dir, mode);
> +	inode->i_fop = &btrfs_file_operations;
> +	inode->i_op = &btrfs_file_inode_operations;
> +	inode->i_mapping->a_ops = &btrfs_aops;
> +
>   	/*
>   	 * 2 for inode item and ref
>   	 * 2 for dir items
>   	 * 1 for xattr if selinux is on
>   	 */
>   	trans = btrfs_start_transaction(root, 5);
> -	if (IS_ERR(trans))
> +	if (IS_ERR(trans)) {
> +		iput(inode);
>   		return PTR_ERR(trans);
> +	}
>   
> -	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
> -			dentry->d_name.name, dentry->d_name.len,
> -			mode, &index);
> -	if (IS_ERR(inode)) {
> -		err = PTR_ERR(inode);
> +	err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
> +			      dentry->d_name.len, &index);
> +	if (err) {
> +		iput(inode);
>   		inode = NULL;
>   		goto out_unlock;
>   	}
> -	/*
> -	* If the active LSM wants to access the inode during
> -	* d_instantiate it needs these. Smack checks to see
> -	* if the filesystem supports xattrs by looking at the
> -	* ops vector.
> -	*/
> -	inode->i_fop = &btrfs_file_operations;
> -	inode->i_op = &btrfs_file_inode_operations;
> -	inode->i_mapping->a_ops = &btrfs_aops;
>   
>   	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
>   	if (err)
> @@ -6562,34 +6548,38 @@ static int btrfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
>   		       struct dentry *dentry, umode_t mode)
>   {
>   	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
> -	struct inode *inode = NULL;
> +	struct inode *inode;
>   	struct btrfs_trans_handle *trans;
>   	struct btrfs_root *root = BTRFS_I(dir)->root;
> -	int err = 0;
> +	int err;
>   	u64 index = 0;
>   
> +	inode = new_inode(dir->i_sb);
> +	if (!inode)
> +		return -ENOMEM;
> +	inode_init_owner(mnt_userns, inode, dir, S_IFDIR | mode);
> +	inode->i_op = &btrfs_dir_inode_operations;
> +	inode->i_fop = &btrfs_dir_file_operations;
> +
>   	/*
>   	 * 2 items for inode and ref
>   	 * 2 items for dir items
>   	 * 1 for xattr if selinux is on
>   	 */
>   	trans = btrfs_start_transaction(root, 5);
> -	if (IS_ERR(trans))
> +	if (IS_ERR(trans)) {
> +		iput(inode);
>   		return PTR_ERR(trans);
> +	}
>   
> -	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
> -			dentry->d_name.name, dentry->d_name.len,
> -			S_IFDIR | mode, &index);
> -	if (IS_ERR(inode)) {
> -		err = PTR_ERR(inode);
> +	err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
> +			      dentry->d_name.len, &index);
> +	if (err) {
> +		iput(inode);
>   		inode = NULL;
>   		goto out_fail;
>   	}
>   
> -	/* these must be set before we unlock the inode */
> -	inode->i_op = &btrfs_dir_inode_operations;
> -	inode->i_fop = &btrfs_dir_file_operations;
> -
>   	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
>   	if (err)
>   		goto out_fail;
> @@ -8747,25 +8737,39 @@ static int btrfs_truncate(struct inode *inode, bool skip_writeback)
>   	return ret;
>   }
>   
> +struct inode *btrfs_new_subvol_inode(struct user_namespace *mnt_userns,
> +				     struct inode *dir)
> +{
> +	struct inode *inode;
> +
> +	inode = new_inode(dir->i_sb);
> +	if (inode) {
> +		/*
> +		 * Subvolumes don't inherit the sgid bit or the parent's gid if
> +		 * the parent's sgid bit is set. This is probably a bug.
> +		 */
> +		inode_init_owner(mnt_userns, inode, NULL,
> +				 S_IFDIR | (~current_umask() & S_IRWXUGO));
> +		inode->i_op = &btrfs_dir_inode_operations;
> +		inode->i_fop = &btrfs_dir_file_operations;
> +	}
> +	return inode;
> +}
> +
>   /*
>    * create a new subvolume directory/inode (helper for the ioctl).
>    */
>   int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
> -			     struct btrfs_root *new_root,
>   			     struct btrfs_root *parent_root,
> -			     struct user_namespace *mnt_userns)
> +			     struct inode *inode)
>   {
> -	struct inode *inode;
> +	struct btrfs_root *new_root = BTRFS_I(inode)->root;
>   	int err;
>   	u64 index = 0;
>   
> -	inode = btrfs_new_inode(trans, new_root, mnt_userns, NULL, "..", 2,
> -				S_IFDIR | (~current_umask() & S_IRWXUGO),
> -				&index);
> -	if (IS_ERR(inode))
> -		return PTR_ERR(inode);
> -	inode->i_op = &btrfs_dir_inode_operations;
> -	inode->i_fop = &btrfs_dir_file_operations;
> +	err = btrfs_new_inode(trans, new_root, inode, NULL, "..", 2, &index);
> +	if (err)
> +		return err;
>   
>   	unlock_new_inode(inode);
>   
> @@ -8776,8 +8780,6 @@ int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
>   			  new_root->root_key.objectid, err);
>   
>   	err = btrfs_update_inode(trans, new_root, BTRFS_I(inode));
> -
> -	iput(inode);
>   	return err;
>   }
>   
> @@ -9254,31 +9256,36 @@ static int btrfs_rename_exchange(struct inode *old_dir,
>   	return ret;
>   }
>   
> +static struct inode *new_whiteout_inode(struct user_namespace *mnt_userns,
> +					struct inode *dir)
> +{
> +	struct inode *inode;
> +
> +	inode = new_inode(dir->i_sb);
> +	if (inode) {
> +		inode_init_owner(mnt_userns, inode, dir,
> +				 S_IFCHR | WHITEOUT_MODE);
> +		inode->i_op = &btrfs_special_inode_operations;
> +		init_special_inode(inode, inode->i_mode, WHITEOUT_DEV);
> +	}
> +	return inode;
> +}
> +
>   static int btrfs_whiteout_for_rename(struct btrfs_trans_handle *trans,
>   				     struct btrfs_root *root,
> -				     struct user_namespace *mnt_userns,
> -				     struct inode *dir,
> +				     struct inode *inode, struct inode *dir,
>   				     struct dentry *dentry)
>   {
>   	int ret;
> -	struct inode *inode;
>   	u64 index;
>   
> -	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
> -				dentry->d_name.name,
> -				dentry->d_name.len,
> -				S_IFCHR | WHITEOUT_MODE,
> -				&index);
> -
> -	if (IS_ERR(inode)) {
> -		ret = PTR_ERR(inode);
> +	ret = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
> +			      dentry->d_name.len, &index);
> +	if (ret) {
> +		iput(inode);
>   		return ret;
>   	}
>   
> -	inode->i_op = &btrfs_special_inode_operations;
> -	init_special_inode(inode, inode->i_mode,
> -		WHITEOUT_DEV);
> -
>   	ret = btrfs_init_inode_security(trans, inode, dir,
>   				&dentry->d_name);
>   	if (ret)
> @@ -9305,6 +9312,7 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
>   			unsigned int flags)
>   {
>   	struct btrfs_fs_info *fs_info = btrfs_sb(old_dir->i_sb);
> +	struct inode *whiteout_inode;
>   	struct btrfs_trans_handle *trans;
>   	unsigned int trans_num_items;
>   	struct btrfs_root *root = BTRFS_I(old_dir)->root;
> @@ -9359,6 +9367,12 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
>   	if (new_inode && S_ISREG(old_inode->i_mode) && new_inode->i_size)
>   		filemap_flush(old_inode->i_mapping);
>   
> +	if (flags & RENAME_WHITEOUT) {
> +		whiteout_inode = new_whiteout_inode(mnt_userns, old_dir);
> +		if (!whiteout_inode)
> +			return -ENOMEM;
> +	}
> +
>   	if (old_ino == BTRFS_FIRST_FREE_OBJECTID) {
>   		/* close the racy window with snapshot create/destroy ioctl */
>   		down_read(&fs_info->subvol_sem);
> @@ -9495,9 +9509,9 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
>   				   rename_ctx.index, new_dentry->d_parent);
>   
>   	if (flags & RENAME_WHITEOUT) {
> -		ret = btrfs_whiteout_for_rename(trans, root, mnt_userns,
> +		ret = btrfs_whiteout_for_rename(trans, root, whiteout_inode,
>   						old_dir, old_dentry);
> -
> +		whiteout_inode = NULL;
>   		if (ret) {
>   			btrfs_abort_transaction(trans, ret);
>   			goto out_fail;
> @@ -9509,7 +9523,8 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
>   out_notrans:
>   	if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
>   		up_read(&fs_info->subvol_sem);
> -
> +	if (flags & RENAME_WHITEOUT)
> +		iput(whiteout_inode);
>   	return ret;
>   }
>   
> @@ -9728,7 +9743,7 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
>   	struct btrfs_root *root = BTRFS_I(dir)->root;
>   	struct btrfs_path *path;
>   	struct btrfs_key key;
> -	struct inode *inode = NULL;
> +	struct inode *inode;
>   	int err;
>   	u64 index = 0;
>   	int name_len;
> @@ -9741,6 +9756,14 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
>   	if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(fs_info))
>   		return -ENAMETOOLONG;
>   
> +	inode = new_inode(dir->i_sb);
> +	if (!inode)
> +		return -ENOMEM;
> +	inode_init_owner(mnt_userns, inode, dir, S_IFLNK | S_IRWXUGO);
> +	inode->i_op = &btrfs_symlink_inode_operations;
> +	inode_nohighmem(inode);
> +	inode->i_mapping->a_ops = &btrfs_aops;
> +
>   	/*
>   	 * 2 items for inode item and ref
>   	 * 2 items for dir items
> @@ -9749,28 +9772,19 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
>   	 * 1 item for xattr if selinux is on
>   	 */
>   	trans = btrfs_start_transaction(root, 7);
> -	if (IS_ERR(trans))
> +	if (IS_ERR(trans)) {
> +		iput(inode);
>   		return PTR_ERR(trans);
> +	}
>   
> -	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
> -				dentry->d_name.name, dentry->d_name.len,
> -				S_IFLNK | S_IRWXUGO, &index);
> -	if (IS_ERR(inode)) {
> -		err = PTR_ERR(inode);
> +	err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
> +			      dentry->d_name.len, &index);
> +	if (err) {
> +		iput(inode);
>   		inode = NULL;
>   		goto out_unlock;
>   	}
>   
> -	/*
> -	* If the active LSM wants to access the inode during
> -	* d_instantiate it needs these. Smack checks to see
> -	* if the filesystem supports xattrs by looking at the
> -	* ops vector.
> -	*/
> -	inode->i_fop = &btrfs_file_operations;
> -	inode->i_op = &btrfs_file_inode_operations;
> -	inode->i_mapping->a_ops = &btrfs_aops;
> -
>   	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
>   	if (err)
>   		goto out_unlock;
> @@ -9806,8 +9820,6 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
>   	btrfs_mark_buffer_dirty(leaf);
>   	btrfs_free_path(path);
>   
> -	inode->i_op = &btrfs_symlink_inode_operations;
> -	inode_nohighmem(inode);
>   	inode_set_bytes(inode, name_len);
>   	btrfs_i_size_write(BTRFS_I(inode), name_len);
>   	err = btrfs_update_inode(trans, root, BTRFS_I(inode));
> @@ -10087,30 +10099,34 @@ static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
>   	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
>   	struct btrfs_trans_handle *trans;
>   	struct btrfs_root *root = BTRFS_I(dir)->root;
> -	struct inode *inode = NULL;
> +	struct inode *inode;
>   	u64 index;
> -	int ret = 0;
> +	int ret;
> +
> +	inode = new_inode(dir->i_sb);
> +	if (!inode)
> +		return -ENOMEM;
> +	inode_init_owner(mnt_userns, inode, dir, mode);
> +	inode->i_fop = &btrfs_file_operations;
> +	inode->i_op = &btrfs_file_inode_operations;
> +	inode->i_mapping->a_ops = &btrfs_aops;
>   
>   	/*
>   	 * 5 units required for adding orphan entry
>   	 */
>   	trans = btrfs_start_transaction(root, 5);
> -	if (IS_ERR(trans))
> +	if (IS_ERR(trans)) {
> +		iput(inode);
>   		return PTR_ERR(trans);
> +	}
>   
> -	inode = btrfs_new_inode(trans, root, mnt_userns, dir, NULL, 0,
> -			mode, &index);
> -	if (IS_ERR(inode)) {
> -		ret = PTR_ERR(inode);
> +	ret = btrfs_new_inode(trans, root, inode, dir, NULL, 0, &index);
> +	if (ret) {
> +		iput(inode);
>   		inode = NULL;
>   		goto out;
>   	}
>   
> -	inode->i_fop = &btrfs_file_operations;
> -	inode->i_op = &btrfs_file_inode_operations;
> -
> -	inode->i_mapping->a_ops = &btrfs_aops;
> -
>   	ret = btrfs_init_inode_security(trans, inode, dir, NULL);
>   	if (ret)
>   		goto out;
> diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
> index 891352fd6d0f..60c907b14547 100644
> --- a/fs/btrfs/ioctl.c
> +++ b/fs/btrfs/ioctl.c
> @@ -587,6 +587,12 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
>   	if (ret < 0)
>   		goto out_root_item;
>   
> +	inode = btrfs_new_subvol_inode(mnt_userns, dir);
> +	if (!inode) {
> +		ret = -ENOMEM;
> +		goto out_anon_dev;
> +	}
> +
>   	btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP);
>   	/*
>   	 * The same as the snapshot creation, please see the comment
> @@ -594,13 +600,13 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
>   	 */
>   	ret = btrfs_subvolume_reserve_metadata(root, &block_rsv, 8, false);
>   	if (ret)
> -		goto out_anon_dev;
> +		goto out_inode;
>   
>   	trans = btrfs_start_transaction(root, 0);
>   	if (IS_ERR(trans)) {
>   		ret = PTR_ERR(trans);
>   		btrfs_subvolume_release_metadata(root, &block_rsv);
> -		goto out_anon_dev;
> +		goto out_inode;
>   	}
>   	trans->block_rsv = &block_rsv;
>   	trans->bytes_reserved = block_rsv.size;
> @@ -683,16 +689,16 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
>   	}
>   	/* anon_dev is owned by new_root now. */
>   	anon_dev = 0;
> +	BTRFS_I(inode)->root = new_root;
> +	/* ... and new_root is owned by inode now. */
>   
>   	ret = btrfs_record_root_in_trans(trans, new_root);
>   	if (ret) {
> -		btrfs_put_root(new_root);
>   		btrfs_abort_transaction(trans, ret);
>   		goto out;
>   	}
>   
> -	ret = btrfs_create_subvol_root(trans, new_root, root, mnt_userns);
> -	btrfs_put_root(new_root);
> +	ret = btrfs_create_subvol_root(trans, root, inode);
>   	if (ret) {
>   		/* We potentially lose an unused inode item here */
>   		btrfs_abort_transaction(trans, ret);
> @@ -745,11 +751,11 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
>   		ret = btrfs_commit_transaction(trans);
>   
>   	if (!ret) {
> -		inode = btrfs_lookup_dentry(dir, dentry);
> -		if (IS_ERR(inode))
> -			return PTR_ERR(inode);
>   		d_instantiate(dentry, inode);
> +		inode = NULL;
>   	}

I don't understand this. Why do we not need to look up the dentry 
anymore?  Was that always unneeded?

I think it's slightly clearer if the conditionals are adjusted:

if (!ret)
     d_instantiate(dentry, inode);

out_inode:
     if (ret)
         iput(inode);

...

to emphasize the iput() only being needed in failure cases, instead of 
relying on iput doing rightly on nulls, but shrug.

> +out_inode:
> +	iput(inode);
>   out_anon_dev:
>   	if (anon_dev)
>   		free_anon_bdev(anon_dev);

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 14/16] btrfs: factor out common part of btrfs_{mknod,create,mkdir}()
  2022-03-10  1:31 ` [PATCH v2 14/16] btrfs: factor out common part of btrfs_{mknod,create,mkdir}() Omar Sandoval
@ 2022-03-11 17:43   ` Sweet Tea Dorminy
  0 siblings, 0 replies; 35+ messages in thread
From: Sweet Tea Dorminy @ 2022-03-11 17:43 UTC (permalink / raw)
  To: Omar Sandoval, linux-btrfs; +Cc: kernel-team


On 3/9/22 20:31, Omar Sandoval wrote:
> From: Omar Sandoval <osandov@fb.com>
>
> btrfs_{mknod,create,mkdir}() are now identical other than the inode
> initialization and some inconsequential function call order differences.
> Factor out the common code to reduce code duplication.
>
> Signed-off-by: Omar Sandoval <osandov@fb.com>
Reviewed-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
> ---
>   fs/btrfs/inode.c | 152 ++++++++++-------------------------------------
>   1 file changed, 33 insertions(+), 119 deletions(-)
>
> diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
> index ff780256c936..bea2cb2d90a5 100644
> --- a/fs/btrfs/inode.c
> +++ b/fs/btrfs/inode.c
> @@ -6346,82 +6346,15 @@ int btrfs_add_link(struct btrfs_trans_handle *trans,
>   	return ret;
>   }
>   
> -static int btrfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
> -		       struct dentry *dentry, umode_t mode, dev_t rdev)
> +static int btrfs_create_common(struct inode *dir, struct dentry *dentry,
> +			       struct inode *inode)
>   {
>   	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
> -	struct btrfs_trans_handle *trans;
>   	struct btrfs_root *root = BTRFS_I(dir)->root;
> -	struct inode *inode;
> +	struct btrfs_trans_handle *trans;
>   	int err;
>   	u64 index = 0;
>   
> -	inode = new_inode(dir->i_sb);
> -	if (!inode)
> -		return -ENOMEM;
> -	inode_init_owner(mnt_userns, inode, dir, mode);
> -	inode->i_op = &btrfs_special_inode_operations;
> -	init_special_inode(inode, inode->i_mode, rdev);
> -
> -	/*
> -	 * 2 for inode item and ref
> -	 * 2 for dir items
> -	 * 1 for xattr if selinux is on
> -	 */
> -	trans = btrfs_start_transaction(root, 5);
> -	if (IS_ERR(trans)) {
> -		iput(inode);
> -		return PTR_ERR(trans);
> -	}
> -
> -	err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
> -			      dentry->d_name.len, &index);
> -	if (err) {
> -		iput(inode);
> -		inode = NULL;
> -		goto out_unlock;
> -	}
> -
> -	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
> -	if (err)
> -		goto out_unlock;
> -
> -	err = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode),
> -			     dentry->d_name.name, dentry->d_name.len, 0, index);
> -	if (err)
> -		goto out_unlock;
> -
> -	btrfs_update_inode(trans, root, BTRFS_I(inode));
> -	d_instantiate_new(dentry, inode);
> -
> -out_unlock:
> -	btrfs_end_transaction(trans);
> -	btrfs_btree_balance_dirty(fs_info);
> -	if (err && inode) {
> -		inode_dec_link_count(inode);
> -		discard_new_inode(inode);
> -	}
> -	return err;
> -}
> -
> -static int btrfs_create(struct user_namespace *mnt_userns, struct inode *dir,
> -			struct dentry *dentry, umode_t mode, bool excl)
> -{
> -	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
> -	struct btrfs_trans_handle *trans;
> -	struct btrfs_root *root = BTRFS_I(dir)->root;
> -	struct inode *inode;
> -	int err;
> -	u64 index = 0;
> -
> -	inode = new_inode(dir->i_sb);
> -	if (!inode)
> -		return -ENOMEM;
> -	inode_init_owner(mnt_userns, inode, dir, mode);
> -	inode->i_fop = &btrfs_file_operations;
> -	inode->i_op = &btrfs_file_inode_operations;
> -	inode->i_mapping->a_ops = &btrfs_aops;
> -
>   	/*
>   	 * 2 for inode item and ref
>   	 * 2 for dir items
> @@ -6466,6 +6399,35 @@ static int btrfs_create(struct user_namespace *mnt_userns, struct inode *dir,
>   	return err;
>   }
>   
> +static int btrfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
> +		       struct dentry *dentry, umode_t mode, dev_t rdev)
> +{
> +	struct inode *inode;
> +
> +	inode = new_inode(dir->i_sb);
> +	if (!inode)
> +		return -ENOMEM;
> +	inode_init_owner(mnt_userns, inode, dir, mode);
> +	inode->i_op = &btrfs_special_inode_operations;
> +	init_special_inode(inode, inode->i_mode, rdev);
> +	return btrfs_create_common(dir, dentry, inode);
> +}
> +
> +static int btrfs_create(struct user_namespace *mnt_userns, struct inode *dir,
> +			struct dentry *dentry, umode_t mode, bool excl)
> +{
> +	struct inode *inode;
> +
> +	inode = new_inode(dir->i_sb);
> +	if (!inode)
> +		return -ENOMEM;
> +	inode_init_owner(mnt_userns, inode, dir, mode);
> +	inode->i_fop = &btrfs_file_operations;
> +	inode->i_op = &btrfs_file_inode_operations;
> +	inode->i_mapping->a_ops = &btrfs_aops;
> +	return btrfs_create_common(dir, dentry, inode);
> +}
> +
>   static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
>   		      struct dentry *dentry)
>   {
> @@ -6547,12 +6509,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
>   static int btrfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
>   		       struct dentry *dentry, umode_t mode)
>   {
> -	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
>   	struct inode *inode;
> -	struct btrfs_trans_handle *trans;
> -	struct btrfs_root *root = BTRFS_I(dir)->root;
> -	int err;
> -	u64 index = 0;
>   
>   	inode = new_inode(dir->i_sb);
>   	if (!inode)
> @@ -6560,50 +6517,7 @@ static int btrfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
>   	inode_init_owner(mnt_userns, inode, dir, S_IFDIR | mode);
>   	inode->i_op = &btrfs_dir_inode_operations;
>   	inode->i_fop = &btrfs_dir_file_operations;
> -
> -	/*
> -	 * 2 items for inode and ref
> -	 * 2 items for dir items
> -	 * 1 for xattr if selinux is on
> -	 */
> -	trans = btrfs_start_transaction(root, 5);
> -	if (IS_ERR(trans)) {
> -		iput(inode);
> -		return PTR_ERR(trans);
> -	}
> -
> -	err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
> -			      dentry->d_name.len, &index);
> -	if (err) {
> -		iput(inode);
> -		inode = NULL;
> -		goto out_fail;
> -	}
> -
> -	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
> -	if (err)
> -		goto out_fail;
> -
> -	err = btrfs_update_inode(trans, root, BTRFS_I(inode));
> -	if (err)
> -		goto out_fail;
> -
> -	err = btrfs_add_link(trans, BTRFS_I(dir), BTRFS_I(inode),
> -			dentry->d_name.name,
> -			dentry->d_name.len, 0, index);
> -	if (err)
> -		goto out_fail;
> -
> -	d_instantiate_new(dentry, inode);
> -
> -out_fail:
> -	btrfs_end_transaction(trans);
> -	if (err && inode) {
> -		inode_dec_link_count(inode);
> -		discard_new_inode(inode);
> -	}
> -	btrfs_btree_balance_dirty(fs_info);
> -	return err;
> +	return btrfs_create_common(dir, dentry, inode);
>   }
>   
>   static noinline int uncompress_inline(struct btrfs_path *path,

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 15/16] btrfs: reserve correct number of items for inode creation
  2022-03-10  1:31 ` [PATCH v2 15/16] btrfs: reserve correct number of items for inode creation Omar Sandoval
@ 2022-03-11 17:56   ` Sweet Tea Dorminy
  2022-03-12  0:45     ` Omar Sandoval
  0 siblings, 1 reply; 35+ messages in thread
From: Sweet Tea Dorminy @ 2022-03-11 17:56 UTC (permalink / raw)
  To: Omar Sandoval, linux-btrfs; +Cc: kernel-team


On 3/9/22 20:31, Omar Sandoval wrote:
> From: Omar Sandoval <osandov@fb.com>
>
> The various inode creation code paths do not account for the compression
> property, POSIX ACLs, or the parent inode item when starting a
> transaction. Fix it by refactoring all of these code paths to use a new
> function, btrfs_new_inode_prepare(), which computes the correct number
> of items. To do so, it needs to know whether POSIX ACLs will be created,
> so move the ACL creation into that function. To reduce the number of
> arguments that need to be passed around for inode creation, define
> struct btrfs_new_inode_args containing all of the relevant information.
>
> btrfs_new_inode_prepare() will also be a good place to set up the
> fscrypt context and encrypted filename in the future.
>
> Signed-off-by: Omar Sandoval <osandov@fb.com>
> ---
>   fs/btrfs/acl.c   |  36 +------
>   fs/btrfs/ctree.h |  34 +++++--
>   fs/btrfs/inode.c | 256 ++++++++++++++++++++++++++++++++++-------------
>   fs/btrfs/ioctl.c |  83 ++++++++++-----
>   4 files changed, 277 insertions(+), 132 deletions(-)
>
> diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c
> index a6909ec9bc38..548d6a5477b4 100644
> --- a/fs/btrfs/acl.c
> +++ b/fs/btrfs/acl.c
> @@ -55,8 +55,8 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu)
>   	return acl;
>   }
>   
> -static int __btrfs_set_acl(struct btrfs_trans_handle *trans,
> -			   struct inode *inode, struct posix_acl *acl, int type)
> +int __btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode,
> +		    struct posix_acl *acl, int type)
>   {
>   	int ret, size = 0;
>   	const char *name;
> @@ -127,35 +127,3 @@ int btrfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
>   		inode->i_mode = old_mode;
>   	return ret;
>   }
> -
> -int btrfs_init_acl(struct btrfs_trans_handle *trans,
> -		   struct inode *inode, struct inode *dir)
> -{
> -	struct posix_acl *default_acl, *acl;
> -	int ret = 0;
> -
> -	/* this happens with subvols */
> -	if (!dir)
> -		return 0;
> -
> -	ret = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
> -	if (ret)
> -		return ret;
> -
> -	if (default_acl) {
> -		ret = __btrfs_set_acl(trans, inode, default_acl,
> -				      ACL_TYPE_DEFAULT);
> -		posix_acl_release(default_acl);
> -	}
> -
> -	if (acl) {
> -		if (!ret)
> -			ret = __btrfs_set_acl(trans, inode, acl,
> -					      ACL_TYPE_ACCESS);
> -		posix_acl_release(acl);
> -	}
> -
> -	if (!default_acl && !acl)
> -		cache_no_acl(inode);
> -	return ret;
> -}
> diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
> index f39730420e8a..322c02610e9e 100644
> --- a/fs/btrfs/ctree.h
> +++ b/fs/btrfs/ctree.h
> @@ -3254,11 +3254,32 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, long nr,
>   int btrfs_set_extent_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
>   			      unsigned int extra_bits,
>   			      struct extent_state **cached_state);
> +struct btrfs_new_inode_args {
> +	/* Input */
> +	struct inode *dir;
> +	struct dentry *dentry;
> +	struct inode *inode;
> +	bool orphan;
> +	bool subvol;
> +
> +	/*
> +	 * Output from btrfs_new_inode_prepare(), input to
> +	 * btrfs_create_new_inode().
> +	 */
> +	struct posix_acl *default_acl;
> +	struct posix_acl *acl;
> +};
> +int btrfs_new_inode_prepare(struct btrfs_new_inode_args *args,
> +			    unsigned int *trans_num_items);
> +int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
> +			   struct btrfs_new_inode_args *args,
> +			   u64 *index);
> +void btrfs_new_inode_args_destroy(struct btrfs_new_inode_args *args);
>   struct inode *btrfs_new_subvol_inode(struct user_namespace *mnt_userns,
>   				     struct inode *dir);
>   int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
>   			     struct btrfs_root *parent_root,
> -			     struct inode *inode);
> +			     struct btrfs_new_inode_args *args);
>    void btrfs_set_delalloc_extent(struct inode *inode, struct extent_state *state,
>   			       unsigned *bits);
>   void btrfs_clear_delalloc_extent(struct inode *inode,
> @@ -3816,15 +3837,16 @@ static inline int __btrfs_fs_compat_ro(struct btrfs_fs_info *fs_info, u64 flag)
>   struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu);
>   int btrfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
>   		  struct posix_acl *acl, int type);
> -int btrfs_init_acl(struct btrfs_trans_handle *trans,
> -		   struct inode *inode, struct inode *dir);
> +int __btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode,
> +		    struct posix_acl *acl, int type);
>   #else
>   #define btrfs_get_acl NULL
>   #define btrfs_set_acl NULL
> -static inline int btrfs_init_acl(struct btrfs_trans_handle *trans,
> -				 struct inode *inode, struct inode *dir)
> +static inline int __btrfs_set_acl(struct btrfs_trans_handle *trans,
> +				  struct inode *inode, struct posix_acl *acl,
> +				  int type)
>   {
> -	return 0;
> +	return -EOPNOTSUPP;
>   }
>   #endif
>   
> diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
> index bea2cb2d90a5..e2b1b1969d0b 100644
> --- a/fs/btrfs/inode.c
> +++ b/fs/btrfs/inode.c
> @@ -223,14 +223,26 @@ static int btrfs_dirty_inode(struct inode *inode);
>   
>   static int btrfs_init_inode_security(struct btrfs_trans_handle *trans,
>   				     struct inode *inode,  struct inode *dir,
> -				     const struct qstr *qstr)
> +				     const struct qstr *qstr,
> +				     struct posix_acl *default_acl,
> +				     struct posix_acl *acl)
>   {
>   	int err;
>   
> -	err = btrfs_init_acl(trans, inode, dir);
> -	if (!err)
> -		err = btrfs_xattr_security_init(trans, inode, dir, qstr);
> -	return err;
> +	if (default_acl) {
> +		err = __btrfs_set_acl(trans, inode, default_acl,
> +				      ACL_TYPE_DEFAULT);
> +		if (err)
> +			return err;
> +	}
> +	if (acl) {
> +		err = __btrfs_set_acl(trans, inode, acl, ACL_TYPE_ACCESS);
> +		if (err)
> +			return err;
> +	}
> +	if (!default_acl && !acl)
> +		cache_no_acl(inode);
> +	return btrfs_xattr_security_init(trans, inode, dir, qstr);
>   }


Would it be worth making this take a btrfs_new_inode_args also, since 
basically everything it needs is contained therein? I think the only 
place calling btrfs_init_inode_security() with params not just pulled 
out of the btrfs_new_inode_args is btrfs_tempfile, which is passing a 
NULL name instead of &dentry->d_name; I'm not clear on why in that case 
it's different...

Either way,

Reviewed-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 16/16] btrfs: move common inode creation code into btrfs_create_new_inode()
  2022-03-10  1:31 ` [PATCH v2 16/16] btrfs: move common inode creation code into btrfs_create_new_inode() Omar Sandoval
@ 2022-03-11 18:04   ` Sweet Tea Dorminy
  0 siblings, 0 replies; 35+ messages in thread
From: Sweet Tea Dorminy @ 2022-03-11 18:04 UTC (permalink / raw)
  To: Omar Sandoval, linux-btrfs; +Cc: kernel-team


On 3/9/22 20:31, Omar Sandoval wrote:
> From: Omar Sandoval <osandov@fb.com>
>
> All of our inode creation code paths duplicate the calls to
> btrfs_init_inode_security() and btrfs_add_link(). Subvolume creation
> additionally duplicates property inheritance and the call to
> btrfs_set_inode_index(). Fix this by moving the common code into
> btrfs_create_new_inode(). This accomplishes a few things at once:
>
> 1. It reduces code duplication.
> 2. It allows us to set up the inode completely before inserting the
>     inode item, removing calls to btrfs_update_inode().
> 3. It fixes a leak of an inode on disk in some error cases. For example,
>     in btrfs_create(), if btrfs_new_inode() succeeds, then we have
>     inserted an inode item and its inode ref. However, if something after
>     that fails (e.g., btrfs_init_inode_security()), then we end the
>     transaction and then decrement the link count on the inode. If the
>     transaction is committed and the system crashes before the failed
>     inode is deleted, then we leak that inode on disk. Instead, this
>     refactoring aborts the transaction when we can't recover more
>     gracefully.
> 4. It exposes various ways that subvolume creation diverges from mkdir
>     in terms of inheriting flags, properties, permissions, and POSIX
>     ACLs, a lot of which appears to be accidental. This patch explicitly
>     does _not_ change the existing non-standard behavior, but it makes
>     those differences more clear in the code and documents them so that
>     we can discuss whether they should be changed.
>
> Signed-off-by: Omar Sandoval <osandov@fb.com>
Reviewed-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 03/16] btrfs: fix anon_dev leak in create_subvol()
  2022-03-11 15:42   ` Sweet Tea Dorminy
@ 2022-03-12  0:29     ` Omar Sandoval
  2022-03-12  1:43       ` Sweet Tea Dorminy
  0 siblings, 1 reply; 35+ messages in thread
From: Omar Sandoval @ 2022-03-12  0:29 UTC (permalink / raw)
  To: Sweet Tea Dorminy; +Cc: linux-btrfs, kernel-team

On Fri, Mar 11, 2022 at 10:42:14AM -0500, Sweet Tea Dorminy wrote:
> 
> > +out_anon_dev:
> >   	if (anon_dev)
> >   		free_anon_bdev(anon_dev);
> 
> It looks to me as though the finer-grained cleanup means free_anon_bdev()
> can always be called with no conditional; if the code reaches this point in
> cleanup, anon_dev was populated by get_anon_bdev() (which must have returned
> zero, indicating successfully populating anon_dev).

The conditional is required because halfway through the function, we
assign the anon_dev to a struct btrfs_root, which means that the
anon_dev will be freed when the root is freed:

	new_root = btrfs_get_new_fs_root(fs_info, objectid, anon_dev);
	if (IS_ERR(new_root)) {
		ret = PTR_ERR(new_root);
		btrfs_abort_transaction(trans, ret);
		goto out;
	}
	/* anon_dev is owned by new_root now. */
	anon_dev = 0;

> Otherwise,
> 
> Reviewed-by: Sweet Tea Dorminy <sweettea-kernel@dorminy.me>
> 
> and thanks.

Thanks!

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 13/16] btrfs: allocate inode outside of btrfs_new_inode()
  2022-03-11 17:11   ` Sweet Tea Dorminy
@ 2022-03-12  0:41     ` Omar Sandoval
  2022-03-14 14:43       ` Sweet Tea Dorminy
  0 siblings, 1 reply; 35+ messages in thread
From: Omar Sandoval @ 2022-03-12  0:41 UTC (permalink / raw)
  To: Sweet Tea Dorminy; +Cc: linux-btrfs, kernel-team

On Fri, Mar 11, 2022 at 12:11:03PM -0500, Sweet Tea Dorminy wrote:
> On 3/9/22 20:31, Omar Sandoval wrote:
> > From: Omar Sandoval <osandov@fb.com>
> > 
> > Instead of calling new_inode() and inode_init_owner() inside of
> > btrfs_new_inode(), do it in the callers. This allows us to pass in just
> > the inode instead of the mnt_userns and mode and removes the need for
> > memalloc_nofs_{save,restores}() since we do it before starting a
> > transaction. This also paves the way for some more cleanups in later
> > patches.
> > 
> > This also removes the comments about Smack checking i_op, which are no
> > longer true since commit 5d6c31910bc0 ("xattr: Add
> > __vfs_{get,set,remove}xattr helpers"). Now it checks inode->i_opflags &
> > IOP_XATTR, which is set based on sb->s_xattr.
> > 
> > Signed-off-by: Omar Sandoval <osandov@fb.com>
> > ---
> >   fs/btrfs/ctree.h |   5 +-
> >   fs/btrfs/inode.c | 284 +++++++++++++++++++++++++----------------------
> >   fs/btrfs/ioctl.c |  22 ++--
> >   3 files changed, 167 insertions(+), 144 deletions(-)
> > 
> > diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
> > index 4db17bd05a21..f39730420e8a 100644
> > --- a/fs/btrfs/ctree.h
> > +++ b/fs/btrfs/ctree.h
> > @@ -3254,10 +3254,11 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, long nr,
> >   int btrfs_set_extent_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
> >   			      unsigned int extra_bits,
> >   			      struct extent_state **cached_state);
> > +struct inode *btrfs_new_subvol_inode(struct user_namespace *mnt_userns,
> > +				     struct inode *dir);
> >   int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
> > -			     struct btrfs_root *new_root,
> >   			     struct btrfs_root *parent_root,
> > -			     struct user_namespace *mnt_userns);
> > +			     struct inode *inode);
> >    void btrfs_set_delalloc_extent(struct inode *inode, struct extent_state *state,
> >   			       unsigned *bits);
> >   void btrfs_clear_delalloc_extent(struct inode *inode,
> > diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
> > index c47bdada2440..ff780256c936 100644
> > --- a/fs/btrfs/inode.c
> > +++ b/fs/btrfs/inode.c
> > @@ -6090,15 +6090,12 @@ static void btrfs_inherit_iflags(struct inode *inode, struct inode *dir)
> >   	btrfs_sync_inode_flags_to_i_flags(inode);
> >   }
> > -static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
> > -				     struct btrfs_root *root,
> > -				     struct user_namespace *mnt_userns,
> > -				     struct inode *dir,
> > -				     const char *name, int name_len,
> > -				     umode_t mode, u64 *index)
> > +static int btrfs_new_inode(struct btrfs_trans_handle *trans,
> > +			   struct btrfs_root *root, struct inode *inode,
> > +			   struct inode *dir, const char *name, int name_len,
> > +			   u64 *index)
> 
> 
> This is a triviality, but now that it doesn't allocate a new inode, I'm not
> sure it deserves the word 'new' in its name -- new_inode() does the
> allocation, and then inode_init_owner() initializes some part of the new
> inode, and then btrfs_new_inode() initializes the rest. Might it be worth
> renaming it something that emphasizes that it initializes a preallocated
> inode, btrfs_prepare/init/init_new/etc_inode()?

One of the later changes renames it to btrfs_create_new_inode(). I.e.,
it creates (on disk) a new inode that you allocated.

> >   {
> >   	struct btrfs_fs_info *fs_info = root->fs_info;
> > -	struct inode *inode;
> >   	struct btrfs_inode_item *inode_item;
> >   	struct btrfs_key *location;
> >   	struct btrfs_path *path;
> > @@ -6108,20 +6105,11 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
> >   	u32 sizes[2];
> >   	struct btrfs_item_batch batch;
> >   	unsigned long ptr;
> > -	unsigned int nofs_flag;
> >   	int ret;
> >   	path = btrfs_alloc_path();
> >   	if (!path)
> > -		return ERR_PTR(-ENOMEM);
> > -
> > -	nofs_flag = memalloc_nofs_save();
> > -	inode = new_inode(fs_info->sb);
> > -	memalloc_nofs_restore(nofs_flag);
> > -	if (!inode) {
> > -		btrfs_free_path(path);
> > -		return ERR_PTR(-ENOMEM);
> > -	}
> > +		return -ENOMEM;
> >   	/*
> >   	 * O_TMPFILE, set link count to 0, so that after this point,
> > @@ -6133,8 +6121,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
> >   	ret = btrfs_get_free_objectid(root, &objectid);
> >   	if (ret) {
> >   		btrfs_free_path(path);
> > -		iput(inode);
> > -		return ERR_PTR(ret);
> > +		return ret;
> >   	}
> >   	inode->i_ino = objectid;
> > @@ -6144,8 +6131,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
> >   		ret = btrfs_set_inode_index(BTRFS_I(dir), index);
> >   		if (ret) {
> >   			btrfs_free_path(path);
> > -			iput(inode);
> > -			return ERR_PTR(ret);
> > +			return ret;
> >   		}
> >   	} else if (dir) {
> >   		*index = 0;
> > @@ -6163,7 +6149,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
> >   	btrfs_inherit_iflags(inode, dir);
> > -	if (S_ISREG(mode)) {
> > +	if (S_ISREG(inode->i_mode)) {
> >   		if (btrfs_test_opt(fs_info, NODATASUM))
> >   			BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM;
> >   		if (btrfs_test_opt(fs_info, NODATACOW))
> > @@ -6208,10 +6194,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
> >   	location->type = BTRFS_INODE_ITEM_KEY;
> >   	ret = btrfs_insert_inode_locked(inode);
> > -	if (ret < 0) {
> > -		iput(inode);
> > +	if (ret < 0)
> >   		goto fail;
> > -	}
> >   	batch.keys = &key[0];
> >   	batch.data_sizes = &sizes[0];
> > @@ -6221,8 +6205,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
> >   	if (ret != 0)
> >   		goto fail_unlock;
> > -	inode_init_owner(mnt_userns, inode, dir, mode);
> > -
> >   	inode->i_mtime = current_time(inode);
> >   	inode->i_atime = inode->i_mtime;
> >   	inode->i_ctime = inode->i_mtime;
> > @@ -6259,15 +6241,20 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
> >   			  "error inheriting props for ino %llu (root %llu): %d",
> >   			btrfs_ino(BTRFS_I(inode)), root->root_key.objectid, ret);
> > -	return inode;
> > +	return 0;
> >   fail_unlock:
> > +	/*
> > +	 * discard_new_inode() calls iput(), but the caller owns the reference
> > +	 * to the inode.
> > +	 */
> > +	ihold(inode);
> >   	discard_new_inode(inode);
> >   fail:
> >   	if (dir && name)
> >   		BTRFS_I(dir)->index_cnt--;
> >   	btrfs_free_path(path);
> > -	return ERR_PTR(ret);
> > +	return ret;
> >   }
> >   /*
> > @@ -6365,37 +6352,36 @@ static int btrfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
> >   	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
> >   	struct btrfs_trans_handle *trans;
> >   	struct btrfs_root *root = BTRFS_I(dir)->root;
> > -	struct inode *inode = NULL;
> > +	struct inode *inode;
> >   	int err;
> >   	u64 index = 0;
> > +	inode = new_inode(dir->i_sb);
> > +	if (!inode)
> > +		return -ENOMEM;
> > +	inode_init_owner(mnt_userns, inode, dir, mode);
> > +	inode->i_op = &btrfs_special_inode_operations;
> > +	init_special_inode(inode, inode->i_mode, rdev);
> > +
> >   	/*
> >   	 * 2 for inode item and ref
> >   	 * 2 for dir items
> >   	 * 1 for xattr if selinux is on
> >   	 */
> >   	trans = btrfs_start_transaction(root, 5);
> > -	if (IS_ERR(trans))
> > +	if (IS_ERR(trans)) {
> > +		iput(inode);
> >   		return PTR_ERR(trans);
> > +	}
> > -	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
> > -			dentry->d_name.name, dentry->d_name.len,
> > -			mode, &index);
> > -	if (IS_ERR(inode)) {
> > -		err = PTR_ERR(inode);
> > +	err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
> > +			      dentry->d_name.len, &index);
> > +	if (err) {
> > +		iput(inode);
> >   		inode = NULL;
> >   		goto out_unlock;
> >   	}
> > -	/*
> > -	* If the active LSM wants to access the inode during
> > -	* d_instantiate it needs these. Smack checks to see
> > -	* if the filesystem supports xattrs by looking at the
> > -	* ops vector.
> > -	*/
> > -	inode->i_op = &btrfs_special_inode_operations;
> > -	init_special_inode(inode, inode->i_mode, rdev);
> > -
> >   	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
> >   	if (err)
> >   		goto out_unlock;
> > @@ -6424,36 +6410,36 @@ static int btrfs_create(struct user_namespace *mnt_userns, struct inode *dir,
> >   	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
> >   	struct btrfs_trans_handle *trans;
> >   	struct btrfs_root *root = BTRFS_I(dir)->root;
> > -	struct inode *inode = NULL;
> > +	struct inode *inode;
> >   	int err;
> >   	u64 index = 0;
> > +	inode = new_inode(dir->i_sb);
> > +	if (!inode)
> > +		return -ENOMEM;
> > +	inode_init_owner(mnt_userns, inode, dir, mode);
> > +	inode->i_fop = &btrfs_file_operations;
> > +	inode->i_op = &btrfs_file_inode_operations;
> > +	inode->i_mapping->a_ops = &btrfs_aops;
> > +
> >   	/*
> >   	 * 2 for inode item and ref
> >   	 * 2 for dir items
> >   	 * 1 for xattr if selinux is on
> >   	 */
> >   	trans = btrfs_start_transaction(root, 5);
> > -	if (IS_ERR(trans))
> > +	if (IS_ERR(trans)) {
> > +		iput(inode);
> >   		return PTR_ERR(trans);
> > +	}
> > -	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
> > -			dentry->d_name.name, dentry->d_name.len,
> > -			mode, &index);
> > -	if (IS_ERR(inode)) {
> > -		err = PTR_ERR(inode);
> > +	err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
> > +			      dentry->d_name.len, &index);
> > +	if (err) {
> > +		iput(inode);
> >   		inode = NULL;
> >   		goto out_unlock;
> >   	}
> > -	/*
> > -	* If the active LSM wants to access the inode during
> > -	* d_instantiate it needs these. Smack checks to see
> > -	* if the filesystem supports xattrs by looking at the
> > -	* ops vector.
> > -	*/
> > -	inode->i_fop = &btrfs_file_operations;
> > -	inode->i_op = &btrfs_file_inode_operations;
> > -	inode->i_mapping->a_ops = &btrfs_aops;
> >   	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
> >   	if (err)
> > @@ -6562,34 +6548,38 @@ static int btrfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
> >   		       struct dentry *dentry, umode_t mode)
> >   {
> >   	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
> > -	struct inode *inode = NULL;
> > +	struct inode *inode;
> >   	struct btrfs_trans_handle *trans;
> >   	struct btrfs_root *root = BTRFS_I(dir)->root;
> > -	int err = 0;
> > +	int err;
> >   	u64 index = 0;
> > +	inode = new_inode(dir->i_sb);
> > +	if (!inode)
> > +		return -ENOMEM;
> > +	inode_init_owner(mnt_userns, inode, dir, S_IFDIR | mode);
> > +	inode->i_op = &btrfs_dir_inode_operations;
> > +	inode->i_fop = &btrfs_dir_file_operations;
> > +
> >   	/*
> >   	 * 2 items for inode and ref
> >   	 * 2 items for dir items
> >   	 * 1 for xattr if selinux is on
> >   	 */
> >   	trans = btrfs_start_transaction(root, 5);
> > -	if (IS_ERR(trans))
> > +	if (IS_ERR(trans)) {
> > +		iput(inode);
> >   		return PTR_ERR(trans);
> > +	}
> > -	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
> > -			dentry->d_name.name, dentry->d_name.len,
> > -			S_IFDIR | mode, &index);
> > -	if (IS_ERR(inode)) {
> > -		err = PTR_ERR(inode);
> > +	err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
> > +			      dentry->d_name.len, &index);
> > +	if (err) {
> > +		iput(inode);
> >   		inode = NULL;
> >   		goto out_fail;
> >   	}
> > -	/* these must be set before we unlock the inode */
> > -	inode->i_op = &btrfs_dir_inode_operations;
> > -	inode->i_fop = &btrfs_dir_file_operations;
> > -
> >   	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
> >   	if (err)
> >   		goto out_fail;
> > @@ -8747,25 +8737,39 @@ static int btrfs_truncate(struct inode *inode, bool skip_writeback)
> >   	return ret;
> >   }
> > +struct inode *btrfs_new_subvol_inode(struct user_namespace *mnt_userns,
> > +				     struct inode *dir)
> > +{
> > +	struct inode *inode;
> > +
> > +	inode = new_inode(dir->i_sb);
> > +	if (inode) {
> > +		/*
> > +		 * Subvolumes don't inherit the sgid bit or the parent's gid if
> > +		 * the parent's sgid bit is set. This is probably a bug.
> > +		 */
> > +		inode_init_owner(mnt_userns, inode, NULL,
> > +				 S_IFDIR | (~current_umask() & S_IRWXUGO));
> > +		inode->i_op = &btrfs_dir_inode_operations;
> > +		inode->i_fop = &btrfs_dir_file_operations;
> > +	}
> > +	return inode;
> > +}
> > +
> >   /*
> >    * create a new subvolume directory/inode (helper for the ioctl).
> >    */
> >   int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
> > -			     struct btrfs_root *new_root,
> >   			     struct btrfs_root *parent_root,
> > -			     struct user_namespace *mnt_userns)
> > +			     struct inode *inode)
> >   {
> > -	struct inode *inode;
> > +	struct btrfs_root *new_root = BTRFS_I(inode)->root;
> >   	int err;
> >   	u64 index = 0;
> > -	inode = btrfs_new_inode(trans, new_root, mnt_userns, NULL, "..", 2,
> > -				S_IFDIR | (~current_umask() & S_IRWXUGO),
> > -				&index);
> > -	if (IS_ERR(inode))
> > -		return PTR_ERR(inode);
> > -	inode->i_op = &btrfs_dir_inode_operations;
> > -	inode->i_fop = &btrfs_dir_file_operations;
> > +	err = btrfs_new_inode(trans, new_root, inode, NULL, "..", 2, &index);
> > +	if (err)
> > +		return err;
> >   	unlock_new_inode(inode);
> > @@ -8776,8 +8780,6 @@ int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
> >   			  new_root->root_key.objectid, err);
> >   	err = btrfs_update_inode(trans, new_root, BTRFS_I(inode));
> > -
> > -	iput(inode);
> >   	return err;
> >   }
> > @@ -9254,31 +9256,36 @@ static int btrfs_rename_exchange(struct inode *old_dir,
> >   	return ret;
> >   }
> > +static struct inode *new_whiteout_inode(struct user_namespace *mnt_userns,
> > +					struct inode *dir)
> > +{
> > +	struct inode *inode;
> > +
> > +	inode = new_inode(dir->i_sb);
> > +	if (inode) {
> > +		inode_init_owner(mnt_userns, inode, dir,
> > +				 S_IFCHR | WHITEOUT_MODE);
> > +		inode->i_op = &btrfs_special_inode_operations;
> > +		init_special_inode(inode, inode->i_mode, WHITEOUT_DEV);
> > +	}
> > +	return inode;
> > +}
> > +
> >   static int btrfs_whiteout_for_rename(struct btrfs_trans_handle *trans,
> >   				     struct btrfs_root *root,
> > -				     struct user_namespace *mnt_userns,
> > -				     struct inode *dir,
> > +				     struct inode *inode, struct inode *dir,
> >   				     struct dentry *dentry)
> >   {
> >   	int ret;
> > -	struct inode *inode;
> >   	u64 index;
> > -	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
> > -				dentry->d_name.name,
> > -				dentry->d_name.len,
> > -				S_IFCHR | WHITEOUT_MODE,
> > -				&index);
> > -
> > -	if (IS_ERR(inode)) {
> > -		ret = PTR_ERR(inode);
> > +	ret = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
> > +			      dentry->d_name.len, &index);
> > +	if (ret) {
> > +		iput(inode);
> >   		return ret;
> >   	}
> > -	inode->i_op = &btrfs_special_inode_operations;
> > -	init_special_inode(inode, inode->i_mode,
> > -		WHITEOUT_DEV);
> > -
> >   	ret = btrfs_init_inode_security(trans, inode, dir,
> >   				&dentry->d_name);
> >   	if (ret)
> > @@ -9305,6 +9312,7 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
> >   			unsigned int flags)
> >   {
> >   	struct btrfs_fs_info *fs_info = btrfs_sb(old_dir->i_sb);
> > +	struct inode *whiteout_inode;
> >   	struct btrfs_trans_handle *trans;
> >   	unsigned int trans_num_items;
> >   	struct btrfs_root *root = BTRFS_I(old_dir)->root;
> > @@ -9359,6 +9367,12 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
> >   	if (new_inode && S_ISREG(old_inode->i_mode) && new_inode->i_size)
> >   		filemap_flush(old_inode->i_mapping);
> > +	if (flags & RENAME_WHITEOUT) {
> > +		whiteout_inode = new_whiteout_inode(mnt_userns, old_dir);
> > +		if (!whiteout_inode)
> > +			return -ENOMEM;
> > +	}
> > +
> >   	if (old_ino == BTRFS_FIRST_FREE_OBJECTID) {
> >   		/* close the racy window with snapshot create/destroy ioctl */
> >   		down_read(&fs_info->subvol_sem);
> > @@ -9495,9 +9509,9 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
> >   				   rename_ctx.index, new_dentry->d_parent);
> >   	if (flags & RENAME_WHITEOUT) {
> > -		ret = btrfs_whiteout_for_rename(trans, root, mnt_userns,
> > +		ret = btrfs_whiteout_for_rename(trans, root, whiteout_inode,
> >   						old_dir, old_dentry);
> > -
> > +		whiteout_inode = NULL;
> >   		if (ret) {
> >   			btrfs_abort_transaction(trans, ret);
> >   			goto out_fail;
> > @@ -9509,7 +9523,8 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
> >   out_notrans:
> >   	if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
> >   		up_read(&fs_info->subvol_sem);
> > -
> > +	if (flags & RENAME_WHITEOUT)
> > +		iput(whiteout_inode);
> >   	return ret;
> >   }
> > @@ -9728,7 +9743,7 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
> >   	struct btrfs_root *root = BTRFS_I(dir)->root;
> >   	struct btrfs_path *path;
> >   	struct btrfs_key key;
> > -	struct inode *inode = NULL;
> > +	struct inode *inode;
> >   	int err;
> >   	u64 index = 0;
> >   	int name_len;
> > @@ -9741,6 +9756,14 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
> >   	if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(fs_info))
> >   		return -ENAMETOOLONG;
> > +	inode = new_inode(dir->i_sb);
> > +	if (!inode)
> > +		return -ENOMEM;
> > +	inode_init_owner(mnt_userns, inode, dir, S_IFLNK | S_IRWXUGO);
> > +	inode->i_op = &btrfs_symlink_inode_operations;
> > +	inode_nohighmem(inode);
> > +	inode->i_mapping->a_ops = &btrfs_aops;
> > +
> >   	/*
> >   	 * 2 items for inode item and ref
> >   	 * 2 items for dir items
> > @@ -9749,28 +9772,19 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
> >   	 * 1 item for xattr if selinux is on
> >   	 */
> >   	trans = btrfs_start_transaction(root, 7);
> > -	if (IS_ERR(trans))
> > +	if (IS_ERR(trans)) {
> > +		iput(inode);
> >   		return PTR_ERR(trans);
> > +	}
> > -	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
> > -				dentry->d_name.name, dentry->d_name.len,
> > -				S_IFLNK | S_IRWXUGO, &index);
> > -	if (IS_ERR(inode)) {
> > -		err = PTR_ERR(inode);
> > +	err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
> > +			      dentry->d_name.len, &index);
> > +	if (err) {
> > +		iput(inode);
> >   		inode = NULL;
> >   		goto out_unlock;
> >   	}
> > -	/*
> > -	* If the active LSM wants to access the inode during
> > -	* d_instantiate it needs these. Smack checks to see
> > -	* if the filesystem supports xattrs by looking at the
> > -	* ops vector.
> > -	*/
> > -	inode->i_fop = &btrfs_file_operations;
> > -	inode->i_op = &btrfs_file_inode_operations;
> > -	inode->i_mapping->a_ops = &btrfs_aops;
> > -
> >   	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
> >   	if (err)
> >   		goto out_unlock;
> > @@ -9806,8 +9820,6 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
> >   	btrfs_mark_buffer_dirty(leaf);
> >   	btrfs_free_path(path);
> > -	inode->i_op = &btrfs_symlink_inode_operations;
> > -	inode_nohighmem(inode);
> >   	inode_set_bytes(inode, name_len);
> >   	btrfs_i_size_write(BTRFS_I(inode), name_len);
> >   	err = btrfs_update_inode(trans, root, BTRFS_I(inode));
> > @@ -10087,30 +10099,34 @@ static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
> >   	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
> >   	struct btrfs_trans_handle *trans;
> >   	struct btrfs_root *root = BTRFS_I(dir)->root;
> > -	struct inode *inode = NULL;
> > +	struct inode *inode;
> >   	u64 index;
> > -	int ret = 0;
> > +	int ret;
> > +
> > +	inode = new_inode(dir->i_sb);
> > +	if (!inode)
> > +		return -ENOMEM;
> > +	inode_init_owner(mnt_userns, inode, dir, mode);
> > +	inode->i_fop = &btrfs_file_operations;
> > +	inode->i_op = &btrfs_file_inode_operations;
> > +	inode->i_mapping->a_ops = &btrfs_aops;
> >   	/*
> >   	 * 5 units required for adding orphan entry
> >   	 */
> >   	trans = btrfs_start_transaction(root, 5);
> > -	if (IS_ERR(trans))
> > +	if (IS_ERR(trans)) {
> > +		iput(inode);
> >   		return PTR_ERR(trans);
> > +	}
> > -	inode = btrfs_new_inode(trans, root, mnt_userns, dir, NULL, 0,
> > -			mode, &index);
> > -	if (IS_ERR(inode)) {
> > -		ret = PTR_ERR(inode);
> > +	ret = btrfs_new_inode(trans, root, inode, dir, NULL, 0, &index);
> > +	if (ret) {
> > +		iput(inode);
> >   		inode = NULL;
> >   		goto out;
> >   	}
> > -	inode->i_fop = &btrfs_file_operations;
> > -	inode->i_op = &btrfs_file_inode_operations;
> > -
> > -	inode->i_mapping->a_ops = &btrfs_aops;
> > -
> >   	ret = btrfs_init_inode_security(trans, inode, dir, NULL);
> >   	if (ret)
> >   		goto out;
> > diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
> > index 891352fd6d0f..60c907b14547 100644
> > --- a/fs/btrfs/ioctl.c
> > +++ b/fs/btrfs/ioctl.c
> > @@ -587,6 +587,12 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
> >   	if (ret < 0)
> >   		goto out_root_item;
> > +	inode = btrfs_new_subvol_inode(mnt_userns, dir);
> > +	if (!inode) {
> > +		ret = -ENOMEM;
> > +		goto out_anon_dev;
> > +	}
> > +
> >   	btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP);
> >   	/*
> >   	 * The same as the snapshot creation, please see the comment
> > @@ -594,13 +600,13 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
> >   	 */
> >   	ret = btrfs_subvolume_reserve_metadata(root, &block_rsv, 8, false);
> >   	if (ret)
> > -		goto out_anon_dev;
> > +		goto out_inode;
> >   	trans = btrfs_start_transaction(root, 0);
> >   	if (IS_ERR(trans)) {
> >   		ret = PTR_ERR(trans);
> >   		btrfs_subvolume_release_metadata(root, &block_rsv);
> > -		goto out_anon_dev;
> > +		goto out_inode;
> >   	}
> >   	trans->block_rsv = &block_rsv;
> >   	trans->bytes_reserved = block_rsv.size;
> > @@ -683,16 +689,16 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
> >   	}
> >   	/* anon_dev is owned by new_root now. */
> >   	anon_dev = 0;
> > +	BTRFS_I(inode)->root = new_root;
> > +	/* ... and new_root is owned by inode now. */
> >   	ret = btrfs_record_root_in_trans(trans, new_root);
> >   	if (ret) {
> > -		btrfs_put_root(new_root);
> >   		btrfs_abort_transaction(trans, ret);
> >   		goto out;
> >   	}
> > -	ret = btrfs_create_subvol_root(trans, new_root, root, mnt_userns);
> > -	btrfs_put_root(new_root);
> > +	ret = btrfs_create_subvol_root(trans, root, inode);
> >   	if (ret) {
> >   		/* We potentially lose an unused inode item here */
> >   		btrfs_abort_transaction(trans, ret);
> > @@ -745,11 +751,11 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
> >   		ret = btrfs_commit_transaction(trans);
> >   	if (!ret) {
> > -		inode = btrfs_lookup_dentry(dir, dentry);
> > -		if (IS_ERR(inode))
> > -			return PTR_ERR(inode);
> >   		d_instantiate(dentry, inode);
> > +		inode = NULL;
> >   	}
> 
> I don't understand this. Why do we not need to look up the dentry anymore? 
> Was that always unneeded?

We previously needed it because btrfs_create_subvol_root() did not
return the struct inode it created, so to get it back here, we had to
look it up. (In fact, it might even be the case that the struct inode
allocated by btrfs_create_subvol_root() is freed by its call to iput(),
and then btrfs_lookup_dentry() has to reread it from the B-tree, which
would be silly.)

But now create_subvol() allocates the inode itself, so it has it handy
to use here.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 15/16] btrfs: reserve correct number of items for inode creation
  2022-03-11 17:56   ` Sweet Tea Dorminy
@ 2022-03-12  0:45     ` Omar Sandoval
  0 siblings, 0 replies; 35+ messages in thread
From: Omar Sandoval @ 2022-03-12  0:45 UTC (permalink / raw)
  To: Sweet Tea Dorminy; +Cc: linux-btrfs, kernel-team

On Fri, Mar 11, 2022 at 12:56:43PM -0500, Sweet Tea Dorminy wrote:
> 
> On 3/9/22 20:31, Omar Sandoval wrote:
> > From: Omar Sandoval <osandov@fb.com>
> > 
> > The various inode creation code paths do not account for the compression
> > property, POSIX ACLs, or the parent inode item when starting a
> > transaction. Fix it by refactoring all of these code paths to use a new
> > function, btrfs_new_inode_prepare(), which computes the correct number
> > of items. To do so, it needs to know whether POSIX ACLs will be created,
> > so move the ACL creation into that function. To reduce the number of
> > arguments that need to be passed around for inode creation, define
> > struct btrfs_new_inode_args containing all of the relevant information.
> > 
> > btrfs_new_inode_prepare() will also be a good place to set up the
> > fscrypt context and encrypted filename in the future.
> > 
> > Signed-off-by: Omar Sandoval <osandov@fb.com>
> > ---
> >   fs/btrfs/acl.c   |  36 +------
> >   fs/btrfs/ctree.h |  34 +++++--
> >   fs/btrfs/inode.c | 256 ++++++++++++++++++++++++++++++++++-------------
> >   fs/btrfs/ioctl.c |  83 ++++++++++-----
> >   4 files changed, 277 insertions(+), 132 deletions(-)
> > 
> > diff --git a/fs/btrfs/acl.c b/fs/btrfs/acl.c
> > index a6909ec9bc38..548d6a5477b4 100644
> > --- a/fs/btrfs/acl.c
> > +++ b/fs/btrfs/acl.c
> > @@ -55,8 +55,8 @@ struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu)
> >   	return acl;
> >   }
> > -static int __btrfs_set_acl(struct btrfs_trans_handle *trans,
> > -			   struct inode *inode, struct posix_acl *acl, int type)
> > +int __btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode,
> > +		    struct posix_acl *acl, int type)
> >   {
> >   	int ret, size = 0;
> >   	const char *name;
> > @@ -127,35 +127,3 @@ int btrfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
> >   		inode->i_mode = old_mode;
> >   	return ret;
> >   }
> > -
> > -int btrfs_init_acl(struct btrfs_trans_handle *trans,
> > -		   struct inode *inode, struct inode *dir)
> > -{
> > -	struct posix_acl *default_acl, *acl;
> > -	int ret = 0;
> > -
> > -	/* this happens with subvols */
> > -	if (!dir)
> > -		return 0;
> > -
> > -	ret = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
> > -	if (ret)
> > -		return ret;
> > -
> > -	if (default_acl) {
> > -		ret = __btrfs_set_acl(trans, inode, default_acl,
> > -				      ACL_TYPE_DEFAULT);
> > -		posix_acl_release(default_acl);
> > -	}
> > -
> > -	if (acl) {
> > -		if (!ret)
> > -			ret = __btrfs_set_acl(trans, inode, acl,
> > -					      ACL_TYPE_ACCESS);
> > -		posix_acl_release(acl);
> > -	}
> > -
> > -	if (!default_acl && !acl)
> > -		cache_no_acl(inode);
> > -	return ret;
> > -}
> > diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
> > index f39730420e8a..322c02610e9e 100644
> > --- a/fs/btrfs/ctree.h
> > +++ b/fs/btrfs/ctree.h
> > @@ -3254,11 +3254,32 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, long nr,
> >   int btrfs_set_extent_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
> >   			      unsigned int extra_bits,
> >   			      struct extent_state **cached_state);
> > +struct btrfs_new_inode_args {
> > +	/* Input */
> > +	struct inode *dir;
> > +	struct dentry *dentry;
> > +	struct inode *inode;
> > +	bool orphan;
> > +	bool subvol;
> > +
> > +	/*
> > +	 * Output from btrfs_new_inode_prepare(), input to
> > +	 * btrfs_create_new_inode().
> > +	 */
> > +	struct posix_acl *default_acl;
> > +	struct posix_acl *acl;
> > +};
> > +int btrfs_new_inode_prepare(struct btrfs_new_inode_args *args,
> > +			    unsigned int *trans_num_items);
> > +int btrfs_create_new_inode(struct btrfs_trans_handle *trans,
> > +			   struct btrfs_new_inode_args *args,
> > +			   u64 *index);
> > +void btrfs_new_inode_args_destroy(struct btrfs_new_inode_args *args);
> >   struct inode *btrfs_new_subvol_inode(struct user_namespace *mnt_userns,
> >   				     struct inode *dir);
> >   int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
> >   			     struct btrfs_root *parent_root,
> > -			     struct inode *inode);
> > +			     struct btrfs_new_inode_args *args);
> >    void btrfs_set_delalloc_extent(struct inode *inode, struct extent_state *state,
> >   			       unsigned *bits);
> >   void btrfs_clear_delalloc_extent(struct inode *inode,
> > @@ -3816,15 +3837,16 @@ static inline int __btrfs_fs_compat_ro(struct btrfs_fs_info *fs_info, u64 flag)
> >   struct posix_acl *btrfs_get_acl(struct inode *inode, int type, bool rcu);
> >   int btrfs_set_acl(struct user_namespace *mnt_userns, struct inode *inode,
> >   		  struct posix_acl *acl, int type);
> > -int btrfs_init_acl(struct btrfs_trans_handle *trans,
> > -		   struct inode *inode, struct inode *dir);
> > +int __btrfs_set_acl(struct btrfs_trans_handle *trans, struct inode *inode,
> > +		    struct posix_acl *acl, int type);
> >   #else
> >   #define btrfs_get_acl NULL
> >   #define btrfs_set_acl NULL
> > -static inline int btrfs_init_acl(struct btrfs_trans_handle *trans,
> > -				 struct inode *inode, struct inode *dir)
> > +static inline int __btrfs_set_acl(struct btrfs_trans_handle *trans,
> > +				  struct inode *inode, struct posix_acl *acl,
> > +				  int type)
> >   {
> > -	return 0;
> > +	return -EOPNOTSUPP;
> >   }
> >   #endif
> > diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
> > index bea2cb2d90a5..e2b1b1969d0b 100644
> > --- a/fs/btrfs/inode.c
> > +++ b/fs/btrfs/inode.c
> > @@ -223,14 +223,26 @@ static int btrfs_dirty_inode(struct inode *inode);
> >   static int btrfs_init_inode_security(struct btrfs_trans_handle *trans,
> >   				     struct inode *inode,  struct inode *dir,
> > -				     const struct qstr *qstr)
> > +				     const struct qstr *qstr,
> > +				     struct posix_acl *default_acl,
> > +				     struct posix_acl *acl)
> >   {
> >   	int err;
> > -	err = btrfs_init_acl(trans, inode, dir);
> > -	if (!err)
> > -		err = btrfs_xattr_security_init(trans, inode, dir, qstr);
> > -	return err;
> > +	if (default_acl) {
> > +		err = __btrfs_set_acl(trans, inode, default_acl,
> > +				      ACL_TYPE_DEFAULT);
> > +		if (err)
> > +			return err;
> > +	}
> > +	if (acl) {
> > +		err = __btrfs_set_acl(trans, inode, acl, ACL_TYPE_ACCESS);
> > +		if (err)
> > +			return err;
> > +	}
> > +	if (!default_acl && !acl)
> > +		cache_no_acl(inode);
> > +	return btrfs_xattr_security_init(trans, inode, dir, qstr);
> >   }
> 
> 
> Would it be worth making this take a btrfs_new_inode_args also, since
> basically everything it needs is contained therein? I think the only place
> calling btrfs_init_inode_security() with params not just pulled out of the
> btrfs_new_inode_args is btrfs_tempfile, which is passing a NULL name instead
> of &dentry->d_name; I'm not clear on why in that case it's different...

That's a good idea, I'll do that.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 03/16] btrfs: fix anon_dev leak in create_subvol()
  2022-03-12  0:29     ` Omar Sandoval
@ 2022-03-12  1:43       ` Sweet Tea Dorminy
  0 siblings, 0 replies; 35+ messages in thread
From: Sweet Tea Dorminy @ 2022-03-12  1:43 UTC (permalink / raw)
  To: Omar Sandoval; +Cc: linux-btrfs, kernel-team


On 3/11/22 19:29, Omar Sandoval wrote:
> On Fri, Mar 11, 2022 at 10:42:14AM -0500, Sweet Tea Dorminy wrote:
>>> +out_anon_dev:
>>>    	if (anon_dev)
>>>    		free_anon_bdev(anon_dev);
>> It looks to me as though the finer-grained cleanup means free_anon_bdev()
>> can always be called with no conditional; if the code reaches this point in
>> cleanup, anon_dev was populated by get_anon_bdev() (which must have returned
>> zero, indicating successfully populating anon_dev).
> The conditional is required because halfway through the function, we
> assign the anon_dev to a struct btrfs_root, which means that the
> anon_dev will be freed when the root is freed:
>
> 	new_root = btrfs_get_new_fs_root(fs_info, objectid, anon_dev);
> 	if (IS_ERR(new_root)) {
> 		ret = PTR_ERR(new_root);
> 		btrfs_abort_transaction(trans, ret);
> 		goto out;
> 	}
> 	/* anon_dev is owned by new_root now. */
> 	anon_dev = 0;

Makes sense, thanks for pointing that out!


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 00/16] btrfs: inode creation cleanups and fixes
  2022-03-10  1:31 [PATCH v2 00/16] btrfs: inode creation cleanups and fixes Omar Sandoval
                   ` (15 preceding siblings ...)
  2022-03-10  1:31 ` [PATCH v2 16/16] btrfs: move common inode creation code into btrfs_create_new_inode() Omar Sandoval
@ 2022-03-14 12:50 ` David Sterba
  2022-03-14 18:42   ` Omar Sandoval
  16 siblings, 1 reply; 35+ messages in thread
From: David Sterba @ 2022-03-14 12:50 UTC (permalink / raw)
  To: Omar Sandoval; +Cc: linux-btrfs, kernel-team

On Wed, Mar 09, 2022 at 05:31:30PM -0800, Omar Sandoval wrote:
> From: Omar Sandoval <osandov@fb.com>
> 
> This series contains several cleanups and fixes for our inode creation
> codepaths. The main motivation for this is preparation for fscrypt
> support (in particular, setting up the fscrypt context and encrypted
> names at inode creation time). But, it also reduces a lot of code
> duplication and fixes some minor bugs, so it's worth getting in ahead of
> time.
> 
> Patches 1-3 are small fixes. Patches 5-12 are small cleanups. Patches
> 13-16 are the bulk of the change.
> 
> Based on misc-next.
> 
> Changes since v1 [1]:
> 
> - Split the big final patch into patches 3 and 13-16.
> - Added Sweet Tea's reviewed-by to the remaining patches.
> - Rebased on latest misc-next.
> 
> Thanks!
> 
> 1: https://lore.kernel.org/linux-btrfs/cover.1646348486.git.osandov@fb.com/
> 
> Omar Sandoval (16):
>   btrfs: reserve correct number of items for unlink and rmdir
>   btrfs: reserve correct number of items for rename
>   btrfs: fix anon_dev leak in create_subvol()
>   btrfs: get rid of btrfs_add_nondir()
>   btrfs: remove unnecessary btrfs_i_size_write(0) calls
>   btrfs: remove unnecessary inode_set_bytes(0) call
>   btrfs: remove unnecessary set_nlink() in btrfs_create_subvol_root()
>   btrfs: remove unused mnt_userns parameter from __btrfs_set_acl
>   btrfs: remove redundant name and name_len parameters to create_subvol
>   btrfs: don't pass parent objectid to btrfs_new_inode() explicitly
>   btrfs: move btrfs_get_free_objectid() call into btrfs_new_inode()
>   btrfs: set inode flags earlier in btrfs_new_inode()
>   btrfs: allocate inode outside of btrfs_new_inode()

Patches 1-13 added to misc-next. The remaining patches seem to be still
a bit big for review.

>   btrfs: factor out common part of btrfs_{mknod,create,mkdir}()
>   btrfs: reserve correct number of items for inode creation
>   btrfs: move common inode creation code into btrfs_create_new_inode()
> 
>  fs/btrfs/acl.c   |  39 +-
>  fs/btrfs/ctree.h |  37 +-
>  fs/btrfs/inode.c | 942 +++++++++++++++++++++++------------------------
>  fs/btrfs/ioctl.c | 176 ++++-----
>  fs/btrfs/props.c |  40 +-
>  fs/btrfs/props.h |   4 -
>  6 files changed, 579 insertions(+), 659 deletions(-)
> 
> -- 
> 2.35.1

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 13/16] btrfs: allocate inode outside of btrfs_new_inode()
  2022-03-12  0:41     ` Omar Sandoval
@ 2022-03-14 14:43       ` Sweet Tea Dorminy
  0 siblings, 0 replies; 35+ messages in thread
From: Sweet Tea Dorminy @ 2022-03-14 14:43 UTC (permalink / raw)
  To: Omar Sandoval; +Cc: linux-btrfs, kernel-team


On 3/11/22 19:41, Omar Sandoval wrote:
> On Fri, Mar 11, 2022 at 12:11:03PM -0500, Sweet Tea Dorminy wrote:
>> On 3/9/22 20:31, Omar Sandoval wrote:
>>> From: Omar Sandoval <osandov@fb.com>
>>>
>>> Instead of calling new_inode() and inode_init_owner() inside of
>>> btrfs_new_inode(), do it in the callers. This allows us to pass in just
>>> the inode instead of the mnt_userns and mode and removes the need for
>>> memalloc_nofs_{save,restores}() since we do it before starting a
>>> transaction. This also paves the way for some more cleanups in later
>>> patches.
>>>
>>> This also removes the comments about Smack checking i_op, which are no
>>> longer true since commit 5d6c31910bc0 ("xattr: Add
>>> __vfs_{get,set,remove}xattr helpers"). Now it checks inode->i_opflags &
>>> IOP_XATTR, which is set based on sb->s_xattr.
>>>
>>> Signed-off-by: Omar Sandoval <osandov@fb.com>
>>> ---
>>>    fs/btrfs/ctree.h |   5 +-
>>>    fs/btrfs/inode.c | 284 +++++++++++++++++++++++++----------------------
>>>    fs/btrfs/ioctl.c |  22 ++--
>>>    3 files changed, 167 insertions(+), 144 deletions(-)
>>>
>>> diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
>>> index 4db17bd05a21..f39730420e8a 100644
>>> --- a/fs/btrfs/ctree.h
>>> +++ b/fs/btrfs/ctree.h
>>> @@ -3254,10 +3254,11 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, long nr,
>>>    int btrfs_set_extent_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
>>>    			      unsigned int extra_bits,
>>>    			      struct extent_state **cached_state);
>>> +struct inode *btrfs_new_subvol_inode(struct user_namespace *mnt_userns,
>>> +				     struct inode *dir);
>>>    int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
>>> -			     struct btrfs_root *new_root,
>>>    			     struct btrfs_root *parent_root,
>>> -			     struct user_namespace *mnt_userns);
>>> +			     struct inode *inode);
>>>     void btrfs_set_delalloc_extent(struct inode *inode, struct extent_state *state,
>>>    			       unsigned *bits);
>>>    void btrfs_clear_delalloc_extent(struct inode *inode,
>>> diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
>>> index c47bdada2440..ff780256c936 100644
>>> --- a/fs/btrfs/inode.c
>>> +++ b/fs/btrfs/inode.c
>>> @@ -6090,15 +6090,12 @@ static void btrfs_inherit_iflags(struct inode *inode, struct inode *dir)
>>>    	btrfs_sync_inode_flags_to_i_flags(inode);
>>>    }
>>> -static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
>>> -				     struct btrfs_root *root,
>>> -				     struct user_namespace *mnt_userns,
>>> -				     struct inode *dir,
>>> -				     const char *name, int name_len,
>>> -				     umode_t mode, u64 *index)
>>> +static int btrfs_new_inode(struct btrfs_trans_handle *trans,
>>> +			   struct btrfs_root *root, struct inode *inode,
>>> +			   struct inode *dir, const char *name, int name_len,
>>> +			   u64 *index)
>>
>> This is a triviality, but now that it doesn't allocate a new inode, I'm not
>> sure it deserves the word 'new' in its name -- new_inode() does the
>> allocation, and then inode_init_owner() initializes some part of the new
>> inode, and then btrfs_new_inode() initializes the rest. Might it be worth
>> renaming it something that emphasizes that it initializes a preallocated
>> inode, btrfs_prepare/init/init_new/etc_inode()?
> One of the later changes renames it to btrfs_create_new_inode(). I.e.,
> it creates (on disk) a new inode that you allocated.
Seems reasonable.
>
>>>    {
>>>    	struct btrfs_fs_info *fs_info = root->fs_info;
>>> -	struct inode *inode;
>>>    	struct btrfs_inode_item *inode_item;
>>>    	struct btrfs_key *location;
>>>    	struct btrfs_path *path;
>>> @@ -6108,20 +6105,11 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
>>>    	u32 sizes[2];
>>>    	struct btrfs_item_batch batch;
>>>    	unsigned long ptr;
>>> -	unsigned int nofs_flag;
>>>    	int ret;
>>>    	path = btrfs_alloc_path();
>>>    	if (!path)
>>> -		return ERR_PTR(-ENOMEM);
>>> -
>>> -	nofs_flag = memalloc_nofs_save();
>>> -	inode = new_inode(fs_info->sb);
>>> -	memalloc_nofs_restore(nofs_flag);
>>> -	if (!inode) {
>>> -		btrfs_free_path(path);
>>> -		return ERR_PTR(-ENOMEM);
>>> -	}
>>> +		return -ENOMEM;
>>>    	/*
>>>    	 * O_TMPFILE, set link count to 0, so that after this point,
>>> @@ -6133,8 +6121,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
>>>    	ret = btrfs_get_free_objectid(root, &objectid);
>>>    	if (ret) {
>>>    		btrfs_free_path(path);
>>> -		iput(inode);
>>> -		return ERR_PTR(ret);
>>> +		return ret;
>>>    	}
>>>    	inode->i_ino = objectid;
>>> @@ -6144,8 +6131,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
>>>    		ret = btrfs_set_inode_index(BTRFS_I(dir), index);
>>>    		if (ret) {
>>>    			btrfs_free_path(path);
>>> -			iput(inode);
>>> -			return ERR_PTR(ret);
>>> +			return ret;
>>>    		}
>>>    	} else if (dir) {
>>>    		*index = 0;
>>> @@ -6163,7 +6149,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
>>>    	btrfs_inherit_iflags(inode, dir);
>>> -	if (S_ISREG(mode)) {
>>> +	if (S_ISREG(inode->i_mode)) {
>>>    		if (btrfs_test_opt(fs_info, NODATASUM))
>>>    			BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM;
>>>    		if (btrfs_test_opt(fs_info, NODATACOW))
>>> @@ -6208,10 +6194,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
>>>    	location->type = BTRFS_INODE_ITEM_KEY;
>>>    	ret = btrfs_insert_inode_locked(inode);
>>> -	if (ret < 0) {
>>> -		iput(inode);
>>> +	if (ret < 0)
>>>    		goto fail;
>>> -	}
>>>    	batch.keys = &key[0];
>>>    	batch.data_sizes = &sizes[0];
>>> @@ -6221,8 +6205,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
>>>    	if (ret != 0)
>>>    		goto fail_unlock;
>>> -	inode_init_owner(mnt_userns, inode, dir, mode);
>>> -
>>>    	inode->i_mtime = current_time(inode);
>>>    	inode->i_atime = inode->i_mtime;
>>>    	inode->i_ctime = inode->i_mtime;
>>> @@ -6259,15 +6241,20 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
>>>    			  "error inheriting props for ino %llu (root %llu): %d",
>>>    			btrfs_ino(BTRFS_I(inode)), root->root_key.objectid, ret);
>>> -	return inode;
>>> +	return 0;
>>>    fail_unlock:
>>> +	/*
>>> +	 * discard_new_inode() calls iput(), but the caller owns the reference
>>> +	 * to the inode.
>>> +	 */
>>> +	ihold(inode);
>>>    	discard_new_inode(inode);
>>>    fail:
>>>    	if (dir && name)
>>>    		BTRFS_I(dir)->index_cnt--;
>>>    	btrfs_free_path(path);
>>> -	return ERR_PTR(ret);
>>> +	return ret;
>>>    }
>>>    /*
>>> @@ -6365,37 +6352,36 @@ static int btrfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
>>>    	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
>>>    	struct btrfs_trans_handle *trans;
>>>    	struct btrfs_root *root = BTRFS_I(dir)->root;
>>> -	struct inode *inode = NULL;
>>> +	struct inode *inode;
>>>    	int err;
>>>    	u64 index = 0;
>>> +	inode = new_inode(dir->i_sb);
>>> +	if (!inode)
>>> +		return -ENOMEM;
>>> +	inode_init_owner(mnt_userns, inode, dir, mode);
>>> +	inode->i_op = &btrfs_special_inode_operations;
>>> +	init_special_inode(inode, inode->i_mode, rdev);
>>> +
>>>    	/*
>>>    	 * 2 for inode item and ref
>>>    	 * 2 for dir items
>>>    	 * 1 for xattr if selinux is on
>>>    	 */
>>>    	trans = btrfs_start_transaction(root, 5);
>>> -	if (IS_ERR(trans))
>>> +	if (IS_ERR(trans)) {
>>> +		iput(inode);
>>>    		return PTR_ERR(trans);
>>> +	}
>>> -	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
>>> -			dentry->d_name.name, dentry->d_name.len,
>>> -			mode, &index);
>>> -	if (IS_ERR(inode)) {
>>> -		err = PTR_ERR(inode);
>>> +	err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
>>> +			      dentry->d_name.len, &index);
>>> +	if (err) {
>>> +		iput(inode);
>>>    		inode = NULL;
>>>    		goto out_unlock;
>>>    	}
>>> -	/*
>>> -	* If the active LSM wants to access the inode during
>>> -	* d_instantiate it needs these. Smack checks to see
>>> -	* if the filesystem supports xattrs by looking at the
>>> -	* ops vector.
>>> -	*/
>>> -	inode->i_op = &btrfs_special_inode_operations;
>>> -	init_special_inode(inode, inode->i_mode, rdev);
>>> -
>>>    	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
>>>    	if (err)
>>>    		goto out_unlock;
>>> @@ -6424,36 +6410,36 @@ static int btrfs_create(struct user_namespace *mnt_userns, struct inode *dir,
>>>    	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
>>>    	struct btrfs_trans_handle *trans;
>>>    	struct btrfs_root *root = BTRFS_I(dir)->root;
>>> -	struct inode *inode = NULL;
>>> +	struct inode *inode;
>>>    	int err;
>>>    	u64 index = 0;
>>> +	inode = new_inode(dir->i_sb);
>>> +	if (!inode)
>>> +		return -ENOMEM;
>>> +	inode_init_owner(mnt_userns, inode, dir, mode);
>>> +	inode->i_fop = &btrfs_file_operations;
>>> +	inode->i_op = &btrfs_file_inode_operations;
>>> +	inode->i_mapping->a_ops = &btrfs_aops;
>>> +
>>>    	/*
>>>    	 * 2 for inode item and ref
>>>    	 * 2 for dir items
>>>    	 * 1 for xattr if selinux is on
>>>    	 */
>>>    	trans = btrfs_start_transaction(root, 5);
>>> -	if (IS_ERR(trans))
>>> +	if (IS_ERR(trans)) {
>>> +		iput(inode);
>>>    		return PTR_ERR(trans);
>>> +	}
>>> -	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
>>> -			dentry->d_name.name, dentry->d_name.len,
>>> -			mode, &index);
>>> -	if (IS_ERR(inode)) {
>>> -		err = PTR_ERR(inode);
>>> +	err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
>>> +			      dentry->d_name.len, &index);
>>> +	if (err) {
>>> +		iput(inode);
>>>    		inode = NULL;
>>>    		goto out_unlock;
>>>    	}
>>> -	/*
>>> -	* If the active LSM wants to access the inode during
>>> -	* d_instantiate it needs these. Smack checks to see
>>> -	* if the filesystem supports xattrs by looking at the
>>> -	* ops vector.
>>> -	*/
>>> -	inode->i_fop = &btrfs_file_operations;
>>> -	inode->i_op = &btrfs_file_inode_operations;
>>> -	inode->i_mapping->a_ops = &btrfs_aops;
>>>    	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
>>>    	if (err)
>>> @@ -6562,34 +6548,38 @@ static int btrfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
>>>    		       struct dentry *dentry, umode_t mode)
>>>    {
>>>    	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
>>> -	struct inode *inode = NULL;
>>> +	struct inode *inode;
>>>    	struct btrfs_trans_handle *trans;
>>>    	struct btrfs_root *root = BTRFS_I(dir)->root;
>>> -	int err = 0;
>>> +	int err;
>>>    	u64 index = 0;
>>> +	inode = new_inode(dir->i_sb);
>>> +	if (!inode)
>>> +		return -ENOMEM;
>>> +	inode_init_owner(mnt_userns, inode, dir, S_IFDIR | mode);
>>> +	inode->i_op = &btrfs_dir_inode_operations;
>>> +	inode->i_fop = &btrfs_dir_file_operations;
>>> +
>>>    	/*
>>>    	 * 2 items for inode and ref
>>>    	 * 2 items for dir items
>>>    	 * 1 for xattr if selinux is on
>>>    	 */
>>>    	trans = btrfs_start_transaction(root, 5);
>>> -	if (IS_ERR(trans))
>>> +	if (IS_ERR(trans)) {
>>> +		iput(inode);
>>>    		return PTR_ERR(trans);
>>> +	}
>>> -	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
>>> -			dentry->d_name.name, dentry->d_name.len,
>>> -			S_IFDIR | mode, &index);
>>> -	if (IS_ERR(inode)) {
>>> -		err = PTR_ERR(inode);
>>> +	err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
>>> +			      dentry->d_name.len, &index);
>>> +	if (err) {
>>> +		iput(inode);
>>>    		inode = NULL;
>>>    		goto out_fail;
>>>    	}
>>> -	/* these must be set before we unlock the inode */
>>> -	inode->i_op = &btrfs_dir_inode_operations;
>>> -	inode->i_fop = &btrfs_dir_file_operations;
>>> -
>>>    	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
>>>    	if (err)
>>>    		goto out_fail;
>>> @@ -8747,25 +8737,39 @@ static int btrfs_truncate(struct inode *inode, bool skip_writeback)
>>>    	return ret;
>>>    }
>>> +struct inode *btrfs_new_subvol_inode(struct user_namespace *mnt_userns,
>>> +				     struct inode *dir)
>>> +{
>>> +	struct inode *inode;
>>> +
>>> +	inode = new_inode(dir->i_sb);
>>> +	if (inode) {
>>> +		/*
>>> +		 * Subvolumes don't inherit the sgid bit or the parent's gid if
>>> +		 * the parent's sgid bit is set. This is probably a bug.
>>> +		 */
>>> +		inode_init_owner(mnt_userns, inode, NULL,
>>> +				 S_IFDIR | (~current_umask() & S_IRWXUGO));
>>> +		inode->i_op = &btrfs_dir_inode_operations;
>>> +		inode->i_fop = &btrfs_dir_file_operations;
>>> +	}
>>> +	return inode;
>>> +}
>>> +
>>>    /*
>>>     * create a new subvolume directory/inode (helper for the ioctl).
>>>     */
>>>    int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
>>> -			     struct btrfs_root *new_root,
>>>    			     struct btrfs_root *parent_root,
>>> -			     struct user_namespace *mnt_userns)
>>> +			     struct inode *inode)
>>>    {
>>> -	struct inode *inode;
>>> +	struct btrfs_root *new_root = BTRFS_I(inode)->root;
>>>    	int err;
>>>    	u64 index = 0;
>>> -	inode = btrfs_new_inode(trans, new_root, mnt_userns, NULL, "..", 2,
>>> -				S_IFDIR | (~current_umask() & S_IRWXUGO),
>>> -				&index);
>>> -	if (IS_ERR(inode))
>>> -		return PTR_ERR(inode);
>>> -	inode->i_op = &btrfs_dir_inode_operations;
>>> -	inode->i_fop = &btrfs_dir_file_operations;
>>> +	err = btrfs_new_inode(trans, new_root, inode, NULL, "..", 2, &index);
>>> +	if (err)
>>> +		return err;
>>>    	unlock_new_inode(inode);
>>> @@ -8776,8 +8780,6 @@ int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
>>>    			  new_root->root_key.objectid, err);
>>>    	err = btrfs_update_inode(trans, new_root, BTRFS_I(inode));
>>> -
>>> -	iput(inode);
>>>    	return err;
>>>    }
>>> @@ -9254,31 +9256,36 @@ static int btrfs_rename_exchange(struct inode *old_dir,
>>>    	return ret;
>>>    }
>>> +static struct inode *new_whiteout_inode(struct user_namespace *mnt_userns,
>>> +					struct inode *dir)
>>> +{
>>> +	struct inode *inode;
>>> +
>>> +	inode = new_inode(dir->i_sb);
>>> +	if (inode) {
>>> +		inode_init_owner(mnt_userns, inode, dir,
>>> +				 S_IFCHR | WHITEOUT_MODE);
>>> +		inode->i_op = &btrfs_special_inode_operations;
>>> +		init_special_inode(inode, inode->i_mode, WHITEOUT_DEV);
>>> +	}
>>> +	return inode;
>>> +}
>>> +
>>>    static int btrfs_whiteout_for_rename(struct btrfs_trans_handle *trans,
>>>    				     struct btrfs_root *root,
>>> -				     struct user_namespace *mnt_userns,
>>> -				     struct inode *dir,
>>> +				     struct inode *inode, struct inode *dir,
>>>    				     struct dentry *dentry)
>>>    {
>>>    	int ret;
>>> -	struct inode *inode;
>>>    	u64 index;
>>> -	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
>>> -				dentry->d_name.name,
>>> -				dentry->d_name.len,
>>> -				S_IFCHR | WHITEOUT_MODE,
>>> -				&index);
>>> -
>>> -	if (IS_ERR(inode)) {
>>> -		ret = PTR_ERR(inode);
>>> +	ret = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
>>> +			      dentry->d_name.len, &index);
>>> +	if (ret) {
>>> +		iput(inode);
>>>    		return ret;
>>>    	}
>>> -	inode->i_op = &btrfs_special_inode_operations;
>>> -	init_special_inode(inode, inode->i_mode,
>>> -		WHITEOUT_DEV);
>>> -
>>>    	ret = btrfs_init_inode_security(trans, inode, dir,
>>>    				&dentry->d_name);
>>>    	if (ret)
>>> @@ -9305,6 +9312,7 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
>>>    			unsigned int flags)
>>>    {
>>>    	struct btrfs_fs_info *fs_info = btrfs_sb(old_dir->i_sb);
>>> +	struct inode *whiteout_inode;
>>>    	struct btrfs_trans_handle *trans;
>>>    	unsigned int trans_num_items;
>>>    	struct btrfs_root *root = BTRFS_I(old_dir)->root;
>>> @@ -9359,6 +9367,12 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
>>>    	if (new_inode && S_ISREG(old_inode->i_mode) && new_inode->i_size)
>>>    		filemap_flush(old_inode->i_mapping);
>>> +	if (flags & RENAME_WHITEOUT) {
>>> +		whiteout_inode = new_whiteout_inode(mnt_userns, old_dir);
>>> +		if (!whiteout_inode)
>>> +			return -ENOMEM;
>>> +	}
>>> +
>>>    	if (old_ino == BTRFS_FIRST_FREE_OBJECTID) {
>>>    		/* close the racy window with snapshot create/destroy ioctl */
>>>    		down_read(&fs_info->subvol_sem);
>>> @@ -9495,9 +9509,9 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
>>>    				   rename_ctx.index, new_dentry->d_parent);
>>>    	if (flags & RENAME_WHITEOUT) {
>>> -		ret = btrfs_whiteout_for_rename(trans, root, mnt_userns,
>>> +		ret = btrfs_whiteout_for_rename(trans, root, whiteout_inode,
>>>    						old_dir, old_dentry);
>>> -
>>> +		whiteout_inode = NULL;
>>>    		if (ret) {
>>>    			btrfs_abort_transaction(trans, ret);
>>>    			goto out_fail;
>>> @@ -9509,7 +9523,8 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
>>>    out_notrans:
>>>    	if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
>>>    		up_read(&fs_info->subvol_sem);
>>> -
>>> +	if (flags & RENAME_WHITEOUT)
>>> +		iput(whiteout_inode);
>>>    	return ret;
>>>    }
>>> @@ -9728,7 +9743,7 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
>>>    	struct btrfs_root *root = BTRFS_I(dir)->root;
>>>    	struct btrfs_path *path;
>>>    	struct btrfs_key key;
>>> -	struct inode *inode = NULL;
>>> +	struct inode *inode;
>>>    	int err;
>>>    	u64 index = 0;
>>>    	int name_len;
>>> @@ -9741,6 +9756,14 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
>>>    	if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(fs_info))
>>>    		return -ENAMETOOLONG;
>>> +	inode = new_inode(dir->i_sb);
>>> +	if (!inode)
>>> +		return -ENOMEM;
>>> +	inode_init_owner(mnt_userns, inode, dir, S_IFLNK | S_IRWXUGO);
>>> +	inode->i_op = &btrfs_symlink_inode_operations;
>>> +	inode_nohighmem(inode);
>>> +	inode->i_mapping->a_ops = &btrfs_aops;
>>> +
>>>    	/*
>>>    	 * 2 items for inode item and ref
>>>    	 * 2 items for dir items
>>> @@ -9749,28 +9772,19 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
>>>    	 * 1 item for xattr if selinux is on
>>>    	 */
>>>    	trans = btrfs_start_transaction(root, 7);
>>> -	if (IS_ERR(trans))
>>> +	if (IS_ERR(trans)) {
>>> +		iput(inode);
>>>    		return PTR_ERR(trans);
>>> +	}
>>> -	inode = btrfs_new_inode(trans, root, mnt_userns, dir,
>>> -				dentry->d_name.name, dentry->d_name.len,
>>> -				S_IFLNK | S_IRWXUGO, &index);
>>> -	if (IS_ERR(inode)) {
>>> -		err = PTR_ERR(inode);
>>> +	err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
>>> +			      dentry->d_name.len, &index);
>>> +	if (err) {
>>> +		iput(inode);
>>>    		inode = NULL;
>>>    		goto out_unlock;
>>>    	}
>>> -	/*
>>> -	* If the active LSM wants to access the inode during
>>> -	* d_instantiate it needs these. Smack checks to see
>>> -	* if the filesystem supports xattrs by looking at the
>>> -	* ops vector.
>>> -	*/
>>> -	inode->i_fop = &btrfs_file_operations;
>>> -	inode->i_op = &btrfs_file_inode_operations;
>>> -	inode->i_mapping->a_ops = &btrfs_aops;
>>> -
>>>    	err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
>>>    	if (err)
>>>    		goto out_unlock;
>>> @@ -9806,8 +9820,6 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
>>>    	btrfs_mark_buffer_dirty(leaf);
>>>    	btrfs_free_path(path);
>>> -	inode->i_op = &btrfs_symlink_inode_operations;
>>> -	inode_nohighmem(inode);
>>>    	inode_set_bytes(inode, name_len);
>>>    	btrfs_i_size_write(BTRFS_I(inode), name_len);
>>>    	err = btrfs_update_inode(trans, root, BTRFS_I(inode));
>>> @@ -10087,30 +10099,34 @@ static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
>>>    	struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
>>>    	struct btrfs_trans_handle *trans;
>>>    	struct btrfs_root *root = BTRFS_I(dir)->root;
>>> -	struct inode *inode = NULL;
>>> +	struct inode *inode;
>>>    	u64 index;
>>> -	int ret = 0;
>>> +	int ret;
>>> +
>>> +	inode = new_inode(dir->i_sb);
>>> +	if (!inode)
>>> +		return -ENOMEM;
>>> +	inode_init_owner(mnt_userns, inode, dir, mode);
>>> +	inode->i_fop = &btrfs_file_operations;
>>> +	inode->i_op = &btrfs_file_inode_operations;
>>> +	inode->i_mapping->a_ops = &btrfs_aops;
>>>    	/*
>>>    	 * 5 units required for adding orphan entry
>>>    	 */
>>>    	trans = btrfs_start_transaction(root, 5);
>>> -	if (IS_ERR(trans))
>>> +	if (IS_ERR(trans)) {
>>> +		iput(inode);
>>>    		return PTR_ERR(trans);
>>> +	}
>>> -	inode = btrfs_new_inode(trans, root, mnt_userns, dir, NULL, 0,
>>> -			mode, &index);
>>> -	if (IS_ERR(inode)) {
>>> -		ret = PTR_ERR(inode);
>>> +	ret = btrfs_new_inode(trans, root, inode, dir, NULL, 0, &index);
>>> +	if (ret) {
>>> +		iput(inode);
>>>    		inode = NULL;
>>>    		goto out;
>>>    	}
>>> -	inode->i_fop = &btrfs_file_operations;
>>> -	inode->i_op = &btrfs_file_inode_operations;
>>> -
>>> -	inode->i_mapping->a_ops = &btrfs_aops;
>>> -
>>>    	ret = btrfs_init_inode_security(trans, inode, dir, NULL);
>>>    	if (ret)
>>>    		goto out;
>>> diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
>>> index 891352fd6d0f..60c907b14547 100644
>>> --- a/fs/btrfs/ioctl.c
>>> +++ b/fs/btrfs/ioctl.c
>>> @@ -587,6 +587,12 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
>>>    	if (ret < 0)
>>>    		goto out_root_item;
>>> +	inode = btrfs_new_subvol_inode(mnt_userns, dir);
>>> +	if (!inode) {
>>> +		ret = -ENOMEM;
>>> +		goto out_anon_dev;
>>> +	}
>>> +
>>>    	btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP);
>>>    	/*
>>>    	 * The same as the snapshot creation, please see the comment
>>> @@ -594,13 +600,13 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
>>>    	 */
>>>    	ret = btrfs_subvolume_reserve_metadata(root, &block_rsv, 8, false);
>>>    	if (ret)
>>> -		goto out_anon_dev;
>>> +		goto out_inode;
>>>    	trans = btrfs_start_transaction(root, 0);
>>>    	if (IS_ERR(trans)) {
>>>    		ret = PTR_ERR(trans);
>>>    		btrfs_subvolume_release_metadata(root, &block_rsv);
>>> -		goto out_anon_dev;
>>> +		goto out_inode;
>>>    	}
>>>    	trans->block_rsv = &block_rsv;
>>>    	trans->bytes_reserved = block_rsv.size;
>>> @@ -683,16 +689,16 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
>>>    	}
>>>    	/* anon_dev is owned by new_root now. */
>>>    	anon_dev = 0;
>>> +	BTRFS_I(inode)->root = new_root;
>>> +	/* ... and new_root is owned by inode now. */
>>>    	ret = btrfs_record_root_in_trans(trans, new_root);
>>>    	if (ret) {
>>> -		btrfs_put_root(new_root);
>>>    		btrfs_abort_transaction(trans, ret);
>>>    		goto out;
>>>    	}
>>> -	ret = btrfs_create_subvol_root(trans, new_root, root, mnt_userns);
>>> -	btrfs_put_root(new_root);
>>> +	ret = btrfs_create_subvol_root(trans, root, inode);
>>>    	if (ret) {
>>>    		/* We potentially lose an unused inode item here */
>>>    		btrfs_abort_transaction(trans, ret);
>>> @@ -745,11 +751,11 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
>>>    		ret = btrfs_commit_transaction(trans);
>>>    	if (!ret) {
>>> -		inode = btrfs_lookup_dentry(dir, dentry);
>>> -		if (IS_ERR(inode))
>>> -			return PTR_ERR(inode);
>>>    		d_instantiate(dentry, inode);
>>> +		inode = NULL;
>>>    	}
>> I don't understand this. Why do we not need to look up the dentry anymore?
>> Was that always unneeded?
> We previously needed it because btrfs_create_subvol_root() did not
> return the struct inode it created, so to get it back here, we had to
> look it up. (In fact, it might even be the case that the struct inode
> allocated by btrfs_create_subvol_root() is freed by its call to iput(),
> and then btrfs_lookup_dentry() has to reread it from the B-tree, which
> would be silly.)
>
> But now create_subvol() allocates the inode itself, so it has it handy
> to use here.

Ahhh, makes sense. I mildly wish this were called out in the commit 
message, or this were in its own change, but I can see the argument that 
such a change would be rather small and maybe not worthwhile. Thanks!


^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 00/16] btrfs: inode creation cleanups and fixes
  2022-03-14 12:50 ` [PATCH v2 00/16] btrfs: inode creation cleanups and fixes David Sterba
@ 2022-03-14 18:42   ` Omar Sandoval
  2022-03-14 19:27     ` David Sterba
  0 siblings, 1 reply; 35+ messages in thread
From: Omar Sandoval @ 2022-03-14 18:42 UTC (permalink / raw)
  To: dsterba, linux-btrfs, kernel-team

On Mon, Mar 14, 2022 at 01:50:59PM +0100, David Sterba wrote:
> On Wed, Mar 09, 2022 at 05:31:30PM -0800, Omar Sandoval wrote:
> > From: Omar Sandoval <osandov@fb.com>
> > 
> > This series contains several cleanups and fixes for our inode creation
> > codepaths. The main motivation for this is preparation for fscrypt
> > support (in particular, setting up the fscrypt context and encrypted
> > names at inode creation time). But, it also reduces a lot of code
> > duplication and fixes some minor bugs, so it's worth getting in ahead of
> > time.
> > 
> > Patches 1-3 are small fixes. Patches 5-12 are small cleanups. Patches
> > 13-16 are the bulk of the change.
> > 
> > Based on misc-next.
> > 
> > Changes since v1 [1]:
> > 
> > - Split the big final patch into patches 3 and 13-16.
> > - Added Sweet Tea's reviewed-by to the remaining patches.
> > - Rebased on latest misc-next.
> > 
> > Thanks!
> > 
> > 1: https://lore.kernel.org/linux-btrfs/cover.1646348486.git.osandov@fb.com/
> > 
> > Omar Sandoval (16):
> >   btrfs: reserve correct number of items for unlink and rmdir
> >   btrfs: reserve correct number of items for rename
> >   btrfs: fix anon_dev leak in create_subvol()
> >   btrfs: get rid of btrfs_add_nondir()
> >   btrfs: remove unnecessary btrfs_i_size_write(0) calls
> >   btrfs: remove unnecessary inode_set_bytes(0) call
> >   btrfs: remove unnecessary set_nlink() in btrfs_create_subvol_root()
> >   btrfs: remove unused mnt_userns parameter from __btrfs_set_acl
> >   btrfs: remove redundant name and name_len parameters to create_subvol
> >   btrfs: don't pass parent objectid to btrfs_new_inode() explicitly
> >   btrfs: move btrfs_get_free_objectid() call into btrfs_new_inode()
> >   btrfs: set inode flags earlier in btrfs_new_inode()
> >   btrfs: allocate inode outside of btrfs_new_inode()
> 
> Patches 1-13 added to misc-next. The remaining patches seem to be still
> a bit big for review.

I see that misc-next has the whole series, did you change your mind? I
was going to resend with a couple of Sweet Tea's comments addressed
(passing btrfs_new_inode_args to btrfs_init_inode_security() and
mentioning the d_instantiate() change in the commit message for patch
13), but I don't see a good way to split these up further.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 00/16] btrfs: inode creation cleanups and fixes
  2022-03-14 18:42   ` Omar Sandoval
@ 2022-03-14 19:27     ` David Sterba
  2022-03-14 19:55       ` Omar Sandoval
  0 siblings, 1 reply; 35+ messages in thread
From: David Sterba @ 2022-03-14 19:27 UTC (permalink / raw)
  To: Omar Sandoval; +Cc: dsterba, linux-btrfs, kernel-team

On Mon, Mar 14, 2022 at 11:42:17AM -0700, Omar Sandoval wrote:
> On Mon, Mar 14, 2022 at 01:50:59PM +0100, David Sterba wrote:
> > On Wed, Mar 09, 2022 at 05:31:30PM -0800, Omar Sandoval wrote:
> > > - Added Sweet Tea's reviewed-by to the remaining patches.
> > > - Rebased on latest misc-next.
> > > 
> > > Thanks!
> > > 
> > > 1: https://lore.kernel.org/linux-btrfs/cover.1646348486.git.osandov@fb.com/
> > > 
> > > Omar Sandoval (16):
> > >   btrfs: reserve correct number of items for unlink and rmdir
> > >   btrfs: reserve correct number of items for rename
> > >   btrfs: fix anon_dev leak in create_subvol()
> > >   btrfs: get rid of btrfs_add_nondir()
> > >   btrfs: remove unnecessary btrfs_i_size_write(0) calls
> > >   btrfs: remove unnecessary inode_set_bytes(0) call
> > >   btrfs: remove unnecessary set_nlink() in btrfs_create_subvol_root()
> > >   btrfs: remove unused mnt_userns parameter from __btrfs_set_acl
> > >   btrfs: remove redundant name and name_len parameters to create_subvol
> > >   btrfs: don't pass parent objectid to btrfs_new_inode() explicitly
> > >   btrfs: move btrfs_get_free_objectid() call into btrfs_new_inode()
> > >   btrfs: set inode flags earlier in btrfs_new_inode()
> > >   btrfs: allocate inode outside of btrfs_new_inode()
> > 
> > Patches 1-13 added to misc-next. The remaining patches seem to be still
> > a bit big for review.
> 
> I see that misc-next has the whole series, did you change your mind? I

I added the branch to misc-next on friday and noticed some comments for
the the patches at the end, so I removed them again.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 00/16] btrfs: inode creation cleanups and fixes
  2022-03-14 19:27     ` David Sterba
@ 2022-03-14 19:55       ` Omar Sandoval
  0 siblings, 0 replies; 35+ messages in thread
From: Omar Sandoval @ 2022-03-14 19:55 UTC (permalink / raw)
  To: dsterba, linux-btrfs, kernel-team

On Mon, Mar 14, 2022 at 08:27:03PM +0100, David Sterba wrote:
> On Mon, Mar 14, 2022 at 11:42:17AM -0700, Omar Sandoval wrote:
> > On Mon, Mar 14, 2022 at 01:50:59PM +0100, David Sterba wrote:
> > > On Wed, Mar 09, 2022 at 05:31:30PM -0800, Omar Sandoval wrote:
> > > > - Added Sweet Tea's reviewed-by to the remaining patches.
> > > > - Rebased on latest misc-next.
> > > > 
> > > > Thanks!
> > > > 
> > > > 1: https://lore.kernel.org/linux-btrfs/cover.1646348486.git.osandov@fb.com/
> > > > 
> > > > Omar Sandoval (16):
> > > >   btrfs: reserve correct number of items for unlink and rmdir
> > > >   btrfs: reserve correct number of items for rename
> > > >   btrfs: fix anon_dev leak in create_subvol()
> > > >   btrfs: get rid of btrfs_add_nondir()
> > > >   btrfs: remove unnecessary btrfs_i_size_write(0) calls
> > > >   btrfs: remove unnecessary inode_set_bytes(0) call
> > > >   btrfs: remove unnecessary set_nlink() in btrfs_create_subvol_root()
> > > >   btrfs: remove unused mnt_userns parameter from __btrfs_set_acl
> > > >   btrfs: remove redundant name and name_len parameters to create_subvol
> > > >   btrfs: don't pass parent objectid to btrfs_new_inode() explicitly
> > > >   btrfs: move btrfs_get_free_objectid() call into btrfs_new_inode()
> > > >   btrfs: set inode flags earlier in btrfs_new_inode()
> > > >   btrfs: allocate inode outside of btrfs_new_inode()
> > > 
> > > Patches 1-13 added to misc-next. The remaining patches seem to be still
> > > a bit big for review.
> > 
> > I see that misc-next has the whole series, did you change your mind? I
> 
> I added the branch to misc-next on friday and noticed some comments for
> the the patches at the end, so I removed them again.

I see. I'll resend 13-16 with the updates.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 13/16] btrfs: allocate inode outside of btrfs_new_inode()
  2022-03-10  1:31 ` [PATCH v2 13/16] btrfs: allocate inode outside of btrfs_new_inode() Omar Sandoval
  2022-03-11 17:11   ` Sweet Tea Dorminy
@ 2022-03-14 23:33   ` Filipe Manana
  2022-03-15  0:16     ` Omar Sandoval
  1 sibling, 1 reply; 35+ messages in thread
From: Filipe Manana @ 2022-03-14 23:33 UTC (permalink / raw)
  To: Omar Sandoval; +Cc: linux-btrfs, kernel-team

On Thu, Mar 10, 2022 at 4:56 AM Omar Sandoval <osandov@osandov.com> wrote:
>
> From: Omar Sandoval <osandov@fb.com>
>
> Instead of calling new_inode() and inode_init_owner() inside of
> btrfs_new_inode(), do it in the callers. This allows us to pass in just
> the inode instead of the mnt_userns and mode and removes the need for
> memalloc_nofs_{save,restores}() since we do it before starting a
> transaction. This also paves the way for some more cleanups in later
> patches.
>
> This also removes the comments about Smack checking i_op, which are no
> longer true since commit 5d6c31910bc0 ("xattr: Add
> __vfs_{get,set,remove}xattr helpers"). Now it checks inode->i_opflags &
> IOP_XATTR, which is set based on sb->s_xattr.
>
> Signed-off-by: Omar Sandoval <osandov@fb.com>

There's some leak here Omar.

misc-next is triggering tons of these on dmesg:

[ 1476.957056] run fstests btrfs/232 at 2022-03-14 23:30:17
[ 1477.657768] BTRFS: device fsid 9674450f-5f48-4518-97d1-c69714c76a89
devid 1 transid 5 /dev/sdc scanned by mkfs.btrfs (96574)
[ 1477.701683] BTRFS info (device sdc): flagging fs with big metadata feature
[ 1477.701689] BTRFS info (device sdc): disk space caching is enabled
[ 1477.701691] BTRFS info (device sdc): has skinny extents
[ 1477.708205] BTRFS info (device sdc): checking UUID tree
[ 1486.226044] BTRFS warning (device sdc): qgroup rescan is already in progress
[ 1486.232228] BTRFS info (device sdc): qgroup scan completed
(inconsistency flag cleared)
[ 1520.615331] BTRFS warning (device sdc): page private not zero on
page 38846464
[ 1520.615350] BTRFS warning (device sdc): page private not zero on
page 38850560
[ 1520.615365] BTRFS warning (device sdc): page private not zero on
page 38854656
[ 1520.615380] BTRFS warning (device sdc): page private not zero on
page 38858752
[ 1520.615394] BTRFS warning (device sdc): page private not zero on
page 44597248
[ 1520.615409] BTRFS warning (device sdc): page private not zero on
page 44601344
[ 1520.615423] BTRFS warning (device sdc): page private not zero on
page 44605440
[ 1520.615482] BTRFS warning (device sdc): page private not zero on
page 44609536
[ 1520.615496] BTRFS warning (device sdc): page private not zero on
page 47349760
[ 1520.615511] BTRFS warning (device sdc): page private not zero on
page 47353856
[ 1520.615525] BTRFS warning (device sdc): page private not zero on
page 47357952
[ 1520.615539] BTRFS warning (device sdc): page private not zero on
page 47362048
[ 1520.615554] BTRFS warning (device sdc): page private not zero on
page 56229888
[ 1520.615568] BTRFS warning (device sdc): page private not zero on
page 56233984
[ 1520.615582] BTRFS warning (device sdc): page private not zero on
page 56238080
[ 1520.615596] BTRFS warning (device sdc): page private not zero on
page 56242176
[ 1520.615611] BTRFS warning (device sdc): page private not zero on
page 59228160
[ 1520.615625] BTRFS warning (device sdc): page private not zero on
page 59232256
[ 1520.615640] BTRFS warning (device sdc): page private not zero on
page 59236352
[ 1520.615654] BTRFS warning (device sdc): page private not zero on
page 59240448
[ 1520.615668] BTRFS warning (device sdc): page private not zero on
page 60702720
[ 1520.615682] BTRFS warning (device sdc): page private not zero on
page 60706816
[ 1520.615722] BTRFS warning (device sdc): page private not zero on
page 60710912
[ 1520.615736] BTRFS warning (device sdc): page private not zero on
page 60715008
[ 1520.615751] BTRFS warning (device sdc): page private not zero on
page 60719104
[ 1520.615765] BTRFS warning (device sdc): page private not zero on
page 60723200
[ 1520.615779] BTRFS warning (device sdc): page private not zero on
page 60727296
[ 1520.615793] BTRFS warning (device sdc): page private not zero on
page 60731392
[ 1520.615808] BTRFS warning (device sdc): page private not zero on
page 62930944
[ 1520.615822] BTRFS warning (device sdc): page private not zero on
page 62935040
[ 1520.615836] BTRFS warning (device sdc): page private not zero on
page 62939136
[ 1520.615851] BTRFS warning (device sdc): page private not zero on
page 62943232
[ 1520.615865] BTRFS warning (device sdc): page private not zero on
page 69533696
[ 1520.615879] BTRFS warning (device sdc): page private not zero on
page 69537792
[ 1520.615893] BTRFS warning (device sdc): page private not zero on
page 69541888
[ 1520.615908] BTRFS warning (device sdc): page private not zero on
page 69545984
[ 1520.615922] BTRFS warning (device sdc): page private not zero on
page 73629696
[ 1520.615959] BTRFS warning (device sdc): page private not zero on
page 73633792
[ 1520.615973] BTRFS warning (device sdc): page private not zero on
page 73637888
[ 1520.615987] BTRFS warning (device sdc): page private not zero on
page 73641984
[ 1520.616002] BTRFS warning (device sdc): page private not zero on
page 83623936
[ 1520.616016] BTRFS warning (device sdc): page private not zero on
page 83628032
[ 1520.616030] BTRFS warning (device sdc): page private not zero on
page 83632128
[ 1520.616045] BTRFS warning (device sdc): page private not zero on
page 83636224
[ 1520.616059] BTRFS warning (device sdc): page private not zero on
page 86884352
[ 1520.616073] BTRFS warning (device sdc): page private not zero on
page 86888448
[ 1520.616088] BTRFS warning (device sdc): page private not zero on
page 86892544
[ 1520.616102] BTRFS warning (device sdc): page private not zero on
page 86896640
[ 1520.616116] BTRFS warning (device sdc): page private not zero on
page 92979200
[ 1520.616130] BTRFS warning (device sdc): page private not zero on
page 92983296
[ 1520.616145] BTRFS warning (device sdc): page private not zero on
page 92987392
[ 1520.616159] BTRFS warning (device sdc): page private not zero on
page 92991488
[ 1520.616212] BTRFS warning (device sdc): page private not zero on
page 97697792
[ 1520.616227] BTRFS warning (device sdc): page private not zero on
page 97701888
[ 1520.616241] BTRFS warning (device sdc): page private not zero on
page 97705984
[ 1520.616255] BTRFS warning (device sdc): page private not zero on
page 97710080
[ 1520.616270] BTRFS warning (device sdc): page private not zero on
page 100270080
[ 1520.616284] BTRFS warning (device sdc): page private not zero on
page 100274176
[ 1520.616298] BTRFS warning (device sdc): page private not zero on
page 100278272
[ 1520.616313] BTRFS warning (device sdc): page private not zero on
page 100282368
[ 1520.616327] BTRFS warning (device sdc): page private not zero on
page 104431616
[ 1520.616341] BTRFS warning (device sdc): page private not zero on
page 104435712
[ 1520.616356] BTRFS warning (device sdc): page private not zero on
page 104439808
[ 1520.616403] BTRFS warning (device sdc): page private not zero on
page 104443904
[ 1520.616418] BTRFS warning (device sdc): page private not zero on
page 110411776
[ 1520.616432] BTRFS warning (device sdc): page private not zero on
page 110415872
[ 1520.616446] BTRFS warning (device sdc): page private not zero on
page 110419968
[ 1520.616461] BTRFS warning (device sdc): page private not zero on
page 110424064
[ 1520.616475] BTRFS warning (device sdc): page private not zero on
page 110854144
[ 1520.616489] BTRFS warning (device sdc): page private not zero on
page 110858240
[ 1520.616503] BTRFS warning (device sdc): page private not zero on
page 110862336
[ 1520.616518] BTRFS warning (device sdc): page private not zero on
page 110866432
[ 1520.616532] BTRFS warning (device sdc): page private not zero on
page 113491968
[ 1520.616546] BTRFS warning (device sdc): page private not zero on
page 113496064
[ 1520.616560] BTRFS warning (device sdc): page private not zero on
page 113500160
[ 1520.616575] BTRFS warning (device sdc): page private not zero on
page 113504256
[ 1520.616589] BTRFS warning (device sdc): page private not zero on
page 118177792
[ 1520.616603] BTRFS warning (device sdc): page private not zero on
page 118181888
[ 1520.616639] BTRFS warning (device sdc): page private not zero on
page 118185984
[ 1520.616654] BTRFS warning (device sdc): page private not zero on
page 118190080
[ 1520.616668] BTRFS warning (device sdc): page private not zero on
page 118210560
[ 1520.616682] BTRFS warning (device sdc): page private not zero on
page 118214656
[ 1520.616696] BTRFS warning (device sdc): page private not zero on
page 118218752
[ 1520.616711] BTRFS warning (device sdc): page private not zero on
page 118222848
[ 1520.616725] BTRFS warning (device sdc): page private not zero on
page 121749504
[ 1520.616739] BTRFS warning (device sdc): page private not zero on
page 121753600
[ 1520.616754] BTRFS warning (device sdc): page private not zero on
page 121757696
[ 1520.616768] BTRFS warning (device sdc): page private not zero on
page 121761792
[ 1520.616782] BTRFS warning (device sdc): page private not zero on
page 128712704
[ 1520.616797] BTRFS warning (device sdc): page private not zero on
page 128716800
[ 1520.616811] BTRFS warning (device sdc): page private not zero on
page 128720896
[ 1520.616825] BTRFS warning (device sdc): page private not zero on
page 128724992
[ 1520.616840] BTRFS warning (device sdc): page private not zero on
page 135806976
[ 1520.616879] BTRFS warning (device sdc): page private not zero on
page 135811072
[ 1520.616894] BTRFS warning (device sdc): page private not zero on
page 135815168
[ 1520.616908] BTRFS warning (device sdc): page private not zero on
page 135819264
[ 1520.616922] BTRFS warning (device sdc): page private not zero on
page 138182656
[ 1520.616936] BTRFS warning (device sdc): page private not zero on
page 138186752
[ 1520.616951] BTRFS warning (device sdc): page private not zero on
page 138190848
[ 1520.616965] BTRFS warning (device sdc): page private not zero on
page 138194944
[ 1520.631273] BTRFS error (device sdc): leaked root 259 refcount 1
[ 1520.632324] BTRFS error (device sdc): leaked root 260 refcount 1
[ 1520.633439] BTRFS error (device sdc): leaked root 258 refcount 1
[ 1520.634585] BTRFS error (device sdc): leaked root 261 refcount 1
[ 1520.635817] BTRFS error (device sdc): leaked root 262 refcount 1
[ 1520.636954] BTRFS error (device sdc): leaked root 263 refcount 1
[ 1520.638021] BTRFS error (device sdc): leaked root 264 refcount 1
[ 1520.639023] BTRFS error (device sdc): leaked root 265 refcount 1
[ 1520.640117] BTRFS error (device sdc): leaked root 267 refcount 1
[ 1520.641238] BTRFS error (device sdc): leaked root 268 refcount 1
[ 1520.642317] BTRFS error (device sdc): leaked root 269 refcount 1
[ 1520.643405] BTRFS error (device sdc): leaked root 271 refcount 1
[ 1520.644567] BTRFS error (device sdc): leaked root 272 refcount 1
[ 1520.645708] BTRFS error (device sdc): leaked root 273 refcount 1
[ 1520.646843] BTRFS error (device sdc): leaked root 274 refcount 1
[ 1520.647923] BTRFS error (device sdc): leaked root 276 refcount 1
[ 1520.649052] BTRFS error (device sdc): leaked root 277 refcount 1
[ 1520.650195] BTRFS error (device sdc): leaked root 280 refcount 1
[ 1520.651361] BTRFS error (device sdc): leaked root 281 refcount 1
[ 1520.652496] BTRFS error (device sdc): leaked root 284 refcount 1
[ 1520.653645] BTRFS error (device sdc): leaked root 285 refcount 1
[ 1520.654804] BTRFS error (device sdc): leaked root 286 refcount 1
[ 1520.655826] BTRFS error (device sdc): leaked root 288 refcount 1
[ 1520.656913] BTRFS error (device sdc): leaked root 289 refcount 1
[ 1520.658003] BTRFS error (device sdc): leaked root 291 refcount 1
[ 1520.659218] BTRFS error (device sdc): leaked root 292 refcount 1
[ 1520.660322] BTRFS error (device sdc): leaked root 296 refcount 1
[ 1520.661473] BTRFS error (device sdc): leaked root 297 refcount 1
[ 1520.662641] BTRFS error (device sdc): leaked root 298 refcount 1
[ 1520.663850] BTRFS error (device sdc): leaked root 302 refcount 1
[ 1520.664974] BTRFS error (device sdc): leaked root 303 refcount 1
[ 1520.666122] BTRFS error (device sdc): leaked root 304 refcount 1
[ 1520.667245] BTRFS error (device sdc): leaked root 305 refcount 1
[ 1520.668027] BTRFS error (device sdc): leaked root 306 refcount 1
[ 1520.668799] BTRFS error (device sdc): leaked root 307 refcount 1
[ 1520.669571] BTRFS error (device sdc): leaked root 310 refcount 1
[ 1520.670353] BTRFS error (device sdc): leaked root 311 refcount 1
[ 1520.671175] BTRFS error (device sdc): leaked root 316 refcount 1
[ 1520.672003] BTRFS error (device sdc): leaked root 319 refcount 1
[ 1520.672945] BTRFS error (device sdc): leaked root 321 refcount 1
[ 1520.673892] BTRFS error (device sdc): leaked root 320 refcount 1
[ 1520.674726] BTRFS error (device sdc): leaked root 324 refcount 1
[ 1520.675626] BTRFS error (device sdc): leaked root 325 refcount 1
[ 1520.676484] BTRFS error (device sdc): leaked root 326 refcount 1
[ 1520.677252] BTRFS error (device sdc): leaked root 327 refcount 1
[ 1520.678168] BTRFS error (device sdc): leaked root 329 refcount 1
[ 1520.679144] BTRFS error (device sdc): leaked root 330 refcount 1
[ 1520.680253] BTRFS error (device sdc): leaked root 332 refcount 1
[ 1520.681365] BTRFS error (device sdc): leaked root 337 refcount 1
[ 1520.682482] BTRFS error (device sdc): leaked root 336 refcount 1
[ 1520.683614] BTRFS error (device sdc): leaked root 333 refcount 1
[ 1520.684725] BTRFS error (device sdc): leaked root 339 refcount 1
[ 1520.685831] BTRFS error (device sdc): leaked root 334 refcount 1
[ 1520.686935] BTRFS error (device sdc): leaked root 335 refcount 1
[ 1520.688060] BTRFS error (device sdc): leaked root 338 refcount 1
[ 1520.689162] BTRFS error (device sdc): leaked root 342 refcount 1
[ 1520.690266] BTRFS error (device sdc): leaked root 344 refcount 1
[ 1520.691402] BTRFS error (device sdc): leaked root 345 refcount 1
[ 1520.692511] BTRFS error (device sdc): leaked root 346 refcount 1
[ 1520.693613] BTRFS error (device sdc): leaked root 350 refcount 1
[ 1520.694735] BTRFS error (device sdc): leaked root 351 refcount 1
[ 1520.695727] BTRFS error (device sdc): leaked root 352 refcount 1
[ 1520.696645] BTRFS error (device sdc): leaked root 353 refcount 1
[ 1520.697540] BTRFS error (device sdc): leaked root 354 refcount 1
[ 1520.698471] BTRFS error (device sdc): leaked root 357 refcount 1
[ 1520.699382] BTRFS error (device sdc): leaked root 359 refcount 1
[ 1520.700353] BTRFS error (device sdc): leaked root 361 refcount 1
[ 1520.701256] BTRFS error (device sdc): leaked root 362 refcount 1
[ 1520.702216] BTRFS error (device sdc): leaked root 367 refcount 1
[ 1520.703215] BTRFS error (device sdc): leaked root 365 refcount 1
[ 1520.704263] BTRFS error (device sdc): leaked root 366 refcount 1
[ 1520.705337] BTRFS error (device sdc): leaked root 372 refcount 1
[ 1520.706426] BTRFS error (device sdc): leaked root 375 refcount 1
[ 1520.707552] BTRFS error (device sdc): leaked root 376 refcount 1
[ 1520.708677] BTRFS error (device sdc): leaked root 378 refcount 1
[ 1520.709812] BTRFS error (device sdc): leaked root 382 refcount 1
[ 1520.710918] BTRFS error (device sdc): leaked root 383 refcount 1
[ 1520.712052] BTRFS error (device sdc): leaked root 384 refcount 1
[ 1520.713288] BTRFS error (device sdc): leaked root 388 refcount 1
[ 1520.714400] BTRFS error (device sdc): leaked root 391 refcount 1
[ 1520.715526] BTRFS error (device sdc): leaked root 394 refcount 1
[ 1520.716631] BTRFS error (device sdc): leaked root 398 refcount 1
[ 1520.717743] BTRFS error (device sdc): leaked root 404 refcount 1
[ 1520.718856] BTRFS error (device sdc): leaked root 405 refcount 1
[ 1520.719690] BTRFS error (device sdc): leaked root 407 refcount 1
[ 1520.720441] BTRFS error (device sdc): leaked root 406 refcount 1
[ 1520.721192] BTRFS error (device sdc): leaked root 408 refcount 1
[ 1520.721977] BTRFS error (device sdc): leaked root 410 refcount 1
[ 1520.722738] BTRFS error (device sdc): leaked root 412 refcount 1
[ 1520.723538] BTRFS error (device sdc): leaked root 411 refcount 1
[ 1520.724311] BTRFS error (device sdc): leaked root 417 refcount 1
[ 1520.725048] BTRFS error (device sdc): leaked root 418 refcount 1
[ 1520.725833] BTRFS error (device sdc): leaked root 420 refcount 1
[ 1520.726608] BTRFS error (device sdc): leaked root 423 refcount 1
[ 1520.727401] BTRFS error (device sdc): leaked root 424 refcount 1
[ 1520.728171] BTRFS error (device sdc): leaked root 425 refcount 1
[ 1520.728923] BTRFS error (device sdc): leaked root 426 refcount 1
[ 1520.729777] BTRFS error (device sdc): leaked root 428 refcount 1
[ 1520.730625] BTRFS error (device sdc): leaked root 430 refcount 1
[ 1520.731687] BTRFS error (device sdc): leaked root 429 refcount 1
[ 1520.733214] BTRFS: buffer leak start 650739712 len 16384 refs 1
bflags 529 owner 483
[ 1520.734174] BTRFS: buffer leak start 648740864 len 16384 refs 1
bflags 529 owner 468
[ 1520.735134] BTRFS: buffer leak start 647577600 len 16384 refs 1
bflags 529 owner 649
[ 1520.736077] BTRFS: buffer leak start 647512064 len 16384 refs 1
bflags 529 owner 651
[ 1520.737023] BTRFS: buffer leak start 645873664 len 16384 refs 1
bflags 529 owner 449
[ 1520.737975] BTRFS: buffer leak start 645562368 len 16384 refs 1
bflags 529 owner 376
[ 1520.738923] BTRFS: buffer leak start 645218304 len 16384 refs 1
bflags 529 owner 633
[ 1520.739879] BTRFS: buffer leak start 645185536 len 16384 refs 1
bflags 529 owner 365
[ 1520.740819] BTRFS: buffer leak start 644382720 len 16384 refs 1
bflags 529 owner 640
[ 1520.741769] BTRFS: buffer leak start 639467520 len 16384 refs 1
bflags 529 owner 439
[ 1520.742706] BTRFS: buffer leak start 638517248 len 16384 refs 1
bflags 529 owner 647
[ 1520.743649] BTRFS: buffer leak start 621477888 len 16384 refs 1
bflags 529 owner 391
[ 1520.744584] BTRFS: buffer leak start 621428736 len 16384 refs 1
bflags 529 owner 484
[ 1520.745518] BTRFS: buffer leak start 621412352 len 16384 refs 1
bflags 529 owner 418
[ 1520.746460] BTRFS: buffer leak start 621395968 len 16384 refs 1
bflags 529 owner 375
[ 1520.747403] BTRFS: buffer leak start 615235584 len 16384 refs 1
bflags 529 owner 645
[ 1520.748345] BTRFS: buffer leak start 607076352 len 16384 refs 1
bflags 529 owner 444
[ 1520.749296] BTRFS: buffer leak start 607027200 len 16384 refs 1
bflags 529 owner 643
[ 1520.750320] BTRFS: buffer leak start 602423296 len 16384 refs 1
bflags 529 owner 534
[ 1520.751285] BTRFS: buffer leak start 602177536 len 16384 refs 1
bflags 529 owner 333
[ 1520.752228] BTRFS: buffer leak start 601587712 len 16384 refs 1
bflags 529 owner 420
[ 1520.753203] BTRFS: buffer leak start 600834048 len 16384 refs 1
bflags 529 owner 359
[ 1520.754145] BTRFS: buffer leak start 597262336 len 16384 refs 1
bflags 529 owner 561
[ 1520.755106] BTRFS: buffer leak start 597082112 len 16384 refs 1
bflags 529 owner 570
[ 1520.756041] BTRFS: buffer leak start 595820544 len 16384 refs 1
bflags 529 owner 477
[ 1520.756980] BTRFS: buffer leak start 594903040 len 16384 refs 1
bflags 529 owner 629
[ 1520.757988] BTRFS: buffer leak start 593575936 len 16384 refs 1
bflags 529 owner 311
[ 1520.758962] BTRFS: buffer leak start 592822272 len 16384 refs 1
bflags 529 owner 426
[ 1520.759928] BTRFS: buffer leak start 591052800 len 16384 refs 1
bflags 529 owner 620
[ 1520.760883] BTRFS: buffer leak start 585383936 len 16384 refs 1
bflags 529 owner 627
[ 1520.761862] BTRFS: buffer leak start 581173248 len 16384 refs 1
bflags 529 owner 599
[ 1520.762809] BTRFS: buffer leak start 579321856 len 16384 refs 1
bflags 529 owner 601
[ 1520.763780] BTRFS: buffer leak start 577994752 len 16384 refs 1
bflags 529 owner 320
[ 1520.764722] BTRFS: buffer leak start 573882368 len 16384 refs 1
bflags 529 owner 430
[ 1520.765661] BTRFS: buffer leak start 571965440 len 16384 refs 1
bflags 529 owner 542
[ 1520.766656] BTRFS: buffer leak start 567951360 len 16384 refs 1
bflags 529 owner 406
[ 1520.767631] BTRFS: buffer leak start 564953088 len 16384 refs 1
bflags 529 owner 624
[ 1520.768581] BTRFS: buffer leak start 562823168 len 16384 refs 1
bflags 529 owner 310
[ 1520.769579] BTRFS: buffer leak start 556138496 len 16384 refs 1
bflags 529 owner 579
[ 1520.770755] BTRFS: buffer leak start 554008576 len 16384 refs 1
bflags 529 owner 615
[ 1520.771905] BTRFS: buffer leak start 550092800 len 16384 refs 1
bflags 529 owner 612
[ 1520.773016] BTRFS: buffer leak start 545488896 len 16384 refs 1
bflags 529 owner 326
[ 1520.774173] BTRFS: buffer leak start 545374208 len 16384 refs 1
bflags 529 owner 297
[ 1520.775263] BTRFS: buffer leak start 542048256 len 16384 refs 1
bflags 529 owner 273
[ 1520.776238] BTRFS: buffer leak start 541999104 len 16384 refs 1
bflags 529 owner 606
[ 1520.777211] BTRFS: buffer leak start 541261824 len 16384 refs 1
bflags 529 owner 513
[ 1520.778177] BTRFS: buffer leak start 539721728 len 16384 refs 1
bflags 529 owner 424
[ 1520.779159] BTRFS: buffer leak start 538460160 len 16384 refs 1
bflags 529 owner 544
[ 1520.780134] BTRFS: buffer leak start 535248896 len 16384 refs 1
bflags 529 owner 566
[ 1520.781096] BTRFS: buffer leak start 534986752 len 16384 refs 1
bflags 529 owner 277
[ 1520.782076] BTRFS: buffer leak start 530939904 len 16384 refs 1
bflags 529 owner 582
[ 1520.783037] BTRFS: buffer leak start 530448384 len 16384 refs 1
bflags 529 owner 354
[ 1520.784050] BTRFS: buffer leak start 529285120 len 16384 refs 1
bflags 529 owner 584
[ 1520.785025] BTRFS: buffer leak start 529022976 len 16384 refs 1
bflags 529 owner 285
[ 1520.786034] BTRFS: buffer leak start 527679488 len 16384 refs 1
bflags 529 owner 578
[ 1520.787026] BTRFS: buffer leak start 526352384 len 16384 refs 1
bflags 529 owner 274
[ 1520.788001] BTRFS: buffer leak start 521420800 len 16384 refs 1
bflags 529 owner 536
[ 1520.788947] BTRFS: buffer leak start 520273920 len 16384 refs 1
bflags 529 owner 352
[ 1520.789906] BTRFS: buffer leak start 516194304 len 16384 refs 1
bflags 529 owner 549
[ 1520.790845] BTRFS: buffer leak start 515571712 len 16384 refs 1
bflags 529 owner 452
[ 1520.791803] BTRFS: buffer leak start 515473408 len 16384 refs 1
bflags 529 owner 357
[ 1520.792753] BTRFS: buffer leak start 514818048 len 16384 refs 1
bflags 529 owner 417
[ 1520.793708] BTRFS: buffer leak start 512835584 len 16384 refs 1
bflags 529 owner 590
[ 1520.794700] BTRFS: buffer leak start 512540672 len 16384 refs 1
bflags 529 owner 411
[ 1520.795670] BTRFS: buffer leak start 512491520 len 16384 refs 1
bflags 529 owner 350
[ 1520.796610] BTRFS: buffer leak start 508936192 len 16384 refs 1
bflags 529 owner 472
[ 1520.797571] BTRFS: buffer leak start 502546432 len 16384 refs 1
bflags 529 owner 591
[ 1520.798531] BTRFS: buffer leak start 501366784 len 16384 refs 1
bflags 529 owner 585
[ 1520.799494] BTRFS: buffer leak start 501235712 len 16384 refs 1
bflags 529 owner 580
[ 1520.800440] BTRFS: buffer leak start 500203520 len 16384 refs 1
bflags 529 owner 558
[ 1520.801386] BTRFS: buffer leak start 495648768 len 16384 refs 1
bflags 529 owner 583
[ 1520.802346] BTRFS: buffer leak start 493813760 len 16384 refs 1
bflags 529 owner 525
[ 1520.803310] BTRFS: buffer leak start 490881024 len 16384 refs 1
bflags 529 owner 492
[ 1520.804247] BTRFS: buffer leak start 486146048 len 16384 refs 1
bflags 529 owner 581
[ 1520.805196] BTRFS: buffer leak start 474529792 len 16384 refs 1
bflags 529 owner 263
[ 1520.806172] BTRFS: buffer leak start 474185728 len 16384 refs 1
bflags 529 owner 576
[ 1520.807146] BTRFS: buffer leak start 466354176 len 16384 refs 1
bflags 529 owner 575
[ 1520.808094] BTRFS: buffer leak start 454000640 len 16384 refs 1
bflags 529 owner 478
[ 1520.809049] BTRFS: buffer leak start 451657728 len 16384 refs 1
bflags 529 owner 384
[ 1520.810027] BTRFS: buffer leak start 451575808 len 16384 refs 1
bflags 529 owner 259
[ 1520.810975] BTRFS: buffer leak start 448479232 len 16384 refs 1
bflags 529 owner 286
[ 1520.811942] BTRFS: buffer leak start 446103552 len 16384 refs 1
bflags 529 owner 521
[ 1520.812890] BTRFS: buffer leak start 444252160 len 16384 refs 1
bflags 529 owner 344
[ 1520.813867] BTRFS: buffer leak start 437616640 len 16384 refs 1
bflags 529 owner 304
[ 1520.814942] BTRFS: buffer leak start 428965888 len 16384 refs 1
bflags 529 owner 366
[ 1520.815918] BTRFS: buffer leak start 428195840 len 16384 refs 1
bflags 529 owner 268
[ 1520.816872] BTRFS: buffer leak start 426901504 len 16384 refs 1
bflags 529 owner 556
[ 1520.817842] BTRFS: buffer leak start 424935424 len 16384 refs 1
bflags 529 owner 554
[ 1520.818791] BTRFS: buffer leak start 424476672 len 16384 refs 1
bflags 529 owner 288
[ 1520.819766] BTRFS: buffer leak start 422592512 len 16384 refs 1
bflags 529 owner 553
[ 1520.820817] BTRFS: buffer leak start 418512896 len 16384 refs 1
bflags 529 owner 448
[ 1520.821793] BTRFS: buffer leak start 415072256 len 16384 refs 1
bflags 529 owner 429
[ 1520.822742] BTRFS: buffer leak start 408682496 len 16384 refs 1
bflags 529 owner 531
[ 1520.823712] BTRFS: buffer leak start 401932288 len 16384 refs 1
bflags 529 owner 532
[ 1520.824666] BTRFS: buffer leak start 400900096 len 16384 refs 1
bflags 529 owner 539
[ 1520.825684] BTRFS: buffer leak start 400359424 len 16384 refs 1
bflags 529 owner 470
[ 1520.826825] BTRFS: buffer leak start 397787136 len 16384 refs 1
bflags 529 owner 537
[ 1520.827780] BTRFS: buffer leak start 388071424 len 16384 refs 1
bflags 529 owner 456
[ 1520.828719] BTRFS: buffer leak start 384303104 len 16384 refs 1
bflags 529 owner 522
[ 1520.829659] BTRFS: buffer leak start 383123456 len 16384 refs 1
bflags 529 owner 339
[ 1520.830613] BTRFS: buffer leak start 377585664 len 16384 refs 1
bflags 529 owner 498
[ 1520.831569] BTRFS: buffer leak start 375209984 len 16384 refs 1
bflags 529 owner 305
[ 1520.832590] BTRFS: buffer leak start 375013376 len 16384 refs 1
bflags 529 owner 264
[ 1520.833551] BTRFS: buffer leak start 374145024 len 16384 refs 1
bflags 529 owner 362
[ 1520.834520] BTRFS: buffer leak start 373260288 len 16384 refs 1
bflags 529 owner 327
[ 1520.835503] BTRFS: buffer leak start 371933184 len 16384 refs 1
bflags 529 owner 502
[ 1520.836468] BTRFS: buffer leak start 355844096 len 16384 refs 1
bflags 529 owner 455
[ 1520.837449] BTRFS: buffer leak start 340525056 len 16384 refs 1
bflags 529 owner 262
[ 1520.838413] BTRFS: buffer leak start 340262912 len 16384 refs 1
bflags 529 owner 388
[ 1520.839375] BTRFS: buffer leak start 340246528 len 16384 refs 1
bflags 529 owner 479
[ 1520.840320] BTRFS: buffer leak start 340230144 len 16384 refs 1
bflags 529 owner 481
[ 1520.841314] BTRFS: buffer leak start 340197376 len 16384 refs 1
bflags 529 owner 281
[ 1520.842269] BTRFS: buffer leak start 339099648 len 16384 refs 1
bflags 529 owner 437
[ 1520.843220] BTRFS: buffer leak start 339017728 len 16384 refs 1
bflags 529 owner 284
[ 1520.844197] BTRFS: buffer leak start 338919424 len 16384 refs 1
bflags 529 owner 258
[ 1520.845156] BTRFS: buffer leak start 338886656 len 16384 refs 1
bflags 529 owner 291
[ 1520.846254] BTRFS: buffer leak start 338706432 len 16384 refs 1
bflags 529 owner 428
[ 1520.847260] BTRFS: buffer leak start 338673664 len 16384 refs 1
bflags 529 owner 272
[ 1520.848240] BTRFS: buffer leak start 337723392 len 16384 refs 1
bflags 529 owner 353
[ 1520.849225] BTRFS: buffer leak start 337625088 len 16384 refs 1
bflags 529 owner 461
[ 1520.850214] BTRFS: buffer leak start 337575936 len 16384 refs 1
bflags 529 owner 511
[ 1520.851207] BTRFS: buffer leak start 337035264 len 16384 refs 1
bflags 529 owner 463
[ 1520.852188] BTRFS: buffer leak start 336756736 len 16384 refs 1
bflags 529 owner 475
[ 1520.853168] BTRFS: buffer leak start 336674816 len 16384 refs 1
bflags 529 owner 510
[ 1520.854146] BTRFS: buffer leak start 335380480 len 16384 refs 1
bflags 529 owner 508
[ 1520.855145] BTRFS: buffer leak start 334331904 len 16384 refs 1
bflags 529 owner 407
[ 1520.856128] BTRFS: buffer leak start 333135872 len 16384 refs 1
bflags 529 owner 280
[ 1520.857148] BTRFS: buffer leak start 331104256 len 16384 refs 1
bflags 529 owner 405
[ 1520.858109] BTRFS: buffer leak start 330924032 len 16384 refs 1
bflags 529 owner 260
[ 1520.859056] BTRFS: buffer leak start 330203136 len 16384 refs 1
bflags 529 owner 425
[ 1520.860012] BTRFS: buffer leak start 329728000 len 16384 refs 1
bflags 529 owner 324
[ 1520.860961] BTRFS: buffer leak start 329285632 len 16384 refs 1
bflags 529 owner 464
[ 1520.861919] BTRFS: buffer leak start 326139904 len 16384 refs 1
bflags 529 owner 398
[ 1520.862876] BTRFS: buffer leak start 325173248 len 16384 refs 1
bflags 529 owner 501
[ 1520.863846] BTRFS: buffer leak start 324059136 len 16384 refs 1
bflags 529 owner 500
[ 1520.864798] BTRFS: buffer leak start 323551232 len 16384 refs 1
bflags 529 owner 367
[ 1520.865766] BTRFS: buffer leak start 310476800 len 16384 refs 1
bflags 529 owner 451
[ 1520.866731] BTRFS: buffer leak start 298860544 len 16384 refs 1
bflags 529 owner 486
[ 1520.867719] BTRFS: buffer leak start 297156608 len 16384 refs 1
bflags 529 owner 378
[ 1520.868674] BTRFS: buffer leak start 270565376 len 16384 refs 1
bflags 529 owner 462
[ 1520.869615] BTRFS: buffer leak start 270483456 len 16384 refs 1
bflags 529 owner 336
[ 1520.870581] BTRFS: buffer leak start 269303808 len 16384 refs 1
bflags 529 owner 473
[ 1520.871659] BTRFS: buffer leak start 266649600 len 16384 refs 1
bflags 529 owner 433
[ 1520.872626] BTRFS: buffer leak start 257409024 len 16384 refs 1
bflags 529 owner 467
[ 1520.873609] BTRFS: buffer leak start 249872384 len 16384 refs 1
bflags 529 owner 412
[ 1520.874597] BTRFS: buffer leak start 241156096 len 16384 refs 1
bflags 529 owner 458
[ 1520.875578] BTRFS: buffer leak start 240517120 len 16384 refs 1
bflags 529 owner 383
[ 1520.876540] BTRFS: buffer leak start 232964096 len 16384 refs 1
bflags 529 owner 329
[ 1520.877509] BTRFS: buffer leak start 229867520 len 16384 refs 1
bflags 529 owner 382
[ 1520.878485] BTRFS: buffer leak start 203472896 len 16384 refs 1
bflags 529 owner 289
[ 1520.879606] BTRFS: buffer leak start 197148672 len 16384 refs 1
bflags 529 owner 435
[ 1520.880861] BTRFS: buffer leak start 190791680 len 16384 refs 1
bflags 529 owner 408
[ 1520.882433] BTRFS: buffer leak start 187875328 len 16384 refs 1
bflags 529 owner 325
[ 1520.883878] BTRFS: buffer leak start 186761216 len 16384 refs 1
bflags 529 owner 316
[ 1520.885201] BTRFS: buffer leak start 181272576 len 16384 refs 1
bflags 529 owner 423
[ 1520.886550] BTRFS: buffer leak start 176816128 len 16384 refs 1
bflags 529 owner 394
[ 1520.887882] BTRFS: buffer leak start 164495360 len 16384 refs 1
bflags 529 owner 410
[ 1520.889217] BTRFS: buffer leak start 158760960 len 16384 refs 1
bflags 529 owner 338
[ 1520.890555] BTRFS: buffer leak start 156450816 len 16384 refs 1
bflags 529 owner 404
[ 1520.891885] BTRFS: buffer leak start 146800640 len 16384 refs 1
bflags 529 owner 346
[ 1520.893217] BTRFS: buffer leak start 138182656 len 16384 refs 1
bflags 529 owner 319
[ 1520.894561] BTRFS: buffer leak start 135806976 len 16384 refs 1
bflags 529 owner 296
[ 1520.895871] BTRFS: buffer leak start 128712704 len 16384 refs 1
bflags 529 owner 276
[ 1520.896835] BTRFS: buffer leak start 121749504 len 16384 refs 1
bflags 529 owner 337
[ 1520.898165] BTRFS: buffer leak start 118210560 len 16384 refs 1
bflags 529 owner 372
[ 1520.899487] BTRFS: buffer leak start 118177792 len 16384 refs 1
bflags 529 owner 361
[ 1520.900801] BTRFS: buffer leak start 113491968 len 16384 refs 1
bflags 529 owner 303
[ 1520.902223] BTRFS: buffer leak start 110854144 len 16384 refs 1
bflags 529 owner 342
[ 1520.903566] BTRFS: buffer leak start 110411776 len 16384 refs 1
bflags 529 owner 335
[ 1520.904808] BTRFS: buffer leak start 104431616 len 16384 refs 1
bflags 529 owner 351
[ 1520.906074] BTRFS: buffer leak start 100270080 len 16384 refs 1
bflags 529 owner 334
[ 1520.907392] BTRFS: buffer leak start 97697792 len 16384 refs 1
bflags 529 owner 330
[ 1520.908697] BTRFS: buffer leak start 92979200 len 16384 refs 1
bflags 529 owner 345
[ 1520.910017] BTRFS: buffer leak start 86884352 len 16384 refs 1
bflags 529 owner 332
[ 1520.911326] BTRFS: buffer leak start 83623936 len 16384 refs 1
bflags 529 owner 261
[ 1520.912506] BTRFS: buffer leak start 73629696 len 16384 refs 1
bflags 529 owner 321
[ 1520.913456] BTRFS: buffer leak start 69533696 len 16384 refs 1
bflags 529 owner 307
[ 1520.914413] BTRFS: buffer leak start 62930944 len 16384 refs 1
bflags 529 owner 306
[ 1520.915383] BTRFS: buffer leak start 60719104 len 16384 refs 1
bflags 529 owner 302
[ 1520.916327] BTRFS: buffer leak start 60702720 len 16384 refs 1
bflags 529 owner 292
[ 1520.917269] BTRFS: buffer leak start 59228160 len 16384 refs 1
bflags 529 owner 298
[ 1520.918223] BTRFS: buffer leak start 56229888 len 16384 refs 1
bflags 529 owner 271
[ 1520.919251] BTRFS: buffer leak start 47349760 len 16384 refs 1
bflags 529 owner 265
[ 1520.920554] BTRFS: buffer leak start 44597248 len 16384 refs 1
bflags 529 owner 269
[ 1520.921860] BTRFS: buffer leak start 38846464 len 16384 refs 1
bflags 529 owner 267

A git bisection reliably points to this patch.
I haven't checked the patch in detail to see where the leak is.

Thanks.



> ---
>  fs/btrfs/ctree.h |   5 +-
>  fs/btrfs/inode.c | 284 +++++++++++++++++++++++++----------------------
>  fs/btrfs/ioctl.c |  22 ++--
>  3 files changed, 167 insertions(+), 144 deletions(-)
>
> diff --git a/fs/btrfs/ctree.h b/fs/btrfs/ctree.h
> index 4db17bd05a21..f39730420e8a 100644
> --- a/fs/btrfs/ctree.h
> +++ b/fs/btrfs/ctree.h
> @@ -3254,10 +3254,11 @@ int btrfs_start_delalloc_roots(struct btrfs_fs_info *fs_info, long nr,
>  int btrfs_set_extent_delalloc(struct btrfs_inode *inode, u64 start, u64 end,
>                               unsigned int extra_bits,
>                               struct extent_state **cached_state);
> +struct inode *btrfs_new_subvol_inode(struct user_namespace *mnt_userns,
> +                                    struct inode *dir);
>  int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
> -                            struct btrfs_root *new_root,
>                              struct btrfs_root *parent_root,
> -                            struct user_namespace *mnt_userns);
> +                            struct inode *inode);
>   void btrfs_set_delalloc_extent(struct inode *inode, struct extent_state *state,
>                                unsigned *bits);
>  void btrfs_clear_delalloc_extent(struct inode *inode,
> diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
> index c47bdada2440..ff780256c936 100644
> --- a/fs/btrfs/inode.c
> +++ b/fs/btrfs/inode.c
> @@ -6090,15 +6090,12 @@ static void btrfs_inherit_iflags(struct inode *inode, struct inode *dir)
>         btrfs_sync_inode_flags_to_i_flags(inode);
>  }
>
> -static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
> -                                    struct btrfs_root *root,
> -                                    struct user_namespace *mnt_userns,
> -                                    struct inode *dir,
> -                                    const char *name, int name_len,
> -                                    umode_t mode, u64 *index)
> +static int btrfs_new_inode(struct btrfs_trans_handle *trans,
> +                          struct btrfs_root *root, struct inode *inode,
> +                          struct inode *dir, const char *name, int name_len,
> +                          u64 *index)
>  {
>         struct btrfs_fs_info *fs_info = root->fs_info;
> -       struct inode *inode;
>         struct btrfs_inode_item *inode_item;
>         struct btrfs_key *location;
>         struct btrfs_path *path;
> @@ -6108,20 +6105,11 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
>         u32 sizes[2];
>         struct btrfs_item_batch batch;
>         unsigned long ptr;
> -       unsigned int nofs_flag;
>         int ret;
>
>         path = btrfs_alloc_path();
>         if (!path)
> -               return ERR_PTR(-ENOMEM);
> -
> -       nofs_flag = memalloc_nofs_save();
> -       inode = new_inode(fs_info->sb);
> -       memalloc_nofs_restore(nofs_flag);
> -       if (!inode) {
> -               btrfs_free_path(path);
> -               return ERR_PTR(-ENOMEM);
> -       }
> +               return -ENOMEM;
>
>         /*
>          * O_TMPFILE, set link count to 0, so that after this point,
> @@ -6133,8 +6121,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
>         ret = btrfs_get_free_objectid(root, &objectid);
>         if (ret) {
>                 btrfs_free_path(path);
> -               iput(inode);
> -               return ERR_PTR(ret);
> +               return ret;
>         }
>         inode->i_ino = objectid;
>
> @@ -6144,8 +6131,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
>                 ret = btrfs_set_inode_index(BTRFS_I(dir), index);
>                 if (ret) {
>                         btrfs_free_path(path);
> -                       iput(inode);
> -                       return ERR_PTR(ret);
> +                       return ret;
>                 }
>         } else if (dir) {
>                 *index = 0;
> @@ -6163,7 +6149,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
>
>         btrfs_inherit_iflags(inode, dir);
>
> -       if (S_ISREG(mode)) {
> +       if (S_ISREG(inode->i_mode)) {
>                 if (btrfs_test_opt(fs_info, NODATASUM))
>                         BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM;
>                 if (btrfs_test_opt(fs_info, NODATACOW))
> @@ -6208,10 +6194,8 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
>         location->type = BTRFS_INODE_ITEM_KEY;
>
>         ret = btrfs_insert_inode_locked(inode);
> -       if (ret < 0) {
> -               iput(inode);
> +       if (ret < 0)
>                 goto fail;
> -       }
>
>         batch.keys = &key[0];
>         batch.data_sizes = &sizes[0];
> @@ -6221,8 +6205,6 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
>         if (ret != 0)
>                 goto fail_unlock;
>
> -       inode_init_owner(mnt_userns, inode, dir, mode);
> -
>         inode->i_mtime = current_time(inode);
>         inode->i_atime = inode->i_mtime;
>         inode->i_ctime = inode->i_mtime;
> @@ -6259,15 +6241,20 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
>                           "error inheriting props for ino %llu (root %llu): %d",
>                         btrfs_ino(BTRFS_I(inode)), root->root_key.objectid, ret);
>
> -       return inode;
> +       return 0;
>
>  fail_unlock:
> +       /*
> +        * discard_new_inode() calls iput(), but the caller owns the reference
> +        * to the inode.
> +        */
> +       ihold(inode);
>         discard_new_inode(inode);
>  fail:
>         if (dir && name)
>                 BTRFS_I(dir)->index_cnt--;
>         btrfs_free_path(path);
> -       return ERR_PTR(ret);
> +       return ret;
>  }
>
>  /*
> @@ -6365,37 +6352,36 @@ static int btrfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,
>         struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
>         struct btrfs_trans_handle *trans;
>         struct btrfs_root *root = BTRFS_I(dir)->root;
> -       struct inode *inode = NULL;
> +       struct inode *inode;
>         int err;
>         u64 index = 0;
>
> +       inode = new_inode(dir->i_sb);
> +       if (!inode)
> +               return -ENOMEM;
> +       inode_init_owner(mnt_userns, inode, dir, mode);
> +       inode->i_op = &btrfs_special_inode_operations;
> +       init_special_inode(inode, inode->i_mode, rdev);
> +
>         /*
>          * 2 for inode item and ref
>          * 2 for dir items
>          * 1 for xattr if selinux is on
>          */
>         trans = btrfs_start_transaction(root, 5);
> -       if (IS_ERR(trans))
> +       if (IS_ERR(trans)) {
> +               iput(inode);
>                 return PTR_ERR(trans);
> +       }
>
> -       inode = btrfs_new_inode(trans, root, mnt_userns, dir,
> -                       dentry->d_name.name, dentry->d_name.len,
> -                       mode, &index);
> -       if (IS_ERR(inode)) {
> -               err = PTR_ERR(inode);
> +       err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
> +                             dentry->d_name.len, &index);
> +       if (err) {
> +               iput(inode);
>                 inode = NULL;
>                 goto out_unlock;
>         }
>
> -       /*
> -       * If the active LSM wants to access the inode during
> -       * d_instantiate it needs these. Smack checks to see
> -       * if the filesystem supports xattrs by looking at the
> -       * ops vector.
> -       */
> -       inode->i_op = &btrfs_special_inode_operations;
> -       init_special_inode(inode, inode->i_mode, rdev);
> -
>         err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
>         if (err)
>                 goto out_unlock;
> @@ -6424,36 +6410,36 @@ static int btrfs_create(struct user_namespace *mnt_userns, struct inode *dir,
>         struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
>         struct btrfs_trans_handle *trans;
>         struct btrfs_root *root = BTRFS_I(dir)->root;
> -       struct inode *inode = NULL;
> +       struct inode *inode;
>         int err;
>         u64 index = 0;
>
> +       inode = new_inode(dir->i_sb);
> +       if (!inode)
> +               return -ENOMEM;
> +       inode_init_owner(mnt_userns, inode, dir, mode);
> +       inode->i_fop = &btrfs_file_operations;
> +       inode->i_op = &btrfs_file_inode_operations;
> +       inode->i_mapping->a_ops = &btrfs_aops;
> +
>         /*
>          * 2 for inode item and ref
>          * 2 for dir items
>          * 1 for xattr if selinux is on
>          */
>         trans = btrfs_start_transaction(root, 5);
> -       if (IS_ERR(trans))
> +       if (IS_ERR(trans)) {
> +               iput(inode);
>                 return PTR_ERR(trans);
> +       }
>
> -       inode = btrfs_new_inode(trans, root, mnt_userns, dir,
> -                       dentry->d_name.name, dentry->d_name.len,
> -                       mode, &index);
> -       if (IS_ERR(inode)) {
> -               err = PTR_ERR(inode);
> +       err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
> +                             dentry->d_name.len, &index);
> +       if (err) {
> +               iput(inode);
>                 inode = NULL;
>                 goto out_unlock;
>         }
> -       /*
> -       * If the active LSM wants to access the inode during
> -       * d_instantiate it needs these. Smack checks to see
> -       * if the filesystem supports xattrs by looking at the
> -       * ops vector.
> -       */
> -       inode->i_fop = &btrfs_file_operations;
> -       inode->i_op = &btrfs_file_inode_operations;
> -       inode->i_mapping->a_ops = &btrfs_aops;
>
>         err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
>         if (err)
> @@ -6562,34 +6548,38 @@ static int btrfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,
>                        struct dentry *dentry, umode_t mode)
>  {
>         struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
> -       struct inode *inode = NULL;
> +       struct inode *inode;
>         struct btrfs_trans_handle *trans;
>         struct btrfs_root *root = BTRFS_I(dir)->root;
> -       int err = 0;
> +       int err;
>         u64 index = 0;
>
> +       inode = new_inode(dir->i_sb);
> +       if (!inode)
> +               return -ENOMEM;
> +       inode_init_owner(mnt_userns, inode, dir, S_IFDIR | mode);
> +       inode->i_op = &btrfs_dir_inode_operations;
> +       inode->i_fop = &btrfs_dir_file_operations;
> +
>         /*
>          * 2 items for inode and ref
>          * 2 items for dir items
>          * 1 for xattr if selinux is on
>          */
>         trans = btrfs_start_transaction(root, 5);
> -       if (IS_ERR(trans))
> +       if (IS_ERR(trans)) {
> +               iput(inode);
>                 return PTR_ERR(trans);
> +       }
>
> -       inode = btrfs_new_inode(trans, root, mnt_userns, dir,
> -                       dentry->d_name.name, dentry->d_name.len,
> -                       S_IFDIR | mode, &index);
> -       if (IS_ERR(inode)) {
> -               err = PTR_ERR(inode);
> +       err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
> +                             dentry->d_name.len, &index);
> +       if (err) {
> +               iput(inode);
>                 inode = NULL;
>                 goto out_fail;
>         }
>
> -       /* these must be set before we unlock the inode */
> -       inode->i_op = &btrfs_dir_inode_operations;
> -       inode->i_fop = &btrfs_dir_file_operations;
> -
>         err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
>         if (err)
>                 goto out_fail;
> @@ -8747,25 +8737,39 @@ static int btrfs_truncate(struct inode *inode, bool skip_writeback)
>         return ret;
>  }
>
> +struct inode *btrfs_new_subvol_inode(struct user_namespace *mnt_userns,
> +                                    struct inode *dir)
> +{
> +       struct inode *inode;
> +
> +       inode = new_inode(dir->i_sb);
> +       if (inode) {
> +               /*
> +                * Subvolumes don't inherit the sgid bit or the parent's gid if
> +                * the parent's sgid bit is set. This is probably a bug.
> +                */
> +               inode_init_owner(mnt_userns, inode, NULL,
> +                                S_IFDIR | (~current_umask() & S_IRWXUGO));
> +               inode->i_op = &btrfs_dir_inode_operations;
> +               inode->i_fop = &btrfs_dir_file_operations;
> +       }
> +       return inode;
> +}
> +
>  /*
>   * create a new subvolume directory/inode (helper for the ioctl).
>   */
>  int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
> -                            struct btrfs_root *new_root,
>                              struct btrfs_root *parent_root,
> -                            struct user_namespace *mnt_userns)
> +                            struct inode *inode)
>  {
> -       struct inode *inode;
> +       struct btrfs_root *new_root = BTRFS_I(inode)->root;
>         int err;
>         u64 index = 0;
>
> -       inode = btrfs_new_inode(trans, new_root, mnt_userns, NULL, "..", 2,
> -                               S_IFDIR | (~current_umask() & S_IRWXUGO),
> -                               &index);
> -       if (IS_ERR(inode))
> -               return PTR_ERR(inode);
> -       inode->i_op = &btrfs_dir_inode_operations;
> -       inode->i_fop = &btrfs_dir_file_operations;
> +       err = btrfs_new_inode(trans, new_root, inode, NULL, "..", 2, &index);
> +       if (err)
> +               return err;
>
>         unlock_new_inode(inode);
>
> @@ -8776,8 +8780,6 @@ int btrfs_create_subvol_root(struct btrfs_trans_handle *trans,
>                           new_root->root_key.objectid, err);
>
>         err = btrfs_update_inode(trans, new_root, BTRFS_I(inode));
> -
> -       iput(inode);
>         return err;
>  }
>
> @@ -9254,31 +9256,36 @@ static int btrfs_rename_exchange(struct inode *old_dir,
>         return ret;
>  }
>
> +static struct inode *new_whiteout_inode(struct user_namespace *mnt_userns,
> +                                       struct inode *dir)
> +{
> +       struct inode *inode;
> +
> +       inode = new_inode(dir->i_sb);
> +       if (inode) {
> +               inode_init_owner(mnt_userns, inode, dir,
> +                                S_IFCHR | WHITEOUT_MODE);
> +               inode->i_op = &btrfs_special_inode_operations;
> +               init_special_inode(inode, inode->i_mode, WHITEOUT_DEV);
> +       }
> +       return inode;
> +}
> +
>  static int btrfs_whiteout_for_rename(struct btrfs_trans_handle *trans,
>                                      struct btrfs_root *root,
> -                                    struct user_namespace *mnt_userns,
> -                                    struct inode *dir,
> +                                    struct inode *inode, struct inode *dir,
>                                      struct dentry *dentry)
>  {
>         int ret;
> -       struct inode *inode;
>         u64 index;
>
> -       inode = btrfs_new_inode(trans, root, mnt_userns, dir,
> -                               dentry->d_name.name,
> -                               dentry->d_name.len,
> -                               S_IFCHR | WHITEOUT_MODE,
> -                               &index);
> -
> -       if (IS_ERR(inode)) {
> -               ret = PTR_ERR(inode);
> +       ret = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
> +                             dentry->d_name.len, &index);
> +       if (ret) {
> +               iput(inode);
>                 return ret;
>         }
>
> -       inode->i_op = &btrfs_special_inode_operations;
> -       init_special_inode(inode, inode->i_mode,
> -               WHITEOUT_DEV);
> -
>         ret = btrfs_init_inode_security(trans, inode, dir,
>                                 &dentry->d_name);
>         if (ret)
> @@ -9305,6 +9312,7 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
>                         unsigned int flags)
>  {
>         struct btrfs_fs_info *fs_info = btrfs_sb(old_dir->i_sb);
> +       struct inode *whiteout_inode;
>         struct btrfs_trans_handle *trans;
>         unsigned int trans_num_items;
>         struct btrfs_root *root = BTRFS_I(old_dir)->root;
> @@ -9359,6 +9367,12 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
>         if (new_inode && S_ISREG(old_inode->i_mode) && new_inode->i_size)
>                 filemap_flush(old_inode->i_mapping);
>
> +       if (flags & RENAME_WHITEOUT) {
> +               whiteout_inode = new_whiteout_inode(mnt_userns, old_dir);
> +               if (!whiteout_inode)
> +                       return -ENOMEM;
> +       }
> +
>         if (old_ino == BTRFS_FIRST_FREE_OBJECTID) {
>                 /* close the racy window with snapshot create/destroy ioctl */
>                 down_read(&fs_info->subvol_sem);
> @@ -9495,9 +9509,9 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
>                                    rename_ctx.index, new_dentry->d_parent);
>
>         if (flags & RENAME_WHITEOUT) {
> -               ret = btrfs_whiteout_for_rename(trans, root, mnt_userns,
> +               ret = btrfs_whiteout_for_rename(trans, root, whiteout_inode,
>                                                 old_dir, old_dentry);
> -
> +               whiteout_inode = NULL;
>                 if (ret) {
>                         btrfs_abort_transaction(trans, ret);
>                         goto out_fail;
> @@ -9509,7 +9523,8 @@ static int btrfs_rename(struct user_namespace *mnt_userns,
>  out_notrans:
>         if (old_ino == BTRFS_FIRST_FREE_OBJECTID)
>                 up_read(&fs_info->subvol_sem);
> -
> +       if (flags & RENAME_WHITEOUT)
> +               iput(whiteout_inode);
>         return ret;
>  }
>
> @@ -9728,7 +9743,7 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
>         struct btrfs_root *root = BTRFS_I(dir)->root;
>         struct btrfs_path *path;
>         struct btrfs_key key;
> -       struct inode *inode = NULL;
> +       struct inode *inode;
>         int err;
>         u64 index = 0;
>         int name_len;
> @@ -9741,6 +9756,14 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
>         if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(fs_info))
>                 return -ENAMETOOLONG;
>
> +       inode = new_inode(dir->i_sb);
> +       if (!inode)
> +               return -ENOMEM;
> +       inode_init_owner(mnt_userns, inode, dir, S_IFLNK | S_IRWXUGO);
> +       inode->i_op = &btrfs_symlink_inode_operations;
> +       inode_nohighmem(inode);
> +       inode->i_mapping->a_ops = &btrfs_aops;
> +
>         /*
>          * 2 items for inode item and ref
>          * 2 items for dir items
> @@ -9749,28 +9772,19 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
>          * 1 item for xattr if selinux is on
>          */
>         trans = btrfs_start_transaction(root, 7);
> -       if (IS_ERR(trans))
> +       if (IS_ERR(trans)) {
> +               iput(inode);
>                 return PTR_ERR(trans);
> +       }
>
> -       inode = btrfs_new_inode(trans, root, mnt_userns, dir,
> -                               dentry->d_name.name, dentry->d_name.len,
> -                               S_IFLNK | S_IRWXUGO, &index);
> -       if (IS_ERR(inode)) {
> -               err = PTR_ERR(inode);
> +       err = btrfs_new_inode(trans, root, inode, dir, dentry->d_name.name,
> +                             dentry->d_name.len, &index);
> +       if (err) {
> +               iput(inode);
>                 inode = NULL;
>                 goto out_unlock;
>         }
>
> -       /*
> -       * If the active LSM wants to access the inode during
> -       * d_instantiate it needs these. Smack checks to see
> -       * if the filesystem supports xattrs by looking at the
> -       * ops vector.
> -       */
> -       inode->i_fop = &btrfs_file_operations;
> -       inode->i_op = &btrfs_file_inode_operations;
> -       inode->i_mapping->a_ops = &btrfs_aops;
> -
>         err = btrfs_init_inode_security(trans, inode, dir, &dentry->d_name);
>         if (err)
>                 goto out_unlock;
> @@ -9806,8 +9820,6 @@ static int btrfs_symlink(struct user_namespace *mnt_userns, struct inode *dir,
>         btrfs_mark_buffer_dirty(leaf);
>         btrfs_free_path(path);
>
> -       inode->i_op = &btrfs_symlink_inode_operations;
> -       inode_nohighmem(inode);
>         inode_set_bytes(inode, name_len);
>         btrfs_i_size_write(BTRFS_I(inode), name_len);
>         err = btrfs_update_inode(trans, root, BTRFS_I(inode));
> @@ -10087,30 +10099,34 @@ static int btrfs_tmpfile(struct user_namespace *mnt_userns, struct inode *dir,
>         struct btrfs_fs_info *fs_info = btrfs_sb(dir->i_sb);
>         struct btrfs_trans_handle *trans;
>         struct btrfs_root *root = BTRFS_I(dir)->root;
> -       struct inode *inode = NULL;
> +       struct inode *inode;
>         u64 index;
> -       int ret = 0;
> +       int ret;
> +
> +       inode = new_inode(dir->i_sb);
> +       if (!inode)
> +               return -ENOMEM;
> +       inode_init_owner(mnt_userns, inode, dir, mode);
> +       inode->i_fop = &btrfs_file_operations;
> +       inode->i_op = &btrfs_file_inode_operations;
> +       inode->i_mapping->a_ops = &btrfs_aops;
>
>         /*
>          * 5 units required for adding orphan entry
>          */
>         trans = btrfs_start_transaction(root, 5);
> -       if (IS_ERR(trans))
> +       if (IS_ERR(trans)) {
> +               iput(inode);
>                 return PTR_ERR(trans);
> +       }
>
> -       inode = btrfs_new_inode(trans, root, mnt_userns, dir, NULL, 0,
> -                       mode, &index);
> -       if (IS_ERR(inode)) {
> -               ret = PTR_ERR(inode);
> +       ret = btrfs_new_inode(trans, root, inode, dir, NULL, 0, &index);
> +       if (ret) {
> +               iput(inode);
>                 inode = NULL;
>                 goto out;
>         }
>
> -       inode->i_fop = &btrfs_file_operations;
> -       inode->i_op = &btrfs_file_inode_operations;
> -
> -       inode->i_mapping->a_ops = &btrfs_aops;
> -
>         ret = btrfs_init_inode_security(trans, inode, dir, NULL);
>         if (ret)
>                 goto out;
> diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
> index 891352fd6d0f..60c907b14547 100644
> --- a/fs/btrfs/ioctl.c
> +++ b/fs/btrfs/ioctl.c
> @@ -587,6 +587,12 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
>         if (ret < 0)
>                 goto out_root_item;
>
> +       inode = btrfs_new_subvol_inode(mnt_userns, dir);
> +       if (!inode) {
> +               ret = -ENOMEM;
> +               goto out_anon_dev;
> +       }
> +
>         btrfs_init_block_rsv(&block_rsv, BTRFS_BLOCK_RSV_TEMP);
>         /*
>          * The same as the snapshot creation, please see the comment
> @@ -594,13 +600,13 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
>          */
>         ret = btrfs_subvolume_reserve_metadata(root, &block_rsv, 8, false);
>         if (ret)
> -               goto out_anon_dev;
> +               goto out_inode;
>
>         trans = btrfs_start_transaction(root, 0);
>         if (IS_ERR(trans)) {
>                 ret = PTR_ERR(trans);
>                 btrfs_subvolume_release_metadata(root, &block_rsv);
> -               goto out_anon_dev;
> +               goto out_inode;
>         }
>         trans->block_rsv = &block_rsv;
>         trans->bytes_reserved = block_rsv.size;
> @@ -683,16 +689,16 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
>         }
>         /* anon_dev is owned by new_root now. */
>         anon_dev = 0;
> +       BTRFS_I(inode)->root = new_root;
> +       /* ... and new_root is owned by inode now. */
>
>         ret = btrfs_record_root_in_trans(trans, new_root);
>         if (ret) {
> -               btrfs_put_root(new_root);
>                 btrfs_abort_transaction(trans, ret);
>                 goto out;
>         }
>
> -       ret = btrfs_create_subvol_root(trans, new_root, root, mnt_userns);
> -       btrfs_put_root(new_root);
> +       ret = btrfs_create_subvol_root(trans, root, inode);
>         if (ret) {
>                 /* We potentially lose an unused inode item here */
>                 btrfs_abort_transaction(trans, ret);
> @@ -745,11 +751,11 @@ static noinline int create_subvol(struct user_namespace *mnt_userns,
>                 ret = btrfs_commit_transaction(trans);
>
>         if (!ret) {
> -               inode = btrfs_lookup_dentry(dir, dentry);
> -               if (IS_ERR(inode))
> -                       return PTR_ERR(inode);
>                 d_instantiate(dentry, inode);
> +               inode = NULL;
>         }
> +out_inode:
> +       iput(inode);
>  out_anon_dev:
>         if (anon_dev)
>                 free_anon_bdev(anon_dev);
> --
> 2.35.1
>


-- 
Filipe David Manana,

“Whether you think you can, or you think you can't — you're right.”

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 13/16] btrfs: allocate inode outside of btrfs_new_inode()
  2022-03-14 23:33   ` Filipe Manana
@ 2022-03-15  0:16     ` Omar Sandoval
  2022-03-15  1:14       ` Omar Sandoval
  0 siblings, 1 reply; 35+ messages in thread
From: Omar Sandoval @ 2022-03-15  0:16 UTC (permalink / raw)
  To: Filipe Manana; +Cc: linux-btrfs, kernel-team

On Mon, Mar 14, 2022 at 11:33:51PM +0000, Filipe Manana wrote:
> On Thu, Mar 10, 2022 at 4:56 AM Omar Sandoval <osandov@osandov.com> wrote:
> >
> > From: Omar Sandoval <osandov@fb.com>
> >
> > Instead of calling new_inode() and inode_init_owner() inside of
> > btrfs_new_inode(), do it in the callers. This allows us to pass in just
> > the inode instead of the mnt_userns and mode and removes the need for
> > memalloc_nofs_{save,restores}() since we do it before starting a
> > transaction. This also paves the way for some more cleanups in later
> > patches.
> >
> > This also removes the comments about Smack checking i_op, which are no
> > longer true since commit 5d6c31910bc0 ("xattr: Add
> > __vfs_{get,set,remove}xattr helpers"). Now it checks inode->i_opflags &
> > IOP_XATTR, which is set based on sb->s_xattr.
> >
> > Signed-off-by: Omar Sandoval <osandov@fb.com>
> 
> There's some leak here Omar.
> 
> misc-next is triggering tons of these on dmesg:

I reproduced the "page private not zero" messages on misc-next, but not
on my full series, so it's probably some mistake I made when splitting
up these patches that doesn't exist in the end result. I'll fix it.

^ permalink raw reply	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 13/16] btrfs: allocate inode outside of btrfs_new_inode()
  2022-03-15  0:16     ` Omar Sandoval
@ 2022-03-15  1:14       ` Omar Sandoval
  2022-03-15  8:01         ` Qu Wenruo
  0 siblings, 1 reply; 35+ messages in thread
From: Omar Sandoval @ 2022-03-15  1:14 UTC (permalink / raw)
  To: Filipe Manana; +Cc: linux-btrfs, kernel-team

On Mon, Mar 14, 2022 at 05:16:45PM -0700, Omar Sandoval wrote:
> On Mon, Mar 14, 2022 at 11:33:51PM +0000, Filipe Manana wrote:
> > On Thu, Mar 10, 2022 at 4:56 AM Omar Sandoval <osandov@osandov.com> wrote:
> > >
> > > From: Omar Sandoval <osandov@fb.com>
> > >
> > > Instead of calling new_inode() and inode_init_owner() inside of
> > > btrfs_new_inode(), do it in the callers. This allows us to pass in just
> > > the inode instead of the mnt_userns and mode and removes the need for
> > > memalloc_nofs_{save,restores}() since we do it before starting a
> > > transaction. This also paves the way for some more cleanups in later
> > > patches.
> > >
> > > This also removes the comments about Smack checking i_op, which are no
> > > longer true since commit 5d6c31910bc0 ("xattr: Add
> > > __vfs_{get,set,remove}xattr helpers"). Now it checks inode->i_opflags &
> > > IOP_XATTR, which is set based on sb->s_xattr.
> > >
> > > Signed-off-by: Omar Sandoval <osandov@fb.com>
> > 
> > There's some leak here Omar.
> > 
> > misc-next is triggering tons of these on dmesg:
> 
> I reproduced the "page private not zero" messages on misc-next, but not
> on my full series, so it's probably some mistake I made when splitting
> up these patches that doesn't exist in the end result. I'll fix it.

Yup, this patch needs:

diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index ff780256c936..d616a3a35e83 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -6143,7 +6143,8 @@ static int btrfs_new_inode(struct btrfs_trans_handle *trans,
 	 */
 	BTRFS_I(inode)->index_cnt = 2;
 	BTRFS_I(inode)->dir_index = *index;
-	BTRFS_I(inode)->root = btrfs_grab_root(root);
+	if (!BTRFS_I(inode)->root)
+		BTRFS_I(inode)->root = btrfs_grab_root(root);
 	BTRFS_I(inode)->generation = trans->transid;
 	inode->i_generation = BTRFS_I(inode)->generation;
 

A later patch does this correctly. For the sake of git bisect, I fixed
this and sent out v4.

^ permalink raw reply related	[flat|nested] 35+ messages in thread

* Re: [PATCH v2 13/16] btrfs: allocate inode outside of btrfs_new_inode()
  2022-03-15  1:14       ` Omar Sandoval
@ 2022-03-15  8:01         ` Qu Wenruo
  0 siblings, 0 replies; 35+ messages in thread
From: Qu Wenruo @ 2022-03-15  8:01 UTC (permalink / raw)
  To: Omar Sandoval, Filipe Manana; +Cc: linux-btrfs, kernel-team



On 2022/3/15 09:14, Omar Sandoval wrote:
> On Mon, Mar 14, 2022 at 05:16:45PM -0700, Omar Sandoval wrote:
>> On Mon, Mar 14, 2022 at 11:33:51PM +0000, Filipe Manana wrote:
>>> On Thu, Mar 10, 2022 at 4:56 AM Omar Sandoval <osandov@osandov.com> wrote:
>>>>
>>>> From: Omar Sandoval <osandov@fb.com>
>>>>
>>>> Instead of calling new_inode() and inode_init_owner() inside of
>>>> btrfs_new_inode(), do it in the callers. This allows us to pass in just
>>>> the inode instead of the mnt_userns and mode and removes the need for
>>>> memalloc_nofs_{save,restores}() since we do it before starting a
>>>> transaction. This also paves the way for some more cleanups in later
>>>> patches.
>>>>
>>>> This also removes the comments about Smack checking i_op, which are no
>>>> longer true since commit 5d6c31910bc0 ("xattr: Add
>>>> __vfs_{get,set,remove}xattr helpers"). Now it checks inode->i_opflags &
>>>> IOP_XATTR, which is set based on sb->s_xattr.
>>>>
>>>> Signed-off-by: Omar Sandoval <osandov@fb.com>
>>>
>>> There's some leak here Omar.
>>>
>>> misc-next is triggering tons of these on dmesg:
>>
>> I reproduced the "page private not zero" messages on misc-next, but not
>> on my full series, so it's probably some mistake I made when splitting
>> up these patches that doesn't exist in the end result. I'll fix it.
>
> Yup, this patch needs:
>
> diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
> index ff780256c936..d616a3a35e83 100644
> --- a/fs/btrfs/inode.c
> +++ b/fs/btrfs/inode.c
> @@ -6143,7 +6143,8 @@ static int btrfs_new_inode(struct btrfs_trans_handle *trans,
>   	 */
>   	BTRFS_I(inode)->index_cnt = 2;
>   	BTRFS_I(inode)->dir_index = *index;
> -	BTRFS_I(inode)->root = btrfs_grab_root(root);
> +	if (!BTRFS_I(inode)->root)
> +		BTRFS_I(inode)->root = btrfs_grab_root(root);
>   	BTRFS_I(inode)->generation = trans->transid;
>   	inode->i_generation = BTRFS_I(inode)->generation;
>
>
> A later patch does this correctly. For the sake of git bisect, I fixed
> this and sent out v4.

It looks like the current misc-next doesn't has this code applied, nor
the later patch to fix it.

Thus it's causing tons of failure (using btrfs/065 as a reliable
reproducer here, dmesg will be full of eb leakage.)

Thanks,
Qu

^ permalink raw reply	[flat|nested] 35+ messages in thread

end of thread, other threads:[~2022-03-15  8:01 UTC | newest]

Thread overview: 35+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-10  1:31 [PATCH v2 00/16] btrfs: inode creation cleanups and fixes Omar Sandoval
2022-03-10  1:31 ` [PATCH v2 01/16] btrfs: reserve correct number of items for unlink and rmdir Omar Sandoval
2022-03-10  1:31 ` [PATCH v2 02/16] btrfs: reserve correct number of items for rename Omar Sandoval
2022-03-10  1:31 ` [PATCH v2 03/16] btrfs: fix anon_dev leak in create_subvol() Omar Sandoval
2022-03-11 15:42   ` Sweet Tea Dorminy
2022-03-12  0:29     ` Omar Sandoval
2022-03-12  1:43       ` Sweet Tea Dorminy
2022-03-10  1:31 ` [PATCH v2 04/16] btrfs: get rid of btrfs_add_nondir() Omar Sandoval
2022-03-10  1:31 ` [PATCH v2 05/16] btrfs: remove unnecessary btrfs_i_size_write(0) calls Omar Sandoval
2022-03-10  1:31 ` [PATCH v2 06/16] btrfs: remove unnecessary inode_set_bytes(0) call Omar Sandoval
2022-03-10  1:31 ` [PATCH v2 07/16] btrfs: remove unnecessary set_nlink() in btrfs_create_subvol_root() Omar Sandoval
2022-03-10  1:31 ` [PATCH v2 08/16] btrfs: remove unused mnt_userns parameter from __btrfs_set_acl Omar Sandoval
2022-03-10  1:31 ` [PATCH v2 09/16] btrfs: remove redundant name and name_len parameters to create_subvol Omar Sandoval
2022-03-10  1:31 ` [PATCH v2 10/16] btrfs: don't pass parent objectid to btrfs_new_inode() explicitly Omar Sandoval
2022-03-10  1:31 ` [PATCH v2 11/16] btrfs: move btrfs_get_free_objectid() call into btrfs_new_inode() Omar Sandoval
2022-03-10  1:31 ` [PATCH v2 12/16] btrfs: set inode flags earlier in btrfs_new_inode() Omar Sandoval
2022-03-10  1:31 ` [PATCH v2 13/16] btrfs: allocate inode outside of btrfs_new_inode() Omar Sandoval
2022-03-11 17:11   ` Sweet Tea Dorminy
2022-03-12  0:41     ` Omar Sandoval
2022-03-14 14:43       ` Sweet Tea Dorminy
2022-03-14 23:33   ` Filipe Manana
2022-03-15  0:16     ` Omar Sandoval
2022-03-15  1:14       ` Omar Sandoval
2022-03-15  8:01         ` Qu Wenruo
2022-03-10  1:31 ` [PATCH v2 14/16] btrfs: factor out common part of btrfs_{mknod,create,mkdir}() Omar Sandoval
2022-03-11 17:43   ` Sweet Tea Dorminy
2022-03-10  1:31 ` [PATCH v2 15/16] btrfs: reserve correct number of items for inode creation Omar Sandoval
2022-03-11 17:56   ` Sweet Tea Dorminy
2022-03-12  0:45     ` Omar Sandoval
2022-03-10  1:31 ` [PATCH v2 16/16] btrfs: move common inode creation code into btrfs_create_new_inode() Omar Sandoval
2022-03-11 18:04   ` Sweet Tea Dorminy
2022-03-14 12:50 ` [PATCH v2 00/16] btrfs: inode creation cleanups and fixes David Sterba
2022-03-14 18:42   ` Omar Sandoval
2022-03-14 19:27     ` David Sterba
2022-03-14 19:55       ` Omar Sandoval

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.