All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 00/17] xfs: Delay Ready Attributes
@ 2019-11-07  1:27 Allison Collins
  2019-11-07  1:27 ` [PATCH v4 01/17] xfs: Remove all strlen in all xfs_attr_* functions for attr names Allison Collins
                   ` (16 more replies)
  0 siblings, 17 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-07  1:27 UTC (permalink / raw)
  To: linux-xfs

Hi all,

This set is a subset of a larger series for delayed attributes. Which
is a subset of an even larger series, parent pointers. Delayed attributes
allow attribute operations (set and remove) to be logged and committed in
the same way that other delayed operations do. This allows more complex 
operations (like parent pointers) to be broken up into multiple smaller 
transactions. To do this, the existing attr operations must be modified to
operate as either a delayed operation or a inline operation since older
filesystems will not be able to use the new log entries. This means that 
they cannot roll, commit, or finish transactions. Instead, they return 
EAGAIN an allow the calling function to handle the transaction. In this
series, we focus on only the clean up and refactoring needed to accomplish
this. We will introduce delayed attrs and parent pointers in a later set.

Changes since v3:
Mostly review updates collected since v3.  Patches 15, 16, and 17 are new
and apply most of the new code flow changes.  No new function is added at
this time. 

I've also made the corresponding updates to the user space side, and
xfstests as well.

Question, comment and feedback appreciated! 

Thanks all!
Allison

Allison Collins (15):
  xfs: Replace attribute parameters with struct xfs_name
  xfs: Embed struct xfs_name in xfs_da_args
  xfs: Add xfs_dabuf defines
  xfs: Factor out new helper functions xfs_attr_rmtval_set
  xfs: Factor up trans handling in xfs_attr3_leaf_flipflags
  xfs: Factor out xfs_attr_leaf_addname helper
  xfs: Factor up commit from xfs_attr_try_sf_addname
  xfs: Factor up trans roll from xfs_attr3_leaf_setflag
  xfs: Add xfs_attr3_leaf helper functions
  xfs: Factor out xfs_attr_rmtval_invalidate
  xfs: Factor up trans roll in xfs_attr3_leaf_clearflag
  xfs: Add delay context to xfs_da_args
  xfs: Check for -ENOATTR or -EEXIST
  xfs: Add delay ready attr remove routines
  xfs: Add delay ready attr set routines

Allison Henderson (2):
  xfs: Remove all strlen in all xfs_attr_* functions for attr names.
  xfs: Add xfs_has_attr and subroutines

 fs/xfs/libxfs/xfs_attr.c        | 771 +++++++++++++++++++++++++---------------
 fs/xfs/libxfs/xfs_attr.h        |   9 +-
 fs/xfs/libxfs/xfs_attr_leaf.c   | 329 +++++++++++------
 fs/xfs/libxfs/xfs_attr_leaf.h   |   7 +
 fs/xfs/libxfs/xfs_attr_remote.c | 103 ++++--
 fs/xfs/libxfs/xfs_attr_remote.h |   4 +-
 fs/xfs/libxfs/xfs_da_btree.c    |  55 ++-
 fs/xfs/libxfs/xfs_da_btree.h    |  32 +-
 fs/xfs/libxfs/xfs_dir2.c        |  18 +-
 fs/xfs/libxfs/xfs_dir2_block.c  |  12 +-
 fs/xfs/libxfs/xfs_dir2_data.c   |   3 +-
 fs/xfs/libxfs/xfs_dir2_leaf.c   |  15 +-
 fs/xfs/libxfs/xfs_dir2_node.c   |  18 +-
 fs/xfs/libxfs/xfs_dir2_sf.c     |  30 +-
 fs/xfs/scrub/attr.c             |  12 +-
 fs/xfs/scrub/common.c           |   2 +
 fs/xfs/scrub/dabtree.c          |   6 +-
 fs/xfs/scrub/dir.c              |   4 +-
 fs/xfs/xfs_acl.c                |  26 +-
 fs/xfs/xfs_attr_inactive.c      |   6 +-
 fs/xfs/xfs_attr_list.c          |  17 +-
 fs/xfs/xfs_ioctl.c              |  20 +-
 fs/xfs/xfs_ioctl32.c            |   2 +
 fs/xfs/xfs_iops.c               |  11 +-
 fs/xfs/xfs_trace.h              |  20 +-
 fs/xfs/xfs_xattr.c              |  23 +-
 26 files changed, 1016 insertions(+), 539 deletions(-)

-- 
2.7.4


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

* [PATCH v4 01/17] xfs: Remove all strlen in all xfs_attr_* functions for attr names.
  2019-11-07  1:27 [PATCH v4 00/17] xfs: Delay Ready Attributes Allison Collins
@ 2019-11-07  1:27 ` Allison Collins
  2019-11-11 17:47   ` Christoph Hellwig
  2019-11-07  1:27 ` [PATCH v4 02/17] xfs: Replace attribute parameters with struct xfs_name Allison Collins
                   ` (15 subsequent siblings)
  16 siblings, 1 reply; 77+ messages in thread
From: Allison Collins @ 2019-11-07  1:27 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.com>

This helps to pre-simplify the extra handling of the null terminator in
delayed operations which use memcpy rather than strlen.  Later
when we introduce parent pointers, attribute names will become binary,
so strlen will not work at all.  Removing uses of strlen now will
help reduce complexities later

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
---
 fs/xfs/libxfs/xfs_attr.c | 12 ++++++++----
 fs/xfs/libxfs/xfs_attr.h |  8 +++++---
 fs/xfs/xfs_acl.c         | 11 +++++++----
 fs/xfs/xfs_ioctl.c       | 13 ++++++++++---
 fs/xfs/xfs_iops.c        |  6 ++++--
 fs/xfs/xfs_xattr.c       | 11 +++++++----
 6 files changed, 41 insertions(+), 20 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 510ca69..7589cb7 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -62,6 +62,7 @@ xfs_attr_args_init(
 	struct xfs_da_args	*args,
 	struct xfs_inode	*dp,
 	const unsigned char	*name,
+	size_t			namelen,
 	int			flags)
 {
 
@@ -74,7 +75,7 @@ xfs_attr_args_init(
 	args->dp = dp;
 	args->flags = flags;
 	args->name = name;
-	args->namelen = strlen((const char *)name);
+	args->namelen = namelen;
 	if (args->namelen >= MAXNAMELEN)
 		return -EFAULT;		/* match IRIX behaviour */
 
@@ -139,6 +140,7 @@ int
 xfs_attr_get(
 	struct xfs_inode	*ip,
 	const unsigned char	*name,
+	size_t			namelen,
 	unsigned char		**value,
 	int			*valuelenp,
 	int			flags)
@@ -154,7 +156,7 @@ xfs_attr_get(
 	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
 		return -EIO;
 
-	error = xfs_attr_args_init(&args, ip, name, flags);
+	error = xfs_attr_args_init(&args, ip, name, namelen, flags);
 	if (error)
 		return error;
 
@@ -338,6 +340,7 @@ int
 xfs_attr_set(
 	struct xfs_inode	*dp,
 	const unsigned char	*name,
+	size_t			namelen,
 	unsigned char		*value,
 	int			valuelen,
 	int			flags)
@@ -353,7 +356,7 @@ xfs_attr_set(
 	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
 		return -EIO;
 
-	error = xfs_attr_args_init(&args, dp, name, flags);
+	error = xfs_attr_args_init(&args, dp, name, namelen, flags);
 	if (error)
 		return error;
 
@@ -442,6 +445,7 @@ int
 xfs_attr_remove(
 	struct xfs_inode	*dp,
 	const unsigned char	*name,
+	size_t			namelen,
 	int			flags)
 {
 	struct xfs_mount	*mp = dp->i_mount;
@@ -453,7 +457,7 @@ xfs_attr_remove(
 	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
 		return -EIO;
 
-	error = xfs_attr_args_init(&args, dp, name, flags);
+	error = xfs_attr_args_init(&args, dp, name, namelen, flags);
 	if (error)
 		return error;
 
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index 94badfa..106a2f2 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -145,11 +145,13 @@ int xfs_attr_list_int(struct xfs_attr_list_context *);
 int xfs_inode_hasattr(struct xfs_inode *ip);
 int xfs_attr_get_ilocked(struct xfs_inode *ip, struct xfs_da_args *args);
 int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
-		 unsigned char **value, int *valuelenp, int flags);
+		 size_t namelen, unsigned char **value, int *valuelenp,
+		 int flags);
 int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
-		 unsigned char *value, int valuelen, int flags);
+		 size_t namelen, unsigned char *value, int valuelen, int flags);
 int xfs_attr_set_args(struct xfs_da_args *args);
-int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name, int flags);
+int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name,
+		    size_t namelen, int flags);
 int xfs_attr_remove_args(struct xfs_da_args *args);
 int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
 		  int flags, struct attrlist_cursor_kern *cursor);
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index 96d7071..12be708 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -135,7 +135,8 @@ xfs_get_acl(struct inode *inode, int type)
 	 * go out to the disk.
 	 */
 	len = XFS_ACL_MAX_SIZE(ip->i_mount);
-	error = xfs_attr_get(ip, ea_name, (unsigned char **)&xfs_acl, &len,
+	error = xfs_attr_get(ip, ea_name, strlen(ea_name), 
+				(unsigned char **)&xfs_acl, &len,
 				ATTR_ALLOC | ATTR_ROOT);
 	if (error) {
 		/*
@@ -186,15 +187,17 @@ __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 		len -= sizeof(struct xfs_acl_entry) *
 			 (XFS_ACL_MAX_ENTRIES(ip->i_mount) - acl->a_count);
 
-		error = xfs_attr_set(ip, ea_name, (unsigned char *)xfs_acl,
-				len, ATTR_ROOT);
+		error = xfs_attr_set(ip, ea_name, strlen(ea_name),
+				     (unsigned char *)xfs_acl, len, ATTR_ROOT);
 
 		kmem_free(xfs_acl);
 	} else {
 		/*
 		 * A NULL ACL argument means we want to remove the ACL.
 		 */
-		error = xfs_attr_remove(ip, ea_name, ATTR_ROOT);
+		error = xfs_attr_remove(ip, ea_name,
+					strlen(ea_name),
+					ATTR_ROOT);
 
 		/*
 		 * If the attribute didn't exist to start with that's fine.
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 800f070..269c321 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -432,6 +432,7 @@ xfs_attrmulti_attr_get(
 {
 	unsigned char		*kbuf;
 	int			error = -EFAULT;
+	size_t			namelen;
 
 	if (*len > XFS_XATTR_SIZE_MAX)
 		return -EINVAL;
@@ -439,7 +440,9 @@ xfs_attrmulti_attr_get(
 	if (!kbuf)
 		return -ENOMEM;
 
-	error = xfs_attr_get(XFS_I(inode), name, &kbuf, (int *)len, flags);
+	namelen = strlen(name);
+	error = xfs_attr_get(XFS_I(inode), name, namelen, &kbuf, (int *)len,
+			     flags);
 	if (error)
 		goto out_kfree;
 
@@ -461,6 +464,7 @@ xfs_attrmulti_attr_set(
 {
 	unsigned char		*kbuf;
 	int			error;
+	size_t			namelen;
 
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 		return -EPERM;
@@ -471,7 +475,8 @@ xfs_attrmulti_attr_set(
 	if (IS_ERR(kbuf))
 		return PTR_ERR(kbuf);
 
-	error = xfs_attr_set(XFS_I(inode), name, kbuf, len, flags);
+	namelen = strlen(name);
+	error = xfs_attr_set(XFS_I(inode), name, namelen, kbuf, len, flags);
 	if (!error)
 		xfs_forget_acl(inode, name, flags);
 	kfree(kbuf);
@@ -485,10 +490,12 @@ xfs_attrmulti_attr_remove(
 	uint32_t		flags)
 {
 	int			error;
+	size_t			namelen;
 
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 		return -EPERM;
-	error = xfs_attr_remove(XFS_I(inode), name, flags);
+	namelen = strlen(name);
+	error = xfs_attr_remove(XFS_I(inode), name, namelen, flags);
 	if (!error)
 		xfs_forget_acl(inode, name, flags);
 	return error;
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 18e45e3..7f47f87 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -49,8 +49,10 @@ xfs_initxattrs(
 	int			error = 0;
 
 	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
-		error = xfs_attr_set(ip, xattr->name, xattr->value,
-				      xattr->value_len, ATTR_SECURE);
+		error = xfs_attr_set(ip, xattr->name,
+				     strlen(xattr->name),
+				     xattr->value, xattr->value_len,
+				     ATTR_SECURE);
 		if (error < 0)
 			break;
 	}
diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
index cb895b1..59ffe6c 100644
--- a/fs/xfs/xfs_xattr.c
+++ b/fs/xfs/xfs_xattr.c
@@ -23,6 +23,7 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
 	int xflags = handler->flags;
 	struct xfs_inode *ip = XFS_I(inode);
 	int error, asize = size;
+	size_t namelen = strlen(name);
 
 	/* Convert Linux syscall to XFS internal ATTR flags */
 	if (!size) {
@@ -30,7 +31,8 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
 		value = NULL;
 	}
 
-	error = xfs_attr_get(ip, name, (unsigned char **)&value, &asize, xflags);
+	error = xfs_attr_get(ip, name, namelen, (unsigned char **)&value,
+			     &asize, xflags);
 	if (error)
 		return error;
 	return asize;
@@ -66,6 +68,7 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
 	int			xflags = handler->flags;
 	struct xfs_inode	*ip = XFS_I(inode);
 	int			error;
+	size_t			namelen = strlen(name);
 
 	/* Convert Linux syscall to XFS internal ATTR flags */
 	if (flags & XATTR_CREATE)
@@ -74,9 +77,9 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
 		xflags |= ATTR_REPLACE;
 
 	if (!value)
-		return xfs_attr_remove(ip, (unsigned char *)name, xflags);
-	error = xfs_attr_set(ip, (unsigned char *)name,
-				(void *)value, size, xflags);
+		return xfs_attr_remove(ip, name,
+				       namelen, xflags);
+	error = xfs_attr_set(ip, name, namelen, (void *)value, size, xflags);
 	if (!error)
 		xfs_forget_acl(inode, name, xflags);
 
-- 
2.7.4


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

* [PATCH v4 02/17] xfs: Replace attribute parameters with struct xfs_name
  2019-11-07  1:27 [PATCH v4 00/17] xfs: Delay Ready Attributes Allison Collins
  2019-11-07  1:27 ` [PATCH v4 01/17] xfs: Remove all strlen in all xfs_attr_* functions for attr names Allison Collins
@ 2019-11-07  1:27 ` Allison Collins
  2019-11-08  1:13   ` Darrick J. Wong
  2019-11-11 17:49   ` Christoph Hellwig
  2019-11-07  1:27 ` [PATCH v4 03/17] xfs: Embed struct xfs_name in xfs_da_args Allison Collins
                   ` (14 subsequent siblings)
  16 siblings, 2 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-07  1:27 UTC (permalink / raw)
  To: linux-xfs

This patch replaces the attribute name and length parameters with a
single struct xfs_name parameter.  This helps to clean up the numbers of
parameters being passed around and pre-simplifies the code some.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c | 22 +++++++++-------------
 fs/xfs/libxfs/xfs_attr.h | 12 +++++-------
 fs/xfs/xfs_acl.c         | 27 +++++++++++++--------------
 fs/xfs/xfs_ioctl.c       | 25 +++++++++++++++----------
 fs/xfs/xfs_iops.c        |  9 ++++++---
 fs/xfs/xfs_xattr.c       | 25 +++++++++++++++----------
 6 files changed, 63 insertions(+), 57 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 7589cb7..5a9624a 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -61,8 +61,7 @@ STATIC int
 xfs_attr_args_init(
 	struct xfs_da_args	*args,
 	struct xfs_inode	*dp,
-	const unsigned char	*name,
-	size_t			namelen,
+	struct xfs_name		*name,
 	int			flags)
 {
 
@@ -74,8 +73,8 @@ xfs_attr_args_init(
 	args->whichfork = XFS_ATTR_FORK;
 	args->dp = dp;
 	args->flags = flags;
-	args->name = name;
-	args->namelen = namelen;
+	args->name = name->name;
+	args->namelen = name->len;
 	if (args->namelen >= MAXNAMELEN)
 		return -EFAULT;		/* match IRIX behaviour */
 
@@ -139,8 +138,7 @@ xfs_attr_get_ilocked(
 int
 xfs_attr_get(
 	struct xfs_inode	*ip,
-	const unsigned char	*name,
-	size_t			namelen,
+	struct xfs_name		*name,
 	unsigned char		**value,
 	int			*valuelenp,
 	int			flags)
@@ -156,7 +154,7 @@ xfs_attr_get(
 	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
 		return -EIO;
 
-	error = xfs_attr_args_init(&args, ip, name, namelen, flags);
+	error = xfs_attr_args_init(&args, ip, name, flags);
 	if (error)
 		return error;
 
@@ -339,8 +337,7 @@ xfs_attr_remove_args(
 int
 xfs_attr_set(
 	struct xfs_inode	*dp,
-	const unsigned char	*name,
-	size_t			namelen,
+	struct xfs_name		*name,
 	unsigned char		*value,
 	int			valuelen,
 	int			flags)
@@ -356,7 +353,7 @@ xfs_attr_set(
 	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
 		return -EIO;
 
-	error = xfs_attr_args_init(&args, dp, name, namelen, flags);
+	error = xfs_attr_args_init(&args, dp, name, flags);
 	if (error)
 		return error;
 
@@ -444,8 +441,7 @@ xfs_attr_set(
 int
 xfs_attr_remove(
 	struct xfs_inode	*dp,
-	const unsigned char	*name,
-	size_t			namelen,
+	struct xfs_name		*name,
 	int			flags)
 {
 	struct xfs_mount	*mp = dp->i_mount;
@@ -457,7 +453,7 @@ xfs_attr_remove(
 	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
 		return -EIO;
 
-	error = xfs_attr_args_init(&args, dp, name, namelen, flags);
+	error = xfs_attr_args_init(&args, dp, name, flags);
 	if (error)
 		return error;
 
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index 106a2f2..44dd07a 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -144,14 +144,12 @@ int xfs_attr_list_int_ilocked(struct xfs_attr_list_context *);
 int xfs_attr_list_int(struct xfs_attr_list_context *);
 int xfs_inode_hasattr(struct xfs_inode *ip);
 int xfs_attr_get_ilocked(struct xfs_inode *ip, struct xfs_da_args *args);
-int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
-		 size_t namelen, unsigned char **value, int *valuelenp,
-		 int flags);
-int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
-		 size_t namelen, unsigned char *value, int valuelen, int flags);
+int xfs_attr_get(struct xfs_inode *ip, struct xfs_name *name,
+		 unsigned char **value, int *valuelenp, int flags);
+int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
+		 unsigned char *value, int valuelen, int flags);
 int xfs_attr_set_args(struct xfs_da_args *args);
-int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name,
-		    size_t namelen, int flags);
+int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
 int xfs_attr_remove_args(struct xfs_da_args *args);
 int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
 		  int flags, struct attrlist_cursor_kern *cursor);
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index 12be708..e868755 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -113,7 +113,7 @@ xfs_get_acl(struct inode *inode, int type)
 	struct xfs_inode *ip = XFS_I(inode);
 	struct posix_acl *acl = NULL;
 	struct xfs_acl *xfs_acl = NULL;
-	unsigned char *ea_name;
+	struct xfs_name name;
 	int error;
 	int len;
 
@@ -121,10 +121,10 @@ xfs_get_acl(struct inode *inode, int type)
 
 	switch (type) {
 	case ACL_TYPE_ACCESS:
-		ea_name = SGI_ACL_FILE;
+		name.name = SGI_ACL_FILE;
 		break;
 	case ACL_TYPE_DEFAULT:
-		ea_name = SGI_ACL_DEFAULT;
+		name.name = SGI_ACL_DEFAULT;
 		break;
 	default:
 		BUG();
@@ -135,9 +135,9 @@ xfs_get_acl(struct inode *inode, int type)
 	 * go out to the disk.
 	 */
 	len = XFS_ACL_MAX_SIZE(ip->i_mount);
-	error = xfs_attr_get(ip, ea_name, strlen(ea_name), 
-				(unsigned char **)&xfs_acl, &len,
-				ATTR_ALLOC | ATTR_ROOT);
+	name.len = strlen(name.name);
+	error = xfs_attr_get(ip, &name, (unsigned char **)&xfs_acl, &len,
+			     ATTR_ALLOC | ATTR_ROOT);
 	if (error) {
 		/*
 		 * If the attribute doesn't exist make sure we have a negative
@@ -157,17 +157,17 @@ int
 __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 {
 	struct xfs_inode *ip = XFS_I(inode);
-	unsigned char *ea_name;
+	struct xfs_name name;
 	int error;
 
 	switch (type) {
 	case ACL_TYPE_ACCESS:
-		ea_name = SGI_ACL_FILE;
+		name.name = SGI_ACL_FILE;
 		break;
 	case ACL_TYPE_DEFAULT:
 		if (!S_ISDIR(inode->i_mode))
 			return acl ? -EACCES : 0;
-		ea_name = SGI_ACL_DEFAULT;
+		name.name = SGI_ACL_DEFAULT;
 		break;
 	default:
 		return -EINVAL;
@@ -187,17 +187,16 @@ __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
 		len -= sizeof(struct xfs_acl_entry) *
 			 (XFS_ACL_MAX_ENTRIES(ip->i_mount) - acl->a_count);
 
-		error = xfs_attr_set(ip, ea_name, strlen(ea_name),
-				     (unsigned char *)xfs_acl, len, ATTR_ROOT);
+		name.len = strlen(name.name);
+		error = xfs_attr_set(ip, &name, (unsigned char *)xfs_acl, len,
+				     ATTR_ROOT);
 
 		kmem_free(xfs_acl);
 	} else {
 		/*
 		 * A NULL ACL argument means we want to remove the ACL.
 		 */
-		error = xfs_attr_remove(ip, ea_name,
-					strlen(ea_name),
-					ATTR_ROOT);
+		error = xfs_attr_remove(ip, &name, ATTR_ROOT);
 
 		/*
 		 * If the attribute didn't exist to start with that's fine.
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index 269c321..ae0ed88 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -432,7 +432,10 @@ xfs_attrmulti_attr_get(
 {
 	unsigned char		*kbuf;
 	int			error = -EFAULT;
-	size_t			namelen;
+	struct xfs_name		xname = {
+		.name		= name,
+		.len		= strlen(name),
+	};
 
 	if (*len > XFS_XATTR_SIZE_MAX)
 		return -EINVAL;
@@ -440,9 +443,7 @@ xfs_attrmulti_attr_get(
 	if (!kbuf)
 		return -ENOMEM;
 
-	namelen = strlen(name);
-	error = xfs_attr_get(XFS_I(inode), name, namelen, &kbuf, (int *)len,
-			     flags);
+	error = xfs_attr_get(XFS_I(inode), &xname, &kbuf, (int *)len, flags);
 	if (error)
 		goto out_kfree;
 
@@ -464,7 +465,7 @@ xfs_attrmulti_attr_set(
 {
 	unsigned char		*kbuf;
 	int			error;
-	size_t			namelen;
+	struct xfs_name		xname;
 
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 		return -EPERM;
@@ -475,8 +476,9 @@ xfs_attrmulti_attr_set(
 	if (IS_ERR(kbuf))
 		return PTR_ERR(kbuf);
 
-	namelen = strlen(name);
-	error = xfs_attr_set(XFS_I(inode), name, namelen, kbuf, len, flags);
+	xname.name = name;
+	xname.len = strlen(name);
+	error = xfs_attr_set(XFS_I(inode), &xname, kbuf, len, flags);
 	if (!error)
 		xfs_forget_acl(inode, name, flags);
 	kfree(kbuf);
@@ -490,12 +492,15 @@ xfs_attrmulti_attr_remove(
 	uint32_t		flags)
 {
 	int			error;
-	size_t			namelen;
+	struct xfs_name		xname = {
+		.name		= name,
+		.len		= strlen(name),
+	};
 
 	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
 		return -EPERM;
-	namelen = strlen(name);
-	error = xfs_attr_remove(XFS_I(inode), name, namelen, flags);
+
+	error = xfs_attr_remove(XFS_I(inode), &xname, flags);
 	if (!error)
 		xfs_forget_acl(inode, name, flags);
 	return error;
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index 7f47f87..aef346e 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -49,9 +49,12 @@ xfs_initxattrs(
 	int			error = 0;
 
 	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
-		error = xfs_attr_set(ip, xattr->name,
-				     strlen(xattr->name),
-				     xattr->value, xattr->value_len,
+		struct xfs_name	name = {
+			.name	= xattr->name,
+			.len	= strlen(xattr->name),
+		};
+
+		error = xfs_attr_set(ip, &name, xattr->value, xattr->value_len,
 				     ATTR_SECURE);
 		if (error < 0)
 			break;
diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
index 59ffe6c..6c5321d 100644
--- a/fs/xfs/xfs_xattr.c
+++ b/fs/xfs/xfs_xattr.c
@@ -20,10 +20,13 @@ static int
 xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
 		struct inode *inode, const char *name, void *value, size_t size)
 {
-	int xflags = handler->flags;
-	struct xfs_inode *ip = XFS_I(inode);
-	int error, asize = size;
-	size_t namelen = strlen(name);
+	int			xflags = handler->flags;
+	struct xfs_inode	*ip = XFS_I(inode);
+	int			error, asize = size;
+	struct xfs_name		xname = {
+		.name		= name,
+		.len		= strlen(name),
+	};
 
 	/* Convert Linux syscall to XFS internal ATTR flags */
 	if (!size) {
@@ -31,8 +34,8 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
 		value = NULL;
 	}
 
-	error = xfs_attr_get(ip, name, namelen, (unsigned char **)&value,
-			     &asize, xflags);
+	error = xfs_attr_get(ip, &xname, (unsigned char **)&value, &asize,
+			     xflags);
 	if (error)
 		return error;
 	return asize;
@@ -68,7 +71,10 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
 	int			xflags = handler->flags;
 	struct xfs_inode	*ip = XFS_I(inode);
 	int			error;
-	size_t			namelen = strlen(name);
+	struct xfs_name		xname = {
+		.name		= name,
+		.len		= strlen(name),
+	};
 
 	/* Convert Linux syscall to XFS internal ATTR flags */
 	if (flags & XATTR_CREATE)
@@ -77,9 +83,8 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
 		xflags |= ATTR_REPLACE;
 
 	if (!value)
-		return xfs_attr_remove(ip, name,
-				       namelen, xflags);
-	error = xfs_attr_set(ip, name, namelen, (void *)value, size, xflags);
+		return xfs_attr_remove(ip, &xname, xflags);
+	error = xfs_attr_set(ip, &xname, (void *)value, size, xflags);
 	if (!error)
 		xfs_forget_acl(inode, name, xflags);
 
-- 
2.7.4


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

* [PATCH v4 03/17] xfs: Embed struct xfs_name in xfs_da_args
  2019-11-07  1:27 [PATCH v4 00/17] xfs: Delay Ready Attributes Allison Collins
  2019-11-07  1:27 ` [PATCH v4 01/17] xfs: Remove all strlen in all xfs_attr_* functions for attr names Allison Collins
  2019-11-07  1:27 ` [PATCH v4 02/17] xfs: Replace attribute parameters with struct xfs_name Allison Collins
@ 2019-11-07  1:27 ` Allison Collins
  2019-11-08  1:25   ` Darrick J. Wong
  2019-11-07  1:27 ` [PATCH v4 04/17] xfs: Add xfs_dabuf defines Allison Collins
                   ` (13 subsequent siblings)
  16 siblings, 1 reply; 77+ messages in thread
From: Allison Collins @ 2019-11-07  1:27 UTC (permalink / raw)
  To: linux-xfs

This patch embeds an xfs_name in xfs_da_args, replacing the name,
namelen, and flags members.  This helps to clean up the xfs_da_args
structure and make it more uniform with the new xfs_name parameter
being passed around.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
---
 fs/xfs/libxfs/xfs_attr.c        |  36 +++++++-------
 fs/xfs/libxfs/xfs_attr_leaf.c   | 106 +++++++++++++++++++++-------------------
 fs/xfs/libxfs/xfs_attr_remote.c |   2 +-
 fs/xfs/libxfs/xfs_da_btree.c    |   5 +-
 fs/xfs/libxfs/xfs_da_btree.h    |   4 +-
 fs/xfs/libxfs/xfs_dir2.c        |  18 +++----
 fs/xfs/libxfs/xfs_dir2_block.c  |   6 +--
 fs/xfs/libxfs/xfs_dir2_leaf.c   |   6 +--
 fs/xfs/libxfs/xfs_dir2_node.c   |   8 +--
 fs/xfs/libxfs/xfs_dir2_sf.c     |  30 ++++++------
 fs/xfs/scrub/attr.c             |  12 ++---
 fs/xfs/xfs_trace.h              |  20 ++++----
 12 files changed, 128 insertions(+), 125 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 5a9624a..b77b985 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -72,13 +72,12 @@ xfs_attr_args_init(
 	args->geo = dp->i_mount->m_attr_geo;
 	args->whichfork = XFS_ATTR_FORK;
 	args->dp = dp;
-	args->flags = flags;
-	args->name = name->name;
-	args->namelen = name->len;
-	if (args->namelen >= MAXNAMELEN)
+	name->type = flags;
+	memcpy(&args->name, name, sizeof(struct xfs_name));
+	if (args->name.len >= MAXNAMELEN)
 		return -EFAULT;		/* match IRIX behaviour */
 
-	args->hashval = xfs_da_hashname(args->name, args->namelen);
+	args->hashval = xfs_da_hashname(args->name.name, args->name.len);
 	return 0;
 }
 
@@ -236,7 +235,7 @@ xfs_attr_try_sf_addname(
 	 * Commit the shortform mods, and we're done.
 	 * NOTE: this is also the error path (EEXIST, etc).
 	 */
-	if (!error && (args->flags & ATTR_KERNOTIME) == 0)
+	if (!error && (args->name.type & ATTR_KERNOTIME) == 0)
 		xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
 
 	if (mp->m_flags & XFS_MOUNT_WSYNC)
@@ -357,6 +356,9 @@ xfs_attr_set(
 	if (error)
 		return error;
 
+	/* Use name now stored in args */
+	name = &args.name;
+
 	args.value = value;
 	args.valuelen = valuelen;
 	args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
@@ -372,7 +374,7 @@ xfs_attr_set(
 	 */
 	if (XFS_IFORK_Q(dp) == 0) {
 		int sf_size = sizeof(xfs_attr_sf_hdr_t) +
-			XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, valuelen);
+			XFS_ATTR_SF_ENTSIZE_BYNAME(args.name.len, valuelen);
 
 		error = xfs_bmap_add_attrfork(dp, sf_size, rsvd);
 		if (error)
@@ -532,10 +534,10 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
 	trace_xfs_attr_sf_addname(args);
 
 	retval = xfs_attr_shortform_lookup(args);
-	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
+	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
 		return retval;
 	} else if (retval == -EEXIST) {
-		if (args->flags & ATTR_CREATE)
+		if (args->name.type & ATTR_CREATE)
 			return retval;
 		retval = xfs_attr_shortform_remove(args);
 		if (retval)
@@ -545,15 +547,15 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
 		 * that the leaf format add routine won't trip over the attr
 		 * not being around.
 		 */
-		args->flags &= ~ATTR_REPLACE;
+		args->name.type &= ~ATTR_REPLACE;
 	}
 
-	if (args->namelen >= XFS_ATTR_SF_ENTSIZE_MAX ||
+	if (args->name.len >= XFS_ATTR_SF_ENTSIZE_MAX ||
 	    args->valuelen >= XFS_ATTR_SF_ENTSIZE_MAX)
 		return -ENOSPC;
 
 	newsize = XFS_ATTR_SF_TOTSIZE(args->dp);
-	newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
+	newsize += XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
 
 	forkoff = xfs_attr_shortform_bytesfit(args->dp, newsize);
 	if (!forkoff)
@@ -598,11 +600,11 @@ xfs_attr_leaf_addname(
 	 * the given flags produce an error or call for an atomic rename.
 	 */
 	retval = xfs_attr3_leaf_lookup_int(bp, args);
-	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
+	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
 		xfs_trans_brelse(args->trans, bp);
 		return retval;
 	} else if (retval == -EEXIST) {
-		if (args->flags & ATTR_CREATE) {	/* pure create op */
+		if (args->name.type & ATTR_CREATE) {	/* pure create op */
 			xfs_trans_brelse(args->trans, bp);
 			return retval;
 		}
@@ -872,10 +874,10 @@ xfs_attr_node_addname(
 		goto out;
 	blk = &state->path.blk[ state->path.active-1 ];
 	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
-	if ((args->flags & ATTR_REPLACE) && (retval == -ENOATTR)) {
+	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
 		goto out;
 	} else if (retval == -EEXIST) {
-		if (args->flags & ATTR_CREATE)
+		if (args->name.type & ATTR_CREATE)
 			goto out;
 
 		trace_xfs_attr_node_replace(args);
@@ -1007,7 +1009,7 @@ xfs_attr_node_addname(
 		 * The INCOMPLETE flag means that we will find the "old"
 		 * attr, not the "new" one.
 		 */
-		args->flags |= XFS_ATTR_INCOMPLETE;
+		args->name.type |= XFS_ATTR_INCOMPLETE;
 		state = xfs_da_state_alloc();
 		state->args = args;
 		state->mp = mp;
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index 56e62b3..cf5de30 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -465,7 +465,7 @@ xfs_attr_copy_value(
 	/*
 	 * No copy if all we have to do is get the length
 	 */
-	if (args->flags & ATTR_KERNOVAL) {
+	if (args->name.type & ATTR_KERNOVAL) {
 		args->valuelen = valuelen;
 		return 0;
 	}
@@ -680,27 +680,27 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
 	sfe = &sf->list[0];
 	for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
 #ifdef DEBUG
-		if (sfe->namelen != args->namelen)
+		if (sfe->namelen != args->name.len)
 			continue;
-		if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
+		if (memcmp(args->name.name, sfe->nameval, args->name.len) != 0)
 			continue;
-		if (!xfs_attr_namesp_match(args->flags, sfe->flags))
+		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
 			continue;
 		ASSERT(0);
 #endif
 	}
 
 	offset = (char *)sfe - (char *)sf;
-	size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->namelen, args->valuelen);
+	size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
 	xfs_idata_realloc(dp, size, XFS_ATTR_FORK);
 	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
 	sfe = (xfs_attr_sf_entry_t *)((char *)sf + offset);
 
-	sfe->namelen = args->namelen;
+	sfe->namelen = args->name.len;
 	sfe->valuelen = args->valuelen;
-	sfe->flags = XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags);
-	memcpy(sfe->nameval, args->name, args->namelen);
-	memcpy(&sfe->nameval[args->namelen], args->value, args->valuelen);
+	sfe->flags = XFS_ATTR_NSP_ARGS_TO_ONDISK(args->name.type);
+	memcpy(sfe->nameval, args->name.name, args->name.len);
+	memcpy(&sfe->nameval[args->name.len], args->value, args->valuelen);
 	sf->hdr.count++;
 	be16_add_cpu(&sf->hdr.totsize, size);
 	xfs_trans_log_inode(args->trans, dp, XFS_ILOG_CORE | XFS_ILOG_ADATA);
@@ -750,11 +750,11 @@ xfs_attr_shortform_remove(xfs_da_args_t *args)
 	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
 					base += size, i++) {
 		size = XFS_ATTR_SF_ENTSIZE(sfe);
-		if (sfe->namelen != args->namelen)
+		if (sfe->namelen != args->name.len)
 			continue;
-		if (memcmp(sfe->nameval, args->name, args->namelen) != 0)
+		if (memcmp(sfe->nameval, args->name.name, args->name.len) != 0)
 			continue;
-		if (!xfs_attr_namesp_match(args->flags, sfe->flags))
+		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
 			continue;
 		break;
 	}
@@ -817,11 +817,11 @@ xfs_attr_shortform_lookup(xfs_da_args_t *args)
 	sfe = &sf->list[0];
 	for (i = 0; i < sf->hdr.count;
 				sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
-		if (sfe->namelen != args->namelen)
+		if (sfe->namelen != args->name.len)
 			continue;
-		if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
+		if (memcmp(args->name.name, sfe->nameval, args->name.len) != 0)
 			continue;
-		if (!xfs_attr_namesp_match(args->flags, sfe->flags))
+		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
 			continue;
 		return -EEXIST;
 	}
@@ -848,13 +848,13 @@ xfs_attr_shortform_getvalue(
 	sfe = &sf->list[0];
 	for (i = 0; i < sf->hdr.count;
 				sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
-		if (sfe->namelen != args->namelen)
+		if (sfe->namelen != args->name.len)
 			continue;
-		if (memcmp(args->name, sfe->nameval, args->namelen) != 0)
+		if (memcmp(args->name.name, sfe->nameval, args->name.len) != 0)
 			continue;
-		if (!xfs_attr_namesp_match(args->flags, sfe->flags))
+		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
 			continue;
-		return xfs_attr_copy_value(args, &sfe->nameval[args->namelen],
+		return xfs_attr_copy_value(args, &sfe->nameval[args->name.len],
 						sfe->valuelen);
 	}
 	return -ENOATTR;
@@ -913,13 +913,13 @@ xfs_attr_shortform_to_leaf(
 
 	sfe = &sf->list[0];
 	for (i = 0; i < sf->hdr.count; i++) {
-		nargs.name = sfe->nameval;
-		nargs.namelen = sfe->namelen;
-		nargs.value = &sfe->nameval[nargs.namelen];
+		nargs.name.name = sfe->nameval;
+		nargs.name.len = sfe->namelen;
+		nargs.value = &sfe->nameval[nargs.name.len];
 		nargs.valuelen = sfe->valuelen;
 		nargs.hashval = xfs_da_hashname(sfe->nameval,
 						sfe->namelen);
-		nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(sfe->flags);
+		nargs.name.type = XFS_ATTR_NSP_ONDISK_TO_ARGS(sfe->flags);
 		error = xfs_attr3_leaf_lookup_int(bp, &nargs); /* set a->index */
 		ASSERT(error == -ENOATTR);
 		error = xfs_attr3_leaf_add(bp, &nargs);
@@ -1120,12 +1120,12 @@ xfs_attr3_leaf_to_shortform(
 			continue;
 		ASSERT(entry->flags & XFS_ATTR_LOCAL);
 		name_loc = xfs_attr3_leaf_name_local(leaf, i);
-		nargs.name = name_loc->nameval;
-		nargs.namelen = name_loc->namelen;
-		nargs.value = &name_loc->nameval[nargs.namelen];
+		nargs.name.name = name_loc->nameval;
+		nargs.name.len = name_loc->namelen;
+		nargs.value = &name_loc->nameval[nargs.name.len];
 		nargs.valuelen = be16_to_cpu(name_loc->valuelen);
 		nargs.hashval = be32_to_cpu(entry->hashval);
-		nargs.flags = XFS_ATTR_NSP_ONDISK_TO_ARGS(entry->flags);
+		nargs.name.type = XFS_ATTR_NSP_ONDISK_TO_ARGS(entry->flags);
 		xfs_attr_shortform_add(&nargs, forkoff);
 	}
 	error = 0;
@@ -1453,7 +1453,7 @@ xfs_attr3_leaf_add_work(
 				     ichdr->freemap[mapindex].size);
 	entry->hashval = cpu_to_be32(args->hashval);
 	entry->flags = tmp ? XFS_ATTR_LOCAL : 0;
-	entry->flags |= XFS_ATTR_NSP_ARGS_TO_ONDISK(args->flags);
+	entry->flags |= XFS_ATTR_NSP_ARGS_TO_ONDISK(args->name.type);
 	if (args->op_flags & XFS_DA_OP_RENAME) {
 		entry->flags |= XFS_ATTR_INCOMPLETE;
 		if ((args->blkno2 == args->blkno) &&
@@ -1477,15 +1477,16 @@ xfs_attr3_leaf_add_work(
 	 */
 	if (entry->flags & XFS_ATTR_LOCAL) {
 		name_loc = xfs_attr3_leaf_name_local(leaf, args->index);
-		name_loc->namelen = args->namelen;
+		name_loc->namelen = args->name.len;
 		name_loc->valuelen = cpu_to_be16(args->valuelen);
-		memcpy((char *)name_loc->nameval, args->name, args->namelen);
-		memcpy((char *)&name_loc->nameval[args->namelen], args->value,
+		memcpy((char *)name_loc->nameval, args->name.name,
+		       args->name.len);
+		memcpy((char *)&name_loc->nameval[args->name.len], args->value,
 				   be16_to_cpu(name_loc->valuelen));
 	} else {
 		name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index);
-		name_rmt->namelen = args->namelen;
-		memcpy((char *)name_rmt->name, args->name, args->namelen);
+		name_rmt->namelen = args->name.len;
+		memcpy((char *)name_rmt->name, args->name.name, args->name.len);
 		entry->flags |= XFS_ATTR_INCOMPLETE;
 		/* just in case */
 		name_rmt->valuelen = 0;
@@ -2398,29 +2399,31 @@ xfs_attr3_leaf_lookup_int(
 		 * If we are looking for INCOMPLETE entries, show only those.
 		 * If we are looking for complete entries, show only those.
 		 */
-		if ((args->flags & XFS_ATTR_INCOMPLETE) !=
+		if ((args->name.type & XFS_ATTR_INCOMPLETE) !=
 		    (entry->flags & XFS_ATTR_INCOMPLETE)) {
 			continue;
 		}
 		if (entry->flags & XFS_ATTR_LOCAL) {
 			name_loc = xfs_attr3_leaf_name_local(leaf, probe);
-			if (name_loc->namelen != args->namelen)
+			if (name_loc->namelen != args->name.len)
 				continue;
-			if (memcmp(args->name, name_loc->nameval,
-							args->namelen) != 0)
+			if (memcmp(args->name.name, name_loc->nameval,
+							args->name.len) != 0)
 				continue;
-			if (!xfs_attr_namesp_match(args->flags, entry->flags))
+			if (!xfs_attr_namesp_match(args->name.type,
+						   entry->flags))
 				continue;
 			args->index = probe;
 			return -EEXIST;
 		} else {
 			name_rmt = xfs_attr3_leaf_name_remote(leaf, probe);
-			if (name_rmt->namelen != args->namelen)
+			if (name_rmt->namelen != args->name.len)
 				continue;
-			if (memcmp(args->name, name_rmt->name,
-							args->namelen) != 0)
+			if (memcmp(args->name.name, name_rmt->name,
+							args->name.len) != 0)
 				continue;
-			if (!xfs_attr_namesp_match(args->flags, entry->flags))
+			if (!xfs_attr_namesp_match(args->name.type,
+						   entry->flags))
 				continue;
 			args->index = probe;
 			args->rmtvaluelen = be32_to_cpu(name_rmt->valuelen);
@@ -2462,16 +2465,17 @@ xfs_attr3_leaf_getvalue(
 	entry = &xfs_attr3_leaf_entryp(leaf)[args->index];
 	if (entry->flags & XFS_ATTR_LOCAL) {
 		name_loc = xfs_attr3_leaf_name_local(leaf, args->index);
-		ASSERT(name_loc->namelen == args->namelen);
-		ASSERT(memcmp(args->name, name_loc->nameval, args->namelen) == 0);
+		ASSERT(name_loc->namelen == args->name.len);
+		ASSERT(memcmp(args->name.name, name_loc->nameval,
+			      args->name.len) == 0);
 		return xfs_attr_copy_value(args,
-					&name_loc->nameval[args->namelen],
+					&name_loc->nameval[args->name.len],
 					be16_to_cpu(name_loc->valuelen));
 	}
 
 	name_rmt = xfs_attr3_leaf_name_remote(leaf, args->index);
-	ASSERT(name_rmt->namelen == args->namelen);
-	ASSERT(memcmp(args->name, name_rmt->name, args->namelen) == 0);
+	ASSERT(name_rmt->namelen == args->name.len);
+	ASSERT(memcmp(args->name.name, name_rmt->name, args->name.len) == 0);
 	args->rmtvaluelen = be32_to_cpu(name_rmt->valuelen);
 	args->rmtblkno = be32_to_cpu(name_rmt->valueblk);
 	args->rmtblkcnt = xfs_attr3_rmt_blocks(args->dp->i_mount,
@@ -2687,7 +2691,7 @@ xfs_attr_leaf_newentsize(
 {
 	int			size;
 
-	size = xfs_attr_leaf_entsize_local(args->namelen, args->valuelen);
+	size = xfs_attr_leaf_entsize_local(args->name.len, args->valuelen);
 	if (size < xfs_attr_leaf_entsize_local_max(args->geo->blksize)) {
 		if (local)
 			*local = 1;
@@ -2695,7 +2699,7 @@ xfs_attr_leaf_newentsize(
 	}
 	if (local)
 		*local = 0;
-	return xfs_attr_leaf_entsize_remote(args->namelen);
+	return xfs_attr_leaf_entsize_remote(args->name.len);
 }
 
 
@@ -2749,8 +2753,8 @@ xfs_attr3_leaf_clearflag(
 		name = (char *)name_rmt->name;
 	}
 	ASSERT(be32_to_cpu(entry->hashval) == args->hashval);
-	ASSERT(namelen == args->namelen);
-	ASSERT(memcmp(name, args->name, namelen) == 0);
+	ASSERT(namelen == args->name.len);
+	ASSERT(memcmp(name, args->name.name, namelen) == 0);
 #endif /* DEBUG */
 
 	entry->flags &= ~XFS_ATTR_INCOMPLETE;
diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
index 3e39b7d..db9247a 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.c
+++ b/fs/xfs/libxfs/xfs_attr_remote.c
@@ -379,7 +379,7 @@ xfs_attr_rmtval_get(
 
 	trace_xfs_attr_rmtval_get(args);
 
-	ASSERT(!(args->flags & ATTR_KERNOVAL));
+	ASSERT(!(args->name.type & ATTR_KERNOVAL));
 	ASSERT(args->rmtvaluelen == args->valuelen);
 
 	valuelen = args->rmtvaluelen;
diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c
index 4fd1223..129ec09 100644
--- a/fs/xfs/libxfs/xfs_da_btree.c
+++ b/fs/xfs/libxfs/xfs_da_btree.c
@@ -2040,8 +2040,9 @@ xfs_da_compname(
 	const unsigned char *name,
 	int		len)
 {
-	return (args->namelen == len && memcmp(args->name, name, len) == 0) ?
-					XFS_CMP_EXACT : XFS_CMP_DIFFERENT;
+	return (args->name.len == len &&
+		memcmp(args->name.name, name, len) == 0) ? XFS_CMP_EXACT :
+		XFS_CMP_DIFFERENT;
 }
 
 static xfs_dahash_t
diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
index ae0bbd2..bed4f40 100644
--- a/fs/xfs/libxfs/xfs_da_btree.h
+++ b/fs/xfs/libxfs/xfs_da_btree.h
@@ -47,12 +47,10 @@ enum xfs_dacmp {
  */
 typedef struct xfs_da_args {
 	struct xfs_da_geometry *geo;	/* da block geometry */
-	const uint8_t		*name;		/* string (maybe not NULL terminated) */
-	int		namelen;	/* length of string (maybe no NULL) */
+	struct xfs_name	name;		/* name, length and argument  flags*/
 	uint8_t		filetype;	/* filetype of inode for directories */
 	uint8_t		*value;		/* set of bytes (maybe contain NULLs) */
 	int		valuelen;	/* length of value */
-	int		flags;		/* argument flags (eg: ATTR_NOCREATE) */
 	xfs_dahash_t	hashval;	/* hash value of name */
 	xfs_ino_t	inumber;	/* input/output inode number */
 	struct xfs_inode *dp;		/* directory inode to manipulate */
diff --git a/fs/xfs/libxfs/xfs_dir2.c b/fs/xfs/libxfs/xfs_dir2.c
index 867c5de..6e8e906 100644
--- a/fs/xfs/libxfs/xfs_dir2.c
+++ b/fs/xfs/libxfs/xfs_dir2.c
@@ -74,14 +74,14 @@ xfs_ascii_ci_compname(
 	enum xfs_dacmp	result;
 	int		i;
 
-	if (args->namelen != len)
+	if (args->name.len != len)
 		return XFS_CMP_DIFFERENT;
 
 	result = XFS_CMP_EXACT;
 	for (i = 0; i < len; i++) {
-		if (args->name[i] == name[i])
+		if (args->name.name[i] == name[i])
 			continue;
-		if (tolower(args->name[i]) != tolower(name[i]))
+		if (tolower(args->name.name[i]) != tolower(name[i]))
 			return XFS_CMP_DIFFERENT;
 		result = XFS_CMP_CASE;
 	}
@@ -259,8 +259,7 @@ xfs_dir_createname(
 		return -ENOMEM;
 
 	args->geo = dp->i_mount->m_dir_geo;
-	args->name = name->name;
-	args->namelen = name->len;
+	memcpy(&args->name, name, sizeof(struct xfs_name));
 	args->filetype = name->type;
 	args->hashval = dp->i_mount->m_dirnameops->hashname(name);
 	args->inumber = inum;
@@ -355,8 +354,7 @@ xfs_dir_lookup(
 	 */
 	args = kmem_zalloc(sizeof(*args), KM_NOFS);
 	args->geo = dp->i_mount->m_dir_geo;
-	args->name = name->name;
-	args->namelen = name->len;
+	memcpy(&args->name, name, sizeof(struct xfs_name));
 	args->filetype = name->type;
 	args->hashval = dp->i_mount->m_dirnameops->hashname(name);
 	args->dp = dp;
@@ -427,8 +425,7 @@ xfs_dir_removename(
 		return -ENOMEM;
 
 	args->geo = dp->i_mount->m_dir_geo;
-	args->name = name->name;
-	args->namelen = name->len;
+	memcpy(&args->name, name, sizeof(struct xfs_name));
 	args->filetype = name->type;
 	args->hashval = dp->i_mount->m_dirnameops->hashname(name);
 	args->inumber = ino;
@@ -488,8 +485,7 @@ xfs_dir_replace(
 		return -ENOMEM;
 
 	args->geo = dp->i_mount->m_dir_geo;
-	args->name = name->name;
-	args->namelen = name->len;
+	memcpy(&args->name, name, sizeof(struct xfs_name));
 	args->filetype = name->type;
 	args->hashval = dp->i_mount->m_dirnameops->hashname(name);
 	args->inumber = inum;
diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
index 49e4bc3..8dedc30 100644
--- a/fs/xfs/libxfs/xfs_dir2_block.c
+++ b/fs/xfs/libxfs/xfs_dir2_block.c
@@ -355,7 +355,7 @@ xfs_dir2_block_addname(
 	if (error)
 		return error;
 
-	len = dp->d_ops->data_entsize(args->namelen);
+	len = dp->d_ops->data_entsize(args->name.len);
 
 	/*
 	 * Set up pointers to parts of the block.
@@ -539,8 +539,8 @@ xfs_dir2_block_addname(
 	 * Create the new data entry.
 	 */
 	dep->inumber = cpu_to_be64(args->inumber);
-	dep->namelen = args->namelen;
-	memcpy(dep->name, args->name, args->namelen);
+	dep->namelen = args->name.len;
+	memcpy(dep->name, args->name.name, args->name.len);
 	dp->d_ops->data_put_ftype(dep, args->filetype);
 	tagp = dp->d_ops->data_entry_tag_p(dep);
 	*tagp = cpu_to_be16((char *)dep - (char *)hdr);
diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
index a53e458..b7046e2 100644
--- a/fs/xfs/libxfs/xfs_dir2_leaf.c
+++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
@@ -610,7 +610,7 @@ xfs_dir2_leaf_addname(
 	ents = dp->d_ops->leaf_ents_p(leaf);
 	dp->d_ops->leaf_hdr_from_disk(&leafhdr, leaf);
 	bestsp = xfs_dir2_leaf_bests_p(ltp);
-	length = dp->d_ops->data_entsize(args->namelen);
+	length = dp->d_ops->data_entsize(args->name.len);
 
 	/*
 	 * See if there are any entries with the same hash value
@@ -813,8 +813,8 @@ xfs_dir2_leaf_addname(
 	 */
 	dep = (xfs_dir2_data_entry_t *)dup;
 	dep->inumber = cpu_to_be64(args->inumber);
-	dep->namelen = args->namelen;
-	memcpy(dep->name, args->name, dep->namelen);
+	dep->namelen = args->name.len;
+	memcpy(dep->name, args->name.name, dep->namelen);
 	dp->d_ops->data_put_ftype(dep, args->filetype);
 	tagp = dp->d_ops->data_entry_tag_p(dep);
 	*tagp = cpu_to_be16((char *)dep - (char *)hdr);
diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
index 705c4f5..8bbd742 100644
--- a/fs/xfs/libxfs/xfs_dir2_node.c
+++ b/fs/xfs/libxfs/xfs_dir2_node.c
@@ -604,7 +604,7 @@ xfs_dir2_leafn_lookup_for_addname(
 		ASSERT(free->hdr.magic == cpu_to_be32(XFS_DIR2_FREE_MAGIC) ||
 		       free->hdr.magic == cpu_to_be32(XFS_DIR3_FREE_MAGIC));
 	}
-	length = dp->d_ops->data_entsize(args->namelen);
+	length = dp->d_ops->data_entsize(args->name.len);
 	/*
 	 * Loop over leaf entries with the right hash value.
 	 */
@@ -1869,7 +1869,7 @@ xfs_dir2_node_addname_int(
 	__be16			*tagp;		/* data entry tag pointer */
 	__be16			*bests;
 
-	length = dp->d_ops->data_entsize(args->namelen);
+	length = dp->d_ops->data_entsize(args->name.len);
 	error = xfs_dir2_node_find_freeblk(args, fblk, &dbno, &fbp, &findex,
 					   length);
 	if (error)
@@ -1924,8 +1924,8 @@ xfs_dir2_node_addname_int(
 	/* Fill in the new entry and log it. */
 	dep = (xfs_dir2_data_entry_t *)dup;
 	dep->inumber = cpu_to_be64(args->inumber);
-	dep->namelen = args->namelen;
-	memcpy(dep->name, args->name, dep->namelen);
+	dep->namelen = args->name.len;
+	memcpy(dep->name, args->name.name, dep->namelen);
 	dp->d_ops->data_put_ftype(dep, args->filetype);
 	tagp = dp->d_ops->data_entry_tag_p(dep);
 	*tagp = cpu_to_be16((char *)dep - (char *)hdr);
diff --git a/fs/xfs/libxfs/xfs_dir2_sf.c b/fs/xfs/libxfs/xfs_dir2_sf.c
index ae16ca7..7659cc2 100644
--- a/fs/xfs/libxfs/xfs_dir2_sf.c
+++ b/fs/xfs/libxfs/xfs_dir2_sf.c
@@ -291,7 +291,7 @@ xfs_dir2_sf_addname(
 	/*
 	 * Compute entry (and change in) size.
 	 */
-	incr_isize = dp->d_ops->sf_entsize(sfp, args->namelen);
+	incr_isize = dp->d_ops->sf_entsize(sfp, args->name.len);
 	objchange = 0;
 
 	/*
@@ -375,7 +375,7 @@ xfs_dir2_sf_addname_easy(
 	/*
 	 * Grow the in-inode space.
 	 */
-	xfs_idata_realloc(dp, dp->d_ops->sf_entsize(sfp, args->namelen),
+	xfs_idata_realloc(dp, dp->d_ops->sf_entsize(sfp, args->name.len),
 			  XFS_DATA_FORK);
 	/*
 	 * Need to set up again due to realloc of the inode data.
@@ -385,9 +385,9 @@ xfs_dir2_sf_addname_easy(
 	/*
 	 * Fill in the new entry.
 	 */
-	sfep->namelen = args->namelen;
+	sfep->namelen = args->name.len;
 	xfs_dir2_sf_put_offset(sfep, offset);
-	memcpy(sfep->name, args->name, sfep->namelen);
+	memcpy(sfep->name, args->name.name, sfep->namelen);
 	dp->d_ops->sf_put_ino(sfp, sfep, args->inumber);
 	dp->d_ops->sf_put_ftype(sfep, args->filetype);
 
@@ -446,7 +446,7 @@ xfs_dir2_sf_addname_hard(
 	 */
 	for (offset = dp->d_ops->data_first_offset,
 	      oldsfep = xfs_dir2_sf_firstentry(oldsfp),
-	      add_datasize = dp->d_ops->data_entsize(args->namelen),
+	      add_datasize = dp->d_ops->data_entsize(args->name.len),
 	      eof = (char *)oldsfep == &buf[old_isize];
 	     !eof;
 	     offset = new_offset + dp->d_ops->data_entsize(oldsfep->namelen),
@@ -476,9 +476,9 @@ xfs_dir2_sf_addname_hard(
 	/*
 	 * Fill in the new entry, and update the header counts.
 	 */
-	sfep->namelen = args->namelen;
+	sfep->namelen = args->name.len;
 	xfs_dir2_sf_put_offset(sfep, offset);
-	memcpy(sfep->name, args->name, sfep->namelen);
+	memcpy(sfep->name, args->name.name, sfep->namelen);
 	dp->d_ops->sf_put_ino(sfp, sfep, args->inumber);
 	dp->d_ops->sf_put_ftype(sfep, args->filetype);
 	sfp->count++;
@@ -522,7 +522,7 @@ xfs_dir2_sf_addname_pick(
 	dp = args->dp;
 
 	sfp = (xfs_dir2_sf_hdr_t *)dp->i_df.if_u1.if_data;
-	size = dp->d_ops->data_entsize(args->namelen);
+	size = dp->d_ops->data_entsize(args->name.len);
 	offset = dp->d_ops->data_first_offset;
 	sfep = xfs_dir2_sf_firstentry(sfp);
 	holefit = 0;
@@ -807,7 +807,7 @@ xfs_dir2_sf_lookup(
 	/*
 	 * Special case for .
 	 */
-	if (args->namelen == 1 && args->name[0] == '.') {
+	if (args->name.len == 1 && args->name.name[0] == '.') {
 		args->inumber = dp->i_ino;
 		args->cmpresult = XFS_CMP_EXACT;
 		args->filetype = XFS_DIR3_FT_DIR;
@@ -816,8 +816,8 @@ xfs_dir2_sf_lookup(
 	/*
 	 * Special case for ..
 	 */
-	if (args->namelen == 2 &&
-	    args->name[0] == '.' && args->name[1] == '.') {
+	if (args->name.len == 2 &&
+	    args->name.name[0] == '.' && args->name.name[1] == '.') {
 		args->inumber = dp->d_ops->sf_get_parent_ino(sfp);
 		args->cmpresult = XFS_CMP_EXACT;
 		args->filetype = XFS_DIR3_FT_DIR;
@@ -912,7 +912,7 @@ xfs_dir2_sf_removename(
 	 * Calculate sizes.
 	 */
 	byteoff = (int)((char *)sfep - (char *)sfp);
-	entsize = dp->d_ops->sf_entsize(sfp, args->namelen);
+	entsize = dp->d_ops->sf_entsize(sfp, args->name.len);
 	newsize = oldsize - entsize;
 	/*
 	 * Copy the part if any after the removed entry, sliding it down.
@@ -1002,12 +1002,12 @@ xfs_dir2_sf_replace(
 	} else
 		i8elevated = 0;
 
-	ASSERT(args->namelen != 1 || args->name[0] != '.');
+	ASSERT(args->name.len != 1 || args->name.name[0] != '.');
 	/*
 	 * Replace ..'s entry.
 	 */
-	if (args->namelen == 2 &&
-	    args->name[0] == '.' && args->name[1] == '.') {
+	if (args->name.len == 2 &&
+	    args->name.name[0] == '.' && args->name.name[1] == '.') {
 		ino = dp->d_ops->sf_get_parent_ino(sfp);
 		ASSERT(args->inumber != ino);
 		dp->d_ops->sf_put_parent_ino(sfp, args->inumber);
diff --git a/fs/xfs/scrub/attr.c b/fs/xfs/scrub/attr.c
index 0edc7f8..42f7c07 100644
--- a/fs/xfs/scrub/attr.c
+++ b/fs/xfs/scrub/attr.c
@@ -147,17 +147,17 @@ xchk_xattr_listent(
 		return;
 	}
 
-	args.flags = ATTR_KERNOTIME;
+	args.name.type = ATTR_KERNOTIME;
 	if (flags & XFS_ATTR_ROOT)
-		args.flags |= ATTR_ROOT;
+		args.name.type |= ATTR_ROOT;
 	else if (flags & XFS_ATTR_SECURE)
-		args.flags |= ATTR_SECURE;
+		args.name.type |= ATTR_SECURE;
 	args.geo = context->dp->i_mount->m_attr_geo;
 	args.whichfork = XFS_ATTR_FORK;
 	args.dp = context->dp;
-	args.name = name;
-	args.namelen = namelen;
-	args.hashval = xfs_da_hashname(args.name, args.namelen);
+	args.name.name = name;
+	args.name.len = namelen;
+	args.hashval = xfs_da_hashname(args.name.name, args.name.len);
 	args.trans = context->tp;
 	args.value = xchk_xattr_valuebuf(sx->sc);
 	args.valuelen = valuelen;
diff --git a/fs/xfs/xfs_trace.h b/fs/xfs/xfs_trace.h
index c13bb36..cee7536 100644
--- a/fs/xfs/xfs_trace.h
+++ b/fs/xfs/xfs_trace.h
@@ -1633,7 +1633,7 @@ DECLARE_EVENT_CLASS(xfs_da_class,
 	TP_STRUCT__entry(
 		__field(dev_t, dev)
 		__field(xfs_ino_t, ino)
-		__dynamic_array(char, name, args->namelen)
+		__dynamic_array(char, name, args->name.len)
 		__field(int, namelen)
 		__field(xfs_dahash_t, hashval)
 		__field(xfs_ino_t, inumber)
@@ -1642,9 +1642,10 @@ DECLARE_EVENT_CLASS(xfs_da_class,
 	TP_fast_assign(
 		__entry->dev = VFS_I(args->dp)->i_sb->s_dev;
 		__entry->ino = args->dp->i_ino;
-		if (args->namelen)
-			memcpy(__get_str(name), args->name, args->namelen);
-		__entry->namelen = args->namelen;
+		if (args->name.len)
+			memcpy(__get_str(name), args->name.name,
+			       args->name.len);
+		__entry->namelen = args->name.len;
 		__entry->hashval = args->hashval;
 		__entry->inumber = args->inumber;
 		__entry->op_flags = args->op_flags;
@@ -1697,7 +1698,7 @@ DECLARE_EVENT_CLASS(xfs_attr_class,
 	TP_STRUCT__entry(
 		__field(dev_t, dev)
 		__field(xfs_ino_t, ino)
-		__dynamic_array(char, name, args->namelen)
+		__dynamic_array(char, name, args->name.len)
 		__field(int, namelen)
 		__field(int, valuelen)
 		__field(xfs_dahash_t, hashval)
@@ -1707,12 +1708,13 @@ DECLARE_EVENT_CLASS(xfs_attr_class,
 	TP_fast_assign(
 		__entry->dev = VFS_I(args->dp)->i_sb->s_dev;
 		__entry->ino = args->dp->i_ino;
-		if (args->namelen)
-			memcpy(__get_str(name), args->name, args->namelen);
-		__entry->namelen = args->namelen;
+		if (args->name.len)
+			memcpy(__get_str(name), args->name.name,
+			       args->name.len);
+		__entry->namelen = args->name.len;
 		__entry->valuelen = args->valuelen;
 		__entry->hashval = args->hashval;
-		__entry->flags = args->flags;
+		__entry->flags = args->name.type;
 		__entry->op_flags = args->op_flags;
 	),
 	TP_printk("dev %d:%d ino 0x%llx name %.*s namelen %d valuelen %d "
-- 
2.7.4


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

* [PATCH v4 04/17] xfs: Add xfs_dabuf defines
  2019-11-07  1:27 [PATCH v4 00/17] xfs: Delay Ready Attributes Allison Collins
                   ` (2 preceding siblings ...)
  2019-11-07  1:27 ` [PATCH v4 03/17] xfs: Embed struct xfs_name in xfs_da_args Allison Collins
@ 2019-11-07  1:27 ` Allison Collins
  2019-11-08 19:19   ` Darrick J. Wong
  2019-11-07  1:27 ` [PATCH v4 05/17] xfs: Add xfs_has_attr and subroutines Allison Collins
                   ` (12 subsequent siblings)
  16 siblings, 1 reply; 77+ messages in thread
From: Allison Collins @ 2019-11-07  1:27 UTC (permalink / raw)
  To: linux-xfs

This patch adds two new defines XFS_DABUF_MAP_NOMAPPING and
XFS_DABUF_MAP_HOLE_OK.  This helps to clean up hard numbers and
makes the code easier to read

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c       | 14 +++++++-----
 fs/xfs/libxfs/xfs_attr_leaf.c  | 23 +++++++++++--------
 fs/xfs/libxfs/xfs_attr_leaf.h  |  3 +++
 fs/xfs/libxfs/xfs_da_btree.c   | 50 ++++++++++++++++++++++++++++--------------
 fs/xfs/libxfs/xfs_dir2_block.c |  6 +++--
 fs/xfs/libxfs/xfs_dir2_data.c  |  3 ++-
 fs/xfs/libxfs/xfs_dir2_leaf.c  |  9 +++++---
 fs/xfs/libxfs/xfs_dir2_node.c  | 10 +++++----
 fs/xfs/scrub/dabtree.c         |  6 ++---
 fs/xfs/scrub/dir.c             |  4 +++-
 fs/xfs/xfs_attr_inactive.c     |  6 +++--
 fs/xfs/xfs_attr_list.c         | 16 +++++++++-----
 12 files changed, 97 insertions(+), 53 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index b77b985..5cb83a8 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -591,7 +591,8 @@ xfs_attr_leaf_addname(
 	 */
 	dp = args->dp;
 	args->blkno = 0;
-	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
+	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
+				    XFS_DABUF_MAP_NOMAPPING, &bp);
 	if (error)
 		return error;
 
@@ -717,7 +718,7 @@ xfs_attr_leaf_addname(
 		 * remove the "old" attr from that block (neat, huh!)
 		 */
 		error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
-					   -1, &bp);
+					   XFS_DABUF_MAP_NOMAPPING, &bp);
 		if (error)
 			return error;
 
@@ -771,7 +772,8 @@ xfs_attr_leaf_removename(
 	 */
 	dp = args->dp;
 	args->blkno = 0;
-	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
+	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
+				    XFS_DABUF_MAP_NOMAPPING, &bp);
 	if (error)
 		return error;
 
@@ -815,7 +817,8 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
 	trace_xfs_attr_leaf_get(args);
 
 	args->blkno = 0;
-	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
+	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
+				    XFS_DABUF_MAP_NOMAPPING, &bp);
 	if (error)
 		return error;
 
@@ -1175,7 +1178,8 @@ xfs_attr_node_removename(
 		ASSERT(state->path.blk[0].bp);
 		state->path.blk[0].bp = NULL;
 
-		error = xfs_attr3_leaf_read(args->trans, args->dp, 0, -1, &bp);
+		error = xfs_attr3_leaf_read(args->trans, args->dp, 0,
+					    XFS_DABUF_MAP_NOMAPPING, &bp);
 		if (error)
 			goto out;
 
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index cf5de30..93c3496 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -1160,11 +1160,13 @@ xfs_attr3_leaf_to_node(
 	error = xfs_da_grow_inode(args, &blkno);
 	if (error)
 		goto out;
-	error = xfs_attr3_leaf_read(args->trans, dp, 0, -1, &bp1);
+	error = xfs_attr3_leaf_read(args->trans, dp, 0, XFS_DABUF_MAP_NOMAPPING,
+				    &bp1);
 	if (error)
 		goto out;
 
-	error = xfs_da_get_buf(args->trans, dp, blkno, -1, &bp2, XFS_ATTR_FORK);
+	error = xfs_da_get_buf(args->trans, dp, blkno, XFS_DABUF_MAP_NOMAPPING,
+			       &bp2, XFS_ATTR_FORK);
 	if (error)
 		goto out;
 
@@ -1226,8 +1228,8 @@ xfs_attr3_leaf_create(
 
 	trace_xfs_attr_leaf_create(args);
 
-	error = xfs_da_get_buf(args->trans, args->dp, blkno, -1, &bp,
-					    XFS_ATTR_FORK);
+	error = xfs_da_get_buf(args->trans, args->dp, blkno,
+			       XFS_DABUF_MAP_NOMAPPING, &bp, XFS_ATTR_FORK);
 	if (error)
 		return error;
 	bp->b_ops = &xfs_attr3_leaf_buf_ops;
@@ -1997,7 +1999,7 @@ xfs_attr3_leaf_toosmall(
 		if (blkno == 0)
 			continue;
 		error = xfs_attr3_leaf_read(state->args->trans, state->args->dp,
-					blkno, -1, &bp);
+					blkno, XFS_DABUF_MAP_NOMAPPING, &bp);
 		if (error)
 			return error;
 
@@ -2730,7 +2732,8 @@ xfs_attr3_leaf_clearflag(
 	/*
 	 * Set up the operation.
 	 */
-	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
+	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
+				    XFS_DABUF_MAP_NOMAPPING, &bp);
 	if (error)
 		return error;
 
@@ -2797,7 +2800,8 @@ xfs_attr3_leaf_setflag(
 	/*
 	 * Set up the operation.
 	 */
-	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp);
+	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
+				    XFS_DABUF_MAP_NOMAPPING, &bp);
 	if (error)
 		return error;
 
@@ -2859,7 +2863,8 @@ xfs_attr3_leaf_flipflags(
 	/*
 	 * Read the block containing the "old" attr
 	 */
-	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno, -1, &bp1);
+	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
+				    XFS_DABUF_MAP_NOMAPPING, &bp1);
 	if (error)
 		return error;
 
@@ -2868,7 +2873,7 @@ xfs_attr3_leaf_flipflags(
 	 */
 	if (args->blkno2 != args->blkno) {
 		error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno2,
-					   -1, &bp2);
+					    XFS_DABUF_MAP_NOMAPPING, &bp2);
 		if (error)
 			return error;
 	} else {
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
index bb08800..017480e 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.h
+++ b/fs/xfs/libxfs/xfs_attr_leaf.h
@@ -16,6 +16,9 @@ struct xfs_da_state_blk;
 struct xfs_inode;
 struct xfs_trans;
 
+#define XFS_DABUF_MAP_NOMAPPING	(-1) /* Caller doesn't have a mapping. */
+#define XFS_DABUF_MAP_HOLE_OK	(-2) /* don't complain if we land in a hole. */
+
 /*
  * Used to keep a list of "remote value" extents when unlinking an inode.
  */
diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c
index 129ec09..ba49ffc 100644
--- a/fs/xfs/libxfs/xfs_da_btree.c
+++ b/fs/xfs/libxfs/xfs_da_btree.c
@@ -343,7 +343,8 @@ xfs_da3_node_create(
 	trace_xfs_da_node_create(args);
 	ASSERT(level <= XFS_DA_NODE_MAXDEPTH);
 
-	error = xfs_da_get_buf(tp, dp, blkno, -1, &bp, whichfork);
+	error = xfs_da_get_buf(tp, dp, blkno, XFS_DABUF_MAP_NOMAPPING, &bp,
+			       whichfork);
 	if (error)
 		return error;
 	bp->b_ops = &xfs_da3_node_buf_ops;
@@ -568,7 +569,8 @@ xfs_da3_root_split(
 
 	dp = args->dp;
 	tp = args->trans;
-	error = xfs_da_get_buf(tp, dp, blkno, -1, &bp, args->whichfork);
+	error = xfs_da_get_buf(tp, dp, blkno, XFS_DABUF_MAP_NOMAPPING, &bp,
+			       args->whichfork);
 	if (error)
 		return error;
 	node = bp->b_addr;
@@ -1109,8 +1111,9 @@ xfs_da3_root_join(
 	btree = dp->d_ops->node_tree_p(oldroot);
 	child = be32_to_cpu(btree[0].before);
 	ASSERT(child != 0);
-	error = xfs_da3_node_read(args->trans, dp, child, -1, &bp,
-					     args->whichfork);
+	error = xfs_da3_node_read(args->trans, dp, child,
+				  XFS_DABUF_MAP_NOMAPPING, &bp,
+				  args->whichfork);
 	if (error)
 		return error;
 	xfs_da_blkinfo_onlychild_validate(bp->b_addr, oldroothdr.level);
@@ -1225,7 +1228,8 @@ xfs_da3_node_toosmall(
 		if (blkno == 0)
 			continue;
 		error = xfs_da3_node_read(state->args->trans, dp,
-					blkno, -1, &bp, state->args->whichfork);
+					blkno, XFS_DABUF_MAP_NOMAPPING, &bp,
+					state->args->whichfork);
 		if (error)
 			return error;
 
@@ -1517,7 +1521,8 @@ xfs_da3_node_lookup_int(
 		 */
 		blk->blkno = blkno;
 		error = xfs_da3_node_read(args->trans, args->dp, blkno,
-					-1, &blk->bp, args->whichfork);
+					XFS_DABUF_MAP_NOMAPPING, &blk->bp,
+					args->whichfork);
 		if (error) {
 			blk->blkno = 0;
 			state->path.active--;
@@ -1746,7 +1751,8 @@ xfs_da3_blk_link(
 		if (old_info->back) {
 			error = xfs_da3_node_read(args->trans, dp,
 						be32_to_cpu(old_info->back),
-						-1, &bp, args->whichfork);
+						XFS_DABUF_MAP_NOMAPPING, &bp,
+						args->whichfork);
 			if (error)
 				return error;
 			ASSERT(bp != NULL);
@@ -1767,7 +1773,8 @@ xfs_da3_blk_link(
 		if (old_info->forw) {
 			error = xfs_da3_node_read(args->trans, dp,
 						be32_to_cpu(old_info->forw),
-						-1, &bp, args->whichfork);
+						XFS_DABUF_MAP_NOMAPPING, &bp,
+						args->whichfork);
 			if (error)
 				return error;
 			ASSERT(bp != NULL);
@@ -1826,7 +1833,8 @@ xfs_da3_blk_unlink(
 		if (drop_info->back) {
 			error = xfs_da3_node_read(args->trans, args->dp,
 						be32_to_cpu(drop_info->back),
-						-1, &bp, args->whichfork);
+						XFS_DABUF_MAP_NOMAPPING, &bp,
+						args->whichfork);
 			if (error)
 				return error;
 			ASSERT(bp != NULL);
@@ -1843,7 +1851,8 @@ xfs_da3_blk_unlink(
 		if (drop_info->forw) {
 			error = xfs_da3_node_read(args->trans, args->dp,
 						be32_to_cpu(drop_info->forw),
-						-1, &bp, args->whichfork);
+						XFS_DABUF_MAP_NOMAPPING, &bp,
+						args->whichfork);
 			if (error)
 				return error;
 			ASSERT(bp != NULL);
@@ -1929,7 +1938,8 @@ xfs_da3_path_shift(
 		/*
 		 * Read the next child block into a local buffer.
 		 */
-		error = xfs_da3_node_read(args->trans, dp, blkno, -1, &bp,
+		error = xfs_da3_node_read(args->trans, dp, blkno,
+					  XFS_DABUF_MAP_NOMAPPING, &bp,
 					  args->whichfork);
 		if (error)
 			return error;
@@ -2223,7 +2233,8 @@ xfs_da3_swap_lastblock(
 	 * Read the last block in the btree space.
 	 */
 	last_blkno = (xfs_dablk_t)lastoff - args->geo->fsbcount;
-	error = xfs_da3_node_read(tp, dp, last_blkno, -1, &last_buf, w);
+	error = xfs_da3_node_read(tp, dp, last_blkno, XFS_DABUF_MAP_NOMAPPING,
+				  &last_buf, w);
 	if (error)
 		return error;
 	/*
@@ -2259,7 +2270,8 @@ xfs_da3_swap_lastblock(
 	 * If the moved block has a left sibling, fix up the pointers.
 	 */
 	if ((sib_blkno = be32_to_cpu(dead_info->back))) {
-		error = xfs_da3_node_read(tp, dp, sib_blkno, -1, &sib_buf, w);
+		error = xfs_da3_node_read(tp, dp, sib_blkno,
+					  XFS_DABUF_MAP_NOMAPPING, &sib_buf, w);
 		if (error)
 			goto done;
 		sib_info = sib_buf->b_addr;
@@ -2281,7 +2293,8 @@ xfs_da3_swap_lastblock(
 	 * If the moved block has a right sibling, fix up the pointers.
 	 */
 	if ((sib_blkno = be32_to_cpu(dead_info->forw))) {
-		error = xfs_da3_node_read(tp, dp, sib_blkno, -1, &sib_buf, w);
+		error = xfs_da3_node_read(tp, dp, sib_blkno,
+					  XFS_DABUF_MAP_NOMAPPING, &sib_buf, w);
 		if (error)
 			goto done;
 		sib_info = sib_buf->b_addr;
@@ -2305,7 +2318,8 @@ xfs_da3_swap_lastblock(
 	 * Walk down the tree looking for the parent of the moved block.
 	 */
 	for (;;) {
-		error = xfs_da3_node_read(tp, dp, par_blkno, -1, &par_buf, w);
+		error = xfs_da3_node_read(tp, dp, par_blkno,
+					  XFS_DABUF_MAP_NOMAPPING, &par_buf, w);
 		if (error)
 			goto done;
 		par_node = par_buf->b_addr;
@@ -2356,7 +2370,8 @@ xfs_da3_swap_lastblock(
 			error = -EFSCORRUPTED;
 			goto done;
 		}
-		error = xfs_da3_node_read(tp, dp, par_blkno, -1, &par_buf, w);
+		error = xfs_da3_node_read(tp, dp, par_blkno,
+					  XFS_DABUF_MAP_NOMAPPING, &par_buf, w);
 		if (error)
 			goto done;
 		par_node = par_buf->b_addr;
@@ -2534,7 +2549,8 @@ xfs_dabuf_map(
 	 * Caller doesn't have a mapping.  -2 means don't complain
 	 * if we land in a hole.
 	 */
-	if (mappedbno == -1 || mappedbno == -2) {
+	if (mappedbno == XFS_DABUF_MAP_NOMAPPING ||
+	    mappedbno == XFS_DABUF_MAP_HOLE_OK) {
 		/*
 		 * Optimize the one-block case.
 		 */
diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
index 8dedc30..6bc7651 100644
--- a/fs/xfs/libxfs/xfs_dir2_block.c
+++ b/fs/xfs/libxfs/xfs_dir2_block.c
@@ -20,6 +20,7 @@
 #include "xfs_error.h"
 #include "xfs_trace.h"
 #include "xfs_log.h"
+#include "xfs_attr_leaf.h"
 
 /*
  * Local function prototypes.
@@ -123,8 +124,9 @@ xfs_dir3_block_read(
 	struct xfs_mount	*mp = dp->i_mount;
 	int			err;
 
-	err = xfs_da_read_buf(tp, dp, mp->m_dir_geo->datablk, -1, bpp,
-				XFS_DATA_FORK, &xfs_dir3_block_buf_ops);
+	err = xfs_da_read_buf(tp, dp, mp->m_dir_geo->datablk,
+			      XFS_DABUF_MAP_NOMAPPING, bpp, XFS_DATA_FORK,
+			      &xfs_dir3_block_buf_ops);
 	if (!err && tp && *bpp)
 		xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_BLOCK_BUF);
 	return err;
diff --git a/fs/xfs/libxfs/xfs_dir2_data.c b/fs/xfs/libxfs/xfs_dir2_data.c
index 2c79be4..a4188de 100644
--- a/fs/xfs/libxfs/xfs_dir2_data.c
+++ b/fs/xfs/libxfs/xfs_dir2_data.c
@@ -17,6 +17,7 @@
 #include "xfs_trans.h"
 #include "xfs_buf_item.h"
 #include "xfs_log.h"
+#include "xfs_attr_leaf.h"
 
 static xfs_failaddr_t xfs_dir2_data_freefind_verify(
 		struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_data_free *bf,
@@ -653,7 +654,7 @@ xfs_dir3_data_init(
 	 * Get the buffer set up for the block.
 	 */
 	error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, blkno),
-			       -1, &bp, XFS_DATA_FORK);
+			       XFS_DABUF_MAP_NOMAPPING, &bp, XFS_DATA_FORK);
 	if (error)
 		return error;
 	bp->b_ops = &xfs_dir3_data_buf_ops;
diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
index b7046e2..a2cba6bd 100644
--- a/fs/xfs/libxfs/xfs_dir2_leaf.c
+++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
@@ -19,6 +19,7 @@
 #include "xfs_trace.h"
 #include "xfs_trans.h"
 #include "xfs_buf_item.h"
+#include "xfs_attr_leaf.h"
 
 /*
  * Local function declarations.
@@ -311,7 +312,7 @@ xfs_dir3_leaf_get_buf(
 	       bno < xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET));
 
 	error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, bno),
-			       -1, &bp, XFS_DATA_FORK);
+			       XFS_DABUF_MAP_NOMAPPING, &bp, XFS_DATA_FORK);
 	if (error)
 		return error;
 
@@ -594,7 +595,8 @@ xfs_dir2_leaf_addname(
 
 	trace_xfs_dir2_leaf_addname(args);
 
-	error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, -1, &lbp);
+	error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk,
+				   XFS_DABUF_MAP_NOMAPPING, &lbp);
 	if (error)
 		return error;
 
@@ -1189,7 +1191,8 @@ xfs_dir2_leaf_lookup_int(
 	tp = args->trans;
 	mp = dp->i_mount;
 
-	error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, -1, &lbp);
+	error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk,
+				   XFS_DABUF_MAP_NOMAPPING, &lbp);
 	if (error)
 		return error;
 
diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
index 8bbd742..0a803e4 100644
--- a/fs/xfs/libxfs/xfs_dir2_node.c
+++ b/fs/xfs/libxfs/xfs_dir2_node.c
@@ -20,6 +20,7 @@
 #include "xfs_trans.h"
 #include "xfs_buf_item.h"
 #include "xfs_log.h"
+#include "xfs_attr_leaf.h"
 
 /*
  * Function declarations.
@@ -227,7 +228,7 @@ xfs_dir2_free_read(
 	xfs_dablk_t		fbno,
 	struct xfs_buf		**bpp)
 {
-	return __xfs_dir3_free_read(tp, dp, fbno, -1, bpp);
+	return __xfs_dir3_free_read(tp, dp, fbno, XFS_DABUF_MAP_NOMAPPING, bpp);
 }
 
 static int
@@ -237,7 +238,7 @@ xfs_dir2_free_try_read(
 	xfs_dablk_t		fbno,
 	struct xfs_buf		**bpp)
 {
-	return __xfs_dir3_free_read(tp, dp, fbno, -2, bpp);
+	return __xfs_dir3_free_read(tp, dp, fbno, XFS_DABUF_MAP_HOLE_OK, bpp);
 }
 
 static int
@@ -254,7 +255,7 @@ xfs_dir3_free_get_buf(
 	struct xfs_dir3_icfree_hdr hdr;
 
 	error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, fbno),
-				   -1, &bp, XFS_DATA_FORK);
+				   XFS_DABUF_MAP_NOMAPPING, &bp, XFS_DATA_FORK);
 	if (error)
 		return error;
 
@@ -1495,7 +1496,8 @@ xfs_dir2_leafn_toosmall(
 		 * Read the sibling leaf block.
 		 */
 		error = xfs_dir3_leafn_read(state->args->trans, dp,
-					    blkno, -1, &bp);
+					    blkno, XFS_DABUF_MAP_NOMAPPING,
+					    &bp);
 		if (error)
 			return error;
 
diff --git a/fs/xfs/scrub/dabtree.c b/fs/xfs/scrub/dabtree.c
index 77ff9f9..353455c 100644
--- a/fs/xfs/scrub/dabtree.c
+++ b/fs/xfs/scrub/dabtree.c
@@ -355,9 +355,9 @@ xchk_da_btree_block(
 		goto out_nobuf;
 
 	/* Read the buffer. */
-	error = xfs_da_read_buf(dargs->trans, dargs->dp, blk->blkno, -2,
-			&blk->bp, dargs->whichfork,
-			&xchk_da_btree_buf_ops);
+	error = xfs_da_read_buf(dargs->trans, dargs->dp, blk->blkno,
+				XFS_DABUF_MAP_HOLE_OK, &blk->bp,
+				dargs->whichfork, &xchk_da_btree_buf_ops);
 	if (!xchk_da_process_error(ds, level, &error))
 		goto out_nobuf;
 	if (blk->bp)
diff --git a/fs/xfs/scrub/dir.c b/fs/xfs/scrub/dir.c
index 1e2e117..eb0fa0f 100644
--- a/fs/xfs/scrub/dir.c
+++ b/fs/xfs/scrub/dir.c
@@ -18,6 +18,7 @@
 #include "scrub/scrub.h"
 #include "scrub/common.h"
 #include "scrub/dabtree.h"
+#include "xfs_attr_leaf.h"
 
 /* Set us up to scrub directories. */
 int
@@ -492,7 +493,8 @@ xchk_directory_leaf1_bestfree(
 	int				error;
 
 	/* Read the free space block. */
-	error = xfs_dir3_leaf_read(sc->tp, sc->ip, lblk, -1, &bp);
+	error = xfs_dir3_leaf_read(sc->tp, sc->ip, lblk,
+				   XFS_DABUF_MAP_NOMAPPING, &bp);
 	if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))
 		goto out;
 	xchk_buffer_recheck(sc, bp);
diff --git a/fs/xfs/xfs_attr_inactive.c b/fs/xfs/xfs_attr_inactive.c
index f83f11d..9c22915 100644
--- a/fs/xfs/xfs_attr_inactive.c
+++ b/fs/xfs/xfs_attr_inactive.c
@@ -235,7 +235,8 @@ xfs_attr3_node_inactive(
 		 * traversal of the tree so we may deal with many blocks
 		 * before we come back to this one.
 		 */
-		error = xfs_da3_node_read(*trans, dp, child_fsb, -1, &child_bp,
+		error = xfs_da3_node_read(*trans, dp, child_fsb,
+					  XFS_DABUF_MAP_NOMAPPING, &child_bp,
 					  XFS_ATTR_FORK);
 		if (error)
 			return error;
@@ -321,7 +322,8 @@ xfs_attr3_root_inactive(
 	 * the extents in reverse order the extent containing
 	 * block 0 must still be there.
 	 */
-	error = xfs_da3_node_read(*trans, dp, 0, -1, &bp, XFS_ATTR_FORK);
+	error = xfs_da3_node_read(*trans, dp, 0, XFS_DABUF_MAP_NOMAPPING, &bp,
+				  XFS_ATTR_FORK);
 	if (error)
 		return error;
 	blkno = bp->b_bn;
diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
index c02f22d..fab416c 100644
--- a/fs/xfs/xfs_attr_list.c
+++ b/fs/xfs/xfs_attr_list.c
@@ -224,8 +224,9 @@ xfs_attr_node_list_lookup(
 	ASSERT(*pbp == NULL);
 	cursor->blkno = 0;
 	for (;;) {
-		error = xfs_da3_node_read(tp, dp, cursor->blkno, -1, &bp,
-				XFS_ATTR_FORK);
+		error = xfs_da3_node_read(tp, dp, cursor->blkno,
+					  XFS_DABUF_MAP_NOMAPPING, &bp,
+					  XFS_ATTR_FORK);
 		if (error)
 			return error;
 		node = bp->b_addr;
@@ -309,8 +310,9 @@ xfs_attr_node_list(
 	 */
 	bp = NULL;
 	if (cursor->blkno > 0) {
-		error = xfs_da3_node_read(context->tp, dp, cursor->blkno, -1,
-					      &bp, XFS_ATTR_FORK);
+		error = xfs_da3_node_read(context->tp, dp, cursor->blkno,
+					  XFS_DABUF_MAP_NOMAPPING, &bp,
+					  XFS_ATTR_FORK);
 		if ((error != 0) && (error != -EFSCORRUPTED))
 			return error;
 		if (bp) {
@@ -377,7 +379,8 @@ xfs_attr_node_list(
 			break;
 		cursor->blkno = leafhdr.forw;
 		xfs_trans_brelse(context->tp, bp);
-		error = xfs_attr3_leaf_read(context->tp, dp, cursor->blkno, -1, &bp);
+		error = xfs_attr3_leaf_read(context->tp, dp, cursor->blkno,
+					    XFS_DABUF_MAP_NOMAPPING, &bp);
 		if (error)
 			return error;
 	}
@@ -497,7 +500,8 @@ xfs_attr_leaf_list(xfs_attr_list_context_t *context)
 	trace_xfs_attr_leaf_list(context);
 
 	context->cursor->blkno = 0;
-	error = xfs_attr3_leaf_read(context->tp, context->dp, 0, -1, &bp);
+	error = xfs_attr3_leaf_read(context->tp, context->dp, 0,
+				    XFS_DABUF_MAP_NOMAPPING, &bp);
 	if (error)
 		return error;
 
-- 
2.7.4


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

* [PATCH v4 05/17] xfs: Add xfs_has_attr and subroutines
  2019-11-07  1:27 [PATCH v4 00/17] xfs: Delay Ready Attributes Allison Collins
                   ` (3 preceding siblings ...)
  2019-11-07  1:27 ` [PATCH v4 04/17] xfs: Add xfs_dabuf defines Allison Collins
@ 2019-11-07  1:27 ` Allison Collins
  2019-11-08 19:32   ` Darrick J. Wong
                     ` (2 more replies)
  2019-11-07  1:27 ` [PATCH v4 06/17] xfs: Factor out new helper functions xfs_attr_rmtval_set Allison Collins
                   ` (11 subsequent siblings)
  16 siblings, 3 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-07  1:27 UTC (permalink / raw)
  To: linux-xfs

From: Allison Henderson <allison.henderson@oracle.com>

This patch adds a new functions to check for the existence of
an attribute.  Subroutines are also added to handle the cases
of leaf blocks, nodes or shortform.  Common code that appears
in existing attr add and remove functions have been factored
out to help reduce the appearence of duplicated code.  We will
need these routines later for delayed attributes since delayed
operations cannot return error codes.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c      | 154 +++++++++++++++++++++++++++---------------
 fs/xfs/libxfs/xfs_attr.h      |   1 +
 fs/xfs/libxfs/xfs_attr_leaf.c | 107 ++++++++++++++++++-----------
 fs/xfs/libxfs/xfs_attr_leaf.h |   2 +
 4 files changed, 171 insertions(+), 93 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 5cb83a8..c8a3273 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -46,6 +46,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
 STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
 STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
 STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
+STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
 
 /*
  * Internal routines when attribute list is more than one block.
@@ -53,6 +54,8 @@ STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
 STATIC int xfs_attr_node_get(xfs_da_args_t *args);
 STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
 STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
+STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
+				 struct xfs_da_state **state);
 STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
 STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
 
@@ -310,6 +313,34 @@ xfs_attr_set_args(
 }
 
 /*
+ * Return EEXIST if attr is found, or ENOATTR if not
+ */
+int
+xfs_has_attr(
+	struct xfs_da_args      *args)
+{
+	struct xfs_inode        *dp = args->dp;
+	struct xfs_buf		*bp;
+	int                     error;
+
+	if (!xfs_inode_hasattr(dp)) {
+		error = -ENOATTR;
+	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
+		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
+		error = xfs_attr_shortform_hasname(args, NULL, NULL);
+	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
+		error = xfs_attr_leaf_hasname(args, &bp);
+		if (error != -ENOATTR && error != -EEXIST)
+			goto out;
+		xfs_trans_brelse(args->trans, bp);
+	} else {
+		error = xfs_attr_node_hasname(args, NULL);
+	}
+out:
+	return error;
+}
+
+/*
  * Remove the attribute specified in @args.
  */
 int
@@ -580,27 +611,20 @@ STATIC int
 xfs_attr_leaf_addname(
 	struct xfs_da_args	*args)
 {
-	struct xfs_inode	*dp;
 	struct xfs_buf		*bp;
 	int			retval, error, forkoff;
+	struct xfs_inode	*dp = args->dp;
 
 	trace_xfs_attr_leaf_addname(args);
 
 	/*
-	 * Read the (only) block in the attribute list in.
-	 */
-	dp = args->dp;
-	args->blkno = 0;
-	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
-				    XFS_DABUF_MAP_NOMAPPING, &bp);
-	if (error)
-		return error;
-
-	/*
 	 * Look up the given attribute in the leaf block.  Figure out if
 	 * the given flags produce an error or call for an atomic rename.
 	 */
-	retval = xfs_attr3_leaf_lookup_int(bp, args);
+	retval = xfs_attr_leaf_hasname(args, &bp);
+	if (retval != -ENOATTR && retval != -EEXIST)
+		return retval;
+
 	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
 		xfs_trans_brelse(args->trans, bp);
 		return retval;
@@ -752,6 +776,24 @@ xfs_attr_leaf_addname(
 }
 
 /*
+ * Return EEXIST if attr is found, or ENOATTR if not
+ */
+STATIC int
+xfs_attr_leaf_hasname(
+	struct xfs_da_args      *args,
+	struct xfs_buf		**bp)
+{
+	int                     error = 0;
+
+	error = xfs_attr3_leaf_read(args->trans, args->dp, 0,
+				    XFS_DABUF_MAP_NOMAPPING, bp);
+	if (error)
+		return error;
+
+	return xfs_attr3_leaf_lookup_int(*bp, args);
+}
+
+/*
  * Remove a name from the leaf attribute list structure
  *
  * This leaf block cannot have a "remote" value, we only call this routine
@@ -771,13 +813,11 @@ xfs_attr_leaf_removename(
 	 * Remove the attribute.
 	 */
 	dp = args->dp;
-	args->blkno = 0;
-	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
-				    XFS_DABUF_MAP_NOMAPPING, &bp);
-	if (error)
+
+	error = xfs_attr_leaf_hasname(args, &bp);
+	if (error != -ENOATTR && error != -EEXIST)
 		return error;
 
-	error = xfs_attr3_leaf_lookup_int(bp, args);
 	if (error == -ENOATTR) {
 		xfs_trans_brelse(args->trans, bp);
 		return error;
@@ -816,13 +856,10 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
 
 	trace_xfs_attr_leaf_get(args);
 
-	args->blkno = 0;
-	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
-				    XFS_DABUF_MAP_NOMAPPING, &bp);
-	if (error)
+	error = xfs_attr_leaf_hasname(args, &bp);
+	if (error != -ENOATTR && error != -EEXIST)
 		return error;
 
-	error = xfs_attr3_leaf_lookup_int(bp, args);
 	if (error != -EEXIST)  {
 		xfs_trans_brelse(args->trans, bp);
 		return error;
@@ -832,6 +869,38 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
 	return error;
 }
 
+/*
+ * Return EEXIST if attr is found, or ENOATTR if not
+ * statep: If not null is set to point at the found state.  Caller will
+ * 	   be responsible for freeing the state in this case.
+ */
+STATIC int
+xfs_attr_node_hasname(
+	struct xfs_da_args	*args,
+	struct xfs_da_state	**statep)
+{
+	struct xfs_da_state	*state;
+	int			retval, error;
+
+	state = xfs_da_state_alloc();
+	state->args = args;
+	state->mp = args->dp->i_mount;
+
+	/*
+	 * Search to see if name exists, and get back a pointer to it.
+	 */
+	error = xfs_da3_node_lookup_int(state, &retval);
+	if (error == 0)
+		error = retval;
+
+	if (statep != NULL)
+		*statep = state;
+	else
+		xfs_da_state_free(state);
+
+	return error;
+}
+
 /*========================================================================
  * External routines when attribute list size > geo->blksize
  *========================================================================*/
@@ -864,20 +933,17 @@ xfs_attr_node_addname(
 	dp = args->dp;
 	mp = dp->i_mount;
 restart:
-	state = xfs_da_state_alloc();
-	state->args = args;
-	state->mp = mp;
-
 	/*
 	 * Search to see if name already exists, and get back a pointer
 	 * to where it should go.
 	 */
-	error = xfs_da3_node_lookup_int(state, &retval);
-	if (error)
+	retval = xfs_attr_node_hasname(args, &state);
+	if (retval != -ENOATTR)
 		goto out;
+
 	blk = &state->path.blk[ state->path.active-1 ];
 	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
-	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
+	if (args->name.type & ATTR_REPLACE) {
 		goto out;
 	} else if (retval == -EEXIST) {
 		if (args->name.type & ATTR_CREATE)
@@ -1079,29 +1145,15 @@ xfs_attr_node_removename(
 {
 	struct xfs_da_state	*state;
 	struct xfs_da_state_blk	*blk;
-	struct xfs_inode	*dp;
 	struct xfs_buf		*bp;
 	int			retval, error, forkoff;
+	struct xfs_inode	*dp = args->dp;
 
 	trace_xfs_attr_node_removename(args);
 
-	/*
-	 * Tie a string around our finger to remind us where we are.
-	 */
-	dp = args->dp;
-	state = xfs_da_state_alloc();
-	state->args = args;
-	state->mp = dp->i_mount;
-
-	/*
-	 * Search to see if name exists, and get back a pointer to it.
-	 */
-	error = xfs_da3_node_lookup_int(state, &retval);
-	if (error || (retval != -EEXIST)) {
-		if (error == 0)
-			error = retval;
+	error = xfs_attr_node_hasname(args, &state);
+	if (error != -EEXIST)
 		goto out;
-	}
 
 	/*
 	 * If there is an out-of-line value, de-allocate the blocks.
@@ -1324,20 +1376,14 @@ xfs_attr_node_get(xfs_da_args_t *args)
 
 	trace_xfs_attr_node_get(args);
 
-	state = xfs_da_state_alloc();
-	state->args = args;
-	state->mp = args->dp->i_mount;
-
 	/*
 	 * Search to see if name exists, and get back a pointer to it.
 	 */
-	error = xfs_da3_node_lookup_int(state, &retval);
-	if (error) {
+	error = xfs_attr_node_hasname(args, &state);
+	if (error != -EEXIST) {
 		retval = error;
 		goto out_release;
 	}
-	if (retval != -EEXIST)
-		goto out_release;
 
 	/*
 	 * Get the value, local or "remote"
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index 44dd07a..3b5dad4 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -150,6 +150,7 @@ int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
 		 unsigned char *value, int valuelen, int flags);
 int xfs_attr_set_args(struct xfs_da_args *args);
 int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
+int xfs_has_attr(struct xfs_da_args *args);
 int xfs_attr_remove_args(struct xfs_da_args *args);
 int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
 		  int flags, struct attrlist_cursor_kern *cursor);
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index 93c3496..d06cfd6 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -655,18 +655,67 @@ xfs_attr_shortform_create(xfs_da_args_t *args)
 }
 
 /*
+ * Return -EEXIST if attr is found, or -ENOATTR if not
+ * args:  args containing attribute name and namelen
+ * sfep:  If not null, pointer will be set to the last attr entry found on
+	  -EEXIST.  On -ENOATTR pointer is left at the last entry in the list
+ * basep: If not null, pointer is set to the byte offset of the entry in the
+ *	  list on -EEXIST.  On -ENOATTR, pointer is left at the byte offset of
+ *	  the last entry in the list
+ */
+int
+xfs_attr_shortform_hasname(
+	struct xfs_da_args	 *args,
+	struct xfs_attr_sf_entry **sfep,
+	int			 *basep)
+{
+	struct xfs_attr_shortform *sf;
+	struct xfs_attr_sf_entry *sfe;
+	int			base = sizeof(struct xfs_attr_sf_hdr);
+	int			size = 0;
+	int			end;
+	int			i;
+
+	base = sizeof(struct xfs_attr_sf_hdr);
+	sf = (struct xfs_attr_shortform *)args->dp->i_afp->if_u1.if_data;
+	sfe = &sf->list[0];
+	end = sf->hdr.count;
+	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
+			base += size, i++) {
+		size = XFS_ATTR_SF_ENTSIZE(sfe);
+		if (sfe->namelen != args->name.len)
+			continue;
+		if (memcmp(sfe->nameval, args->name.name, args->name.len) != 0)
+			continue;
+		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
+			continue;
+		break;
+	}
+
+	if (sfep != NULL)
+		*sfep = sfe;
+
+	if (basep != NULL)
+		*basep = base;
+
+	if (i == end)
+		return -ENOATTR;
+	return -EEXIST;
+}
+
+/*
  * Add a name/value pair to the shortform attribute list.
  * Overflow from the inode has already been checked for.
  */
 void
 xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
 {
-	xfs_attr_shortform_t *sf;
-	xfs_attr_sf_entry_t *sfe;
-	int i, offset, size;
-	xfs_mount_t *mp;
-	xfs_inode_t *dp;
-	struct xfs_ifork *ifp;
+	struct xfs_attr_shortform	*sf;
+	struct xfs_attr_sf_entry	*sfe;
+	int				offset, size, error;
+	struct xfs_mount		*mp;
+	struct xfs_inode		*dp;
+	struct xfs_ifork		*ifp;
 
 	trace_xfs_attr_sf_add(args);
 
@@ -677,18 +726,8 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
 	ifp = dp->i_afp;
 	ASSERT(ifp->if_flags & XFS_IFINLINE);
 	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
-	sfe = &sf->list[0];
-	for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
-#ifdef DEBUG
-		if (sfe->namelen != args->name.len)
-			continue;
-		if (memcmp(args->name.name, sfe->nameval, args->name.len) != 0)
-			continue;
-		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
-			continue;
-		ASSERT(0);
-#endif
-	}
+	error = xfs_attr_shortform_hasname(args, &sfe, NULL);
+	ASSERT(error != -EEXIST);
 
 	offset = (char *)sfe - (char *)sf;
 	size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
@@ -733,33 +772,23 @@ xfs_attr_fork_remove(
 int
 xfs_attr_shortform_remove(xfs_da_args_t *args)
 {
-	xfs_attr_shortform_t *sf;
-	xfs_attr_sf_entry_t *sfe;
-	int base, size=0, end, totsize, i;
-	xfs_mount_t *mp;
-	xfs_inode_t *dp;
+	struct xfs_attr_shortform	*sf;
+	struct xfs_attr_sf_entry	*sfe;
+	int				base, size = 0, end, totsize;
+	struct xfs_mount		*mp;
+	struct xfs_inode		*dp;
+	int				error;
 
 	trace_xfs_attr_sf_remove(args);
 
 	dp = args->dp;
 	mp = dp->i_mount;
-	base = sizeof(xfs_attr_sf_hdr_t);
 	sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
-	sfe = &sf->list[0];
-	end = sf->hdr.count;
-	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
-					base += size, i++) {
-		size = XFS_ATTR_SF_ENTSIZE(sfe);
-		if (sfe->namelen != args->name.len)
-			continue;
-		if (memcmp(sfe->nameval, args->name.name, args->name.len) != 0)
-			continue;
-		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
-			continue;
-		break;
-	}
-	if (i == end)
-		return -ENOATTR;
+
+	error = xfs_attr_shortform_hasname(args, &sfe, &base);
+	if (error != -EEXIST)
+		return error;
+	size = XFS_ATTR_SF_ENTSIZE(sfe);
 
 	/*
 	 * Fix up the attribute fork data, covering the hole
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
index 017480e..e108b37 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.h
+++ b/fs/xfs/libxfs/xfs_attr_leaf.h
@@ -42,6 +42,8 @@ int	xfs_attr_shortform_getvalue(struct xfs_da_args *args);
 int	xfs_attr_shortform_to_leaf(struct xfs_da_args *args,
 			struct xfs_buf **leaf_bp);
 int	xfs_attr_shortform_remove(struct xfs_da_args *args);
+int	xfs_attr_shortform_hasname(struct xfs_da_args *args,
+			       struct xfs_attr_sf_entry **sfep, int *basep);
 int	xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp);
 int	xfs_attr_shortform_bytesfit(struct xfs_inode *dp, int bytes);
 xfs_failaddr_t xfs_attr_shortform_verify(struct xfs_inode *ip);
-- 
2.7.4


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

* [PATCH v4 06/17] xfs: Factor out new helper functions xfs_attr_rmtval_set
  2019-11-07  1:27 [PATCH v4 00/17] xfs: Delay Ready Attributes Allison Collins
                   ` (4 preceding siblings ...)
  2019-11-07  1:27 ` [PATCH v4 05/17] xfs: Add xfs_has_attr and subroutines Allison Collins
@ 2019-11-07  1:27 ` Allison Collins
  2019-11-08 19:34   ` Darrick J. Wong
  2019-11-07  1:27 ` [PATCH v4 07/17] xfs: Factor up trans handling in xfs_attr3_leaf_flipflags Allison Collins
                   ` (10 subsequent siblings)
  16 siblings, 1 reply; 77+ messages in thread
From: Allison Collins @ 2019-11-07  1:27 UTC (permalink / raw)
  To: linux-xfs

Break xfs_attr_rmtval_set into two helper functions
xfs_attr_rmt_find_hole and xfs_attr_rmtval_set_value.
xfs_attr_rmtval_set rolls the transaction between the
helpers, but delayed operations cannot.  We will use
the helpers later when constructing new delayed
attribute routines.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
---
 fs/xfs/libxfs/xfs_attr_remote.c | 71 +++++++++++++++++++++++++++++++----------
 fs/xfs/libxfs/xfs_attr_remote.h |  3 +-
 2 files changed, 56 insertions(+), 18 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
index db9247a..db51388 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.c
+++ b/fs/xfs/libxfs/xfs_attr_remote.c
@@ -21,6 +21,7 @@
 #include "xfs_attr.h"
 #include "xfs_trace.h"
 #include "xfs_error.h"
+#include "xfs_attr_remote.h"
 
 #define ATTR_RMTVALUE_MAPSIZE	1	/* # of map entries at once */
 
@@ -432,34 +433,20 @@ xfs_attr_rmtval_set(
 	struct xfs_da_args	*args)
 {
 	struct xfs_inode	*dp = args->dp;
-	struct xfs_mount	*mp = dp->i_mount;
 	struct xfs_bmbt_irec	map;
 	xfs_dablk_t		lblkno;
-	xfs_fileoff_t		lfileoff = 0;
-	uint8_t			*src = args->value;
 	int			blkcnt;
-	int			valuelen;
 	int			nmap;
 	int			error;
-	int			offset = 0;
 
 	trace_xfs_attr_rmtval_set(args);
 
-	/*
-	 * Find a "hole" in the attribute address space large enough for
-	 * us to drop the new attribute's value into. Because CRC enable
-	 * attributes have headers, we can't just do a straight byte to FSB
-	 * conversion and have to take the header space into account.
-	 */
-	blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
-	error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
-						   XFS_ATTR_FORK);
+	error = xfs_attr_rmt_find_hole(args);
 	if (error)
 		return error;
 
-	args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff;
-	args->rmtblkcnt = blkcnt;
-
+	blkcnt = args->rmtblkcnt;
+	lblkno = (xfs_dablk_t)args->rmtblkno;
 	/*
 	 * Roll through the "value", allocating blocks on disk as required.
 	 */
@@ -500,6 +487,56 @@ xfs_attr_rmtval_set(
 			return error;
 	}
 
+	return xfs_attr_rmtval_set_value(args);
+}
+
+
+/*
+ * Find a "hole" in the attribute address space large enough for us to drop the
+ * new attribute's value into
+ */
+int
+xfs_attr_rmt_find_hole(
+	struct xfs_da_args	*args)
+{
+	struct xfs_inode        *dp = args->dp;
+	struct xfs_mount	*mp = dp->i_mount;
+	int			error;
+	int			blkcnt;
+	xfs_fileoff_t		lfileoff = 0;
+
+	/*
+	 * Because CRC enable attributes have headers, we can't just do a
+	 * straight byte to FSB conversion and have to take the header space
+	 * into account.
+	 */
+	blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
+	error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
+						   XFS_ATTR_FORK);
+	if (error)
+		return error;
+
+	args->rmtblkno = (xfs_dablk_t)lfileoff;
+	args->rmtblkcnt = blkcnt;
+
+	return 0;
+}
+
+int
+xfs_attr_rmtval_set_value(
+	struct xfs_da_args	*args)
+{
+	struct xfs_inode	*dp = args->dp;
+	struct xfs_mount	*mp = dp->i_mount;
+	struct xfs_bmbt_irec	map;
+	xfs_dablk_t		lblkno;
+	uint8_t			*src = args->value;
+	int			blkcnt;
+	int			valuelen;
+	int			nmap;
+	int			error;
+	int			offset = 0;
+
 	/*
 	 * Roll through the "value", copying the attribute value to the
 	 * already-allocated blocks.  Blocks are written synchronously
diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
index 9d20b66..cd7670d 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.h
+++ b/fs/xfs/libxfs/xfs_attr_remote.h
@@ -11,5 +11,6 @@ int xfs_attr3_rmt_blocks(struct xfs_mount *mp, int attrlen);
 int xfs_attr_rmtval_get(struct xfs_da_args *args);
 int xfs_attr_rmtval_set(struct xfs_da_args *args);
 int xfs_attr_rmtval_remove(struct xfs_da_args *args);
-
+int xfs_attr_rmtval_set_value(struct xfs_da_args *args);
+int xfs_attr_rmt_find_hole(struct xfs_da_args *args);
 #endif /* __XFS_ATTR_REMOTE_H__ */
-- 
2.7.4


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

* [PATCH v4 07/17] xfs: Factor up trans handling in xfs_attr3_leaf_flipflags
  2019-11-07  1:27 [PATCH v4 00/17] xfs: Delay Ready Attributes Allison Collins
                   ` (5 preceding siblings ...)
  2019-11-07  1:27 ` [PATCH v4 06/17] xfs: Factor out new helper functions xfs_attr_rmtval_set Allison Collins
@ 2019-11-07  1:27 ` Allison Collins
  2019-11-08 19:35   ` Darrick J. Wong
  2019-11-07  1:27 ` [PATCH v4 08/17] xfs: Factor out xfs_attr_leaf_addname helper Allison Collins
                   ` (9 subsequent siblings)
  16 siblings, 1 reply; 77+ messages in thread
From: Allison Collins @ 2019-11-07  1:27 UTC (permalink / raw)
  To: linux-xfs

Since delayed operations cannot roll transactions, factor
up the transaction handling into the calling function

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
---
 fs/xfs/libxfs/xfs_attr.c      | 14 ++++++++++++++
 fs/xfs/libxfs/xfs_attr_leaf.c |  5 -----
 2 files changed, 14 insertions(+), 5 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index c8a3273..212995f 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -721,6 +721,13 @@ xfs_attr_leaf_addname(
 		error = xfs_attr3_leaf_flipflags(args);
 		if (error)
 			return error;
+		/*
+		 * Commit the flag value change and start the next trans in
+		 * series.
+		 */
+		error = xfs_trans_roll_inode(&args->trans, args->dp);
+		if (error)
+			return error;
 
 		/*
 		 * Dismantle the "old" attribute/value pair by removing
@@ -1057,6 +1064,13 @@ xfs_attr_node_addname(
 		error = xfs_attr3_leaf_flipflags(args);
 		if (error)
 			goto out;
+		/*
+		 * Commit the flag value change and start the next trans in
+		 * series
+		 */
+		error = xfs_trans_roll_inode(&args->trans, args->dp);
+		if (error)
+			goto out;
 
 		/*
 		 * Dismantle the "old" attribute/value pair by removing
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index d06cfd6..134eb00 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -2973,10 +2973,5 @@ xfs_attr3_leaf_flipflags(
 			 XFS_DA_LOGRANGE(leaf2, name_rmt, sizeof(*name_rmt)));
 	}
 
-	/*
-	 * Commit the flag value change and start the next trans in series.
-	 */
-	error = xfs_trans_roll_inode(&args->trans, args->dp);
-
 	return error;
 }
-- 
2.7.4


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

* [PATCH v4 08/17] xfs: Factor out xfs_attr_leaf_addname helper
  2019-11-07  1:27 [PATCH v4 00/17] xfs: Delay Ready Attributes Allison Collins
                   ` (6 preceding siblings ...)
  2019-11-07  1:27 ` [PATCH v4 07/17] xfs: Factor up trans handling in xfs_attr3_leaf_flipflags Allison Collins
@ 2019-11-07  1:27 ` Allison Collins
  2019-11-08 20:57   ` Darrick J. Wong
  2019-11-07  1:27 ` [PATCH v4 09/17] xfs: Factor up commit from xfs_attr_try_sf_addname Allison Collins
                   ` (8 subsequent siblings)
  16 siblings, 1 reply; 77+ messages in thread
From: Allison Collins @ 2019-11-07  1:27 UTC (permalink / raw)
  To: linux-xfs

Factor out new helper function xfs_attr_leaf_try_add.
Because new delayed attribute routines cannot roll
transactions, we carve off the parts of
xfs_attr_leaf_addname that we can use.  This will help
to reduce repetitive code later when we introduce
delayed attributes.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c | 84 +++++++++++++++++++++++++++++-------------------
 1 file changed, 51 insertions(+), 33 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 212995f..dda2eba 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -305,10 +305,33 @@ xfs_attr_set_args(
 		}
 	}
 
-	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
+	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
 		error = xfs_attr_leaf_addname(args);
-	else
+		if (error == -ENOSPC) {
+			/*
+			 * Commit that transaction so that the node_addname()
+			 * call can manage its own transactions.
+			 */
+			error = xfs_defer_finish(&args->trans);
+			if (error)
+				return error;
+
+			/*
+			 * Commit the current trans (including the inode) and
+			 * start a new one.
+			 */
+			error = xfs_trans_roll_inode(&args->trans, dp);
+			if (error)
+				return error;
+
+			/*
+			 * Fob the rest of the problem off on the Btree code.
+			 */
+			error = xfs_attr_node_addname(args);
+		}
+	} else {
 		error = xfs_attr_node_addname(args);
+	}
 	return error;
 }
 
@@ -601,21 +624,12 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
  * External routines when attribute list is one block
  *========================================================================*/
 
-/*
- * Add a name to the leaf attribute list structure
- *
- * This leaf block cannot have a "remote" value, we only call this routine
- * if bmap_one_block() says there is only one block (ie: no remote blks).
- */
 STATIC int
-xfs_attr_leaf_addname(
-	struct xfs_da_args	*args)
+xfs_attr_leaf_try_add(
+	struct xfs_da_args	*args,
+	struct xfs_buf		*bp)
 {
-	struct xfs_buf		*bp;
-	int			retval, error, forkoff;
-	struct xfs_inode	*dp = args->dp;
-
-	trace_xfs_attr_leaf_addname(args);
+	int			retval, error;
 
 	/*
 	 * Look up the given attribute in the leaf block.  Figure out if
@@ -661,31 +675,35 @@ xfs_attr_leaf_addname(
 	retval = xfs_attr3_leaf_add(bp, args);
 	if (retval == -ENOSPC) {
 		/*
-		 * Promote the attribute list to the Btree format, then
-		 * Commit that transaction so that the node_addname() call
-		 * can manage its own transactions.
+		 * Promote the attribute list to the Btree format.
+		 * Unless an error occurs, retain the -ENOSPC retval
 		 */
 		error = xfs_attr3_leaf_to_node(args);
 		if (error)
 			return error;
-		error = xfs_defer_finish(&args->trans);
-		if (error)
-			return error;
+	}
+	return retval;
+}
 
-		/*
-		 * Commit the current trans (including the inode) and start
-		 * a new one.
-		 */
-		error = xfs_trans_roll_inode(&args->trans, dp);
-		if (error)
-			return error;
 
-		/*
-		 * Fob the whole rest of the problem off on the Btree code.
-		 */
-		error = xfs_attr_node_addname(args);
+/*
+ * Add a name to the leaf attribute list structure
+ *
+ * This leaf block cannot have a "remote" value, we only call this routine
+ * if bmap_one_block() says there is only one block (ie: no remote blks).
+ */
+STATIC int
+xfs_attr_leaf_addname(struct xfs_da_args	*args)
+{
+	int			error, forkoff;
+	struct xfs_buf		*bp = NULL;
+	struct xfs_inode	*dp = args->dp;
+
+	trace_xfs_attr_leaf_addname(args);
+
+	error = xfs_attr_leaf_try_add(args, bp);
+	if (error)
 		return error;
-	}
 
 	/*
 	 * Commit the transaction that added the attr name so that
-- 
2.7.4


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

* [PATCH v4 09/17] xfs: Factor up commit from xfs_attr_try_sf_addname
  2019-11-07  1:27 [PATCH v4 00/17] xfs: Delay Ready Attributes Allison Collins
                   ` (7 preceding siblings ...)
  2019-11-07  1:27 ` [PATCH v4 08/17] xfs: Factor out xfs_attr_leaf_addname helper Allison Collins
@ 2019-11-07  1:27 ` Allison Collins
  2019-11-08 21:04   ` Darrick J. Wong
  2019-11-07  1:27 ` [PATCH v4 10/17] xfs: Factor up trans roll from xfs_attr3_leaf_setflag Allison Collins
                   ` (7 subsequent siblings)
  16 siblings, 1 reply; 77+ messages in thread
From: Allison Collins @ 2019-11-07  1:27 UTC (permalink / raw)
  To: linux-xfs

New delayed attribute routines cannot handle transactions,
so factor this up to the calling function.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c | 23 ++++++++++++-----------
 1 file changed, 12 insertions(+), 11 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index dda2eba..e0a38a2 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -227,8 +227,7 @@ xfs_attr_try_sf_addname(
 	struct xfs_da_args	*args)
 {
 
-	struct xfs_mount	*mp = dp->i_mount;
-	int			error, error2;
+	int			error;
 
 	error = xfs_attr_shortform_addname(args);
 	if (error == -ENOSPC)
@@ -241,12 +240,7 @@ xfs_attr_try_sf_addname(
 	if (!error && (args->name.type & ATTR_KERNOTIME) == 0)
 		xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
 
-	if (mp->m_flags & XFS_MOUNT_WSYNC)
-		xfs_trans_set_sync(args->trans);
-
-	error2 = xfs_trans_commit(args->trans);
-	args->trans = NULL;
-	return error ? error : error2;
+	return error;
 }
 
 /*
@@ -258,7 +252,7 @@ xfs_attr_set_args(
 {
 	struct xfs_inode	*dp = args->dp;
 	struct xfs_buf          *leaf_bp = NULL;
-	int			error;
+	int			error, error2 = 0;;
 
 	/*
 	 * If the attribute list is non-existent or a shortform list,
@@ -278,8 +272,15 @@ xfs_attr_set_args(
 		 * Try to add the attr to the attribute list in the inode.
 		 */
 		error = xfs_attr_try_sf_addname(dp, args);
-		if (error != -ENOSPC)
-			return error;
+		if (error != -ENOSPC) {
+			if (dp->i_mount->m_flags & XFS_MOUNT_WSYNC)
+				xfs_trans_set_sync(args->trans);
+
+			error2 = xfs_trans_commit(args->trans);
+			args->trans = NULL;
+			return error ? error : error2;
+		}
+
 
 		/*
 		 * It won't fit in the shortform, transform to a leaf block.
-- 
2.7.4


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

* [PATCH v4 10/17] xfs: Factor up trans roll from xfs_attr3_leaf_setflag
  2019-11-07  1:27 [PATCH v4 00/17] xfs: Delay Ready Attributes Allison Collins
                   ` (8 preceding siblings ...)
  2019-11-07  1:27 ` [PATCH v4 09/17] xfs: Factor up commit from xfs_attr_try_sf_addname Allison Collins
@ 2019-11-07  1:27 ` Allison Collins
  2019-11-07  1:27 ` [PATCH v4 11/17] xfs: Add xfs_attr3_leaf helper functions Allison Collins
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-07  1:27 UTC (permalink / raw)
  To: linux-xfs

New delayed allocation routines cannot be handling
transactions so factor them up into the calling functions

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
---
 fs/xfs/libxfs/xfs_attr.c      | 5 +++++
 fs/xfs/libxfs/xfs_attr_leaf.c | 5 +----
 2 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index e0a38a2..2f9fb7a 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -1213,6 +1213,11 @@ xfs_attr_node_removename(
 		error = xfs_attr3_leaf_setflag(args);
 		if (error)
 			goto out;
+
+		error = xfs_trans_roll_inode(&args->trans, args->dp);
+		if (error)
+			goto out;
+
 		error = xfs_attr_rmtval_remove(args);
 		if (error)
 			goto out;
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index 134eb00..42c037e 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -2854,10 +2854,7 @@ xfs_attr3_leaf_setflag(
 			 XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt)));
 	}
 
-	/*
-	 * Commit the flag value change and start the next trans in series.
-	 */
-	return xfs_trans_roll_inode(&args->trans, args->dp);
+	return error;
 }
 
 /*
-- 
2.7.4


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

* [PATCH v4 11/17] xfs: Add xfs_attr3_leaf helper functions
  2019-11-07  1:27 [PATCH v4 00/17] xfs: Delay Ready Attributes Allison Collins
                   ` (9 preceding siblings ...)
  2019-11-07  1:27 ` [PATCH v4 10/17] xfs: Factor up trans roll from xfs_attr3_leaf_setflag Allison Collins
@ 2019-11-07  1:27 ` Allison Collins
  2019-11-08 21:17   ` Darrick J. Wong
  2019-11-07  1:27 ` [PATCH v4 12/17] xfs: Factor out xfs_attr_rmtval_invalidate Allison Collins
                   ` (5 subsequent siblings)
  16 siblings, 1 reply; 77+ messages in thread
From: Allison Collins @ 2019-11-07  1:27 UTC (permalink / raw)
  To: linux-xfs

And new helper functions xfs_attr3_leaf_flag_is_set and
xfs_attr3_leaf_flagsflipped.  These routines check to see
if xfs_attr3_leaf_setflag or xfs_attr3_leaf_flipflags have
already been run.  We will need this later for delayed
attributes since routines may be recalled several times
when -EAGAIN is returned.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr_leaf.c | 94 +++++++++++++++++++++++++++++++++++++++++++
 fs/xfs/libxfs/xfs_attr_leaf.h |  2 +
 2 files changed, 96 insertions(+)

diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index 42c037e..023c616 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -2809,6 +2809,40 @@ xfs_attr3_leaf_clearflag(
 }
 
 /*
+ * Check if the INCOMPLETE flag on an entry in a leaf block is set.  This
+ * function can be used to check if xfs_attr3_leaf_setflag has already been
+ * called.  The INCOMPLETE flag is used during attr rename operations to mark
+ * entries that are being renamed. Since renames should be atomic, only one of
+ * them should appear as a completed attribute.
+ *
+ * isset is set to true if the flag is set or false otherwise
+ */
+int
+xfs_attr3_leaf_flag_is_set(
+	struct xfs_da_args		*args,
+	bool				*isset)
+{
+	struct xfs_attr_leafblock	*leaf;
+	struct xfs_attr_leaf_entry	*entry;
+	struct xfs_buf			*bp;
+	struct xfs_inode		*dp = args->dp;
+	int				error = 0;
+
+	error = xfs_attr3_leaf_read(args->trans, dp, args->blkno,
+				    XFS_DABUF_MAP_NOMAPPING, &bp);
+	if (error)
+		return error;
+
+	leaf = bp->b_addr;
+	entry = &xfs_attr3_leaf_entryp(leaf)[args->index];
+
+	*isset = ((entry->flags & XFS_ATTR_INCOMPLETE) != 0);
+	xfs_trans_brelse(args->trans, bp);
+
+	return 0;
+}
+
+/*
  * Set the INCOMPLETE flag on an entry in a leaf block.
  */
 int
@@ -2972,3 +3006,63 @@ xfs_attr3_leaf_flipflags(
 
 	return error;
 }
+
+/*
+ * On a leaf entry, check to see if the INCOMPLETE flag is cleared
+ * in args->blkno/index and set in args->blkno2/index2.  Note that they could be
+ * in different blocks, or in the same block.  This function can be used to
+ * check if xfs_attr3_leaf_flipflags has already been called.  The INCOMPLETE
+ * flag is used during attr rename operations to mark entries that are being
+ * renamed. Since renames should be atomic, only one of them should appear as a
+ * completed attribute.
+ *
+ * isflipped is set to true if flags are flipped or false otherwise
+ */
+int
+xfs_attr3_leaf_flagsflipped(
+	struct xfs_da_args		*args,
+	bool				*isflipped)
+{
+	struct xfs_attr_leafblock	*leaf1;
+	struct xfs_attr_leafblock	*leaf2;
+	struct xfs_attr_leaf_entry	*entry1;
+	struct xfs_attr_leaf_entry	*entry2;
+	struct xfs_buf			*bp1;
+	struct xfs_buf			*bp2;
+	struct xfs_inode		*dp = args->dp;
+	int				error = 0;
+
+	/*
+	 * Read the block containing the "old" attr
+	 */
+	error = xfs_attr3_leaf_read(args->trans, dp, args->blkno,
+				    XFS_DABUF_MAP_NOMAPPING, &bp1);
+	if (error)
+		return error;
+
+	/*
+	 * Read the block containing the "new" attr, if it is different
+	 */
+	if (args->blkno2 != args->blkno) {
+		error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno2,
+					   -1, &bp2);
+		if (error)
+			return error;
+	} else {
+		bp2 = bp1;
+	}
+
+	leaf1 = bp1->b_addr;
+	entry1 = &xfs_attr3_leaf_entryp(leaf1)[args->index];
+
+	leaf2 = bp2->b_addr;
+	entry2 = &xfs_attr3_leaf_entryp(leaf2)[args->index2];
+
+	*isflipped = (((entry1->flags & XFS_ATTR_INCOMPLETE) == 0) &&
+		      (entry2->flags & XFS_ATTR_INCOMPLETE));
+
+	xfs_trans_brelse(args->trans, bp1);
+	xfs_trans_brelse(args->trans, bp2);
+
+	return 0;
+}
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
index e108b37..12283cf 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.h
+++ b/fs/xfs/libxfs/xfs_attr_leaf.h
@@ -57,7 +57,9 @@ int	xfs_attr3_leaf_to_shortform(struct xfs_buf *bp,
 				   struct xfs_da_args *args, int forkoff);
 int	xfs_attr3_leaf_clearflag(struct xfs_da_args *args);
 int	xfs_attr3_leaf_setflag(struct xfs_da_args *args);
+int	xfs_attr3_leaf_flag_is_set(struct xfs_da_args *args, bool *isset);
 int	xfs_attr3_leaf_flipflags(struct xfs_da_args *args);
+int	xfs_attr3_leaf_flagsflipped(struct xfs_da_args *args, bool *isflipped);
 
 /*
  * Routines used for growing the Btree.
-- 
2.7.4


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

* [PATCH v4 12/17] xfs: Factor out xfs_attr_rmtval_invalidate
  2019-11-07  1:27 [PATCH v4 00/17] xfs: Delay Ready Attributes Allison Collins
                   ` (10 preceding siblings ...)
  2019-11-07  1:27 ` [PATCH v4 11/17] xfs: Add xfs_attr3_leaf helper functions Allison Collins
@ 2019-11-07  1:27 ` Allison Collins
  2019-11-08 21:19   ` Darrick J. Wong
  2019-11-07  1:27 ` [PATCH v4 13/17] xfs: Factor up trans roll in xfs_attr3_leaf_clearflag Allison Collins
                   ` (4 subsequent siblings)
  16 siblings, 1 reply; 77+ messages in thread
From: Allison Collins @ 2019-11-07  1:27 UTC (permalink / raw)
  To: linux-xfs

Because new delayed attribute routines cannot roll
transactions, we carve off the parts of
xfs_attr_rmtval_remove that we can use.  This will help to
reduce repetitive code later when we introduce delayed
attributes.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
Reviewed-by: Brian Foster <bfoster@redhat.com>
---
 fs/xfs/libxfs/xfs_attr_remote.c | 30 +++++++++++++++++++++---------
 fs/xfs/libxfs/xfs_attr_remote.h |  1 +
 2 files changed, 22 insertions(+), 9 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
index db51388..1544138 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.c
+++ b/fs/xfs/libxfs/xfs_attr_remote.c
@@ -588,21 +588,14 @@ xfs_attr_rmtval_set_value(
 	return 0;
 }
 
-/*
- * Remove the value associated with an attribute by deleting the
- * out-of-line buffer that it is stored on.
- */
 int
-xfs_attr_rmtval_remove(
+xfs_attr_rmtval_invalidate(
 	struct xfs_da_args	*args)
 {
 	struct xfs_mount	*mp = args->dp->i_mount;
 	xfs_dablk_t		lblkno;
 	int			blkcnt;
 	int			error;
-	int			done;
-
-	trace_xfs_attr_rmtval_remove(args);
 
 	/*
 	 * Roll through the "value", invalidating the attribute value's blocks.
@@ -644,13 +637,32 @@ xfs_attr_rmtval_remove(
 		lblkno += map.br_blockcount;
 		blkcnt -= map.br_blockcount;
 	}
+	return 0;
+}
 
+/*
+ * Remove the value associated with an attribute by deleting the
+ * out-of-line buffer that it is stored on.
+ */
+int
+xfs_attr_rmtval_remove(
+	struct xfs_da_args      *args)
+{
+	xfs_dablk_t		lblkno;
+	int			blkcnt;
+	int			error = 0;
+	int			done = 0;
+
+	trace_xfs_attr_rmtval_remove(args);
+
+	error = xfs_attr_rmtval_invalidate(args);
+	if (error)
+		return error;
 	/*
 	 * Keep de-allocating extents until the remote-value region is gone.
 	 */
 	lblkno = args->rmtblkno;
 	blkcnt = args->rmtblkcnt;
-	done = 0;
 	while (!done) {
 		error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
 				    XFS_BMAPI_ATTRFORK, 1, &done);
diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
index cd7670d..b6fd35a 100644
--- a/fs/xfs/libxfs/xfs_attr_remote.h
+++ b/fs/xfs/libxfs/xfs_attr_remote.h
@@ -11,6 +11,7 @@ int xfs_attr3_rmt_blocks(struct xfs_mount *mp, int attrlen);
 int xfs_attr_rmtval_get(struct xfs_da_args *args);
 int xfs_attr_rmtval_set(struct xfs_da_args *args);
 int xfs_attr_rmtval_remove(struct xfs_da_args *args);
+int xfs_attr_rmtval_invalidate(struct xfs_da_args *args);
 int xfs_attr_rmtval_set_value(struct xfs_da_args *args);
 int xfs_attr_rmt_find_hole(struct xfs_da_args *args);
 #endif /* __XFS_ATTR_REMOTE_H__ */
-- 
2.7.4


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

* [PATCH v4 13/17] xfs: Factor up trans roll in xfs_attr3_leaf_clearflag
  2019-11-07  1:27 [PATCH v4 00/17] xfs: Delay Ready Attributes Allison Collins
                   ` (11 preceding siblings ...)
  2019-11-07  1:27 ` [PATCH v4 12/17] xfs: Factor out xfs_attr_rmtval_invalidate Allison Collins
@ 2019-11-07  1:27 ` Allison Collins
  2019-11-08 21:19   ` Darrick J. Wong
  2019-11-11 18:23   ` Brian Foster
  2019-11-07  1:27 ` [PATCH v4 14/17] xfs: Add delay context to xfs_da_args Allison Collins
                   ` (3 subsequent siblings)
  16 siblings, 2 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-07  1:27 UTC (permalink / raw)
  To: linux-xfs

New delayed allocation routines cannot be handling
transactions so factor them up into the calling functions

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c      | 16 ++++++++++++++++
 fs/xfs/libxfs/xfs_attr_leaf.c |  5 +----
 2 files changed, 17 insertions(+), 4 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 2f9fb7a..5dcb19f 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -797,6 +797,14 @@ xfs_attr_leaf_addname(struct xfs_da_args	*args)
 		 * Added a "remote" value, just clear the incomplete flag.
 		 */
 		error = xfs_attr3_leaf_clearflag(args);
+		if (error)
+			return error;
+
+		/*
+		 * Commit the flag value change and start the next trans in
+		 * series.
+		 */
+		error = xfs_trans_roll_inode(&args->trans, args->dp);
 	}
 	return error;
 }
@@ -1154,6 +1162,14 @@ xfs_attr_node_addname(
 		error = xfs_attr3_leaf_clearflag(args);
 		if (error)
 			goto out;
+
+		 /*
+		  * Commit the flag value change and start the next trans in
+		  * series.
+		  */
+		error = xfs_trans_roll_inode(&args->trans, args->dp);
+		if (error)
+			goto out;
 	}
 	retval = error = 0;
 
diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
index 023c616..07eee3ff 100644
--- a/fs/xfs/libxfs/xfs_attr_leaf.c
+++ b/fs/xfs/libxfs/xfs_attr_leaf.c
@@ -2802,10 +2802,7 @@ xfs_attr3_leaf_clearflag(
 			 XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt)));
 	}
 
-	/*
-	 * Commit the flag value change and start the next trans in series.
-	 */
-	return xfs_trans_roll_inode(&args->trans, args->dp);
+	return error;
 }
 
 /*
-- 
2.7.4


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

* [PATCH v4 14/17] xfs: Add delay context to xfs_da_args
  2019-11-07  1:27 [PATCH v4 00/17] xfs: Delay Ready Attributes Allison Collins
                   ` (12 preceding siblings ...)
  2019-11-07  1:27 ` [PATCH v4 13/17] xfs: Factor up trans roll in xfs_attr3_leaf_clearflag Allison Collins
@ 2019-11-07  1:27 ` Allison Collins
  2019-11-08 21:22   ` Darrick J. Wong
  2019-11-11 18:23   ` Brian Foster
  2019-11-07  1:27 ` [PATCH v4 15/17] xfs: Check for -ENOATTR or -EEXIST Allison Collins
                   ` (2 subsequent siblings)
  16 siblings, 2 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-07  1:27 UTC (permalink / raw)
  To: linux-xfs

This patch adds a new struct xfs_delay_context, which we
will use to keep track of the current state of a delayed
attribute operation.

The new enum is used to track various operations that
are in progress so that we know not to repeat them, and
resume where we left off before EAGAIN was returned to
cycle out the transaction.  Other members take the place
of local variables that need to retain their values
across multiple function recalls.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_da_btree.h | 28 ++++++++++++++++++++++++++++
 fs/xfs/scrub/common.c        |  2 ++
 fs/xfs/xfs_acl.c             |  2 ++
 fs/xfs/xfs_attr_list.c       |  1 +
 fs/xfs/xfs_ioctl.c           |  2 ++
 fs/xfs/xfs_ioctl32.c         |  2 ++
 fs/xfs/xfs_iops.c            |  2 ++
 fs/xfs/xfs_xattr.c           |  1 +
 8 files changed, 40 insertions(+)

diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
index bed4f40..ef23ed8 100644
--- a/fs/xfs/libxfs/xfs_da_btree.h
+++ b/fs/xfs/libxfs/xfs_da_btree.h
@@ -42,6 +42,33 @@ enum xfs_dacmp {
 	XFS_CMP_CASE		/* names are same but differ in case */
 };
 
+enum xfs_attr_state {
+	XFS_DC_INIT		= 1, /* Init delay info */
+	XFS_DC_SF_TO_LEAF	= 2, /* Converted short form to leaf */
+	XFS_DC_FOUND_LBLK	= 3, /* We found leaf blk for attr */
+	XFS_DC_LEAF_TO_NODE	= 4, /* Converted leaf to node */
+	XFS_DC_FOUND_NBLK	= 5, /* We found node blk for attr */
+	XFS_DC_ALLOC_LEAF	= 6, /* We are allocating leaf blocks */
+	XFS_DC_ALLOC_NODE	= 7, /* We are allocating node blocks */
+	XFS_DC_RM_INVALIDATE	= 8, /* We are invalidating blocks */
+	XFS_DC_RM_SHRINK	= 9, /* We are shrinking the tree */
+	XFS_DC_RM_NODE_BLKS	= 10,/* We are removing node blocks */
+};
+
+/*
+ * Context used for keeping track of delayed attribute operations
+ */
+struct xfs_delay_context {
+	enum xfs_attr_state	dc_state;
+	struct xfs_buf		*leaf_bp;
+	struct xfs_bmbt_irec	map;
+	xfs_dablk_t		lblkno;
+	xfs_fileoff_t		lfileoff;
+	int			blkcnt;
+	struct xfs_da_state	*da_state;
+	struct xfs_da_state_blk *blk;
+};
+
 /*
  * Structure to ease passing around component names.
  */
@@ -69,6 +96,7 @@ typedef struct xfs_da_args {
 	int		rmtvaluelen2;	/* remote attr value length in bytes */
 	int		op_flags;	/* operation flags */
 	enum xfs_dacmp	cmpresult;	/* name compare result for lookups */
+	struct xfs_delay_context  dc;	/* context used for delay attr ops */
 } xfs_da_args_t;
 
 /*
diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
index 1887605..9a649d1 100644
--- a/fs/xfs/scrub/common.c
+++ b/fs/xfs/scrub/common.c
@@ -24,6 +24,8 @@
 #include "xfs_rmap_btree.h"
 #include "xfs_log.h"
 #include "xfs_trans_priv.h"
+#include "xfs_da_format.h"
+#include "xfs_da_btree.h"
 #include "xfs_attr.h"
 #include "xfs_reflink.h"
 #include "scrub/scrub.h"
diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
index e868755..1336477 100644
--- a/fs/xfs/xfs_acl.c
+++ b/fs/xfs/xfs_acl.c
@@ -10,6 +10,8 @@
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
 #include "xfs_inode.h"
+#include "xfs_da_format.h"
+#include "xfs_da_btree.h"
 #include "xfs_attr.h"
 #include "xfs_trace.h"
 #include <linux/posix_acl_xattr.h>
diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
index fab416c..e395864 100644
--- a/fs/xfs/xfs_attr_list.c
+++ b/fs/xfs/xfs_attr_list.c
@@ -12,6 +12,7 @@
 #include "xfs_trans_resv.h"
 #include "xfs_mount.h"
 #include "xfs_da_format.h"
+#include "xfs_da_btree.h"
 #include "xfs_inode.h"
 #include "xfs_trans.h"
 #include "xfs_bmap.h"
diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
index ae0ed88..23b0ca6 100644
--- a/fs/xfs/xfs_ioctl.c
+++ b/fs/xfs/xfs_ioctl.c
@@ -15,6 +15,8 @@
 #include "xfs_iwalk.h"
 #include "xfs_itable.h"
 #include "xfs_error.h"
+#include "xfs_da_format.h"
+#include "xfs_da_btree.h"
 #include "xfs_attr.h"
 #include "xfs_bmap.h"
 #include "xfs_bmap_util.h"
diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c
index 3c0d518..e3278ac 100644
--- a/fs/xfs/xfs_ioctl32.c
+++ b/fs/xfs/xfs_ioctl32.c
@@ -17,6 +17,8 @@
 #include "xfs_itable.h"
 #include "xfs_fsops.h"
 #include "xfs_rtalloc.h"
+#include "xfs_da_format.h"
+#include "xfs_da_btree.h"
 #include "xfs_attr.h"
 #include "xfs_ioctl.h"
 #include "xfs_ioctl32.h"
diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
index aef346e..68b9cd0 100644
--- a/fs/xfs/xfs_iops.c
+++ b/fs/xfs/xfs_iops.c
@@ -13,6 +13,8 @@
 #include "xfs_inode.h"
 #include "xfs_acl.h"
 #include "xfs_quota.h"
+#include "xfs_da_format.h"
+#include "xfs_da_btree.h"
 #include "xfs_attr.h"
 #include "xfs_trans.h"
 #include "xfs_trace.h"
diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
index 6c5321d..0f0ebab 100644
--- a/fs/xfs/xfs_xattr.c
+++ b/fs/xfs/xfs_xattr.c
@@ -10,6 +10,7 @@
 #include "xfs_log_format.h"
 #include "xfs_da_format.h"
 #include "xfs_inode.h"
+#include "xfs_da_btree.h"
 #include "xfs_attr.h"
 
 #include <linux/posix_acl_xattr.h>
-- 
2.7.4


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

* [PATCH v4 15/17] xfs: Check for -ENOATTR or -EEXIST
  2019-11-07  1:27 [PATCH v4 00/17] xfs: Delay Ready Attributes Allison Collins
                   ` (13 preceding siblings ...)
  2019-11-07  1:27 ` [PATCH v4 14/17] xfs: Add delay context to xfs_da_args Allison Collins
@ 2019-11-07  1:27 ` Allison Collins
  2019-11-08 21:28   ` Darrick J. Wong
  2019-11-11 18:24   ` Brian Foster
  2019-11-07  1:28 ` [PATCH v4 16/17] xfs: Add delay ready attr remove routines Allison Collins
  2019-11-07  1:28 ` [PATCH v4 17/17] xfs: Add delay ready attr set routines Allison Collins
  16 siblings, 2 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-07  1:27 UTC (permalink / raw)
  To: linux-xfs

Delayed operations cannot return error codes.  So we must check for
these conditions first before starting set or remove operations

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 5dcb19f..626d4a98 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -458,6 +458,27 @@ xfs_attr_set(
 		goto out_trans_cancel;
 
 	xfs_trans_ijoin(args.trans, dp, 0);
+
+	error = xfs_has_attr(&args);
+	if (error == -EEXIST) {
+		if (name->type & ATTR_CREATE)
+			goto out_trans_cancel;
+		else
+			name->type |= ATTR_REPLACE;
+	}
+
+	if (error == -ENOATTR && (name->type & ATTR_REPLACE))
+		goto out_trans_cancel;
+
+	if (name->type & ATTR_REPLACE) {
+		name->type &= ~ATTR_REPLACE;
+		error = xfs_attr_remove_args(&args);
+		if (error)
+			goto out_trans_cancel;
+
+		name->type |= ATTR_CREATE;
+	}
+
 	error = xfs_attr_set_args(&args);
 	if (error)
 		goto out_trans_cancel;
@@ -543,6 +564,10 @@ xfs_attr_remove(
 	 */
 	xfs_trans_ijoin(args.trans, dp, 0);
 
+	error = xfs_has_attr(&args);
+	if (error == -ENOATTR)
+		goto out;
+
 	error = xfs_attr_remove_args(&args);
 	if (error)
 		goto out;
-- 
2.7.4


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

* [PATCH v4 16/17] xfs: Add delay ready attr remove routines
  2019-11-07  1:27 [PATCH v4 00/17] xfs: Delay Ready Attributes Allison Collins
                   ` (14 preceding siblings ...)
  2019-11-07  1:27 ` [PATCH v4 15/17] xfs: Check for -ENOATTR or -EEXIST Allison Collins
@ 2019-11-07  1:28 ` Allison Collins
  2019-11-08 21:37   ` Darrick J. Wong
  2019-11-12 13:37   ` Brian Foster
  2019-11-07  1:28 ` [PATCH v4 17/17] xfs: Add delay ready attr set routines Allison Collins
  16 siblings, 2 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-07  1:28 UTC (permalink / raw)
  To: linux-xfs

This patch modifies the attr remove routines to be delay ready.
This means they no longer roll or commit transactions, but instead
return -EAGAIN to have the calling routine roll and refresh the
transaction.  In this series, xfs_attr_remove_args has become
xfs_attr_remove_later, which uses a state machine to keep track
of where it was when EAGAIN was returned.  xfs_attr_node_removename
has also been modified to use the state machine, and a  new version of
xfs_attr_remove_args consists of a simple loop to refresh the
transaction until the operation is completed.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c | 123 +++++++++++++++++++++++++++++++++++++++--------
 fs/xfs/libxfs/xfs_attr.h |   1 +
 2 files changed, 104 insertions(+), 20 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 626d4a98..38d5c5c 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -369,10 +369,56 @@ xfs_has_attr(
  */
 int
 xfs_attr_remove_args(
+	struct xfs_da_args	*args)
+{
+	int			error = 0;
+	int			err2 = 0;
+
+	do {
+		error = xfs_attr_remove_later(args);
+		if (error && error != -EAGAIN)
+			goto out;
+
+		xfs_trans_log_inode(args->trans, args->dp,
+			XFS_ILOG_CORE | XFS_ILOG_ADATA);
+
+		err2 = xfs_trans_roll(&args->trans);
+		if (err2) {
+			error = err2;
+			goto out;
+		}
+
+		/* Rejoin inode */
+		xfs_trans_ijoin(args->trans, args->dp, 0);
+
+	} while (error == -EAGAIN);
+out:
+	return error;
+}
+
+/*
+ * Remove the attribute specified in @args.
+ * This routine is meant to function as a delayed operation, and may return
+ * -EGAIN when the transaction needs to be rolled.  Calling functions will need
+ * to handle this, and recall the function until a successful error code is
+ * returned.
+ */
+int
+xfs_attr_remove_later(
 	struct xfs_da_args      *args)
 {
 	struct xfs_inode	*dp = args->dp;
-	int			error;
+	int			error = 0;
+
+	/* State machine switch */
+	switch (args->dc.dc_state) {
+	case XFS_DC_RM_INVALIDATE:
+	case XFS_DC_RM_SHRINK:
+	case XFS_DC_RM_NODE_BLKS:
+		goto node;
+	default:
+		break;
+	}
 
 	if (!xfs_inode_hasattr(dp)) {
 		error = -ENOATTR;
@@ -382,6 +428,7 @@ xfs_attr_remove_args(
 	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
 		error = xfs_attr_leaf_removename(args);
 	} else {
+node:
 		error = xfs_attr_node_removename(args);
 	}
 
@@ -892,9 +939,6 @@ xfs_attr_leaf_removename(
 		/* bp is gone due to xfs_da_shrink_inode */
 		if (error)
 			return error;
-		error = xfs_defer_finish(&args->trans);
-		if (error)
-			return error;
 	}
 	return 0;
 }
@@ -1212,6 +1256,11 @@ xfs_attr_node_addname(
  * This will involve walking down the Btree, and may involve joining
  * leaf nodes and even joining intermediate nodes up to and including
  * the root node (a special case of an intermediate node).
+ *
+ * This routine is meant to function as a delayed operation, and may return
+ * -EAGAIN when the transaction needs to be rolled.  Calling functions
+ * will need to handle this, and recall the function until a successful error
+ * code is returned.
  */
 STATIC int
 xfs_attr_node_removename(
@@ -1222,12 +1271,29 @@ xfs_attr_node_removename(
 	struct xfs_buf		*bp;
 	int			retval, error, forkoff;
 	struct xfs_inode	*dp = args->dp;
+	int			done = 0;
 
 	trace_xfs_attr_node_removename(args);
+	state = args->dc.da_state;
+	blk = args->dc.blk;
+
+	/* State machine switch */
+	switch (args->dc.dc_state) {
+	case XFS_DC_RM_NODE_BLKS:
+		goto rm_node_blks;
+	case XFS_DC_RM_INVALIDATE:
+		goto rm_invalidate;
+	case XFS_DC_RM_SHRINK:
+		goto rm_shrink;
+	default:
+		break;
+	}
 
 	error = xfs_attr_node_hasname(args, &state);
 	if (error != -EEXIST)
 		goto out;
+	else
+		error = 0;
 
 	/*
 	 * If there is an out-of-line value, de-allocate the blocks.
@@ -1237,6 +1303,14 @@ xfs_attr_node_removename(
 	blk = &state->path.blk[ state->path.active-1 ];
 	ASSERT(blk->bp != NULL);
 	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
+
+	/*
+	 * Store blk and state in the context incase we need to cycle out the
+	 * transaction
+	 */
+	args->dc.blk = blk;
+	args->dc.da_state = state;
+
 	if (args->rmtblkno > 0) {
 		/*
 		 * Fill in disk block numbers in the state structure
@@ -1255,13 +1329,30 @@ xfs_attr_node_removename(
 		if (error)
 			goto out;
 
-		error = xfs_trans_roll_inode(&args->trans, args->dp);
+		args->dc.dc_state = XFS_DC_RM_INVALIDATE;
+		return -EAGAIN;
+rm_invalidate:
+		error = xfs_attr_rmtval_invalidate(args);
 		if (error)
 			goto out;
+rm_node_blks:
+		/*
+		 * Unmap value blocks for this attr.  This is similar to
+		 * xfs_attr_rmtval_remove, but open coded here to return EAGAIN
+		 * for new transactions
+		 */
+		while (!done && !error) {
+			error = xfs_bunmapi(args->trans, args->dp,
+				    args->rmtblkno, args->rmtblkcnt,
+				    XFS_BMAPI_ATTRFORK, 1, &done);
+			if (error)
+				return error;
 
-		error = xfs_attr_rmtval_remove(args);
-		if (error)
-			goto out;
+			if (!done) {
+				args->dc.dc_state = XFS_DC_RM_NODE_BLKS;
+				return -EAGAIN;
+			}
+		}
 
 		/*
 		 * Refill the state structure with buffers, the prior calls
@@ -1287,17 +1378,12 @@ xfs_attr_node_removename(
 		error = xfs_da3_join(state);
 		if (error)
 			goto out;
-		error = xfs_defer_finish(&args->trans);
-		if (error)
-			goto out;
-		/*
-		 * Commit the Btree join operation and start a new trans.
-		 */
-		error = xfs_trans_roll_inode(&args->trans, dp);
-		if (error)
-			goto out;
+
+		args->dc.dc_state = XFS_DC_RM_SHRINK;
+		return -EAGAIN;
 	}
 
+rm_shrink:
 	/*
 	 * If the result is small enough, push it all into the inode.
 	 */
@@ -1319,9 +1405,6 @@ xfs_attr_node_removename(
 			/* bp is gone due to xfs_da_shrink_inode */
 			if (error)
 				goto out;
-			error = xfs_defer_finish(&args->trans);
-			if (error)
-				goto out;
 		} else
 			xfs_trans_brelse(args->trans, bp);
 	}
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index 3b5dad4..fb8bf5b 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -152,6 +152,7 @@ int xfs_attr_set_args(struct xfs_da_args *args);
 int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
 int xfs_has_attr(struct xfs_da_args *args);
 int xfs_attr_remove_args(struct xfs_da_args *args);
+int xfs_attr_remove_later(struct xfs_da_args *args);
 int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
 		  int flags, struct attrlist_cursor_kern *cursor);
 bool xfs_attr_namecheck(const void *name, size_t length);
-- 
2.7.4


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

* [PATCH v4 17/17] xfs: Add delay ready attr set routines
  2019-11-07  1:27 [PATCH v4 00/17] xfs: Delay Ready Attributes Allison Collins
                   ` (15 preceding siblings ...)
  2019-11-07  1:28 ` [PATCH v4 16/17] xfs: Add delay ready attr remove routines Allison Collins
@ 2019-11-07  1:28 ` Allison Collins
  2019-11-08 21:42   ` Darrick J. Wong
  2019-11-12 13:37   ` Brian Foster
  16 siblings, 2 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-07  1:28 UTC (permalink / raw)
  To: linux-xfs

This patch modifies the attr set routines to be delay ready.
This means they no longer roll or commit transactions, but instead
return -EAGAIN to have the calling routine roll and refresh the
transaction.  In this series, xfs_attr_set_args has become
xfs_attr_set_later, which uses a state machine to keep track
of where it was when EAGAIN was returned.  Part of
xfs_attr_leaf_addname has been factored out into a new helper
function xfs_attr_leaf_try_add to allow transaction cycling between
the two routines, and the flipflags logic has been removed since we
can simply cancel the transaction upon error.  xfs_attr_set_args
consists of a simple loop to refresh the transaction until the
operation is completed.

Signed-off-by: Allison Collins <allison.henderson@oracle.com>
---
 fs/xfs/libxfs/xfs_attr.c | 435 +++++++++++++++++++++++------------------------
 fs/xfs/libxfs/xfs_attr.h |   1 +
 2 files changed, 211 insertions(+), 225 deletions(-)

diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
index 38d5c5c..97e5ae0 100644
--- a/fs/xfs/libxfs/xfs_attr.c
+++ b/fs/xfs/libxfs/xfs_attr.c
@@ -58,6 +58,7 @@ STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
 				 struct xfs_da_state **state);
 STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
 STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
+STATIC int xfs_attr_leaf_try_add(struct xfs_da_args *args, struct xfs_buf *bp);
 
 
 STATIC int
@@ -250,9 +251,79 @@ int
 xfs_attr_set_args(
 	struct xfs_da_args	*args)
 {
+	int			error = 0;
+	int			err2 = 0;
+	struct xfs_buf		*leaf_bp = NULL;
+
+	do {
+		error = xfs_attr_set_later(args, &leaf_bp);
+		if (error && error != -EAGAIN)
+			goto out;
+
+		xfs_trans_log_inode(args->trans, args->dp,
+				    XFS_ILOG_CORE | XFS_ILOG_ADATA);
+
+		err2 = xfs_trans_roll(&args->trans);
+		if (err2) {
+			error = err2;
+			goto out;
+		}
+
+		/* Rejoin inode and leaf if needed */
+		xfs_trans_ijoin(args->trans, args->dp, 0);
+		if (leaf_bp) {
+			xfs_trans_bjoin(args->trans, leaf_bp);
+			xfs_trans_bhold(args->trans, leaf_bp);
+		}
+
+	} while (error == -EAGAIN);
+
+out:
+	return error;
+}
+
+/*
+ * Set the attribute specified in @args.
+ * This routine is meant to function as a delayed operation, and may return
+ * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
+ * to handle this, and recall the function until a successful error code is
+ * returned.
+ */
+int
+xfs_attr_set_later(
+	struct xfs_da_args	*args,
+	struct xfs_buf          **leaf_bp)
+{
 	struct xfs_inode	*dp = args->dp;
-	struct xfs_buf          *leaf_bp = NULL;
-	int			error, error2 = 0;;
+	int			error = 0;
+	int			sf_size;
+
+	/* State machine switch */
+	switch (args->dc.dc_state) {
+	case XFS_DC_SF_TO_LEAF:
+		goto sf_to_leaf;
+	case XFS_DC_ALLOC_LEAF:
+	case XFS_DC_FOUND_LBLK:
+		goto leaf;
+	case XFS_DC_FOUND_NBLK:
+	case XFS_DC_ALLOC_NODE:
+	case XFS_DC_LEAF_TO_NODE:
+		goto node;
+	default:
+		break;
+	}
+
+	/*
+	 * New inodes may not have an attribute fork yet. So set the attribute
+	 * fork appropriately
+	 */
+	if (XFS_IFORK_Q((args->dp)) == 0) {
+		sf_size = sizeof(struct xfs_attr_sf_hdr) +
+		     XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
+		xfs_bmap_set_attrforkoff(args->dp, sf_size, NULL);
+		args->dp->i_afp = kmem_zone_zalloc(xfs_ifork_zone, 0);
+		args->dp->i_afp->if_flags = XFS_IFEXTENTS;
+	}
 
 	/*
 	 * If the attribute list is non-existent or a shortform list,
@@ -272,21 +343,14 @@ xfs_attr_set_args(
 		 * Try to add the attr to the attribute list in the inode.
 		 */
 		error = xfs_attr_try_sf_addname(dp, args);
-		if (error != -ENOSPC) {
-			if (dp->i_mount->m_flags & XFS_MOUNT_WSYNC)
-				xfs_trans_set_sync(args->trans);
-
-			error2 = xfs_trans_commit(args->trans);
-			args->trans = NULL;
-			return error ? error : error2;
-		}
-
+		if (error != -ENOSPC)
+			return error;
 
 		/*
 		 * It won't fit in the shortform, transform to a leaf block.
 		 * GROT: another possible req'mt for a double-split btree op.
 		 */
-		error = xfs_attr_shortform_to_leaf(args, &leaf_bp);
+		error = xfs_attr_shortform_to_leaf(args, leaf_bp);
 		if (error)
 			return error;
 
@@ -294,43 +358,42 @@ xfs_attr_set_args(
 		 * Prevent the leaf buffer from being unlocked so that a
 		 * concurrent AIL push cannot grab the half-baked leaf
 		 * buffer and run into problems with the write verifier.
-		 * Once we're done rolling the transaction we can release
-		 * the hold and add the attr to the leaf.
 		 */
-		xfs_trans_bhold(args->trans, leaf_bp);
-		error = xfs_defer_finish(&args->trans);
-		xfs_trans_bhold_release(args->trans, leaf_bp);
-		if (error) {
-			xfs_trans_brelse(args->trans, leaf_bp);
-			return error;
-		}
+
+		xfs_trans_bhold(args->trans, *leaf_bp);
+		args->dc.dc_state = XFS_DC_SF_TO_LEAF;
+		return -EAGAIN;
+	}
+sf_to_leaf:
+
+	/*
+	 * After a shortform to leaf conversion, we need to hold the leaf and
+	 * cylce out the transaction.  When we get back, we need to release
+	 * the leaf.
+	 */
+	if (*leaf_bp != NULL) {
+		xfs_trans_brelse(args->trans, *leaf_bp);
+		*leaf_bp = NULL;
 	}
 
 	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
+		error = xfs_attr_leaf_try_add(args, *leaf_bp);
+		if (error == -ENOSPC)
+			args->dc.dc_state = XFS_DC_LEAF_TO_NODE;
+		else if (error)
+			return error;
+		else
+			args->dc.dc_state = XFS_DC_FOUND_LBLK;
+		return -EAGAIN;
+leaf:
 		error = xfs_attr_leaf_addname(args);
 		if (error == -ENOSPC) {
-			/*
-			 * Commit that transaction so that the node_addname()
-			 * call can manage its own transactions.
-			 */
-			error = xfs_defer_finish(&args->trans);
-			if (error)
-				return error;
-
-			/*
-			 * Commit the current trans (including the inode) and
-			 * start a new one.
-			 */
-			error = xfs_trans_roll_inode(&args->trans, dp);
-			if (error)
-				return error;
-
-			/*
-			 * Fob the rest of the problem off on the Btree code.
-			 */
-			error = xfs_attr_node_addname(args);
+			args->dc.dc_state = XFS_DC_LEAF_TO_NODE;
+			return -EAGAIN;
 		}
 	} else {
+		args->dc.dc_state = XFS_DC_LEAF_TO_NODE;
+node:
 		error = xfs_attr_node_addname(args);
 	}
 	return error;
@@ -764,27 +827,26 @@ xfs_attr_leaf_try_add(
  *
  * This leaf block cannot have a "remote" value, we only call this routine
  * if bmap_one_block() says there is only one block (ie: no remote blks).
+ *
+ * This routine is meant to function as a delayed operation, and may return
+ * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
+ * to handle this, and recall the function until a successful error code is
+ * returned.
  */
 STATIC int
 xfs_attr_leaf_addname(struct xfs_da_args	*args)
 {
-	int			error, forkoff;
-	struct xfs_buf		*bp = NULL;
+	int			error, nmap;
 	struct xfs_inode	*dp = args->dp;
+	struct xfs_bmbt_irec	*map = &args->dc.map;
 
-	trace_xfs_attr_leaf_addname(args);
-
-	error = xfs_attr_leaf_try_add(args, bp);
-	if (error)
-		return error;
-
-	/*
-	 * Commit the transaction that added the attr name so that
-	 * later routines can manage their own transactions.
-	 */
-	error = xfs_trans_roll_inode(&args->trans, dp);
-	if (error)
-		return error;
+	/* State machine switch */
+	switch (args->dc.dc_state) {
+	case XFS_DC_ALLOC_LEAF:
+		goto alloc_leaf;
+	default:
+		break;
+	}
 
 	/*
 	 * If there was an out-of-line value, allocate the blocks we
@@ -793,90 +855,58 @@ xfs_attr_leaf_addname(struct xfs_da_args	*args)
 	 * maximum size of a transaction and/or hit a deadlock.
 	 */
 	if (args->rmtblkno > 0) {
-		error = xfs_attr_rmtval_set(args);
-		if (error)
-			return error;
-	}
 
-	/*
-	 * If this is an atomic rename operation, we must "flip" the
-	 * incomplete flags on the "new" and "old" attribute/value pairs
-	 * so that one disappears and one appears atomically.  Then we
-	 * must remove the "old" attribute/value pair.
-	 */
-	if (args->op_flags & XFS_DA_OP_RENAME) {
-		/*
-		 * In a separate transaction, set the incomplete flag on the
-		 * "old" attr and clear the incomplete flag on the "new" attr.
-		 */
-		error = xfs_attr3_leaf_flipflags(args);
-		if (error)
-			return error;
-		/*
-		 * Commit the flag value change and start the next trans in
-		 * series.
-		 */
-		error = xfs_trans_roll_inode(&args->trans, args->dp);
-		if (error)
-			return error;
+		/* Open coded xfs_attr_rmtval_set without trans handling */
 
-		/*
-		 * Dismantle the "old" attribute/value pair by removing
-		 * a "remote" value (if it exists).
-		 */
-		args->index = args->index2;
-		args->blkno = args->blkno2;
-		args->rmtblkno = args->rmtblkno2;
-		args->rmtblkcnt = args->rmtblkcnt2;
-		args->rmtvaluelen = args->rmtvaluelen2;
-		if (args->rmtblkno) {
-			error = xfs_attr_rmtval_remove(args);
-			if (error)
-				return error;
-		}
+		args->dc.lfileoff = 0;
+		args->dc.lblkno = 0;
+		args->dc.blkcnt = 0;
+		args->rmtblkcnt = 0;
+		args->rmtblkno = 0;
+		memset(map, 0, sizeof(struct xfs_bmbt_irec));
 
-		/*
-		 * Read in the block containing the "old" attr, then
-		 * remove the "old" attr from that block (neat, huh!)
-		 */
-		error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
-					   XFS_DABUF_MAP_NOMAPPING, &bp);
+		error = xfs_attr_rmt_find_hole(args);
 		if (error)
 			return error;
 
-		xfs_attr3_leaf_remove(bp, args);
+		args->dc.blkcnt = args->rmtblkcnt;
+		args->dc.lblkno = args->rmtblkno;
 
 		/*
-		 * If the result is small enough, shrink it all into the inode.
+		 * Roll through the "value", allocating blocks on disk as
+		 * required.
 		 */
-		if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
-			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
-			/* bp is gone due to xfs_da_shrink_inode */
-			if (error)
-				return error;
-			error = xfs_defer_finish(&args->trans);
+alloc_leaf:
+		while (args->dc.blkcnt > 0) {
+			nmap = 1;
+			error = xfs_bmapi_write(args->trans, dp,
+				  (xfs_fileoff_t)args->dc.lblkno,
+				  args->dc.blkcnt, XFS_BMAPI_ATTRFORK,
+				  args->total, map, &nmap);
 			if (error)
 				return error;
-		}
+			ASSERT(nmap == 1);
+			ASSERT((map->br_startblock != DELAYSTARTBLOCK) &&
+			       (map->br_startblock != HOLESTARTBLOCK));
 
-		/*
-		 * Commit the remove and start the next trans in series.
-		 */
-		error = xfs_trans_roll_inode(&args->trans, dp);
+			/* roll attribute extent map forwards */
+			args->dc.lblkno += map->br_blockcount;
+			args->dc.blkcnt -= map->br_blockcount;
 
-	} else if (args->rmtblkno > 0) {
-		/*
-		 * Added a "remote" value, just clear the incomplete flag.
-		 */
-		error = xfs_attr3_leaf_clearflag(args);
+			args->dc.dc_state = XFS_DC_ALLOC_LEAF;
+			return -EAGAIN;
+		}
+
+		error = xfs_attr_rmtval_set_value(args);
 		if (error)
 			return error;
+	}
 
+	if (args->rmtblkno > 0) {
 		/*
-		 * Commit the flag value change and start the next trans in
-		 * series.
+		 * Added a "remote" value, just clear the incomplete flag.
 		 */
-		error = xfs_trans_roll_inode(&args->trans, args->dp);
+		error = xfs_attr3_leaf_clearflag(args);
 	}
 	return error;
 }
@@ -1017,16 +1047,23 @@ xfs_attr_node_hasname(
  *
  * "Remote" attribute values confuse the issue and atomic rename operations
  * add a whole extra layer of confusion on top of that.
+ *
+ * This routine is meant to function as a delayed operation, and may return
+ * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
+ * to handle this, and recall the function until a successful error code is
+ *returned.
  */
 STATIC int
 xfs_attr_node_addname(
 	struct xfs_da_args	*args)
 {
-	struct xfs_da_state	*state;
+	struct xfs_da_state	*state = NULL;
 	struct xfs_da_state_blk	*blk;
 	struct xfs_inode	*dp;
-	struct xfs_mount	*mp;
-	int			retval, error;
+	int			retval = 0;
+	int			error = 0;
+	int			nmap;
+	struct xfs_bmbt_irec    *map = &args->dc.map;
 
 	trace_xfs_attr_node_addname(args);
 
@@ -1034,8 +1071,17 @@ xfs_attr_node_addname(
 	 * Fill in bucket of arguments/results/context to carry around.
 	 */
 	dp = args->dp;
-	mp = dp->i_mount;
-restart:
+
+	/* State machine switch */
+	switch (args->dc.dc_state) {
+	case XFS_DC_FOUND_NBLK:
+		goto found_nblk;
+	case XFS_DC_ALLOC_NODE:
+		goto alloc_node;
+	default:
+		break;
+	}
+
 	/*
 	 * Search to see if name already exists, and get back a pointer
 	 * to where it should go.
@@ -1085,19 +1131,12 @@ xfs_attr_node_addname(
 			error = xfs_attr3_leaf_to_node(args);
 			if (error)
 				goto out;
-			error = xfs_defer_finish(&args->trans);
-			if (error)
-				goto out;
 
 			/*
-			 * Commit the node conversion and start the next
-			 * trans in the chain.
+			 * Restart routine from the top.  No need to set  the
+			 * state
 			 */
-			error = xfs_trans_roll_inode(&args->trans, dp);
-			if (error)
-				goto out;
-
-			goto restart;
+			return -EAGAIN;
 		}
 
 		/*
@@ -1109,9 +1148,6 @@ xfs_attr_node_addname(
 		error = xfs_da3_split(state);
 		if (error)
 			goto out;
-		error = xfs_defer_finish(&args->trans);
-		if (error)
-			goto out;
 	} else {
 		/*
 		 * Addition succeeded, update Btree hashvals.
@@ -1126,13 +1162,9 @@ xfs_attr_node_addname(
 	xfs_da_state_free(state);
 	state = NULL;
 
-	/*
-	 * Commit the leaf addition or btree split and start the next
-	 * trans in the chain.
-	 */
-	error = xfs_trans_roll_inode(&args->trans, dp);
-	if (error)
-		goto out;
+	args->dc.dc_state = XFS_DC_FOUND_NBLK;
+	return -EAGAIN;
+found_nblk:
 
 	/*
 	 * If there was an out-of-line value, allocate the blocks we
@@ -1141,104 +1173,57 @@ xfs_attr_node_addname(
 	 * maximum size of a transaction and/or hit a deadlock.
 	 */
 	if (args->rmtblkno > 0) {
-		error = xfs_attr_rmtval_set(args);
-		if (error)
-			return error;
-	}
+		/* Open coded xfs_attr_rmtval_set without trans handling */
+		args->dc.lblkno = 0;
+		args->dc.lfileoff = 0;
+		args->dc.blkcnt = 0;
+		args->rmtblkcnt = 0;
+		args->rmtblkno = 0;
+		memset(map, 0, sizeof(struct xfs_bmbt_irec));
 
-	/*
-	 * If this is an atomic rename operation, we must "flip" the
-	 * incomplete flags on the "new" and "old" attribute/value pairs
-	 * so that one disappears and one appears atomically.  Then we
-	 * must remove the "old" attribute/value pair.
-	 */
-	if (args->op_flags & XFS_DA_OP_RENAME) {
-		/*
-		 * In a separate transaction, set the incomplete flag on the
-		 * "old" attr and clear the incomplete flag on the "new" attr.
-		 */
-		error = xfs_attr3_leaf_flipflags(args);
-		if (error)
-			goto out;
-		/*
-		 * Commit the flag value change and start the next trans in
-		 * series
-		 */
-		error = xfs_trans_roll_inode(&args->trans, args->dp);
+		error = xfs_attr_rmt_find_hole(args);
 		if (error)
-			goto out;
+			return error;
 
+		args->dc.blkcnt = args->rmtblkcnt;
+		args->dc.lblkno = args->rmtblkno;
 		/*
-		 * Dismantle the "old" attribute/value pair by removing
-		 * a "remote" value (if it exists).
+		 * Roll through the "value", allocating blocks on disk as
+		 * required.
 		 */
-		args->index = args->index2;
-		args->blkno = args->blkno2;
-		args->rmtblkno = args->rmtblkno2;
-		args->rmtblkcnt = args->rmtblkcnt2;
-		args->rmtvaluelen = args->rmtvaluelen2;
-		if (args->rmtblkno) {
-			error = xfs_attr_rmtval_remove(args);
+alloc_node:
+		while (args->dc.blkcnt > 0) {
+			nmap = 1;
+			error = xfs_bmapi_write(args->trans, dp,
+				(xfs_fileoff_t)args->dc.lblkno, args->dc.blkcnt,
+				XFS_BMAPI_ATTRFORK, args->total, map, &nmap);
 			if (error)
 				return error;
-		}
 
-		/*
-		 * Re-find the "old" attribute entry after any split ops.
-		 * The INCOMPLETE flag means that we will find the "old"
-		 * attr, not the "new" one.
-		 */
-		args->name.type |= XFS_ATTR_INCOMPLETE;
-		state = xfs_da_state_alloc();
-		state->args = args;
-		state->mp = mp;
-		state->inleaf = 0;
-		error = xfs_da3_node_lookup_int(state, &retval);
-		if (error)
-			goto out;
+			ASSERT(nmap == 1);
+			ASSERT((map->br_startblock != DELAYSTARTBLOCK) &&
+			       (map->br_startblock != HOLESTARTBLOCK));
 
-		/*
-		 * Remove the name and update the hashvals in the tree.
-		 */
-		blk = &state->path.blk[ state->path.active-1 ];
-		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
-		error = xfs_attr3_leaf_remove(blk->bp, args);
-		xfs_da3_fixhashpath(state, &state->path);
+			/* roll attribute extent map forwards */
+			args->dc.lblkno += map->br_blockcount;
+			args->dc.blkcnt -= map->br_blockcount;
 
-		/*
-		 * Check to see if the tree needs to be collapsed.
-		 */
-		if (retval && (state->path.active > 1)) {
-			error = xfs_da3_join(state);
-			if (error)
-				goto out;
-			error = xfs_defer_finish(&args->trans);
-			if (error)
-				goto out;
+			args->dc.dc_state = XFS_DC_ALLOC_NODE;
+			return -EAGAIN;
 		}
 
-		/*
-		 * Commit and start the next trans in the chain.
-		 */
-		error = xfs_trans_roll_inode(&args->trans, dp);
+		error = xfs_attr_rmtval_set_value(args);
 		if (error)
-			goto out;
+			return error;
+	}
 
-	} else if (args->rmtblkno > 0) {
+	if (args->rmtblkno > 0) {
 		/*
 		 * Added a "remote" value, just clear the incomplete flag.
 		 */
 		error = xfs_attr3_leaf_clearflag(args);
 		if (error)
 			goto out;
-
-		 /*
-		  * Commit the flag value change and start the next trans in
-		  * series.
-		  */
-		error = xfs_trans_roll_inode(&args->trans, args->dp);
-		if (error)
-			goto out;
 	}
 	retval = error = 0;
 
diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
index fb8bf5b..c710387 100644
--- a/fs/xfs/libxfs/xfs_attr.h
+++ b/fs/xfs/libxfs/xfs_attr.h
@@ -149,6 +149,7 @@ int xfs_attr_get(struct xfs_inode *ip, struct xfs_name *name,
 int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
 		 unsigned char *value, int valuelen, int flags);
 int xfs_attr_set_args(struct xfs_da_args *args);
+int xfs_attr_set_later(struct xfs_da_args *args, struct xfs_buf **leaf_bp);
 int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
 int xfs_has_attr(struct xfs_da_args *args);
 int xfs_attr_remove_args(struct xfs_da_args *args);
-- 
2.7.4


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

* Re: [PATCH v4 02/17] xfs: Replace attribute parameters with struct xfs_name
  2019-11-07  1:27 ` [PATCH v4 02/17] xfs: Replace attribute parameters with struct xfs_name Allison Collins
@ 2019-11-08  1:13   ` Darrick J. Wong
  2019-11-08 17:16     ` Allison Collins
  2019-11-11 17:49   ` Christoph Hellwig
  1 sibling, 1 reply; 77+ messages in thread
From: Darrick J. Wong @ 2019-11-08  1:13 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Wed, Nov 06, 2019 at 06:27:46PM -0700, Allison Collins wrote:
> This patch replaces the attribute name and length parameters with a
> single struct xfs_name parameter.  This helps to clean up the numbers of
> parameters being passed around and pre-simplifies the code some.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 22 +++++++++-------------
>  fs/xfs/libxfs/xfs_attr.h | 12 +++++-------
>  fs/xfs/xfs_acl.c         | 27 +++++++++++++--------------
>  fs/xfs/xfs_ioctl.c       | 25 +++++++++++++++----------
>  fs/xfs/xfs_iops.c        |  9 ++++++---
>  fs/xfs/xfs_xattr.c       | 25 +++++++++++++++----------
>  6 files changed, 63 insertions(+), 57 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 7589cb7..5a9624a 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -61,8 +61,7 @@ STATIC int
>  xfs_attr_args_init(
>  	struct xfs_da_args	*args,
>  	struct xfs_inode	*dp,
> -	const unsigned char	*name,
> -	size_t			namelen,
> +	struct xfs_name		*name,
>  	int			flags)
>  {
>  
> @@ -74,8 +73,8 @@ xfs_attr_args_init(
>  	args->whichfork = XFS_ATTR_FORK;
>  	args->dp = dp;
>  	args->flags = flags;
> -	args->name = name;
> -	args->namelen = namelen;
> +	args->name = name->name;
> +	args->namelen = name->len;
>  	if (args->namelen >= MAXNAMELEN)
>  		return -EFAULT;		/* match IRIX behaviour */
>  
> @@ -139,8 +138,7 @@ xfs_attr_get_ilocked(
>  int
>  xfs_attr_get(
>  	struct xfs_inode	*ip,
> -	const unsigned char	*name,
> -	size_t			namelen,
> +	struct xfs_name		*name,
>  	unsigned char		**value,
>  	int			*valuelenp,
>  	int			flags)
> @@ -156,7 +154,7 @@ xfs_attr_get(
>  	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
>  		return -EIO;
>  
> -	error = xfs_attr_args_init(&args, ip, name, namelen, flags);
> +	error = xfs_attr_args_init(&args, ip, name, flags);
>  	if (error)
>  		return error;
>  
> @@ -339,8 +337,7 @@ xfs_attr_remove_args(
>  int
>  xfs_attr_set(
>  	struct xfs_inode	*dp,
> -	const unsigned char	*name,
> -	size_t			namelen,
> +	struct xfs_name		*name,
>  	unsigned char		*value,
>  	int			valuelen,
>  	int			flags)
> @@ -356,7 +353,7 @@ xfs_attr_set(
>  	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
>  		return -EIO;
>  
> -	error = xfs_attr_args_init(&args, dp, name, namelen, flags);
> +	error = xfs_attr_args_init(&args, dp, name, flags);
>  	if (error)
>  		return error;
>  
> @@ -444,8 +441,7 @@ xfs_attr_set(
>  int
>  xfs_attr_remove(
>  	struct xfs_inode	*dp,
> -	const unsigned char	*name,
> -	size_t			namelen,
> +	struct xfs_name		*name,
>  	int			flags)
>  {
>  	struct xfs_mount	*mp = dp->i_mount;
> @@ -457,7 +453,7 @@ xfs_attr_remove(
>  	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
>  		return -EIO;
>  
> -	error = xfs_attr_args_init(&args, dp, name, namelen, flags);
> +	error = xfs_attr_args_init(&args, dp, name, flags);
>  	if (error)
>  		return error;
>  
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index 106a2f2..44dd07a 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -144,14 +144,12 @@ int xfs_attr_list_int_ilocked(struct xfs_attr_list_context *);
>  int xfs_attr_list_int(struct xfs_attr_list_context *);
>  int xfs_inode_hasattr(struct xfs_inode *ip);
>  int xfs_attr_get_ilocked(struct xfs_inode *ip, struct xfs_da_args *args);
> -int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
> -		 size_t namelen, unsigned char **value, int *valuelenp,
> -		 int flags);
> -int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
> -		 size_t namelen, unsigned char *value, int valuelen, int flags);
> +int xfs_attr_get(struct xfs_inode *ip, struct xfs_name *name,
> +		 unsigned char **value, int *valuelenp, int flags);
> +int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
> +		 unsigned char *value, int valuelen, int flags);
>  int xfs_attr_set_args(struct xfs_da_args *args);
> -int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name,
> -		    size_t namelen, int flags);
> +int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
>  int xfs_attr_remove_args(struct xfs_da_args *args);
>  int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>  		  int flags, struct attrlist_cursor_kern *cursor);
> diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
> index 12be708..e868755 100644
> --- a/fs/xfs/xfs_acl.c
> +++ b/fs/xfs/xfs_acl.c
> @@ -113,7 +113,7 @@ xfs_get_acl(struct inode *inode, int type)
>  	struct xfs_inode *ip = XFS_I(inode);
>  	struct posix_acl *acl = NULL;
>  	struct xfs_acl *xfs_acl = NULL;
> -	unsigned char *ea_name;
> +	struct xfs_name name;
>  	int error;
>  	int len;
>  
> @@ -121,10 +121,10 @@ xfs_get_acl(struct inode *inode, int type)
>  
>  	switch (type) {
>  	case ACL_TYPE_ACCESS:
> -		ea_name = SGI_ACL_FILE;
> +		name.name = SGI_ACL_FILE;
>  		break;
>  	case ACL_TYPE_DEFAULT:
> -		ea_name = SGI_ACL_DEFAULT;
> +		name.name = SGI_ACL_DEFAULT;
>  		break;
>  	default:
>  		BUG();
> @@ -135,9 +135,9 @@ xfs_get_acl(struct inode *inode, int type)
>  	 * go out to the disk.
>  	 */
>  	len = XFS_ACL_MAX_SIZE(ip->i_mount);
> -	error = xfs_attr_get(ip, ea_name, strlen(ea_name), 
> -				(unsigned char **)&xfs_acl, &len,
> -				ATTR_ALLOC | ATTR_ROOT);
> +	name.len = strlen(name.name);
> +	error = xfs_attr_get(ip, &name, (unsigned char **)&xfs_acl, &len,
> +			     ATTR_ALLOC | ATTR_ROOT);
>  	if (error) {
>  		/*
>  		 * If the attribute doesn't exist make sure we have a negative
> @@ -157,17 +157,17 @@ int
>  __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
>  {
>  	struct xfs_inode *ip = XFS_I(inode);
> -	unsigned char *ea_name;
> +	struct xfs_name name;
>  	int error;
>  
>  	switch (type) {
>  	case ACL_TYPE_ACCESS:
> -		ea_name = SGI_ACL_FILE;
> +		name.name = SGI_ACL_FILE;
>  		break;
>  	case ACL_TYPE_DEFAULT:
>  		if (!S_ISDIR(inode->i_mode))
>  			return acl ? -EACCES : 0;
> -		ea_name = SGI_ACL_DEFAULT;
> +		name.name = SGI_ACL_DEFAULT;
>  		break;
>  	default:
>  		return -EINVAL;
> @@ -187,17 +187,16 @@ __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
>  		len -= sizeof(struct xfs_acl_entry) *
>  			 (XFS_ACL_MAX_ENTRIES(ip->i_mount) - acl->a_count);
>  
> -		error = xfs_attr_set(ip, ea_name, strlen(ea_name),
> -				     (unsigned char *)xfs_acl, len, ATTR_ROOT);
> +		name.len = strlen(name.name);

/me wonders if you ought to write a helper function to initialize an
xfs_name and calculate name->len instead of open coding it here
because...

> +		error = xfs_attr_set(ip, &name, (unsigned char *)xfs_acl, len,
> +				     ATTR_ROOT);
>  
>  		kmem_free(xfs_acl);
>  	} else {
>  		/*
>  		 * A NULL ACL argument means we want to remove the ACL.
>  		 */
> -		error = xfs_attr_remove(ip, ea_name,
> -					strlen(ea_name),
> -					ATTR_ROOT);
> +		error = xfs_attr_remove(ip, &name, ATTR_ROOT);

..I think name.len is uninitialized here?

--D

>  
>  		/*
>  		 * If the attribute didn't exist to start with that's fine.
> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> index 269c321..ae0ed88 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -432,7 +432,10 @@ xfs_attrmulti_attr_get(
>  {
>  	unsigned char		*kbuf;
>  	int			error = -EFAULT;
> -	size_t			namelen;
> +	struct xfs_name		xname = {
> +		.name		= name,
> +		.len		= strlen(name),
> +	};
>  
>  	if (*len > XFS_XATTR_SIZE_MAX)
>  		return -EINVAL;
> @@ -440,9 +443,7 @@ xfs_attrmulti_attr_get(
>  	if (!kbuf)
>  		return -ENOMEM;
>  
> -	namelen = strlen(name);
> -	error = xfs_attr_get(XFS_I(inode), name, namelen, &kbuf, (int *)len,
> -			     flags);
> +	error = xfs_attr_get(XFS_I(inode), &xname, &kbuf, (int *)len, flags);
>  	if (error)
>  		goto out_kfree;
>  
> @@ -464,7 +465,7 @@ xfs_attrmulti_attr_set(
>  {
>  	unsigned char		*kbuf;
>  	int			error;
> -	size_t			namelen;
> +	struct xfs_name		xname;
>  
>  	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
>  		return -EPERM;
> @@ -475,8 +476,9 @@ xfs_attrmulti_attr_set(
>  	if (IS_ERR(kbuf))
>  		return PTR_ERR(kbuf);
>  
> -	namelen = strlen(name);
> -	error = xfs_attr_set(XFS_I(inode), name, namelen, kbuf, len, flags);
> +	xname.name = name;
> +	xname.len = strlen(name);
> +	error = xfs_attr_set(XFS_I(inode), &xname, kbuf, len, flags);
>  	if (!error)
>  		xfs_forget_acl(inode, name, flags);
>  	kfree(kbuf);
> @@ -490,12 +492,15 @@ xfs_attrmulti_attr_remove(
>  	uint32_t		flags)
>  {
>  	int			error;
> -	size_t			namelen;
> +	struct xfs_name		xname = {
> +		.name		= name,
> +		.len		= strlen(name),
> +	};
>  
>  	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
>  		return -EPERM;
> -	namelen = strlen(name);
> -	error = xfs_attr_remove(XFS_I(inode), name, namelen, flags);
> +
> +	error = xfs_attr_remove(XFS_I(inode), &xname, flags);
>  	if (!error)
>  		xfs_forget_acl(inode, name, flags);
>  	return error;
> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> index 7f47f87..aef346e 100644
> --- a/fs/xfs/xfs_iops.c
> +++ b/fs/xfs/xfs_iops.c
> @@ -49,9 +49,12 @@ xfs_initxattrs(
>  	int			error = 0;
>  
>  	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
> -		error = xfs_attr_set(ip, xattr->name,
> -				     strlen(xattr->name),
> -				     xattr->value, xattr->value_len,
> +		struct xfs_name	name = {
> +			.name	= xattr->name,
> +			.len	= strlen(xattr->name),
> +		};
> +
> +		error = xfs_attr_set(ip, &name, xattr->value, xattr->value_len,
>  				     ATTR_SECURE);
>  		if (error < 0)
>  			break;
> diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
> index 59ffe6c..6c5321d 100644
> --- a/fs/xfs/xfs_xattr.c
> +++ b/fs/xfs/xfs_xattr.c
> @@ -20,10 +20,13 @@ static int
>  xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
>  		struct inode *inode, const char *name, void *value, size_t size)
>  {
> -	int xflags = handler->flags;
> -	struct xfs_inode *ip = XFS_I(inode);
> -	int error, asize = size;
> -	size_t namelen = strlen(name);
> +	int			xflags = handler->flags;
> +	struct xfs_inode	*ip = XFS_I(inode);
> +	int			error, asize = size;
> +	struct xfs_name		xname = {
> +		.name		= name,
> +		.len		= strlen(name),
> +	};
>  
>  	/* Convert Linux syscall to XFS internal ATTR flags */
>  	if (!size) {
> @@ -31,8 +34,8 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
>  		value = NULL;
>  	}
>  
> -	error = xfs_attr_get(ip, name, namelen, (unsigned char **)&value,
> -			     &asize, xflags);
> +	error = xfs_attr_get(ip, &xname, (unsigned char **)&value, &asize,
> +			     xflags);
>  	if (error)
>  		return error;
>  	return asize;
> @@ -68,7 +71,10 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
>  	int			xflags = handler->flags;
>  	struct xfs_inode	*ip = XFS_I(inode);
>  	int			error;
> -	size_t			namelen = strlen(name);
> +	struct xfs_name		xname = {
> +		.name		= name,
> +		.len		= strlen(name),
> +	};
>  
>  	/* Convert Linux syscall to XFS internal ATTR flags */
>  	if (flags & XATTR_CREATE)
> @@ -77,9 +83,8 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
>  		xflags |= ATTR_REPLACE;
>  
>  	if (!value)
> -		return xfs_attr_remove(ip, name,
> -				       namelen, xflags);
> -	error = xfs_attr_set(ip, name, namelen, (void *)value, size, xflags);
> +		return xfs_attr_remove(ip, &xname, xflags);
> +	error = xfs_attr_set(ip, &xname, (void *)value, size, xflags);
>  	if (!error)
>  		xfs_forget_acl(inode, name, xflags);
>  
> -- 
> 2.7.4
> 

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

* Re: [PATCH v4 03/17] xfs: Embed struct xfs_name in xfs_da_args
  2019-11-07  1:27 ` [PATCH v4 03/17] xfs: Embed struct xfs_name in xfs_da_args Allison Collins
@ 2019-11-08  1:25   ` Darrick J. Wong
  2019-11-08 16:11     ` Allison Collins
  0 siblings, 1 reply; 77+ messages in thread
From: Darrick J. Wong @ 2019-11-08  1:25 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Wed, Nov 06, 2019 at 06:27:47PM -0700, Allison Collins wrote:
> This patch embeds an xfs_name in xfs_da_args, replacing the name,
> namelen, and flags members.  This helps to clean up the xfs_da_args
> structure and make it more uniform with the new xfs_name parameter
> being passed around.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Brian Foster <bfoster@redhat.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c        |  36 +++++++-------
>  fs/xfs/libxfs/xfs_attr_leaf.c   | 106 +++++++++++++++++++++-------------------
>  fs/xfs/libxfs/xfs_attr_remote.c |   2 +-
>  fs/xfs/libxfs/xfs_da_btree.c    |   5 +-
>  fs/xfs/libxfs/xfs_da_btree.h    |   4 +-
>  fs/xfs/libxfs/xfs_dir2.c        |  18 +++----
>  fs/xfs/libxfs/xfs_dir2_block.c  |   6 +--
>  fs/xfs/libxfs/xfs_dir2_leaf.c   |   6 +--
>  fs/xfs/libxfs/xfs_dir2_node.c   |   8 +--
>  fs/xfs/libxfs/xfs_dir2_sf.c     |  30 ++++++------
>  fs/xfs/scrub/attr.c             |  12 ++---
>  fs/xfs/xfs_trace.h              |  20 ++++----
>  12 files changed, 128 insertions(+), 125 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 5a9624a..b77b985 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -72,13 +72,12 @@ xfs_attr_args_init(
>  	args->geo = dp->i_mount->m_attr_geo;
>  	args->whichfork = XFS_ATTR_FORK;
>  	args->dp = dp;
> -	args->flags = flags;
> -	args->name = name->name;
> -	args->namelen = name->len;
> -	if (args->namelen >= MAXNAMELEN)
> +	name->type = flags;

Is there a purpose for modifying the caller's @name, instead of setting
args.name.type = flags after the memcpy?

> +	memcpy(&args->name, name, sizeof(struct xfs_name));
> +	if (args->name.len >= MAXNAMELEN)
>  		return -EFAULT;		/* match IRIX behaviour */
>  
> -	args->hashval = xfs_da_hashname(args->name, args->namelen);
> +	args->hashval = xfs_da_hashname(args->name.name, args->name.len);
>  	return 0;
>  }
>  
> @@ -236,7 +235,7 @@ xfs_attr_try_sf_addname(
>  	 * Commit the shortform mods, and we're done.
>  	 * NOTE: this is also the error path (EEXIST, etc).
>  	 */
> -	if (!error && (args->flags & ATTR_KERNOTIME) == 0)
> +	if (!error && (args->name.type & ATTR_KERNOTIME) == 0)
>  		xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
>  
>  	if (mp->m_flags & XFS_MOUNT_WSYNC)
> @@ -357,6 +356,9 @@ xfs_attr_set(
>  	if (error)
>  		return error;
>  
> +	/* Use name now stored in args */
> +	name = &args.name;

You could probably set this as part of the variable declaration, e.g.

struct xfs_name		*name = &args.name;

> +
>  	args.value = value;
>  	args.valuelen = valuelen;
>  	args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
> @@ -372,7 +374,7 @@ xfs_attr_set(
>  	 */
>  	if (XFS_IFORK_Q(dp) == 0) {
>  		int sf_size = sizeof(xfs_attr_sf_hdr_t) +
> -			XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, valuelen);
> +			XFS_ATTR_SF_ENTSIZE_BYNAME(args.name.len, valuelen);

If you're going to keep the convenience variable @name, then please use
it throughout the function.

>  
>  		error = xfs_bmap_add_attrfork(dp, sf_size, rsvd);
>  		if (error)

<snip>

> diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c
> index 4fd1223..129ec09 100644
> --- a/fs/xfs/libxfs/xfs_da_btree.c
> +++ b/fs/xfs/libxfs/xfs_da_btree.c
> @@ -2040,8 +2040,9 @@ xfs_da_compname(
>  	const unsigned char *name,
>  	int		len)
>  {
> -	return (args->namelen == len && memcmp(args->name, name, len) == 0) ?
> -					XFS_CMP_EXACT : XFS_CMP_DIFFERENT;

Wow that's gross. :)

	if (args->name.len == len && !memcmp(args->name.name, name, len))
		return XFS_CMP_EXACT;

	return XFS_CMP_DIFFERENT;

Hmm, is that better?

The rest looks reasonable...

--D

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

* Re: [PATCH v4 03/17] xfs: Embed struct xfs_name in xfs_da_args
  2019-11-08  1:25   ` Darrick J. Wong
@ 2019-11-08 16:11     ` Allison Collins
  2019-11-08 21:47       ` Darrick J. Wong
  0 siblings, 1 reply; 77+ messages in thread
From: Allison Collins @ 2019-11-08 16:11 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 11/7/19 6:25 PM, Darrick J. Wong wrote:
> On Wed, Nov 06, 2019 at 06:27:47PM -0700, Allison Collins wrote:
>> This patch embeds an xfs_name in xfs_da_args, replacing the name,
>> namelen, and flags members.  This helps to clean up the xfs_da_args
>> structure and make it more uniform with the new xfs_name parameter
>> being passed around.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> Reviewed-by: Brian Foster <bfoster@redhat.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c        |  36 +++++++-------
>>   fs/xfs/libxfs/xfs_attr_leaf.c   | 106 +++++++++++++++++++++-------------------
>>   fs/xfs/libxfs/xfs_attr_remote.c |   2 +-
>>   fs/xfs/libxfs/xfs_da_btree.c    |   5 +-
>>   fs/xfs/libxfs/xfs_da_btree.h    |   4 +-
>>   fs/xfs/libxfs/xfs_dir2.c        |  18 +++----
>>   fs/xfs/libxfs/xfs_dir2_block.c  |   6 +--
>>   fs/xfs/libxfs/xfs_dir2_leaf.c   |   6 +--
>>   fs/xfs/libxfs/xfs_dir2_node.c   |   8 +--
>>   fs/xfs/libxfs/xfs_dir2_sf.c     |  30 ++++++------
>>   fs/xfs/scrub/attr.c             |  12 ++---
>>   fs/xfs/xfs_trace.h              |  20 ++++----
>>   12 files changed, 128 insertions(+), 125 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 5a9624a..b77b985 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -72,13 +72,12 @@ xfs_attr_args_init(
>>   	args->geo = dp->i_mount->m_attr_geo;
>>   	args->whichfork = XFS_ATTR_FORK;
>>   	args->dp = dp;
>> -	args->flags = flags;
>> -	args->name = name->name;
>> -	args->namelen = name->len;
>> -	if (args->namelen >= MAXNAMELEN)
>> +	name->type = flags;
> 
> Is there a purpose for modifying the caller's @name, instead of setting
> args.name.type = flags after the memcpy?
Not really other than to just make them consistent so that the mem copy 
would cover all three members.  I think initially they were set 
individually, but people preferred the memcpy, and then later we decided 
to break the flags variable out of the name struct.  I can explicitly 
set args.name.type if folks prefer.

A subtle pitfall I noticed about using the name struct like this now: 
callers need to take care to abandon the original name struct or update 
the original pointer to this struct.  It's kind of easy to continue 
using the original struct like it's a convenience pointer, but it not 
the same memory so if args gets passed into some subroutine that 
modifies it, now you're out of sync.  If it doesnt get passed around or 
modified, it doesnt matter, but we've created a sort of usage rule about 
how to handle the name param which may not be entirely obvious to other 
developers.

> 
>> +	memcpy(&args->name, name, sizeof(struct xfs_name));
>> +	if (args->name.len >= MAXNAMELEN)
>>   		return -EFAULT;		/* match IRIX behaviour */
>>   
>> -	args->hashval = xfs_da_hashname(args->name, args->namelen);
>> +	args->hashval = xfs_da_hashname(args->name.name, args->name.len);
>>   	return 0;
>>   }
>>   
>> @@ -236,7 +235,7 @@ xfs_attr_try_sf_addname(
>>   	 * Commit the shortform mods, and we're done.
>>   	 * NOTE: this is also the error path (EEXIST, etc).
>>   	 */
>> -	if (!error && (args->flags & ATTR_KERNOTIME) == 0)
>> +	if (!error && (args->name.type & ATTR_KERNOTIME) == 0)
>>   		xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
>>   
>>   	if (mp->m_flags & XFS_MOUNT_WSYNC)
>> @@ -357,6 +356,9 @@ xfs_attr_set(
>>   	if (error)
>>   		return error;
>>   
>> +	/* Use name now stored in args */
>> +	name = &args.name;
> 
> You could probably set this as part of the variable declaration, e.g.
> 
> struct xfs_name		*name = &args.name;
No, because name is a parameter here, so you would loose the contents at 
the start of the function if we did this.  And then args init would 
memcopy and empty struct onto itself.  And then confusion would 
ensue.... :-(

> 
>> +
>>   	args.value = value;
>>   	args.valuelen = valuelen;
>>   	args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
>> @@ -372,7 +374,7 @@ xfs_attr_set(
>>   	 */
>>   	if (XFS_IFORK_Q(dp) == 0) {
>>   		int sf_size = sizeof(xfs_attr_sf_hdr_t) +
>> -			XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, valuelen);
>> +			XFS_ATTR_SF_ENTSIZE_BYNAME(args.name.len, valuelen);
> 
> If you're going to keep the convenience variable @name, then please use
> it throughout the function.
I think this is the only place it's used for this function at this time. 
  I use it later in patch 15 though.  I think I stumbled across the name 
sync bug then, and corrected it with the parameter pointer assignment 
above just because it seemed like the right place to fix it.

Do you want the function to uniformly use an explicit reference, or the 
param?  Seems like a bit of a wart unfortunately :-(

> 
>>   
>>   		error = xfs_bmap_add_attrfork(dp, sf_size, rsvd);
>>   		if (error)
> 
> <snip>
> 
>> diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c
>> index 4fd1223..129ec09 100644
>> --- a/fs/xfs/libxfs/xfs_da_btree.c
>> +++ b/fs/xfs/libxfs/xfs_da_btree.c
>> @@ -2040,8 +2040,9 @@ xfs_da_compname(
>>   	const unsigned char *name,
>>   	int		len)
>>   {
>> -	return (args->namelen == len && memcmp(args->name, name, len) == 0) ?
>> -					XFS_CMP_EXACT : XFS_CMP_DIFFERENT;
> 
> Wow that's gross. :)
> 
> 	if (args->name.len == len && !memcmp(args->name.name, name, len))
> 		return XFS_CMP_EXACT;
> 
> 	return XFS_CMP_DIFFERENT;
> 
> Hmm, is that better?
Sure, will fix.

Allison

> 
> The rest looks reasonable...
> 
> --D
> 

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

* Re: [PATCH v4 02/17] xfs: Replace attribute parameters with struct xfs_name
  2019-11-08  1:13   ` Darrick J. Wong
@ 2019-11-08 17:16     ` Allison Collins
  0 siblings, 0 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-08 17:16 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 11/7/19 6:13 PM, Darrick J. Wong wrote:
> On Wed, Nov 06, 2019 at 06:27:46PM -0700, Allison Collins wrote:
>> This patch replaces the attribute name and length parameters with a
>> single struct xfs_name parameter.  This helps to clean up the numbers of
>> parameters being passed around and pre-simplifies the code some.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 22 +++++++++-------------
>>   fs/xfs/libxfs/xfs_attr.h | 12 +++++-------
>>   fs/xfs/xfs_acl.c         | 27 +++++++++++++--------------
>>   fs/xfs/xfs_ioctl.c       | 25 +++++++++++++++----------
>>   fs/xfs/xfs_iops.c        |  9 ++++++---
>>   fs/xfs/xfs_xattr.c       | 25 +++++++++++++++----------
>>   6 files changed, 63 insertions(+), 57 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 7589cb7..5a9624a 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -61,8 +61,7 @@ STATIC int
>>   xfs_attr_args_init(
>>   	struct xfs_da_args	*args,
>>   	struct xfs_inode	*dp,
>> -	const unsigned char	*name,
>> -	size_t			namelen,
>> +	struct xfs_name		*name,
>>   	int			flags)
>>   {
>>   
>> @@ -74,8 +73,8 @@ xfs_attr_args_init(
>>   	args->whichfork = XFS_ATTR_FORK;
>>   	args->dp = dp;
>>   	args->flags = flags;
>> -	args->name = name;
>> -	args->namelen = namelen;
>> +	args->name = name->name;
>> +	args->namelen = name->len;
>>   	if (args->namelen >= MAXNAMELEN)
>>   		return -EFAULT;		/* match IRIX behaviour */
>>   
>> @@ -139,8 +138,7 @@ xfs_attr_get_ilocked(
>>   int
>>   xfs_attr_get(
>>   	struct xfs_inode	*ip,
>> -	const unsigned char	*name,
>> -	size_t			namelen,
>> +	struct xfs_name		*name,
>>   	unsigned char		**value,
>>   	int			*valuelenp,
>>   	int			flags)
>> @@ -156,7 +154,7 @@ xfs_attr_get(
>>   	if (XFS_FORCED_SHUTDOWN(ip->i_mount))
>>   		return -EIO;
>>   
>> -	error = xfs_attr_args_init(&args, ip, name, namelen, flags);
>> +	error = xfs_attr_args_init(&args, ip, name, flags);
>>   	if (error)
>>   		return error;
>>   
>> @@ -339,8 +337,7 @@ xfs_attr_remove_args(
>>   int
>>   xfs_attr_set(
>>   	struct xfs_inode	*dp,
>> -	const unsigned char	*name,
>> -	size_t			namelen,
>> +	struct xfs_name		*name,
>>   	unsigned char		*value,
>>   	int			valuelen,
>>   	int			flags)
>> @@ -356,7 +353,7 @@ xfs_attr_set(
>>   	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
>>   		return -EIO;
>>   
>> -	error = xfs_attr_args_init(&args, dp, name, namelen, flags);
>> +	error = xfs_attr_args_init(&args, dp, name, flags);
>>   	if (error)
>>   		return error;
>>   
>> @@ -444,8 +441,7 @@ xfs_attr_set(
>>   int
>>   xfs_attr_remove(
>>   	struct xfs_inode	*dp,
>> -	const unsigned char	*name,
>> -	size_t			namelen,
>> +	struct xfs_name		*name,
>>   	int			flags)
>>   {
>>   	struct xfs_mount	*mp = dp->i_mount;
>> @@ -457,7 +453,7 @@ xfs_attr_remove(
>>   	if (XFS_FORCED_SHUTDOWN(dp->i_mount))
>>   		return -EIO;
>>   
>> -	error = xfs_attr_args_init(&args, dp, name, namelen, flags);
>> +	error = xfs_attr_args_init(&args, dp, name, flags);
>>   	if (error)
>>   		return error;
>>   
>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>> index 106a2f2..44dd07a 100644
>> --- a/fs/xfs/libxfs/xfs_attr.h
>> +++ b/fs/xfs/libxfs/xfs_attr.h
>> @@ -144,14 +144,12 @@ int xfs_attr_list_int_ilocked(struct xfs_attr_list_context *);
>>   int xfs_attr_list_int(struct xfs_attr_list_context *);
>>   int xfs_inode_hasattr(struct xfs_inode *ip);
>>   int xfs_attr_get_ilocked(struct xfs_inode *ip, struct xfs_da_args *args);
>> -int xfs_attr_get(struct xfs_inode *ip, const unsigned char *name,
>> -		 size_t namelen, unsigned char **value, int *valuelenp,
>> -		 int flags);
>> -int xfs_attr_set(struct xfs_inode *dp, const unsigned char *name,
>> -		 size_t namelen, unsigned char *value, int valuelen, int flags);
>> +int xfs_attr_get(struct xfs_inode *ip, struct xfs_name *name,
>> +		 unsigned char **value, int *valuelenp, int flags);
>> +int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
>> +		 unsigned char *value, int valuelen, int flags);
>>   int xfs_attr_set_args(struct xfs_da_args *args);
>> -int xfs_attr_remove(struct xfs_inode *dp, const unsigned char *name,
>> -		    size_t namelen, int flags);
>> +int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
>>   int xfs_attr_remove_args(struct xfs_da_args *args);
>>   int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>>   		  int flags, struct attrlist_cursor_kern *cursor);
>> diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
>> index 12be708..e868755 100644
>> --- a/fs/xfs/xfs_acl.c
>> +++ b/fs/xfs/xfs_acl.c
>> @@ -113,7 +113,7 @@ xfs_get_acl(struct inode *inode, int type)
>>   	struct xfs_inode *ip = XFS_I(inode);
>>   	struct posix_acl *acl = NULL;
>>   	struct xfs_acl *xfs_acl = NULL;
>> -	unsigned char *ea_name;
>> +	struct xfs_name name;
>>   	int error;
>>   	int len;
>>   
>> @@ -121,10 +121,10 @@ xfs_get_acl(struct inode *inode, int type)
>>   
>>   	switch (type) {
>>   	case ACL_TYPE_ACCESS:
>> -		ea_name = SGI_ACL_FILE;
>> +		name.name = SGI_ACL_FILE;
>>   		break;
>>   	case ACL_TYPE_DEFAULT:
>> -		ea_name = SGI_ACL_DEFAULT;
>> +		name.name = SGI_ACL_DEFAULT;
>>   		break;
>>   	default:
>>   		BUG();
>> @@ -135,9 +135,9 @@ xfs_get_acl(struct inode *inode, int type)
>>   	 * go out to the disk.
>>   	 */
>>   	len = XFS_ACL_MAX_SIZE(ip->i_mount);
>> -	error = xfs_attr_get(ip, ea_name, strlen(ea_name),
>> -				(unsigned char **)&xfs_acl, &len,
>> -				ATTR_ALLOC | ATTR_ROOT);
>> +	name.len = strlen(name.name);
>> +	error = xfs_attr_get(ip, &name, (unsigned char **)&xfs_acl, &len,
>> +			     ATTR_ALLOC | ATTR_ROOT);
>>   	if (error) {
>>   		/*
>>   		 * If the attribute doesn't exist make sure we have a negative
>> @@ -157,17 +157,17 @@ int
>>   __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
>>   {
>>   	struct xfs_inode *ip = XFS_I(inode);
>> -	unsigned char *ea_name;
>> +	struct xfs_name name;
>>   	int error;
>>   
>>   	switch (type) {
>>   	case ACL_TYPE_ACCESS:
>> -		ea_name = SGI_ACL_FILE;
>> +		name.name = SGI_ACL_FILE;
>>   		break;
>>   	case ACL_TYPE_DEFAULT:
>>   		if (!S_ISDIR(inode->i_mode))
>>   			return acl ? -EACCES : 0;
>> -		ea_name = SGI_ACL_DEFAULT;
>> +		name.name = SGI_ACL_DEFAULT;
>>   		break;
>>   	default:
>>   		return -EINVAL;
>> @@ -187,17 +187,16 @@ __xfs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
>>   		len -= sizeof(struct xfs_acl_entry) *
>>   			 (XFS_ACL_MAX_ENTRIES(ip->i_mount) - acl->a_count);
>>   
>> -		error = xfs_attr_set(ip, ea_name, strlen(ea_name),
>> -				     (unsigned char *)xfs_acl, len, ATTR_ROOT);
>> +		name.len = strlen(name.name);
> 
> /me wonders if you ought to write a helper function to initialize an
> xfs_name and calculate name->len instead of open coding it here
> because...
Ok, I think in one of the previous reviews we decided on an explicit 
struct initialization.  It works in most cases, but just couldn't be 
applied here because of the case handling.  I'm not sure how opinionated 
people really are about though?

> 
>> +		error = xfs_attr_set(ip, &name, (unsigned char *)xfs_acl, len,
>> +				     ATTR_ROOT);
>>   
>>   		kmem_free(xfs_acl);
>>   	} else {
>>   		/*
>>   		 * A NULL ACL argument means we want to remove the ACL.
>>   		 */
>> -		error = xfs_attr_remove(ip, ea_name,
>> -					strlen(ea_name),
>> -					ATTR_ROOT);
>> +		error = xfs_attr_remove(ip, &name, ATTR_ROOT);
> 
Ok, will fix.  Thanks for catch!

Allison

> ..I think name.len is uninitialized here?
> 
> --D
> 
>>   
>>   		/*
>>   		 * If the attribute didn't exist to start with that's fine.
>> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
>> index 269c321..ae0ed88 100644
>> --- a/fs/xfs/xfs_ioctl.c
>> +++ b/fs/xfs/xfs_ioctl.c
>> @@ -432,7 +432,10 @@ xfs_attrmulti_attr_get(
>>   {
>>   	unsigned char		*kbuf;
>>   	int			error = -EFAULT;
>> -	size_t			namelen;
>> +	struct xfs_name		xname = {
>> +		.name		= name,
>> +		.len		= strlen(name),
>> +	};
>>   
>>   	if (*len > XFS_XATTR_SIZE_MAX)
>>   		return -EINVAL;
>> @@ -440,9 +443,7 @@ xfs_attrmulti_attr_get(
>>   	if (!kbuf)
>>   		return -ENOMEM;
>>   
>> -	namelen = strlen(name);
>> -	error = xfs_attr_get(XFS_I(inode), name, namelen, &kbuf, (int *)len,
>> -			     flags);
>> +	error = xfs_attr_get(XFS_I(inode), &xname, &kbuf, (int *)len, flags);
>>   	if (error)
>>   		goto out_kfree;
>>   
>> @@ -464,7 +465,7 @@ xfs_attrmulti_attr_set(
>>   {
>>   	unsigned char		*kbuf;
>>   	int			error;
>> -	size_t			namelen;
>> +	struct xfs_name		xname;
>>   
>>   	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
>>   		return -EPERM;
>> @@ -475,8 +476,9 @@ xfs_attrmulti_attr_set(
>>   	if (IS_ERR(kbuf))
>>   		return PTR_ERR(kbuf);
>>   
>> -	namelen = strlen(name);
>> -	error = xfs_attr_set(XFS_I(inode), name, namelen, kbuf, len, flags);
>> +	xname.name = name;
>> +	xname.len = strlen(name);
>> +	error = xfs_attr_set(XFS_I(inode), &xname, kbuf, len, flags);
>>   	if (!error)
>>   		xfs_forget_acl(inode, name, flags);
>>   	kfree(kbuf);
>> @@ -490,12 +492,15 @@ xfs_attrmulti_attr_remove(
>>   	uint32_t		flags)
>>   {
>>   	int			error;
>> -	size_t			namelen;
>> +	struct xfs_name		xname = {
>> +		.name		= name,
>> +		.len		= strlen(name),
>> +	};
>>   
>>   	if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
>>   		return -EPERM;
>> -	namelen = strlen(name);
>> -	error = xfs_attr_remove(XFS_I(inode), name, namelen, flags);
>> +
>> +	error = xfs_attr_remove(XFS_I(inode), &xname, flags);
>>   	if (!error)
>>   		xfs_forget_acl(inode, name, flags);
>>   	return error;
>> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
>> index 7f47f87..aef346e 100644
>> --- a/fs/xfs/xfs_iops.c
>> +++ b/fs/xfs/xfs_iops.c
>> @@ -49,9 +49,12 @@ xfs_initxattrs(
>>   	int			error = 0;
>>   
>>   	for (xattr = xattr_array; xattr->name != NULL; xattr++) {
>> -		error = xfs_attr_set(ip, xattr->name,
>> -				     strlen(xattr->name),
>> -				     xattr->value, xattr->value_len,
>> +		struct xfs_name	name = {
>> +			.name	= xattr->name,
>> +			.len	= strlen(xattr->name),
>> +		};
>> +
>> +		error = xfs_attr_set(ip, &name, xattr->value, xattr->value_len,
>>   				     ATTR_SECURE);
>>   		if (error < 0)
>>   			break;
>> diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
>> index 59ffe6c..6c5321d 100644
>> --- a/fs/xfs/xfs_xattr.c
>> +++ b/fs/xfs/xfs_xattr.c
>> @@ -20,10 +20,13 @@ static int
>>   xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
>>   		struct inode *inode, const char *name, void *value, size_t size)
>>   {
>> -	int xflags = handler->flags;
>> -	struct xfs_inode *ip = XFS_I(inode);
>> -	int error, asize = size;
>> -	size_t namelen = strlen(name);
>> +	int			xflags = handler->flags;
>> +	struct xfs_inode	*ip = XFS_I(inode);
>> +	int			error, asize = size;
>> +	struct xfs_name		xname = {
>> +		.name		= name,
>> +		.len		= strlen(name),
>> +	};
>>   
>>   	/* Convert Linux syscall to XFS internal ATTR flags */
>>   	if (!size) {
>> @@ -31,8 +34,8 @@ xfs_xattr_get(const struct xattr_handler *handler, struct dentry *unused,
>>   		value = NULL;
>>   	}
>>   
>> -	error = xfs_attr_get(ip, name, namelen, (unsigned char **)&value,
>> -			     &asize, xflags);
>> +	error = xfs_attr_get(ip, &xname, (unsigned char **)&value, &asize,
>> +			     xflags);
>>   	if (error)
>>   		return error;
>>   	return asize;
>> @@ -68,7 +71,10 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
>>   	int			xflags = handler->flags;
>>   	struct xfs_inode	*ip = XFS_I(inode);
>>   	int			error;
>> -	size_t			namelen = strlen(name);
>> +	struct xfs_name		xname = {
>> +		.name		= name,
>> +		.len		= strlen(name),
>> +	};
>>   
>>   	/* Convert Linux syscall to XFS internal ATTR flags */
>>   	if (flags & XATTR_CREATE)
>> @@ -77,9 +83,8 @@ xfs_xattr_set(const struct xattr_handler *handler, struct dentry *unused,
>>   		xflags |= ATTR_REPLACE;
>>   
>>   	if (!value)
>> -		return xfs_attr_remove(ip, name,
>> -				       namelen, xflags);
>> -	error = xfs_attr_set(ip, name, namelen, (void *)value, size, xflags);
>> +		return xfs_attr_remove(ip, &xname, xflags);
>> +	error = xfs_attr_set(ip, &xname, (void *)value, size, xflags);
>>   	if (!error)
>>   		xfs_forget_acl(inode, name, xflags);
>>   
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v4 04/17] xfs: Add xfs_dabuf defines
  2019-11-07  1:27 ` [PATCH v4 04/17] xfs: Add xfs_dabuf defines Allison Collins
@ 2019-11-08 19:19   ` Darrick J. Wong
  2019-11-09 17:32     ` Allison Collins
  0 siblings, 1 reply; 77+ messages in thread
From: Darrick J. Wong @ 2019-11-08 19:19 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Wed, Nov 06, 2019 at 06:27:48PM -0700, Allison Collins wrote:
> This patch adds two new defines XFS_DABUF_MAP_NOMAPPING and
> XFS_DABUF_MAP_HOLE_OK.  This helps to clean up hard numbers and
> makes the code easier to read
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c       | 14 +++++++-----
>  fs/xfs/libxfs/xfs_attr_leaf.c  | 23 +++++++++++--------
>  fs/xfs/libxfs/xfs_attr_leaf.h  |  3 +++
>  fs/xfs/libxfs/xfs_da_btree.c   | 50 ++++++++++++++++++++++++++++--------------
>  fs/xfs/libxfs/xfs_dir2_block.c |  6 +++--
>  fs/xfs/libxfs/xfs_dir2_data.c  |  3 ++-
>  fs/xfs/libxfs/xfs_dir2_leaf.c  |  9 +++++---
>  fs/xfs/libxfs/xfs_dir2_node.c  | 10 +++++----
>  fs/xfs/scrub/dabtree.c         |  6 ++---
>  fs/xfs/scrub/dir.c             |  4 +++-
>  fs/xfs/xfs_attr_inactive.c     |  6 +++--
>  fs/xfs/xfs_attr_list.c         | 16 +++++++++-----
>  12 files changed, 97 insertions(+), 53 deletions(-)

<snip>

> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
> index bb08800..017480e 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.h
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.h
> @@ -16,6 +16,9 @@ struct xfs_da_state_blk;
>  struct xfs_inode;
>  struct xfs_trans;
>  
> +#define XFS_DABUF_MAP_NOMAPPING	(-1) /* Caller doesn't have a mapping. */
> +#define XFS_DABUF_MAP_HOLE_OK	(-2) /* don't complain if we land in a hole. */

These are parameters to xfs_da_{get,read,reada}_buf, please put them
next to the declarations for those functions.

Also they probably ought to be explicitly cast to xfs_daddr_t, e.g.

/* Force a fresh lookup for the dir/attr mapping. */
#define XFS_DABUF_MAP_NOMAPPING	((xfs_daddr_t)-1)

/* Don't complain if we land in a hole. */
#define XFS_DABUF_MAP_HOLE_OK	((xfs_daddr_t)-2)

> +
>  /*
>   * Used to keep a list of "remote value" extents when unlinking an inode.
>   */

<snip>

> diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
> index 8dedc30..6bc7651 100644
> --- a/fs/xfs/libxfs/xfs_dir2_block.c
> +++ b/fs/xfs/libxfs/xfs_dir2_block.c
> @@ -20,6 +20,7 @@
>  #include "xfs_error.h"
>  #include "xfs_trace.h"
>  #include "xfs_log.h"
> +#include "xfs_attr_leaf.h"
>  
>  /*
>   * Local function prototypes.
> @@ -123,8 +124,9 @@ xfs_dir3_block_read(
>  	struct xfs_mount	*mp = dp->i_mount;
>  	int			err;
>  
> -	err = xfs_da_read_buf(tp, dp, mp->m_dir_geo->datablk, -1, bpp,
> -				XFS_DATA_FORK, &xfs_dir3_block_buf_ops);
> +	err = xfs_da_read_buf(tp, dp, mp->m_dir_geo->datablk,
> +			      XFS_DABUF_MAP_NOMAPPING, bpp, XFS_DATA_FORK,
> +			      &xfs_dir3_block_buf_ops);
>  	if (!err && tp && *bpp)
>  		xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_BLOCK_BUF);
>  	return err;

I think this misses the xfs_dir3_data_read call in
xfs_dir2_leaf_to_block?

> diff --git a/fs/xfs/libxfs/xfs_dir2_data.c b/fs/xfs/libxfs/xfs_dir2_data.c
> index 2c79be4..a4188de 100644
> --- a/fs/xfs/libxfs/xfs_dir2_data.c
> +++ b/fs/xfs/libxfs/xfs_dir2_data.c
> @@ -17,6 +17,7 @@
>  #include "xfs_trans.h"
>  #include "xfs_buf_item.h"
>  #include "xfs_log.h"
> +#include "xfs_attr_leaf.h"
>  
>  static xfs_failaddr_t xfs_dir2_data_freefind_verify(
>  		struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_data_free *bf,
> @@ -653,7 +654,7 @@ xfs_dir3_data_init(
>  	 * Get the buffer set up for the block.
>  	 */
>  	error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, blkno),
> -			       -1, &bp, XFS_DATA_FORK);
> +			       XFS_DABUF_MAP_NOMAPPING, &bp, XFS_DATA_FORK);
>  	if (error)
>  		return error;
>  	bp->b_ops = &xfs_dir3_data_buf_ops;
> diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
> index b7046e2..a2cba6bd 100644
> --- a/fs/xfs/libxfs/xfs_dir2_leaf.c
> +++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
> @@ -19,6 +19,7 @@
>  #include "xfs_trace.h"
>  #include "xfs_trans.h"
>  #include "xfs_buf_item.h"
> +#include "xfs_attr_leaf.h"
>  
>  /*
>   * Local function declarations.
> @@ -311,7 +312,7 @@ xfs_dir3_leaf_get_buf(
>  	       bno < xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET));
>  
>  	error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, bno),
> -			       -1, &bp, XFS_DATA_FORK);
> +			       XFS_DABUF_MAP_NOMAPPING, &bp, XFS_DATA_FORK);
>  	if (error)
>  		return error;
>  
> @@ -594,7 +595,8 @@ xfs_dir2_leaf_addname(
>  
>  	trace_xfs_dir2_leaf_addname(args);
>  
> -	error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, -1, &lbp);
> +	error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk,
> +				   XFS_DABUF_MAP_NOMAPPING, &lbp);
>  	if (error)
>  		return error;
>  

I think there are some missing conversions for xfs_dir3_data_read calls
in xfs_dir2_leaf_addname...

> @@ -1189,7 +1191,8 @@ xfs_dir2_leaf_lookup_int(
>  	tp = args->trans;
>  	mp = dp->i_mount;
>  
> -	error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, -1, &lbp);
> +	error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk,
> +				   XFS_DABUF_MAP_NOMAPPING, &lbp);
>  	if (error)
>  		return error;
>  

...and two more dir3_leaf_read calls further down in this function...

...and one more in xfs_dir2_leaf_trim_data...

> diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
> index 8bbd742..0a803e4 100644
> --- a/fs/xfs/libxfs/xfs_dir2_node.c
> +++ b/fs/xfs/libxfs/xfs_dir2_node.c
> @@ -20,6 +20,7 @@
>  #include "xfs_trans.h"
>  #include "xfs_buf_item.h"
>  #include "xfs_log.h"
> +#include "xfs_attr_leaf.h"
>  
>  /*
>   * Function declarations.
> @@ -227,7 +228,7 @@ xfs_dir2_free_read(
>  	xfs_dablk_t		fbno,
>  	struct xfs_buf		**bpp)
>  {
> -	return __xfs_dir3_free_read(tp, dp, fbno, -1, bpp);
> +	return __xfs_dir3_free_read(tp, dp, fbno, XFS_DABUF_MAP_NOMAPPING, bpp);
>  }
>  
>  static int
> @@ -237,7 +238,7 @@ xfs_dir2_free_try_read(
>  	xfs_dablk_t		fbno,
>  	struct xfs_buf		**bpp)
>  {
> -	return __xfs_dir3_free_read(tp, dp, fbno, -2, bpp);
> +	return __xfs_dir3_free_read(tp, dp, fbno, XFS_DABUF_MAP_HOLE_OK, bpp);
>  }
>  
>  static int
> @@ -254,7 +255,7 @@ xfs_dir3_free_get_buf(
>  	struct xfs_dir3_icfree_hdr hdr;
>  
>  	error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, fbno),
> -				   -1, &bp, XFS_DATA_FORK);
> +				   XFS_DABUF_MAP_NOMAPPING, &bp, XFS_DATA_FORK);
>  	if (error)
>  		return error;
>  

...there's also a missing call in xfs_dir2_leafn_lookup_for_entry...

> @@ -1495,7 +1496,8 @@ xfs_dir2_leafn_toosmall(
>  		 * Read the sibling leaf block.
>  		 */
>  		error = xfs_dir3_leafn_read(state->args->trans, dp,
> -					    blkno, -1, &bp);
> +					    blkno, XFS_DABUF_MAP_NOMAPPING,
> +					    &bp);
>  		if (error)
>  			return error;
>  

...and another one in xfs_dir2_node_addname_int.

> diff --git a/fs/xfs/scrub/dabtree.c b/fs/xfs/scrub/dabtree.c
> index 77ff9f9..353455c 100644
> --- a/fs/xfs/scrub/dabtree.c
> +++ b/fs/xfs/scrub/dabtree.c
> @@ -355,9 +355,9 @@ xchk_da_btree_block(
>  		goto out_nobuf;
>  
>  	/* Read the buffer. */
> -	error = xfs_da_read_buf(dargs->trans, dargs->dp, blk->blkno, -2,
> -			&blk->bp, dargs->whichfork,
> -			&xchk_da_btree_buf_ops);
> +	error = xfs_da_read_buf(dargs->trans, dargs->dp, blk->blkno,
> +				XFS_DABUF_MAP_HOLE_OK, &blk->bp,
> +				dargs->whichfork, &xchk_da_btree_buf_ops);
>  	if (!xchk_da_process_error(ds, level, &error))
>  		goto out_nobuf;
>  	if (blk->bp)
> diff --git a/fs/xfs/scrub/dir.c b/fs/xfs/scrub/dir.c
> index 1e2e117..eb0fa0f 100644
> --- a/fs/xfs/scrub/dir.c
> +++ b/fs/xfs/scrub/dir.c
> @@ -18,6 +18,7 @@
>  #include "scrub/scrub.h"
>  #include "scrub/common.h"
>  #include "scrub/dabtree.h"
> +#include "xfs_attr_leaf.h"
>  
>  /* Set us up to scrub directories. */
>  int

I also noticed missing conversions for xfs_dir3_data_read in
xchk_dir_rec, xchk_directory_data_bestfree,
xchk_directory_leaf1_bestfree, and xchk_directory_free_bestfree.

> @@ -492,7 +493,8 @@ xchk_directory_leaf1_bestfree(
>  	int				error;
>  
>  	/* Read the free space block. */
> -	error = xfs_dir3_leaf_read(sc->tp, sc->ip, lblk, -1, &bp);
> +	error = xfs_dir3_leaf_read(sc->tp, sc->ip, lblk,
> +				   XFS_DABUF_MAP_NOMAPPING, &bp);
>  	if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))
>  		goto out;
>  	xchk_buffer_recheck(sc, bp);

There's also a missing xfs_dir3_data_readahead conversion in
xchk_parent_count_parent_dentries in fs/xfs/scrub/parent.c.

> diff --git a/fs/xfs/xfs_attr_inactive.c b/fs/xfs/xfs_attr_inactive.c
> index f83f11d..9c22915 100644
> --- a/fs/xfs/xfs_attr_inactive.c
> +++ b/fs/xfs/xfs_attr_inactive.c
> @@ -235,7 +235,8 @@ xfs_attr3_node_inactive(
>  		 * traversal of the tree so we may deal with many blocks
>  		 * before we come back to this one.
>  		 */
> -		error = xfs_da3_node_read(*trans, dp, child_fsb, -1, &child_bp,
> +		error = xfs_da3_node_read(*trans, dp, child_fsb,
> +					  XFS_DABUF_MAP_NOMAPPING, &child_bp,
>  					  XFS_ATTR_FORK);
>  		if (error)
>  			return error;
> @@ -321,7 +322,8 @@ xfs_attr3_root_inactive(
>  	 * the extents in reverse order the extent containing
>  	 * block 0 must still be there.
>  	 */
> -	error = xfs_da3_node_read(*trans, dp, 0, -1, &bp, XFS_ATTR_FORK);
> +	error = xfs_da3_node_read(*trans, dp, 0, XFS_DABUF_MAP_NOMAPPING, &bp,
> +				  XFS_ATTR_FORK);
>  	if (error)
>  		return error;
>  	blkno = bp->b_bn;
> diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
> index c02f22d..fab416c 100644
> --- a/fs/xfs/xfs_attr_list.c
> +++ b/fs/xfs/xfs_attr_list.c
> @@ -224,8 +224,9 @@ xfs_attr_node_list_lookup(
>  	ASSERT(*pbp == NULL);
>  	cursor->blkno = 0;
>  	for (;;) {
> -		error = xfs_da3_node_read(tp, dp, cursor->blkno, -1, &bp,
> -				XFS_ATTR_FORK);
> +		error = xfs_da3_node_read(tp, dp, cursor->blkno,
> +					  XFS_DABUF_MAP_NOMAPPING, &bp,
> +					  XFS_ATTR_FORK);
>  		if (error)
>  			return error;
>  		node = bp->b_addr;
> @@ -309,8 +310,9 @@ xfs_attr_node_list(
>  	 */
>  	bp = NULL;
>  	if (cursor->blkno > 0) {
> -		error = xfs_da3_node_read(context->tp, dp, cursor->blkno, -1,
> -					      &bp, XFS_ATTR_FORK);
> +		error = xfs_da3_node_read(context->tp, dp, cursor->blkno,
> +					  XFS_DABUF_MAP_NOMAPPING, &bp,
> +					  XFS_ATTR_FORK);
>  		if ((error != 0) && (error != -EFSCORRUPTED))
>  			return error;
>  		if (bp) {
> @@ -377,7 +379,8 @@ xfs_attr_node_list(
>  			break;
>  		cursor->blkno = leafhdr.forw;
>  		xfs_trans_brelse(context->tp, bp);
> -		error = xfs_attr3_leaf_read(context->tp, dp, cursor->blkno, -1, &bp);
> +		error = xfs_attr3_leaf_read(context->tp, dp, cursor->blkno,
> +					    XFS_DABUF_MAP_NOMAPPING, &bp);
>  		if (error)
>  			return error;
>  	}
> @@ -497,7 +500,8 @@ xfs_attr_leaf_list(xfs_attr_list_context_t *context)
>  	trace_xfs_attr_leaf_list(context);
>  
>  	context->cursor->blkno = 0;
> -	error = xfs_attr3_leaf_read(context->tp, context->dp, 0, -1, &bp);
> +	error = xfs_attr3_leaf_read(context->tp, context->dp, 0,
> +				    XFS_DABUF_MAP_NOMAPPING, &bp);
>  	if (error)
>  		return error;
>  

...more missing conversions of xfs_dir3_data_read in
xfs_dir2_leaf_readbuf; and of xfs_dir3_data_readahead in
xfs_dir2_leaf_readbuf...

...and a missing conversion of xfs_dir3_data_readahead in xfs_dir_open
in fs/xfs/xfs_file.c.

--D

> -- 
> 2.7.4
> 

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

* Re: [PATCH v4 05/17] xfs: Add xfs_has_attr and subroutines
  2019-11-07  1:27 ` [PATCH v4 05/17] xfs: Add xfs_has_attr and subroutines Allison Collins
@ 2019-11-08 19:32   ` Darrick J. Wong
  2019-11-08 19:51     ` Allison Collins
  2019-11-11 17:40   ` Brian Foster
  2019-11-11 17:53   ` Christoph Hellwig
  2 siblings, 1 reply; 77+ messages in thread
From: Darrick J. Wong @ 2019-11-08 19:32 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Wed, Nov 06, 2019 at 06:27:49PM -0700, Allison Collins wrote:
> From: Allison Henderson <allison.henderson@oracle.com>
> 
> This patch adds a new functions to check for the existence of
> an attribute.  Subroutines are also added to handle the cases
> of leaf blocks, nodes or shortform.  Common code that appears
> in existing attr add and remove functions have been factored
> out to help reduce the appearence of duplicated code.  We will
> need these routines later for delayed attributes since delayed
> operations cannot return error codes.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c      | 154 +++++++++++++++++++++++++++---------------
>  fs/xfs/libxfs/xfs_attr.h      |   1 +
>  fs/xfs/libxfs/xfs_attr_leaf.c | 107 ++++++++++++++++++-----------
>  fs/xfs/libxfs/xfs_attr_leaf.h |   2 +
>  4 files changed, 171 insertions(+), 93 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 5cb83a8..c8a3273 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -46,6 +46,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
>  STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
>  STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
>  STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
> +STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
>  
>  /*
>   * Internal routines when attribute list is more than one block.
> @@ -53,6 +54,8 @@ STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
>  STATIC int xfs_attr_node_get(xfs_da_args_t *args);
>  STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
>  STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
> +STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
> +				 struct xfs_da_state **state);
>  STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
>  STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
>  
> @@ -310,6 +313,34 @@ xfs_attr_set_args(
>  }
>  
>  /*
> + * Return EEXIST if attr is found, or ENOATTR if not
> + */
> +int
> +xfs_has_attr(
> +	struct xfs_da_args      *args)

I was really hoping for a "replace ENOATTR/EEXIST with a boolean"
cleanup at the end of this series, though as a straight hoisting and
refactoring, this patch is ok for leaving the existing error code
overloading. :)

> +{
> +	struct xfs_inode        *dp = args->dp;
> +	struct xfs_buf		*bp;
> +	int                     error;
> +
> +	if (!xfs_inode_hasattr(dp)) {
> +		error = -ENOATTR;
> +	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
> +		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
> +		error = xfs_attr_shortform_hasname(args, NULL, NULL);
> +	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> +		error = xfs_attr_leaf_hasname(args, &bp);
> +		if (error != -ENOATTR && error != -EEXIST)
> +			goto out;
> +		xfs_trans_brelse(args->trans, bp);
> +	} else {
> +		error = xfs_attr_node_hasname(args, NULL);
> +	}
> +out:
> +	return error;
> +}
> +
> +/*
>   * Remove the attribute specified in @args.
>   */
>  int
> @@ -580,27 +611,20 @@ STATIC int
>  xfs_attr_leaf_addname(
>  	struct xfs_da_args	*args)
>  {
> -	struct xfs_inode	*dp;
>  	struct xfs_buf		*bp;
>  	int			retval, error, forkoff;
> +	struct xfs_inode	*dp = args->dp;
>  
>  	trace_xfs_attr_leaf_addname(args);
>  
>  	/*
> -	 * Read the (only) block in the attribute list in.
> -	 */
> -	dp = args->dp;
> -	args->blkno = 0;
> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
> -				    XFS_DABUF_MAP_NOMAPPING, &bp);
> -	if (error)
> -		return error;
> -
> -	/*
>  	 * Look up the given attribute in the leaf block.  Figure out if
>  	 * the given flags produce an error or call for an atomic rename.
>  	 */
> -	retval = xfs_attr3_leaf_lookup_int(bp, args);
> +	retval = xfs_attr_leaf_hasname(args, &bp);
> +	if (retval != -ENOATTR && retval != -EEXIST)
> +		return retval;
> +
>  	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
>  		xfs_trans_brelse(args->trans, bp);
>  		return retval;
> @@ -752,6 +776,24 @@ xfs_attr_leaf_addname(
>  }
>  
>  /*
> + * Return EEXIST if attr is found, or ENOATTR if not
> + */
> +STATIC int
> +xfs_attr_leaf_hasname(
> +	struct xfs_da_args      *args,
> +	struct xfs_buf		**bp)
> +{
> +	int                     error = 0;
> +
> +	error = xfs_attr3_leaf_read(args->trans, args->dp, 0,
> +				    XFS_DABUF_MAP_NOMAPPING, bp);
> +	if (error)
> +		return error;
> +
> +	return xfs_attr3_leaf_lookup_int(*bp, args);
> +}
> +
> +/*
>   * Remove a name from the leaf attribute list structure
>   *
>   * This leaf block cannot have a "remote" value, we only call this routine
> @@ -771,13 +813,11 @@ xfs_attr_leaf_removename(
>  	 * Remove the attribute.
>  	 */
>  	dp = args->dp;
> -	args->blkno = 0;
> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
> -				    XFS_DABUF_MAP_NOMAPPING, &bp);
> -	if (error)
> +
> +	error = xfs_attr_leaf_hasname(args, &bp);
> +	if (error != -ENOATTR && error != -EEXIST)
>  		return error;
>  
> -	error = xfs_attr3_leaf_lookup_int(bp, args);
>  	if (error == -ENOATTR) {
>  		xfs_trans_brelse(args->trans, bp);
>  		return error;
> @@ -816,13 +856,10 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>  
>  	trace_xfs_attr_leaf_get(args);
>  
> -	args->blkno = 0;
> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
> -				    XFS_DABUF_MAP_NOMAPPING, &bp);
> -	if (error)
> +	error = xfs_attr_leaf_hasname(args, &bp);
> +	if (error != -ENOATTR && error != -EEXIST)
>  		return error;
>  
> -	error = xfs_attr3_leaf_lookup_int(bp, args);
>  	if (error != -EEXIST)  {
>  		xfs_trans_brelse(args->trans, bp);
>  		return error;
> @@ -832,6 +869,38 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>  	return error;
>  }
>  
> +/*
> + * Return EEXIST if attr is found, or ENOATTR if not
> + * statep: If not null is set to point at the found state.  Caller will
> + * 	   be responsible for freeing the state in this case.
> + */
> +STATIC int
> +xfs_attr_node_hasname(
> +	struct xfs_da_args	*args,
> +	struct xfs_da_state	**statep)
> +{
> +	struct xfs_da_state	*state;
> +	int			retval, error;
> +
> +	state = xfs_da_state_alloc();
> +	state->args = args;
> +	state->mp = args->dp->i_mount;
> +
> +	/*
> +	 * Search to see if name exists, and get back a pointer to it.
> +	 */
> +	error = xfs_da3_node_lookup_int(state, &retval);
> +	if (error == 0)
> +		error = retval;
> +
> +	if (statep != NULL)
> +		*statep = state;
> +	else
> +		xfs_da_state_free(state);
> +
> +	return error;
> +}
> +
>  /*========================================================================
>   * External routines when attribute list size > geo->blksize
>   *========================================================================*/
> @@ -864,20 +933,17 @@ xfs_attr_node_addname(
>  	dp = args->dp;
>  	mp = dp->i_mount;
>  restart:
> -	state = xfs_da_state_alloc();
> -	state->args = args;
> -	state->mp = mp;
> -
>  	/*
>  	 * Search to see if name already exists, and get back a pointer
>  	 * to where it should go.
>  	 */
> -	error = xfs_da3_node_lookup_int(state, &retval);
> -	if (error)
> +	retval = xfs_attr_node_hasname(args, &state);
> +	if (retval != -ENOATTR)
>  		goto out;
> +
>  	blk = &state->path.blk[ state->path.active-1 ];
>  	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> -	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
> +	if (args->name.type & ATTR_REPLACE) {
>  		goto out;
>  	} else if (retval == -EEXIST) {
>  		if (args->name.type & ATTR_CREATE)
> @@ -1079,29 +1145,15 @@ xfs_attr_node_removename(
>  {
>  	struct xfs_da_state	*state;
>  	struct xfs_da_state_blk	*blk;
> -	struct xfs_inode	*dp;
>  	struct xfs_buf		*bp;
>  	int			retval, error, forkoff;
> +	struct xfs_inode	*dp = args->dp;
>  
>  	trace_xfs_attr_node_removename(args);
>  
> -	/*
> -	 * Tie a string around our finger to remind us where we are.
> -	 */
> -	dp = args->dp;
> -	state = xfs_da_state_alloc();
> -	state->args = args;
> -	state->mp = dp->i_mount;
> -
> -	/*
> -	 * Search to see if name exists, and get back a pointer to it.
> -	 */
> -	error = xfs_da3_node_lookup_int(state, &retval);
> -	if (error || (retval != -EEXIST)) {
> -		if (error == 0)
> -			error = retval;
> +	error = xfs_attr_node_hasname(args, &state);
> +	if (error != -EEXIST)
>  		goto out;
> -	}
>  
>  	/*
>  	 * If there is an out-of-line value, de-allocate the blocks.
> @@ -1324,20 +1376,14 @@ xfs_attr_node_get(xfs_da_args_t *args)
>  
>  	trace_xfs_attr_node_get(args);
>  
> -	state = xfs_da_state_alloc();
> -	state->args = args;
> -	state->mp = args->dp->i_mount;
> -
>  	/*
>  	 * Search to see if name exists, and get back a pointer to it.
>  	 */
> -	error = xfs_da3_node_lookup_int(state, &retval);
> -	if (error) {
> +	error = xfs_attr_node_hasname(args, &state);
> +	if (error != -EEXIST) {
>  		retval = error;
>  		goto out_release;
>  	}
> -	if (retval != -EEXIST)
> -		goto out_release;
>  
>  	/*
>  	 * Get the value, local or "remote"
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index 44dd07a..3b5dad4 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -150,6 +150,7 @@ int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
>  		 unsigned char *value, int valuelen, int flags);
>  int xfs_attr_set_args(struct xfs_da_args *args);
>  int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
> +int xfs_has_attr(struct xfs_da_args *args);
>  int xfs_attr_remove_args(struct xfs_da_args *args);
>  int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>  		  int flags, struct attrlist_cursor_kern *cursor);
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> index 93c3496..d06cfd6 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -655,18 +655,67 @@ xfs_attr_shortform_create(xfs_da_args_t *args)
>  }
>  
>  /*
> + * Return -EEXIST if attr is found, or -ENOATTR if not
> + * args:  args containing attribute name and namelen
> + * sfep:  If not null, pointer will be set to the last attr entry found on
> +	  -EEXIST.  On -ENOATTR pointer is left at the last entry in the list
> + * basep: If not null, pointer is set to the byte offset of the entry in the
> + *	  list on -EEXIST.  On -ENOATTR, pointer is left at the byte offset of
> + *	  the last entry in the list
> + */
> +int
> +xfs_attr_shortform_hasname(
> +	struct xfs_da_args	 *args,
> +	struct xfs_attr_sf_entry **sfep,
> +	int			 *basep)

Byte offsets can't be negative, so this should be unsigned int.

Seeing as we also return the location of the sf entry and byte offset,
maybe this ought to be called xfs_attr_sf_findname ?

> +{
> +	struct xfs_attr_shortform *sf;
> +	struct xfs_attr_sf_entry *sfe;
> +	int			base = sizeof(struct xfs_attr_sf_hdr);
> +	int			size = 0;
> +	int			end;
> +	int			i;
> +
> +	base = sizeof(struct xfs_attr_sf_hdr);
> +	sf = (struct xfs_attr_shortform *)args->dp->i_afp->if_u1.if_data;
> +	sfe = &sf->list[0];
> +	end = sf->hdr.count;
> +	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
> +			base += size, i++) {
> +		size = XFS_ATTR_SF_ENTSIZE(sfe);
> +		if (sfe->namelen != args->name.len)
> +			continue;
> +		if (memcmp(sfe->nameval, args->name.name, args->name.len) != 0)
> +			continue;
> +		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
> +			continue;
> +		break;
> +	}
> +
> +	if (sfep != NULL)
> +		*sfep = sfe;
> +
> +	if (basep != NULL)
> +		*basep = base;
> +
> +	if (i == end)
> +		return -ENOATTR;
> +	return -EEXIST;
> +}
> +
> +/*
>   * Add a name/value pair to the shortform attribute list.
>   * Overflow from the inode has already been checked for.
>   */
>  void
>  xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
>  {
> -	xfs_attr_shortform_t *sf;
> -	xfs_attr_sf_entry_t *sfe;
> -	int i, offset, size;
> -	xfs_mount_t *mp;
> -	xfs_inode_t *dp;
> -	struct xfs_ifork *ifp;
> +	struct xfs_attr_shortform	*sf;
> +	struct xfs_attr_sf_entry	*sfe;
> +	int				offset, size, error;
> +	struct xfs_mount		*mp;
> +	struct xfs_inode		*dp;
> +	struct xfs_ifork		*ifp;
>  
>  	trace_xfs_attr_sf_add(args);
>  
> @@ -677,18 +726,8 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
>  	ifp = dp->i_afp;
>  	ASSERT(ifp->if_flags & XFS_IFINLINE);
>  	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
> -	sfe = &sf->list[0];
> -	for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
> -#ifdef DEBUG
> -		if (sfe->namelen != args->name.len)
> -			continue;
> -		if (memcmp(args->name.name, sfe->nameval, args->name.len) != 0)
> -			continue;
> -		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
> -			continue;
> -		ASSERT(0);
> -#endif
> -	}
> +	error = xfs_attr_shortform_hasname(args, &sfe, NULL);
> +	ASSERT(error != -EEXIST);

If this assertion triggers, the fs is corrupt and we need to log
something and bail out.  5.5 for-next will soon have a new
XFS_IS_CORRUPT macro that takes care of this, so you can do:

	error = xfs_attr_shortform_hasname(args, &sfe, NULL);
	if (XFS_IS_CORRUPT(mp, error != -EEXIST))
		return -EFSCORRUPTED;

--D


>  
>  	offset = (char *)sfe - (char *)sf;
>  	size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
> @@ -733,33 +772,23 @@ xfs_attr_fork_remove(
>  int
>  xfs_attr_shortform_remove(xfs_da_args_t *args)
>  {
> -	xfs_attr_shortform_t *sf;
> -	xfs_attr_sf_entry_t *sfe;
> -	int base, size=0, end, totsize, i;
> -	xfs_mount_t *mp;
> -	xfs_inode_t *dp;
> +	struct xfs_attr_shortform	*sf;
> +	struct xfs_attr_sf_entry	*sfe;
> +	int				base, size = 0, end, totsize;
> +	struct xfs_mount		*mp;
> +	struct xfs_inode		*dp;
> +	int				error;
>  
>  	trace_xfs_attr_sf_remove(args);
>  
>  	dp = args->dp;
>  	mp = dp->i_mount;
> -	base = sizeof(xfs_attr_sf_hdr_t);
>  	sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
> -	sfe = &sf->list[0];
> -	end = sf->hdr.count;
> -	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
> -					base += size, i++) {
> -		size = XFS_ATTR_SF_ENTSIZE(sfe);
> -		if (sfe->namelen != args->name.len)
> -			continue;
> -		if (memcmp(sfe->nameval, args->name.name, args->name.len) != 0)
> -			continue;
> -		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
> -			continue;
> -		break;
> -	}
> -	if (i == end)
> -		return -ENOATTR;
> +
> +	error = xfs_attr_shortform_hasname(args, &sfe, &base);
> +	if (error != -EEXIST)
> +		return error;
> +	size = XFS_ATTR_SF_ENTSIZE(sfe);
>  
>  	/*
>  	 * Fix up the attribute fork data, covering the hole
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
> index 017480e..e108b37 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.h
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.h
> @@ -42,6 +42,8 @@ int	xfs_attr_shortform_getvalue(struct xfs_da_args *args);
>  int	xfs_attr_shortform_to_leaf(struct xfs_da_args *args,
>  			struct xfs_buf **leaf_bp);
>  int	xfs_attr_shortform_remove(struct xfs_da_args *args);
> +int	xfs_attr_shortform_hasname(struct xfs_da_args *args,
> +			       struct xfs_attr_sf_entry **sfep, int *basep);
>  int	xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp);
>  int	xfs_attr_shortform_bytesfit(struct xfs_inode *dp, int bytes);
>  xfs_failaddr_t xfs_attr_shortform_verify(struct xfs_inode *ip);
> -- 
> 2.7.4
> 

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

* Re: [PATCH v4 06/17] xfs: Factor out new helper functions xfs_attr_rmtval_set
  2019-11-07  1:27 ` [PATCH v4 06/17] xfs: Factor out new helper functions xfs_attr_rmtval_set Allison Collins
@ 2019-11-08 19:34   ` Darrick J. Wong
  2019-11-08 19:51     ` Allison Collins
  0 siblings, 1 reply; 77+ messages in thread
From: Darrick J. Wong @ 2019-11-08 19:34 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Wed, Nov 06, 2019 at 06:27:50PM -0700, Allison Collins wrote:
> Break xfs_attr_rmtval_set into two helper functions
> xfs_attr_rmt_find_hole and xfs_attr_rmtval_set_value.
> xfs_attr_rmtval_set rolls the transaction between the
> helpers, but delayed operations cannot.  We will use
> the helpers later when constructing new delayed
> attribute routines.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Brian Foster <bfoster@redhat.com>

Looks good,
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

--D

> ---
>  fs/xfs/libxfs/xfs_attr_remote.c | 71 +++++++++++++++++++++++++++++++----------
>  fs/xfs/libxfs/xfs_attr_remote.h |  3 +-
>  2 files changed, 56 insertions(+), 18 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> index db9247a..db51388 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.c
> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> @@ -21,6 +21,7 @@
>  #include "xfs_attr.h"
>  #include "xfs_trace.h"
>  #include "xfs_error.h"
> +#include "xfs_attr_remote.h"
>  
>  #define ATTR_RMTVALUE_MAPSIZE	1	/* # of map entries at once */
>  
> @@ -432,34 +433,20 @@ xfs_attr_rmtval_set(
>  	struct xfs_da_args	*args)
>  {
>  	struct xfs_inode	*dp = args->dp;
> -	struct xfs_mount	*mp = dp->i_mount;
>  	struct xfs_bmbt_irec	map;
>  	xfs_dablk_t		lblkno;
> -	xfs_fileoff_t		lfileoff = 0;
> -	uint8_t			*src = args->value;
>  	int			blkcnt;
> -	int			valuelen;
>  	int			nmap;
>  	int			error;
> -	int			offset = 0;
>  
>  	trace_xfs_attr_rmtval_set(args);
>  
> -	/*
> -	 * Find a "hole" in the attribute address space large enough for
> -	 * us to drop the new attribute's value into. Because CRC enable
> -	 * attributes have headers, we can't just do a straight byte to FSB
> -	 * conversion and have to take the header space into account.
> -	 */
> -	blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
> -	error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
> -						   XFS_ATTR_FORK);
> +	error = xfs_attr_rmt_find_hole(args);
>  	if (error)
>  		return error;
>  
> -	args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff;
> -	args->rmtblkcnt = blkcnt;
> -
> +	blkcnt = args->rmtblkcnt;
> +	lblkno = (xfs_dablk_t)args->rmtblkno;
>  	/*
>  	 * Roll through the "value", allocating blocks on disk as required.
>  	 */
> @@ -500,6 +487,56 @@ xfs_attr_rmtval_set(
>  			return error;
>  	}
>  
> +	return xfs_attr_rmtval_set_value(args);
> +}
> +
> +
> +/*
> + * Find a "hole" in the attribute address space large enough for us to drop the
> + * new attribute's value into
> + */
> +int
> +xfs_attr_rmt_find_hole(
> +	struct xfs_da_args	*args)
> +{
> +	struct xfs_inode        *dp = args->dp;
> +	struct xfs_mount	*mp = dp->i_mount;
> +	int			error;
> +	int			blkcnt;
> +	xfs_fileoff_t		lfileoff = 0;
> +
> +	/*
> +	 * Because CRC enable attributes have headers, we can't just do a
> +	 * straight byte to FSB conversion and have to take the header space
> +	 * into account.
> +	 */
> +	blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
> +	error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
> +						   XFS_ATTR_FORK);
> +	if (error)
> +		return error;
> +
> +	args->rmtblkno = (xfs_dablk_t)lfileoff;
> +	args->rmtblkcnt = blkcnt;
> +
> +	return 0;
> +}
> +
> +int
> +xfs_attr_rmtval_set_value(
> +	struct xfs_da_args	*args)
> +{
> +	struct xfs_inode	*dp = args->dp;
> +	struct xfs_mount	*mp = dp->i_mount;
> +	struct xfs_bmbt_irec	map;
> +	xfs_dablk_t		lblkno;
> +	uint8_t			*src = args->value;
> +	int			blkcnt;
> +	int			valuelen;
> +	int			nmap;
> +	int			error;
> +	int			offset = 0;
> +
>  	/*
>  	 * Roll through the "value", copying the attribute value to the
>  	 * already-allocated blocks.  Blocks are written synchronously
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
> index 9d20b66..cd7670d 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.h
> +++ b/fs/xfs/libxfs/xfs_attr_remote.h
> @@ -11,5 +11,6 @@ int xfs_attr3_rmt_blocks(struct xfs_mount *mp, int attrlen);
>  int xfs_attr_rmtval_get(struct xfs_da_args *args);
>  int xfs_attr_rmtval_set(struct xfs_da_args *args);
>  int xfs_attr_rmtval_remove(struct xfs_da_args *args);
> -
> +int xfs_attr_rmtval_set_value(struct xfs_da_args *args);
> +int xfs_attr_rmt_find_hole(struct xfs_da_args *args);
>  #endif /* __XFS_ATTR_REMOTE_H__ */
> -- 
> 2.7.4
> 

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

* Re: [PATCH v4 07/17] xfs: Factor up trans handling in xfs_attr3_leaf_flipflags
  2019-11-07  1:27 ` [PATCH v4 07/17] xfs: Factor up trans handling in xfs_attr3_leaf_flipflags Allison Collins
@ 2019-11-08 19:35   ` Darrick J. Wong
  2019-11-08 19:52     ` Allison Collins
  0 siblings, 1 reply; 77+ messages in thread
From: Darrick J. Wong @ 2019-11-08 19:35 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Wed, Nov 06, 2019 at 06:27:51PM -0700, Allison Collins wrote:
> Since delayed operations cannot roll transactions, factor
> up the transaction handling into the calling function
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Brian Foster <bfoster@redhat.com>

Looks ok,
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

--D

> ---
>  fs/xfs/libxfs/xfs_attr.c      | 14 ++++++++++++++
>  fs/xfs/libxfs/xfs_attr_leaf.c |  5 -----
>  2 files changed, 14 insertions(+), 5 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index c8a3273..212995f 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -721,6 +721,13 @@ xfs_attr_leaf_addname(
>  		error = xfs_attr3_leaf_flipflags(args);
>  		if (error)
>  			return error;
> +		/*
> +		 * Commit the flag value change and start the next trans in
> +		 * series.
> +		 */
> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
> +		if (error)
> +			return error;
>  
>  		/*
>  		 * Dismantle the "old" attribute/value pair by removing
> @@ -1057,6 +1064,13 @@ xfs_attr_node_addname(
>  		error = xfs_attr3_leaf_flipflags(args);
>  		if (error)
>  			goto out;
> +		/*
> +		 * Commit the flag value change and start the next trans in
> +		 * series
> +		 */
> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
> +		if (error)
> +			goto out;
>  
>  		/*
>  		 * Dismantle the "old" attribute/value pair by removing
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> index d06cfd6..134eb00 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -2973,10 +2973,5 @@ xfs_attr3_leaf_flipflags(
>  			 XFS_DA_LOGRANGE(leaf2, name_rmt, sizeof(*name_rmt)));
>  	}
>  
> -	/*
> -	 * Commit the flag value change and start the next trans in series.
> -	 */
> -	error = xfs_trans_roll_inode(&args->trans, args->dp);
> -
>  	return error;
>  }
> -- 
> 2.7.4
> 

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

* Re: [PATCH v4 05/17] xfs: Add xfs_has_attr and subroutines
  2019-11-08 19:32   ` Darrick J. Wong
@ 2019-11-08 19:51     ` Allison Collins
  0 siblings, 0 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-08 19:51 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 11/8/19 12:32 PM, Darrick J. Wong wrote:
> On Wed, Nov 06, 2019 at 06:27:49PM -0700, Allison Collins wrote:
>> From: Allison Henderson <allison.henderson@oracle.com>
>>
>> This patch adds a new functions to check for the existence of
>> an attribute.  Subroutines are also added to handle the cases
>> of leaf blocks, nodes or shortform.  Common code that appears
>> in existing attr add and remove functions have been factored
>> out to help reduce the appearence of duplicated code.  We will
>> need these routines later for delayed attributes since delayed
>> operations cannot return error codes.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c      | 154 +++++++++++++++++++++++++++---------------
>>   fs/xfs/libxfs/xfs_attr.h      |   1 +
>>   fs/xfs/libxfs/xfs_attr_leaf.c | 107 ++++++++++++++++++-----------
>>   fs/xfs/libxfs/xfs_attr_leaf.h |   2 +
>>   4 files changed, 171 insertions(+), 93 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 5cb83a8..c8a3273 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -46,6 +46,7 @@ STATIC int xfs_attr_shortform_addname(xfs_da_args_t *args);
>>   STATIC int xfs_attr_leaf_get(xfs_da_args_t *args);
>>   STATIC int xfs_attr_leaf_addname(xfs_da_args_t *args);
>>   STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
>> +STATIC int xfs_attr_leaf_hasname(struct xfs_da_args *args, struct xfs_buf **bp);
>>   
>>   /*
>>    * Internal routines when attribute list is more than one block.
>> @@ -53,6 +54,8 @@ STATIC int xfs_attr_leaf_removename(xfs_da_args_t *args);
>>   STATIC int xfs_attr_node_get(xfs_da_args_t *args);
>>   STATIC int xfs_attr_node_addname(xfs_da_args_t *args);
>>   STATIC int xfs_attr_node_removename(xfs_da_args_t *args);
>> +STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
>> +				 struct xfs_da_state **state);
>>   STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
>>   STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
>>   
>> @@ -310,6 +313,34 @@ xfs_attr_set_args(
>>   }
>>   
>>   /*
>> + * Return EEXIST if attr is found, or ENOATTR if not
>> + */
>> +int
>> +xfs_has_attr(
>> +	struct xfs_da_args      *args)
> 
> I was really hoping for a "replace ENOATTR/EEXIST with a boolean"
> cleanup at the end of this series, though as a straight hoisting and
> refactoring, this patch is ok for leaving the existing error code
> overloading. :)
> 
>> +{
>> +	struct xfs_inode        *dp = args->dp;
>> +	struct xfs_buf		*bp;
>> +	int                     error;
>> +
>> +	if (!xfs_inode_hasattr(dp)) {
>> +		error = -ENOATTR;
>> +	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
>> +		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
>> +		error = xfs_attr_shortform_hasname(args, NULL, NULL);
>> +	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>> +		error = xfs_attr_leaf_hasname(args, &bp);
>> +		if (error != -ENOATTR && error != -EEXIST)
>> +			goto out;
>> +		xfs_trans_brelse(args->trans, bp);
>> +	} else {
>> +		error = xfs_attr_node_hasname(args, NULL);
>> +	}
>> +out:
>> +	return error;
>> +}
>> +
>> +/*
>>    * Remove the attribute specified in @args.
>>    */
>>   int
>> @@ -580,27 +611,20 @@ STATIC int
>>   xfs_attr_leaf_addname(
>>   	struct xfs_da_args	*args)
>>   {
>> -	struct xfs_inode	*dp;
>>   	struct xfs_buf		*bp;
>>   	int			retval, error, forkoff;
>> +	struct xfs_inode	*dp = args->dp;
>>   
>>   	trace_xfs_attr_leaf_addname(args);
>>   
>>   	/*
>> -	 * Read the (only) block in the attribute list in.
>> -	 */
>> -	dp = args->dp;
>> -	args->blkno = 0;
>> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
>> -				    XFS_DABUF_MAP_NOMAPPING, &bp);
>> -	if (error)
>> -		return error;
>> -
>> -	/*
>>   	 * Look up the given attribute in the leaf block.  Figure out if
>>   	 * the given flags produce an error or call for an atomic rename.
>>   	 */
>> -	retval = xfs_attr3_leaf_lookup_int(bp, args);
>> +	retval = xfs_attr_leaf_hasname(args, &bp);
>> +	if (retval != -ENOATTR && retval != -EEXIST)
>> +		return retval;
>> +
>>   	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
>>   		xfs_trans_brelse(args->trans, bp);
>>   		return retval;
>> @@ -752,6 +776,24 @@ xfs_attr_leaf_addname(
>>   }
>>   
>>   /*
>> + * Return EEXIST if attr is found, or ENOATTR if not
>> + */
>> +STATIC int
>> +xfs_attr_leaf_hasname(
>> +	struct xfs_da_args      *args,
>> +	struct xfs_buf		**bp)
>> +{
>> +	int                     error = 0;
>> +
>> +	error = xfs_attr3_leaf_read(args->trans, args->dp, 0,
>> +				    XFS_DABUF_MAP_NOMAPPING, bp);
>> +	if (error)
>> +		return error;
>> +
>> +	return xfs_attr3_leaf_lookup_int(*bp, args);
>> +}
>> +
>> +/*
>>    * Remove a name from the leaf attribute list structure
>>    *
>>    * This leaf block cannot have a "remote" value, we only call this routine
>> @@ -771,13 +813,11 @@ xfs_attr_leaf_removename(
>>   	 * Remove the attribute.
>>   	 */
>>   	dp = args->dp;
>> -	args->blkno = 0;
>> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
>> -				    XFS_DABUF_MAP_NOMAPPING, &bp);
>> -	if (error)
>> +
>> +	error = xfs_attr_leaf_hasname(args, &bp);
>> +	if (error != -ENOATTR && error != -EEXIST)
>>   		return error;
>>   
>> -	error = xfs_attr3_leaf_lookup_int(bp, args);
>>   	if (error == -ENOATTR) {
>>   		xfs_trans_brelse(args->trans, bp);
>>   		return error;
>> @@ -816,13 +856,10 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>>   
>>   	trace_xfs_attr_leaf_get(args);
>>   
>> -	args->blkno = 0;
>> -	error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
>> -				    XFS_DABUF_MAP_NOMAPPING, &bp);
>> -	if (error)
>> +	error = xfs_attr_leaf_hasname(args, &bp);
>> +	if (error != -ENOATTR && error != -EEXIST)
>>   		return error;
>>   
>> -	error = xfs_attr3_leaf_lookup_int(bp, args);
>>   	if (error != -EEXIST)  {
>>   		xfs_trans_brelse(args->trans, bp);
>>   		return error;
>> @@ -832,6 +869,38 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>>   	return error;
>>   }
>>   
>> +/*
>> + * Return EEXIST if attr is found, or ENOATTR if not
>> + * statep: If not null is set to point at the found state.  Caller will
>> + * 	   be responsible for freeing the state in this case.
>> + */
>> +STATIC int
>> +xfs_attr_node_hasname(
>> +	struct xfs_da_args	*args,
>> +	struct xfs_da_state	**statep)
>> +{
>> +	struct xfs_da_state	*state;
>> +	int			retval, error;
>> +
>> +	state = xfs_da_state_alloc();
>> +	state->args = args;
>> +	state->mp = args->dp->i_mount;
>> +
>> +	/*
>> +	 * Search to see if name exists, and get back a pointer to it.
>> +	 */
>> +	error = xfs_da3_node_lookup_int(state, &retval);
>> +	if (error == 0)
>> +		error = retval;
>> +
>> +	if (statep != NULL)
>> +		*statep = state;
>> +	else
>> +		xfs_da_state_free(state);
>> +
>> +	return error;
>> +}
>> +
>>   /*========================================================================
>>    * External routines when attribute list size > geo->blksize
>>    *========================================================================*/
>> @@ -864,20 +933,17 @@ xfs_attr_node_addname(
>>   	dp = args->dp;
>>   	mp = dp->i_mount;
>>   restart:
>> -	state = xfs_da_state_alloc();
>> -	state->args = args;
>> -	state->mp = mp;
>> -
>>   	/*
>>   	 * Search to see if name already exists, and get back a pointer
>>   	 * to where it should go.
>>   	 */
>> -	error = xfs_da3_node_lookup_int(state, &retval);
>> -	if (error)
>> +	retval = xfs_attr_node_hasname(args, &state);
>> +	if (retval != -ENOATTR)
>>   		goto out;
>> +
>>   	blk = &state->path.blk[ state->path.active-1 ];
>>   	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>> -	if ((args->name.type & ATTR_REPLACE) && (retval == -ENOATTR)) {
>> +	if (args->name.type & ATTR_REPLACE) {
>>   		goto out;
>>   	} else if (retval == -EEXIST) {
>>   		if (args->name.type & ATTR_CREATE)
>> @@ -1079,29 +1145,15 @@ xfs_attr_node_removename(
>>   {
>>   	struct xfs_da_state	*state;
>>   	struct xfs_da_state_blk	*blk;
>> -	struct xfs_inode	*dp;
>>   	struct xfs_buf		*bp;
>>   	int			retval, error, forkoff;
>> +	struct xfs_inode	*dp = args->dp;
>>   
>>   	trace_xfs_attr_node_removename(args);
>>   
>> -	/*
>> -	 * Tie a string around our finger to remind us where we are.
>> -	 */
>> -	dp = args->dp;
>> -	state = xfs_da_state_alloc();
>> -	state->args = args;
>> -	state->mp = dp->i_mount;
>> -
>> -	/*
>> -	 * Search to see if name exists, and get back a pointer to it.
>> -	 */
>> -	error = xfs_da3_node_lookup_int(state, &retval);
>> -	if (error || (retval != -EEXIST)) {
>> -		if (error == 0)
>> -			error = retval;
>> +	error = xfs_attr_node_hasname(args, &state);
>> +	if (error != -EEXIST)
>>   		goto out;
>> -	}
>>   
>>   	/*
>>   	 * If there is an out-of-line value, de-allocate the blocks.
>> @@ -1324,20 +1376,14 @@ xfs_attr_node_get(xfs_da_args_t *args)
>>   
>>   	trace_xfs_attr_node_get(args);
>>   
>> -	state = xfs_da_state_alloc();
>> -	state->args = args;
>> -	state->mp = args->dp->i_mount;
>> -
>>   	/*
>>   	 * Search to see if name exists, and get back a pointer to it.
>>   	 */
>> -	error = xfs_da3_node_lookup_int(state, &retval);
>> -	if (error) {
>> +	error = xfs_attr_node_hasname(args, &state);
>> +	if (error != -EEXIST) {
>>   		retval = error;
>>   		goto out_release;
>>   	}
>> -	if (retval != -EEXIST)
>> -		goto out_release;
>>   
>>   	/*
>>   	 * Get the value, local or "remote"
>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>> index 44dd07a..3b5dad4 100644
>> --- a/fs/xfs/libxfs/xfs_attr.h
>> +++ b/fs/xfs/libxfs/xfs_attr.h
>> @@ -150,6 +150,7 @@ int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
>>   		 unsigned char *value, int valuelen, int flags);
>>   int xfs_attr_set_args(struct xfs_da_args *args);
>>   int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
>> +int xfs_has_attr(struct xfs_da_args *args);
>>   int xfs_attr_remove_args(struct xfs_da_args *args);
>>   int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>>   		  int flags, struct attrlist_cursor_kern *cursor);
>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
>> index 93c3496..d06cfd6 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
>> @@ -655,18 +655,67 @@ xfs_attr_shortform_create(xfs_da_args_t *args)
>>   }
>>   
>>   /*
>> + * Return -EEXIST if attr is found, or -ENOATTR if not
>> + * args:  args containing attribute name and namelen
>> + * sfep:  If not null, pointer will be set to the last attr entry found on
>> +	  -EEXIST.  On -ENOATTR pointer is left at the last entry in the list
>> + * basep: If not null, pointer is set to the byte offset of the entry in the
>> + *	  list on -EEXIST.  On -ENOATTR, pointer is left at the byte offset of
>> + *	  the last entry in the list
>> + */
>> +int
>> +xfs_attr_shortform_hasname(
>> +	struct xfs_da_args	 *args,
>> +	struct xfs_attr_sf_entry **sfep,
>> +	int			 *basep)
> 
> Byte offsets can't be negative, so this should be unsigned int.
> 
> Seeing as we also return the location of the sf entry and byte offset,
> maybe this ought to be called xfs_attr_sf_findname ?

Sure, will fix.

> 
>> +{
>> +	struct xfs_attr_shortform *sf;
>> +	struct xfs_attr_sf_entry *sfe;
>> +	int			base = sizeof(struct xfs_attr_sf_hdr);
>> +	int			size = 0;
>> +	int			end;
>> +	int			i;
>> +
>> +	base = sizeof(struct xfs_attr_sf_hdr);
>> +	sf = (struct xfs_attr_shortform *)args->dp->i_afp->if_u1.if_data;
>> +	sfe = &sf->list[0];
>> +	end = sf->hdr.count;
>> +	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
>> +			base += size, i++) {
>> +		size = XFS_ATTR_SF_ENTSIZE(sfe);
>> +		if (sfe->namelen != args->name.len)
>> +			continue;
>> +		if (memcmp(sfe->nameval, args->name.name, args->name.len) != 0)
>> +			continue;
>> +		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
>> +			continue;
>> +		break;
>> +	}
>> +
>> +	if (sfep != NULL)
>> +		*sfep = sfe;
>> +
>> +	if (basep != NULL)
>> +		*basep = base;
>> +
>> +	if (i == end)
>> +		return -ENOATTR;
>> +	return -EEXIST;
>> +}
>> +
>> +/*
>>    * Add a name/value pair to the shortform attribute list.
>>    * Overflow from the inode has already been checked for.
>>    */
>>   void
>>   xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
>>   {
>> -	xfs_attr_shortform_t *sf;
>> -	xfs_attr_sf_entry_t *sfe;
>> -	int i, offset, size;
>> -	xfs_mount_t *mp;
>> -	xfs_inode_t *dp;
>> -	struct xfs_ifork *ifp;
>> +	struct xfs_attr_shortform	*sf;
>> +	struct xfs_attr_sf_entry	*sfe;
>> +	int				offset, size, error;
>> +	struct xfs_mount		*mp;
>> +	struct xfs_inode		*dp;
>> +	struct xfs_ifork		*ifp;
>>   
>>   	trace_xfs_attr_sf_add(args);
>>   
>> @@ -677,18 +726,8 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
>>   	ifp = dp->i_afp;
>>   	ASSERT(ifp->if_flags & XFS_IFINLINE);
>>   	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
>> -	sfe = &sf->list[0];
>> -	for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
>> -#ifdef DEBUG
>> -		if (sfe->namelen != args->name.len)
>> -			continue;
>> -		if (memcmp(args->name.name, sfe->nameval, args->name.len) != 0)
>> -			continue;
>> -		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
>> -			continue;
>> -		ASSERT(0);
>> -#endif
>> -	}
>> +	error = xfs_attr_shortform_hasname(args, &sfe, NULL);
>> +	ASSERT(error != -EEXIST);
> 
> If this assertion triggers, the fs is corrupt and we need to log
> something and bail out.  5.5 for-next will soon have a new
> XFS_IS_CORRUPT macro that takes care of this, so you can do:
> 
> 	error = xfs_attr_shortform_hasname(args, &sfe, NULL);
> 	if (XFS_IS_CORRUPT(mp, error != -EEXIST))
> 		return -EFSCORRUPTED;
> 
> --D
Ok, I will keep an eye out for that then.  Thanks!
Allison

> 
> 
>>   
>>   	offset = (char *)sfe - (char *)sf;
>>   	size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
>> @@ -733,33 +772,23 @@ xfs_attr_fork_remove(
>>   int
>>   xfs_attr_shortform_remove(xfs_da_args_t *args)
>>   {
>> -	xfs_attr_shortform_t *sf;
>> -	xfs_attr_sf_entry_t *sfe;
>> -	int base, size=0, end, totsize, i;
>> -	xfs_mount_t *mp;
>> -	xfs_inode_t *dp;
>> +	struct xfs_attr_shortform	*sf;
>> +	struct xfs_attr_sf_entry	*sfe;
>> +	int				base, size = 0, end, totsize;
>> +	struct xfs_mount		*mp;
>> +	struct xfs_inode		*dp;
>> +	int				error;
>>   
>>   	trace_xfs_attr_sf_remove(args);
>>   
>>   	dp = args->dp;
>>   	mp = dp->i_mount;
>> -	base = sizeof(xfs_attr_sf_hdr_t);
>>   	sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
>> -	sfe = &sf->list[0];
>> -	end = sf->hdr.count;
>> -	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
>> -					base += size, i++) {
>> -		size = XFS_ATTR_SF_ENTSIZE(sfe);
>> -		if (sfe->namelen != args->name.len)
>> -			continue;
>> -		if (memcmp(sfe->nameval, args->name.name, args->name.len) != 0)
>> -			continue;
>> -		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
>> -			continue;
>> -		break;
>> -	}
>> -	if (i == end)
>> -		return -ENOATTR;
>> +
>> +	error = xfs_attr_shortform_hasname(args, &sfe, &base);
>> +	if (error != -EEXIST)
>> +		return error;
>> +	size = XFS_ATTR_SF_ENTSIZE(sfe);
>>   
>>   	/*
>>   	 * Fix up the attribute fork data, covering the hole
>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
>> index 017480e..e108b37 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.h
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.h
>> @@ -42,6 +42,8 @@ int	xfs_attr_shortform_getvalue(struct xfs_da_args *args);
>>   int	xfs_attr_shortform_to_leaf(struct xfs_da_args *args,
>>   			struct xfs_buf **leaf_bp);
>>   int	xfs_attr_shortform_remove(struct xfs_da_args *args);
>> +int	xfs_attr_shortform_hasname(struct xfs_da_args *args,
>> +			       struct xfs_attr_sf_entry **sfep, int *basep);
>>   int	xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp);
>>   int	xfs_attr_shortform_bytesfit(struct xfs_inode *dp, int bytes);
>>   xfs_failaddr_t xfs_attr_shortform_verify(struct xfs_inode *ip);
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v4 06/17] xfs: Factor out new helper functions xfs_attr_rmtval_set
  2019-11-08 19:34   ` Darrick J. Wong
@ 2019-11-08 19:51     ` Allison Collins
  0 siblings, 0 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-08 19:51 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 11/8/19 12:34 PM, Darrick J. Wong wrote:
> On Wed, Nov 06, 2019 at 06:27:50PM -0700, Allison Collins wrote:
>> Break xfs_attr_rmtval_set into two helper functions
>> xfs_attr_rmt_find_hole and xfs_attr_rmtval_set_value.
>> xfs_attr_rmtval_set rolls the transaction between the
>> helpers, but delayed operations cannot.  We will use
>> the helpers later when constructing new delayed
>> attribute routines.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> Reviewed-by: Brian Foster <bfoster@redhat.com>
> 
> Looks good,
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
> 
> --D

Alrighty, thanks for the reviews!
Allison

> 
>> ---
>>   fs/xfs/libxfs/xfs_attr_remote.c | 71 +++++++++++++++++++++++++++++++----------
>>   fs/xfs/libxfs/xfs_attr_remote.h |  3 +-
>>   2 files changed, 56 insertions(+), 18 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
>> index db9247a..db51388 100644
>> --- a/fs/xfs/libxfs/xfs_attr_remote.c
>> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
>> @@ -21,6 +21,7 @@
>>   #include "xfs_attr.h"
>>   #include "xfs_trace.h"
>>   #include "xfs_error.h"
>> +#include "xfs_attr_remote.h"
>>   
>>   #define ATTR_RMTVALUE_MAPSIZE	1	/* # of map entries at once */
>>   
>> @@ -432,34 +433,20 @@ xfs_attr_rmtval_set(
>>   	struct xfs_da_args	*args)
>>   {
>>   	struct xfs_inode	*dp = args->dp;
>> -	struct xfs_mount	*mp = dp->i_mount;
>>   	struct xfs_bmbt_irec	map;
>>   	xfs_dablk_t		lblkno;
>> -	xfs_fileoff_t		lfileoff = 0;
>> -	uint8_t			*src = args->value;
>>   	int			blkcnt;
>> -	int			valuelen;
>>   	int			nmap;
>>   	int			error;
>> -	int			offset = 0;
>>   
>>   	trace_xfs_attr_rmtval_set(args);
>>   
>> -	/*
>> -	 * Find a "hole" in the attribute address space large enough for
>> -	 * us to drop the new attribute's value into. Because CRC enable
>> -	 * attributes have headers, we can't just do a straight byte to FSB
>> -	 * conversion and have to take the header space into account.
>> -	 */
>> -	blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
>> -	error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
>> -						   XFS_ATTR_FORK);
>> +	error = xfs_attr_rmt_find_hole(args);
>>   	if (error)
>>   		return error;
>>   
>> -	args->rmtblkno = lblkno = (xfs_dablk_t)lfileoff;
>> -	args->rmtblkcnt = blkcnt;
>> -
>> +	blkcnt = args->rmtblkcnt;
>> +	lblkno = (xfs_dablk_t)args->rmtblkno;
>>   	/*
>>   	 * Roll through the "value", allocating blocks on disk as required.
>>   	 */
>> @@ -500,6 +487,56 @@ xfs_attr_rmtval_set(
>>   			return error;
>>   	}
>>   
>> +	return xfs_attr_rmtval_set_value(args);
>> +}
>> +
>> +
>> +/*
>> + * Find a "hole" in the attribute address space large enough for us to drop the
>> + * new attribute's value into
>> + */
>> +int
>> +xfs_attr_rmt_find_hole(
>> +	struct xfs_da_args	*args)
>> +{
>> +	struct xfs_inode        *dp = args->dp;
>> +	struct xfs_mount	*mp = dp->i_mount;
>> +	int			error;
>> +	int			blkcnt;
>> +	xfs_fileoff_t		lfileoff = 0;
>> +
>> +	/*
>> +	 * Because CRC enable attributes have headers, we can't just do a
>> +	 * straight byte to FSB conversion and have to take the header space
>> +	 * into account.
>> +	 */
>> +	blkcnt = xfs_attr3_rmt_blocks(mp, args->rmtvaluelen);
>> +	error = xfs_bmap_first_unused(args->trans, args->dp, blkcnt, &lfileoff,
>> +						   XFS_ATTR_FORK);
>> +	if (error)
>> +		return error;
>> +
>> +	args->rmtblkno = (xfs_dablk_t)lfileoff;
>> +	args->rmtblkcnt = blkcnt;
>> +
>> +	return 0;
>> +}
>> +
>> +int
>> +xfs_attr_rmtval_set_value(
>> +	struct xfs_da_args	*args)
>> +{
>> +	struct xfs_inode	*dp = args->dp;
>> +	struct xfs_mount	*mp = dp->i_mount;
>> +	struct xfs_bmbt_irec	map;
>> +	xfs_dablk_t		lblkno;
>> +	uint8_t			*src = args->value;
>> +	int			blkcnt;
>> +	int			valuelen;
>> +	int			nmap;
>> +	int			error;
>> +	int			offset = 0;
>> +
>>   	/*
>>   	 * Roll through the "value", copying the attribute value to the
>>   	 * already-allocated blocks.  Blocks are written synchronously
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
>> index 9d20b66..cd7670d 100644
>> --- a/fs/xfs/libxfs/xfs_attr_remote.h
>> +++ b/fs/xfs/libxfs/xfs_attr_remote.h
>> @@ -11,5 +11,6 @@ int xfs_attr3_rmt_blocks(struct xfs_mount *mp, int attrlen);
>>   int xfs_attr_rmtval_get(struct xfs_da_args *args);
>>   int xfs_attr_rmtval_set(struct xfs_da_args *args);
>>   int xfs_attr_rmtval_remove(struct xfs_da_args *args);
>> -
>> +int xfs_attr_rmtval_set_value(struct xfs_da_args *args);
>> +int xfs_attr_rmt_find_hole(struct xfs_da_args *args);
>>   #endif /* __XFS_ATTR_REMOTE_H__ */
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v4 07/17] xfs: Factor up trans handling in xfs_attr3_leaf_flipflags
  2019-11-08 19:35   ` Darrick J. Wong
@ 2019-11-08 19:52     ` Allison Collins
  0 siblings, 0 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-08 19:52 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 11/8/19 12:35 PM, Darrick J. Wong wrote:
> On Wed, Nov 06, 2019 at 06:27:51PM -0700, Allison Collins wrote:
>> Since delayed operations cannot roll transactions, factor
>> up the transaction handling into the calling function
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> Reviewed-by: Brian Foster <bfoster@redhat.com>
> 
> Looks ok,
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
> 
> --D

Thank you!
Allison

> 
>> ---
>>   fs/xfs/libxfs/xfs_attr.c      | 14 ++++++++++++++
>>   fs/xfs/libxfs/xfs_attr_leaf.c |  5 -----
>>   2 files changed, 14 insertions(+), 5 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index c8a3273..212995f 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -721,6 +721,13 @@ xfs_attr_leaf_addname(
>>   		error = xfs_attr3_leaf_flipflags(args);
>>   		if (error)
>>   			return error;
>> +		/*
>> +		 * Commit the flag value change and start the next trans in
>> +		 * series.
>> +		 */
>> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> +		if (error)
>> +			return error;
>>   
>>   		/*
>>   		 * Dismantle the "old" attribute/value pair by removing
>> @@ -1057,6 +1064,13 @@ xfs_attr_node_addname(
>>   		error = xfs_attr3_leaf_flipflags(args);
>>   		if (error)
>>   			goto out;
>> +		/*
>> +		 * Commit the flag value change and start the next trans in
>> +		 * series
>> +		 */
>> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> +		if (error)
>> +			goto out;
>>   
>>   		/*
>>   		 * Dismantle the "old" attribute/value pair by removing
>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
>> index d06cfd6..134eb00 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
>> @@ -2973,10 +2973,5 @@ xfs_attr3_leaf_flipflags(
>>   			 XFS_DA_LOGRANGE(leaf2, name_rmt, sizeof(*name_rmt)));
>>   	}
>>   
>> -	/*
>> -	 * Commit the flag value change and start the next trans in series.
>> -	 */
>> -	error = xfs_trans_roll_inode(&args->trans, args->dp);
>> -
>>   	return error;
>>   }
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v4 08/17] xfs: Factor out xfs_attr_leaf_addname helper
  2019-11-07  1:27 ` [PATCH v4 08/17] xfs: Factor out xfs_attr_leaf_addname helper Allison Collins
@ 2019-11-08 20:57   ` Darrick J. Wong
  2019-11-09 21:41     ` Allison Collins
  0 siblings, 1 reply; 77+ messages in thread
From: Darrick J. Wong @ 2019-11-08 20:57 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Wed, Nov 06, 2019 at 06:27:52PM -0700, Allison Collins wrote:
> Factor out new helper function xfs_attr_leaf_try_add.
> Because new delayed attribute routines cannot roll
> transactions, we carve off the parts of
> xfs_attr_leaf_addname that we can use.  This will help
> to reduce repetitive code later when we introduce
> delayed attributes.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 84 +++++++++++++++++++++++++++++-------------------
>  1 file changed, 51 insertions(+), 33 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 212995f..dda2eba 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -305,10 +305,33 @@ xfs_attr_set_args(
>  		}
>  	}
>  
> -	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>  		error = xfs_attr_leaf_addname(args);
> -	else
> +		if (error == -ENOSPC) {
> +			/*
> +			 * Commit that transaction so that the node_addname()
> +			 * call can manage its own transactions.
> +			 */
> +			error = xfs_defer_finish(&args->trans);
> +			if (error)
> +				return error;
> +
> +			/*
> +			 * Commit the current trans (including the inode) and
> +			 * start a new one.
> +			 */
> +			error = xfs_trans_roll_inode(&args->trans, dp);
> +			if (error)
> +				return error;
> +
> +			/*
> +			 * Fob the rest of the problem off on the Btree code.
> +			 */
> +			error = xfs_attr_node_addname(args);
> +		}
> +	} else {
>  		error = xfs_attr_node_addname(args);
> +	}
>  	return error;


>  }
>  
> @@ -601,21 +624,12 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
>   * External routines when attribute list is one block
>   *========================================================================*/
>  
> -/*
> - * Add a name to the leaf attribute list structure
> - *
> - * This leaf block cannot have a "remote" value, we only call this routine
> - * if bmap_one_block() says there is only one block (ie: no remote blks).
> - */
>  STATIC int
> -xfs_attr_leaf_addname(
> -	struct xfs_da_args	*args)
> +xfs_attr_leaf_try_add(

(total stream of consciousness here...)

AFAICT the old _addname function's responsibilities were:

1 Try to add a new attr key entry to the leaf block, with INCOMPLETE set
  if it's a rename op or we need to set a remote value.
2 If there wasn't space in the leaf block, convert to node format, call
  the node version of this function, and exit.
3 Allocating blocks for the remote attr value and writing them, if
  applicable
4 If it's a rename operation, clearing the INCOMPLETE flag on the new
  entry; setting it on the old entry; and then removing the old entry.
5 Clearing the INCOMPLETE flag on the new entry when we're done writing
  a remote value (if applicable)

I think we arrive at this split so that we don't have a transaction roll
in the middle of the function, right?  And also to make the "convert to
node format and roll" bits go elsewhere?

The way I'm thinking about how to accomplish this is...

xfs_attr_leaf_addname should be renamed xfs_attr_leaf_setname, and then
hoist (1) into a separate function, move (2) into xfs_attr_set_args, and
hoist (4) into a separate function.

...ok, so let's test how closely my understanding fits the changes made
in this patch:

_try_add is basically (1).

Most of (2) happened, though the call to xfs_attr3_leaf_to_node ought to
go into the caller so that the conversion stays with the defer_finish
and roll.

(4) could still be done, maybe as a separate prep patch.

Hm, ok, I think I understand what this patch does.  The call site in
xfs_attr_set_args would be clearer (and less indenty) if it looked like:

	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
		error = xfs_attr_leaf_addname(args);
		if (error == 0 || error != -ENOSPC)
			return error;

		/* Promote the attribute list to node format. */
		error = xfs_attr3_leaf_to_node(args);
		if (error)
			return error;

		/*
		 * Commit that transaction so that the node_addname()
		 * call can manage its own transactions.
		 */
		error = xfs_defer_finish(&args->trans);
		if (error)
			return error;

		/*
		 * Commit the current trans (including the inode) and
		 * start a new one.
		 */
		error = xfs_trans_roll_inode(&args->trans, dp);
		if (error)
			return error;
	}

	return xfs_attr_node_addname(args);

But otherwise it looks decent, assuming I understood any of it. :)

--D

> +	struct xfs_da_args	*args,
> +	struct xfs_buf		*bp)
>  {
> -	struct xfs_buf		*bp;
> -	int			retval, error, forkoff;
> -	struct xfs_inode	*dp = args->dp;
> -
> -	trace_xfs_attr_leaf_addname(args);
> +	int			retval, error;
>  
>  	/*
>  	 * Look up the given attribute in the leaf block.  Figure out if
> @@ -661,31 +675,35 @@ xfs_attr_leaf_addname(
>  	retval = xfs_attr3_leaf_add(bp, args);
>  	if (retval == -ENOSPC) {
>  		/*
> -		 * Promote the attribute list to the Btree format, then
> -		 * Commit that transaction so that the node_addname() call
> -		 * can manage its own transactions.
> +		 * Promote the attribute list to the Btree format.
> +		 * Unless an error occurs, retain the -ENOSPC retval
>  		 */
>  		error = xfs_attr3_leaf_to_node(args);
>  		if (error)
>  			return error;
> -		error = xfs_defer_finish(&args->trans);
> -		if (error)
> -			return error;
> +	}
> +	return retval;
> +}
>  
> -		/*
> -		 * Commit the current trans (including the inode) and start
> -		 * a new one.
> -		 */
> -		error = xfs_trans_roll_inode(&args->trans, dp);
> -		if (error)
> -			return error;
>  
> -		/*
> -		 * Fob the whole rest of the problem off on the Btree code.
> -		 */
> -		error = xfs_attr_node_addname(args);
> +/*
> + * Add a name to the leaf attribute list structure
> + *
> + * This leaf block cannot have a "remote" value, we only call this routine
> + * if bmap_one_block() says there is only one block (ie: no remote blks).
> + */
> +STATIC int
> +xfs_attr_leaf_addname(struct xfs_da_args	*args)
> +{
> +	int			error, forkoff;
> +	struct xfs_buf		*bp = NULL;
> +	struct xfs_inode	*dp = args->dp;
> +
> +	trace_xfs_attr_leaf_addname(args);
> +
> +	error = xfs_attr_leaf_try_add(args, bp);
> +	if (error)
>  		return error;
> -	}
>  
>  	/*
>  	 * Commit the transaction that added the attr name so that
> -- 
> 2.7.4
> 

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

* Re: [PATCH v4 09/17] xfs: Factor up commit from xfs_attr_try_sf_addname
  2019-11-07  1:27 ` [PATCH v4 09/17] xfs: Factor up commit from xfs_attr_try_sf_addname Allison Collins
@ 2019-11-08 21:04   ` Darrick J. Wong
  2019-11-08 23:13     ` Allison Collins
  0 siblings, 1 reply; 77+ messages in thread
From: Darrick J. Wong @ 2019-11-08 21:04 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Wed, Nov 06, 2019 at 06:27:53PM -0700, Allison Collins wrote:
> New delayed attribute routines cannot handle transactions,
> so factor this up to the calling function.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 23 ++++++++++++-----------
>  1 file changed, 12 insertions(+), 11 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index dda2eba..e0a38a2 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -227,8 +227,7 @@ xfs_attr_try_sf_addname(
>  	struct xfs_da_args	*args)
>  {
>  
> -	struct xfs_mount	*mp = dp->i_mount;
> -	int			error, error2;
> +	int			error;
>  
>  	error = xfs_attr_shortform_addname(args);
>  	if (error == -ENOSPC)
> @@ -241,12 +240,7 @@ xfs_attr_try_sf_addname(
>  	if (!error && (args->name.type & ATTR_KERNOTIME) == 0)
>  		xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);

What if you moved this part (the conditional ichgtime) into
xfs_attr_shortform_addname?  Then this function can just go away.

>  
> -	if (mp->m_flags & XFS_MOUNT_WSYNC)
> -		xfs_trans_set_sync(args->trans);
> -
> -	error2 = xfs_trans_commit(args->trans);
> -	args->trans = NULL;
> -	return error ? error : error2;
> +	return error;
>  }
>  
>  /*
> @@ -258,7 +252,7 @@ xfs_attr_set_args(
>  {
>  	struct xfs_inode	*dp = args->dp;
>  	struct xfs_buf          *leaf_bp = NULL;
> -	int			error;
> +	int			error, error2 = 0;;
>  
>  	/*
>  	 * If the attribute list is non-existent or a shortform list,
> @@ -278,8 +272,15 @@ xfs_attr_set_args(
>  		 * Try to add the attr to the attribute list in the inode.
>  		 */
>  		error = xfs_attr_try_sf_addname(dp, args);
> -		if (error != -ENOSPC)
> -			return error;
> +		if (error != -ENOSPC) {
> +			if (dp->i_mount->m_flags & XFS_MOUNT_WSYNC)
> +				xfs_trans_set_sync(args->trans);
> +
> +			error2 = xfs_trans_commit(args->trans);
> +			args->trans = NULL;
> +			return error ? error : error2;

Can error be something other than 0 or EEXIST?  If so, does it make
sense to commit even in those cases?  (Have I asked this before...?) It
looks odd to me that we'd commit the transaction even if something
handed back EFSCORRUPTED.

Hm, it's a local attr fork so I guess the only possible error is ENOSPC?
If that's true then please add a comment/ASSERT to that effect.

--D

> +		}
> +
>  
>  		/*
>  		 * It won't fit in the shortform, transform to a leaf block.
> -- 
> 2.7.4
> 

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

* Re: [PATCH v4 11/17] xfs: Add xfs_attr3_leaf helper functions
  2019-11-07  1:27 ` [PATCH v4 11/17] xfs: Add xfs_attr3_leaf helper functions Allison Collins
@ 2019-11-08 21:17   ` Darrick J. Wong
  2019-11-09  0:09     ` Allison Collins
  0 siblings, 1 reply; 77+ messages in thread
From: Darrick J. Wong @ 2019-11-08 21:17 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Wed, Nov 06, 2019 at 06:27:55PM -0700, Allison Collins wrote:
> And new helper functions xfs_attr3_leaf_flag_is_set and
> xfs_attr3_leaf_flagsflipped.  These routines check to see
> if xfs_attr3_leaf_setflag or xfs_attr3_leaf_flipflags have
> already been run.  We will need this later for delayed
> attributes since routines may be recalled several times
> when -EAGAIN is returned.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr_leaf.c | 94 +++++++++++++++++++++++++++++++++++++++++++
>  fs/xfs/libxfs/xfs_attr_leaf.h |  2 +
>  2 files changed, 96 insertions(+)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> index 42c037e..023c616 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -2809,6 +2809,40 @@ xfs_attr3_leaf_clearflag(
>  }
>  
>  /*
> + * Check if the INCOMPLETE flag on an entry in a leaf block is set.  This
> + * function can be used to check if xfs_attr3_leaf_setflag has already been
> + * called.  The INCOMPLETE flag is used during attr rename operations to mark
> + * entries that are being renamed. Since renames should be atomic, only one of

It's also used when creating an xattr with a value stored in a remote
block so that we can commit the name entry to the log (with INCOMPLETE
set), allocate/write the remote value with ordered buffers, and then
commit a second transaction clearing the INCOMPLETE flag.

Now that I think about it ... this predicate is for non-rename setting
of attrs with remote values, and the "flagsflipped" predicate is for
rename operations, aren't they?

> + * them should appear as a completed attribute.
> + *
> + * isset is set to true if the flag is set or false otherwise
> + */
> +int
> +xfs_attr3_leaf_flag_is_set(
> +	struct xfs_da_args		*args,
> +	bool				*isset)
> +{
> +	struct xfs_attr_leafblock	*leaf;
> +	struct xfs_attr_leaf_entry	*entry;
> +	struct xfs_buf			*bp;
> +	struct xfs_inode		*dp = args->dp;
> +	int				error = 0;
> +
> +	error = xfs_attr3_leaf_read(args->trans, dp, args->blkno,
> +				    XFS_DABUF_MAP_NOMAPPING, &bp);
> +	if (error)
> +		return error;
> +
> +	leaf = bp->b_addr;
> +	entry = &xfs_attr3_leaf_entryp(leaf)[args->index];
> +
> +	*isset = ((entry->flags & XFS_ATTR_INCOMPLETE) != 0);
> +	xfs_trans_brelse(args->trans, bp);
> +
> +	return 0;
> +}
> +
> +/*
>   * Set the INCOMPLETE flag on an entry in a leaf block.
>   */
>  int
> @@ -2972,3 +3006,63 @@ xfs_attr3_leaf_flipflags(
>  
>  	return error;
>  }
> +
> +/*
> + * On a leaf entry, check to see if the INCOMPLETE flag is cleared
> + * in args->blkno/index and set in args->blkno2/index2.

Might be worth mentioning here that args->blkno is the old entry and
args->blkno2 is the new entry.  This predicate will be used (by the
deferred attr item recovery code) to decide if we have to finish that
part of a rename operation, right?

>  Note that they could be
> + * in different blocks, or in the same block.  This function can be used to
> + * check if xfs_attr3_leaf_flipflags has already been called.  The INCOMPLETE
> + * flag is used during attr rename operations to mark entries that are being
> + * renamed. Since renames should be atomic, only one of them should appear as a
> + * completed attribute.
> + *
> + * isflipped is set to true if flags are flipped or false otherwise
> + */
> +int
> +xfs_attr3_leaf_flagsflipped(

I don't like "flagsflipped" because it's not clear to me what "flipped"
means.

xfs_attr3_leaf_rename_is_incomplete() ?

> +	struct xfs_da_args		*args,
> +	bool				*isflipped)
> +{
> +	struct xfs_attr_leafblock	*leaf1;
> +	struct xfs_attr_leafblock	*leaf2;
> +	struct xfs_attr_leaf_entry	*entry1;
> +	struct xfs_attr_leaf_entry	*entry2;
> +	struct xfs_buf			*bp1;
> +	struct xfs_buf			*bp2;
> +	struct xfs_inode		*dp = args->dp;
> +	int				error = 0;
> +
> +	/*
> +	 * Read the block containing the "old" attr
> +	 */
> +	error = xfs_attr3_leaf_read(args->trans, dp, args->blkno,
> +				    XFS_DABUF_MAP_NOMAPPING, &bp1);
> +	if (error)
> +		return error;
> +
> +	/*
> +	 * Read the block containing the "new" attr, if it is different
> +	 */
> +	if (args->blkno2 != args->blkno) {
> +		error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno2,
> +					   -1, &bp2);
> +		if (error)

bp1 leaks here, I think.

> +			return error;
> +	} else {
> +		bp2 = bp1;
> +	}
> +
> +	leaf1 = bp1->b_addr;
> +	entry1 = &xfs_attr3_leaf_entryp(leaf1)[args->index];
> +
> +	leaf2 = bp2->b_addr;
> +	entry2 = &xfs_attr3_leaf_entryp(leaf2)[args->index2];
> +
> +	*isflipped = (((entry1->flags & XFS_ATTR_INCOMPLETE) == 0) &&

Nit: ((entry1->flags & XFS_ATTR_INCOMPLETE) == 0) could be written as
!(entry1->flags & XFS_ATTR_INCOMPLETE)

> +		      (entry2->flags & XFS_ATTR_INCOMPLETE));
> +
> +	xfs_trans_brelse(args->trans, bp1);
> +	xfs_trans_brelse(args->trans, bp2);

This double-frees bp2 if bp1 == bp2.

--D


> +
> +	return 0;
> +}
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
> index e108b37..12283cf 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.h
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.h
> @@ -57,7 +57,9 @@ int	xfs_attr3_leaf_to_shortform(struct xfs_buf *bp,
>  				   struct xfs_da_args *args, int forkoff);
>  int	xfs_attr3_leaf_clearflag(struct xfs_da_args *args);
>  int	xfs_attr3_leaf_setflag(struct xfs_da_args *args);
> +int	xfs_attr3_leaf_flag_is_set(struct xfs_da_args *args, bool *isset);
>  int	xfs_attr3_leaf_flipflags(struct xfs_da_args *args);
> +int	xfs_attr3_leaf_flagsflipped(struct xfs_da_args *args, bool *isflipped);
>  
>  /*
>   * Routines used for growing the Btree.
> -- 
> 2.7.4
> 

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

* Re: [PATCH v4 12/17] xfs: Factor out xfs_attr_rmtval_invalidate
  2019-11-07  1:27 ` [PATCH v4 12/17] xfs: Factor out xfs_attr_rmtval_invalidate Allison Collins
@ 2019-11-08 21:19   ` Darrick J. Wong
  2019-11-09  0:10     ` Allison Collins
  0 siblings, 1 reply; 77+ messages in thread
From: Darrick J. Wong @ 2019-11-08 21:19 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Wed, Nov 06, 2019 at 06:27:56PM -0700, Allison Collins wrote:
> Because new delayed attribute routines cannot roll
> transactions, we carve off the parts of
> xfs_attr_rmtval_remove that we can use.  This will help to
> reduce repetitive code later when we introduce delayed
> attributes.

Looks good.
Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

--D


> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> Reviewed-by: Brian Foster <bfoster@redhat.com>
> ---
>  fs/xfs/libxfs/xfs_attr_remote.c | 30 +++++++++++++++++++++---------
>  fs/xfs/libxfs/xfs_attr_remote.h |  1 +
>  2 files changed, 22 insertions(+), 9 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
> index db51388..1544138 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.c
> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
> @@ -588,21 +588,14 @@ xfs_attr_rmtval_set_value(
>  	return 0;
>  }
>  
> -/*
> - * Remove the value associated with an attribute by deleting the
> - * out-of-line buffer that it is stored on.
> - */
>  int
> -xfs_attr_rmtval_remove(
> +xfs_attr_rmtval_invalidate(
>  	struct xfs_da_args	*args)
>  {
>  	struct xfs_mount	*mp = args->dp->i_mount;
>  	xfs_dablk_t		lblkno;
>  	int			blkcnt;
>  	int			error;
> -	int			done;
> -
> -	trace_xfs_attr_rmtval_remove(args);
>  
>  	/*
>  	 * Roll through the "value", invalidating the attribute value's blocks.
> @@ -644,13 +637,32 @@ xfs_attr_rmtval_remove(
>  		lblkno += map.br_blockcount;
>  		blkcnt -= map.br_blockcount;
>  	}
> +	return 0;
> +}
>  
> +/*
> + * Remove the value associated with an attribute by deleting the
> + * out-of-line buffer that it is stored on.
> + */
> +int
> +xfs_attr_rmtval_remove(
> +	struct xfs_da_args      *args)
> +{
> +	xfs_dablk_t		lblkno;
> +	int			blkcnt;
> +	int			error = 0;
> +	int			done = 0;
> +
> +	trace_xfs_attr_rmtval_remove(args);
> +
> +	error = xfs_attr_rmtval_invalidate(args);
> +	if (error)
> +		return error;
>  	/*
>  	 * Keep de-allocating extents until the remote-value region is gone.
>  	 */
>  	lblkno = args->rmtblkno;
>  	blkcnt = args->rmtblkcnt;
> -	done = 0;
>  	while (!done) {
>  		error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
>  				    XFS_BMAPI_ATTRFORK, 1, &done);
> diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
> index cd7670d..b6fd35a 100644
> --- a/fs/xfs/libxfs/xfs_attr_remote.h
> +++ b/fs/xfs/libxfs/xfs_attr_remote.h
> @@ -11,6 +11,7 @@ int xfs_attr3_rmt_blocks(struct xfs_mount *mp, int attrlen);
>  int xfs_attr_rmtval_get(struct xfs_da_args *args);
>  int xfs_attr_rmtval_set(struct xfs_da_args *args);
>  int xfs_attr_rmtval_remove(struct xfs_da_args *args);
> +int xfs_attr_rmtval_invalidate(struct xfs_da_args *args);
>  int xfs_attr_rmtval_set_value(struct xfs_da_args *args);
>  int xfs_attr_rmt_find_hole(struct xfs_da_args *args);
>  #endif /* __XFS_ATTR_REMOTE_H__ */
> -- 
> 2.7.4
> 

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

* Re: [PATCH v4 13/17] xfs: Factor up trans roll in xfs_attr3_leaf_clearflag
  2019-11-07  1:27 ` [PATCH v4 13/17] xfs: Factor up trans roll in xfs_attr3_leaf_clearflag Allison Collins
@ 2019-11-08 21:19   ` Darrick J. Wong
  2019-11-09  0:11     ` Allison Collins
  2019-11-11 18:23   ` Brian Foster
  1 sibling, 1 reply; 77+ messages in thread
From: Darrick J. Wong @ 2019-11-08 21:19 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Wed, Nov 06, 2019 at 06:27:57PM -0700, Allison Collins wrote:
> New delayed allocation routines cannot be handling
> transactions so factor them up into the calling functions
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>

Looks pretty straightforward,

Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>

--D

> ---
>  fs/xfs/libxfs/xfs_attr.c      | 16 ++++++++++++++++
>  fs/xfs/libxfs/xfs_attr_leaf.c |  5 +----
>  2 files changed, 17 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 2f9fb7a..5dcb19f 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -797,6 +797,14 @@ xfs_attr_leaf_addname(struct xfs_da_args	*args)
>  		 * Added a "remote" value, just clear the incomplete flag.
>  		 */
>  		error = xfs_attr3_leaf_clearflag(args);
> +		if (error)
> +			return error;
> +
> +		/*
> +		 * Commit the flag value change and start the next trans in
> +		 * series.
> +		 */
> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
>  	}
>  	return error;
>  }
> @@ -1154,6 +1162,14 @@ xfs_attr_node_addname(
>  		error = xfs_attr3_leaf_clearflag(args);
>  		if (error)
>  			goto out;
> +
> +		 /*
> +		  * Commit the flag value change and start the next trans in
> +		  * series.
> +		  */
> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
> +		if (error)
> +			goto out;
>  	}
>  	retval = error = 0;
>  
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> index 023c616..07eee3ff 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -2802,10 +2802,7 @@ xfs_attr3_leaf_clearflag(
>  			 XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt)));
>  	}
>  
> -	/*
> -	 * Commit the flag value change and start the next trans in series.
> -	 */
> -	return xfs_trans_roll_inode(&args->trans, args->dp);
> +	return error;
>  }
>  
>  /*
> -- 
> 2.7.4
> 

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

* Re: [PATCH v4 14/17] xfs: Add delay context to xfs_da_args
  2019-11-07  1:27 ` [PATCH v4 14/17] xfs: Add delay context to xfs_da_args Allison Collins
@ 2019-11-08 21:22   ` Darrick J. Wong
  2019-11-09  0:23     ` Allison Collins
  2019-11-11 18:23   ` Brian Foster
  1 sibling, 1 reply; 77+ messages in thread
From: Darrick J. Wong @ 2019-11-08 21:22 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Wed, Nov 06, 2019 at 06:27:58PM -0700, Allison Collins wrote:
> This patch adds a new struct xfs_delay_context, which we
> will use to keep track of the current state of a delayed
> attribute operation.
> 
> The new enum is used to track various operations that
> are in progress so that we know not to repeat them, and
> resume where we left off before EAGAIN was returned to
> cycle out the transaction.  Other members take the place
> of local variables that need to retain their values
> across multiple function recalls.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_da_btree.h | 28 ++++++++++++++++++++++++++++
>  fs/xfs/scrub/common.c        |  2 ++
>  fs/xfs/xfs_acl.c             |  2 ++
>  fs/xfs/xfs_attr_list.c       |  1 +
>  fs/xfs/xfs_ioctl.c           |  2 ++
>  fs/xfs/xfs_ioctl32.c         |  2 ++
>  fs/xfs/xfs_iops.c            |  2 ++
>  fs/xfs/xfs_xattr.c           |  1 +
>  8 files changed, 40 insertions(+)
> 
> diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
> index bed4f40..ef23ed8 100644
> --- a/fs/xfs/libxfs/xfs_da_btree.h
> +++ b/fs/xfs/libxfs/xfs_da_btree.h
> @@ -42,6 +42,33 @@ enum xfs_dacmp {
>  	XFS_CMP_CASE		/* names are same but differ in case */
>  };
>  
> +enum xfs_attr_state {

enum xfs_dc_state ?

Hm, "dc" seems a little short.

enum xfs_delattr_state?

> +	XFS_DC_INIT		= 1, /* Init delay info */
> +	XFS_DC_SF_TO_LEAF	= 2, /* Converted short form to leaf */
> +	XFS_DC_FOUND_LBLK	= 3, /* We found leaf blk for attr */
> +	XFS_DC_LEAF_TO_NODE	= 4, /* Converted leaf to node */
> +	XFS_DC_FOUND_NBLK	= 5, /* We found node blk for attr */
> +	XFS_DC_ALLOC_LEAF	= 6, /* We are allocating leaf blocks */
> +	XFS_DC_ALLOC_NODE	= 7, /* We are allocating node blocks */
> +	XFS_DC_RM_INVALIDATE	= 8, /* We are invalidating blocks */
> +	XFS_DC_RM_SHRINK	= 9, /* We are shrinking the tree */
> +	XFS_DC_RM_NODE_BLKS	= 10,/* We are removing node blocks */
> +};
> +
> +/*
> + * Context used for keeping track of delayed attribute operations
> + */
> +struct xfs_delay_context {

struct xfs_delattr_context ?

> +	enum xfs_attr_state	dc_state;
> +	struct xfs_buf		*leaf_bp;
> +	struct xfs_bmbt_irec	map;
> +	xfs_dablk_t		lblkno;
> +	xfs_fileoff_t		lfileoff;
> +	int			blkcnt;
> +	struct xfs_da_state	*da_state;
> +	struct xfs_da_state_blk *blk;
> +};

Would be kinda nice to keep this structure size to a minimum by
reordering these in order of decreasing size.  pahole is your friend for
doing that (or shouting me down). ;)

But otherwise this seems ok.

--D

> +
>  /*
>   * Structure to ease passing around component names.
>   */
> @@ -69,6 +96,7 @@ typedef struct xfs_da_args {
>  	int		rmtvaluelen2;	/* remote attr value length in bytes */
>  	int		op_flags;	/* operation flags */
>  	enum xfs_dacmp	cmpresult;	/* name compare result for lookups */
> +	struct xfs_delay_context  dc;	/* context used for delay attr ops */
>  } xfs_da_args_t;
>  
>  /*
> diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
> index 1887605..9a649d1 100644
> --- a/fs/xfs/scrub/common.c
> +++ b/fs/xfs/scrub/common.c
> @@ -24,6 +24,8 @@
>  #include "xfs_rmap_btree.h"
>  #include "xfs_log.h"
>  #include "xfs_trans_priv.h"
> +#include "xfs_da_format.h"
> +#include "xfs_da_btree.h"
>  #include "xfs_attr.h"
>  #include "xfs_reflink.h"
>  #include "scrub/scrub.h"
> diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
> index e868755..1336477 100644
> --- a/fs/xfs/xfs_acl.c
> +++ b/fs/xfs/xfs_acl.c
> @@ -10,6 +10,8 @@
>  #include "xfs_trans_resv.h"
>  #include "xfs_mount.h"
>  #include "xfs_inode.h"
> +#include "xfs_da_format.h"
> +#include "xfs_da_btree.h"
>  #include "xfs_attr.h"
>  #include "xfs_trace.h"
>  #include <linux/posix_acl_xattr.h>
> diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
> index fab416c..e395864 100644
> --- a/fs/xfs/xfs_attr_list.c
> +++ b/fs/xfs/xfs_attr_list.c
> @@ -12,6 +12,7 @@
>  #include "xfs_trans_resv.h"
>  #include "xfs_mount.h"
>  #include "xfs_da_format.h"
> +#include "xfs_da_btree.h"
>  #include "xfs_inode.h"
>  #include "xfs_trans.h"
>  #include "xfs_bmap.h"
> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> index ae0ed88..23b0ca6 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -15,6 +15,8 @@
>  #include "xfs_iwalk.h"
>  #include "xfs_itable.h"
>  #include "xfs_error.h"
> +#include "xfs_da_format.h"
> +#include "xfs_da_btree.h"
>  #include "xfs_attr.h"
>  #include "xfs_bmap.h"
>  #include "xfs_bmap_util.h"
> diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c
> index 3c0d518..e3278ac 100644
> --- a/fs/xfs/xfs_ioctl32.c
> +++ b/fs/xfs/xfs_ioctl32.c
> @@ -17,6 +17,8 @@
>  #include "xfs_itable.h"
>  #include "xfs_fsops.h"
>  #include "xfs_rtalloc.h"
> +#include "xfs_da_format.h"
> +#include "xfs_da_btree.h"
>  #include "xfs_attr.h"
>  #include "xfs_ioctl.h"
>  #include "xfs_ioctl32.h"
> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> index aef346e..68b9cd0 100644
> --- a/fs/xfs/xfs_iops.c
> +++ b/fs/xfs/xfs_iops.c
> @@ -13,6 +13,8 @@
>  #include "xfs_inode.h"
>  #include "xfs_acl.h"
>  #include "xfs_quota.h"
> +#include "xfs_da_format.h"
> +#include "xfs_da_btree.h"
>  #include "xfs_attr.h"
>  #include "xfs_trans.h"
>  #include "xfs_trace.h"
> diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
> index 6c5321d..0f0ebab 100644
> --- a/fs/xfs/xfs_xattr.c
> +++ b/fs/xfs/xfs_xattr.c
> @@ -10,6 +10,7 @@
>  #include "xfs_log_format.h"
>  #include "xfs_da_format.h"
>  #include "xfs_inode.h"
> +#include "xfs_da_btree.h"
>  #include "xfs_attr.h"
>  
>  #include <linux/posix_acl_xattr.h>
> -- 
> 2.7.4
> 

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

* Re: [PATCH v4 15/17] xfs: Check for -ENOATTR or -EEXIST
  2019-11-07  1:27 ` [PATCH v4 15/17] xfs: Check for -ENOATTR or -EEXIST Allison Collins
@ 2019-11-08 21:28   ` Darrick J. Wong
  2019-11-08 21:42     ` Allison Collins
  2019-11-11 18:24   ` Brian Foster
  1 sibling, 1 reply; 77+ messages in thread
From: Darrick J. Wong @ 2019-11-08 21:28 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Wed, Nov 06, 2019 at 06:27:59PM -0700, Allison Collins wrote:
> Delayed operations cannot return error codes.  So we must check for
> these conditions first before starting set or remove operations
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 25 +++++++++++++++++++++++++
>  1 file changed, 25 insertions(+)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 5dcb19f..626d4a98 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -458,6 +458,27 @@ xfs_attr_set(
>  		goto out_trans_cancel;
>  
>  	xfs_trans_ijoin(args.trans, dp, 0);
> +
> +	error = xfs_has_attr(&args);
> +	if (error == -EEXIST) {
> +		if (name->type & ATTR_CREATE)
> +			goto out_trans_cancel;
> +		else
> +			name->type |= ATTR_REPLACE;
> +	}
> +
> +	if (error == -ENOATTR && (name->type & ATTR_REPLACE))
> +		goto out_trans_cancel;
> +
> +	if (name->type & ATTR_REPLACE) {
> +		name->type &= ~ATTR_REPLACE;
> +		error = xfs_attr_remove_args(&args);
> +		if (error)
> +			goto out_trans_cancel;
> +
> +		name->type |= ATTR_CREATE;

I thought _set_args already handled the remove part of replacing an
attr?  And I thought that it did this with an atomic rename?  Won't this
break the atomicity of attr replacement?

--D

> +	}
> +
>  	error = xfs_attr_set_args(&args);
>  	if (error)
>  		goto out_trans_cancel;
> @@ -543,6 +564,10 @@ xfs_attr_remove(
>  	 */
>  	xfs_trans_ijoin(args.trans, dp, 0);
>  
> +	error = xfs_has_attr(&args);
> +	if (error == -ENOATTR)
> +		goto out;
> +
>  	error = xfs_attr_remove_args(&args);
>  	if (error)
>  		goto out;
> -- 
> 2.7.4
> 

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

* Re: [PATCH v4 16/17] xfs: Add delay ready attr remove routines
  2019-11-07  1:28 ` [PATCH v4 16/17] xfs: Add delay ready attr remove routines Allison Collins
@ 2019-11-08 21:37   ` Darrick J. Wong
  2019-11-09  0:25     ` Allison Collins
  2019-11-12 13:37   ` Brian Foster
  1 sibling, 1 reply; 77+ messages in thread
From: Darrick J. Wong @ 2019-11-08 21:37 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Wed, Nov 06, 2019 at 06:28:00PM -0700, Allison Collins wrote:
> This patch modifies the attr remove routines to be delay ready.
> This means they no longer roll or commit transactions, but instead
> return -EAGAIN to have the calling routine roll and refresh the
> transaction.  In this series, xfs_attr_remove_args has become
> xfs_attr_remove_later, which uses a state machine to keep track
> of where it was when EAGAIN was returned.  xfs_attr_node_removename
> has also been modified to use the state machine, and a  new version of
> xfs_attr_remove_args consists of a simple loop to refresh the
> transaction until the operation is completed.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 123 +++++++++++++++++++++++++++++++++++++++--------
>  fs/xfs/libxfs/xfs_attr.h |   1 +
>  2 files changed, 104 insertions(+), 20 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 626d4a98..38d5c5c 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -369,10 +369,56 @@ xfs_has_attr(
>   */
>  int
>  xfs_attr_remove_args(
> +	struct xfs_da_args	*args)
> +{
> +	int			error = 0;
> +	int			err2 = 0;
> +
> +	do {
> +		error = xfs_attr_remove_later(args);
> +		if (error && error != -EAGAIN)
> +			goto out;
> +
> +		xfs_trans_log_inode(args->trans, args->dp,
> +			XFS_ILOG_CORE | XFS_ILOG_ADATA);

Don't the individual pieces of attr removal log ADATA on their own, when
needed?

If it weren't for that, this could just be xfs_trans_roll_inode, right?

--D

> +
> +		err2 = xfs_trans_roll(&args->trans);
> +		if (err2) {
> +			error = err2;
> +			goto out;
> +		}
> +
> +		/* Rejoin inode */
> +		xfs_trans_ijoin(args->trans, args->dp, 0);
> +
> +	} while (error == -EAGAIN);
> +out:
> +	return error;
> +}
> +
> +/*
> + * Remove the attribute specified in @args.
> + * This routine is meant to function as a delayed operation, and may return
> + * -EGAIN when the transaction needs to be rolled.  Calling functions will need
> + * to handle this, and recall the function until a successful error code is
> + * returned.
> + */
> +int
> +xfs_attr_remove_later(
>  	struct xfs_da_args      *args)
>  {
>  	struct xfs_inode	*dp = args->dp;
> -	int			error;
> +	int			error = 0;
> +
> +	/* State machine switch */
> +	switch (args->dc.dc_state) {
> +	case XFS_DC_RM_INVALIDATE:
> +	case XFS_DC_RM_SHRINK:
> +	case XFS_DC_RM_NODE_BLKS:
> +		goto node;
> +	default:
> +		break;
> +	}
>  
>  	if (!xfs_inode_hasattr(dp)) {
>  		error = -ENOATTR;
> @@ -382,6 +428,7 @@ xfs_attr_remove_args(
>  	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>  		error = xfs_attr_leaf_removename(args);
>  	} else {
> +node:
>  		error = xfs_attr_node_removename(args);
>  	}
>  
> @@ -892,9 +939,6 @@ xfs_attr_leaf_removename(
>  		/* bp is gone due to xfs_da_shrink_inode */
>  		if (error)
>  			return error;
> -		error = xfs_defer_finish(&args->trans);
> -		if (error)
> -			return error;
>  	}
>  	return 0;
>  }
> @@ -1212,6 +1256,11 @@ xfs_attr_node_addname(
>   * This will involve walking down the Btree, and may involve joining
>   * leaf nodes and even joining intermediate nodes up to and including
>   * the root node (a special case of an intermediate node).
> + *
> + * This routine is meant to function as a delayed operation, and may return
> + * -EAGAIN when the transaction needs to be rolled.  Calling functions
> + * will need to handle this, and recall the function until a successful error
> + * code is returned.
>   */
>  STATIC int
>  xfs_attr_node_removename(
> @@ -1222,12 +1271,29 @@ xfs_attr_node_removename(
>  	struct xfs_buf		*bp;
>  	int			retval, error, forkoff;
>  	struct xfs_inode	*dp = args->dp;
> +	int			done = 0;
>  
>  	trace_xfs_attr_node_removename(args);
> +	state = args->dc.da_state;
> +	blk = args->dc.blk;
> +
> +	/* State machine switch */
> +	switch (args->dc.dc_state) {
> +	case XFS_DC_RM_NODE_BLKS:
> +		goto rm_node_blks;
> +	case XFS_DC_RM_INVALIDATE:
> +		goto rm_invalidate;
> +	case XFS_DC_RM_SHRINK:
> +		goto rm_shrink;
> +	default:
> +		break;
> +	}
>  
>  	error = xfs_attr_node_hasname(args, &state);
>  	if (error != -EEXIST)
>  		goto out;
> +	else
> +		error = 0;
>  
>  	/*
>  	 * If there is an out-of-line value, de-allocate the blocks.
> @@ -1237,6 +1303,14 @@ xfs_attr_node_removename(
>  	blk = &state->path.blk[ state->path.active-1 ];
>  	ASSERT(blk->bp != NULL);
>  	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> +
> +	/*
> +	 * Store blk and state in the context incase we need to cycle out the
> +	 * transaction
> +	 */
> +	args->dc.blk = blk;
> +	args->dc.da_state = state;
> +
>  	if (args->rmtblkno > 0) {
>  		/*
>  		 * Fill in disk block numbers in the state structure
> @@ -1255,13 +1329,30 @@ xfs_attr_node_removename(
>  		if (error)
>  			goto out;
>  
> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
> +		args->dc.dc_state = XFS_DC_RM_INVALIDATE;
> +		return -EAGAIN;
> +rm_invalidate:
> +		error = xfs_attr_rmtval_invalidate(args);
>  		if (error)
>  			goto out;
> +rm_node_blks:
> +		/*
> +		 * Unmap value blocks for this attr.  This is similar to
> +		 * xfs_attr_rmtval_remove, but open coded here to return EAGAIN
> +		 * for new transactions
> +		 */
> +		while (!done && !error) {
> +			error = xfs_bunmapi(args->trans, args->dp,
> +				    args->rmtblkno, args->rmtblkcnt,
> +				    XFS_BMAPI_ATTRFORK, 1, &done);
> +			if (error)
> +				return error;
>  
> -		error = xfs_attr_rmtval_remove(args);
> -		if (error)
> -			goto out;
> +			if (!done) {
> +				args->dc.dc_state = XFS_DC_RM_NODE_BLKS;
> +				return -EAGAIN;
> +			}
> +		}
>  
>  		/*
>  		 * Refill the state structure with buffers, the prior calls
> @@ -1287,17 +1378,12 @@ xfs_attr_node_removename(
>  		error = xfs_da3_join(state);
>  		if (error)
>  			goto out;
> -		error = xfs_defer_finish(&args->trans);
> -		if (error)
> -			goto out;
> -		/*
> -		 * Commit the Btree join operation and start a new trans.
> -		 */
> -		error = xfs_trans_roll_inode(&args->trans, dp);
> -		if (error)
> -			goto out;
> +
> +		args->dc.dc_state = XFS_DC_RM_SHRINK;
> +		return -EAGAIN;
>  	}
>  
> +rm_shrink:
>  	/*
>  	 * If the result is small enough, push it all into the inode.
>  	 */
> @@ -1319,9 +1405,6 @@ xfs_attr_node_removename(
>  			/* bp is gone due to xfs_da_shrink_inode */
>  			if (error)
>  				goto out;
> -			error = xfs_defer_finish(&args->trans);
> -			if (error)
> -				goto out;
>  		} else
>  			xfs_trans_brelse(args->trans, bp);
>  	}
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index 3b5dad4..fb8bf5b 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -152,6 +152,7 @@ int xfs_attr_set_args(struct xfs_da_args *args);
>  int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
>  int xfs_has_attr(struct xfs_da_args *args);
>  int xfs_attr_remove_args(struct xfs_da_args *args);
> +int xfs_attr_remove_later(struct xfs_da_args *args);
>  int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>  		  int flags, struct attrlist_cursor_kern *cursor);
>  bool xfs_attr_namecheck(const void *name, size_t length);
> -- 
> 2.7.4
> 

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

* Re: [PATCH v4 17/17] xfs: Add delay ready attr set routines
  2019-11-07  1:28 ` [PATCH v4 17/17] xfs: Add delay ready attr set routines Allison Collins
@ 2019-11-08 21:42   ` Darrick J. Wong
  2019-11-08 21:52     ` Allison Collins
  2019-11-09  4:07     ` Allison Collins
  2019-11-12 13:37   ` Brian Foster
  1 sibling, 2 replies; 77+ messages in thread
From: Darrick J. Wong @ 2019-11-08 21:42 UTC (permalink / raw)
  To: Allison Collins, g; +Cc: linux-xfs

On Wed, Nov 06, 2019 at 06:28:01PM -0700, Allison Collins wrote:
> This patch modifies the attr set routines to be delay ready.
> This means they no longer roll or commit transactions, but instead
> return -EAGAIN to have the calling routine roll and refresh the
> transaction.  In this series, xfs_attr_set_args has become
> xfs_attr_set_later, which uses a state machine to keep track
> of where it was when EAGAIN was returned.  Part of
> xfs_attr_leaf_addname has been factored out into a new helper
> function xfs_attr_leaf_try_add to allow transaction cycling between
> the two routines, and the flipflags logic has been removed since we
> can simply cancel the transaction upon error.  xfs_attr_set_args
> consists of a simple loop to refresh the transaction until the
> operation is completed.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 435 +++++++++++++++++++++++------------------------
>  fs/xfs/libxfs/xfs_attr.h |   1 +
>  2 files changed, 211 insertions(+), 225 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 38d5c5c..97e5ae0 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -58,6 +58,7 @@ STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
>  				 struct xfs_da_state **state);
>  STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
>  STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
> +STATIC int xfs_attr_leaf_try_add(struct xfs_da_args *args, struct xfs_buf *bp);
>  
>  
>  STATIC int
> @@ -250,9 +251,79 @@ int
>  xfs_attr_set_args(
>  	struct xfs_da_args	*args)
>  {
> +	int			error = 0;
> +	int			err2 = 0;
> +	struct xfs_buf		*leaf_bp = NULL;
> +
> +	do {
> +		error = xfs_attr_set_later(args, &leaf_bp);
> +		if (error && error != -EAGAIN)
> +			goto out;
> +
> +		xfs_trans_log_inode(args->trans, args->dp,
> +				    XFS_ILOG_CORE | XFS_ILOG_ADATA);

Same question as the last patch about ADATA.

> +
> +		err2 = xfs_trans_roll(&args->trans);
> +		if (err2) {
> +			error = err2;
> +			goto out;
> +		}
> +
> +		/* Rejoin inode and leaf if needed */
> +		xfs_trans_ijoin(args->trans, args->dp, 0);
> +		if (leaf_bp) {
> +			xfs_trans_bjoin(args->trans, leaf_bp);
> +			xfs_trans_bhold(args->trans, leaf_bp);
> +		}
> +
> +	} while (error == -EAGAIN);
> +
> +out:
> +	return error;
> +}
> +
> +/*
> + * Set the attribute specified in @args.
> + * This routine is meant to function as a delayed operation, and may return
> + * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
> + * to handle this, and recall the function until a successful error code is
> + * returned.
> + */
> +int
> +xfs_attr_set_later(
> +	struct xfs_da_args	*args,
> +	struct xfs_buf          **leaf_bp)
> +{
>  	struct xfs_inode	*dp = args->dp;
> -	struct xfs_buf          *leaf_bp = NULL;
> -	int			error, error2 = 0;;
> +	int			error = 0;
> +	int			sf_size;
> +
> +	/* State machine switch */
> +	switch (args->dc.dc_state) {
> +	case XFS_DC_SF_TO_LEAF:
> +		goto sf_to_leaf;
> +	case XFS_DC_ALLOC_LEAF:
> +	case XFS_DC_FOUND_LBLK:
> +		goto leaf;
> +	case XFS_DC_FOUND_NBLK:
> +	case XFS_DC_ALLOC_NODE:
> +	case XFS_DC_LEAF_TO_NODE:
> +		goto node;
> +	default:
> +		break;
> +	}
> +
> +	/*
> +	 * New inodes may not have an attribute fork yet. So set the attribute
> +	 * fork appropriately
> +	 */
> +	if (XFS_IFORK_Q((args->dp)) == 0) {
> +		sf_size = sizeof(struct xfs_attr_sf_hdr) +
> +		     XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
> +		xfs_bmap_set_attrforkoff(args->dp, sf_size, NULL);
> +		args->dp->i_afp = kmem_zone_zalloc(xfs_ifork_zone, 0);
> +		args->dp->i_afp->if_flags = XFS_IFEXTENTS;
> +	}
>  
>  	/*
>  	 * If the attribute list is non-existent or a shortform list,
> @@ -272,21 +343,14 @@ xfs_attr_set_args(
>  		 * Try to add the attr to the attribute list in the inode.
>  		 */
>  		error = xfs_attr_try_sf_addname(dp, args);
> -		if (error != -ENOSPC) {
> -			if (dp->i_mount->m_flags & XFS_MOUNT_WSYNC)
> -				xfs_trans_set_sync(args->trans);

Where does the xfs_trans_set_sync call go?  Do we not need it anymore?

> -			error2 = xfs_trans_commit(args->trans);
> -			args->trans = NULL;
> -			return error ? error : error2;
> -		}
> -
> +		if (error != -ENOSPC)
> +			return error;
>  
>  		/*
>  		 * It won't fit in the shortform, transform to a leaf block.
>  		 * GROT: another possible req'mt for a double-split btree op.
>  		 */
> -		error = xfs_attr_shortform_to_leaf(args, &leaf_bp);
> +		error = xfs_attr_shortform_to_leaf(args, leaf_bp);
>  		if (error)
>  			return error;
>  
> @@ -294,43 +358,42 @@ xfs_attr_set_args(
>  		 * Prevent the leaf buffer from being unlocked so that a
>  		 * concurrent AIL push cannot grab the half-baked leaf
>  		 * buffer and run into problems with the write verifier.
> -		 * Once we're done rolling the transaction we can release
> -		 * the hold and add the attr to the leaf.
>  		 */
> -		xfs_trans_bhold(args->trans, leaf_bp);
> -		error = xfs_defer_finish(&args->trans);
> -		xfs_trans_bhold_release(args->trans, leaf_bp);
> -		if (error) {
> -			xfs_trans_brelse(args->trans, leaf_bp);
> -			return error;
> -		}
> +
> +		xfs_trans_bhold(args->trans, *leaf_bp);
> +		args->dc.dc_state = XFS_DC_SF_TO_LEAF;
> +		return -EAGAIN;
> +	}
> +sf_to_leaf:
> +
> +	/*
> +	 * After a shortform to leaf conversion, we need to hold the leaf and
> +	 * cylce out the transaction.  When we get back, we need to release

           "cycle"

> +	 * the leaf.
> +	 */
> +	if (*leaf_bp != NULL) {
> +		xfs_trans_brelse(args->trans, *leaf_bp);
> +		*leaf_bp = NULL;
>  	}
>  
>  	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> +		error = xfs_attr_leaf_try_add(args, *leaf_bp);
> +		if (error == -ENOSPC)
> +			args->dc.dc_state = XFS_DC_LEAF_TO_NODE;
> +		else if (error)
> +			return error;
> +		else
> +			args->dc.dc_state = XFS_DC_FOUND_LBLK;
> +		return -EAGAIN;

Please use a switch statement here...

switch (error) {
case -ENOSPC:
	dc_state = LEAF_TO_NODE;
	return -EAGAIN;
case 0:
	dc_state = FOUND_LBLK;
	return -EAGAIN;
default:
	return error;
}

> +leaf:
>  		error = xfs_attr_leaf_addname(args);
>  		if (error == -ENOSPC) {
> -			/*
> -			 * Commit that transaction so that the node_addname()
> -			 * call can manage its own transactions.
> -			 */
> -			error = xfs_defer_finish(&args->trans);
> -			if (error)
> -				return error;
> -
> -			/*
> -			 * Commit the current trans (including the inode) and
> -			 * start a new one.
> -			 */
> -			error = xfs_trans_roll_inode(&args->trans, dp);
> -			if (error)
> -				return error;
> -
> -			/*
> -			 * Fob the rest of the problem off on the Btree code.
> -			 */
> -			error = xfs_attr_node_addname(args);
> +			args->dc.dc_state = XFS_DC_LEAF_TO_NODE;
> +			return -EAGAIN;
>  		}
>  	} else {
> +		args->dc.dc_state = XFS_DC_LEAF_TO_NODE;
> +node:
>  		error = xfs_attr_node_addname(args);
>  	}
>  	return error;
> @@ -764,27 +827,26 @@ xfs_attr_leaf_try_add(
>   *
>   * This leaf block cannot have a "remote" value, we only call this routine
>   * if bmap_one_block() says there is only one block (ie: no remote blks).
> + *
> + * This routine is meant to function as a delayed operation, and may return
> + * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
> + * to handle this, and recall the function until a successful error code is
> + * returned.
>   */
>  STATIC int
>  xfs_attr_leaf_addname(struct xfs_da_args	*args)
>  {
> -	int			error, forkoff;
> -	struct xfs_buf		*bp = NULL;
> +	int			error, nmap;
>  	struct xfs_inode	*dp = args->dp;
> +	struct xfs_bmbt_irec	*map = &args->dc.map;
>  
> -	trace_xfs_attr_leaf_addname(args);
> -
> -	error = xfs_attr_leaf_try_add(args, bp);
> -	if (error)
> -		return error;
> -
> -	/*
> -	 * Commit the transaction that added the attr name so that
> -	 * later routines can manage their own transactions.
> -	 */
> -	error = xfs_trans_roll_inode(&args->trans, dp);
> -	if (error)
> -		return error;
> +	/* State machine switch */
> +	switch (args->dc.dc_state) {
> +	case XFS_DC_ALLOC_LEAF:
> +		goto alloc_leaf;
> +	default:
> +		break;
> +	}
>  
>  	/*
>  	 * If there was an out-of-line value, allocate the blocks we
> @@ -793,90 +855,58 @@ xfs_attr_leaf_addname(struct xfs_da_args	*args)
>  	 * maximum size of a transaction and/or hit a deadlock.
>  	 */
>  	if (args->rmtblkno > 0) {
> -		error = xfs_attr_rmtval_set(args);
> -		if (error)
> -			return error;
> -	}
>  
> -	/*
> -	 * If this is an atomic rename operation, we must "flip" the
> -	 * incomplete flags on the "new" and "old" attribute/value pairs
> -	 * so that one disappears and one appears atomically.  Then we
> -	 * must remove the "old" attribute/value pair.
> -	 */
> -	if (args->op_flags & XFS_DA_OP_RENAME) {
> -		/*
> -		 * In a separate transaction, set the incomplete flag on the
> -		 * "old" attr and clear the incomplete flag on the "new" attr.
> -		 */
> -		error = xfs_attr3_leaf_flipflags(args);
> -		if (error)
> -			return error;
> -		/*
> -		 * Commit the flag value change and start the next trans in
> -		 * series.
> -		 */
> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
> -		if (error)
> -			return error;
> +		/* Open coded xfs_attr_rmtval_set without trans handling */

Can't we just fix that instead of reproducing it here?

Especially because I think I see it twice in this patch?

Also, do you have a git tree handy?  I /think/ I see how this works but
oh man is it difficult to see that from patches alone.

--D

>  
> -		/*
> -		 * Dismantle the "old" attribute/value pair by removing
> -		 * a "remote" value (if it exists).
> -		 */
> -		args->index = args->index2;
> -		args->blkno = args->blkno2;
> -		args->rmtblkno = args->rmtblkno2;
> -		args->rmtblkcnt = args->rmtblkcnt2;
> -		args->rmtvaluelen = args->rmtvaluelen2;
> -		if (args->rmtblkno) {
> -			error = xfs_attr_rmtval_remove(args);
> -			if (error)
> -				return error;
> -		}
> +		args->dc.lfileoff = 0;
> +		args->dc.lblkno = 0;
> +		args->dc.blkcnt = 0;
> +		args->rmtblkcnt = 0;
> +		args->rmtblkno = 0;
> +		memset(map, 0, sizeof(struct xfs_bmbt_irec));
>  
> -		/*
> -		 * Read in the block containing the "old" attr, then
> -		 * remove the "old" attr from that block (neat, huh!)
> -		 */
> -		error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
> -					   XFS_DABUF_MAP_NOMAPPING, &bp);
> +		error = xfs_attr_rmt_find_hole(args);
>  		if (error)
>  			return error;
>  
> -		xfs_attr3_leaf_remove(bp, args);
> +		args->dc.blkcnt = args->rmtblkcnt;
> +		args->dc.lblkno = args->rmtblkno;
>  
>  		/*
> -		 * If the result is small enough, shrink it all into the inode.
> +		 * Roll through the "value", allocating blocks on disk as
> +		 * required.
>  		 */
> -		if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
> -			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
> -			/* bp is gone due to xfs_da_shrink_inode */
> -			if (error)
> -				return error;
> -			error = xfs_defer_finish(&args->trans);
> +alloc_leaf:
> +		while (args->dc.blkcnt > 0) {
> +			nmap = 1;
> +			error = xfs_bmapi_write(args->trans, dp,
> +				  (xfs_fileoff_t)args->dc.lblkno,
> +				  args->dc.blkcnt, XFS_BMAPI_ATTRFORK,
> +				  args->total, map, &nmap);
>  			if (error)
>  				return error;
> -		}
> +			ASSERT(nmap == 1);
> +			ASSERT((map->br_startblock != DELAYSTARTBLOCK) &&
> +			       (map->br_startblock != HOLESTARTBLOCK));
>  
> -		/*
> -		 * Commit the remove and start the next trans in series.
> -		 */
> -		error = xfs_trans_roll_inode(&args->trans, dp);
> +			/* roll attribute extent map forwards */
> +			args->dc.lblkno += map->br_blockcount;
> +			args->dc.blkcnt -= map->br_blockcount;
>  
> -	} else if (args->rmtblkno > 0) {
> -		/*
> -		 * Added a "remote" value, just clear the incomplete flag.
> -		 */
> -		error = xfs_attr3_leaf_clearflag(args);
> +			args->dc.dc_state = XFS_DC_ALLOC_LEAF;
> +			return -EAGAIN;
> +		}
> +
> +		error = xfs_attr_rmtval_set_value(args);
>  		if (error)
>  			return error;
> +	}
>  
> +	if (args->rmtblkno > 0) {
>  		/*
> -		 * Commit the flag value change and start the next trans in
> -		 * series.
> +		 * Added a "remote" value, just clear the incomplete flag.
>  		 */
> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
> +		error = xfs_attr3_leaf_clearflag(args);
>  	}
>  	return error;
>  }
> @@ -1017,16 +1047,23 @@ xfs_attr_node_hasname(
>   *
>   * "Remote" attribute values confuse the issue and atomic rename operations
>   * add a whole extra layer of confusion on top of that.
> + *
> + * This routine is meant to function as a delayed operation, and may return
> + * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
> + * to handle this, and recall the function until a successful error code is
> + *returned.
>   */
>  STATIC int
>  xfs_attr_node_addname(
>  	struct xfs_da_args	*args)
>  {
> -	struct xfs_da_state	*state;
> +	struct xfs_da_state	*state = NULL;
>  	struct xfs_da_state_blk	*blk;
>  	struct xfs_inode	*dp;
> -	struct xfs_mount	*mp;
> -	int			retval, error;
> +	int			retval = 0;
> +	int			error = 0;
> +	int			nmap;
> +	struct xfs_bmbt_irec    *map = &args->dc.map;
>  
>  	trace_xfs_attr_node_addname(args);
>  
> @@ -1034,8 +1071,17 @@ xfs_attr_node_addname(
>  	 * Fill in bucket of arguments/results/context to carry around.
>  	 */
>  	dp = args->dp;
> -	mp = dp->i_mount;
> -restart:
> +
> +	/* State machine switch */
> +	switch (args->dc.dc_state) {
> +	case XFS_DC_FOUND_NBLK:
> +		goto found_nblk;
> +	case XFS_DC_ALLOC_NODE:
> +		goto alloc_node;
> +	default:
> +		break;
> +	}
> +
>  	/*
>  	 * Search to see if name already exists, and get back a pointer
>  	 * to where it should go.
> @@ -1085,19 +1131,12 @@ xfs_attr_node_addname(
>  			error = xfs_attr3_leaf_to_node(args);
>  			if (error)
>  				goto out;
> -			error = xfs_defer_finish(&args->trans);
> -			if (error)
> -				goto out;
>  
>  			/*
> -			 * Commit the node conversion and start the next
> -			 * trans in the chain.
> +			 * Restart routine from the top.  No need to set  the
> +			 * state
>  			 */
> -			error = xfs_trans_roll_inode(&args->trans, dp);
> -			if (error)
> -				goto out;
> -
> -			goto restart;
> +			return -EAGAIN;
>  		}
>  
>  		/*
> @@ -1109,9 +1148,6 @@ xfs_attr_node_addname(
>  		error = xfs_da3_split(state);
>  		if (error)
>  			goto out;
> -		error = xfs_defer_finish(&args->trans);
> -		if (error)
> -			goto out;
>  	} else {
>  		/*
>  		 * Addition succeeded, update Btree hashvals.
> @@ -1126,13 +1162,9 @@ xfs_attr_node_addname(
>  	xfs_da_state_free(state);
>  	state = NULL;
>  
> -	/*
> -	 * Commit the leaf addition or btree split and start the next
> -	 * trans in the chain.
> -	 */
> -	error = xfs_trans_roll_inode(&args->trans, dp);
> -	if (error)
> -		goto out;
> +	args->dc.dc_state = XFS_DC_FOUND_NBLK;
> +	return -EAGAIN;
> +found_nblk:
>  
>  	/*
>  	 * If there was an out-of-line value, allocate the blocks we
> @@ -1141,104 +1173,57 @@ xfs_attr_node_addname(
>  	 * maximum size of a transaction and/or hit a deadlock.
>  	 */
>  	if (args->rmtblkno > 0) {
> -		error = xfs_attr_rmtval_set(args);
> -		if (error)
> -			return error;
> -	}
> +		/* Open coded xfs_attr_rmtval_set without trans handling */
> +		args->dc.lblkno = 0;
> +		args->dc.lfileoff = 0;
> +		args->dc.blkcnt = 0;
> +		args->rmtblkcnt = 0;
> +		args->rmtblkno = 0;
> +		memset(map, 0, sizeof(struct xfs_bmbt_irec));
>  
> -	/*
> -	 * If this is an atomic rename operation, we must "flip" the
> -	 * incomplete flags on the "new" and "old" attribute/value pairs
> -	 * so that one disappears and one appears atomically.  Then we
> -	 * must remove the "old" attribute/value pair.
> -	 */
> -	if (args->op_flags & XFS_DA_OP_RENAME) {
> -		/*
> -		 * In a separate transaction, set the incomplete flag on the
> -		 * "old" attr and clear the incomplete flag on the "new" attr.
> -		 */
> -		error = xfs_attr3_leaf_flipflags(args);
> -		if (error)
> -			goto out;
> -		/*
> -		 * Commit the flag value change and start the next trans in
> -		 * series
> -		 */
> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
> +		error = xfs_attr_rmt_find_hole(args);
>  		if (error)
> -			goto out;
> +			return error;
>  
> +		args->dc.blkcnt = args->rmtblkcnt;
> +		args->dc.lblkno = args->rmtblkno;
>  		/*
> -		 * Dismantle the "old" attribute/value pair by removing
> -		 * a "remote" value (if it exists).
> +		 * Roll through the "value", allocating blocks on disk as
> +		 * required.
>  		 */
> -		args->index = args->index2;
> -		args->blkno = args->blkno2;
> -		args->rmtblkno = args->rmtblkno2;
> -		args->rmtblkcnt = args->rmtblkcnt2;
> -		args->rmtvaluelen = args->rmtvaluelen2;
> -		if (args->rmtblkno) {
> -			error = xfs_attr_rmtval_remove(args);
> +alloc_node:
> +		while (args->dc.blkcnt > 0) {
> +			nmap = 1;
> +			error = xfs_bmapi_write(args->trans, dp,
> +				(xfs_fileoff_t)args->dc.lblkno, args->dc.blkcnt,
> +				XFS_BMAPI_ATTRFORK, args->total, map, &nmap);
>  			if (error)
>  				return error;
> -		}
>  
> -		/*
> -		 * Re-find the "old" attribute entry after any split ops.
> -		 * The INCOMPLETE flag means that we will find the "old"
> -		 * attr, not the "new" one.
> -		 */
> -		args->name.type |= XFS_ATTR_INCOMPLETE;
> -		state = xfs_da_state_alloc();
> -		state->args = args;
> -		state->mp = mp;
> -		state->inleaf = 0;
> -		error = xfs_da3_node_lookup_int(state, &retval);
> -		if (error)
> -			goto out;
> +			ASSERT(nmap == 1);
> +			ASSERT((map->br_startblock != DELAYSTARTBLOCK) &&
> +			       (map->br_startblock != HOLESTARTBLOCK));
>  
> -		/*
> -		 * Remove the name and update the hashvals in the tree.
> -		 */
> -		blk = &state->path.blk[ state->path.active-1 ];
> -		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> -		error = xfs_attr3_leaf_remove(blk->bp, args);
> -		xfs_da3_fixhashpath(state, &state->path);
> +			/* roll attribute extent map forwards */
> +			args->dc.lblkno += map->br_blockcount;
> +			args->dc.blkcnt -= map->br_blockcount;
>  
> -		/*
> -		 * Check to see if the tree needs to be collapsed.
> -		 */
> -		if (retval && (state->path.active > 1)) {
> -			error = xfs_da3_join(state);
> -			if (error)
> -				goto out;
> -			error = xfs_defer_finish(&args->trans);
> -			if (error)
> -				goto out;
> +			args->dc.dc_state = XFS_DC_ALLOC_NODE;
> +			return -EAGAIN;
>  		}
>  
> -		/*
> -		 * Commit and start the next trans in the chain.
> -		 */
> -		error = xfs_trans_roll_inode(&args->trans, dp);
> +		error = xfs_attr_rmtval_set_value(args);
>  		if (error)
> -			goto out;
> +			return error;
> +	}
>  
> -	} else if (args->rmtblkno > 0) {
> +	if (args->rmtblkno > 0) {
>  		/*
>  		 * Added a "remote" value, just clear the incomplete flag.
>  		 */
>  		error = xfs_attr3_leaf_clearflag(args);
>  		if (error)
>  			goto out;
> -
> -		 /*
> -		  * Commit the flag value change and start the next trans in
> -		  * series.
> -		  */
> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
> -		if (error)
> -			goto out;
>  	}
>  	retval = error = 0;
>  
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index fb8bf5b..c710387 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -149,6 +149,7 @@ int xfs_attr_get(struct xfs_inode *ip, struct xfs_name *name,
>  int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
>  		 unsigned char *value, int valuelen, int flags);
>  int xfs_attr_set_args(struct xfs_da_args *args);
> +int xfs_attr_set_later(struct xfs_da_args *args, struct xfs_buf **leaf_bp);
>  int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
>  int xfs_has_attr(struct xfs_da_args *args);
>  int xfs_attr_remove_args(struct xfs_da_args *args);
> -- 
> 2.7.4
> 

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

* Re: [PATCH v4 15/17] xfs: Check for -ENOATTR or -EEXIST
  2019-11-08 21:28   ` Darrick J. Wong
@ 2019-11-08 21:42     ` Allison Collins
  2019-11-08 21:51       ` Darrick J. Wong
  0 siblings, 1 reply; 77+ messages in thread
From: Allison Collins @ 2019-11-08 21:42 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 11/8/19 2:28 PM, Darrick J. Wong wrote:
> On Wed, Nov 06, 2019 at 06:27:59PM -0700, Allison Collins wrote:
>> Delayed operations cannot return error codes.  So we must check for
>> these conditions first before starting set or remove operations
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 25 +++++++++++++++++++++++++
>>   1 file changed, 25 insertions(+)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 5dcb19f..626d4a98 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -458,6 +458,27 @@ xfs_attr_set(
>>   		goto out_trans_cancel;
>>   
>>   	xfs_trans_ijoin(args.trans, dp, 0);
>> +
>> +	error = xfs_has_attr(&args);
>> +	if (error == -EEXIST) {
>> +		if (name->type & ATTR_CREATE)
>> +			goto out_trans_cancel;
>> +		else
>> +			name->type |= ATTR_REPLACE;
>> +	}
>> +
>> +	if (error == -ENOATTR && (name->type & ATTR_REPLACE))
>> +		goto out_trans_cancel;
>> +
>> +	if (name->type & ATTR_REPLACE) {
>> +		name->type &= ~ATTR_REPLACE;
>> +		error = xfs_attr_remove_args(&args);
>> +		if (error)
>> +			goto out_trans_cancel;
>> +
>> +		name->type |= ATTR_CREATE;
> 
> I thought _set_args already handled the remove part of replacing an
> attr?  
No, IIRC in one of the other reviews we decided to break the rename into 
a set and then a remove.  That way the error handling moves up here 
instead of trying to deal with it in the middle of the delayed operation

And I thought that it did this with an atomic rename?  Won't this
> break the atomicity of attr replacement?
Hmm, think this worked for delayed operations, but not anymore since 
we're going back to supporting both delayed and inline in one code path. 
  I think what this means is that the flip flag has to get moved in 
here, right?  We flip on the incomplete flag before the remove and then 
set it when the rename is done?

> 
> --D
> 
>> +	}
>> +
>>   	error = xfs_attr_set_args(&args);
>>   	if (error)
>>   		goto out_trans_cancel;
>> @@ -543,6 +564,10 @@ xfs_attr_remove(
>>   	 */
>>   	xfs_trans_ijoin(args.trans, dp, 0);
>>   
>> +	error = xfs_has_attr(&args);
>> +	if (error == -ENOATTR)
>> +		goto out;
>> +
>>   	error = xfs_attr_remove_args(&args);
>>   	if (error)
>>   		goto out;
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v4 03/17] xfs: Embed struct xfs_name in xfs_da_args
  2019-11-08 16:11     ` Allison Collins
@ 2019-11-08 21:47       ` Darrick J. Wong
  0 siblings, 0 replies; 77+ messages in thread
From: Darrick J. Wong @ 2019-11-08 21:47 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Fri, Nov 08, 2019 at 09:11:54AM -0700, Allison Collins wrote:
> On 11/7/19 6:25 PM, Darrick J. Wong wrote:
> > On Wed, Nov 06, 2019 at 06:27:47PM -0700, Allison Collins wrote:
> > > This patch embeds an xfs_name in xfs_da_args, replacing the name,
> > > namelen, and flags members.  This helps to clean up the xfs_da_args
> > > structure and make it more uniform with the new xfs_name parameter
> > > being passed around.
> > > 
> > > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > > Reviewed-by: Brian Foster <bfoster@redhat.com>
> > > ---
> > >   fs/xfs/libxfs/xfs_attr.c        |  36 +++++++-------
> > >   fs/xfs/libxfs/xfs_attr_leaf.c   | 106 +++++++++++++++++++++-------------------
> > >   fs/xfs/libxfs/xfs_attr_remote.c |   2 +-
> > >   fs/xfs/libxfs/xfs_da_btree.c    |   5 +-
> > >   fs/xfs/libxfs/xfs_da_btree.h    |   4 +-
> > >   fs/xfs/libxfs/xfs_dir2.c        |  18 +++----
> > >   fs/xfs/libxfs/xfs_dir2_block.c  |   6 +--
> > >   fs/xfs/libxfs/xfs_dir2_leaf.c   |   6 +--
> > >   fs/xfs/libxfs/xfs_dir2_node.c   |   8 +--
> > >   fs/xfs/libxfs/xfs_dir2_sf.c     |  30 ++++++------
> > >   fs/xfs/scrub/attr.c             |  12 ++---
> > >   fs/xfs/xfs_trace.h              |  20 ++++----
> > >   12 files changed, 128 insertions(+), 125 deletions(-)
> > > 
> > > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > > index 5a9624a..b77b985 100644
> > > --- a/fs/xfs/libxfs/xfs_attr.c
> > > +++ b/fs/xfs/libxfs/xfs_attr.c
> > > @@ -72,13 +72,12 @@ xfs_attr_args_init(
> > >   	args->geo = dp->i_mount->m_attr_geo;
> > >   	args->whichfork = XFS_ATTR_FORK;
> > >   	args->dp = dp;
> > > -	args->flags = flags;
> > > -	args->name = name->name;
> > > -	args->namelen = name->len;
> > > -	if (args->namelen >= MAXNAMELEN)
> > > +	name->type = flags;
> > 
> > Is there a purpose for modifying the caller's @name, instead of setting
> > args.name.type = flags after the memcpy?
> Not really other than to just make them consistent so that the mem copy
> would cover all three members.  I think initially they were set
> individually, but people preferred the memcpy, and then later we decided to
> break the flags variable out of the name struct.  I can explicitly set
> args.name.type if folks prefer.
> 
> A subtle pitfall I noticed about using the name struct like this now:
> callers need to take care to abandon the original name struct or update the
> original pointer to this struct.  It's kind of easy to continue using the
> original struct like it's a convenience pointer, but it not the same memory
> so if args gets passed into some subroutine that modifies it, now you're out
> of sync.  If it doesnt get passed around or modified, it doesnt matter, but
> we've created a sort of usage rule about how to handle the name param which
> may not be entirely obvious to other developers.

Hm, maybe the da_args should keep a pointer to the caller's name, if
you're worried about coherency between different xfs_names?

Though, the only state that changes is the type field, right?  Maybe we
don't care and that should stay internal to the da_args anyway...

> > 
> > > +	memcpy(&args->name, name, sizeof(struct xfs_name));
> > > +	if (args->name.len >= MAXNAMELEN)
> > >   		return -EFAULT;		/* match IRIX behaviour */
> > > -	args->hashval = xfs_da_hashname(args->name, args->namelen);
> > > +	args->hashval = xfs_da_hashname(args->name.name, args->name.len);
> > >   	return 0;
> > >   }
> > > @@ -236,7 +235,7 @@ xfs_attr_try_sf_addname(
> > >   	 * Commit the shortform mods, and we're done.
> > >   	 * NOTE: this is also the error path (EEXIST, etc).
> > >   	 */
> > > -	if (!error && (args->flags & ATTR_KERNOTIME) == 0)
> > > +	if (!error && (args->name.type & ATTR_KERNOTIME) == 0)
> > >   		xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
> > >   	if (mp->m_flags & XFS_MOUNT_WSYNC)
> > > @@ -357,6 +356,9 @@ xfs_attr_set(
> > >   	if (error)
> > >   		return error;
> > > +	/* Use name now stored in args */
> > > +	name = &args.name;
> > 
> > You could probably set this as part of the variable declaration, e.g.
> > 
> > struct xfs_name		*name = &args.name;
> No, because name is a parameter here, so you would loose the contents at the
> start of the function if we did this.  And then args init would memcopy and
> empty struct onto itself.  And then confusion would ensue.... :-(
> 
> > 
> > > +
> > >   	args.value = value;
> > >   	args.valuelen = valuelen;
> > >   	args.op_flags = XFS_DA_OP_ADDNAME | XFS_DA_OP_OKNOENT;
> > > @@ -372,7 +374,7 @@ xfs_attr_set(
> > >   	 */
> > >   	if (XFS_IFORK_Q(dp) == 0) {
> > >   		int sf_size = sizeof(xfs_attr_sf_hdr_t) +
> > > -			XFS_ATTR_SF_ENTSIZE_BYNAME(args.namelen, valuelen);
> > > +			XFS_ATTR_SF_ENTSIZE_BYNAME(args.name.len, valuelen);
> > 
> > If you're going to keep the convenience variable @name, then please use
> > it throughout the function.
> I think this is the only place it's used for this function at this time.  I
> use it later in patch 15 though.  I think I stumbled across the name sync
> bug then, and corrected it with the parameter pointer assignment above just
> because it seemed like the right place to fix it.
> 
> Do you want the function to uniformly use an explicit reference, or the
> param?  Seems like a bit of a wart unfortunately :-(

One or the other, just not both mixed in the same function.

--D

> > 
> > >   		error = xfs_bmap_add_attrfork(dp, sf_size, rsvd);
> > >   		if (error)
> > 
> > <snip>
> > 
> > > diff --git a/fs/xfs/libxfs/xfs_da_btree.c b/fs/xfs/libxfs/xfs_da_btree.c
> > > index 4fd1223..129ec09 100644
> > > --- a/fs/xfs/libxfs/xfs_da_btree.c
> > > +++ b/fs/xfs/libxfs/xfs_da_btree.c
> > > @@ -2040,8 +2040,9 @@ xfs_da_compname(
> > >   	const unsigned char *name,
> > >   	int		len)
> > >   {
> > > -	return (args->namelen == len && memcmp(args->name, name, len) == 0) ?
> > > -					XFS_CMP_EXACT : XFS_CMP_DIFFERENT;
> > 
> > Wow that's gross. :)
> > 
> > 	if (args->name.len == len && !memcmp(args->name.name, name, len))
> > 		return XFS_CMP_EXACT;
> > 
> > 	return XFS_CMP_DIFFERENT;
> > 
> > Hmm, is that better?
> Sure, will fix.
> 
> Allison
> 
> > 
> > The rest looks reasonable...
> > 
> > --D
> > 

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

* Re: [PATCH v4 15/17] xfs: Check for -ENOATTR or -EEXIST
  2019-11-08 21:42     ` Allison Collins
@ 2019-11-08 21:51       ` Darrick J. Wong
  0 siblings, 0 replies; 77+ messages in thread
From: Darrick J. Wong @ 2019-11-08 21:51 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Fri, Nov 08, 2019 at 02:42:52PM -0700, Allison Collins wrote:
> On 11/8/19 2:28 PM, Darrick J. Wong wrote:
> > On Wed, Nov 06, 2019 at 06:27:59PM -0700, Allison Collins wrote:
> > > Delayed operations cannot return error codes.  So we must check for
> > > these conditions first before starting set or remove operations
> > > 
> > > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > > ---
> > >   fs/xfs/libxfs/xfs_attr.c | 25 +++++++++++++++++++++++++
> > >   1 file changed, 25 insertions(+)
> > > 
> > > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > > index 5dcb19f..626d4a98 100644
> > > --- a/fs/xfs/libxfs/xfs_attr.c
> > > +++ b/fs/xfs/libxfs/xfs_attr.c
> > > @@ -458,6 +458,27 @@ xfs_attr_set(
> > >   		goto out_trans_cancel;
> > >   	xfs_trans_ijoin(args.trans, dp, 0);
> > > +
> > > +	error = xfs_has_attr(&args);
> > > +	if (error == -EEXIST) {
> > > +		if (name->type & ATTR_CREATE)
> > > +			goto out_trans_cancel;
> > > +		else
> > > +			name->type |= ATTR_REPLACE;
> > > +	}
> > > +
> > > +	if (error == -ENOATTR && (name->type & ATTR_REPLACE))
> > > +		goto out_trans_cancel;
> > > +
> > > +	if (name->type & ATTR_REPLACE) {
> > > +		name->type &= ~ATTR_REPLACE;
> > > +		error = xfs_attr_remove_args(&args);
> > > +		if (error)
> > > +			goto out_trans_cancel;
> > > +
> > > +		name->type |= ATTR_CREATE;
> > 
> > I thought _set_args already handled the remove part of replacing an
> > attr?
> No, IIRC in one of the other reviews we decided to break the rename into a
> set and then a remove.

But this looks like we remove the old attr before setting the new one,
which means that if we crash right here we'll come back up with no attr
at all.  The INCOMPLETE flag flipping trick only works for ATTR_REPLACE
if you add the new attr before removing the old one.

(Or am I misreading something here?)

> That way the error handling moves up here instead of
> trying to deal with it in the middle of the delayed operation

Sounds good.

> > And I thought that it did this with an atomic rename?  Won't this
> > break the atomicity of attr replacement?

> Hmm, think this worked for delayed operations, but not anymore since we're
> going back to supporting both delayed and inline in one code path.  I think
> what this means is that the flip flag has to get moved in here, right?  We
> flip on the incomplete flag before the remove and then set it when the
> rename is done?

Yeah.

--D

> 
> > 
> > --D
> > 
> > > +	}
> > > +
> > >   	error = xfs_attr_set_args(&args);
> > >   	if (error)
> > >   		goto out_trans_cancel;
> > > @@ -543,6 +564,10 @@ xfs_attr_remove(
> > >   	 */
> > >   	xfs_trans_ijoin(args.trans, dp, 0);
> > > +	error = xfs_has_attr(&args);
> > > +	if (error == -ENOATTR)
> > > +		goto out;
> > > +
> > >   	error = xfs_attr_remove_args(&args);
> > >   	if (error)
> > >   		goto out;
> > > -- 
> > > 2.7.4
> > > 

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

* Re: [PATCH v4 17/17] xfs: Add delay ready attr set routines
  2019-11-08 21:42   ` Darrick J. Wong
@ 2019-11-08 21:52     ` Allison Collins
  2019-11-09  4:07     ` Allison Collins
  1 sibling, 0 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-08 21:52 UTC (permalink / raw)
  To: Darrick J. Wong, g; +Cc: linux-xfs



On 11/8/19 2:42 PM, Darrick J. Wong wrote:
> On Wed, Nov 06, 2019 at 06:28:01PM -0700, Allison Collins wrote:
>> This patch modifies the attr set routines to be delay ready.
>> This means they no longer roll or commit transactions, but instead
>> return -EAGAIN to have the calling routine roll and refresh the
>> transaction.  In this series, xfs_attr_set_args has become
>> xfs_attr_set_later, which uses a state machine to keep track
>> of where it was when EAGAIN was returned.  Part of
>> xfs_attr_leaf_addname has been factored out into a new helper
>> function xfs_attr_leaf_try_add to allow transaction cycling between
>> the two routines, and the flipflags logic has been removed since we
>> can simply cancel the transaction upon error.  xfs_attr_set_args
>> consists of a simple loop to refresh the transaction until the
>> operation is completed.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 435 +++++++++++++++++++++++------------------------
>>   fs/xfs/libxfs/xfs_attr.h |   1 +
>>   2 files changed, 211 insertions(+), 225 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 38d5c5c..97e5ae0 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -58,6 +58,7 @@ STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
>>   				 struct xfs_da_state **state);
>>   STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
>>   STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
>> +STATIC int xfs_attr_leaf_try_add(struct xfs_da_args *args, struct xfs_buf *bp);
>>   
>>   
>>   STATIC int
>> @@ -250,9 +251,79 @@ int
>>   xfs_attr_set_args(
>>   	struct xfs_da_args	*args)
>>   {
>> +	int			error = 0;
>> +	int			err2 = 0;
>> +	struct xfs_buf		*leaf_bp = NULL;
>> +
>> +	do {
>> +		error = xfs_attr_set_later(args, &leaf_bp);
>> +		if (error && error != -EAGAIN)
>> +			goto out;
>> +
>> +		xfs_trans_log_inode(args->trans, args->dp,
>> +				    XFS_ILOG_CORE | XFS_ILOG_ADATA);
> 
> Same question as the last patch about ADATA.
> 
>> +
>> +		err2 = xfs_trans_roll(&args->trans);
>> +		if (err2) {
>> +			error = err2;
>> +			goto out;
>> +		}
>> +
>> +		/* Rejoin inode and leaf if needed */
>> +		xfs_trans_ijoin(args->trans, args->dp, 0);
>> +		if (leaf_bp) {
>> +			xfs_trans_bjoin(args->trans, leaf_bp);
>> +			xfs_trans_bhold(args->trans, leaf_bp);
>> +		}
>> +
>> +	} while (error == -EAGAIN);
>> +
>> +out:
>> +	return error;
>> +}
>> +
>> +/*
>> + * Set the attribute specified in @args.
>> + * This routine is meant to function as a delayed operation, and may return
>> + * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
>> + * to handle this, and recall the function until a successful error code is
>> + * returned.
>> + */
>> +int
>> +xfs_attr_set_later(
>> +	struct xfs_da_args	*args,
>> +	struct xfs_buf          **leaf_bp)
>> +{
>>   	struct xfs_inode	*dp = args->dp;
>> -	struct xfs_buf          *leaf_bp = NULL;
>> -	int			error, error2 = 0;;
>> +	int			error = 0;
>> +	int			sf_size;
>> +
>> +	/* State machine switch */
>> +	switch (args->dc.dc_state) {
>> +	case XFS_DC_SF_TO_LEAF:
>> +		goto sf_to_leaf;
>> +	case XFS_DC_ALLOC_LEAF:
>> +	case XFS_DC_FOUND_LBLK:
>> +		goto leaf;
>> +	case XFS_DC_FOUND_NBLK:
>> +	case XFS_DC_ALLOC_NODE:
>> +	case XFS_DC_LEAF_TO_NODE:
>> +		goto node;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	/*
>> +	 * New inodes may not have an attribute fork yet. So set the attribute
>> +	 * fork appropriately
>> +	 */
>> +	if (XFS_IFORK_Q((args->dp)) == 0) {
>> +		sf_size = sizeof(struct xfs_attr_sf_hdr) +
>> +		     XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
>> +		xfs_bmap_set_attrforkoff(args->dp, sf_size, NULL);
>> +		args->dp->i_afp = kmem_zone_zalloc(xfs_ifork_zone, 0);
>> +		args->dp->i_afp->if_flags = XFS_IFEXTENTS;
>> +	}
>>   
>>   	/*
>>   	 * If the attribute list is non-existent or a shortform list,
>> @@ -272,21 +343,14 @@ xfs_attr_set_args(
>>   		 * Try to add the attr to the attribute list in the inode.
>>   		 */
>>   		error = xfs_attr_try_sf_addname(dp, args);
>> -		if (error != -ENOSPC) {
>> -			if (dp->i_mount->m_flags & XFS_MOUNT_WSYNC)
>> -				xfs_trans_set_sync(args->trans);
> 
> Where does the xfs_trans_set_sync call go?  Do we not need it anymore?
> 
>> -			error2 = xfs_trans_commit(args->trans);
>> -			args->trans = NULL;
>> -			return error ? error : error2;
>> -		}
>> -
>> +		if (error != -ENOSPC)
>> +			return error;
>>   
>>   		/*
>>   		 * It won't fit in the shortform, transform to a leaf block.
>>   		 * GROT: another possible req'mt for a double-split btree op.
>>   		 */
>> -		error = xfs_attr_shortform_to_leaf(args, &leaf_bp);
>> +		error = xfs_attr_shortform_to_leaf(args, leaf_bp);
>>   		if (error)
>>   			return error;
>>   
>> @@ -294,43 +358,42 @@ xfs_attr_set_args(
>>   		 * Prevent the leaf buffer from being unlocked so that a
>>   		 * concurrent AIL push cannot grab the half-baked leaf
>>   		 * buffer and run into problems with the write verifier.
>> -		 * Once we're done rolling the transaction we can release
>> -		 * the hold and add the attr to the leaf.
>>   		 */
>> -		xfs_trans_bhold(args->trans, leaf_bp);
>> -		error = xfs_defer_finish(&args->trans);
>> -		xfs_trans_bhold_release(args->trans, leaf_bp);
>> -		if (error) {
>> -			xfs_trans_brelse(args->trans, leaf_bp);
>> -			return error;
>> -		}
>> +
>> +		xfs_trans_bhold(args->trans, *leaf_bp);
>> +		args->dc.dc_state = XFS_DC_SF_TO_LEAF;
>> +		return -EAGAIN;
>> +	}
>> +sf_to_leaf:
>> +
>> +	/*
>> +	 * After a shortform to leaf conversion, we need to hold the leaf and
>> +	 * cylce out the transaction.  When we get back, we need to release
> 
>             "cycle"
> 
>> +	 * the leaf.
>> +	 */
>> +	if (*leaf_bp != NULL) {
>> +		xfs_trans_brelse(args->trans, *leaf_bp);
>> +		*leaf_bp = NULL;
>>   	}
>>   
>>   	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>> +		error = xfs_attr_leaf_try_add(args, *leaf_bp);
>> +		if (error == -ENOSPC)
>> +			args->dc.dc_state = XFS_DC_LEAF_TO_NODE;
>> +		else if (error)
>> +			return error;
>> +		else
>> +			args->dc.dc_state = XFS_DC_FOUND_LBLK;
>> +		return -EAGAIN;
> 
> Please use a switch statement here...
> 
> switch (error) {
> case -ENOSPC:
> 	dc_state = LEAF_TO_NODE;
> 	return -EAGAIN;
> case 0:
> 	dc_state = FOUND_LBLK;
> 	return -EAGAIN;
> default:
> 	return error;
> }
> 
>> +leaf:
>>   		error = xfs_attr_leaf_addname(args);
>>   		if (error == -ENOSPC) {
>> -			/*
>> -			 * Commit that transaction so that the node_addname()
>> -			 * call can manage its own transactions.
>> -			 */
>> -			error = xfs_defer_finish(&args->trans);
>> -			if (error)
>> -				return error;
>> -
>> -			/*
>> -			 * Commit the current trans (including the inode) and
>> -			 * start a new one.
>> -			 */
>> -			error = xfs_trans_roll_inode(&args->trans, dp);
>> -			if (error)
>> -				return error;
>> -
>> -			/*
>> -			 * Fob the rest of the problem off on the Btree code.
>> -			 */
>> -			error = xfs_attr_node_addname(args);
>> +			args->dc.dc_state = XFS_DC_LEAF_TO_NODE;
>> +			return -EAGAIN;
>>   		}
>>   	} else {
>> +		args->dc.dc_state = XFS_DC_LEAF_TO_NODE;
>> +node:
>>   		error = xfs_attr_node_addname(args);
>>   	}
>>   	return error;
>> @@ -764,27 +827,26 @@ xfs_attr_leaf_try_add(
>>    *
>>    * This leaf block cannot have a "remote" value, we only call this routine
>>    * if bmap_one_block() says there is only one block (ie: no remote blks).
>> + *
>> + * This routine is meant to function as a delayed operation, and may return
>> + * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
>> + * to handle this, and recall the function until a successful error code is
>> + * returned.
>>    */
>>   STATIC int
>>   xfs_attr_leaf_addname(struct xfs_da_args	*args)
>>   {
>> -	int			error, forkoff;
>> -	struct xfs_buf		*bp = NULL;
>> +	int			error, nmap;
>>   	struct xfs_inode	*dp = args->dp;
>> +	struct xfs_bmbt_irec	*map = &args->dc.map;
>>   
>> -	trace_xfs_attr_leaf_addname(args);
>> -
>> -	error = xfs_attr_leaf_try_add(args, bp);
>> -	if (error)
>> -		return error;
>> -
>> -	/*
>> -	 * Commit the transaction that added the attr name so that
>> -	 * later routines can manage their own transactions.
>> -	 */
>> -	error = xfs_trans_roll_inode(&args->trans, dp);
>> -	if (error)
>> -		return error;
>> +	/* State machine switch */
>> +	switch (args->dc.dc_state) {
>> +	case XFS_DC_ALLOC_LEAF:
>> +		goto alloc_leaf;
>> +	default:
>> +		break;
>> +	}
>>   
>>   	/*
>>   	 * If there was an out-of-line value, allocate the blocks we
>> @@ -793,90 +855,58 @@ xfs_attr_leaf_addname(struct xfs_da_args	*args)
>>   	 * maximum size of a transaction and/or hit a deadlock.
>>   	 */
>>   	if (args->rmtblkno > 0) {
>> -		error = xfs_attr_rmtval_set(args);
>> -		if (error)
>> -			return error;
>> -	}
>>   
>> -	/*
>> -	 * If this is an atomic rename operation, we must "flip" the
>> -	 * incomplete flags on the "new" and "old" attribute/value pairs
>> -	 * so that one disappears and one appears atomically.  Then we
>> -	 * must remove the "old" attribute/value pair.
>> -	 */
>> -	if (args->op_flags & XFS_DA_OP_RENAME) {
>> -		/*
>> -		 * In a separate transaction, set the incomplete flag on the
>> -		 * "old" attr and clear the incomplete flag on the "new" attr.
>> -		 */
>> -		error = xfs_attr3_leaf_flipflags(args);
>> -		if (error)
>> -			return error;
>> -		/*
>> -		 * Commit the flag value change and start the next trans in
>> -		 * series.
>> -		 */
>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> -		if (error)
>> -			return error;
>> +		/* Open coded xfs_attr_rmtval_set without trans handling */
> 
> Can't we just fix that instead of reproducing it here?
> 
> Especially because I think I see it twice in this patch?
> 
> Also, do you have a git tree handy?  I /think/ I see how this works but
> oh man is it difficult to see that from patches alone.

Sure, I've pushed the branches here.  These ones go all the way through 
delayed attrs and ppts, but I usually just checkout the commit of the 
subset I need to work on.


https://github.com/allisonhenderson/xfs_work/tree/pptrs_restart38

https://github.com/allisonhenderson/xfs_work/tree/parent_pointers_xfsprogs_restart30

> 
> --D
> 
>>   
>> -		/*
>> -		 * Dismantle the "old" attribute/value pair by removing
>> -		 * a "remote" value (if it exists).
>> -		 */
>> -		args->index = args->index2;
>> -		args->blkno = args->blkno2;
>> -		args->rmtblkno = args->rmtblkno2;
>> -		args->rmtblkcnt = args->rmtblkcnt2;
>> -		args->rmtvaluelen = args->rmtvaluelen2;
>> -		if (args->rmtblkno) {
>> -			error = xfs_attr_rmtval_remove(args);
>> -			if (error)
>> -				return error;
>> -		}
>> +		args->dc.lfileoff = 0;
>> +		args->dc.lblkno = 0;
>> +		args->dc.blkcnt = 0;
>> +		args->rmtblkcnt = 0;
>> +		args->rmtblkno = 0;
>> +		memset(map, 0, sizeof(struct xfs_bmbt_irec));
>>   
>> -		/*
>> -		 * Read in the block containing the "old" attr, then
>> -		 * remove the "old" attr from that block (neat, huh!)
>> -		 */
>> -		error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
>> -					   XFS_DABUF_MAP_NOMAPPING, &bp);
>> +		error = xfs_attr_rmt_find_hole(args);
>>   		if (error)
>>   			return error;
>>   
>> -		xfs_attr3_leaf_remove(bp, args);
>> +		args->dc.blkcnt = args->rmtblkcnt;
>> +		args->dc.lblkno = args->rmtblkno;
>>   
>>   		/*
>> -		 * If the result is small enough, shrink it all into the inode.
>> +		 * Roll through the "value", allocating blocks on disk as
>> +		 * required.
>>   		 */
>> -		if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
>> -			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
>> -			/* bp is gone due to xfs_da_shrink_inode */
>> -			if (error)
>> -				return error;
>> -			error = xfs_defer_finish(&args->trans);
>> +alloc_leaf:
>> +		while (args->dc.blkcnt > 0) {
>> +			nmap = 1;
>> +			error = xfs_bmapi_write(args->trans, dp,
>> +				  (xfs_fileoff_t)args->dc.lblkno,
>> +				  args->dc.blkcnt, XFS_BMAPI_ATTRFORK,
>> +				  args->total, map, &nmap);
>>   			if (error)
>>   				return error;
>> -		}
>> +			ASSERT(nmap == 1);
>> +			ASSERT((map->br_startblock != DELAYSTARTBLOCK) &&
>> +			       (map->br_startblock != HOLESTARTBLOCK));
>>   
>> -		/*
>> -		 * Commit the remove and start the next trans in series.
>> -		 */
>> -		error = xfs_trans_roll_inode(&args->trans, dp);
>> +			/* roll attribute extent map forwards */
>> +			args->dc.lblkno += map->br_blockcount;
>> +			args->dc.blkcnt -= map->br_blockcount;
>>   
>> -	} else if (args->rmtblkno > 0) {
>> -		/*
>> -		 * Added a "remote" value, just clear the incomplete flag.
>> -		 */
>> -		error = xfs_attr3_leaf_clearflag(args);
>> +			args->dc.dc_state = XFS_DC_ALLOC_LEAF;
>> +			return -EAGAIN;
>> +		}
>> +
>> +		error = xfs_attr_rmtval_set_value(args);
>>   		if (error)
>>   			return error;
>> +	}
>>   
>> +	if (args->rmtblkno > 0) {
>>   		/*
>> -		 * Commit the flag value change and start the next trans in
>> -		 * series.
>> +		 * Added a "remote" value, just clear the incomplete flag.
>>   		 */
>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> +		error = xfs_attr3_leaf_clearflag(args);
>>   	}
>>   	return error;
>>   }
>> @@ -1017,16 +1047,23 @@ xfs_attr_node_hasname(
>>    *
>>    * "Remote" attribute values confuse the issue and atomic rename operations
>>    * add a whole extra layer of confusion on top of that.
>> + *
>> + * This routine is meant to function as a delayed operation, and may return
>> + * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
>> + * to handle this, and recall the function until a successful error code is
>> + *returned.
>>    */
>>   STATIC int
>>   xfs_attr_node_addname(
>>   	struct xfs_da_args	*args)
>>   {
>> -	struct xfs_da_state	*state;
>> +	struct xfs_da_state	*state = NULL;
>>   	struct xfs_da_state_blk	*blk;
>>   	struct xfs_inode	*dp;
>> -	struct xfs_mount	*mp;
>> -	int			retval, error;
>> +	int			retval = 0;
>> +	int			error = 0;
>> +	int			nmap;
>> +	struct xfs_bmbt_irec    *map = &args->dc.map;
>>   
>>   	trace_xfs_attr_node_addname(args);
>>   
>> @@ -1034,8 +1071,17 @@ xfs_attr_node_addname(
>>   	 * Fill in bucket of arguments/results/context to carry around.
>>   	 */
>>   	dp = args->dp;
>> -	mp = dp->i_mount;
>> -restart:
>> +
>> +	/* State machine switch */
>> +	switch (args->dc.dc_state) {
>> +	case XFS_DC_FOUND_NBLK:
>> +		goto found_nblk;
>> +	case XFS_DC_ALLOC_NODE:
>> +		goto alloc_node;
>> +	default:
>> +		break;
>> +	}
>> +
>>   	/*
>>   	 * Search to see if name already exists, and get back a pointer
>>   	 * to where it should go.
>> @@ -1085,19 +1131,12 @@ xfs_attr_node_addname(
>>   			error = xfs_attr3_leaf_to_node(args);
>>   			if (error)
>>   				goto out;
>> -			error = xfs_defer_finish(&args->trans);
>> -			if (error)
>> -				goto out;
>>   
>>   			/*
>> -			 * Commit the node conversion and start the next
>> -			 * trans in the chain.
>> +			 * Restart routine from the top.  No need to set  the
>> +			 * state
>>   			 */
>> -			error = xfs_trans_roll_inode(&args->trans, dp);
>> -			if (error)
>> -				goto out;
>> -
>> -			goto restart;
>> +			return -EAGAIN;
>>   		}
>>   
>>   		/*
>> @@ -1109,9 +1148,6 @@ xfs_attr_node_addname(
>>   		error = xfs_da3_split(state);
>>   		if (error)
>>   			goto out;
>> -		error = xfs_defer_finish(&args->trans);
>> -		if (error)
>> -			goto out;
>>   	} else {
>>   		/*
>>   		 * Addition succeeded, update Btree hashvals.
>> @@ -1126,13 +1162,9 @@ xfs_attr_node_addname(
>>   	xfs_da_state_free(state);
>>   	state = NULL;
>>   
>> -	/*
>> -	 * Commit the leaf addition or btree split and start the next
>> -	 * trans in the chain.
>> -	 */
>> -	error = xfs_trans_roll_inode(&args->trans, dp);
>> -	if (error)
>> -		goto out;
>> +	args->dc.dc_state = XFS_DC_FOUND_NBLK;
>> +	return -EAGAIN;
>> +found_nblk:
>>   
>>   	/*
>>   	 * If there was an out-of-line value, allocate the blocks we
>> @@ -1141,104 +1173,57 @@ xfs_attr_node_addname(
>>   	 * maximum size of a transaction and/or hit a deadlock.
>>   	 */
>>   	if (args->rmtblkno > 0) {
>> -		error = xfs_attr_rmtval_set(args);
>> -		if (error)
>> -			return error;
>> -	}
>> +		/* Open coded xfs_attr_rmtval_set without trans handling */
>> +		args->dc.lblkno = 0;
>> +		args->dc.lfileoff = 0;
>> +		args->dc.blkcnt = 0;
>> +		args->rmtblkcnt = 0;
>> +		args->rmtblkno = 0;
>> +		memset(map, 0, sizeof(struct xfs_bmbt_irec));
>>   
>> -	/*
>> -	 * If this is an atomic rename operation, we must "flip" the
>> -	 * incomplete flags on the "new" and "old" attribute/value pairs
>> -	 * so that one disappears and one appears atomically.  Then we
>> -	 * must remove the "old" attribute/value pair.
>> -	 */
>> -	if (args->op_flags & XFS_DA_OP_RENAME) {
>> -		/*
>> -		 * In a separate transaction, set the incomplete flag on the
>> -		 * "old" attr and clear the incomplete flag on the "new" attr.
>> -		 */
>> -		error = xfs_attr3_leaf_flipflags(args);
>> -		if (error)
>> -			goto out;
>> -		/*
>> -		 * Commit the flag value change and start the next trans in
>> -		 * series
>> -		 */
>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> +		error = xfs_attr_rmt_find_hole(args);
>>   		if (error)
>> -			goto out;
>> +			return error;
>>   
>> +		args->dc.blkcnt = args->rmtblkcnt;
>> +		args->dc.lblkno = args->rmtblkno;
>>   		/*
>> -		 * Dismantle the "old" attribute/value pair by removing
>> -		 * a "remote" value (if it exists).
>> +		 * Roll through the "value", allocating blocks on disk as
>> +		 * required.
>>   		 */
>> -		args->index = args->index2;
>> -		args->blkno = args->blkno2;
>> -		args->rmtblkno = args->rmtblkno2;
>> -		args->rmtblkcnt = args->rmtblkcnt2;
>> -		args->rmtvaluelen = args->rmtvaluelen2;
>> -		if (args->rmtblkno) {
>> -			error = xfs_attr_rmtval_remove(args);
>> +alloc_node:
>> +		while (args->dc.blkcnt > 0) {
>> +			nmap = 1;
>> +			error = xfs_bmapi_write(args->trans, dp,
>> +				(xfs_fileoff_t)args->dc.lblkno, args->dc.blkcnt,
>> +				XFS_BMAPI_ATTRFORK, args->total, map, &nmap);
>>   			if (error)
>>   				return error;
>> -		}
>>   
>> -		/*
>> -		 * Re-find the "old" attribute entry after any split ops.
>> -		 * The INCOMPLETE flag means that we will find the "old"
>> -		 * attr, not the "new" one.
>> -		 */
>> -		args->name.type |= XFS_ATTR_INCOMPLETE;
>> -		state = xfs_da_state_alloc();
>> -		state->args = args;
>> -		state->mp = mp;
>> -		state->inleaf = 0;
>> -		error = xfs_da3_node_lookup_int(state, &retval);
>> -		if (error)
>> -			goto out;
>> +			ASSERT(nmap == 1);
>> +			ASSERT((map->br_startblock != DELAYSTARTBLOCK) &&
>> +			       (map->br_startblock != HOLESTARTBLOCK));
>>   
>> -		/*
>> -		 * Remove the name and update the hashvals in the tree.
>> -		 */
>> -		blk = &state->path.blk[ state->path.active-1 ];
>> -		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>> -		error = xfs_attr3_leaf_remove(blk->bp, args);
>> -		xfs_da3_fixhashpath(state, &state->path);
>> +			/* roll attribute extent map forwards */
>> +			args->dc.lblkno += map->br_blockcount;
>> +			args->dc.blkcnt -= map->br_blockcount;
>>   
>> -		/*
>> -		 * Check to see if the tree needs to be collapsed.
>> -		 */
>> -		if (retval && (state->path.active > 1)) {
>> -			error = xfs_da3_join(state);
>> -			if (error)
>> -				goto out;
>> -			error = xfs_defer_finish(&args->trans);
>> -			if (error)
>> -				goto out;
>> +			args->dc.dc_state = XFS_DC_ALLOC_NODE;
>> +			return -EAGAIN;
>>   		}
>>   
>> -		/*
>> -		 * Commit and start the next trans in the chain.
>> -		 */
>> -		error = xfs_trans_roll_inode(&args->trans, dp);
>> +		error = xfs_attr_rmtval_set_value(args);
>>   		if (error)
>> -			goto out;
>> +			return error;
>> +	}
>>   
>> -	} else if (args->rmtblkno > 0) {
>> +	if (args->rmtblkno > 0) {
>>   		/*
>>   		 * Added a "remote" value, just clear the incomplete flag.
>>   		 */
>>   		error = xfs_attr3_leaf_clearflag(args);
>>   		if (error)
>>   			goto out;
>> -
>> -		 /*
>> -		  * Commit the flag value change and start the next trans in
>> -		  * series.
>> -		  */
>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> -		if (error)
>> -			goto out;
>>   	}
>>   	retval = error = 0;
>>   
>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>> index fb8bf5b..c710387 100644
>> --- a/fs/xfs/libxfs/xfs_attr.h
>> +++ b/fs/xfs/libxfs/xfs_attr.h
>> @@ -149,6 +149,7 @@ int xfs_attr_get(struct xfs_inode *ip, struct xfs_name *name,
>>   int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
>>   		 unsigned char *value, int valuelen, int flags);
>>   int xfs_attr_set_args(struct xfs_da_args *args);
>> +int xfs_attr_set_later(struct xfs_da_args *args, struct xfs_buf **leaf_bp);
>>   int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
>>   int xfs_has_attr(struct xfs_da_args *args);
>>   int xfs_attr_remove_args(struct xfs_da_args *args);
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v4 09/17] xfs: Factor up commit from xfs_attr_try_sf_addname
  2019-11-08 21:04   ` Darrick J. Wong
@ 2019-11-08 23:13     ` Allison Collins
  0 siblings, 0 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-08 23:13 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 11/8/19 2:04 PM, Darrick J. Wong wrote:
> On Wed, Nov 06, 2019 at 06:27:53PM -0700, Allison Collins wrote:
>> New delayed attribute routines cannot handle transactions,
>> so factor this up to the calling function.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 23 ++++++++++++-----------
>>   1 file changed, 12 insertions(+), 11 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index dda2eba..e0a38a2 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -227,8 +227,7 @@ xfs_attr_try_sf_addname(
>>   	struct xfs_da_args	*args)
>>   {
>>   
>> -	struct xfs_mount	*mp = dp->i_mount;
>> -	int			error, error2;
>> +	int			error;
>>   
>>   	error = xfs_attr_shortform_addname(args);
>>   	if (error == -ENOSPC)
>> @@ -241,12 +240,7 @@ xfs_attr_try_sf_addname(
>>   	if (!error && (args->name.type & ATTR_KERNOTIME) == 0)
>>   		xfs_trans_ichgtime(args->trans, dp, XFS_ICHGTIME_CHG);
> 
> What if you moved this part (the conditional ichgtime) into
> xfs_attr_shortform_addname?  Then this function can just go away.
Sure, I may do that in a separate patch though just to make it easier to 
review.

> 
>>   
>> -	if (mp->m_flags & XFS_MOUNT_WSYNC)
>> -		xfs_trans_set_sync(args->trans);
>> -
>> -	error2 = xfs_trans_commit(args->trans);
>> -	args->trans = NULL;
>> -	return error ? error : error2;
>> +	return error;
>>   }
>>   
>>   /*
>> @@ -258,7 +252,7 @@ xfs_attr_set_args(
>>   {
>>   	struct xfs_inode	*dp = args->dp;
>>   	struct xfs_buf          *leaf_bp = NULL;
>> -	int			error;
>> +	int			error, error2 = 0;;
>>   
>>   	/*
>>   	 * If the attribute list is non-existent or a shortform list,
>> @@ -278,8 +272,15 @@ xfs_attr_set_args(
>>   		 * Try to add the attr to the attribute list in the inode.
>>   		 */
>>   		error = xfs_attr_try_sf_addname(dp, args);
>> -		if (error != -ENOSPC)
>> -			return error;
>> +		if (error != -ENOSPC) {
>> +			if (dp->i_mount->m_flags & XFS_MOUNT_WSYNC)
>> +				xfs_trans_set_sync(args->trans);
>> +
>> +			error2 = xfs_trans_commit(args->trans);
>> +			args->trans = NULL;
>> +			return error ? error : error2;
> 
> Can error be something other than 0 or EEXIST?  If so, does it make
> sense to commit even in those cases?  (Have I asked this before...?)
Yeah, this came up once before:
https://patchwork.kernel.org/patch/11087647/

So I simplified it, but then I think people were more comfortable with a 
straight refactor with no function change:
https://patchwork.kernel.org/patch/11134023/

So I put it back. :-)

  It
> looks odd to me that we'd commit the transaction even if something
> handed back EFSCORRUPTED.
> 
> Hm, it's a local attr fork so I guess the only possible error is ENOSPC?
> If that's true then please add a comment/ASSERT to that effect.

Ok, how about a comment.  Something like
/* Should only be 0, EEXIST or ENOSPC */

Sound good?
Allison

> 
> --D
> 
>> +		}
>> +
>>   
>>   		/*
>>   		 * It won't fit in the shortform, transform to a leaf block.
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v4 11/17] xfs: Add xfs_attr3_leaf helper functions
  2019-11-08 21:17   ` Darrick J. Wong
@ 2019-11-09  0:09     ` Allison Collins
  0 siblings, 0 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-09  0:09 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 11/8/19 2:17 PM, Darrick J. Wong wrote:
> On Wed, Nov 06, 2019 at 06:27:55PM -0700, Allison Collins wrote:
>> And new helper functions xfs_attr3_leaf_flag_is_set and
>> xfs_attr3_leaf_flagsflipped.  These routines check to see
>> if xfs_attr3_leaf_setflag or xfs_attr3_leaf_flipflags have
>> already been run.  We will need this later for delayed
>> attributes since routines may be recalled several times
>> when -EAGAIN is returned.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr_leaf.c | 94 +++++++++++++++++++++++++++++++++++++++++++
>>   fs/xfs/libxfs/xfs_attr_leaf.h |  2 +
>>   2 files changed, 96 insertions(+)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
>> index 42c037e..023c616 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
>> @@ -2809,6 +2809,40 @@ xfs_attr3_leaf_clearflag(
>>   }
>>   
>>   /*
>> + * Check if the INCOMPLETE flag on an entry in a leaf block is set.  This
>> + * function can be used to check if xfs_attr3_leaf_setflag has already been
>> + * called.  The INCOMPLETE flag is used during attr rename operations to mark
>> + * entries that are being renamed. Since renames should be atomic, only one of
> 
> It's also used when creating an xattr with a value stored in a remote
> block so that we can commit the name entry to the log (with INCOMPLETE
> set), allocate/write the remote value with ordered buffers, and then
> commit a second transaction clearing the INCOMPLETE flag.
> 
> Now that I think about it ... this predicate is for non-rename setting
> of attrs with remote values, and the "flagsflipped" predicate is for
> rename operations, aren't they?\

Yes, but I'm realizing now, that we may not need these helpers if we 
continue to move forward with the state machine.  With the state 
machine, we can simply flip the flag, set the next state, and move on 
since that region of code will not execute again.  The state switch will 
jump us forward to where we were without having to check if we already 
did it.

> 
>> + * them should appear as a completed attribute.
>> + *
>> + * isset is set to true if the flag is set or false otherwise
>> + */
>> +int
>> +xfs_attr3_leaf_flag_is_set(
>> +	struct xfs_da_args		*args,
>> +	bool				*isset)
>> +{
>> +	struct xfs_attr_leafblock	*leaf;
>> +	struct xfs_attr_leaf_entry	*entry;
>> +	struct xfs_buf			*bp;
>> +	struct xfs_inode		*dp = args->dp;
>> +	int				error = 0;
>> +
>> +	error = xfs_attr3_leaf_read(args->trans, dp, args->blkno,
>> +				    XFS_DABUF_MAP_NOMAPPING, &bp);
>> +	if (error)
>> +		return error;
>> +
>> +	leaf = bp->b_addr;
>> +	entry = &xfs_attr3_leaf_entryp(leaf)[args->index];
>> +
>> +	*isset = ((entry->flags & XFS_ATTR_INCOMPLETE) != 0);
>> +	xfs_trans_brelse(args->trans, bp);
>> +
>> +	return 0;
>> +}
>> +
>> +/*
>>    * Set the INCOMPLETE flag on an entry in a leaf block.
>>    */
>>   int
>> @@ -2972,3 +3006,63 @@ xfs_attr3_leaf_flipflags(
>>   
>>   	return error;
>>   }
>> +
>> +/*
>> + * On a leaf entry, check to see if the INCOMPLETE flag is cleared
>> + * in args->blkno/index and set in args->blkno2/index2.
> 
> Might be worth mentioning here that args->blkno is the old entry and
> args->blkno2 is the new entry.  This predicate will be used (by the
> deferred attr item recovery code) to decide if we have to finish that
> part of a rename operation, right?
No, it was used in the previous series xfs_attr_set_later where I was 
aiming to rely more on the state of the fork rather than the state 
machine.  But with the new state machine in this series, I may be able 
to just drop this patch.

> 
>>   Note that they could be
>> + * in different blocks, or in the same block.  This function can be used to
>> + * check if xfs_attr3_leaf_flipflags has already been called.  The INCOMPLETE
>> + * flag is used during attr rename operations to mark entries that are being
>> + * renamed. Since renames should be atomic, only one of them should appear as a
>> + * completed attribute.
>> + *
>> + * isflipped is set to true if flags are flipped or false otherwise
>> + */
>> +int
>> +xfs_attr3_leaf_flagsflipped(
> 
> I don't like "flagsflipped" because it's not clear to me what "flipped"
> means.
> 
> xfs_attr3_leaf_rename_is_incomplete() ?
> 
Sure, if I keep this patch in the set I will update it.  Things are 
still pretty wiggly, so i may still find a use for it, but hopefully I 
can let it go.

>> +	struct xfs_da_args		*args,
>> +	bool				*isflipped)
>> +{
>> +	struct xfs_attr_leafblock	*leaf1;
>> +	struct xfs_attr_leafblock	*leaf2;
>> +	struct xfs_attr_leaf_entry	*entry1;
>> +	struct xfs_attr_leaf_entry	*entry2;
>> +	struct xfs_buf			*bp1;
>> +	struct xfs_buf			*bp2;
>> +	struct xfs_inode		*dp = args->dp;
>> +	int				error = 0;
>> +
>> +	/*
>> +	 * Read the block containing the "old" attr
>> +	 */
>> +	error = xfs_attr3_leaf_read(args->trans, dp, args->blkno,
>> +				    XFS_DABUF_MAP_NOMAPPING, &bp1);
>> +	if (error)
>> +		return error;
>> +
>> +	/*
>> +	 * Read the block containing the "new" attr, if it is different
>> +	 */
>> +	if (args->blkno2 != args->blkno) {
>> +		error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno2,
>> +					   -1, &bp2);
>> +		if (error)
> 
> bp1 leaks here, I think.
ok, will make a note.

> 
>> +			return error;
>> +	} else {
>> +		bp2 = bp1;
>> +	}
>> +
>> +	leaf1 = bp1->b_addr;
>> +	entry1 = &xfs_attr3_leaf_entryp(leaf1)[args->index];
>> +
>> +	leaf2 = bp2->b_addr;
>> +	entry2 = &xfs_attr3_leaf_entryp(leaf2)[args->index2];
>> +
>> +	*isflipped = (((entry1->flags & XFS_ATTR_INCOMPLETE) == 0) &&
> 
> Nit: ((entry1->flags & XFS_ATTR_INCOMPLETE) == 0) could be written as
> !(entry1->flags & XFS_ATTR_INCOMPLETE)
> 
>> +		      (entry2->flags & XFS_ATTR_INCOMPLETE));
>> +
>> +	xfs_trans_brelse(args->trans, bp1);
>> +	xfs_trans_brelse(args->trans, bp2);
> 
> This double-frees bp2 if bp1 == bp2.
Ok, will fix if needed.  Thanks for the review!  Sorry for the stray patch!

Allison
> 
> --D
> 
> 
>> +
>> +	return 0;
>> +}
>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
>> index e108b37..12283cf 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.h
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.h
>> @@ -57,7 +57,9 @@ int	xfs_attr3_leaf_to_shortform(struct xfs_buf *bp,
>>   				   struct xfs_da_args *args, int forkoff);
>>   int	xfs_attr3_leaf_clearflag(struct xfs_da_args *args);
>>   int	xfs_attr3_leaf_setflag(struct xfs_da_args *args);
>> +int	xfs_attr3_leaf_flag_is_set(struct xfs_da_args *args, bool *isset);
>>   int	xfs_attr3_leaf_flipflags(struct xfs_da_args *args);
>> +int	xfs_attr3_leaf_flagsflipped(struct xfs_da_args *args, bool *isflipped);
>>   
>>   /*
>>    * Routines used for growing the Btree.
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v4 12/17] xfs: Factor out xfs_attr_rmtval_invalidate
  2019-11-08 21:19   ` Darrick J. Wong
@ 2019-11-09  0:10     ` Allison Collins
  0 siblings, 0 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-09  0:10 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 11/8/19 2:19 PM, Darrick J. Wong wrote:
> On Wed, Nov 06, 2019 at 06:27:56PM -0700, Allison Collins wrote:
>> Because new delayed attribute routines cannot roll
>> transactions, we carve off the parts of
>> xfs_attr_rmtval_remove that we can use.  This will help to
>> reduce repetitive code later when we introduce delayed
>> attributes.
> 
> Looks good.
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
> 
> --D
Ok, thank you!

Allison

> 
> 
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> Reviewed-by: Brian Foster <bfoster@redhat.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr_remote.c | 30 +++++++++++++++++++++---------
>>   fs/xfs/libxfs/xfs_attr_remote.h |  1 +
>>   2 files changed, 22 insertions(+), 9 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.c b/fs/xfs/libxfs/xfs_attr_remote.c
>> index db51388..1544138 100644
>> --- a/fs/xfs/libxfs/xfs_attr_remote.c
>> +++ b/fs/xfs/libxfs/xfs_attr_remote.c
>> @@ -588,21 +588,14 @@ xfs_attr_rmtval_set_value(
>>   	return 0;
>>   }
>>   
>> -/*
>> - * Remove the value associated with an attribute by deleting the
>> - * out-of-line buffer that it is stored on.
>> - */
>>   int
>> -xfs_attr_rmtval_remove(
>> +xfs_attr_rmtval_invalidate(
>>   	struct xfs_da_args	*args)
>>   {
>>   	struct xfs_mount	*mp = args->dp->i_mount;
>>   	xfs_dablk_t		lblkno;
>>   	int			blkcnt;
>>   	int			error;
>> -	int			done;
>> -
>> -	trace_xfs_attr_rmtval_remove(args);
>>   
>>   	/*
>>   	 * Roll through the "value", invalidating the attribute value's blocks.
>> @@ -644,13 +637,32 @@ xfs_attr_rmtval_remove(
>>   		lblkno += map.br_blockcount;
>>   		blkcnt -= map.br_blockcount;
>>   	}
>> +	return 0;
>> +}
>>   
>> +/*
>> + * Remove the value associated with an attribute by deleting the
>> + * out-of-line buffer that it is stored on.
>> + */
>> +int
>> +xfs_attr_rmtval_remove(
>> +	struct xfs_da_args      *args)
>> +{
>> +	xfs_dablk_t		lblkno;
>> +	int			blkcnt;
>> +	int			error = 0;
>> +	int			done = 0;
>> +
>> +	trace_xfs_attr_rmtval_remove(args);
>> +
>> +	error = xfs_attr_rmtval_invalidate(args);
>> +	if (error)
>> +		return error;
>>   	/*
>>   	 * Keep de-allocating extents until the remote-value region is gone.
>>   	 */
>>   	lblkno = args->rmtblkno;
>>   	blkcnt = args->rmtblkcnt;
>> -	done = 0;
>>   	while (!done) {
>>   		error = xfs_bunmapi(args->trans, args->dp, lblkno, blkcnt,
>>   				    XFS_BMAPI_ATTRFORK, 1, &done);
>> diff --git a/fs/xfs/libxfs/xfs_attr_remote.h b/fs/xfs/libxfs/xfs_attr_remote.h
>> index cd7670d..b6fd35a 100644
>> --- a/fs/xfs/libxfs/xfs_attr_remote.h
>> +++ b/fs/xfs/libxfs/xfs_attr_remote.h
>> @@ -11,6 +11,7 @@ int xfs_attr3_rmt_blocks(struct xfs_mount *mp, int attrlen);
>>   int xfs_attr_rmtval_get(struct xfs_da_args *args);
>>   int xfs_attr_rmtval_set(struct xfs_da_args *args);
>>   int xfs_attr_rmtval_remove(struct xfs_da_args *args);
>> +int xfs_attr_rmtval_invalidate(struct xfs_da_args *args);
>>   int xfs_attr_rmtval_set_value(struct xfs_da_args *args);
>>   int xfs_attr_rmt_find_hole(struct xfs_da_args *args);
>>   #endif /* __XFS_ATTR_REMOTE_H__ */
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v4 13/17] xfs: Factor up trans roll in xfs_attr3_leaf_clearflag
  2019-11-08 21:19   ` Darrick J. Wong
@ 2019-11-09  0:11     ` Allison Collins
  0 siblings, 0 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-09  0:11 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 11/8/19 2:19 PM, Darrick J. Wong wrote:
> On Wed, Nov 06, 2019 at 06:27:57PM -0700, Allison Collins wrote:
>> New delayed allocation routines cannot be handling
>> transactions so factor them up into the calling functions
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> 
> Looks pretty straightforward,
> 
> Reviewed-by: Darrick J. Wong <darrick.wong@oracle.com>
> 
> --D
Thanks!

Allison

> 
>> ---
>>   fs/xfs/libxfs/xfs_attr.c      | 16 ++++++++++++++++
>>   fs/xfs/libxfs/xfs_attr_leaf.c |  5 +----
>>   2 files changed, 17 insertions(+), 4 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 2f9fb7a..5dcb19f 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -797,6 +797,14 @@ xfs_attr_leaf_addname(struct xfs_da_args	*args)
>>   		 * Added a "remote" value, just clear the incomplete flag.
>>   		 */
>>   		error = xfs_attr3_leaf_clearflag(args);
>> +		if (error)
>> +			return error;
>> +
>> +		/*
>> +		 * Commit the flag value change and start the next trans in
>> +		 * series.
>> +		 */
>> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
>>   	}
>>   	return error;
>>   }
>> @@ -1154,6 +1162,14 @@ xfs_attr_node_addname(
>>   		error = xfs_attr3_leaf_clearflag(args);
>>   		if (error)
>>   			goto out;
>> +
>> +		 /*
>> +		  * Commit the flag value change and start the next trans in
>> +		  * series.
>> +		  */
>> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> +		if (error)
>> +			goto out;
>>   	}
>>   	retval = error = 0;
>>   
>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
>> index 023c616..07eee3ff 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
>> @@ -2802,10 +2802,7 @@ xfs_attr3_leaf_clearflag(
>>   			 XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt)));
>>   	}
>>   
>> -	/*
>> -	 * Commit the flag value change and start the next trans in series.
>> -	 */
>> -	return xfs_trans_roll_inode(&args->trans, args->dp);
>> +	return error;
>>   }
>>   
>>   /*
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v4 14/17] xfs: Add delay context to xfs_da_args
  2019-11-08 21:22   ` Darrick J. Wong
@ 2019-11-09  0:23     ` Allison Collins
  0 siblings, 0 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-09  0:23 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 11/8/19 2:22 PM, Darrick J. Wong wrote:
> On Wed, Nov 06, 2019 at 06:27:58PM -0700, Allison Collins wrote:
>> This patch adds a new struct xfs_delay_context, which we
>> will use to keep track of the current state of a delayed
>> attribute operation.
>>
>> The new enum is used to track various operations that
>> are in progress so that we know not to repeat them, and
>> resume where we left off before EAGAIN was returned to
>> cycle out the transaction.  Other members take the place
>> of local variables that need to retain their values
>> across multiple function recalls.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_da_btree.h | 28 ++++++++++++++++++++++++++++
>>   fs/xfs/scrub/common.c        |  2 ++
>>   fs/xfs/xfs_acl.c             |  2 ++
>>   fs/xfs/xfs_attr_list.c       |  1 +
>>   fs/xfs/xfs_ioctl.c           |  2 ++
>>   fs/xfs/xfs_ioctl32.c         |  2 ++
>>   fs/xfs/xfs_iops.c            |  2 ++
>>   fs/xfs/xfs_xattr.c           |  1 +
>>   8 files changed, 40 insertions(+)
>>
>> diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
>> index bed4f40..ef23ed8 100644
>> --- a/fs/xfs/libxfs/xfs_da_btree.h
>> +++ b/fs/xfs/libxfs/xfs_da_btree.h
>> @@ -42,6 +42,33 @@ enum xfs_dacmp {
>>   	XFS_CMP_CASE		/* names are same but differ in case */
>>   };
>>   
>> +enum xfs_attr_state {
> 
> enum xfs_dc_state ?
> 
> Hm, "dc" seems a little short.
> 
> enum xfs_delattr_state?
> 
Sure.  Maybe instead of XFS_DC_* we could do XFS_DAS_*?

>> +	XFS_DC_INIT		= 1, /* Init delay info */
>> +	XFS_DC_SF_TO_LEAF	= 2, /* Converted short form to leaf */
>> +	XFS_DC_FOUND_LBLK	= 3, /* We found leaf blk for attr */
>> +	XFS_DC_LEAF_TO_NODE	= 4, /* Converted leaf to node */
>> +	XFS_DC_FOUND_NBLK	= 5, /* We found node blk for attr */
>> +	XFS_DC_ALLOC_LEAF	= 6, /* We are allocating leaf blocks */
>> +	XFS_DC_ALLOC_NODE	= 7, /* We are allocating node blocks */
>> +	XFS_DC_RM_INVALIDATE	= 8, /* We are invalidating blocks */
>> +	XFS_DC_RM_SHRINK	= 9, /* We are shrinking the tree */
>> +	XFS_DC_RM_NODE_BLKS	= 10,/* We are removing node blocks */
>> +};
>> +
>> +/*
>> + * Context used for keeping track of delayed attribute operations
>> + */
>> +struct xfs_delay_context {
> 
> struct xfs_delattr_context ?
Sure, I'm not too particular on the names.
> 
>> +	enum xfs_attr_state	dc_state;
>> +	struct xfs_buf		*leaf_bp;
>> +	struct xfs_bmbt_irec	map;
>> +	xfs_dablk_t		lblkno;
>> +	xfs_fileoff_t		lfileoff;
>> +	int			blkcnt;
>> +	struct xfs_da_state	*da_state;
>> +	struct xfs_da_state_blk *blk;
>> +};
> 
> Would be kinda nice to keep this structure size to a minimum by
> reordering these in order of decreasing size.  pahole is your friend for
> doing that (or shouting me down). ;)
> 
Ok, I'll check that.  Thanks for the review!

Allison

> But otherwise this seems ok.
> 
> --D
> 
>> +
>>   /*
>>    * Structure to ease passing around component names.
>>    */
>> @@ -69,6 +96,7 @@ typedef struct xfs_da_args {
>>   	int		rmtvaluelen2;	/* remote attr value length in bytes */
>>   	int		op_flags;	/* operation flags */
>>   	enum xfs_dacmp	cmpresult;	/* name compare result for lookups */
>> +	struct xfs_delay_context  dc;	/* context used for delay attr ops */
>>   } xfs_da_args_t;
>>   
>>   /*
>> diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
>> index 1887605..9a649d1 100644
>> --- a/fs/xfs/scrub/common.c
>> +++ b/fs/xfs/scrub/common.c
>> @@ -24,6 +24,8 @@
>>   #include "xfs_rmap_btree.h"
>>   #include "xfs_log.h"
>>   #include "xfs_trans_priv.h"
>> +#include "xfs_da_format.h"
>> +#include "xfs_da_btree.h"
>>   #include "xfs_attr.h"
>>   #include "xfs_reflink.h"
>>   #include "scrub/scrub.h"
>> diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
>> index e868755..1336477 100644
>> --- a/fs/xfs/xfs_acl.c
>> +++ b/fs/xfs/xfs_acl.c
>> @@ -10,6 +10,8 @@
>>   #include "xfs_trans_resv.h"
>>   #include "xfs_mount.h"
>>   #include "xfs_inode.h"
>> +#include "xfs_da_format.h"
>> +#include "xfs_da_btree.h"
>>   #include "xfs_attr.h"
>>   #include "xfs_trace.h"
>>   #include <linux/posix_acl_xattr.h>
>> diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
>> index fab416c..e395864 100644
>> --- a/fs/xfs/xfs_attr_list.c
>> +++ b/fs/xfs/xfs_attr_list.c
>> @@ -12,6 +12,7 @@
>>   #include "xfs_trans_resv.h"
>>   #include "xfs_mount.h"
>>   #include "xfs_da_format.h"
>> +#include "xfs_da_btree.h"
>>   #include "xfs_inode.h"
>>   #include "xfs_trans.h"
>>   #include "xfs_bmap.h"
>> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
>> index ae0ed88..23b0ca6 100644
>> --- a/fs/xfs/xfs_ioctl.c
>> +++ b/fs/xfs/xfs_ioctl.c
>> @@ -15,6 +15,8 @@
>>   #include "xfs_iwalk.h"
>>   #include "xfs_itable.h"
>>   #include "xfs_error.h"
>> +#include "xfs_da_format.h"
>> +#include "xfs_da_btree.h"
>>   #include "xfs_attr.h"
>>   #include "xfs_bmap.h"
>>   #include "xfs_bmap_util.h"
>> diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c
>> index 3c0d518..e3278ac 100644
>> --- a/fs/xfs/xfs_ioctl32.c
>> +++ b/fs/xfs/xfs_ioctl32.c
>> @@ -17,6 +17,8 @@
>>   #include "xfs_itable.h"
>>   #include "xfs_fsops.h"
>>   #include "xfs_rtalloc.h"
>> +#include "xfs_da_format.h"
>> +#include "xfs_da_btree.h"
>>   #include "xfs_attr.h"
>>   #include "xfs_ioctl.h"
>>   #include "xfs_ioctl32.h"
>> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
>> index aef346e..68b9cd0 100644
>> --- a/fs/xfs/xfs_iops.c
>> +++ b/fs/xfs/xfs_iops.c
>> @@ -13,6 +13,8 @@
>>   #include "xfs_inode.h"
>>   #include "xfs_acl.h"
>>   #include "xfs_quota.h"
>> +#include "xfs_da_format.h"
>> +#include "xfs_da_btree.h"
>>   #include "xfs_attr.h"
>>   #include "xfs_trans.h"
>>   #include "xfs_trace.h"
>> diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
>> index 6c5321d..0f0ebab 100644
>> --- a/fs/xfs/xfs_xattr.c
>> +++ b/fs/xfs/xfs_xattr.c
>> @@ -10,6 +10,7 @@
>>   #include "xfs_log_format.h"
>>   #include "xfs_da_format.h"
>>   #include "xfs_inode.h"
>> +#include "xfs_da_btree.h"
>>   #include "xfs_attr.h"
>>   
>>   #include <linux/posix_acl_xattr.h>
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v4 16/17] xfs: Add delay ready attr remove routines
  2019-11-08 21:37   ` Darrick J. Wong
@ 2019-11-09  0:25     ` Allison Collins
  0 siblings, 0 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-09  0:25 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 11/8/19 2:37 PM, Darrick J. Wong wrote:
> On Wed, Nov 06, 2019 at 06:28:00PM -0700, Allison Collins wrote:
>> This patch modifies the attr remove routines to be delay ready.
>> This means they no longer roll or commit transactions, but instead
>> return -EAGAIN to have the calling routine roll and refresh the
>> transaction.  In this series, xfs_attr_remove_args has become
>> xfs_attr_remove_later, which uses a state machine to keep track
>> of where it was when EAGAIN was returned.  xfs_attr_node_removename
>> has also been modified to use the state machine, and a  new version of
>> xfs_attr_remove_args consists of a simple loop to refresh the
>> transaction until the operation is completed.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 123 +++++++++++++++++++++++++++++++++++++++--------
>>   fs/xfs/libxfs/xfs_attr.h |   1 +
>>   2 files changed, 104 insertions(+), 20 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 626d4a98..38d5c5c 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -369,10 +369,56 @@ xfs_has_attr(
>>    */
>>   int
>>   xfs_attr_remove_args(
>> +	struct xfs_da_args	*args)
>> +{
>> +	int			error = 0;
>> +	int			err2 = 0;
>> +
>> +	do {
>> +		error = xfs_attr_remove_later(args);
>> +		if (error && error != -EAGAIN)
>> +			goto out;
>> +
>> +		xfs_trans_log_inode(args->trans, args->dp,
>> +			XFS_ILOG_CORE | XFS_ILOG_ADATA);
> 
> Don't the individual pieces of attr removal log ADATA on their own, when
> needed?
> 
> If it weren't for that, this could just be xfs_trans_roll_inode, right?

Oh i see.  I will see if I can simplify that.  Thanks!
Allison

> 
> --D
> 
>> +
>> +		err2 = xfs_trans_roll(&args->trans);
>> +		if (err2) {
>> +			error = err2;
>> +			goto out;
>> +		}
>> +
>> +		/* Rejoin inode */
>> +		xfs_trans_ijoin(args->trans, args->dp, 0);
>> +
>> +	} while (error == -EAGAIN);
>> +out:
>> +	return error;
>> +}
>> +
>> +/*
>> + * Remove the attribute specified in @args.
>> + * This routine is meant to function as a delayed operation, and may return
>> + * -EGAIN when the transaction needs to be rolled.  Calling functions will need
>> + * to handle this, and recall the function until a successful error code is
>> + * returned.
>> + */
>> +int
>> +xfs_attr_remove_later(
>>   	struct xfs_da_args      *args)
>>   {
>>   	struct xfs_inode	*dp = args->dp;
>> -	int			error;
>> +	int			error = 0;
>> +
>> +	/* State machine switch */
>> +	switch (args->dc.dc_state) {
>> +	case XFS_DC_RM_INVALIDATE:
>> +	case XFS_DC_RM_SHRINK:
>> +	case XFS_DC_RM_NODE_BLKS:
>> +		goto node;
>> +	default:
>> +		break;
>> +	}
>>   
>>   	if (!xfs_inode_hasattr(dp)) {
>>   		error = -ENOATTR;
>> @@ -382,6 +428,7 @@ xfs_attr_remove_args(
>>   	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>>   		error = xfs_attr_leaf_removename(args);
>>   	} else {
>> +node:
>>   		error = xfs_attr_node_removename(args);
>>   	}
>>   
>> @@ -892,9 +939,6 @@ xfs_attr_leaf_removename(
>>   		/* bp is gone due to xfs_da_shrink_inode */
>>   		if (error)
>>   			return error;
>> -		error = xfs_defer_finish(&args->trans);
>> -		if (error)
>> -			return error;
>>   	}
>>   	return 0;
>>   }
>> @@ -1212,6 +1256,11 @@ xfs_attr_node_addname(
>>    * This will involve walking down the Btree, and may involve joining
>>    * leaf nodes and even joining intermediate nodes up to and including
>>    * the root node (a special case of an intermediate node).
>> + *
>> + * This routine is meant to function as a delayed operation, and may return
>> + * -EAGAIN when the transaction needs to be rolled.  Calling functions
>> + * will need to handle this, and recall the function until a successful error
>> + * code is returned.
>>    */
>>   STATIC int
>>   xfs_attr_node_removename(
>> @@ -1222,12 +1271,29 @@ xfs_attr_node_removename(
>>   	struct xfs_buf		*bp;
>>   	int			retval, error, forkoff;
>>   	struct xfs_inode	*dp = args->dp;
>> +	int			done = 0;
>>   
>>   	trace_xfs_attr_node_removename(args);
>> +	state = args->dc.da_state;
>> +	blk = args->dc.blk;
>> +
>> +	/* State machine switch */
>> +	switch (args->dc.dc_state) {
>> +	case XFS_DC_RM_NODE_BLKS:
>> +		goto rm_node_blks;
>> +	case XFS_DC_RM_INVALIDATE:
>> +		goto rm_invalidate;
>> +	case XFS_DC_RM_SHRINK:
>> +		goto rm_shrink;
>> +	default:
>> +		break;
>> +	}
>>   
>>   	error = xfs_attr_node_hasname(args, &state);
>>   	if (error != -EEXIST)
>>   		goto out;
>> +	else
>> +		error = 0;
>>   
>>   	/*
>>   	 * If there is an out-of-line value, de-allocate the blocks.
>> @@ -1237,6 +1303,14 @@ xfs_attr_node_removename(
>>   	blk = &state->path.blk[ state->path.active-1 ];
>>   	ASSERT(blk->bp != NULL);
>>   	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>> +
>> +	/*
>> +	 * Store blk and state in the context incase we need to cycle out the
>> +	 * transaction
>> +	 */
>> +	args->dc.blk = blk;
>> +	args->dc.da_state = state;
>> +
>>   	if (args->rmtblkno > 0) {
>>   		/*
>>   		 * Fill in disk block numbers in the state structure
>> @@ -1255,13 +1329,30 @@ xfs_attr_node_removename(
>>   		if (error)
>>   			goto out;
>>   
>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> +		args->dc.dc_state = XFS_DC_RM_INVALIDATE;
>> +		return -EAGAIN;
>> +rm_invalidate:
>> +		error = xfs_attr_rmtval_invalidate(args);
>>   		if (error)
>>   			goto out;
>> +rm_node_blks:
>> +		/*
>> +		 * Unmap value blocks for this attr.  This is similar to
>> +		 * xfs_attr_rmtval_remove, but open coded here to return EAGAIN
>> +		 * for new transactions
>> +		 */
>> +		while (!done && !error) {
>> +			error = xfs_bunmapi(args->trans, args->dp,
>> +				    args->rmtblkno, args->rmtblkcnt,
>> +				    XFS_BMAPI_ATTRFORK, 1, &done);
>> +			if (error)
>> +				return error;
>>   
>> -		error = xfs_attr_rmtval_remove(args);
>> -		if (error)
>> -			goto out;
>> +			if (!done) {
>> +				args->dc.dc_state = XFS_DC_RM_NODE_BLKS;
>> +				return -EAGAIN;
>> +			}
>> +		}
>>   
>>   		/*
>>   		 * Refill the state structure with buffers, the prior calls
>> @@ -1287,17 +1378,12 @@ xfs_attr_node_removename(
>>   		error = xfs_da3_join(state);
>>   		if (error)
>>   			goto out;
>> -		error = xfs_defer_finish(&args->trans);
>> -		if (error)
>> -			goto out;
>> -		/*
>> -		 * Commit the Btree join operation and start a new trans.
>> -		 */
>> -		error = xfs_trans_roll_inode(&args->trans, dp);
>> -		if (error)
>> -			goto out;
>> +
>> +		args->dc.dc_state = XFS_DC_RM_SHRINK;
>> +		return -EAGAIN;
>>   	}
>>   
>> +rm_shrink:
>>   	/*
>>   	 * If the result is small enough, push it all into the inode.
>>   	 */
>> @@ -1319,9 +1405,6 @@ xfs_attr_node_removename(
>>   			/* bp is gone due to xfs_da_shrink_inode */
>>   			if (error)
>>   				goto out;
>> -			error = xfs_defer_finish(&args->trans);
>> -			if (error)
>> -				goto out;
>>   		} else
>>   			xfs_trans_brelse(args->trans, bp);
>>   	}
>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>> index 3b5dad4..fb8bf5b 100644
>> --- a/fs/xfs/libxfs/xfs_attr.h
>> +++ b/fs/xfs/libxfs/xfs_attr.h
>> @@ -152,6 +152,7 @@ int xfs_attr_set_args(struct xfs_da_args *args);
>>   int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
>>   int xfs_has_attr(struct xfs_da_args *args);
>>   int xfs_attr_remove_args(struct xfs_da_args *args);
>> +int xfs_attr_remove_later(struct xfs_da_args *args);
>>   int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>>   		  int flags, struct attrlist_cursor_kern *cursor);
>>   bool xfs_attr_namecheck(const void *name, size_t length);
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v4 17/17] xfs: Add delay ready attr set routines
  2019-11-08 21:42   ` Darrick J. Wong
  2019-11-08 21:52     ` Allison Collins
@ 2019-11-09  4:07     ` Allison Collins
  1 sibling, 0 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-09  4:07 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 11/8/19 2:42 PM, Darrick J. Wong wrote:
> On Wed, Nov 06, 2019 at 06:28:01PM -0700, Allison Collins wrote:
>> This patch modifies the attr set routines to be delay ready.
>> This means they no longer roll or commit transactions, but instead
>> return -EAGAIN to have the calling routine roll and refresh the
>> transaction.  In this series, xfs_attr_set_args has become
>> xfs_attr_set_later, which uses a state machine to keep track
>> of where it was when EAGAIN was returned.  Part of
>> xfs_attr_leaf_addname has been factored out into a new helper
>> function xfs_attr_leaf_try_add to allow transaction cycling between
>> the two routines, and the flipflags logic has been removed since we
>> can simply cancel the transaction upon error.  xfs_attr_set_args
>> consists of a simple loop to refresh the transaction until the
>> operation is completed.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 435 +++++++++++++++++++++++------------------------
>>   fs/xfs/libxfs/xfs_attr.h |   1 +
>>   2 files changed, 211 insertions(+), 225 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 38d5c5c..97e5ae0 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -58,6 +58,7 @@ STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
>>   				 struct xfs_da_state **state);
>>   STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
>>   STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
>> +STATIC int xfs_attr_leaf_try_add(struct xfs_da_args *args, struct xfs_buf *bp);
>>   
>>   
>>   STATIC int
>> @@ -250,9 +251,79 @@ int
>>   xfs_attr_set_args(
>>   	struct xfs_da_args	*args)
>>   {
>> +	int			error = 0;
>> +	int			err2 = 0;
>> +	struct xfs_buf		*leaf_bp = NULL;
>> +
>> +	do {
>> +		error = xfs_attr_set_later(args, &leaf_bp);
>> +		if (error && error != -EAGAIN)
>> +			goto out;
>> +
>> +		xfs_trans_log_inode(args->trans, args->dp,
>> +				    XFS_ILOG_CORE | XFS_ILOG_ADATA);
> 
> Same question as the last patch about ADATA.
> 
>> +
>> +		err2 = xfs_trans_roll(&args->trans);
>> +		if (err2) {
>> +			error = err2;
>> +			goto out;
>> +		}
>> +
>> +		/* Rejoin inode and leaf if needed */
>> +		xfs_trans_ijoin(args->trans, args->dp, 0);
>> +		if (leaf_bp) {
>> +			xfs_trans_bjoin(args->trans, leaf_bp);
>> +			xfs_trans_bhold(args->trans, leaf_bp);
>> +		}
>> +
>> +	} while (error == -EAGAIN);
>> +
>> +out:
>> +	return error;
>> +}
>> +
>> +/*
>> + * Set the attribute specified in @args.
>> + * This routine is meant to function as a delayed operation, and may return
>> + * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
>> + * to handle this, and recall the function until a successful error code is
>> + * returned.
>> + */
>> +int
>> +xfs_attr_set_later(
>> +	struct xfs_da_args	*args,
>> +	struct xfs_buf          **leaf_bp)
>> +{
>>   	struct xfs_inode	*dp = args->dp;
>> -	struct xfs_buf          *leaf_bp = NULL;
>> -	int			error, error2 = 0;;
>> +	int			error = 0;
>> +	int			sf_size;
>> +
>> +	/* State machine switch */
>> +	switch (args->dc.dc_state) {
>> +	case XFS_DC_SF_TO_LEAF:
>> +		goto sf_to_leaf;
>> +	case XFS_DC_ALLOC_LEAF:
>> +	case XFS_DC_FOUND_LBLK:
>> +		goto leaf;
>> +	case XFS_DC_FOUND_NBLK:
>> +	case XFS_DC_ALLOC_NODE:
>> +	case XFS_DC_LEAF_TO_NODE:
>> +		goto node;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	/*
>> +	 * New inodes may not have an attribute fork yet. So set the attribute
>> +	 * fork appropriately
>> +	 */
>> +	if (XFS_IFORK_Q((args->dp)) == 0) {
>> +		sf_size = sizeof(struct xfs_attr_sf_hdr) +
>> +		     XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
>> +		xfs_bmap_set_attrforkoff(args->dp, sf_size, NULL);
>> +		args->dp->i_afp = kmem_zone_zalloc(xfs_ifork_zone, 0);
>> +		args->dp->i_afp->if_flags = XFS_IFEXTENTS;
>> +	}
>>   
>>   	/*
>>   	 * If the attribute list is non-existent or a shortform list,
>> @@ -272,21 +343,14 @@ xfs_attr_set_args(
>>   		 * Try to add the attr to the attribute list in the inode.
>>   		 */
>>   		error = xfs_attr_try_sf_addname(dp, args);
>> -		if (error != -ENOSPC) {
>> -			if (dp->i_mount->m_flags & XFS_MOUNT_WSYNC)
>> -				xfs_trans_set_sync(args->trans);
> 
> Where does the xfs_trans_set_sync call go?  Do we not need it anymore?
I may have lost it somewhere in all the re-refactoring.  I will add it 
back.  Sorry!

> 
>> -			error2 = xfs_trans_commit(args->trans);
>> -			args->trans = NULL;
>> -			return error ? error : error2;
>> -		}
>> -
>> +		if (error != -ENOSPC)
>> +			return error;
>>   
>>   		/*
>>   		 * It won't fit in the shortform, transform to a leaf block.
>>   		 * GROT: another possible req'mt for a double-split btree op.
>>   		 */
>> -		error = xfs_attr_shortform_to_leaf(args, &leaf_bp);
>> +		error = xfs_attr_shortform_to_leaf(args, leaf_bp);
>>   		if (error)
>>   			return error;
>>   
>> @@ -294,43 +358,42 @@ xfs_attr_set_args(
>>   		 * Prevent the leaf buffer from being unlocked so that a
>>   		 * concurrent AIL push cannot grab the half-baked leaf
>>   		 * buffer and run into problems with the write verifier.
>> -		 * Once we're done rolling the transaction we can release
>> -		 * the hold and add the attr to the leaf.
>>   		 */
>> -		xfs_trans_bhold(args->trans, leaf_bp);
>> -		error = xfs_defer_finish(&args->trans);
>> -		xfs_trans_bhold_release(args->trans, leaf_bp);
>> -		if (error) {
>> -			xfs_trans_brelse(args->trans, leaf_bp);
>> -			return error;
>> -		}
>> +
>> +		xfs_trans_bhold(args->trans, *leaf_bp);
>> +		args->dc.dc_state = XFS_DC_SF_TO_LEAF;
>> +		return -EAGAIN;
>> +	}
>> +sf_to_leaf:
>> +
>> +	/*
>> +	 * After a shortform to leaf conversion, we need to hold the leaf and
>> +	 * cylce out the transaction.  When we get back, we need to release
> 
>             "cycle"
> 
>> +	 * the leaf.
>> +	 */
>> +	if (*leaf_bp != NULL) {
>> +		xfs_trans_brelse(args->trans, *leaf_bp);
>> +		*leaf_bp = NULL;
>>   	}
>>   
>>   	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>> +		error = xfs_attr_leaf_try_add(args, *leaf_bp);
>> +		if (error == -ENOSPC)
>> +			args->dc.dc_state = XFS_DC_LEAF_TO_NODE;
>> +		else if (error)
>> +			return error;
>> +		else
>> +			args->dc.dc_state = XFS_DC_FOUND_LBLK;
>> +		return -EAGAIN;
> 
> Please use a switch statement here...
> 
> switch (error) {
> case -ENOSPC:
> 	dc_state = LEAF_TO_NODE;
> 	return -EAGAIN;
> case 0:
> 	dc_state = FOUND_LBLK;
> 	return -EAGAIN;
> default:
> 	return error;
> }
Sure, will do

> 
>> +leaf:
>>   		error = xfs_attr_leaf_addname(args);
>>   		if (error == -ENOSPC) {
>> -			/*
>> -			 * Commit that transaction so that the node_addname()
>> -			 * call can manage its own transactions.
>> -			 */
>> -			error = xfs_defer_finish(&args->trans);
>> -			if (error)
>> -				return error;
>> -
>> -			/*
>> -			 * Commit the current trans (including the inode) and
>> -			 * start a new one.
>> -			 */
>> -			error = xfs_trans_roll_inode(&args->trans, dp);
>> -			if (error)
>> -				return error;
>> -
>> -			/*
>> -			 * Fob the rest of the problem off on the Btree code.
>> -			 */
>> -			error = xfs_attr_node_addname(args);
>> +			args->dc.dc_state = XFS_DC_LEAF_TO_NODE;
>> +			return -EAGAIN;
>>   		}
>>   	} else {
>> +		args->dc.dc_state = XFS_DC_LEAF_TO_NODE;
>> +node:
>>   		error = xfs_attr_node_addname(args);
>>   	}
>>   	return error;
>> @@ -764,27 +827,26 @@ xfs_attr_leaf_try_add(
>>    *
>>    * This leaf block cannot have a "remote" value, we only call this routine
>>    * if bmap_one_block() says there is only one block (ie: no remote blks).
>> + *
>> + * This routine is meant to function as a delayed operation, and may return
>> + * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
>> + * to handle this, and recall the function until a successful error code is
>> + * returned.
>>    */
>>   STATIC int
>>   xfs_attr_leaf_addname(struct xfs_da_args	*args)
>>   {
>> -	int			error, forkoff;
>> -	struct xfs_buf		*bp = NULL;
>> +	int			error, nmap;
>>   	struct xfs_inode	*dp = args->dp;
>> +	struct xfs_bmbt_irec	*map = &args->dc.map;
>>   
>> -	trace_xfs_attr_leaf_addname(args);
>> -
>> -	error = xfs_attr_leaf_try_add(args, bp);
>> -	if (error)
>> -		return error;
>> -
>> -	/*
>> -	 * Commit the transaction that added the attr name so that
>> -	 * later routines can manage their own transactions.
>> -	 */
>> -	error = xfs_trans_roll_inode(&args->trans, dp);
>> -	if (error)
>> -		return error;
>> +	/* State machine switch */
>> +	switch (args->dc.dc_state) {
>> +	case XFS_DC_ALLOC_LEAF:
>> +		goto alloc_leaf;
>> +	default:
>> +		break;
>> +	}
>>   
>>   	/*
>>   	 * If there was an out-of-line value, allocate the blocks we
>> @@ -793,90 +855,58 @@ xfs_attr_leaf_addname(struct xfs_da_args	*args)
>>   	 * maximum size of a transaction and/or hit a deadlock.
>>   	 */
>>   	if (args->rmtblkno > 0) {
>> -		error = xfs_attr_rmtval_set(args);
>> -		if (error)
>> -			return error;
>> -	}
>>   
>> -	/*
>> -	 * If this is an atomic rename operation, we must "flip" the
>> -	 * incomplete flags on the "new" and "old" attribute/value pairs
>> -	 * so that one disappears and one appears atomically.  Then we
>> -	 * must remove the "old" attribute/value pair.
>> -	 */
>> -	if (args->op_flags & XFS_DA_OP_RENAME) {
>> -		/*
>> -		 * In a separate transaction, set the incomplete flag on the
>> -		 * "old" attr and clear the incomplete flag on the "new" attr.
>> -		 */
>> -		error = xfs_attr3_leaf_flipflags(args);
>> -		if (error)
>> -			return error;
>> -		/*
>> -		 * Commit the flag value change and start the next trans in
>> -		 * series.
>> -		 */
>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> -		if (error)
>> -			return error;
>> +		/* Open coded xfs_attr_rmtval_set without trans handling */
> 
> Can't we just fix that instead of reproducing it here?
By fix, you mean to plumb in the state machine into xfs_attr_rmtval_set? 
  We can, it will just need a few more states I think.  I guess I was 
just trying to avoid that as much as possible by surfacing all the 
places that we need to return EAGAIN.  I think the idea Brian was aiming 
for in some of the earlier reviews was to refactor things such that we 
have the helper calls in between the EAGAINS so that the state machine 
hops are easier to see rather than being buried here and there in sub 
routines.

But spots like this are harder to do that with because of the while 
loop.  The loop has to come up, and then the transaction code 
disappears, but then there's not much left to modularize with in the 
loop body. It is hard to see though patch diff though, hopefully those 
links helped?

Allison

> 
> Especially because I think I see it twice in this patch?
> 
> Also, do you have a git tree handy?  I /think/ I see how this works but
> oh man is it difficult to see that from patches alone.
> 
> --D
> 
>>   
>> -		/*
>> -		 * Dismantle the "old" attribute/value pair by removing
>> -		 * a "remote" value (if it exists).
>> -		 */
>> -		args->index = args->index2;
>> -		args->blkno = args->blkno2;
>> -		args->rmtblkno = args->rmtblkno2;
>> -		args->rmtblkcnt = args->rmtblkcnt2;
>> -		args->rmtvaluelen = args->rmtvaluelen2;
>> -		if (args->rmtblkno) {
>> -			error = xfs_attr_rmtval_remove(args);
>> -			if (error)
>> -				return error;
>> -		}
>> +		args->dc.lfileoff = 0;
>> +		args->dc.lblkno = 0;
>> +		args->dc.blkcnt = 0;
>> +		args->rmtblkcnt = 0;
>> +		args->rmtblkno = 0;
>> +		memset(map, 0, sizeof(struct xfs_bmbt_irec));
>>   
>> -		/*
>> -		 * Read in the block containing the "old" attr, then
>> -		 * remove the "old" attr from that block (neat, huh!)
>> -		 */
>> -		error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
>> -					   XFS_DABUF_MAP_NOMAPPING, &bp);
>> +		error = xfs_attr_rmt_find_hole(args);
>>   		if (error)
>>   			return error;
>>   
>> -		xfs_attr3_leaf_remove(bp, args);
>> +		args->dc.blkcnt = args->rmtblkcnt;
>> +		args->dc.lblkno = args->rmtblkno;
>>   
>>   		/*
>> -		 * If the result is small enough, shrink it all into the inode.
>> +		 * Roll through the "value", allocating blocks on disk as
>> +		 * required.
>>   		 */
>> -		if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
>> -			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
>> -			/* bp is gone due to xfs_da_shrink_inode */
>> -			if (error)
>> -				return error;
>> -			error = xfs_defer_finish(&args->trans);
>> +alloc_leaf:
>> +		while (args->dc.blkcnt > 0) {
>> +			nmap = 1;
>> +			error = xfs_bmapi_write(args->trans, dp,
>> +				  (xfs_fileoff_t)args->dc.lblkno,
>> +				  args->dc.blkcnt, XFS_BMAPI_ATTRFORK,
>> +				  args->total, map, &nmap);
>>   			if (error)
>>   				return error;
>> -		}
>> +			ASSERT(nmap == 1);
>> +			ASSERT((map->br_startblock != DELAYSTARTBLOCK) &&
>> +			       (map->br_startblock != HOLESTARTBLOCK));
>>   
>> -		/*
>> -		 * Commit the remove and start the next trans in series.
>> -		 */
>> -		error = xfs_trans_roll_inode(&args->trans, dp);
>> +			/* roll attribute extent map forwards */
>> +			args->dc.lblkno += map->br_blockcount;
>> +			args->dc.blkcnt -= map->br_blockcount;
>>   
>> -	} else if (args->rmtblkno > 0) {
>> -		/*
>> -		 * Added a "remote" value, just clear the incomplete flag.
>> -		 */
>> -		error = xfs_attr3_leaf_clearflag(args);
>> +			args->dc.dc_state = XFS_DC_ALLOC_LEAF;
>> +			return -EAGAIN;
>> +		}
>> +
>> +		error = xfs_attr_rmtval_set_value(args);
>>   		if (error)
>>   			return error;
>> +	}
>>   
>> +	if (args->rmtblkno > 0) {
>>   		/*
>> -		 * Commit the flag value change and start the next trans in
>> -		 * series.
>> +		 * Added a "remote" value, just clear the incomplete flag.
>>   		 */
>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> +		error = xfs_attr3_leaf_clearflag(args);
>>   	}
>>   	return error;
>>   }
>> @@ -1017,16 +1047,23 @@ xfs_attr_node_hasname(
>>    *
>>    * "Remote" attribute values confuse the issue and atomic rename operations
>>    * add a whole extra layer of confusion on top of that.
>> + *
>> + * This routine is meant to function as a delayed operation, and may return
>> + * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
>> + * to handle this, and recall the function until a successful error code is
>> + *returned.
>>    */
>>   STATIC int
>>   xfs_attr_node_addname(
>>   	struct xfs_da_args	*args)
>>   {
>> -	struct xfs_da_state	*state;
>> +	struct xfs_da_state	*state = NULL;
>>   	struct xfs_da_state_blk	*blk;
>>   	struct xfs_inode	*dp;
>> -	struct xfs_mount	*mp;
>> -	int			retval, error;
>> +	int			retval = 0;
>> +	int			error = 0;
>> +	int			nmap;
>> +	struct xfs_bmbt_irec    *map = &args->dc.map;
>>   
>>   	trace_xfs_attr_node_addname(args);
>>   
>> @@ -1034,8 +1071,17 @@ xfs_attr_node_addname(
>>   	 * Fill in bucket of arguments/results/context to carry around.
>>   	 */
>>   	dp = args->dp;
>> -	mp = dp->i_mount;
>> -restart:
>> +
>> +	/* State machine switch */
>> +	switch (args->dc.dc_state) {
>> +	case XFS_DC_FOUND_NBLK:
>> +		goto found_nblk;
>> +	case XFS_DC_ALLOC_NODE:
>> +		goto alloc_node;
>> +	default:
>> +		break;
>> +	}
>> +
>>   	/*
>>   	 * Search to see if name already exists, and get back a pointer
>>   	 * to where it should go.
>> @@ -1085,19 +1131,12 @@ xfs_attr_node_addname(
>>   			error = xfs_attr3_leaf_to_node(args);
>>   			if (error)
>>   				goto out;
>> -			error = xfs_defer_finish(&args->trans);
>> -			if (error)
>> -				goto out;
>>   
>>   			/*
>> -			 * Commit the node conversion and start the next
>> -			 * trans in the chain.
>> +			 * Restart routine from the top.  No need to set  the
>> +			 * state
>>   			 */
>> -			error = xfs_trans_roll_inode(&args->trans, dp);
>> -			if (error)
>> -				goto out;
>> -
>> -			goto restart;
>> +			return -EAGAIN;
>>   		}
>>   
>>   		/*
>> @@ -1109,9 +1148,6 @@ xfs_attr_node_addname(
>>   		error = xfs_da3_split(state);
>>   		if (error)
>>   			goto out;
>> -		error = xfs_defer_finish(&args->trans);
>> -		if (error)
>> -			goto out;
>>   	} else {
>>   		/*
>>   		 * Addition succeeded, update Btree hashvals.
>> @@ -1126,13 +1162,9 @@ xfs_attr_node_addname(
>>   	xfs_da_state_free(state);
>>   	state = NULL;
>>   
>> -	/*
>> -	 * Commit the leaf addition or btree split and start the next
>> -	 * trans in the chain.
>> -	 */
>> -	error = xfs_trans_roll_inode(&args->trans, dp);
>> -	if (error)
>> -		goto out;
>> +	args->dc.dc_state = XFS_DC_FOUND_NBLK;
>> +	return -EAGAIN;
>> +found_nblk:
>>   
>>   	/*
>>   	 * If there was an out-of-line value, allocate the blocks we
>> @@ -1141,104 +1173,57 @@ xfs_attr_node_addname(
>>   	 * maximum size of a transaction and/or hit a deadlock.
>>   	 */
>>   	if (args->rmtblkno > 0) {
>> -		error = xfs_attr_rmtval_set(args);
>> -		if (error)
>> -			return error;
>> -	}
>> +		/* Open coded xfs_attr_rmtval_set without trans handling */
>> +		args->dc.lblkno = 0;
>> +		args->dc.lfileoff = 0;
>> +		args->dc.blkcnt = 0;
>> +		args->rmtblkcnt = 0;
>> +		args->rmtblkno = 0;
>> +		memset(map, 0, sizeof(struct xfs_bmbt_irec));
>>   
>> -	/*
>> -	 * If this is an atomic rename operation, we must "flip" the
>> -	 * incomplete flags on the "new" and "old" attribute/value pairs
>> -	 * so that one disappears and one appears atomically.  Then we
>> -	 * must remove the "old" attribute/value pair.
>> -	 */
>> -	if (args->op_flags & XFS_DA_OP_RENAME) {
>> -		/*
>> -		 * In a separate transaction, set the incomplete flag on the
>> -		 * "old" attr and clear the incomplete flag on the "new" attr.
>> -		 */
>> -		error = xfs_attr3_leaf_flipflags(args);
>> -		if (error)
>> -			goto out;
>> -		/*
>> -		 * Commit the flag value change and start the next trans in
>> -		 * series
>> -		 */
>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> +		error = xfs_attr_rmt_find_hole(args);
>>   		if (error)
>> -			goto out;
>> +			return error;
>>   
>> +		args->dc.blkcnt = args->rmtblkcnt;
>> +		args->dc.lblkno = args->rmtblkno;
>>   		/*
>> -		 * Dismantle the "old" attribute/value pair by removing
>> -		 * a "remote" value (if it exists).
>> +		 * Roll through the "value", allocating blocks on disk as
>> +		 * required.
>>   		 */
>> -		args->index = args->index2;
>> -		args->blkno = args->blkno2;
>> -		args->rmtblkno = args->rmtblkno2;
>> -		args->rmtblkcnt = args->rmtblkcnt2;
>> -		args->rmtvaluelen = args->rmtvaluelen2;
>> -		if (args->rmtblkno) {
>> -			error = xfs_attr_rmtval_remove(args);
>> +alloc_node:
>> +		while (args->dc.blkcnt > 0) {
>> +			nmap = 1;
>> +			error = xfs_bmapi_write(args->trans, dp,
>> +				(xfs_fileoff_t)args->dc.lblkno, args->dc.blkcnt,
>> +				XFS_BMAPI_ATTRFORK, args->total, map, &nmap);
>>   			if (error)
>>   				return error;
>> -		}
>>   
>> -		/*
>> -		 * Re-find the "old" attribute entry after any split ops.
>> -		 * The INCOMPLETE flag means that we will find the "old"
>> -		 * attr, not the "new" one.
>> -		 */
>> -		args->name.type |= XFS_ATTR_INCOMPLETE;
>> -		state = xfs_da_state_alloc();
>> -		state->args = args;
>> -		state->mp = mp;
>> -		state->inleaf = 0;
>> -		error = xfs_da3_node_lookup_int(state, &retval);
>> -		if (error)
>> -			goto out;
>> +			ASSERT(nmap == 1);
>> +			ASSERT((map->br_startblock != DELAYSTARTBLOCK) &&
>> +			       (map->br_startblock != HOLESTARTBLOCK));
>>   
>> -		/*
>> -		 * Remove the name and update the hashvals in the tree.
>> -		 */
>> -		blk = &state->path.blk[ state->path.active-1 ];
>> -		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>> -		error = xfs_attr3_leaf_remove(blk->bp, args);
>> -		xfs_da3_fixhashpath(state, &state->path);
>> +			/* roll attribute extent map forwards */
>> +			args->dc.lblkno += map->br_blockcount;
>> +			args->dc.blkcnt -= map->br_blockcount;
>>   
>> -		/*
>> -		 * Check to see if the tree needs to be collapsed.
>> -		 */
>> -		if (retval && (state->path.active > 1)) {
>> -			error = xfs_da3_join(state);
>> -			if (error)
>> -				goto out;
>> -			error = xfs_defer_finish(&args->trans);
>> -			if (error)
>> -				goto out;
>> +			args->dc.dc_state = XFS_DC_ALLOC_NODE;
>> +			return -EAGAIN;
>>   		}
>>   
>> -		/*
>> -		 * Commit and start the next trans in the chain.
>> -		 */
>> -		error = xfs_trans_roll_inode(&args->trans, dp);
>> +		error = xfs_attr_rmtval_set_value(args);
>>   		if (error)
>> -			goto out;
>> +			return error;
>> +	}
>>   
>> -	} else if (args->rmtblkno > 0) {
>> +	if (args->rmtblkno > 0) {
>>   		/*
>>   		 * Added a "remote" value, just clear the incomplete flag.
>>   		 */
>>   		error = xfs_attr3_leaf_clearflag(args);
>>   		if (error)
>>   			goto out;
>> -
>> -		 /*
>> -		  * Commit the flag value change and start the next trans in
>> -		  * series.
>> -		  */
>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> -		if (error)
>> -			goto out;
>>   	}
>>   	retval = error = 0;
>>   
>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>> index fb8bf5b..c710387 100644
>> --- a/fs/xfs/libxfs/xfs_attr.h
>> +++ b/fs/xfs/libxfs/xfs_attr.h
>> @@ -149,6 +149,7 @@ int xfs_attr_get(struct xfs_inode *ip, struct xfs_name *name,
>>   int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
>>   		 unsigned char *value, int valuelen, int flags);
>>   int xfs_attr_set_args(struct xfs_da_args *args);
>> +int xfs_attr_set_later(struct xfs_da_args *args, struct xfs_buf **leaf_bp);
>>   int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
>>   int xfs_has_attr(struct xfs_da_args *args);
>>   int xfs_attr_remove_args(struct xfs_da_args *args);
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v4 04/17] xfs: Add xfs_dabuf defines
  2019-11-08 19:19   ` Darrick J. Wong
@ 2019-11-09 17:32     ` Allison Collins
  2019-11-09 20:11       ` Darrick J. Wong
  0 siblings, 1 reply; 77+ messages in thread
From: Allison Collins @ 2019-11-09 17:32 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs

On 11/8/19 12:19 PM, Darrick J. Wong wrote:
> On Wed, Nov 06, 2019 at 06:27:48PM -0700, Allison Collins wrote:
>> This patch adds two new defines XFS_DABUF_MAP_NOMAPPING and
>> XFS_DABUF_MAP_HOLE_OK.  This helps to clean up hard numbers and
>> makes the code easier to read
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c       | 14 +++++++-----
>>   fs/xfs/libxfs/xfs_attr_leaf.c  | 23 +++++++++++--------
>>   fs/xfs/libxfs/xfs_attr_leaf.h  |  3 +++
>>   fs/xfs/libxfs/xfs_da_btree.c   | 50 ++++++++++++++++++++++++++++--------------
>>   fs/xfs/libxfs/xfs_dir2_block.c |  6 +++--
>>   fs/xfs/libxfs/xfs_dir2_data.c  |  3 ++-
>>   fs/xfs/libxfs/xfs_dir2_leaf.c  |  9 +++++---
>>   fs/xfs/libxfs/xfs_dir2_node.c  | 10 +++++----
>>   fs/xfs/scrub/dabtree.c         |  6 ++---
>>   fs/xfs/scrub/dir.c             |  4 +++-
>>   fs/xfs/xfs_attr_inactive.c     |  6 +++--
>>   fs/xfs/xfs_attr_list.c         | 16 +++++++++-----
>>   12 files changed, 97 insertions(+), 53 deletions(-)
> 
> <snip>
> 
>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
>> index bb08800..017480e 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.h
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.h
>> @@ -16,6 +16,9 @@ struct xfs_da_state_blk;
>>   struct xfs_inode;
>>   struct xfs_trans;
>>   
>> +#define XFS_DABUF_MAP_NOMAPPING	(-1) /* Caller doesn't have a mapping. */
>> +#define XFS_DABUF_MAP_HOLE_OK	(-2) /* don't complain if we land in a hole. */
> 
> These are parameters to xfs_da_{get,read,reada}_buf, please put them
> next to the declarations for those functions.
Hmm, I dont see that these are declared in a header file, but how about 
fs/xfs/libxfs/xfs_da_btree.h ?  Did I miss them somewhere?

Allison


> 
> Also they probably ought to be explicitly cast to xfs_daddr_t, e.g.
> 
> /* Force a fresh lookup for the dir/attr mapping. */
> #define XFS_DABUF_MAP_NOMAPPING	((xfs_daddr_t)-1)
> 
> /* Don't complain if we land in a hole. */
> #define XFS_DABUF_MAP_HOLE_OK	((xfs_daddr_t)-2)
> 
>> +
>>   /*
>>    * Used to keep a list of "remote value" extents when unlinking an inode.
>>    */
> 
> <snip>
> 
>> diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
>> index 8dedc30..6bc7651 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_block.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_block.c
>> @@ -20,6 +20,7 @@
>>   #include "xfs_error.h"
>>   #include "xfs_trace.h"
>>   #include "xfs_log.h"
>> +#include "xfs_attr_leaf.h"
>>   
>>   /*
>>    * Local function prototypes.
>> @@ -123,8 +124,9 @@ xfs_dir3_block_read(
>>   	struct xfs_mount	*mp = dp->i_mount;
>>   	int			err;
>>   
>> -	err = xfs_da_read_buf(tp, dp, mp->m_dir_geo->datablk, -1, bpp,
>> -				XFS_DATA_FORK, &xfs_dir3_block_buf_ops);
>> +	err = xfs_da_read_buf(tp, dp, mp->m_dir_geo->datablk,
>> +			      XFS_DABUF_MAP_NOMAPPING, bpp, XFS_DATA_FORK,
>> +			      &xfs_dir3_block_buf_ops);
>>   	if (!err && tp && *bpp)
>>   		xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_BLOCK_BUF);
>>   	return err;
> 
> I think this misses the xfs_dir3_data_read call in
> xfs_dir2_leaf_to_block?
> 
>> diff --git a/fs/xfs/libxfs/xfs_dir2_data.c b/fs/xfs/libxfs/xfs_dir2_data.c
>> index 2c79be4..a4188de 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_data.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_data.c
>> @@ -17,6 +17,7 @@
>>   #include "xfs_trans.h"
>>   #include "xfs_buf_item.h"
>>   #include "xfs_log.h"
>> +#include "xfs_attr_leaf.h"
>>   
>>   static xfs_failaddr_t xfs_dir2_data_freefind_verify(
>>   		struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_data_free *bf,
>> @@ -653,7 +654,7 @@ xfs_dir3_data_init(
>>   	 * Get the buffer set up for the block.
>>   	 */
>>   	error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, blkno),
>> -			       -1, &bp, XFS_DATA_FORK);
>> +			       XFS_DABUF_MAP_NOMAPPING, &bp, XFS_DATA_FORK);
>>   	if (error)
>>   		return error;
>>   	bp->b_ops = &xfs_dir3_data_buf_ops;
>> diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
>> index b7046e2..a2cba6bd 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
>> @@ -19,6 +19,7 @@
>>   #include "xfs_trace.h"
>>   #include "xfs_trans.h"
>>   #include "xfs_buf_item.h"
>> +#include "xfs_attr_leaf.h"
>>   
>>   /*
>>    * Local function declarations.
>> @@ -311,7 +312,7 @@ xfs_dir3_leaf_get_buf(
>>   	       bno < xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET));
>>   
>>   	error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, bno),
>> -			       -1, &bp, XFS_DATA_FORK);
>> +			       XFS_DABUF_MAP_NOMAPPING, &bp, XFS_DATA_FORK);
>>   	if (error)
>>   		return error;
>>   
>> @@ -594,7 +595,8 @@ xfs_dir2_leaf_addname(
>>   
>>   	trace_xfs_dir2_leaf_addname(args);
>>   
>> -	error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, -1, &lbp);
>> +	error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk,
>> +				   XFS_DABUF_MAP_NOMAPPING, &lbp);
>>   	if (error)
>>   		return error;
>>   
> 
> I think there are some missing conversions for xfs_dir3_data_read calls
> in xfs_dir2_leaf_addname...
> 
>> @@ -1189,7 +1191,8 @@ xfs_dir2_leaf_lookup_int(
>>   	tp = args->trans;
>>   	mp = dp->i_mount;
>>   
>> -	error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, -1, &lbp);
>> +	error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk,
>> +				   XFS_DABUF_MAP_NOMAPPING, &lbp);
>>   	if (error)
>>   		return error;
>>   
> 
> ...and two more dir3_leaf_read calls further down in this function...
> 
> ...and one more in xfs_dir2_leaf_trim_data...
> 
>> diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
>> index 8bbd742..0a803e4 100644
>> --- a/fs/xfs/libxfs/xfs_dir2_node.c
>> +++ b/fs/xfs/libxfs/xfs_dir2_node.c
>> @@ -20,6 +20,7 @@
>>   #include "xfs_trans.h"
>>   #include "xfs_buf_item.h"
>>   #include "xfs_log.h"
>> +#include "xfs_attr_leaf.h"
>>   
>>   /*
>>    * Function declarations.
>> @@ -227,7 +228,7 @@ xfs_dir2_free_read(
>>   	xfs_dablk_t		fbno,
>>   	struct xfs_buf		**bpp)
>>   {
>> -	return __xfs_dir3_free_read(tp, dp, fbno, -1, bpp);
>> +	return __xfs_dir3_free_read(tp, dp, fbno, XFS_DABUF_MAP_NOMAPPING, bpp);
>>   }
>>   
>>   static int
>> @@ -237,7 +238,7 @@ xfs_dir2_free_try_read(
>>   	xfs_dablk_t		fbno,
>>   	struct xfs_buf		**bpp)
>>   {
>> -	return __xfs_dir3_free_read(tp, dp, fbno, -2, bpp);
>> +	return __xfs_dir3_free_read(tp, dp, fbno, XFS_DABUF_MAP_HOLE_OK, bpp);
>>   }
>>   
>>   static int
>> @@ -254,7 +255,7 @@ xfs_dir3_free_get_buf(
>>   	struct xfs_dir3_icfree_hdr hdr;
>>   
>>   	error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, fbno),
>> -				   -1, &bp, XFS_DATA_FORK);
>> +				   XFS_DABUF_MAP_NOMAPPING, &bp, XFS_DATA_FORK);
>>   	if (error)
>>   		return error;
>>   
> 
> ...there's also a missing call in xfs_dir2_leafn_lookup_for_entry...
> 
>> @@ -1495,7 +1496,8 @@ xfs_dir2_leafn_toosmall(
>>   		 * Read the sibling leaf block.
>>   		 */
>>   		error = xfs_dir3_leafn_read(state->args->trans, dp,
>> -					    blkno, -1, &bp);
>> +					    blkno, XFS_DABUF_MAP_NOMAPPING,
>> +					    &bp);
>>   		if (error)
>>   			return error;
>>   
> 
> ...and another one in xfs_dir2_node_addname_int.
> 
>> diff --git a/fs/xfs/scrub/dabtree.c b/fs/xfs/scrub/dabtree.c
>> index 77ff9f9..353455c 100644
>> --- a/fs/xfs/scrub/dabtree.c
>> +++ b/fs/xfs/scrub/dabtree.c
>> @@ -355,9 +355,9 @@ xchk_da_btree_block(
>>   		goto out_nobuf;
>>   
>>   	/* Read the buffer. */
>> -	error = xfs_da_read_buf(dargs->trans, dargs->dp, blk->blkno, -2,
>> -			&blk->bp, dargs->whichfork,
>> -			&xchk_da_btree_buf_ops);
>> +	error = xfs_da_read_buf(dargs->trans, dargs->dp, blk->blkno,
>> +				XFS_DABUF_MAP_HOLE_OK, &blk->bp,
>> +				dargs->whichfork, &xchk_da_btree_buf_ops);
>>   	if (!xchk_da_process_error(ds, level, &error))
>>   		goto out_nobuf;
>>   	if (blk->bp)
>> diff --git a/fs/xfs/scrub/dir.c b/fs/xfs/scrub/dir.c
>> index 1e2e117..eb0fa0f 100644
>> --- a/fs/xfs/scrub/dir.c
>> +++ b/fs/xfs/scrub/dir.c
>> @@ -18,6 +18,7 @@
>>   #include "scrub/scrub.h"
>>   #include "scrub/common.h"
>>   #include "scrub/dabtree.h"
>> +#include "xfs_attr_leaf.h"
>>   
>>   /* Set us up to scrub directories. */
>>   int
> 
> I also noticed missing conversions for xfs_dir3_data_read in
> xchk_dir_rec, xchk_directory_data_bestfree,
> xchk_directory_leaf1_bestfree, and xchk_directory_free_bestfree.
> 
>> @@ -492,7 +493,8 @@ xchk_directory_leaf1_bestfree(
>>   	int				error;
>>   
>>   	/* Read the free space block. */
>> -	error = xfs_dir3_leaf_read(sc->tp, sc->ip, lblk, -1, &bp);
>> +	error = xfs_dir3_leaf_read(sc->tp, sc->ip, lblk,
>> +				   XFS_DABUF_MAP_NOMAPPING, &bp);
>>   	if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))
>>   		goto out;
>>   	xchk_buffer_recheck(sc, bp);
> 
> There's also a missing xfs_dir3_data_readahead conversion in
> xchk_parent_count_parent_dentries in fs/xfs/scrub/parent.c.
> 
>> diff --git a/fs/xfs/xfs_attr_inactive.c b/fs/xfs/xfs_attr_inactive.c
>> index f83f11d..9c22915 100644
>> --- a/fs/xfs/xfs_attr_inactive.c
>> +++ b/fs/xfs/xfs_attr_inactive.c
>> @@ -235,7 +235,8 @@ xfs_attr3_node_inactive(
>>   		 * traversal of the tree so we may deal with many blocks
>>   		 * before we come back to this one.
>>   		 */
>> -		error = xfs_da3_node_read(*trans, dp, child_fsb, -1, &child_bp,
>> +		error = xfs_da3_node_read(*trans, dp, child_fsb,
>> +					  XFS_DABUF_MAP_NOMAPPING, &child_bp,
>>   					  XFS_ATTR_FORK);
>>   		if (error)
>>   			return error;
>> @@ -321,7 +322,8 @@ xfs_attr3_root_inactive(
>>   	 * the extents in reverse order the extent containing
>>   	 * block 0 must still be there.
>>   	 */
>> -	error = xfs_da3_node_read(*trans, dp, 0, -1, &bp, XFS_ATTR_FORK);
>> +	error = xfs_da3_node_read(*trans, dp, 0, XFS_DABUF_MAP_NOMAPPING, &bp,
>> +				  XFS_ATTR_FORK);
>>   	if (error)
>>   		return error;
>>   	blkno = bp->b_bn;
>> diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
>> index c02f22d..fab416c 100644
>> --- a/fs/xfs/xfs_attr_list.c
>> +++ b/fs/xfs/xfs_attr_list.c
>> @@ -224,8 +224,9 @@ xfs_attr_node_list_lookup(
>>   	ASSERT(*pbp == NULL);
>>   	cursor->blkno = 0;
>>   	for (;;) {
>> -		error = xfs_da3_node_read(tp, dp, cursor->blkno, -1, &bp,
>> -				XFS_ATTR_FORK);
>> +		error = xfs_da3_node_read(tp, dp, cursor->blkno,
>> +					  XFS_DABUF_MAP_NOMAPPING, &bp,
>> +					  XFS_ATTR_FORK);
>>   		if (error)
>>   			return error;
>>   		node = bp->b_addr;
>> @@ -309,8 +310,9 @@ xfs_attr_node_list(
>>   	 */
>>   	bp = NULL;
>>   	if (cursor->blkno > 0) {
>> -		error = xfs_da3_node_read(context->tp, dp, cursor->blkno, -1,
>> -					      &bp, XFS_ATTR_FORK);
>> +		error = xfs_da3_node_read(context->tp, dp, cursor->blkno,
>> +					  XFS_DABUF_MAP_NOMAPPING, &bp,
>> +					  XFS_ATTR_FORK);
>>   		if ((error != 0) && (error != -EFSCORRUPTED))
>>   			return error;
>>   		if (bp) {
>> @@ -377,7 +379,8 @@ xfs_attr_node_list(
>>   			break;
>>   		cursor->blkno = leafhdr.forw;
>>   		xfs_trans_brelse(context->tp, bp);
>> -		error = xfs_attr3_leaf_read(context->tp, dp, cursor->blkno, -1, &bp);
>> +		error = xfs_attr3_leaf_read(context->tp, dp, cursor->blkno,
>> +					    XFS_DABUF_MAP_NOMAPPING, &bp);
>>   		if (error)
>>   			return error;
>>   	}
>> @@ -497,7 +500,8 @@ xfs_attr_leaf_list(xfs_attr_list_context_t *context)
>>   	trace_xfs_attr_leaf_list(context);
>>   
>>   	context->cursor->blkno = 0;
>> -	error = xfs_attr3_leaf_read(context->tp, context->dp, 0, -1, &bp);
>> +	error = xfs_attr3_leaf_read(context->tp, context->dp, 0,
>> +				    XFS_DABUF_MAP_NOMAPPING, &bp);
>>   	if (error)
>>   		return error;
>>   
> 
> ...more missing conversions of xfs_dir3_data_read in
> xfs_dir2_leaf_readbuf; and of xfs_dir3_data_readahead in
> xfs_dir2_leaf_readbuf...
> 
> ...and a missing conversion of xfs_dir3_data_readahead in xfs_dir_open
> in fs/xfs/xfs_file.c.
> 
> --D
> 
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v4 04/17] xfs: Add xfs_dabuf defines
  2019-11-09 17:32     ` Allison Collins
@ 2019-11-09 20:11       ` Darrick J. Wong
  2019-11-09 22:06         ` Allison Collins
  0 siblings, 1 reply; 77+ messages in thread
From: Darrick J. Wong @ 2019-11-09 20:11 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Sat, Nov 09, 2019 at 10:32:17AM -0700, Allison Collins wrote:
> On 11/8/19 12:19 PM, Darrick J. Wong wrote:
> > On Wed, Nov 06, 2019 at 06:27:48PM -0700, Allison Collins wrote:
> > > This patch adds two new defines XFS_DABUF_MAP_NOMAPPING and
> > > XFS_DABUF_MAP_HOLE_OK.  This helps to clean up hard numbers and
> > > makes the code easier to read
> > > 
> > > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > > ---
> > >   fs/xfs/libxfs/xfs_attr.c       | 14 +++++++-----
> > >   fs/xfs/libxfs/xfs_attr_leaf.c  | 23 +++++++++++--------
> > >   fs/xfs/libxfs/xfs_attr_leaf.h  |  3 +++
> > >   fs/xfs/libxfs/xfs_da_btree.c   | 50 ++++++++++++++++++++++++++++--------------
> > >   fs/xfs/libxfs/xfs_dir2_block.c |  6 +++--
> > >   fs/xfs/libxfs/xfs_dir2_data.c  |  3 ++-
> > >   fs/xfs/libxfs/xfs_dir2_leaf.c  |  9 +++++---
> > >   fs/xfs/libxfs/xfs_dir2_node.c  | 10 +++++----
> > >   fs/xfs/scrub/dabtree.c         |  6 ++---
> > >   fs/xfs/scrub/dir.c             |  4 +++-
> > >   fs/xfs/xfs_attr_inactive.c     |  6 +++--
> > >   fs/xfs/xfs_attr_list.c         | 16 +++++++++-----
> > >   12 files changed, 97 insertions(+), 53 deletions(-)
> > 
> > <snip>
> > 
> > > diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
> > > index bb08800..017480e 100644
> > > --- a/fs/xfs/libxfs/xfs_attr_leaf.h
> > > +++ b/fs/xfs/libxfs/xfs_attr_leaf.h
> > > @@ -16,6 +16,9 @@ struct xfs_da_state_blk;
> > >   struct xfs_inode;
> > >   struct xfs_trans;
> > > +#define XFS_DABUF_MAP_NOMAPPING	(-1) /* Caller doesn't have a mapping. */
> > > +#define XFS_DABUF_MAP_HOLE_OK	(-2) /* don't complain if we land in a hole. */
> > 
> > These are parameters to xfs_da_{get,read,reada}_buf, please put them
> > next to the declarations for those functions.
> Hmm, I dont see that these are declared in a header file, but how about
> fs/xfs/libxfs/xfs_da_btree.h ?  Did I miss them somewhere?

They should be declared around line 200 in that very file.

--D

> Allison
> 
> 
> > 
> > Also they probably ought to be explicitly cast to xfs_daddr_t, e.g.
> > 
> > /* Force a fresh lookup for the dir/attr mapping. */
> > #define XFS_DABUF_MAP_NOMAPPING	((xfs_daddr_t)-1)
> > 
> > /* Don't complain if we land in a hole. */
> > #define XFS_DABUF_MAP_HOLE_OK	((xfs_daddr_t)-2)
> > 
> > > +
> > >   /*
> > >    * Used to keep a list of "remote value" extents when unlinking an inode.
> > >    */
> > 
> > <snip>
> > 
> > > diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
> > > index 8dedc30..6bc7651 100644
> > > --- a/fs/xfs/libxfs/xfs_dir2_block.c
> > > +++ b/fs/xfs/libxfs/xfs_dir2_block.c
> > > @@ -20,6 +20,7 @@
> > >   #include "xfs_error.h"
> > >   #include "xfs_trace.h"
> > >   #include "xfs_log.h"
> > > +#include "xfs_attr_leaf.h"
> > >   /*
> > >    * Local function prototypes.
> > > @@ -123,8 +124,9 @@ xfs_dir3_block_read(
> > >   	struct xfs_mount	*mp = dp->i_mount;
> > >   	int			err;
> > > -	err = xfs_da_read_buf(tp, dp, mp->m_dir_geo->datablk, -1, bpp,
> > > -				XFS_DATA_FORK, &xfs_dir3_block_buf_ops);
> > > +	err = xfs_da_read_buf(tp, dp, mp->m_dir_geo->datablk,
> > > +			      XFS_DABUF_MAP_NOMAPPING, bpp, XFS_DATA_FORK,
> > > +			      &xfs_dir3_block_buf_ops);
> > >   	if (!err && tp && *bpp)
> > >   		xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_BLOCK_BUF);
> > >   	return err;
> > 
> > I think this misses the xfs_dir3_data_read call in
> > xfs_dir2_leaf_to_block?
> > 
> > > diff --git a/fs/xfs/libxfs/xfs_dir2_data.c b/fs/xfs/libxfs/xfs_dir2_data.c
> > > index 2c79be4..a4188de 100644
> > > --- a/fs/xfs/libxfs/xfs_dir2_data.c
> > > +++ b/fs/xfs/libxfs/xfs_dir2_data.c
> > > @@ -17,6 +17,7 @@
> > >   #include "xfs_trans.h"
> > >   #include "xfs_buf_item.h"
> > >   #include "xfs_log.h"
> > > +#include "xfs_attr_leaf.h"
> > >   static xfs_failaddr_t xfs_dir2_data_freefind_verify(
> > >   		struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_data_free *bf,
> > > @@ -653,7 +654,7 @@ xfs_dir3_data_init(
> > >   	 * Get the buffer set up for the block.
> > >   	 */
> > >   	error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, blkno),
> > > -			       -1, &bp, XFS_DATA_FORK);
> > > +			       XFS_DABUF_MAP_NOMAPPING, &bp, XFS_DATA_FORK);
> > >   	if (error)
> > >   		return error;
> > >   	bp->b_ops = &xfs_dir3_data_buf_ops;
> > > diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
> > > index b7046e2..a2cba6bd 100644
> > > --- a/fs/xfs/libxfs/xfs_dir2_leaf.c
> > > +++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
> > > @@ -19,6 +19,7 @@
> > >   #include "xfs_trace.h"
> > >   #include "xfs_trans.h"
> > >   #include "xfs_buf_item.h"
> > > +#include "xfs_attr_leaf.h"
> > >   /*
> > >    * Local function declarations.
> > > @@ -311,7 +312,7 @@ xfs_dir3_leaf_get_buf(
> > >   	       bno < xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET));
> > >   	error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, bno),
> > > -			       -1, &bp, XFS_DATA_FORK);
> > > +			       XFS_DABUF_MAP_NOMAPPING, &bp, XFS_DATA_FORK);
> > >   	if (error)
> > >   		return error;
> > > @@ -594,7 +595,8 @@ xfs_dir2_leaf_addname(
> > >   	trace_xfs_dir2_leaf_addname(args);
> > > -	error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, -1, &lbp);
> > > +	error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk,
> > > +				   XFS_DABUF_MAP_NOMAPPING, &lbp);
> > >   	if (error)
> > >   		return error;
> > 
> > I think there are some missing conversions for xfs_dir3_data_read calls
> > in xfs_dir2_leaf_addname...
> > 
> > > @@ -1189,7 +1191,8 @@ xfs_dir2_leaf_lookup_int(
> > >   	tp = args->trans;
> > >   	mp = dp->i_mount;
> > > -	error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, -1, &lbp);
> > > +	error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk,
> > > +				   XFS_DABUF_MAP_NOMAPPING, &lbp);
> > >   	if (error)
> > >   		return error;
> > 
> > ...and two more dir3_leaf_read calls further down in this function...
> > 
> > ...and one more in xfs_dir2_leaf_trim_data...
> > 
> > > diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
> > > index 8bbd742..0a803e4 100644
> > > --- a/fs/xfs/libxfs/xfs_dir2_node.c
> > > +++ b/fs/xfs/libxfs/xfs_dir2_node.c
> > > @@ -20,6 +20,7 @@
> > >   #include "xfs_trans.h"
> > >   #include "xfs_buf_item.h"
> > >   #include "xfs_log.h"
> > > +#include "xfs_attr_leaf.h"
> > >   /*
> > >    * Function declarations.
> > > @@ -227,7 +228,7 @@ xfs_dir2_free_read(
> > >   	xfs_dablk_t		fbno,
> > >   	struct xfs_buf		**bpp)
> > >   {
> > > -	return __xfs_dir3_free_read(tp, dp, fbno, -1, bpp);
> > > +	return __xfs_dir3_free_read(tp, dp, fbno, XFS_DABUF_MAP_NOMAPPING, bpp);
> > >   }
> > >   static int
> > > @@ -237,7 +238,7 @@ xfs_dir2_free_try_read(
> > >   	xfs_dablk_t		fbno,
> > >   	struct xfs_buf		**bpp)
> > >   {
> > > -	return __xfs_dir3_free_read(tp, dp, fbno, -2, bpp);
> > > +	return __xfs_dir3_free_read(tp, dp, fbno, XFS_DABUF_MAP_HOLE_OK, bpp);
> > >   }
> > >   static int
> > > @@ -254,7 +255,7 @@ xfs_dir3_free_get_buf(
> > >   	struct xfs_dir3_icfree_hdr hdr;
> > >   	error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, fbno),
> > > -				   -1, &bp, XFS_DATA_FORK);
> > > +				   XFS_DABUF_MAP_NOMAPPING, &bp, XFS_DATA_FORK);
> > >   	if (error)
> > >   		return error;
> > 
> > ...there's also a missing call in xfs_dir2_leafn_lookup_for_entry...
> > 
> > > @@ -1495,7 +1496,8 @@ xfs_dir2_leafn_toosmall(
> > >   		 * Read the sibling leaf block.
> > >   		 */
> > >   		error = xfs_dir3_leafn_read(state->args->trans, dp,
> > > -					    blkno, -1, &bp);
> > > +					    blkno, XFS_DABUF_MAP_NOMAPPING,
> > > +					    &bp);
> > >   		if (error)
> > >   			return error;
> > 
> > ...and another one in xfs_dir2_node_addname_int.
> > 
> > > diff --git a/fs/xfs/scrub/dabtree.c b/fs/xfs/scrub/dabtree.c
> > > index 77ff9f9..353455c 100644
> > > --- a/fs/xfs/scrub/dabtree.c
> > > +++ b/fs/xfs/scrub/dabtree.c
> > > @@ -355,9 +355,9 @@ xchk_da_btree_block(
> > >   		goto out_nobuf;
> > >   	/* Read the buffer. */
> > > -	error = xfs_da_read_buf(dargs->trans, dargs->dp, blk->blkno, -2,
> > > -			&blk->bp, dargs->whichfork,
> > > -			&xchk_da_btree_buf_ops);
> > > +	error = xfs_da_read_buf(dargs->trans, dargs->dp, blk->blkno,
> > > +				XFS_DABUF_MAP_HOLE_OK, &blk->bp,
> > > +				dargs->whichfork, &xchk_da_btree_buf_ops);
> > >   	if (!xchk_da_process_error(ds, level, &error))
> > >   		goto out_nobuf;
> > >   	if (blk->bp)
> > > diff --git a/fs/xfs/scrub/dir.c b/fs/xfs/scrub/dir.c
> > > index 1e2e117..eb0fa0f 100644
> > > --- a/fs/xfs/scrub/dir.c
> > > +++ b/fs/xfs/scrub/dir.c
> > > @@ -18,6 +18,7 @@
> > >   #include "scrub/scrub.h"
> > >   #include "scrub/common.h"
> > >   #include "scrub/dabtree.h"
> > > +#include "xfs_attr_leaf.h"
> > >   /* Set us up to scrub directories. */
> > >   int
> > 
> > I also noticed missing conversions for xfs_dir3_data_read in
> > xchk_dir_rec, xchk_directory_data_bestfree,
> > xchk_directory_leaf1_bestfree, and xchk_directory_free_bestfree.
> > 
> > > @@ -492,7 +493,8 @@ xchk_directory_leaf1_bestfree(
> > >   	int				error;
> > >   	/* Read the free space block. */
> > > -	error = xfs_dir3_leaf_read(sc->tp, sc->ip, lblk, -1, &bp);
> > > +	error = xfs_dir3_leaf_read(sc->tp, sc->ip, lblk,
> > > +				   XFS_DABUF_MAP_NOMAPPING, &bp);
> > >   	if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))
> > >   		goto out;
> > >   	xchk_buffer_recheck(sc, bp);
> > 
> > There's also a missing xfs_dir3_data_readahead conversion in
> > xchk_parent_count_parent_dentries in fs/xfs/scrub/parent.c.
> > 
> > > diff --git a/fs/xfs/xfs_attr_inactive.c b/fs/xfs/xfs_attr_inactive.c
> > > index f83f11d..9c22915 100644
> > > --- a/fs/xfs/xfs_attr_inactive.c
> > > +++ b/fs/xfs/xfs_attr_inactive.c
> > > @@ -235,7 +235,8 @@ xfs_attr3_node_inactive(
> > >   		 * traversal of the tree so we may deal with many blocks
> > >   		 * before we come back to this one.
> > >   		 */
> > > -		error = xfs_da3_node_read(*trans, dp, child_fsb, -1, &child_bp,
> > > +		error = xfs_da3_node_read(*trans, dp, child_fsb,
> > > +					  XFS_DABUF_MAP_NOMAPPING, &child_bp,
> > >   					  XFS_ATTR_FORK);
> > >   		if (error)
> > >   			return error;
> > > @@ -321,7 +322,8 @@ xfs_attr3_root_inactive(
> > >   	 * the extents in reverse order the extent containing
> > >   	 * block 0 must still be there.
> > >   	 */
> > > -	error = xfs_da3_node_read(*trans, dp, 0, -1, &bp, XFS_ATTR_FORK);
> > > +	error = xfs_da3_node_read(*trans, dp, 0, XFS_DABUF_MAP_NOMAPPING, &bp,
> > > +				  XFS_ATTR_FORK);
> > >   	if (error)
> > >   		return error;
> > >   	blkno = bp->b_bn;
> > > diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
> > > index c02f22d..fab416c 100644
> > > --- a/fs/xfs/xfs_attr_list.c
> > > +++ b/fs/xfs/xfs_attr_list.c
> > > @@ -224,8 +224,9 @@ xfs_attr_node_list_lookup(
> > >   	ASSERT(*pbp == NULL);
> > >   	cursor->blkno = 0;
> > >   	for (;;) {
> > > -		error = xfs_da3_node_read(tp, dp, cursor->blkno, -1, &bp,
> > > -				XFS_ATTR_FORK);
> > > +		error = xfs_da3_node_read(tp, dp, cursor->blkno,
> > > +					  XFS_DABUF_MAP_NOMAPPING, &bp,
> > > +					  XFS_ATTR_FORK);
> > >   		if (error)
> > >   			return error;
> > >   		node = bp->b_addr;
> > > @@ -309,8 +310,9 @@ xfs_attr_node_list(
> > >   	 */
> > >   	bp = NULL;
> > >   	if (cursor->blkno > 0) {
> > > -		error = xfs_da3_node_read(context->tp, dp, cursor->blkno, -1,
> > > -					      &bp, XFS_ATTR_FORK);
> > > +		error = xfs_da3_node_read(context->tp, dp, cursor->blkno,
> > > +					  XFS_DABUF_MAP_NOMAPPING, &bp,
> > > +					  XFS_ATTR_FORK);
> > >   		if ((error != 0) && (error != -EFSCORRUPTED))
> > >   			return error;
> > >   		if (bp) {
> > > @@ -377,7 +379,8 @@ xfs_attr_node_list(
> > >   			break;
> > >   		cursor->blkno = leafhdr.forw;
> > >   		xfs_trans_brelse(context->tp, bp);
> > > -		error = xfs_attr3_leaf_read(context->tp, dp, cursor->blkno, -1, &bp);
> > > +		error = xfs_attr3_leaf_read(context->tp, dp, cursor->blkno,
> > > +					    XFS_DABUF_MAP_NOMAPPING, &bp);
> > >   		if (error)
> > >   			return error;
> > >   	}
> > > @@ -497,7 +500,8 @@ xfs_attr_leaf_list(xfs_attr_list_context_t *context)
> > >   	trace_xfs_attr_leaf_list(context);
> > >   	context->cursor->blkno = 0;
> > > -	error = xfs_attr3_leaf_read(context->tp, context->dp, 0, -1, &bp);
> > > +	error = xfs_attr3_leaf_read(context->tp, context->dp, 0,
> > > +				    XFS_DABUF_MAP_NOMAPPING, &bp);
> > >   	if (error)
> > >   		return error;
> > 
> > ...more missing conversions of xfs_dir3_data_read in
> > xfs_dir2_leaf_readbuf; and of xfs_dir3_data_readahead in
> > xfs_dir2_leaf_readbuf...
> > 
> > ...and a missing conversion of xfs_dir3_data_readahead in xfs_dir_open
> > in fs/xfs/xfs_file.c.
> > 
> > --D
> > 
> > > -- 
> > > 2.7.4
> > > 

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

* Re: [PATCH v4 08/17] xfs: Factor out xfs_attr_leaf_addname helper
  2019-11-08 20:57   ` Darrick J. Wong
@ 2019-11-09 21:41     ` Allison Collins
  0 siblings, 0 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-09 21:41 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 11/8/19 1:57 PM, Darrick J. Wong wrote:
> On Wed, Nov 06, 2019 at 06:27:52PM -0700, Allison Collins wrote:
>> Factor out new helper function xfs_attr_leaf_try_add.
>> Because new delayed attribute routines cannot roll
>> transactions, we carve off the parts of
>> xfs_attr_leaf_addname that we can use.  This will help
>> to reduce repetitive code later when we introduce
>> delayed attributes.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 84 +++++++++++++++++++++++++++++-------------------
>>   1 file changed, 51 insertions(+), 33 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 212995f..dda2eba 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -305,10 +305,33 @@ xfs_attr_set_args(
>>   		}
>>   	}
>>   
>> -	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK))
>> +	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>>   		error = xfs_attr_leaf_addname(args);
>> -	else
>> +		if (error == -ENOSPC) {
>> +			/*
>> +			 * Commit that transaction so that the node_addname()
>> +			 * call can manage its own transactions.
>> +			 */
>> +			error = xfs_defer_finish(&args->trans);
>> +			if (error)
>> +				return error;
>> +
>> +			/*
>> +			 * Commit the current trans (including the inode) and
>> +			 * start a new one.
>> +			 */
>> +			error = xfs_trans_roll_inode(&args->trans, dp);
>> +			if (error)
>> +				return error;
>> +
>> +			/*
>> +			 * Fob the rest of the problem off on the Btree code.
>> +			 */
>> +			error = xfs_attr_node_addname(args);
>> +		}
>> +	} else {
>>   		error = xfs_attr_node_addname(args);
>> +	}
>>   	return error;
> 
> 
>>   }
>>   
>> @@ -601,21 +624,12 @@ xfs_attr_shortform_addname(xfs_da_args_t *args)
>>    * External routines when attribute list is one block
>>    *========================================================================*/
>>   
>> -/*
>> - * Add a name to the leaf attribute list structure
>> - *
>> - * This leaf block cannot have a "remote" value, we only call this routine
>> - * if bmap_one_block() says there is only one block (ie: no remote blks).
>> - */
>>   STATIC int
>> -xfs_attr_leaf_addname(
>> -	struct xfs_da_args	*args)
>> +xfs_attr_leaf_try_add(
> 
> (total stream of consciousness here...)
> 
> AFAICT the old _addname function's responsibilities were:
> 
> 1 Try to add a new attr key entry to the leaf block, with INCOMPLETE set
>    if it's a rename op or we need to set a remote value.
> 2 If there wasn't space in the leaf block, convert to node format, call
>    the node version of this function, and exit.
> 3 Allocating blocks for the remote attr value and writing them, if
>    applicable
> 4 If it's a rename operation, clearing the INCOMPLETE flag on the new
>    entry; setting it on the old entry; and then removing the old entry.
> 5 Clearing the INCOMPLETE flag on the new entry when we're done writing
>    a remote value (if applicable)
> 
> I think we arrive at this split so that we don't have a transaction roll
> in the middle of the function, right?  And also to make the "convert to
> node format and roll" bits go elsewhere?
> 
> The way I'm thinking about how to accomplish this is...
> 
> xfs_attr_leaf_addname should be renamed xfs_attr_leaf_setname, and then
> hoist (1) into a separate function, move (2) into xfs_attr_set_args, and
> hoist (4) into a separate function.
> 
> ...ok, so let's test how closely my understanding fits the changes made
> in this patch:
> 
> _try_add is basically (1).
> 
> Most of (2) happened, though the call to xfs_attr3_leaf_to_node ought to
> go into the caller so that the conversion stays with the defer_finish
> and roll.
> 
> (4) could still be done, maybe as a separate prep patch.
> 

I think you're on the right track.  Perhaps the diff made it look a 
little crazier than it seems. Maybe its easier to describe it as this:

I renamed xfs_attr_leaf_addname to xfs_attr_leaf_try_add,
and then deleted (2) out of the body of the function.  The upper half 
(1) became the helper function, and lower half (3, 4, and 5) became the 
new xfs_attr_leaf_addname, which now calls the helper at the start of 
the routine. Finally (2) got factored up into the caller.

Hope that helps some :-)  The point of all this being to jigsaw out (1) 
into a stand alone routine that we can use later in delayed attrs.


> Hm, ok, I think I understand what this patch does.  The call site in
> xfs_attr_set_args would be clearer (and less indenty) if it looked like:
> 
> 	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> 		error = xfs_attr_leaf_addname(args);
> 		if (error == 0 || error != -ENOSPC)
> 			return error;
> 
> 		/* Promote the attribute list to node format. */
> 		error = xfs_attr3_leaf_to_node(args);
> 		if (error)
> 			return error;
I think this part here is already taken care of in 
xfs_attr_leaf_addname, but otherwise, I think the rest of this is 
equivalent.  Will update in the next set.

Thanks for the reviews!
Allison



> 
> 		/*
> 		 * Commit that transaction so that the node_addname()
> 		 * call can manage its own transactions.
> 		 */
> 		error = xfs_defer_finish(&args->trans);
> 		if (error)
> 			return error;
> 
> 		/*
> 		 * Commit the current trans (including the inode) and
> 		 * start a new one.
> 		 */
> 		error = xfs_trans_roll_inode(&args->trans, dp);
> 		if (error)
> 			return error;
> 	}
> 
> 	return xfs_attr_node_addname(args);
> 
> But otherwise it looks decent, assuming I understood any of it. :)
> 
> --D
> 
>> +	struct xfs_da_args	*args,
>> +	struct xfs_buf		*bp)
>>   {
>> -	struct xfs_buf		*bp;
>> -	int			retval, error, forkoff;
>> -	struct xfs_inode	*dp = args->dp;
>> -
>> -	trace_xfs_attr_leaf_addname(args);
>> +	int			retval, error;
>>   
>>   	/*
>>   	 * Look up the given attribute in the leaf block.  Figure out if
>> @@ -661,31 +675,35 @@ xfs_attr_leaf_addname(
>>   	retval = xfs_attr3_leaf_add(bp, args);
>>   	if (retval == -ENOSPC) {
>>   		/*
>> -		 * Promote the attribute list to the Btree format, then
>> -		 * Commit that transaction so that the node_addname() call
>> -		 * can manage its own transactions.
>> +		 * Promote the attribute list to the Btree format.
>> +		 * Unless an error occurs, retain the -ENOSPC retval
>>   		 */
>>   		error = xfs_attr3_leaf_to_node(args);
>>   		if (error)
>>   			return error;
>> -		error = xfs_defer_finish(&args->trans);
>> -		if (error)
>> -			return error;
>> +	}
>> +	return retval;
>> +}
>>   
>> -		/*
>> -		 * Commit the current trans (including the inode) and start
>> -		 * a new one.
>> -		 */
>> -		error = xfs_trans_roll_inode(&args->trans, dp);
>> -		if (error)
>> -			return error;
>>   
>> -		/*
>> -		 * Fob the whole rest of the problem off on the Btree code.
>> -		 */
>> -		error = xfs_attr_node_addname(args);
>> +/*
>> + * Add a name to the leaf attribute list structure
>> + *
>> + * This leaf block cannot have a "remote" value, we only call this routine
>> + * if bmap_one_block() says there is only one block (ie: no remote blks).
>> + */
>> +STATIC int
>> +xfs_attr_leaf_addname(struct xfs_da_args	*args)
>> +{
>> +	int			error, forkoff;
>> +	struct xfs_buf		*bp = NULL;
>> +	struct xfs_inode	*dp = args->dp;
>> +
>> +	trace_xfs_attr_leaf_addname(args);
>> +
>> +	error = xfs_attr_leaf_try_add(args, bp);
>> +	if (error)
>>   		return error;
>> -	}
>>   
>>   	/*
>>   	 * Commit the transaction that added the attr name so that
>> -- 
>> 2.7.4
>>

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

* Re: [PATCH v4 04/17] xfs: Add xfs_dabuf defines
  2019-11-09 20:11       ` Darrick J. Wong
@ 2019-11-09 22:06         ` Allison Collins
  0 siblings, 0 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-09 22:06 UTC (permalink / raw)
  To: Darrick J. Wong; +Cc: linux-xfs



On 11/9/19 1:11 PM, Darrick J. Wong wrote:
> On Sat, Nov 09, 2019 at 10:32:17AM -0700, Allison Collins wrote:
>> On 11/8/19 12:19 PM, Darrick J. Wong wrote:
>>> On Wed, Nov 06, 2019 at 06:27:48PM -0700, Allison Collins wrote:
>>>> This patch adds two new defines XFS_DABUF_MAP_NOMAPPING and
>>>> XFS_DABUF_MAP_HOLE_OK.  This helps to clean up hard numbers and
>>>> makes the code easier to read
>>>>
>>>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>>>> ---
>>>>    fs/xfs/libxfs/xfs_attr.c       | 14 +++++++-----
>>>>    fs/xfs/libxfs/xfs_attr_leaf.c  | 23 +++++++++++--------
>>>>    fs/xfs/libxfs/xfs_attr_leaf.h  |  3 +++
>>>>    fs/xfs/libxfs/xfs_da_btree.c   | 50 ++++++++++++++++++++++++++++--------------
>>>>    fs/xfs/libxfs/xfs_dir2_block.c |  6 +++--
>>>>    fs/xfs/libxfs/xfs_dir2_data.c  |  3 ++-
>>>>    fs/xfs/libxfs/xfs_dir2_leaf.c  |  9 +++++---
>>>>    fs/xfs/libxfs/xfs_dir2_node.c  | 10 +++++----
>>>>    fs/xfs/scrub/dabtree.c         |  6 ++---
>>>>    fs/xfs/scrub/dir.c             |  4 +++-
>>>>    fs/xfs/xfs_attr_inactive.c     |  6 +++--
>>>>    fs/xfs/xfs_attr_list.c         | 16 +++++++++-----
>>>>    12 files changed, 97 insertions(+), 53 deletions(-)
>>>
>>> <snip>
>>>
>>>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
>>>> index bb08800..017480e 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr_leaf.h
>>>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.h
>>>> @@ -16,6 +16,9 @@ struct xfs_da_state_blk;
>>>>    struct xfs_inode;
>>>>    struct xfs_trans;
>>>> +#define XFS_DABUF_MAP_NOMAPPING	(-1) /* Caller doesn't have a mapping. */
>>>> +#define XFS_DABUF_MAP_HOLE_OK	(-2) /* don't complain if we land in a hole. */
>>>
>>> These are parameters to xfs_da_{get,read,reada}_buf, please put them
>>> next to the declarations for those functions.
>> Hmm, I dont see that these are declared in a header file, but how about
>> fs/xfs/libxfs/xfs_da_btree.h ?  Did I miss them somewhere?
> 
> They should be declared around line 200 in that very file.
Ok, I found it... I foo-bared search command.  Will update then.  Thx!

Allison
> 
> --D
> 
>> Allison
>>
>>
>>>
>>> Also they probably ought to be explicitly cast to xfs_daddr_t, e.g.
>>>
>>> /* Force a fresh lookup for the dir/attr mapping. */
>>> #define XFS_DABUF_MAP_NOMAPPING	((xfs_daddr_t)-1)
>>>
>>> /* Don't complain if we land in a hole. */
>>> #define XFS_DABUF_MAP_HOLE_OK	((xfs_daddr_t)-2)
>>>
>>>> +
>>>>    /*
>>>>     * Used to keep a list of "remote value" extents when unlinking an inode.
>>>>     */
>>>
>>> <snip>
>>>
>>>> diff --git a/fs/xfs/libxfs/xfs_dir2_block.c b/fs/xfs/libxfs/xfs_dir2_block.c
>>>> index 8dedc30..6bc7651 100644
>>>> --- a/fs/xfs/libxfs/xfs_dir2_block.c
>>>> +++ b/fs/xfs/libxfs/xfs_dir2_block.c
>>>> @@ -20,6 +20,7 @@
>>>>    #include "xfs_error.h"
>>>>    #include "xfs_trace.h"
>>>>    #include "xfs_log.h"
>>>> +#include "xfs_attr_leaf.h"
>>>>    /*
>>>>     * Local function prototypes.
>>>> @@ -123,8 +124,9 @@ xfs_dir3_block_read(
>>>>    	struct xfs_mount	*mp = dp->i_mount;
>>>>    	int			err;
>>>> -	err = xfs_da_read_buf(tp, dp, mp->m_dir_geo->datablk, -1, bpp,
>>>> -				XFS_DATA_FORK, &xfs_dir3_block_buf_ops);
>>>> +	err = xfs_da_read_buf(tp, dp, mp->m_dir_geo->datablk,
>>>> +			      XFS_DABUF_MAP_NOMAPPING, bpp, XFS_DATA_FORK,
>>>> +			      &xfs_dir3_block_buf_ops);
>>>>    	if (!err && tp && *bpp)
>>>>    		xfs_trans_buf_set_type(tp, *bpp, XFS_BLFT_DIR_BLOCK_BUF);
>>>>    	return err;
>>>
>>> I think this misses the xfs_dir3_data_read call in
>>> xfs_dir2_leaf_to_block?
>>>
>>>> diff --git a/fs/xfs/libxfs/xfs_dir2_data.c b/fs/xfs/libxfs/xfs_dir2_data.c
>>>> index 2c79be4..a4188de 100644
>>>> --- a/fs/xfs/libxfs/xfs_dir2_data.c
>>>> +++ b/fs/xfs/libxfs/xfs_dir2_data.c
>>>> @@ -17,6 +17,7 @@
>>>>    #include "xfs_trans.h"
>>>>    #include "xfs_buf_item.h"
>>>>    #include "xfs_log.h"
>>>> +#include "xfs_attr_leaf.h"
>>>>    static xfs_failaddr_t xfs_dir2_data_freefind_verify(
>>>>    		struct xfs_dir2_data_hdr *hdr, struct xfs_dir2_data_free *bf,
>>>> @@ -653,7 +654,7 @@ xfs_dir3_data_init(
>>>>    	 * Get the buffer set up for the block.
>>>>    	 */
>>>>    	error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, blkno),
>>>> -			       -1, &bp, XFS_DATA_FORK);
>>>> +			       XFS_DABUF_MAP_NOMAPPING, &bp, XFS_DATA_FORK);
>>>>    	if (error)
>>>>    		return error;
>>>>    	bp->b_ops = &xfs_dir3_data_buf_ops;
>>>> diff --git a/fs/xfs/libxfs/xfs_dir2_leaf.c b/fs/xfs/libxfs/xfs_dir2_leaf.c
>>>> index b7046e2..a2cba6bd 100644
>>>> --- a/fs/xfs/libxfs/xfs_dir2_leaf.c
>>>> +++ b/fs/xfs/libxfs/xfs_dir2_leaf.c
>>>> @@ -19,6 +19,7 @@
>>>>    #include "xfs_trace.h"
>>>>    #include "xfs_trans.h"
>>>>    #include "xfs_buf_item.h"
>>>> +#include "xfs_attr_leaf.h"
>>>>    /*
>>>>     * Local function declarations.
>>>> @@ -311,7 +312,7 @@ xfs_dir3_leaf_get_buf(
>>>>    	       bno < xfs_dir2_byte_to_db(args->geo, XFS_DIR2_FREE_OFFSET));
>>>>    	error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, bno),
>>>> -			       -1, &bp, XFS_DATA_FORK);
>>>> +			       XFS_DABUF_MAP_NOMAPPING, &bp, XFS_DATA_FORK);
>>>>    	if (error)
>>>>    		return error;
>>>> @@ -594,7 +595,8 @@ xfs_dir2_leaf_addname(
>>>>    	trace_xfs_dir2_leaf_addname(args);
>>>> -	error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, -1, &lbp);
>>>> +	error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk,
>>>> +				   XFS_DABUF_MAP_NOMAPPING, &lbp);
>>>>    	if (error)
>>>>    		return error;
>>>
>>> I think there are some missing conversions for xfs_dir3_data_read calls
>>> in xfs_dir2_leaf_addname...
>>>
>>>> @@ -1189,7 +1191,8 @@ xfs_dir2_leaf_lookup_int(
>>>>    	tp = args->trans;
>>>>    	mp = dp->i_mount;
>>>> -	error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk, -1, &lbp);
>>>> +	error = xfs_dir3_leaf_read(tp, dp, args->geo->leafblk,
>>>> +				   XFS_DABUF_MAP_NOMAPPING, &lbp);
>>>>    	if (error)
>>>>    		return error;
>>>
>>> ...and two more dir3_leaf_read calls further down in this function...
>>>
>>> ...and one more in xfs_dir2_leaf_trim_data...
>>>
>>>> diff --git a/fs/xfs/libxfs/xfs_dir2_node.c b/fs/xfs/libxfs/xfs_dir2_node.c
>>>> index 8bbd742..0a803e4 100644
>>>> --- a/fs/xfs/libxfs/xfs_dir2_node.c
>>>> +++ b/fs/xfs/libxfs/xfs_dir2_node.c
>>>> @@ -20,6 +20,7 @@
>>>>    #include "xfs_trans.h"
>>>>    #include "xfs_buf_item.h"
>>>>    #include "xfs_log.h"
>>>> +#include "xfs_attr_leaf.h"
>>>>    /*
>>>>     * Function declarations.
>>>> @@ -227,7 +228,7 @@ xfs_dir2_free_read(
>>>>    	xfs_dablk_t		fbno,
>>>>    	struct xfs_buf		**bpp)
>>>>    {
>>>> -	return __xfs_dir3_free_read(tp, dp, fbno, -1, bpp);
>>>> +	return __xfs_dir3_free_read(tp, dp, fbno, XFS_DABUF_MAP_NOMAPPING, bpp);
>>>>    }
>>>>    static int
>>>> @@ -237,7 +238,7 @@ xfs_dir2_free_try_read(
>>>>    	xfs_dablk_t		fbno,
>>>>    	struct xfs_buf		**bpp)
>>>>    {
>>>> -	return __xfs_dir3_free_read(tp, dp, fbno, -2, bpp);
>>>> +	return __xfs_dir3_free_read(tp, dp, fbno, XFS_DABUF_MAP_HOLE_OK, bpp);
>>>>    }
>>>>    static int
>>>> @@ -254,7 +255,7 @@ xfs_dir3_free_get_buf(
>>>>    	struct xfs_dir3_icfree_hdr hdr;
>>>>    	error = xfs_da_get_buf(tp, dp, xfs_dir2_db_to_da(args->geo, fbno),
>>>> -				   -1, &bp, XFS_DATA_FORK);
>>>> +				   XFS_DABUF_MAP_NOMAPPING, &bp, XFS_DATA_FORK);
>>>>    	if (error)
>>>>    		return error;
>>>
>>> ...there's also a missing call in xfs_dir2_leafn_lookup_for_entry...
>>>
>>>> @@ -1495,7 +1496,8 @@ xfs_dir2_leafn_toosmall(
>>>>    		 * Read the sibling leaf block.
>>>>    		 */
>>>>    		error = xfs_dir3_leafn_read(state->args->trans, dp,
>>>> -					    blkno, -1, &bp);
>>>> +					    blkno, XFS_DABUF_MAP_NOMAPPING,
>>>> +					    &bp);
>>>>    		if (error)
>>>>    			return error;
>>>
>>> ...and another one in xfs_dir2_node_addname_int.
>>>
>>>> diff --git a/fs/xfs/scrub/dabtree.c b/fs/xfs/scrub/dabtree.c
>>>> index 77ff9f9..353455c 100644
>>>> --- a/fs/xfs/scrub/dabtree.c
>>>> +++ b/fs/xfs/scrub/dabtree.c
>>>> @@ -355,9 +355,9 @@ xchk_da_btree_block(
>>>>    		goto out_nobuf;
>>>>    	/* Read the buffer. */
>>>> -	error = xfs_da_read_buf(dargs->trans, dargs->dp, blk->blkno, -2,
>>>> -			&blk->bp, dargs->whichfork,
>>>> -			&xchk_da_btree_buf_ops);
>>>> +	error = xfs_da_read_buf(dargs->trans, dargs->dp, blk->blkno,
>>>> +				XFS_DABUF_MAP_HOLE_OK, &blk->bp,
>>>> +				dargs->whichfork, &xchk_da_btree_buf_ops);
>>>>    	if (!xchk_da_process_error(ds, level, &error))
>>>>    		goto out_nobuf;
>>>>    	if (blk->bp)
>>>> diff --git a/fs/xfs/scrub/dir.c b/fs/xfs/scrub/dir.c
>>>> index 1e2e117..eb0fa0f 100644
>>>> --- a/fs/xfs/scrub/dir.c
>>>> +++ b/fs/xfs/scrub/dir.c
>>>> @@ -18,6 +18,7 @@
>>>>    #include "scrub/scrub.h"
>>>>    #include "scrub/common.h"
>>>>    #include "scrub/dabtree.h"
>>>> +#include "xfs_attr_leaf.h"
>>>>    /* Set us up to scrub directories. */
>>>>    int
>>>
>>> I also noticed missing conversions for xfs_dir3_data_read in
>>> xchk_dir_rec, xchk_directory_data_bestfree,
>>> xchk_directory_leaf1_bestfree, and xchk_directory_free_bestfree.
>>>
>>>> @@ -492,7 +493,8 @@ xchk_directory_leaf1_bestfree(
>>>>    	int				error;
>>>>    	/* Read the free space block. */
>>>> -	error = xfs_dir3_leaf_read(sc->tp, sc->ip, lblk, -1, &bp);
>>>> +	error = xfs_dir3_leaf_read(sc->tp, sc->ip, lblk,
>>>> +				   XFS_DABUF_MAP_NOMAPPING, &bp);
>>>>    	if (!xchk_fblock_process_error(sc, XFS_DATA_FORK, lblk, &error))
>>>>    		goto out;
>>>>    	xchk_buffer_recheck(sc, bp);
>>>
>>> There's also a missing xfs_dir3_data_readahead conversion in
>>> xchk_parent_count_parent_dentries in fs/xfs/scrub/parent.c.
>>>
>>>> diff --git a/fs/xfs/xfs_attr_inactive.c b/fs/xfs/xfs_attr_inactive.c
>>>> index f83f11d..9c22915 100644
>>>> --- a/fs/xfs/xfs_attr_inactive.c
>>>> +++ b/fs/xfs/xfs_attr_inactive.c
>>>> @@ -235,7 +235,8 @@ xfs_attr3_node_inactive(
>>>>    		 * traversal of the tree so we may deal with many blocks
>>>>    		 * before we come back to this one.
>>>>    		 */
>>>> -		error = xfs_da3_node_read(*trans, dp, child_fsb, -1, &child_bp,
>>>> +		error = xfs_da3_node_read(*trans, dp, child_fsb,
>>>> +					  XFS_DABUF_MAP_NOMAPPING, &child_bp,
>>>>    					  XFS_ATTR_FORK);
>>>>    		if (error)
>>>>    			return error;
>>>> @@ -321,7 +322,8 @@ xfs_attr3_root_inactive(
>>>>    	 * the extents in reverse order the extent containing
>>>>    	 * block 0 must still be there.
>>>>    	 */
>>>> -	error = xfs_da3_node_read(*trans, dp, 0, -1, &bp, XFS_ATTR_FORK);
>>>> +	error = xfs_da3_node_read(*trans, dp, 0, XFS_DABUF_MAP_NOMAPPING, &bp,
>>>> +				  XFS_ATTR_FORK);
>>>>    	if (error)
>>>>    		return error;
>>>>    	blkno = bp->b_bn;
>>>> diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
>>>> index c02f22d..fab416c 100644
>>>> --- a/fs/xfs/xfs_attr_list.c
>>>> +++ b/fs/xfs/xfs_attr_list.c
>>>> @@ -224,8 +224,9 @@ xfs_attr_node_list_lookup(
>>>>    	ASSERT(*pbp == NULL);
>>>>    	cursor->blkno = 0;
>>>>    	for (;;) {
>>>> -		error = xfs_da3_node_read(tp, dp, cursor->blkno, -1, &bp,
>>>> -				XFS_ATTR_FORK);
>>>> +		error = xfs_da3_node_read(tp, dp, cursor->blkno,
>>>> +					  XFS_DABUF_MAP_NOMAPPING, &bp,
>>>> +					  XFS_ATTR_FORK);
>>>>    		if (error)
>>>>    			return error;
>>>>    		node = bp->b_addr;
>>>> @@ -309,8 +310,9 @@ xfs_attr_node_list(
>>>>    	 */
>>>>    	bp = NULL;
>>>>    	if (cursor->blkno > 0) {
>>>> -		error = xfs_da3_node_read(context->tp, dp, cursor->blkno, -1,
>>>> -					      &bp, XFS_ATTR_FORK);
>>>> +		error = xfs_da3_node_read(context->tp, dp, cursor->blkno,
>>>> +					  XFS_DABUF_MAP_NOMAPPING, &bp,
>>>> +					  XFS_ATTR_FORK);
>>>>    		if ((error != 0) && (error != -EFSCORRUPTED))
>>>>    			return error;
>>>>    		if (bp) {
>>>> @@ -377,7 +379,8 @@ xfs_attr_node_list(
>>>>    			break;
>>>>    		cursor->blkno = leafhdr.forw;
>>>>    		xfs_trans_brelse(context->tp, bp);
>>>> -		error = xfs_attr3_leaf_read(context->tp, dp, cursor->blkno, -1, &bp);
>>>> +		error = xfs_attr3_leaf_read(context->tp, dp, cursor->blkno,
>>>> +					    XFS_DABUF_MAP_NOMAPPING, &bp);
>>>>    		if (error)
>>>>    			return error;
>>>>    	}
>>>> @@ -497,7 +500,8 @@ xfs_attr_leaf_list(xfs_attr_list_context_t *context)
>>>>    	trace_xfs_attr_leaf_list(context);
>>>>    	context->cursor->blkno = 0;
>>>> -	error = xfs_attr3_leaf_read(context->tp, context->dp, 0, -1, &bp);
>>>> +	error = xfs_attr3_leaf_read(context->tp, context->dp, 0,
>>>> +				    XFS_DABUF_MAP_NOMAPPING, &bp);
>>>>    	if (error)
>>>>    		return error;
>>>
>>> ...more missing conversions of xfs_dir3_data_read in
>>> xfs_dir2_leaf_readbuf; and of xfs_dir3_data_readahead in
>>> xfs_dir2_leaf_readbuf...
>>>
>>> ...and a missing conversion of xfs_dir3_data_readahead in xfs_dir_open
>>> in fs/xfs/xfs_file.c.
>>>
>>> --D
>>>
>>>> -- 
>>>> 2.7.4
>>>>

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

* Re: [PATCH v4 05/17] xfs: Add xfs_has_attr and subroutines
  2019-11-07  1:27 ` [PATCH v4 05/17] xfs: Add xfs_has_attr and subroutines Allison Collins
  2019-11-08 19:32   ` Darrick J. Wong
@ 2019-11-11 17:40   ` Brian Foster
  2019-11-11 23:34     ` Allison Collins
  2019-11-11 17:53   ` Christoph Hellwig
  2 siblings, 1 reply; 77+ messages in thread
From: Brian Foster @ 2019-11-11 17:40 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Wed, Nov 06, 2019 at 06:27:49PM -0700, Allison Collins wrote:
> From: Allison Henderson <allison.henderson@oracle.com>
> 
> This patch adds a new functions to check for the existence of
> an attribute.  Subroutines are also added to handle the cases
> of leaf blocks, nodes or shortform.  Common code that appears
> in existing attr add and remove functions have been factored
> out to help reduce the appearence of duplicated code.  We will
> need these routines later for delayed attributes since delayed
> operations cannot return error codes.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---

This mostly looks good to me. Just some small nits..

>  fs/xfs/libxfs/xfs_attr.c      | 154 +++++++++++++++++++++++++++---------------
>  fs/xfs/libxfs/xfs_attr.h      |   1 +
>  fs/xfs/libxfs/xfs_attr_leaf.c | 107 ++++++++++++++++++-----------
>  fs/xfs/libxfs/xfs_attr_leaf.h |   2 +
>  4 files changed, 171 insertions(+), 93 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 5cb83a8..c8a3273 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
...
> @@ -310,6 +313,34 @@ xfs_attr_set_args(
>  }
>  
>  /*
> + * Return EEXIST if attr is found, or ENOATTR if not
> + */
> +int
> +xfs_has_attr(
> +	struct xfs_da_args      *args)
> +{
> +	struct xfs_inode        *dp = args->dp;
> +	struct xfs_buf		*bp;
> +	int                     error;
> +
> +	if (!xfs_inode_hasattr(dp)) {
> +		error = -ENOATTR;
> +	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
> +		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
> +		error = xfs_attr_shortform_hasname(args, NULL, NULL);
> +	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> +		error = xfs_attr_leaf_hasname(args, &bp);
> +		if (error != -ENOATTR && error != -EEXIST)
> +			goto out;

Hmm.. is this basically an indirect check for whether bp is set? If so,
I think doing bp = NULL above and:

		if (bp)
			xfs_trans_brelse(args->trans, bp);

... is more straightforward.

> +		xfs_trans_brelse(args->trans, bp);
> +	} else {
> +		error = xfs_attr_node_hasname(args, NULL);
> +	}
> +out:
> +	return error;
> +}
> +
> +/*
>   * Remove the attribute specified in @args.
>   */
>  int
...
> @@ -832,6 +869,38 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>  	return error;
>  }
>  
> +/*
> + * Return EEXIST if attr is found, or ENOATTR if not
> + * statep: If not null is set to point at the found state.  Caller will
> + * 	   be responsible for freeing the state in this case.
> + */
> +STATIC int
> +xfs_attr_node_hasname(
> +	struct xfs_da_args	*args,
> +	struct xfs_da_state	**statep)
> +{
> +	struct xfs_da_state	*state;
> +	int			retval, error;
> +
> +	state = xfs_da_state_alloc();
> +	state->args = args;
> +	state->mp = args->dp->i_mount;
> +
> +	/*
> +	 * Search to see if name exists, and get back a pointer to it.
> +	 */
> +	error = xfs_da3_node_lookup_int(state, &retval);
> +	if (error == 0)
> +		error = retval;
> +
> +	if (statep != NULL)
> +		*statep = state;
> +	else
> +		xfs_da_state_free(state);
> +
> +	return error;
> +}

The state allocation handling is a little wonky here in the error
scenario. I think precedent is that if we're returning an unexpected
error, we should probably just free state directly rather than rely on
the caller to do so. If the function returns "success" (meaning -EEXIST
or -ENOATTR), then the caller owns the state memory. It might also make
sense to NULL init the pointer either at the top of this helper or the
caller.

> +
>  /*========================================================================
>   * External routines when attribute list size > geo->blksize
>   *========================================================================*/
...
> @@ -1324,20 +1376,14 @@ xfs_attr_node_get(xfs_da_args_t *args)
>  
>  	trace_xfs_attr_node_get(args);
>  
> -	state = xfs_da_state_alloc();
> -	state->args = args;
> -	state->mp = args->dp->i_mount;
> -
>  	/*
>  	 * Search to see if name exists, and get back a pointer to it.
>  	 */
> -	error = xfs_da3_node_lookup_int(state, &retval);
> -	if (error) {
> +	error = xfs_attr_node_hasname(args, &state);
> +	if (error != -EEXIST) {
>  		retval = error;

Can we kill retval in this function now? The only use is to assign error
to it.

>  		goto out_release;
>  	}
> -	if (retval != -EEXIST)
> -		goto out_release;
>  
>  	/*
>  	 * Get the value, local or "remote"
...
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> index 93c3496..d06cfd6 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -655,18 +655,67 @@ xfs_attr_shortform_create(xfs_da_args_t *args)
>  }
>  
>  /*
> + * Return -EEXIST if attr is found, or -ENOATTR if not
> + * args:  args containing attribute name and namelen
> + * sfep:  If not null, pointer will be set to the last attr entry found on
> +	  -EEXIST.  On -ENOATTR pointer is left at the last entry in the list
> + * basep: If not null, pointer is set to the byte offset of the entry in the
> + *	  list on -EEXIST.  On -ENOATTR, pointer is left at the byte offset of
> + *	  the last entry in the list
> + */
> +int
> +xfs_attr_shortform_hasname(
> +	struct xfs_da_args	 *args,
> +	struct xfs_attr_sf_entry **sfep,
> +	int			 *basep)
> +{
> +	struct xfs_attr_shortform *sf;
> +	struct xfs_attr_sf_entry *sfe;
> +	int			base = sizeof(struct xfs_attr_sf_hdr);
> +	int			size = 0;
> +	int			end;
> +	int			i;
> +
> +	base = sizeof(struct xfs_attr_sf_hdr);

Double init.

> +	sf = (struct xfs_attr_shortform *)args->dp->i_afp->if_u1.if_data;
> +	sfe = &sf->list[0];
> +	end = sf->hdr.count;
> +	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
> +			base += size, i++) {
> +		size = XFS_ATTR_SF_ENTSIZE(sfe);
> +		if (sfe->namelen != args->name.len)
> +			continue;
> +		if (memcmp(sfe->nameval, args->name.name, args->name.len) != 0)
> +			continue;
> +		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
> +			continue;
> +		break;
> +	}
> +
> +	if (sfep != NULL)
> +		*sfep = sfe;
> +
> +	if (basep != NULL)
> +		*basep = base;
> +
> +	if (i == end)
> +		return -ENOATTR;
> +	return -EEXIST;
> +}
> +
> +/*
>   * Add a name/value pair to the shortform attribute list.
>   * Overflow from the inode has already been checked for.
>   */
>  void
>  xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
>  {
> -	xfs_attr_shortform_t *sf;
> -	xfs_attr_sf_entry_t *sfe;
> -	int i, offset, size;
> -	xfs_mount_t *mp;
> -	xfs_inode_t *dp;
> -	struct xfs_ifork *ifp;
> +	struct xfs_attr_shortform	*sf;
> +	struct xfs_attr_sf_entry	*sfe;
> +	int				offset, size, error;
> +	struct xfs_mount		*mp;
> +	struct xfs_inode		*dp;
> +	struct xfs_ifork		*ifp;

Might as well fix up the typedef in the function signature (here and
below) as well.

Brian

>  
>  	trace_xfs_attr_sf_add(args);
>  
> @@ -677,18 +726,8 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
>  	ifp = dp->i_afp;
>  	ASSERT(ifp->if_flags & XFS_IFINLINE);
>  	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
> -	sfe = &sf->list[0];
> -	for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
> -#ifdef DEBUG
> -		if (sfe->namelen != args->name.len)
> -			continue;
> -		if (memcmp(args->name.name, sfe->nameval, args->name.len) != 0)
> -			continue;
> -		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
> -			continue;
> -		ASSERT(0);
> -#endif
> -	}
> +	error = xfs_attr_shortform_hasname(args, &sfe, NULL);
> +	ASSERT(error != -EEXIST);
>  
>  	offset = (char *)sfe - (char *)sf;
>  	size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
> @@ -733,33 +772,23 @@ xfs_attr_fork_remove(
>  int
>  xfs_attr_shortform_remove(xfs_da_args_t *args)
>  {
> -	xfs_attr_shortform_t *sf;
> -	xfs_attr_sf_entry_t *sfe;
> -	int base, size=0, end, totsize, i;
> -	xfs_mount_t *mp;
> -	xfs_inode_t *dp;
> +	struct xfs_attr_shortform	*sf;
> +	struct xfs_attr_sf_entry	*sfe;
> +	int				base, size = 0, end, totsize;
> +	struct xfs_mount		*mp;
> +	struct xfs_inode		*dp;
> +	int				error;
>  
>  	trace_xfs_attr_sf_remove(args);
>  
>  	dp = args->dp;
>  	mp = dp->i_mount;
> -	base = sizeof(xfs_attr_sf_hdr_t);
>  	sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
> -	sfe = &sf->list[0];
> -	end = sf->hdr.count;
> -	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
> -					base += size, i++) {
> -		size = XFS_ATTR_SF_ENTSIZE(sfe);
> -		if (sfe->namelen != args->name.len)
> -			continue;
> -		if (memcmp(sfe->nameval, args->name.name, args->name.len) != 0)
> -			continue;
> -		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
> -			continue;
> -		break;
> -	}
> -	if (i == end)
> -		return -ENOATTR;
> +
> +	error = xfs_attr_shortform_hasname(args, &sfe, &base);
> +	if (error != -EEXIST)
> +		return error;
> +	size = XFS_ATTR_SF_ENTSIZE(sfe);
>  
>  	/*
>  	 * Fix up the attribute fork data, covering the hole
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
> index 017480e..e108b37 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.h
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.h
> @@ -42,6 +42,8 @@ int	xfs_attr_shortform_getvalue(struct xfs_da_args *args);
>  int	xfs_attr_shortform_to_leaf(struct xfs_da_args *args,
>  			struct xfs_buf **leaf_bp);
>  int	xfs_attr_shortform_remove(struct xfs_da_args *args);
> +int	xfs_attr_shortform_hasname(struct xfs_da_args *args,
> +			       struct xfs_attr_sf_entry **sfep, int *basep);
>  int	xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp);
>  int	xfs_attr_shortform_bytesfit(struct xfs_inode *dp, int bytes);
>  xfs_failaddr_t xfs_attr_shortform_verify(struct xfs_inode *ip);
> -- 
> 2.7.4
> 


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

* Re: [PATCH v4 01/17] xfs: Remove all strlen in all xfs_attr_* functions for attr names.
  2019-11-07  1:27 ` [PATCH v4 01/17] xfs: Remove all strlen in all xfs_attr_* functions for attr names Allison Collins
@ 2019-11-11 17:47   ` Christoph Hellwig
  2019-11-11 23:35     ` Allison Collins
  0 siblings, 1 reply; 77+ messages in thread
From: Christoph Hellwig @ 2019-11-11 17:47 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

Looks good,

Reviewed-by: Christoph Hellwig <hch@lst.de>

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

* Re: [PATCH v4 02/17] xfs: Replace attribute parameters with struct xfs_name
  2019-11-07  1:27 ` [PATCH v4 02/17] xfs: Replace attribute parameters with struct xfs_name Allison Collins
  2019-11-08  1:13   ` Darrick J. Wong
@ 2019-11-11 17:49   ` Christoph Hellwig
  2019-11-11 20:07     ` Allison Collins
  1 sibling, 1 reply; 77+ messages in thread
From: Christoph Hellwig @ 2019-11-11 17:49 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Wed, Nov 06, 2019 at 06:27:46PM -0700, Allison Collins wrote:
> This patch replaces the attribute name and length parameters with a
> single struct xfs_name parameter.  This helps to clean up the numbers of
> parameters being passed around and pre-simplifies the code some.

Does it?  As-is the patch doesn't look too bad, although it adds more
lines than it removes.  But together with the next patch that embedds
an xfs_name into the xfs_da_args structure and the now added memcpys
it doesn't really look very helpful to me.

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

* Re: [PATCH v4 05/17] xfs: Add xfs_has_attr and subroutines
  2019-11-07  1:27 ` [PATCH v4 05/17] xfs: Add xfs_has_attr and subroutines Allison Collins
  2019-11-08 19:32   ` Darrick J. Wong
  2019-11-11 17:40   ` Brian Foster
@ 2019-11-11 17:53   ` Christoph Hellwig
  2019-11-11 23:36     ` Allison Collins
  2 siblings, 1 reply; 77+ messages in thread
From: Christoph Hellwig @ 2019-11-11 17:53 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

> +	if (!xfs_inode_hasattr(dp)) {
> +		error = -ENOATTR;
> +	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
> +		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
> +		error = xfs_attr_shortform_hasname(args, NULL, NULL);
> +	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> +		error = xfs_attr_leaf_hasname(args, &bp);
> +		if (error != -ENOATTR && error != -EEXIST)
> +			goto out;
> +		xfs_trans_brelse(args->trans, bp);
> +	} else {
> +		error = xfs_attr_node_hasname(args, NULL);
> +	}
> +out:
> +	return error;
> +}

I think a lot of this would be much simpler without the goto out, e.g.:

	if (!xfs_inode_hasattr(dp))
		return -ENOATTR;

	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
		return xfs_attr_shortform_hasname(args, NULL, NULL);
	}

	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
		struct xfs_buf	*bp;
		int		error = xfs_attr_leaf_hasname(args, &bp);

		if (error == -ENOATTR || error == -EEXIST)
			xfs_trans_brelse(args->trans, bp);
		return error;
	}

	return xfs_attr_node_hasname(args, NULL);

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

* Re: [PATCH v4 13/17] xfs: Factor up trans roll in xfs_attr3_leaf_clearflag
  2019-11-07  1:27 ` [PATCH v4 13/17] xfs: Factor up trans roll in xfs_attr3_leaf_clearflag Allison Collins
  2019-11-08 21:19   ` Darrick J. Wong
@ 2019-11-11 18:23   ` Brian Foster
  2019-11-11 23:37     ` Allison Collins
  1 sibling, 1 reply; 77+ messages in thread
From: Brian Foster @ 2019-11-11 18:23 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Wed, Nov 06, 2019 at 06:27:57PM -0700, Allison Collins wrote:
> New delayed allocation routines cannot be handling
> transactions so factor them up into the calling functions
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---

Reviewed-by: Brian Foster <bfoster@redhat.com>

>  fs/xfs/libxfs/xfs_attr.c      | 16 ++++++++++++++++
>  fs/xfs/libxfs/xfs_attr_leaf.c |  5 +----
>  2 files changed, 17 insertions(+), 4 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 2f9fb7a..5dcb19f 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -797,6 +797,14 @@ xfs_attr_leaf_addname(struct xfs_da_args	*args)
>  		 * Added a "remote" value, just clear the incomplete flag.
>  		 */
>  		error = xfs_attr3_leaf_clearflag(args);
> +		if (error)
> +			return error;
> +
> +		/*
> +		 * Commit the flag value change and start the next trans in
> +		 * series.
> +		 */
> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
>  	}
>  	return error;
>  }
> @@ -1154,6 +1162,14 @@ xfs_attr_node_addname(
>  		error = xfs_attr3_leaf_clearflag(args);
>  		if (error)
>  			goto out;
> +
> +		 /*
> +		  * Commit the flag value change and start the next trans in
> +		  * series.
> +		  */
> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
> +		if (error)
> +			goto out;
>  	}
>  	retval = error = 0;
>  
> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
> index 023c616..07eee3ff 100644
> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
> @@ -2802,10 +2802,7 @@ xfs_attr3_leaf_clearflag(
>  			 XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt)));
>  	}
>  
> -	/*
> -	 * Commit the flag value change and start the next trans in series.
> -	 */
> -	return xfs_trans_roll_inode(&args->trans, args->dp);
> +	return error;
>  }
>  
>  /*
> -- 
> 2.7.4
> 


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

* Re: [PATCH v4 14/17] xfs: Add delay context to xfs_da_args
  2019-11-07  1:27 ` [PATCH v4 14/17] xfs: Add delay context to xfs_da_args Allison Collins
  2019-11-08 21:22   ` Darrick J. Wong
@ 2019-11-11 18:23   ` Brian Foster
  2019-11-11 23:42     ` Allison Collins
  1 sibling, 1 reply; 77+ messages in thread
From: Brian Foster @ 2019-11-11 18:23 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Wed, Nov 06, 2019 at 06:27:58PM -0700, Allison Collins wrote:
> This patch adds a new struct xfs_delay_context, which we
> will use to keep track of the current state of a delayed
> attribute operation.
> 

Technically, this should track delayed or non-delayed attr operations,
right? IIRC, the goal is that the difference between the two is that the
former is driven by the dfops mechanism while the latter executes the
same code with a higher level hack to roll transactions and loop through
the state machine...

Brian

> The new enum is used to track various operations that
> are in progress so that we know not to repeat them, and
> resume where we left off before EAGAIN was returned to
> cycle out the transaction.  Other members take the place
> of local variables that need to retain their values
> across multiple function recalls.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_da_btree.h | 28 ++++++++++++++++++++++++++++
>  fs/xfs/scrub/common.c        |  2 ++
>  fs/xfs/xfs_acl.c             |  2 ++
>  fs/xfs/xfs_attr_list.c       |  1 +
>  fs/xfs/xfs_ioctl.c           |  2 ++
>  fs/xfs/xfs_ioctl32.c         |  2 ++
>  fs/xfs/xfs_iops.c            |  2 ++
>  fs/xfs/xfs_xattr.c           |  1 +
>  8 files changed, 40 insertions(+)
> 
> diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
> index bed4f40..ef23ed8 100644
> --- a/fs/xfs/libxfs/xfs_da_btree.h
> +++ b/fs/xfs/libxfs/xfs_da_btree.h
> @@ -42,6 +42,33 @@ enum xfs_dacmp {
>  	XFS_CMP_CASE		/* names are same but differ in case */
>  };
>  
> +enum xfs_attr_state {
> +	XFS_DC_INIT		= 1, /* Init delay info */
> +	XFS_DC_SF_TO_LEAF	= 2, /* Converted short form to leaf */
> +	XFS_DC_FOUND_LBLK	= 3, /* We found leaf blk for attr */
> +	XFS_DC_LEAF_TO_NODE	= 4, /* Converted leaf to node */
> +	XFS_DC_FOUND_NBLK	= 5, /* We found node blk for attr */
> +	XFS_DC_ALLOC_LEAF	= 6, /* We are allocating leaf blocks */
> +	XFS_DC_ALLOC_NODE	= 7, /* We are allocating node blocks */
> +	XFS_DC_RM_INVALIDATE	= 8, /* We are invalidating blocks */
> +	XFS_DC_RM_SHRINK	= 9, /* We are shrinking the tree */
> +	XFS_DC_RM_NODE_BLKS	= 10,/* We are removing node blocks */
> +};
> +
> +/*
> + * Context used for keeping track of delayed attribute operations
> + */
> +struct xfs_delay_context {
> +	enum xfs_attr_state	dc_state;
> +	struct xfs_buf		*leaf_bp;
> +	struct xfs_bmbt_irec	map;
> +	xfs_dablk_t		lblkno;
> +	xfs_fileoff_t		lfileoff;
> +	int			blkcnt;
> +	struct xfs_da_state	*da_state;
> +	struct xfs_da_state_blk *blk;
> +};
> +
>  /*
>   * Structure to ease passing around component names.
>   */
> @@ -69,6 +96,7 @@ typedef struct xfs_da_args {
>  	int		rmtvaluelen2;	/* remote attr value length in bytes */
>  	int		op_flags;	/* operation flags */
>  	enum xfs_dacmp	cmpresult;	/* name compare result for lookups */
> +	struct xfs_delay_context  dc;	/* context used for delay attr ops */
>  } xfs_da_args_t;
>  
>  /*
> diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
> index 1887605..9a649d1 100644
> --- a/fs/xfs/scrub/common.c
> +++ b/fs/xfs/scrub/common.c
> @@ -24,6 +24,8 @@
>  #include "xfs_rmap_btree.h"
>  #include "xfs_log.h"
>  #include "xfs_trans_priv.h"
> +#include "xfs_da_format.h"
> +#include "xfs_da_btree.h"
>  #include "xfs_attr.h"
>  #include "xfs_reflink.h"
>  #include "scrub/scrub.h"
> diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
> index e868755..1336477 100644
> --- a/fs/xfs/xfs_acl.c
> +++ b/fs/xfs/xfs_acl.c
> @@ -10,6 +10,8 @@
>  #include "xfs_trans_resv.h"
>  #include "xfs_mount.h"
>  #include "xfs_inode.h"
> +#include "xfs_da_format.h"
> +#include "xfs_da_btree.h"
>  #include "xfs_attr.h"
>  #include "xfs_trace.h"
>  #include <linux/posix_acl_xattr.h>
> diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
> index fab416c..e395864 100644
> --- a/fs/xfs/xfs_attr_list.c
> +++ b/fs/xfs/xfs_attr_list.c
> @@ -12,6 +12,7 @@
>  #include "xfs_trans_resv.h"
>  #include "xfs_mount.h"
>  #include "xfs_da_format.h"
> +#include "xfs_da_btree.h"
>  #include "xfs_inode.h"
>  #include "xfs_trans.h"
>  #include "xfs_bmap.h"
> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
> index ae0ed88..23b0ca6 100644
> --- a/fs/xfs/xfs_ioctl.c
> +++ b/fs/xfs/xfs_ioctl.c
> @@ -15,6 +15,8 @@
>  #include "xfs_iwalk.h"
>  #include "xfs_itable.h"
>  #include "xfs_error.h"
> +#include "xfs_da_format.h"
> +#include "xfs_da_btree.h"
>  #include "xfs_attr.h"
>  #include "xfs_bmap.h"
>  #include "xfs_bmap_util.h"
> diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c
> index 3c0d518..e3278ac 100644
> --- a/fs/xfs/xfs_ioctl32.c
> +++ b/fs/xfs/xfs_ioctl32.c
> @@ -17,6 +17,8 @@
>  #include "xfs_itable.h"
>  #include "xfs_fsops.h"
>  #include "xfs_rtalloc.h"
> +#include "xfs_da_format.h"
> +#include "xfs_da_btree.h"
>  #include "xfs_attr.h"
>  #include "xfs_ioctl.h"
>  #include "xfs_ioctl32.h"
> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
> index aef346e..68b9cd0 100644
> --- a/fs/xfs/xfs_iops.c
> +++ b/fs/xfs/xfs_iops.c
> @@ -13,6 +13,8 @@
>  #include "xfs_inode.h"
>  #include "xfs_acl.h"
>  #include "xfs_quota.h"
> +#include "xfs_da_format.h"
> +#include "xfs_da_btree.h"
>  #include "xfs_attr.h"
>  #include "xfs_trans.h"
>  #include "xfs_trace.h"
> diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
> index 6c5321d..0f0ebab 100644
> --- a/fs/xfs/xfs_xattr.c
> +++ b/fs/xfs/xfs_xattr.c
> @@ -10,6 +10,7 @@
>  #include "xfs_log_format.h"
>  #include "xfs_da_format.h"
>  #include "xfs_inode.h"
> +#include "xfs_da_btree.h"
>  #include "xfs_attr.h"
>  
>  #include <linux/posix_acl_xattr.h>
> -- 
> 2.7.4
> 


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

* Re: [PATCH v4 15/17] xfs: Check for -ENOATTR or -EEXIST
  2019-11-07  1:27 ` [PATCH v4 15/17] xfs: Check for -ENOATTR or -EEXIST Allison Collins
  2019-11-08 21:28   ` Darrick J. Wong
@ 2019-11-11 18:24   ` Brian Foster
  2019-11-12  0:33     ` Allison Collins
  1 sibling, 1 reply; 77+ messages in thread
From: Brian Foster @ 2019-11-11 18:24 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Wed, Nov 06, 2019 at 06:27:59PM -0700, Allison Collins wrote:
> Delayed operations cannot return error codes.  So we must check for
> these conditions first before starting set or remove operations
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---
>  fs/xfs/libxfs/xfs_attr.c | 25 +++++++++++++++++++++++++
>  1 file changed, 25 insertions(+)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 5dcb19f..626d4a98 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -458,6 +458,27 @@ xfs_attr_set(
>  		goto out_trans_cancel;
>  
>  	xfs_trans_ijoin(args.trans, dp, 0);
> +
> +	error = xfs_has_attr(&args);
> +	if (error == -EEXIST) {
> +		if (name->type & ATTR_CREATE)
> +			goto out_trans_cancel;
> +		else
> +			name->type |= ATTR_REPLACE;
> +	}
> +
> +	if (error == -ENOATTR && (name->type & ATTR_REPLACE))
> +		goto out_trans_cancel;
> +
> +	if (name->type & ATTR_REPLACE) {
> +		name->type &= ~ATTR_REPLACE;
> +		error = xfs_attr_remove_args(&args);
> +		if (error)
> +			goto out_trans_cancel;
> +
> +		name->type |= ATTR_CREATE;
> +	}
> +

I see Darrick already commented on this.. I think the behavior of the
existing rename code is to essentially create the new xattr with the
INCOMPLETE flag set so we can roll transactions, etc. without any
observable behavior to userspace. Once the new xattr is fully in place,
the rename is performed atomically from the userspace perspective by
flipping the INCOMPLETE flag from the newly constructed xattr to the old
one and we can then remove the old xattr from there.

>  	error = xfs_attr_set_args(&args);
>  	if (error)
>  		goto out_trans_cancel;
> @@ -543,6 +564,10 @@ xfs_attr_remove(
>  	 */
>  	xfs_trans_ijoin(args.trans, dp, 0);
>  
> +	error = xfs_has_attr(&args);
> +	if (error == -ENOATTR)
> +		goto out;
> +

Wouldn't we want to return any error that might occur here (except
-EEXIST), not just -ENOATTR if there's actually no xattr?

Brian

>  	error = xfs_attr_remove_args(&args);
>  	if (error)
>  		goto out;
> -- 
> 2.7.4
> 


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

* Re: [PATCH v4 02/17] xfs: Replace attribute parameters with struct xfs_name
  2019-11-11 17:49   ` Christoph Hellwig
@ 2019-11-11 20:07     ` Allison Collins
  2019-11-13 15:12       ` Allison Collins
  0 siblings, 1 reply; 77+ messages in thread
From: Allison Collins @ 2019-11-11 20:07 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: linux-xfs, Dave Chinner



On 11/11/19 10:49 AM, Christoph Hellwig wrote:
> On Wed, Nov 06, 2019 at 06:27:46PM -0700, Allison Collins wrote:
>> This patch replaces the attribute name and length parameters with a
>> single struct xfs_name parameter.  This helps to clean up the numbers of
>> parameters being passed around and pre-simplifies the code some.
> 
> Does it?  As-is the patch doesn't look too bad, although it adds more
> lines than it removes.  But together with the next patch that embedds
> an xfs_name into the xfs_da_args structure and the now added memcpys
> it doesn't really look very helpful to me.
> 
It has evolved a bit since its initial proposition.  Maybe it would help 
to raise the question of: is patch 2 or 3 alone more helpful than the 
combination of them?  I think initially Dave had suggested the clean up 
in one of the earlier reviews a while ago, so he may have an opinion here.

Personally I'm not super opinionated about it if people have strong 
feelings toward keeping or pitching it.  I will say after having worked 
with it as it is, I'm not sure I'm particularly fond of having a name 
struct in the param, and another in the args.  I think eventually 
someones going to forget that args supersedes the param after the init 
routine.  People will probably figure it out pretty quick if they get 
bit I suppose, but I do think it's a sort of wart to consider.

Allison

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

* Re: [PATCH v4 05/17] xfs: Add xfs_has_attr and subroutines
  2019-11-11 17:40   ` Brian Foster
@ 2019-11-11 23:34     ` Allison Collins
  0 siblings, 0 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-11 23:34 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 11/11/19 10:40 AM, Brian Foster wrote:
> On Wed, Nov 06, 2019 at 06:27:49PM -0700, Allison Collins wrote:
>> From: Allison Henderson <allison.henderson@oracle.com>
>>
>> This patch adds a new functions to check for the existence of
>> an attribute.  Subroutines are also added to handle the cases
>> of leaf blocks, nodes or shortform.  Common code that appears
>> in existing attr add and remove functions have been factored
>> out to help reduce the appearence of duplicated code.  We will
>> need these routines later for delayed attributes since delayed
>> operations cannot return error codes.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
> 
> This mostly looks good to me. Just some small nits..
> 
>>   fs/xfs/libxfs/xfs_attr.c      | 154 +++++++++++++++++++++++++++---------------
>>   fs/xfs/libxfs/xfs_attr.h      |   1 +
>>   fs/xfs/libxfs/xfs_attr_leaf.c | 107 ++++++++++++++++++-----------
>>   fs/xfs/libxfs/xfs_attr_leaf.h |   2 +
>>   4 files changed, 171 insertions(+), 93 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 5cb83a8..c8a3273 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
> ...
>> @@ -310,6 +313,34 @@ xfs_attr_set_args(
>>   }
>>   
>>   /*
>> + * Return EEXIST if attr is found, or ENOATTR if not
>> + */
>> +int
>> +xfs_has_attr(
>> +	struct xfs_da_args      *args)
>> +{
>> +	struct xfs_inode        *dp = args->dp;
>> +	struct xfs_buf		*bp;
>> +	int                     error;
>> +
>> +	if (!xfs_inode_hasattr(dp)) {
>> +		error = -ENOATTR;
>> +	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
>> +		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
>> +		error = xfs_attr_shortform_hasname(args, NULL, NULL);
>> +	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>> +		error = xfs_attr_leaf_hasname(args, &bp);
>> +		if (error != -ENOATTR && error != -EEXIST)
>> +			goto out;
> 
> Hmm.. is this basically an indirect check for whether bp is set? If so,
> I think doing bp = NULL above and:
> 
> 		if (bp)
> 			xfs_trans_brelse(args->trans, bp);
> 
> ... is more straightforward.
> 
>> +		xfs_trans_brelse(args->trans, bp);
>> +	} else {
>> +		error = xfs_attr_node_hasname(args, NULL);
>> +	}
>> +out:
>> +	return error;
>> +}
>> +
>> +/*
>>    * Remove the attribute specified in @args.
>>    */
>>   int
> ...
>> @@ -832,6 +869,38 @@ xfs_attr_leaf_get(xfs_da_args_t *args)
>>   	return error;
>>   }
>>   
>> +/*
>> + * Return EEXIST if attr is found, or ENOATTR if not
>> + * statep: If not null is set to point at the found state.  Caller will
>> + * 	   be responsible for freeing the state in this case.
>> + */
>> +STATIC int
>> +xfs_attr_node_hasname(
>> +	struct xfs_da_args	*args,
>> +	struct xfs_da_state	**statep)
>> +{
>> +	struct xfs_da_state	*state;
>> +	int			retval, error;
>> +
>> +	state = xfs_da_state_alloc();
>> +	state->args = args;
>> +	state->mp = args->dp->i_mount;
>> +
>> +	/*
>> +	 * Search to see if name exists, and get back a pointer to it.
>> +	 */
>> +	error = xfs_da3_node_lookup_int(state, &retval);
>> +	if (error == 0)
>> +		error = retval;
>> +
>> +	if (statep != NULL)
>> +		*statep = state;
>> +	else
>> +		xfs_da_state_free(state);
>> +
>> +	return error;
>> +}
> 
> The state allocation handling is a little wonky here in the error
> scenario. I think precedent is that if we're returning an unexpected
> error, we should probably just free state directly rather than rely on
> the caller to do so. If the function returns "success" (meaning -EEXIST
> or -ENOATTR), then the caller owns the state memory. It might also make
> sense to NULL init the pointer either at the top of this helper or the
> caller.
> 
>> +
>>   /*========================================================================
>>    * External routines when attribute list size > geo->blksize
>>    *========================================================================*/
> ...
>> @@ -1324,20 +1376,14 @@ xfs_attr_node_get(xfs_da_args_t *args)
>>   
>>   	trace_xfs_attr_node_get(args);
>>   
>> -	state = xfs_da_state_alloc();
>> -	state->args = args;
>> -	state->mp = args->dp->i_mount;
>> -
>>   	/*
>>   	 * Search to see if name exists, and get back a pointer to it.
>>   	 */
>> -	error = xfs_da3_node_lookup_int(state, &retval);
>> -	if (error) {
>> +	error = xfs_attr_node_hasname(args, &state);
>> +	if (error != -EEXIST) {
>>   		retval = error;
> 
> Can we kill retval in this function now? The only use is to assign error
> to it.
> 
>>   		goto out_release;
>>   	}
>> -	if (retval != -EEXIST)
>> -		goto out_release;
>>   
>>   	/*
>>   	 * Get the value, local or "remote"
> ...
>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
>> index 93c3496..d06cfd6 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
>> @@ -655,18 +655,67 @@ xfs_attr_shortform_create(xfs_da_args_t *args)
>>   }
>>   
>>   /*
>> + * Return -EEXIST if attr is found, or -ENOATTR if not
>> + * args:  args containing attribute name and namelen
>> + * sfep:  If not null, pointer will be set to the last attr entry found on
>> +	  -EEXIST.  On -ENOATTR pointer is left at the last entry in the list
>> + * basep: If not null, pointer is set to the byte offset of the entry in the
>> + *	  list on -EEXIST.  On -ENOATTR, pointer is left at the byte offset of
>> + *	  the last entry in the list
>> + */
>> +int
>> +xfs_attr_shortform_hasname(
>> +	struct xfs_da_args	 *args,
>> +	struct xfs_attr_sf_entry **sfep,
>> +	int			 *basep)
>> +{
>> +	struct xfs_attr_shortform *sf;
>> +	struct xfs_attr_sf_entry *sfe;
>> +	int			base = sizeof(struct xfs_attr_sf_hdr);
>> +	int			size = 0;
>> +	int			end;
>> +	int			i;
>> +
>> +	base = sizeof(struct xfs_attr_sf_hdr);
> 
> Double init.
> 
>> +	sf = (struct xfs_attr_shortform *)args->dp->i_afp->if_u1.if_data;
>> +	sfe = &sf->list[0];
>> +	end = sf->hdr.count;
>> +	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
>> +			base += size, i++) {
>> +		size = XFS_ATTR_SF_ENTSIZE(sfe);
>> +		if (sfe->namelen != args->name.len)
>> +			continue;
>> +		if (memcmp(sfe->nameval, args->name.name, args->name.len) != 0)
>> +			continue;
>> +		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
>> +			continue;
>> +		break;
>> +	}
>> +
>> +	if (sfep != NULL)
>> +		*sfep = sfe;
>> +
>> +	if (basep != NULL)
>> +		*basep = base;
>> +
>> +	if (i == end)
>> +		return -ENOATTR;
>> +	return -EEXIST;
>> +}
>> +
>> +/*
>>    * Add a name/value pair to the shortform attribute list.
>>    * Overflow from the inode has already been checked for.
>>    */
>>   void
>>   xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
>>   {
>> -	xfs_attr_shortform_t *sf;
>> -	xfs_attr_sf_entry_t *sfe;
>> -	int i, offset, size;
>> -	xfs_mount_t *mp;
>> -	xfs_inode_t *dp;
>> -	struct xfs_ifork *ifp;
>> +	struct xfs_attr_shortform	*sf;
>> +	struct xfs_attr_sf_entry	*sfe;
>> +	int				offset, size, error;
>> +	struct xfs_mount		*mp;
>> +	struct xfs_inode		*dp;
>> +	struct xfs_ifork		*ifp;
> 
> Might as well fix up the typedef in the function signature (here and
> below) as well.
> 
> Brian

Sure, all the nits sound reasonable I will update them in the next 
version.  Thanks for the review!

Allison

> 
>>   
>>   	trace_xfs_attr_sf_add(args);
>>   
>> @@ -677,18 +726,8 @@ xfs_attr_shortform_add(xfs_da_args_t *args, int forkoff)
>>   	ifp = dp->i_afp;
>>   	ASSERT(ifp->if_flags & XFS_IFINLINE);
>>   	sf = (xfs_attr_shortform_t *)ifp->if_u1.if_data;
>> -	sfe = &sf->list[0];
>> -	for (i = 0; i < sf->hdr.count; sfe = XFS_ATTR_SF_NEXTENTRY(sfe), i++) {
>> -#ifdef DEBUG
>> -		if (sfe->namelen != args->name.len)
>> -			continue;
>> -		if (memcmp(args->name.name, sfe->nameval, args->name.len) != 0)
>> -			continue;
>> -		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
>> -			continue;
>> -		ASSERT(0);
>> -#endif
>> -	}
>> +	error = xfs_attr_shortform_hasname(args, &sfe, NULL);
>> +	ASSERT(error != -EEXIST);
>>   
>>   	offset = (char *)sfe - (char *)sf;
>>   	size = XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
>> @@ -733,33 +772,23 @@ xfs_attr_fork_remove(
>>   int
>>   xfs_attr_shortform_remove(xfs_da_args_t *args)
>>   {
>> -	xfs_attr_shortform_t *sf;
>> -	xfs_attr_sf_entry_t *sfe;
>> -	int base, size=0, end, totsize, i;
>> -	xfs_mount_t *mp;
>> -	xfs_inode_t *dp;
>> +	struct xfs_attr_shortform	*sf;
>> +	struct xfs_attr_sf_entry	*sfe;
>> +	int				base, size = 0, end, totsize;
>> +	struct xfs_mount		*mp;
>> +	struct xfs_inode		*dp;
>> +	int				error;
>>   
>>   	trace_xfs_attr_sf_remove(args);
>>   
>>   	dp = args->dp;
>>   	mp = dp->i_mount;
>> -	base = sizeof(xfs_attr_sf_hdr_t);
>>   	sf = (xfs_attr_shortform_t *)dp->i_afp->if_u1.if_data;
>> -	sfe = &sf->list[0];
>> -	end = sf->hdr.count;
>> -	for (i = 0; i < end; sfe = XFS_ATTR_SF_NEXTENTRY(sfe),
>> -					base += size, i++) {
>> -		size = XFS_ATTR_SF_ENTSIZE(sfe);
>> -		if (sfe->namelen != args->name.len)
>> -			continue;
>> -		if (memcmp(sfe->nameval, args->name.name, args->name.len) != 0)
>> -			continue;
>> -		if (!xfs_attr_namesp_match(args->name.type, sfe->flags))
>> -			continue;
>> -		break;
>> -	}
>> -	if (i == end)
>> -		return -ENOATTR;
>> +
>> +	error = xfs_attr_shortform_hasname(args, &sfe, &base);
>> +	if (error != -EEXIST)
>> +		return error;
>> +	size = XFS_ATTR_SF_ENTSIZE(sfe);
>>   
>>   	/*
>>   	 * Fix up the attribute fork data, covering the hole
>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.h b/fs/xfs/libxfs/xfs_attr_leaf.h
>> index 017480e..e108b37 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.h
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.h
>> @@ -42,6 +42,8 @@ int	xfs_attr_shortform_getvalue(struct xfs_da_args *args);
>>   int	xfs_attr_shortform_to_leaf(struct xfs_da_args *args,
>>   			struct xfs_buf **leaf_bp);
>>   int	xfs_attr_shortform_remove(struct xfs_da_args *args);
>> +int	xfs_attr_shortform_hasname(struct xfs_da_args *args,
>> +			       struct xfs_attr_sf_entry **sfep, int *basep);
>>   int	xfs_attr_shortform_allfit(struct xfs_buf *bp, struct xfs_inode *dp);
>>   int	xfs_attr_shortform_bytesfit(struct xfs_inode *dp, int bytes);
>>   xfs_failaddr_t xfs_attr_shortform_verify(struct xfs_inode *ip);
>> -- 
>> 2.7.4
>>
> 

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

* Re: [PATCH v4 01/17] xfs: Remove all strlen in all xfs_attr_* functions for attr names.
  2019-11-11 17:47   ` Christoph Hellwig
@ 2019-11-11 23:35     ` Allison Collins
  0 siblings, 0 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-11 23:35 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: linux-xfs



On 11/11/19 10:47 AM, Christoph Hellwig wrote:
> Looks good,
> 
> Reviewed-by: Christoph Hellwig <hch@lst.de>
> 
Great!  Thanks for the review!
Allison

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

* Re: [PATCH v4 05/17] xfs: Add xfs_has_attr and subroutines
  2019-11-11 17:53   ` Christoph Hellwig
@ 2019-11-11 23:36     ` Allison Collins
  0 siblings, 0 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-11 23:36 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: linux-xfs



On 11/11/19 10:53 AM, Christoph Hellwig wrote:
>> +	if (!xfs_inode_hasattr(dp)) {
>> +		error = -ENOATTR;
>> +	} else if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
>> +		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
>> +		error = xfs_attr_shortform_hasname(args, NULL, NULL);
>> +	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>> +		error = xfs_attr_leaf_hasname(args, &bp);
>> +		if (error != -ENOATTR && error != -EEXIST)
>> +			goto out;
>> +		xfs_trans_brelse(args->trans, bp);
>> +	} else {
>> +		error = xfs_attr_node_hasname(args, NULL);
>> +	}
>> +out:
>> +	return error;
>> +}
> 
> I think a lot of this would be much simpler without the goto out, e.g.:
> 
> 	if (!xfs_inode_hasattr(dp))
> 		return -ENOATTR;
> 
> 	if (dp->i_d.di_aformat == XFS_DINODE_FMT_LOCAL) {
> 		ASSERT(dp->i_afp->if_flags & XFS_IFINLINE);
> 		return xfs_attr_shortform_hasname(args, NULL, NULL);
> 	}
> 
> 	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> 		struct xfs_buf	*bp;
> 		int		error = xfs_attr_leaf_hasname(args, &bp);
> 
> 		if (error == -ENOATTR || error == -EEXIST)
> 			xfs_trans_brelse(args->trans, bp);
> 		return error;
> 	}
> 
> 	return xfs_attr_node_hasname(args, NULL);
> 

Sure, will fix this along with Brians suggestions too.  Thanks!
Allison

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

* Re: [PATCH v4 13/17] xfs: Factor up trans roll in xfs_attr3_leaf_clearflag
  2019-11-11 18:23   ` Brian Foster
@ 2019-11-11 23:37     ` Allison Collins
  0 siblings, 0 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-11 23:37 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 11/11/19 11:23 AM, Brian Foster wrote:
> On Wed, Nov 06, 2019 at 06:27:57PM -0700, Allison Collins wrote:
>> New delayed allocation routines cannot be handling
>> transactions so factor them up into the calling functions
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
> 
> Reviewed-by: Brian Foster <bfoster@redhat.com>
Thank you!
Allison

> 
>>   fs/xfs/libxfs/xfs_attr.c      | 16 ++++++++++++++++
>>   fs/xfs/libxfs/xfs_attr_leaf.c |  5 +----
>>   2 files changed, 17 insertions(+), 4 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 2f9fb7a..5dcb19f 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -797,6 +797,14 @@ xfs_attr_leaf_addname(struct xfs_da_args	*args)
>>   		 * Added a "remote" value, just clear the incomplete flag.
>>   		 */
>>   		error = xfs_attr3_leaf_clearflag(args);
>> +		if (error)
>> +			return error;
>> +
>> +		/*
>> +		 * Commit the flag value change and start the next trans in
>> +		 * series.
>> +		 */
>> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
>>   	}
>>   	return error;
>>   }
>> @@ -1154,6 +1162,14 @@ xfs_attr_node_addname(
>>   		error = xfs_attr3_leaf_clearflag(args);
>>   		if (error)
>>   			goto out;
>> +
>> +		 /*
>> +		  * Commit the flag value change and start the next trans in
>> +		  * series.
>> +		  */
>> +		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> +		if (error)
>> +			goto out;
>>   	}
>>   	retval = error = 0;
>>   
>> diff --git a/fs/xfs/libxfs/xfs_attr_leaf.c b/fs/xfs/libxfs/xfs_attr_leaf.c
>> index 023c616..07eee3ff 100644
>> --- a/fs/xfs/libxfs/xfs_attr_leaf.c
>> +++ b/fs/xfs/libxfs/xfs_attr_leaf.c
>> @@ -2802,10 +2802,7 @@ xfs_attr3_leaf_clearflag(
>>   			 XFS_DA_LOGRANGE(leaf, name_rmt, sizeof(*name_rmt)));
>>   	}
>>   
>> -	/*
>> -	 * Commit the flag value change and start the next trans in series.
>> -	 */
>> -	return xfs_trans_roll_inode(&args->trans, args->dp);
>> +	return error;
>>   }
>>   
>>   /*
>> -- 
>> 2.7.4
>>
> 

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

* Re: [PATCH v4 14/17] xfs: Add delay context to xfs_da_args
  2019-11-11 18:23   ` Brian Foster
@ 2019-11-11 23:42     ` Allison Collins
  0 siblings, 0 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-11 23:42 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 11/11/19 11:23 AM, Brian Foster wrote:
> On Wed, Nov 06, 2019 at 06:27:58PM -0700, Allison Collins wrote:
>> This patch adds a new struct xfs_delay_context, which we
>> will use to keep track of the current state of a delayed
>> attribute operation.
>>
> 
> Technically, this should track delayed or non-delayed attr operations,
> right? IIRC, the goal is that the difference between the two is that the
> former is driven by the dfops mechanism while the latter executes the
> same code with a higher level hack to roll transactions and loop through
> the state machine...
> 
> Brian

Yep, I will update the commit message.  Thanks!
Allison

> 
>> The new enum is used to track various operations that
>> are in progress so that we know not to repeat them, and
>> resume where we left off before EAGAIN was returned to
>> cycle out the transaction.  Other members take the place
>> of local variables that need to retain their values
>> across multiple function recalls.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_da_btree.h | 28 ++++++++++++++++++++++++++++
>>   fs/xfs/scrub/common.c        |  2 ++
>>   fs/xfs/xfs_acl.c             |  2 ++
>>   fs/xfs/xfs_attr_list.c       |  1 +
>>   fs/xfs/xfs_ioctl.c           |  2 ++
>>   fs/xfs/xfs_ioctl32.c         |  2 ++
>>   fs/xfs/xfs_iops.c            |  2 ++
>>   fs/xfs/xfs_xattr.c           |  1 +
>>   8 files changed, 40 insertions(+)
>>
>> diff --git a/fs/xfs/libxfs/xfs_da_btree.h b/fs/xfs/libxfs/xfs_da_btree.h
>> index bed4f40..ef23ed8 100644
>> --- a/fs/xfs/libxfs/xfs_da_btree.h
>> +++ b/fs/xfs/libxfs/xfs_da_btree.h
>> @@ -42,6 +42,33 @@ enum xfs_dacmp {
>>   	XFS_CMP_CASE		/* names are same but differ in case */
>>   };
>>   
>> +enum xfs_attr_state {
>> +	XFS_DC_INIT		= 1, /* Init delay info */
>> +	XFS_DC_SF_TO_LEAF	= 2, /* Converted short form to leaf */
>> +	XFS_DC_FOUND_LBLK	= 3, /* We found leaf blk for attr */
>> +	XFS_DC_LEAF_TO_NODE	= 4, /* Converted leaf to node */
>> +	XFS_DC_FOUND_NBLK	= 5, /* We found node blk for attr */
>> +	XFS_DC_ALLOC_LEAF	= 6, /* We are allocating leaf blocks */
>> +	XFS_DC_ALLOC_NODE	= 7, /* We are allocating node blocks */
>> +	XFS_DC_RM_INVALIDATE	= 8, /* We are invalidating blocks */
>> +	XFS_DC_RM_SHRINK	= 9, /* We are shrinking the tree */
>> +	XFS_DC_RM_NODE_BLKS	= 10,/* We are removing node blocks */
>> +};
>> +
>> +/*
>> + * Context used for keeping track of delayed attribute operations
>> + */
>> +struct xfs_delay_context {
>> +	enum xfs_attr_state	dc_state;
>> +	struct xfs_buf		*leaf_bp;
>> +	struct xfs_bmbt_irec	map;
>> +	xfs_dablk_t		lblkno;
>> +	xfs_fileoff_t		lfileoff;
>> +	int			blkcnt;
>> +	struct xfs_da_state	*da_state;
>> +	struct xfs_da_state_blk *blk;
>> +};
>> +
>>   /*
>>    * Structure to ease passing around component names.
>>    */
>> @@ -69,6 +96,7 @@ typedef struct xfs_da_args {
>>   	int		rmtvaluelen2;	/* remote attr value length in bytes */
>>   	int		op_flags;	/* operation flags */
>>   	enum xfs_dacmp	cmpresult;	/* name compare result for lookups */
>> +	struct xfs_delay_context  dc;	/* context used for delay attr ops */
>>   } xfs_da_args_t;
>>   
>>   /*
>> diff --git a/fs/xfs/scrub/common.c b/fs/xfs/scrub/common.c
>> index 1887605..9a649d1 100644
>> --- a/fs/xfs/scrub/common.c
>> +++ b/fs/xfs/scrub/common.c
>> @@ -24,6 +24,8 @@
>>   #include "xfs_rmap_btree.h"
>>   #include "xfs_log.h"
>>   #include "xfs_trans_priv.h"
>> +#include "xfs_da_format.h"
>> +#include "xfs_da_btree.h"
>>   #include "xfs_attr.h"
>>   #include "xfs_reflink.h"
>>   #include "scrub/scrub.h"
>> diff --git a/fs/xfs/xfs_acl.c b/fs/xfs/xfs_acl.c
>> index e868755..1336477 100644
>> --- a/fs/xfs/xfs_acl.c
>> +++ b/fs/xfs/xfs_acl.c
>> @@ -10,6 +10,8 @@
>>   #include "xfs_trans_resv.h"
>>   #include "xfs_mount.h"
>>   #include "xfs_inode.h"
>> +#include "xfs_da_format.h"
>> +#include "xfs_da_btree.h"
>>   #include "xfs_attr.h"
>>   #include "xfs_trace.h"
>>   #include <linux/posix_acl_xattr.h>
>> diff --git a/fs/xfs/xfs_attr_list.c b/fs/xfs/xfs_attr_list.c
>> index fab416c..e395864 100644
>> --- a/fs/xfs/xfs_attr_list.c
>> +++ b/fs/xfs/xfs_attr_list.c
>> @@ -12,6 +12,7 @@
>>   #include "xfs_trans_resv.h"
>>   #include "xfs_mount.h"
>>   #include "xfs_da_format.h"
>> +#include "xfs_da_btree.h"
>>   #include "xfs_inode.h"
>>   #include "xfs_trans.h"
>>   #include "xfs_bmap.h"
>> diff --git a/fs/xfs/xfs_ioctl.c b/fs/xfs/xfs_ioctl.c
>> index ae0ed88..23b0ca6 100644
>> --- a/fs/xfs/xfs_ioctl.c
>> +++ b/fs/xfs/xfs_ioctl.c
>> @@ -15,6 +15,8 @@
>>   #include "xfs_iwalk.h"
>>   #include "xfs_itable.h"
>>   #include "xfs_error.h"
>> +#include "xfs_da_format.h"
>> +#include "xfs_da_btree.h"
>>   #include "xfs_attr.h"
>>   #include "xfs_bmap.h"
>>   #include "xfs_bmap_util.h"
>> diff --git a/fs/xfs/xfs_ioctl32.c b/fs/xfs/xfs_ioctl32.c
>> index 3c0d518..e3278ac 100644
>> --- a/fs/xfs/xfs_ioctl32.c
>> +++ b/fs/xfs/xfs_ioctl32.c
>> @@ -17,6 +17,8 @@
>>   #include "xfs_itable.h"
>>   #include "xfs_fsops.h"
>>   #include "xfs_rtalloc.h"
>> +#include "xfs_da_format.h"
>> +#include "xfs_da_btree.h"
>>   #include "xfs_attr.h"
>>   #include "xfs_ioctl.h"
>>   #include "xfs_ioctl32.h"
>> diff --git a/fs/xfs/xfs_iops.c b/fs/xfs/xfs_iops.c
>> index aef346e..68b9cd0 100644
>> --- a/fs/xfs/xfs_iops.c
>> +++ b/fs/xfs/xfs_iops.c
>> @@ -13,6 +13,8 @@
>>   #include "xfs_inode.h"
>>   #include "xfs_acl.h"
>>   #include "xfs_quota.h"
>> +#include "xfs_da_format.h"
>> +#include "xfs_da_btree.h"
>>   #include "xfs_attr.h"
>>   #include "xfs_trans.h"
>>   #include "xfs_trace.h"
>> diff --git a/fs/xfs/xfs_xattr.c b/fs/xfs/xfs_xattr.c
>> index 6c5321d..0f0ebab 100644
>> --- a/fs/xfs/xfs_xattr.c
>> +++ b/fs/xfs/xfs_xattr.c
>> @@ -10,6 +10,7 @@
>>   #include "xfs_log_format.h"
>>   #include "xfs_da_format.h"
>>   #include "xfs_inode.h"
>> +#include "xfs_da_btree.h"
>>   #include "xfs_attr.h"
>>   
>>   #include <linux/posix_acl_xattr.h>
>> -- 
>> 2.7.4
>>
> 

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

* Re: [PATCH v4 15/17] xfs: Check for -ENOATTR or -EEXIST
  2019-11-11 18:24   ` Brian Foster
@ 2019-11-12  0:33     ` Allison Collins
  0 siblings, 0 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-12  0:33 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 11/11/19 11:24 AM, Brian Foster wrote:
> On Wed, Nov 06, 2019 at 06:27:59PM -0700, Allison Collins wrote:
>> Delayed operations cannot return error codes.  So we must check for
>> these conditions first before starting set or remove operations
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
>>   fs/xfs/libxfs/xfs_attr.c | 25 +++++++++++++++++++++++++
>>   1 file changed, 25 insertions(+)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 5dcb19f..626d4a98 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -458,6 +458,27 @@ xfs_attr_set(
>>   		goto out_trans_cancel;
>>   
>>   	xfs_trans_ijoin(args.trans, dp, 0);
>> +
>> +	error = xfs_has_attr(&args);
>> +	if (error == -EEXIST) {
>> +		if (name->type & ATTR_CREATE)
>> +			goto out_trans_cancel;
>> +		else
>> +			name->type |= ATTR_REPLACE;
>> +	}
>> +
>> +	if (error == -ENOATTR && (name->type & ATTR_REPLACE))
>> +		goto out_trans_cancel;
>> +
>> +	if (name->type & ATTR_REPLACE) {
>> +		name->type &= ~ATTR_REPLACE;
>> +		error = xfs_attr_remove_args(&args);
>> +		if (error)
>> +			goto out_trans_cancel;
>> +
>> +		name->type |= ATTR_CREATE;
>> +	}
>> +
> 
> I see Darrick already commented on this.. I think the behavior of the
> existing rename code is to essentially create the new xattr with the
> INCOMPLETE flag set so we can roll transactions, etc. without any
> observable behavior to userspace. Once the new xattr is fully in place,
> the rename is performed atomically from the userspace perspective by
> flipping the INCOMPLETE flag from the newly constructed xattr to the old
> one and we can then remove the old xattr from there.
Yes, I will add this logic in the next revision

> 
>>   	error = xfs_attr_set_args(&args);
>>   	if (error)
>>   		goto out_trans_cancel;
>> @@ -543,6 +564,10 @@ xfs_attr_remove(
>>   	 */
>>   	xfs_trans_ijoin(args.trans, dp, 0);
>>   
>> +	error = xfs_has_attr(&args);
>> +	if (error == -ENOATTR)
>> +		goto out;
>> +
> 
> Wouldn't we want to return any error that might occur here (except
> -EEXIST), not just -ENOATTR if there's actually no xattr?
> 
> Brian

Ok, I will change this to (error != -EEXIST)
Thanks for the reviews!

Allison


> 
>>   	error = xfs_attr_remove_args(&args);
>>   	if (error)
>>   		goto out;
>> -- 
>> 2.7.4
>>
> 

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

* Re: [PATCH v4 16/17] xfs: Add delay ready attr remove routines
  2019-11-07  1:28 ` [PATCH v4 16/17] xfs: Add delay ready attr remove routines Allison Collins
  2019-11-08 21:37   ` Darrick J. Wong
@ 2019-11-12 13:37   ` Brian Foster
  2019-11-13  0:43     ` Allison Collins
  1 sibling, 1 reply; 77+ messages in thread
From: Brian Foster @ 2019-11-12 13:37 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Wed, Nov 06, 2019 at 06:28:00PM -0700, Allison Collins wrote:
> This patch modifies the attr remove routines to be delay ready.
> This means they no longer roll or commit transactions, but instead
> return -EAGAIN to have the calling routine roll and refresh the
> transaction.  In this series, xfs_attr_remove_args has become
> xfs_attr_remove_later, which uses a state machine to keep track
> of where it was when EAGAIN was returned.  xfs_attr_node_removename
> has also been modified to use the state machine, and a  new version of
> xfs_attr_remove_args consists of a simple loop to refresh the
> transaction until the operation is completed.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---

On a cursory look, this is definitely more along the lines of what I was
thinking on the previous revisions. I would like to see if we can get a
bit more refactoring/cleanup before this point though. Further thoughts
inline..

>  fs/xfs/libxfs/xfs_attr.c | 123 +++++++++++++++++++++++++++++++++++++++--------
>  fs/xfs/libxfs/xfs_attr.h |   1 +
>  2 files changed, 104 insertions(+), 20 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 626d4a98..38d5c5c 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -369,10 +369,56 @@ xfs_has_attr(
>   */
>  int
>  xfs_attr_remove_args(
> +	struct xfs_da_args	*args)
> +{
> +	int			error = 0;
> +	int			err2 = 0;
> +
> +	do {
> +		error = xfs_attr_remove_later(args);
> +		if (error && error != -EAGAIN)
> +			goto out;

xfs_attr_remove_later() strikes me as an odd name with respect to the
functionality. Perhaps something like xfs_attr_remove_step() is
(slightly) more accurate..?

> +
> +		xfs_trans_log_inode(args->trans, args->dp,
> +			XFS_ILOG_CORE | XFS_ILOG_ADATA);
> +
> +		err2 = xfs_trans_roll(&args->trans);
> +		if (err2) {
> +			error = err2;

Also do we really need two error codes in this function? It seems like
we should be able to write this with one, but I haven't tried it..

> +			goto out;
> +		}
> +
> +		/* Rejoin inode */
> +		xfs_trans_ijoin(args->trans, args->dp, 0);
> +
> +	} while (error == -EAGAIN);
> +out:
> +	return error;
> +}
> +
> +/*
> + * Remove the attribute specified in @args.
> + * This routine is meant to function as a delayed operation, and may return
> + * -EGAIN when the transaction needs to be rolled.  Calling functions will need
> + * to handle this, and recall the function until a successful error code is
> + * returned.
> + */
> +int
> +xfs_attr_remove_later(
>  	struct xfs_da_args      *args)
>  {
>  	struct xfs_inode	*dp = args->dp;
> -	int			error;
> +	int			error = 0;
> +
> +	/* State machine switch */
> +	switch (args->dc.dc_state) {
> +	case XFS_DC_RM_INVALIDATE:
> +	case XFS_DC_RM_SHRINK:
> +	case XFS_DC_RM_NODE_BLKS:
> +		goto node;
> +	default:
> +		break;
> +	}
>  
>  	if (!xfs_inode_hasattr(dp)) {
>  		error = -ENOATTR;
> @@ -382,6 +428,7 @@ xfs_attr_remove_args(
>  	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>  		error = xfs_attr_leaf_removename(args);
>  	} else {
> +node:
>  		error = xfs_attr_node_removename(args);
>  	}
>  
> @@ -892,9 +939,6 @@ xfs_attr_leaf_removename(
>  		/* bp is gone due to xfs_da_shrink_inode */
>  		if (error)
>  			return error;
> -		error = xfs_defer_finish(&args->trans);
> -		if (error)
> -			return error;
>  	}
>  	return 0;
>  }
> @@ -1212,6 +1256,11 @@ xfs_attr_node_addname(
>   * This will involve walking down the Btree, and may involve joining
>   * leaf nodes and even joining intermediate nodes up to and including
>   * the root node (a special case of an intermediate node).
> + *
> + * This routine is meant to function as a delayed operation, and may return
> + * -EAGAIN when the transaction needs to be rolled.  Calling functions
> + * will need to handle this, and recall the function until a successful error
> + * code is returned.
>   */
>  STATIC int
>  xfs_attr_node_removename(
> @@ -1222,12 +1271,29 @@ xfs_attr_node_removename(
>  	struct xfs_buf		*bp;
>  	int			retval, error, forkoff;
>  	struct xfs_inode	*dp = args->dp;
> +	int			done = 0;
>  
>  	trace_xfs_attr_node_removename(args);
> +	state = args->dc.da_state;
> +	blk = args->dc.blk;
> +
> +	/* State machine switch */
> +	switch (args->dc.dc_state) {
> +	case XFS_DC_RM_NODE_BLKS:
> +		goto rm_node_blks;
> +	case XFS_DC_RM_INVALIDATE:
> +		goto rm_invalidate;
> +	case XFS_DC_RM_SHRINK:
> +		goto rm_shrink;
> +	default:
> +		break;

I wonder if it's worth having an explicit state for the initial path.
That could be useful for readability and debuggability in the future.

> +	}
>  
>  	error = xfs_attr_node_hasname(args, &state);
>  	if (error != -EEXIST)
>  		goto out;
> +	else
> +		error = 0;
>  
>  	/*
>  	 * If there is an out-of-line value, de-allocate the blocks.
> @@ -1237,6 +1303,14 @@ xfs_attr_node_removename(
>  	blk = &state->path.blk[ state->path.active-1 ];
>  	ASSERT(blk->bp != NULL);
>  	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> +
> +	/*
> +	 * Store blk and state in the context incase we need to cycle out the
> +	 * transaction
> +	 */
> +	args->dc.blk = blk;
> +	args->dc.da_state = state;
> +
>  	if (args->rmtblkno > 0) {
>  		/*
>  		 * Fill in disk block numbers in the state structure
> @@ -1255,13 +1329,30 @@ xfs_attr_node_removename(
>  		if (error)
>  			goto out;
>  
> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
> +		args->dc.dc_state = XFS_DC_RM_INVALIDATE;
> +		return -EAGAIN;
> +rm_invalidate:
> +		error = xfs_attr_rmtval_invalidate(args);
>  		if (error)
>  			goto out;
> +rm_node_blks:

While I think the design is the right idea, jumping down into a function
like this is pretty hairy. I think we should try to further break this
function down into smaller elements one way or another that model the
steps defined by the state structure. There's probably multiple ways to
do that. For example, the remote attr bits could be broken down into
a subfunction that processes the couple of states associated with remote
blocks. That said, ISTM it might be wiser to try and keep the state
processing in one place if possible. That would imply to break the
remote processing loop down into a couple functions. All in all, this
function might end up looking something like:

xfs_attr_node_removename()
{
	/* switch statement and comment to document each state */

	error = xfs_attr_node_hasname(args, &state);
	...

	if (remote) {
		error = do_setflag();
		if (error)
			return error;

		/* roll */
		state = INVALIDATE;
		return -EAGAIN;
	}

rmt_invalidate:
	state = INVALIDATE;
	if (remote)
		do_invalidate();
	/* fallthru */

rmt_rm_blks:
	state = RM_NODE_BLKS;
	if (remote) {
		/* loops and returns -EAGAIN until we fallthru */
		error = rmt_remove_step();
		if (error)
			return error;

		xfs_attr_refillstate();
	}

/* maybe worth a new state here? */
removename:
	state = REMOVENAME;
	xfs_attr3_leaf_remove();
	...
	if (...) {
		state = SHRINK;
		return -EAGAIN;
	}

shrink:
	state = SHRINK;
	error = do_shrink();

	return 0;
}

I'm not totally sold on the idea of rolling the state forward explicitly
like this, but it seems like it could be a bit more maintainable. All in
all this is still fairly ugly, but this is mostly a mechanical attempt
to keep state management isolated and we can polish it up from there.
Thoughts?

Brian

> +		/*
> +		 * Unmap value blocks for this attr.  This is similar to
> +		 * xfs_attr_rmtval_remove, but open coded here to return EAGAIN
> +		 * for new transactions
> +		 */
> +		while (!done && !error) {
> +			error = xfs_bunmapi(args->trans, args->dp,
> +				    args->rmtblkno, args->rmtblkcnt,
> +				    XFS_BMAPI_ATTRFORK, 1, &done);
> +			if (error)
> +				return error;
>  
> -		error = xfs_attr_rmtval_remove(args);
> -		if (error)
> -			goto out;
> +			if (!done) {
> +				args->dc.dc_state = XFS_DC_RM_NODE_BLKS;
> +				return -EAGAIN;
> +			}
> +		}
>  
>  		/*
>  		 * Refill the state structure with buffers, the prior calls
> @@ -1287,17 +1378,12 @@ xfs_attr_node_removename(
>  		error = xfs_da3_join(state);
>  		if (error)
>  			goto out;
> -		error = xfs_defer_finish(&args->trans);
> -		if (error)
> -			goto out;
> -		/*
> -		 * Commit the Btree join operation and start a new trans.
> -		 */
> -		error = xfs_trans_roll_inode(&args->trans, dp);
> -		if (error)
> -			goto out;
> +
> +		args->dc.dc_state = XFS_DC_RM_SHRINK;
> +		return -EAGAIN;
>  	}
>  
> +rm_shrink:
>  	/*
>  	 * If the result is small enough, push it all into the inode.
>  	 */
> @@ -1319,9 +1405,6 @@ xfs_attr_node_removename(
>  			/* bp is gone due to xfs_da_shrink_inode */
>  			if (error)
>  				goto out;
> -			error = xfs_defer_finish(&args->trans);
> -			if (error)
> -				goto out;
>  		} else
>  			xfs_trans_brelse(args->trans, bp);
>  	}
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index 3b5dad4..fb8bf5b 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -152,6 +152,7 @@ int xfs_attr_set_args(struct xfs_da_args *args);
>  int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
>  int xfs_has_attr(struct xfs_da_args *args);
>  int xfs_attr_remove_args(struct xfs_da_args *args);
> +int xfs_attr_remove_later(struct xfs_da_args *args);
>  int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>  		  int flags, struct attrlist_cursor_kern *cursor);
>  bool xfs_attr_namecheck(const void *name, size_t length);
> -- 
> 2.7.4
> 


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

* Re: [PATCH v4 17/17] xfs: Add delay ready attr set routines
  2019-11-07  1:28 ` [PATCH v4 17/17] xfs: Add delay ready attr set routines Allison Collins
  2019-11-08 21:42   ` Darrick J. Wong
@ 2019-11-12 13:37   ` Brian Foster
  2019-11-13  4:57     ` Allison Collins
  1 sibling, 1 reply; 77+ messages in thread
From: Brian Foster @ 2019-11-12 13:37 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Wed, Nov 06, 2019 at 06:28:01PM -0700, Allison Collins wrote:
> This patch modifies the attr set routines to be delay ready.
> This means they no longer roll or commit transactions, but instead
> return -EAGAIN to have the calling routine roll and refresh the
> transaction.  In this series, xfs_attr_set_args has become
> xfs_attr_set_later, which uses a state machine to keep track
> of where it was when EAGAIN was returned.  Part of
> xfs_attr_leaf_addname has been factored out into a new helper
> function xfs_attr_leaf_try_add to allow transaction cycling between
> the two routines, and the flipflags logic has been removed since we
> can simply cancel the transaction upon error.  xfs_attr_set_args
> consists of a simple loop to refresh the transaction until the
> operation is completed.
> 
> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> ---

Pretty much the same fundamental comments here as for the remove patch.
Can we break things down further to avoid much of the jumping into if
branch behavior and such? I also wonder if it might be possible to split
this one up into smaller patches to fix up the leaf/node paths
separately, but additional prep refactoring might simplify things enough
on its own to make that unnecessary..

Brian

>  fs/xfs/libxfs/xfs_attr.c | 435 +++++++++++++++++++++++------------------------
>  fs/xfs/libxfs/xfs_attr.h |   1 +
>  2 files changed, 211 insertions(+), 225 deletions(-)
> 
> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> index 38d5c5c..97e5ae0 100644
> --- a/fs/xfs/libxfs/xfs_attr.c
> +++ b/fs/xfs/libxfs/xfs_attr.c
> @@ -58,6 +58,7 @@ STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
>  				 struct xfs_da_state **state);
>  STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
>  STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
> +STATIC int xfs_attr_leaf_try_add(struct xfs_da_args *args, struct xfs_buf *bp);
>  
>  
>  STATIC int
> @@ -250,9 +251,79 @@ int
>  xfs_attr_set_args(
>  	struct xfs_da_args	*args)
>  {
> +	int			error = 0;
> +	int			err2 = 0;
> +	struct xfs_buf		*leaf_bp = NULL;
> +
> +	do {
> +		error = xfs_attr_set_later(args, &leaf_bp);
> +		if (error && error != -EAGAIN)
> +			goto out;
> +
> +		xfs_trans_log_inode(args->trans, args->dp,
> +				    XFS_ILOG_CORE | XFS_ILOG_ADATA);
> +
> +		err2 = xfs_trans_roll(&args->trans);
> +		if (err2) {
> +			error = err2;
> +			goto out;
> +		}
> +
> +		/* Rejoin inode and leaf if needed */
> +		xfs_trans_ijoin(args->trans, args->dp, 0);
> +		if (leaf_bp) {
> +			xfs_trans_bjoin(args->trans, leaf_bp);
> +			xfs_trans_bhold(args->trans, leaf_bp);
> +		}
> +
> +	} while (error == -EAGAIN);
> +
> +out:
> +	return error;
> +}
> +
> +/*
> + * Set the attribute specified in @args.
> + * This routine is meant to function as a delayed operation, and may return
> + * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
> + * to handle this, and recall the function until a successful error code is
> + * returned.
> + */
> +int
> +xfs_attr_set_later(
> +	struct xfs_da_args	*args,
> +	struct xfs_buf          **leaf_bp)
> +{
>  	struct xfs_inode	*dp = args->dp;
> -	struct xfs_buf          *leaf_bp = NULL;
> -	int			error, error2 = 0;;
> +	int			error = 0;
> +	int			sf_size;
> +
> +	/* State machine switch */
> +	switch (args->dc.dc_state) {
> +	case XFS_DC_SF_TO_LEAF:
> +		goto sf_to_leaf;
> +	case XFS_DC_ALLOC_LEAF:
> +	case XFS_DC_FOUND_LBLK:
> +		goto leaf;
> +	case XFS_DC_FOUND_NBLK:
> +	case XFS_DC_ALLOC_NODE:
> +	case XFS_DC_LEAF_TO_NODE:
> +		goto node;
> +	default:
> +		break;
> +	}
> +
> +	/*
> +	 * New inodes may not have an attribute fork yet. So set the attribute
> +	 * fork appropriately
> +	 */
> +	if (XFS_IFORK_Q((args->dp)) == 0) {
> +		sf_size = sizeof(struct xfs_attr_sf_hdr) +
> +		     XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
> +		xfs_bmap_set_attrforkoff(args->dp, sf_size, NULL);
> +		args->dp->i_afp = kmem_zone_zalloc(xfs_ifork_zone, 0);
> +		args->dp->i_afp->if_flags = XFS_IFEXTENTS;
> +	}
>  
>  	/*
>  	 * If the attribute list is non-existent or a shortform list,
> @@ -272,21 +343,14 @@ xfs_attr_set_args(
>  		 * Try to add the attr to the attribute list in the inode.
>  		 */
>  		error = xfs_attr_try_sf_addname(dp, args);
> -		if (error != -ENOSPC) {
> -			if (dp->i_mount->m_flags & XFS_MOUNT_WSYNC)
> -				xfs_trans_set_sync(args->trans);
> -
> -			error2 = xfs_trans_commit(args->trans);
> -			args->trans = NULL;
> -			return error ? error : error2;
> -		}
> -
> +		if (error != -ENOSPC)
> +			return error;
>  
>  		/*
>  		 * It won't fit in the shortform, transform to a leaf block.
>  		 * GROT: another possible req'mt for a double-split btree op.
>  		 */
> -		error = xfs_attr_shortform_to_leaf(args, &leaf_bp);
> +		error = xfs_attr_shortform_to_leaf(args, leaf_bp);
>  		if (error)
>  			return error;
>  
> @@ -294,43 +358,42 @@ xfs_attr_set_args(
>  		 * Prevent the leaf buffer from being unlocked so that a
>  		 * concurrent AIL push cannot grab the half-baked leaf
>  		 * buffer and run into problems with the write verifier.
> -		 * Once we're done rolling the transaction we can release
> -		 * the hold and add the attr to the leaf.
>  		 */
> -		xfs_trans_bhold(args->trans, leaf_bp);
> -		error = xfs_defer_finish(&args->trans);
> -		xfs_trans_bhold_release(args->trans, leaf_bp);
> -		if (error) {
> -			xfs_trans_brelse(args->trans, leaf_bp);
> -			return error;
> -		}
> +
> +		xfs_trans_bhold(args->trans, *leaf_bp);
> +		args->dc.dc_state = XFS_DC_SF_TO_LEAF;
> +		return -EAGAIN;
> +	}
> +sf_to_leaf:
> +
> +	/*
> +	 * After a shortform to leaf conversion, we need to hold the leaf and
> +	 * cylce out the transaction.  When we get back, we need to release
> +	 * the leaf.
> +	 */
> +	if (*leaf_bp != NULL) {
> +		xfs_trans_brelse(args->trans, *leaf_bp);
> +		*leaf_bp = NULL;
>  	}
>  
>  	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> +		error = xfs_attr_leaf_try_add(args, *leaf_bp);
> +		if (error == -ENOSPC)
> +			args->dc.dc_state = XFS_DC_LEAF_TO_NODE;
> +		else if (error)
> +			return error;
> +		else
> +			args->dc.dc_state = XFS_DC_FOUND_LBLK;
> +		return -EAGAIN;
> +leaf:
>  		error = xfs_attr_leaf_addname(args);
>  		if (error == -ENOSPC) {
> -			/*
> -			 * Commit that transaction so that the node_addname()
> -			 * call can manage its own transactions.
> -			 */
> -			error = xfs_defer_finish(&args->trans);
> -			if (error)
> -				return error;
> -
> -			/*
> -			 * Commit the current trans (including the inode) and
> -			 * start a new one.
> -			 */
> -			error = xfs_trans_roll_inode(&args->trans, dp);
> -			if (error)
> -				return error;
> -
> -			/*
> -			 * Fob the rest of the problem off on the Btree code.
> -			 */
> -			error = xfs_attr_node_addname(args);
> +			args->dc.dc_state = XFS_DC_LEAF_TO_NODE;
> +			return -EAGAIN;
>  		}
>  	} else {
> +		args->dc.dc_state = XFS_DC_LEAF_TO_NODE;
> +node:
>  		error = xfs_attr_node_addname(args);
>  	}
>  	return error;
> @@ -764,27 +827,26 @@ xfs_attr_leaf_try_add(
>   *
>   * This leaf block cannot have a "remote" value, we only call this routine
>   * if bmap_one_block() says there is only one block (ie: no remote blks).
> + *
> + * This routine is meant to function as a delayed operation, and may return
> + * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
> + * to handle this, and recall the function until a successful error code is
> + * returned.
>   */
>  STATIC int
>  xfs_attr_leaf_addname(struct xfs_da_args	*args)
>  {
> -	int			error, forkoff;
> -	struct xfs_buf		*bp = NULL;
> +	int			error, nmap;
>  	struct xfs_inode	*dp = args->dp;
> +	struct xfs_bmbt_irec	*map = &args->dc.map;
>  
> -	trace_xfs_attr_leaf_addname(args);
> -
> -	error = xfs_attr_leaf_try_add(args, bp);
> -	if (error)
> -		return error;
> -
> -	/*
> -	 * Commit the transaction that added the attr name so that
> -	 * later routines can manage their own transactions.
> -	 */
> -	error = xfs_trans_roll_inode(&args->trans, dp);
> -	if (error)
> -		return error;
> +	/* State machine switch */
> +	switch (args->dc.dc_state) {
> +	case XFS_DC_ALLOC_LEAF:
> +		goto alloc_leaf;
> +	default:
> +		break;
> +	}
>  
>  	/*
>  	 * If there was an out-of-line value, allocate the blocks we
> @@ -793,90 +855,58 @@ xfs_attr_leaf_addname(struct xfs_da_args	*args)
>  	 * maximum size of a transaction and/or hit a deadlock.
>  	 */
>  	if (args->rmtblkno > 0) {
> -		error = xfs_attr_rmtval_set(args);
> -		if (error)
> -			return error;
> -	}
>  
> -	/*
> -	 * If this is an atomic rename operation, we must "flip" the
> -	 * incomplete flags on the "new" and "old" attribute/value pairs
> -	 * so that one disappears and one appears atomically.  Then we
> -	 * must remove the "old" attribute/value pair.
> -	 */
> -	if (args->op_flags & XFS_DA_OP_RENAME) {
> -		/*
> -		 * In a separate transaction, set the incomplete flag on the
> -		 * "old" attr and clear the incomplete flag on the "new" attr.
> -		 */
> -		error = xfs_attr3_leaf_flipflags(args);
> -		if (error)
> -			return error;
> -		/*
> -		 * Commit the flag value change and start the next trans in
> -		 * series.
> -		 */
> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
> -		if (error)
> -			return error;
> +		/* Open coded xfs_attr_rmtval_set without trans handling */
>  
> -		/*
> -		 * Dismantle the "old" attribute/value pair by removing
> -		 * a "remote" value (if it exists).
> -		 */
> -		args->index = args->index2;
> -		args->blkno = args->blkno2;
> -		args->rmtblkno = args->rmtblkno2;
> -		args->rmtblkcnt = args->rmtblkcnt2;
> -		args->rmtvaluelen = args->rmtvaluelen2;
> -		if (args->rmtblkno) {
> -			error = xfs_attr_rmtval_remove(args);
> -			if (error)
> -				return error;
> -		}
> +		args->dc.lfileoff = 0;
> +		args->dc.lblkno = 0;
> +		args->dc.blkcnt = 0;
> +		args->rmtblkcnt = 0;
> +		args->rmtblkno = 0;
> +		memset(map, 0, sizeof(struct xfs_bmbt_irec));
>  
> -		/*
> -		 * Read in the block containing the "old" attr, then
> -		 * remove the "old" attr from that block (neat, huh!)
> -		 */
> -		error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
> -					   XFS_DABUF_MAP_NOMAPPING, &bp);
> +		error = xfs_attr_rmt_find_hole(args);
>  		if (error)
>  			return error;
>  
> -		xfs_attr3_leaf_remove(bp, args);
> +		args->dc.blkcnt = args->rmtblkcnt;
> +		args->dc.lblkno = args->rmtblkno;
>  
>  		/*
> -		 * If the result is small enough, shrink it all into the inode.
> +		 * Roll through the "value", allocating blocks on disk as
> +		 * required.
>  		 */
> -		if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
> -			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
> -			/* bp is gone due to xfs_da_shrink_inode */
> -			if (error)
> -				return error;
> -			error = xfs_defer_finish(&args->trans);
> +alloc_leaf:
> +		while (args->dc.blkcnt > 0) {
> +			nmap = 1;
> +			error = xfs_bmapi_write(args->trans, dp,
> +				  (xfs_fileoff_t)args->dc.lblkno,
> +				  args->dc.blkcnt, XFS_BMAPI_ATTRFORK,
> +				  args->total, map, &nmap);
>  			if (error)
>  				return error;
> -		}
> +			ASSERT(nmap == 1);
> +			ASSERT((map->br_startblock != DELAYSTARTBLOCK) &&
> +			       (map->br_startblock != HOLESTARTBLOCK));
>  
> -		/*
> -		 * Commit the remove and start the next trans in series.
> -		 */
> -		error = xfs_trans_roll_inode(&args->trans, dp);
> +			/* roll attribute extent map forwards */
> +			args->dc.lblkno += map->br_blockcount;
> +			args->dc.blkcnt -= map->br_blockcount;
>  
> -	} else if (args->rmtblkno > 0) {
> -		/*
> -		 * Added a "remote" value, just clear the incomplete flag.
> -		 */
> -		error = xfs_attr3_leaf_clearflag(args);
> +			args->dc.dc_state = XFS_DC_ALLOC_LEAF;
> +			return -EAGAIN;
> +		}
> +
> +		error = xfs_attr_rmtval_set_value(args);
>  		if (error)
>  			return error;
> +	}
>  
> +	if (args->rmtblkno > 0) {
>  		/*
> -		 * Commit the flag value change and start the next trans in
> -		 * series.
> +		 * Added a "remote" value, just clear the incomplete flag.
>  		 */
> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
> +		error = xfs_attr3_leaf_clearflag(args);
>  	}
>  	return error;
>  }
> @@ -1017,16 +1047,23 @@ xfs_attr_node_hasname(
>   *
>   * "Remote" attribute values confuse the issue and atomic rename operations
>   * add a whole extra layer of confusion on top of that.
> + *
> + * This routine is meant to function as a delayed operation, and may return
> + * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
> + * to handle this, and recall the function until a successful error code is
> + *returned.
>   */
>  STATIC int
>  xfs_attr_node_addname(
>  	struct xfs_da_args	*args)
>  {
> -	struct xfs_da_state	*state;
> +	struct xfs_da_state	*state = NULL;
>  	struct xfs_da_state_blk	*blk;
>  	struct xfs_inode	*dp;
> -	struct xfs_mount	*mp;
> -	int			retval, error;
> +	int			retval = 0;
> +	int			error = 0;
> +	int			nmap;
> +	struct xfs_bmbt_irec    *map = &args->dc.map;
>  
>  	trace_xfs_attr_node_addname(args);
>  
> @@ -1034,8 +1071,17 @@ xfs_attr_node_addname(
>  	 * Fill in bucket of arguments/results/context to carry around.
>  	 */
>  	dp = args->dp;
> -	mp = dp->i_mount;
> -restart:
> +
> +	/* State machine switch */
> +	switch (args->dc.dc_state) {
> +	case XFS_DC_FOUND_NBLK:
> +		goto found_nblk;
> +	case XFS_DC_ALLOC_NODE:
> +		goto alloc_node;
> +	default:
> +		break;
> +	}
> +
>  	/*
>  	 * Search to see if name already exists, and get back a pointer
>  	 * to where it should go.
> @@ -1085,19 +1131,12 @@ xfs_attr_node_addname(
>  			error = xfs_attr3_leaf_to_node(args);
>  			if (error)
>  				goto out;
> -			error = xfs_defer_finish(&args->trans);
> -			if (error)
> -				goto out;
>  
>  			/*
> -			 * Commit the node conversion and start the next
> -			 * trans in the chain.
> +			 * Restart routine from the top.  No need to set  the
> +			 * state
>  			 */
> -			error = xfs_trans_roll_inode(&args->trans, dp);
> -			if (error)
> -				goto out;
> -
> -			goto restart;
> +			return -EAGAIN;
>  		}
>  
>  		/*
> @@ -1109,9 +1148,6 @@ xfs_attr_node_addname(
>  		error = xfs_da3_split(state);
>  		if (error)
>  			goto out;
> -		error = xfs_defer_finish(&args->trans);
> -		if (error)
> -			goto out;
>  	} else {
>  		/*
>  		 * Addition succeeded, update Btree hashvals.
> @@ -1126,13 +1162,9 @@ xfs_attr_node_addname(
>  	xfs_da_state_free(state);
>  	state = NULL;
>  
> -	/*
> -	 * Commit the leaf addition or btree split and start the next
> -	 * trans in the chain.
> -	 */
> -	error = xfs_trans_roll_inode(&args->trans, dp);
> -	if (error)
> -		goto out;
> +	args->dc.dc_state = XFS_DC_FOUND_NBLK;
> +	return -EAGAIN;
> +found_nblk:
>  
>  	/*
>  	 * If there was an out-of-line value, allocate the blocks we
> @@ -1141,104 +1173,57 @@ xfs_attr_node_addname(
>  	 * maximum size of a transaction and/or hit a deadlock.
>  	 */
>  	if (args->rmtblkno > 0) {
> -		error = xfs_attr_rmtval_set(args);
> -		if (error)
> -			return error;
> -	}
> +		/* Open coded xfs_attr_rmtval_set without trans handling */
> +		args->dc.lblkno = 0;
> +		args->dc.lfileoff = 0;
> +		args->dc.blkcnt = 0;
> +		args->rmtblkcnt = 0;
> +		args->rmtblkno = 0;
> +		memset(map, 0, sizeof(struct xfs_bmbt_irec));
>  
> -	/*
> -	 * If this is an atomic rename operation, we must "flip" the
> -	 * incomplete flags on the "new" and "old" attribute/value pairs
> -	 * so that one disappears and one appears atomically.  Then we
> -	 * must remove the "old" attribute/value pair.
> -	 */
> -	if (args->op_flags & XFS_DA_OP_RENAME) {
> -		/*
> -		 * In a separate transaction, set the incomplete flag on the
> -		 * "old" attr and clear the incomplete flag on the "new" attr.
> -		 */
> -		error = xfs_attr3_leaf_flipflags(args);
> -		if (error)
> -			goto out;
> -		/*
> -		 * Commit the flag value change and start the next trans in
> -		 * series
> -		 */
> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
> +		error = xfs_attr_rmt_find_hole(args);
>  		if (error)
> -			goto out;
> +			return error;
>  
> +		args->dc.blkcnt = args->rmtblkcnt;
> +		args->dc.lblkno = args->rmtblkno;
>  		/*
> -		 * Dismantle the "old" attribute/value pair by removing
> -		 * a "remote" value (if it exists).
> +		 * Roll through the "value", allocating blocks on disk as
> +		 * required.
>  		 */
> -		args->index = args->index2;
> -		args->blkno = args->blkno2;
> -		args->rmtblkno = args->rmtblkno2;
> -		args->rmtblkcnt = args->rmtblkcnt2;
> -		args->rmtvaluelen = args->rmtvaluelen2;
> -		if (args->rmtblkno) {
> -			error = xfs_attr_rmtval_remove(args);
> +alloc_node:
> +		while (args->dc.blkcnt > 0) {
> +			nmap = 1;
> +			error = xfs_bmapi_write(args->trans, dp,
> +				(xfs_fileoff_t)args->dc.lblkno, args->dc.blkcnt,
> +				XFS_BMAPI_ATTRFORK, args->total, map, &nmap);
>  			if (error)
>  				return error;
> -		}
>  
> -		/*
> -		 * Re-find the "old" attribute entry after any split ops.
> -		 * The INCOMPLETE flag means that we will find the "old"
> -		 * attr, not the "new" one.
> -		 */
> -		args->name.type |= XFS_ATTR_INCOMPLETE;
> -		state = xfs_da_state_alloc();
> -		state->args = args;
> -		state->mp = mp;
> -		state->inleaf = 0;
> -		error = xfs_da3_node_lookup_int(state, &retval);
> -		if (error)
> -			goto out;
> +			ASSERT(nmap == 1);
> +			ASSERT((map->br_startblock != DELAYSTARTBLOCK) &&
> +			       (map->br_startblock != HOLESTARTBLOCK));
>  
> -		/*
> -		 * Remove the name and update the hashvals in the tree.
> -		 */
> -		blk = &state->path.blk[ state->path.active-1 ];
> -		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> -		error = xfs_attr3_leaf_remove(blk->bp, args);
> -		xfs_da3_fixhashpath(state, &state->path);
> +			/* roll attribute extent map forwards */
> +			args->dc.lblkno += map->br_blockcount;
> +			args->dc.blkcnt -= map->br_blockcount;
>  
> -		/*
> -		 * Check to see if the tree needs to be collapsed.
> -		 */
> -		if (retval && (state->path.active > 1)) {
> -			error = xfs_da3_join(state);
> -			if (error)
> -				goto out;
> -			error = xfs_defer_finish(&args->trans);
> -			if (error)
> -				goto out;
> +			args->dc.dc_state = XFS_DC_ALLOC_NODE;
> +			return -EAGAIN;
>  		}
>  
> -		/*
> -		 * Commit and start the next trans in the chain.
> -		 */
> -		error = xfs_trans_roll_inode(&args->trans, dp);
> +		error = xfs_attr_rmtval_set_value(args);
>  		if (error)
> -			goto out;
> +			return error;
> +	}
>  
> -	} else if (args->rmtblkno > 0) {
> +	if (args->rmtblkno > 0) {
>  		/*
>  		 * Added a "remote" value, just clear the incomplete flag.
>  		 */
>  		error = xfs_attr3_leaf_clearflag(args);
>  		if (error)
>  			goto out;
> -
> -		 /*
> -		  * Commit the flag value change and start the next trans in
> -		  * series.
> -		  */
> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
> -		if (error)
> -			goto out;
>  	}
>  	retval = error = 0;
>  
> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> index fb8bf5b..c710387 100644
> --- a/fs/xfs/libxfs/xfs_attr.h
> +++ b/fs/xfs/libxfs/xfs_attr.h
> @@ -149,6 +149,7 @@ int xfs_attr_get(struct xfs_inode *ip, struct xfs_name *name,
>  int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
>  		 unsigned char *value, int valuelen, int flags);
>  int xfs_attr_set_args(struct xfs_da_args *args);
> +int xfs_attr_set_later(struct xfs_da_args *args, struct xfs_buf **leaf_bp);
>  int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
>  int xfs_has_attr(struct xfs_da_args *args);
>  int xfs_attr_remove_args(struct xfs_da_args *args);
> -- 
> 2.7.4
> 


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

* Re: [PATCH v4 16/17] xfs: Add delay ready attr remove routines
  2019-11-12 13:37   ` Brian Foster
@ 2019-11-13  0:43     ` Allison Collins
  2019-11-13 11:54       ` Brian Foster
  0 siblings, 1 reply; 77+ messages in thread
From: Allison Collins @ 2019-11-13  0:43 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 11/12/19 6:37 AM, Brian Foster wrote:
> On Wed, Nov 06, 2019 at 06:28:00PM -0700, Allison Collins wrote:
>> This patch modifies the attr remove routines to be delay ready.
>> This means they no longer roll or commit transactions, but instead
>> return -EAGAIN to have the calling routine roll and refresh the
>> transaction.  In this series, xfs_attr_remove_args has become
>> xfs_attr_remove_later, which uses a state machine to keep track
>> of where it was when EAGAIN was returned.  xfs_attr_node_removename
>> has also been modified to use the state machine, and a  new version of
>> xfs_attr_remove_args consists of a simple loop to refresh the
>> transaction until the operation is completed.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
> 
> On a cursory look, this is definitely more along the lines of what I was
> thinking on the previous revisions. I would like to see if we can get a
> bit more refactoring/cleanup before this point though. Further thoughts
> inline..
> 
>>   fs/xfs/libxfs/xfs_attr.c | 123 +++++++++++++++++++++++++++++++++++++++--------
>>   fs/xfs/libxfs/xfs_attr.h |   1 +
>>   2 files changed, 104 insertions(+), 20 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 626d4a98..38d5c5c 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -369,10 +369,56 @@ xfs_has_attr(
>>    */
>>   int
>>   xfs_attr_remove_args(
>> +	struct xfs_da_args	*args)
>> +{
>> +	int			error = 0;
>> +	int			err2 = 0;
>> +
>> +	do {
>> +		error = xfs_attr_remove_later(args);
>> +		if (error && error != -EAGAIN)
>> +			goto out;
> 
> xfs_attr_remove_later() strikes me as an odd name with respect to the
> functionality. Perhaps something like xfs_attr_remove_step() is
> (slightly) more accurate..?
Sure that's fine.  I think Darrick had proposed the *_later scheme in an 
earlier review but that was when the code paths were split.  Darrick, 
does the *_step scheme work for you?

> 
>> +
>> +		xfs_trans_log_inode(args->trans, args->dp,
>> +			XFS_ILOG_CORE | XFS_ILOG_ADATA);
>> +
>> +		err2 = xfs_trans_roll(&args->trans);
>> +		if (err2) {
>> +			error = err2;
> 
> Also do we really need two error codes in this function? It seems like
> we should be able to write this with one, but I haven't tried it..
No, because then we'll loose the xfs_attr_remove_later return code, 
which is either 0 or EAGAIN at this point.  And we need that to drive 
the loop.  To get rid of err2, we'd need another "not_done" variable or 
something.  Like:

do {
	...
	not_done = (error == -EAGAIN);
	...
} while (not_done)


Not sure if not_done is really preferable to err2?

> 
>> +			goto out;
>> +		}
>> +
>> +		/* Rejoin inode */
>> +		xfs_trans_ijoin(args->trans, args->dp, 0);
>> +
>> +	} while (error == -EAGAIN);
>> +out:
>> +	return error;
>> +}
>> +
>> +/*
>> + * Remove the attribute specified in @args.
>> + * This routine is meant to function as a delayed operation, and may return
>> + * -EGAIN when the transaction needs to be rolled.  Calling functions will need
>> + * to handle this, and recall the function until a successful error code is
>> + * returned.
>> + */
>> +int
>> +xfs_attr_remove_later(
>>   	struct xfs_da_args      *args)
>>   {
>>   	struct xfs_inode	*dp = args->dp;
>> -	int			error;
>> +	int			error = 0;
>> +
>> +	/* State machine switch */
>> +	switch (args->dc.dc_state) {
>> +	case XFS_DC_RM_INVALIDATE:
>> +	case XFS_DC_RM_SHRINK:
>> +	case XFS_DC_RM_NODE_BLKS:
>> +		goto node;
>> +	default:
>> +		break;
>> +	}
>>   
>>   	if (!xfs_inode_hasattr(dp)) {
>>   		error = -ENOATTR;
>> @@ -382,6 +428,7 @@ xfs_attr_remove_args(
>>   	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>>   		error = xfs_attr_leaf_removename(args);
>>   	} else {
>> +node:
>>   		error = xfs_attr_node_removename(args);
>>   	}
>>   
>> @@ -892,9 +939,6 @@ xfs_attr_leaf_removename(
>>   		/* bp is gone due to xfs_da_shrink_inode */
>>   		if (error)
>>   			return error;
>> -		error = xfs_defer_finish(&args->trans);
>> -		if (error)
>> -			return error;
>>   	}
>>   	return 0;
>>   }
>> @@ -1212,6 +1256,11 @@ xfs_attr_node_addname(
>>    * This will involve walking down the Btree, and may involve joining
>>    * leaf nodes and even joining intermediate nodes up to and including
>>    * the root node (a special case of an intermediate node).
>> + *
>> + * This routine is meant to function as a delayed operation, and may return
>> + * -EAGAIN when the transaction needs to be rolled.  Calling functions
>> + * will need to handle this, and recall the function until a successful error
>> + * code is returned.
>>    */
>>   STATIC int
>>   xfs_attr_node_removename(
>> @@ -1222,12 +1271,29 @@ xfs_attr_node_removename(
>>   	struct xfs_buf		*bp;
>>   	int			retval, error, forkoff;
>>   	struct xfs_inode	*dp = args->dp;
>> +	int			done = 0;
>>   
>>   	trace_xfs_attr_node_removename(args);
>> +	state = args->dc.da_state;
>> +	blk = args->dc.blk;
>> +
>> +	/* State machine switch */
>> +	switch (args->dc.dc_state) {
>> +	case XFS_DC_RM_NODE_BLKS:
>> +		goto rm_node_blks;
>> +	case XFS_DC_RM_INVALIDATE:
>> +		goto rm_invalidate;
>> +	case XFS_DC_RM_SHRINK:
>> +		goto rm_shrink;
>> +	default:
>> +		break;
> 
> I wonder if it's worth having an explicit state for the initial path.
> That could be useful for readability and debuggability in the future.
We could, it will just require to the calling function to set that 
before state calling it.

Mechanically, I dont think it would hurt anything, but it may lead to 
developer wonderments like... "Where's the EAGAIN for this state?" 
"Shouldnt this state appear in the switch up top too?"  Or if it does 
"Why do we have it here, if it never executes?"  "I wonder if i should 
sent a patch to take it out..." :-)

Puzzlement aside though, I cant quite think of what condition it would 
help to debug?  It's not an error for the statemachine to hold a value 
outside of the helpers scope.  It just means the caller was using it up 
to this point.  Helpers really shouldnt have enough context about their 
callers to know or care what the caller states mean.  If we added a 
special init state, all the default statement would really mean is: "The 
caller forgot to set the init state".

Thoughts?

> 
>> +	}
>>   
>>   	error = xfs_attr_node_hasname(args, &state);
>>   	if (error != -EEXIST)
>>   		goto out;
>> +	else
>> +		error = 0;
>>   
>>   	/*
>>   	 * If there is an out-of-line value, de-allocate the blocks.
>> @@ -1237,6 +1303,14 @@ xfs_attr_node_removename(
>>   	blk = &state->path.blk[ state->path.active-1 ];
>>   	ASSERT(blk->bp != NULL);
>>   	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>> +
>> +	/*
>> +	 * Store blk and state in the context incase we need to cycle out the
>> +	 * transaction
>> +	 */
>> +	args->dc.blk = blk;
>> +	args->dc.da_state = state;
>> +
>>   	if (args->rmtblkno > 0) {
>>   		/*
>>   		 * Fill in disk block numbers in the state structure
>> @@ -1255,13 +1329,30 @@ xfs_attr_node_removename(
>>   		if (error)
>>   			goto out;
>>   
>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> +		args->dc.dc_state = XFS_DC_RM_INVALIDATE;
>> +		return -EAGAIN;
>> +rm_invalidate:
>> +		error = xfs_attr_rmtval_invalidate(args);
>>   		if (error)
>>   			goto out;
>> +rm_node_blks:
> 
> While I think the design is the right idea, jumping down into a function
> like this is pretty hairy. I think we should try to further break this
> function down into smaller elements one way or another that model the
> steps defined by the state structure. There's probably multiple ways to
> do that. For example, the remote attr bits could be broken down into
> a subfunction that processes the couple of states associated with remote
> blocks. That said, ISTM it might be wiser to try and keep the state
> processing in one place if possible. That would imply to break the
> remote processing loop down into a couple functions. All in all, this
> function might end up looking something like:
> 
> xfs_attr_node_removename()
> {
> 	/* switch statement and comment to document each state */
> 
> 	error = xfs_attr_node_hasname(args, &state);
> 	...
> 
> 	if (remote) {
> 		error = do_setflag();
> 		if (error)
> 			return error;
> 
> 		/* roll */
> 		state = INVALIDATE;
> 		return -EAGAIN;
> 	}
> 
> rmt_invalidate:
> 	state = INVALIDATE;
> 	if (remote)
> 		do_invalidate();
> 	/* fallthru */
> 
> rmt_rm_blks:
> 	state = RM_NODE_BLKS;
> 	if (remote) {
> 		/* loops and returns -EAGAIN until we fallthru */
> 		error = rmt_remove_step();
> 		if (error)
> 			return error;
> 
> 		xfs_attr_refillstate();
> 	}
> 
> /* maybe worth a new state here? */
> removename:
> 	state = REMOVENAME;
> 	xfs_attr3_leaf_remove();
> 	...
> 	if (...) {
> 		state = SHRINK;
> 		return -EAGAIN;
> 	}
> 
> shrink:
> 	state = SHRINK;
> 	error = do_shrink();
> 
> 	return 0;
> }
Ok, I had to go over this a few times, but I think I understand what 
you're describing.  Will update in the next version
> 
> I'm not totally sold on the idea of rolling the state forward explicitly
> like this, but it seems like it could be a bit more maintainable.
I think it is.  Having a dedicated struct just for this purpose 
alleviates a lot of struggle with trying to grab onto things like the 
fork or the incomplete flags to represent what we're trying to do here. 
Doing so also overloads their original intent in that if these 
structures ever change in the future, it may break something that the 
state machine depends on.  In this solution, they remain disjoint 
concepts dedicated to their purpose.  And anyway, I couldn't completely 
escape the state machine in the previous set.  I still had to add the 
extra flag space which functioned more or less like "i was here" tick 
marks.  If we have to have it, we may as well leverage what it can do. 
For example I can drop patch 11 from this set because I don't need the 
extra isset helpers to see if it's already been done.

  All in
> all this is still fairly ugly, but this is mostly a mechanical attempt
> to keep state management isolated and we can polish it up from there.
> Thoughts?

Yes, at this point, I do kind of feel like it's the least of the ugly 
prototypes.  So I'm just kind of proceeding, with caution. :-)

Thanks for the in depths reviews!!  I know its a lot!  Much appreciated!!

Allison

> 
> Brian
> 
>> +		/*
>> +		 * Unmap value blocks for this attr.  This is similar to
>> +		 * xfs_attr_rmtval_remove, but open coded here to return EAGAIN
>> +		 * for new transactions
>> +		 */
>> +		while (!done && !error) {
>> +			error = xfs_bunmapi(args->trans, args->dp,
>> +				    args->rmtblkno, args->rmtblkcnt,
>> +				    XFS_BMAPI_ATTRFORK, 1, &done);
>> +			if (error)
>> +				return error;
>>   
>> -		error = xfs_attr_rmtval_remove(args);
>> -		if (error)
>> -			goto out;
>> +			if (!done) {
>> +				args->dc.dc_state = XFS_DC_RM_NODE_BLKS;
>> +				return -EAGAIN;
>> +			}
>> +		}
>>   
>>   		/*
>>   		 * Refill the state structure with buffers, the prior calls
>> @@ -1287,17 +1378,12 @@ xfs_attr_node_removename(
>>   		error = xfs_da3_join(state);
>>   		if (error)
>>   			goto out;
>> -		error = xfs_defer_finish(&args->trans);
>> -		if (error)
>> -			goto out;
>> -		/*
>> -		 * Commit the Btree join operation and start a new trans.
>> -		 */
>> -		error = xfs_trans_roll_inode(&args->trans, dp);
>> -		if (error)
>> -			goto out;
>> +
>> +		args->dc.dc_state = XFS_DC_RM_SHRINK;
>> +		return -EAGAIN;
>>   	}
>>   
>> +rm_shrink:
>>   	/*
>>   	 * If the result is small enough, push it all into the inode.
>>   	 */
>> @@ -1319,9 +1405,6 @@ xfs_attr_node_removename(
>>   			/* bp is gone due to xfs_da_shrink_inode */
>>   			if (error)
>>   				goto out;
>> -			error = xfs_defer_finish(&args->trans);
>> -			if (error)
>> -				goto out;
>>   		} else
>>   			xfs_trans_brelse(args->trans, bp);
>>   	}
>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>> index 3b5dad4..fb8bf5b 100644
>> --- a/fs/xfs/libxfs/xfs_attr.h
>> +++ b/fs/xfs/libxfs/xfs_attr.h
>> @@ -152,6 +152,7 @@ int xfs_attr_set_args(struct xfs_da_args *args);
>>   int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
>>   int xfs_has_attr(struct xfs_da_args *args);
>>   int xfs_attr_remove_args(struct xfs_da_args *args);
>> +int xfs_attr_remove_later(struct xfs_da_args *args);
>>   int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>>   		  int flags, struct attrlist_cursor_kern *cursor);
>>   bool xfs_attr_namecheck(const void *name, size_t length);
>> -- 
>> 2.7.4
>>
> 

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

* Re: [PATCH v4 17/17] xfs: Add delay ready attr set routines
  2019-11-12 13:37   ` Brian Foster
@ 2019-11-13  4:57     ` Allison Collins
  0 siblings, 0 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-13  4:57 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 11/12/19 6:37 AM, Brian Foster wrote:
> On Wed, Nov 06, 2019 at 06:28:01PM -0700, Allison Collins wrote:
>> This patch modifies the attr set routines to be delay ready.
>> This means they no longer roll or commit transactions, but instead
>> return -EAGAIN to have the calling routine roll and refresh the
>> transaction.  In this series, xfs_attr_set_args has become
>> xfs_attr_set_later, which uses a state machine to keep track
>> of where it was when EAGAIN was returned.  Part of
>> xfs_attr_leaf_addname has been factored out into a new helper
>> function xfs_attr_leaf_try_add to allow transaction cycling between
>> the two routines, and the flipflags logic has been removed since we
>> can simply cancel the transaction upon error.  xfs_attr_set_args
>> consists of a simple loop to refresh the transaction until the
>> operation is completed.
>>
>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>> ---
> 
> Pretty much the same fundamental comments here as for the remove patch.
> Can we break things down further to avoid much of the jumping into if
> branch behavior and such? I also wonder if it might be possible to split
> this one up into smaller patches to fix up the leaf/node paths
> separately, but additional prep refactoring might simplify things enough
> on its own to make that unnecessary..
> 
> Brian

Sure, I'll see if I can get the branching out of the if statements. 
Maybe I can break this up into smaller patches too.  Thanks again for 
the reviews!

Allison

> 
>>   fs/xfs/libxfs/xfs_attr.c | 435 +++++++++++++++++++++++------------------------
>>   fs/xfs/libxfs/xfs_attr.h |   1 +
>>   2 files changed, 211 insertions(+), 225 deletions(-)
>>
>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>> index 38d5c5c..97e5ae0 100644
>> --- a/fs/xfs/libxfs/xfs_attr.c
>> +++ b/fs/xfs/libxfs/xfs_attr.c
>> @@ -58,6 +58,7 @@ STATIC int xfs_attr_node_hasname(xfs_da_args_t *args,
>>   				 struct xfs_da_state **state);
>>   STATIC int xfs_attr_fillstate(xfs_da_state_t *state);
>>   STATIC int xfs_attr_refillstate(xfs_da_state_t *state);
>> +STATIC int xfs_attr_leaf_try_add(struct xfs_da_args *args, struct xfs_buf *bp);
>>   
>>   
>>   STATIC int
>> @@ -250,9 +251,79 @@ int
>>   xfs_attr_set_args(
>>   	struct xfs_da_args	*args)
>>   {
>> +	int			error = 0;
>> +	int			err2 = 0;
>> +	struct xfs_buf		*leaf_bp = NULL;
>> +
>> +	do {
>> +		error = xfs_attr_set_later(args, &leaf_bp);
>> +		if (error && error != -EAGAIN)
>> +			goto out;
>> +
>> +		xfs_trans_log_inode(args->trans, args->dp,
>> +				    XFS_ILOG_CORE | XFS_ILOG_ADATA);
>> +
>> +		err2 = xfs_trans_roll(&args->trans);
>> +		if (err2) {
>> +			error = err2;
>> +			goto out;
>> +		}
>> +
>> +		/* Rejoin inode and leaf if needed */
>> +		xfs_trans_ijoin(args->trans, args->dp, 0);
>> +		if (leaf_bp) {
>> +			xfs_trans_bjoin(args->trans, leaf_bp);
>> +			xfs_trans_bhold(args->trans, leaf_bp);
>> +		}
>> +
>> +	} while (error == -EAGAIN);
>> +
>> +out:
>> +	return error;
>> +}
>> +
>> +/*
>> + * Set the attribute specified in @args.
>> + * This routine is meant to function as a delayed operation, and may return
>> + * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
>> + * to handle this, and recall the function until a successful error code is
>> + * returned.
>> + */
>> +int
>> +xfs_attr_set_later(
>> +	struct xfs_da_args	*args,
>> +	struct xfs_buf          **leaf_bp)
>> +{
>>   	struct xfs_inode	*dp = args->dp;
>> -	struct xfs_buf          *leaf_bp = NULL;
>> -	int			error, error2 = 0;;
>> +	int			error = 0;
>> +	int			sf_size;
>> +
>> +	/* State machine switch */
>> +	switch (args->dc.dc_state) {
>> +	case XFS_DC_SF_TO_LEAF:
>> +		goto sf_to_leaf;
>> +	case XFS_DC_ALLOC_LEAF:
>> +	case XFS_DC_FOUND_LBLK:
>> +		goto leaf;
>> +	case XFS_DC_FOUND_NBLK:
>> +	case XFS_DC_ALLOC_NODE:
>> +	case XFS_DC_LEAF_TO_NODE:
>> +		goto node;
>> +	default:
>> +		break;
>> +	}
>> +
>> +	/*
>> +	 * New inodes may not have an attribute fork yet. So set the attribute
>> +	 * fork appropriately
>> +	 */
>> +	if (XFS_IFORK_Q((args->dp)) == 0) {
>> +		sf_size = sizeof(struct xfs_attr_sf_hdr) +
>> +		     XFS_ATTR_SF_ENTSIZE_BYNAME(args->name.len, args->valuelen);
>> +		xfs_bmap_set_attrforkoff(args->dp, sf_size, NULL);
>> +		args->dp->i_afp = kmem_zone_zalloc(xfs_ifork_zone, 0);
>> +		args->dp->i_afp->if_flags = XFS_IFEXTENTS;
>> +	}
>>   
>>   	/*
>>   	 * If the attribute list is non-existent or a shortform list,
>> @@ -272,21 +343,14 @@ xfs_attr_set_args(
>>   		 * Try to add the attr to the attribute list in the inode.
>>   		 */
>>   		error = xfs_attr_try_sf_addname(dp, args);
>> -		if (error != -ENOSPC) {
>> -			if (dp->i_mount->m_flags & XFS_MOUNT_WSYNC)
>> -				xfs_trans_set_sync(args->trans);
>> -
>> -			error2 = xfs_trans_commit(args->trans);
>> -			args->trans = NULL;
>> -			return error ? error : error2;
>> -		}
>> -
>> +		if (error != -ENOSPC)
>> +			return error;
>>   
>>   		/*
>>   		 * It won't fit in the shortform, transform to a leaf block.
>>   		 * GROT: another possible req'mt for a double-split btree op.
>>   		 */
>> -		error = xfs_attr_shortform_to_leaf(args, &leaf_bp);
>> +		error = xfs_attr_shortform_to_leaf(args, leaf_bp);
>>   		if (error)
>>   			return error;
>>   
>> @@ -294,43 +358,42 @@ xfs_attr_set_args(
>>   		 * Prevent the leaf buffer from being unlocked so that a
>>   		 * concurrent AIL push cannot grab the half-baked leaf
>>   		 * buffer and run into problems with the write verifier.
>> -		 * Once we're done rolling the transaction we can release
>> -		 * the hold and add the attr to the leaf.
>>   		 */
>> -		xfs_trans_bhold(args->trans, leaf_bp);
>> -		error = xfs_defer_finish(&args->trans);
>> -		xfs_trans_bhold_release(args->trans, leaf_bp);
>> -		if (error) {
>> -			xfs_trans_brelse(args->trans, leaf_bp);
>> -			return error;
>> -		}
>> +
>> +		xfs_trans_bhold(args->trans, *leaf_bp);
>> +		args->dc.dc_state = XFS_DC_SF_TO_LEAF;
>> +		return -EAGAIN;
>> +	}
>> +sf_to_leaf:
>> +
>> +	/*
>> +	 * After a shortform to leaf conversion, we need to hold the leaf and
>> +	 * cylce out the transaction.  When we get back, we need to release
>> +	 * the leaf.
>> +	 */
>> +	if (*leaf_bp != NULL) {
>> +		xfs_trans_brelse(args->trans, *leaf_bp);
>> +		*leaf_bp = NULL;
>>   	}
>>   
>>   	if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>> +		error = xfs_attr_leaf_try_add(args, *leaf_bp);
>> +		if (error == -ENOSPC)
>> +			args->dc.dc_state = XFS_DC_LEAF_TO_NODE;
>> +		else if (error)
>> +			return error;
>> +		else
>> +			args->dc.dc_state = XFS_DC_FOUND_LBLK;
>> +		return -EAGAIN;
>> +leaf:
>>   		error = xfs_attr_leaf_addname(args);
>>   		if (error == -ENOSPC) {
>> -			/*
>> -			 * Commit that transaction so that the node_addname()
>> -			 * call can manage its own transactions.
>> -			 */
>> -			error = xfs_defer_finish(&args->trans);
>> -			if (error)
>> -				return error;
>> -
>> -			/*
>> -			 * Commit the current trans (including the inode) and
>> -			 * start a new one.
>> -			 */
>> -			error = xfs_trans_roll_inode(&args->trans, dp);
>> -			if (error)
>> -				return error;
>> -
>> -			/*
>> -			 * Fob the rest of the problem off on the Btree code.
>> -			 */
>> -			error = xfs_attr_node_addname(args);
>> +			args->dc.dc_state = XFS_DC_LEAF_TO_NODE;
>> +			return -EAGAIN;
>>   		}
>>   	} else {
>> +		args->dc.dc_state = XFS_DC_LEAF_TO_NODE;
>> +node:
>>   		error = xfs_attr_node_addname(args);
>>   	}
>>   	return error;
>> @@ -764,27 +827,26 @@ xfs_attr_leaf_try_add(
>>    *
>>    * This leaf block cannot have a "remote" value, we only call this routine
>>    * if bmap_one_block() says there is only one block (ie: no remote blks).
>> + *
>> + * This routine is meant to function as a delayed operation, and may return
>> + * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
>> + * to handle this, and recall the function until a successful error code is
>> + * returned.
>>    */
>>   STATIC int
>>   xfs_attr_leaf_addname(struct xfs_da_args	*args)
>>   {
>> -	int			error, forkoff;
>> -	struct xfs_buf		*bp = NULL;
>> +	int			error, nmap;
>>   	struct xfs_inode	*dp = args->dp;
>> +	struct xfs_bmbt_irec	*map = &args->dc.map;
>>   
>> -	trace_xfs_attr_leaf_addname(args);
>> -
>> -	error = xfs_attr_leaf_try_add(args, bp);
>> -	if (error)
>> -		return error;
>> -
>> -	/*
>> -	 * Commit the transaction that added the attr name so that
>> -	 * later routines can manage their own transactions.
>> -	 */
>> -	error = xfs_trans_roll_inode(&args->trans, dp);
>> -	if (error)
>> -		return error;
>> +	/* State machine switch */
>> +	switch (args->dc.dc_state) {
>> +	case XFS_DC_ALLOC_LEAF:
>> +		goto alloc_leaf;
>> +	default:
>> +		break;
>> +	}
>>   
>>   	/*
>>   	 * If there was an out-of-line value, allocate the blocks we
>> @@ -793,90 +855,58 @@ xfs_attr_leaf_addname(struct xfs_da_args	*args)
>>   	 * maximum size of a transaction and/or hit a deadlock.
>>   	 */
>>   	if (args->rmtblkno > 0) {
>> -		error = xfs_attr_rmtval_set(args);
>> -		if (error)
>> -			return error;
>> -	}
>>   
>> -	/*
>> -	 * If this is an atomic rename operation, we must "flip" the
>> -	 * incomplete flags on the "new" and "old" attribute/value pairs
>> -	 * so that one disappears and one appears atomically.  Then we
>> -	 * must remove the "old" attribute/value pair.
>> -	 */
>> -	if (args->op_flags & XFS_DA_OP_RENAME) {
>> -		/*
>> -		 * In a separate transaction, set the incomplete flag on the
>> -		 * "old" attr and clear the incomplete flag on the "new" attr.
>> -		 */
>> -		error = xfs_attr3_leaf_flipflags(args);
>> -		if (error)
>> -			return error;
>> -		/*
>> -		 * Commit the flag value change and start the next trans in
>> -		 * series.
>> -		 */
>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> -		if (error)
>> -			return error;
>> +		/* Open coded xfs_attr_rmtval_set without trans handling */
>>   
>> -		/*
>> -		 * Dismantle the "old" attribute/value pair by removing
>> -		 * a "remote" value (if it exists).
>> -		 */
>> -		args->index = args->index2;
>> -		args->blkno = args->blkno2;
>> -		args->rmtblkno = args->rmtblkno2;
>> -		args->rmtblkcnt = args->rmtblkcnt2;
>> -		args->rmtvaluelen = args->rmtvaluelen2;
>> -		if (args->rmtblkno) {
>> -			error = xfs_attr_rmtval_remove(args);
>> -			if (error)
>> -				return error;
>> -		}
>> +		args->dc.lfileoff = 0;
>> +		args->dc.lblkno = 0;
>> +		args->dc.blkcnt = 0;
>> +		args->rmtblkcnt = 0;
>> +		args->rmtblkno = 0;
>> +		memset(map, 0, sizeof(struct xfs_bmbt_irec));
>>   
>> -		/*
>> -		 * Read in the block containing the "old" attr, then
>> -		 * remove the "old" attr from that block (neat, huh!)
>> -		 */
>> -		error = xfs_attr3_leaf_read(args->trans, args->dp, args->blkno,
>> -					   XFS_DABUF_MAP_NOMAPPING, &bp);
>> +		error = xfs_attr_rmt_find_hole(args);
>>   		if (error)
>>   			return error;
>>   
>> -		xfs_attr3_leaf_remove(bp, args);
>> +		args->dc.blkcnt = args->rmtblkcnt;
>> +		args->dc.lblkno = args->rmtblkno;
>>   
>>   		/*
>> -		 * If the result is small enough, shrink it all into the inode.
>> +		 * Roll through the "value", allocating blocks on disk as
>> +		 * required.
>>   		 */
>> -		if ((forkoff = xfs_attr_shortform_allfit(bp, dp))) {
>> -			error = xfs_attr3_leaf_to_shortform(bp, args, forkoff);
>> -			/* bp is gone due to xfs_da_shrink_inode */
>> -			if (error)
>> -				return error;
>> -			error = xfs_defer_finish(&args->trans);
>> +alloc_leaf:
>> +		while (args->dc.blkcnt > 0) {
>> +			nmap = 1;
>> +			error = xfs_bmapi_write(args->trans, dp,
>> +				  (xfs_fileoff_t)args->dc.lblkno,
>> +				  args->dc.blkcnt, XFS_BMAPI_ATTRFORK,
>> +				  args->total, map, &nmap);
>>   			if (error)
>>   				return error;
>> -		}
>> +			ASSERT(nmap == 1);
>> +			ASSERT((map->br_startblock != DELAYSTARTBLOCK) &&
>> +			       (map->br_startblock != HOLESTARTBLOCK));
>>   
>> -		/*
>> -		 * Commit the remove and start the next trans in series.
>> -		 */
>> -		error = xfs_trans_roll_inode(&args->trans, dp);
>> +			/* roll attribute extent map forwards */
>> +			args->dc.lblkno += map->br_blockcount;
>> +			args->dc.blkcnt -= map->br_blockcount;
>>   
>> -	} else if (args->rmtblkno > 0) {
>> -		/*
>> -		 * Added a "remote" value, just clear the incomplete flag.
>> -		 */
>> -		error = xfs_attr3_leaf_clearflag(args);
>> +			args->dc.dc_state = XFS_DC_ALLOC_LEAF;
>> +			return -EAGAIN;
>> +		}
>> +
>> +		error = xfs_attr_rmtval_set_value(args);
>>   		if (error)
>>   			return error;
>> +	}
>>   
>> +	if (args->rmtblkno > 0) {
>>   		/*
>> -		 * Commit the flag value change and start the next trans in
>> -		 * series.
>> +		 * Added a "remote" value, just clear the incomplete flag.
>>   		 */
>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> +		error = xfs_attr3_leaf_clearflag(args);
>>   	}
>>   	return error;
>>   }
>> @@ -1017,16 +1047,23 @@ xfs_attr_node_hasname(
>>    *
>>    * "Remote" attribute values confuse the issue and atomic rename operations
>>    * add a whole extra layer of confusion on top of that.
>> + *
>> + * This routine is meant to function as a delayed operation, and may return
>> + * -EAGAIN when the transaction needs to be rolled.  Calling functions will need
>> + * to handle this, and recall the function until a successful error code is
>> + *returned.
>>    */
>>   STATIC int
>>   xfs_attr_node_addname(
>>   	struct xfs_da_args	*args)
>>   {
>> -	struct xfs_da_state	*state;
>> +	struct xfs_da_state	*state = NULL;
>>   	struct xfs_da_state_blk	*blk;
>>   	struct xfs_inode	*dp;
>> -	struct xfs_mount	*mp;
>> -	int			retval, error;
>> +	int			retval = 0;
>> +	int			error = 0;
>> +	int			nmap;
>> +	struct xfs_bmbt_irec    *map = &args->dc.map;
>>   
>>   	trace_xfs_attr_node_addname(args);
>>   
>> @@ -1034,8 +1071,17 @@ xfs_attr_node_addname(
>>   	 * Fill in bucket of arguments/results/context to carry around.
>>   	 */
>>   	dp = args->dp;
>> -	mp = dp->i_mount;
>> -restart:
>> +
>> +	/* State machine switch */
>> +	switch (args->dc.dc_state) {
>> +	case XFS_DC_FOUND_NBLK:
>> +		goto found_nblk;
>> +	case XFS_DC_ALLOC_NODE:
>> +		goto alloc_node;
>> +	default:
>> +		break;
>> +	}
>> +
>>   	/*
>>   	 * Search to see if name already exists, and get back a pointer
>>   	 * to where it should go.
>> @@ -1085,19 +1131,12 @@ xfs_attr_node_addname(
>>   			error = xfs_attr3_leaf_to_node(args);
>>   			if (error)
>>   				goto out;
>> -			error = xfs_defer_finish(&args->trans);
>> -			if (error)
>> -				goto out;
>>   
>>   			/*
>> -			 * Commit the node conversion and start the next
>> -			 * trans in the chain.
>> +			 * Restart routine from the top.  No need to set  the
>> +			 * state
>>   			 */
>> -			error = xfs_trans_roll_inode(&args->trans, dp);
>> -			if (error)
>> -				goto out;
>> -
>> -			goto restart;
>> +			return -EAGAIN;
>>   		}
>>   
>>   		/*
>> @@ -1109,9 +1148,6 @@ xfs_attr_node_addname(
>>   		error = xfs_da3_split(state);
>>   		if (error)
>>   			goto out;
>> -		error = xfs_defer_finish(&args->trans);
>> -		if (error)
>> -			goto out;
>>   	} else {
>>   		/*
>>   		 * Addition succeeded, update Btree hashvals.
>> @@ -1126,13 +1162,9 @@ xfs_attr_node_addname(
>>   	xfs_da_state_free(state);
>>   	state = NULL;
>>   
>> -	/*
>> -	 * Commit the leaf addition or btree split and start the next
>> -	 * trans in the chain.
>> -	 */
>> -	error = xfs_trans_roll_inode(&args->trans, dp);
>> -	if (error)
>> -		goto out;
>> +	args->dc.dc_state = XFS_DC_FOUND_NBLK;
>> +	return -EAGAIN;
>> +found_nblk:
>>   
>>   	/*
>>   	 * If there was an out-of-line value, allocate the blocks we
>> @@ -1141,104 +1173,57 @@ xfs_attr_node_addname(
>>   	 * maximum size of a transaction and/or hit a deadlock.
>>   	 */
>>   	if (args->rmtblkno > 0) {
>> -		error = xfs_attr_rmtval_set(args);
>> -		if (error)
>> -			return error;
>> -	}
>> +		/* Open coded xfs_attr_rmtval_set without trans handling */
>> +		args->dc.lblkno = 0;
>> +		args->dc.lfileoff = 0;
>> +		args->dc.blkcnt = 0;
>> +		args->rmtblkcnt = 0;
>> +		args->rmtblkno = 0;
>> +		memset(map, 0, sizeof(struct xfs_bmbt_irec));
>>   
>> -	/*
>> -	 * If this is an atomic rename operation, we must "flip" the
>> -	 * incomplete flags on the "new" and "old" attribute/value pairs
>> -	 * so that one disappears and one appears atomically.  Then we
>> -	 * must remove the "old" attribute/value pair.
>> -	 */
>> -	if (args->op_flags & XFS_DA_OP_RENAME) {
>> -		/*
>> -		 * In a separate transaction, set the incomplete flag on the
>> -		 * "old" attr and clear the incomplete flag on the "new" attr.
>> -		 */
>> -		error = xfs_attr3_leaf_flipflags(args);
>> -		if (error)
>> -			goto out;
>> -		/*
>> -		 * Commit the flag value change and start the next trans in
>> -		 * series
>> -		 */
>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> +		error = xfs_attr_rmt_find_hole(args);
>>   		if (error)
>> -			goto out;
>> +			return error;
>>   
>> +		args->dc.blkcnt = args->rmtblkcnt;
>> +		args->dc.lblkno = args->rmtblkno;
>>   		/*
>> -		 * Dismantle the "old" attribute/value pair by removing
>> -		 * a "remote" value (if it exists).
>> +		 * Roll through the "value", allocating blocks on disk as
>> +		 * required.
>>   		 */
>> -		args->index = args->index2;
>> -		args->blkno = args->blkno2;
>> -		args->rmtblkno = args->rmtblkno2;
>> -		args->rmtblkcnt = args->rmtblkcnt2;
>> -		args->rmtvaluelen = args->rmtvaluelen2;
>> -		if (args->rmtblkno) {
>> -			error = xfs_attr_rmtval_remove(args);
>> +alloc_node:
>> +		while (args->dc.blkcnt > 0) {
>> +			nmap = 1;
>> +			error = xfs_bmapi_write(args->trans, dp,
>> +				(xfs_fileoff_t)args->dc.lblkno, args->dc.blkcnt,
>> +				XFS_BMAPI_ATTRFORK, args->total, map, &nmap);
>>   			if (error)
>>   				return error;
>> -		}
>>   
>> -		/*
>> -		 * Re-find the "old" attribute entry after any split ops.
>> -		 * The INCOMPLETE flag means that we will find the "old"
>> -		 * attr, not the "new" one.
>> -		 */
>> -		args->name.type |= XFS_ATTR_INCOMPLETE;
>> -		state = xfs_da_state_alloc();
>> -		state->args = args;
>> -		state->mp = mp;
>> -		state->inleaf = 0;
>> -		error = xfs_da3_node_lookup_int(state, &retval);
>> -		if (error)
>> -			goto out;
>> +			ASSERT(nmap == 1);
>> +			ASSERT((map->br_startblock != DELAYSTARTBLOCK) &&
>> +			       (map->br_startblock != HOLESTARTBLOCK));
>>   
>> -		/*
>> -		 * Remove the name and update the hashvals in the tree.
>> -		 */
>> -		blk = &state->path.blk[ state->path.active-1 ];
>> -		ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>> -		error = xfs_attr3_leaf_remove(blk->bp, args);
>> -		xfs_da3_fixhashpath(state, &state->path);
>> +			/* roll attribute extent map forwards */
>> +			args->dc.lblkno += map->br_blockcount;
>> +			args->dc.blkcnt -= map->br_blockcount;
>>   
>> -		/*
>> -		 * Check to see if the tree needs to be collapsed.
>> -		 */
>> -		if (retval && (state->path.active > 1)) {
>> -			error = xfs_da3_join(state);
>> -			if (error)
>> -				goto out;
>> -			error = xfs_defer_finish(&args->trans);
>> -			if (error)
>> -				goto out;
>> +			args->dc.dc_state = XFS_DC_ALLOC_NODE;
>> +			return -EAGAIN;
>>   		}
>>   
>> -		/*
>> -		 * Commit and start the next trans in the chain.
>> -		 */
>> -		error = xfs_trans_roll_inode(&args->trans, dp);
>> +		error = xfs_attr_rmtval_set_value(args);
>>   		if (error)
>> -			goto out;
>> +			return error;
>> +	}
>>   
>> -	} else if (args->rmtblkno > 0) {
>> +	if (args->rmtblkno > 0) {
>>   		/*
>>   		 * Added a "remote" value, just clear the incomplete flag.
>>   		 */
>>   		error = xfs_attr3_leaf_clearflag(args);
>>   		if (error)
>>   			goto out;
>> -
>> -		 /*
>> -		  * Commit the flag value change and start the next trans in
>> -		  * series.
>> -		  */
>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>> -		if (error)
>> -			goto out;
>>   	}
>>   	retval = error = 0;
>>   
>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>> index fb8bf5b..c710387 100644
>> --- a/fs/xfs/libxfs/xfs_attr.h
>> +++ b/fs/xfs/libxfs/xfs_attr.h
>> @@ -149,6 +149,7 @@ int xfs_attr_get(struct xfs_inode *ip, struct xfs_name *name,
>>   int xfs_attr_set(struct xfs_inode *dp, struct xfs_name *name,
>>   		 unsigned char *value, int valuelen, int flags);
>>   int xfs_attr_set_args(struct xfs_da_args *args);
>> +int xfs_attr_set_later(struct xfs_da_args *args, struct xfs_buf **leaf_bp);
>>   int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
>>   int xfs_has_attr(struct xfs_da_args *args);
>>   int xfs_attr_remove_args(struct xfs_da_args *args);
>> -- 
>> 2.7.4
>>
> 

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

* Re: [PATCH v4 16/17] xfs: Add delay ready attr remove routines
  2019-11-13  0:43     ` Allison Collins
@ 2019-11-13 11:54       ` Brian Foster
  2019-11-13 23:39         ` Allison Collins
  0 siblings, 1 reply; 77+ messages in thread
From: Brian Foster @ 2019-11-13 11:54 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Tue, Nov 12, 2019 at 05:43:04PM -0700, Allison Collins wrote:
> 
> 
> On 11/12/19 6:37 AM, Brian Foster wrote:
> > On Wed, Nov 06, 2019 at 06:28:00PM -0700, Allison Collins wrote:
> > > This patch modifies the attr remove routines to be delay ready.
> > > This means they no longer roll or commit transactions, but instead
> > > return -EAGAIN to have the calling routine roll and refresh the
> > > transaction.  In this series, xfs_attr_remove_args has become
> > > xfs_attr_remove_later, which uses a state machine to keep track
> > > of where it was when EAGAIN was returned.  xfs_attr_node_removename
> > > has also been modified to use the state machine, and a  new version of
> > > xfs_attr_remove_args consists of a simple loop to refresh the
> > > transaction until the operation is completed.
> > > 
> > > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > > ---
> > 
> > On a cursory look, this is definitely more along the lines of what I was
> > thinking on the previous revisions. I would like to see if we can get a
> > bit more refactoring/cleanup before this point though. Further thoughts
> > inline..
> > 
> > >   fs/xfs/libxfs/xfs_attr.c | 123 +++++++++++++++++++++++++++++++++++++++--------
> > >   fs/xfs/libxfs/xfs_attr.h |   1 +
> > >   2 files changed, 104 insertions(+), 20 deletions(-)
> > > 
> > > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > > index 626d4a98..38d5c5c 100644
> > > --- a/fs/xfs/libxfs/xfs_attr.c
> > > +++ b/fs/xfs/libxfs/xfs_attr.c
> > > @@ -369,10 +369,56 @@ xfs_has_attr(
> > >    */
> > >   int
> > >   xfs_attr_remove_args(
> > > +	struct xfs_da_args	*args)
> > > +{
> > > +	int			error = 0;
> > > +	int			err2 = 0;
> > > +
> > > +	do {
> > > +		error = xfs_attr_remove_later(args);
> > > +		if (error && error != -EAGAIN)
> > > +			goto out;
> > 
> > xfs_attr_remove_later() strikes me as an odd name with respect to the
> > functionality. Perhaps something like xfs_attr_remove_step() is
> > (slightly) more accurate..?
> Sure that's fine.  I think Darrick had proposed the *_later scheme in an
> earlier review but that was when the code paths were split.  Darrick, does
> the *_step scheme work for you?
> 

FWIW, xfs_attr_remove_iter() also came to mind after sending the
previous mail.

> > 
> > > +
> > > +		xfs_trans_log_inode(args->trans, args->dp,
> > > +			XFS_ILOG_CORE | XFS_ILOG_ADATA);
> > > +
> > > +		err2 = xfs_trans_roll(&args->trans);
> > > +		if (err2) {
> > > +			error = err2;
> > 
> > Also do we really need two error codes in this function? It seems like
> > we should be able to write this with one, but I haven't tried it..
> No, because then we'll loose the xfs_attr_remove_later return code, which is
> either 0 or EAGAIN at this point.  And we need that to drive the loop.  To
> get rid of err2, we'd need another "not_done" variable or something.  Like:
> 
> do {
> 	...
> 	not_done = (error == -EAGAIN);
> 	...
> } while (not_done)
> 
> 
> Not sure if not_done is really preferable to err2?
> 

Eh, NBD. It just looked like potentially verbose logic on a quick scan.
On a closer look, I see that we want to handle both error == 0 and error
== -EAGAIN, so this seems fine as is to me.

> > 
> > > +			goto out;
> > > +		}
> > > +
> > > +		/* Rejoin inode */
> > > +		xfs_trans_ijoin(args->trans, args->dp, 0);
> > > +
> > > +	} while (error == -EAGAIN);
> > > +out:
> > > +	return error;
> > > +}
> > > +
> > > +/*
> > > + * Remove the attribute specified in @args.
> > > + * This routine is meant to function as a delayed operation, and may return
> > > + * -EGAIN when the transaction needs to be rolled.  Calling functions will need
> > > + * to handle this, and recall the function until a successful error code is
> > > + * returned.
> > > + */
> > > +int
> > > +xfs_attr_remove_later(
> > >   	struct xfs_da_args      *args)
> > >   {
> > >   	struct xfs_inode	*dp = args->dp;
> > > -	int			error;
> > > +	int			error = 0;
> > > +
> > > +	/* State machine switch */
> > > +	switch (args->dc.dc_state) {
> > > +	case XFS_DC_RM_INVALIDATE:
> > > +	case XFS_DC_RM_SHRINK:
> > > +	case XFS_DC_RM_NODE_BLKS:
> > > +		goto node;
> > > +	default:
> > > +		break;
> > > +	}
> > >   	if (!xfs_inode_hasattr(dp)) {
> > >   		error = -ENOATTR;
> > > @@ -382,6 +428,7 @@ xfs_attr_remove_args(
> > >   	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> > >   		error = xfs_attr_leaf_removename(args);
> > >   	} else {
> > > +node:
> > >   		error = xfs_attr_node_removename(args);
> > >   	}
> > > @@ -892,9 +939,6 @@ xfs_attr_leaf_removename(
> > >   		/* bp is gone due to xfs_da_shrink_inode */
> > >   		if (error)
> > >   			return error;
> > > -		error = xfs_defer_finish(&args->trans);
> > > -		if (error)
> > > -			return error;
> > >   	}
> > >   	return 0;
> > >   }
> > > @@ -1212,6 +1256,11 @@ xfs_attr_node_addname(
> > >    * This will involve walking down the Btree, and may involve joining
> > >    * leaf nodes and even joining intermediate nodes up to and including
> > >    * the root node (a special case of an intermediate node).
> > > + *
> > > + * This routine is meant to function as a delayed operation, and may return
> > > + * -EAGAIN when the transaction needs to be rolled.  Calling functions
> > > + * will need to handle this, and recall the function until a successful error
> > > + * code is returned.
> > >    */
> > >   STATIC int
> > >   xfs_attr_node_removename(
> > > @@ -1222,12 +1271,29 @@ xfs_attr_node_removename(
> > >   	struct xfs_buf		*bp;
> > >   	int			retval, error, forkoff;
> > >   	struct xfs_inode	*dp = args->dp;
> > > +	int			done = 0;
> > >   	trace_xfs_attr_node_removename(args);
> > > +	state = args->dc.da_state;
> > > +	blk = args->dc.blk;
> > > +
> > > +	/* State machine switch */
> > > +	switch (args->dc.dc_state) {
> > > +	case XFS_DC_RM_NODE_BLKS:
> > > +		goto rm_node_blks;
> > > +	case XFS_DC_RM_INVALIDATE:
> > > +		goto rm_invalidate;
> > > +	case XFS_DC_RM_SHRINK:
> > > +		goto rm_shrink;
> > > +	default:
> > > +		break;
> > 
> > I wonder if it's worth having an explicit state for the initial path.
> > That could be useful for readability and debuggability in the future.
> We could, it will just require to the calling function to set that before
> state calling it.
> 

Looking back, I see we have XFS_DC_INIT in the enum, but it isn't used.
What is that particular state for? Any reason the enum doesn't start
with a value of 0?

> Mechanically, I dont think it would hurt anything, but it may lead to
> developer wonderments like... "Where's the EAGAIN for this state?" "Shouldnt
> this state appear in the switch up top too?"  Or if it does "Why do we have
> it here, if it never executes?"  "I wonder if i should sent a patch to take
> it out..." :-)
> 

Perhaps, though some of those questions already exist with the current
code. Not every function cares about every state from what I can tell.
Also, not every state that can return -EAGAIN is guaranteed to do so.

> Puzzlement aside though, I cant quite think of what condition it would help
> to debug?  It's not an error for the statemachine to hold a value outside of
> the helpers scope.  It just means the caller was using it up to this point.
> Helpers really shouldnt have enough context about their callers to know or
> care what the caller states mean.  If we added a special init state, all the
> default statement would really mean is: "The caller forgot to set the init
> state".
> 

See my question above around the existing init state. However that is
intended to be used is not really clear to me. BTW, it might be better
to introduce the core structures in one patch and add the individual
states as they are used by the subsequent patches that use them.

WRT to readability/debuggability, I suppose a simple example would be to
consider if we had a tracepoint somewhere in the higher level code that
printed state and error code and we wanted to use that to identify an
unexpected error that occurs during an attr op. With the current code,
if that printed something like:

	state INVALIDATE error -EIO

... that doesn't tell us a whole lot about what happened beyond
something failed sometime after the setflag state. The attr itself might
not even have remote blocks to invalidate, which is slightly confusing.
This is handwavy/subjective, of course..

> Thoughts?
> 
> > 
> > > +	}
> > >   	error = xfs_attr_node_hasname(args, &state);
> > >   	if (error != -EEXIST)
> > >   		goto out;
> > > +	else
> > > +		error = 0;
> > >   	/*
> > >   	 * If there is an out-of-line value, de-allocate the blocks.
> > > @@ -1237,6 +1303,14 @@ xfs_attr_node_removename(
> > >   	blk = &state->path.blk[ state->path.active-1 ];
> > >   	ASSERT(blk->bp != NULL);
> > >   	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> > > +
> > > +	/*
> > > +	 * Store blk and state in the context incase we need to cycle out the
> > > +	 * transaction
> > > +	 */
> > > +	args->dc.blk = blk;
> > > +	args->dc.da_state = state;
> > > +
> > >   	if (args->rmtblkno > 0) {
> > >   		/*
> > >   		 * Fill in disk block numbers in the state structure
> > > @@ -1255,13 +1329,30 @@ xfs_attr_node_removename(
> > >   		if (error)
> > >   			goto out;
> > > -		error = xfs_trans_roll_inode(&args->trans, args->dp);
> > > +		args->dc.dc_state = XFS_DC_RM_INVALIDATE;
> > > +		return -EAGAIN;
> > > +rm_invalidate:
> > > +		error = xfs_attr_rmtval_invalidate(args);
> > >   		if (error)
> > >   			goto out;
> > > +rm_node_blks:
> > 
> > While I think the design is the right idea, jumping down into a function
> > like this is pretty hairy. I think we should try to further break this
> > function down into smaller elements one way or another that model the
> > steps defined by the state structure. There's probably multiple ways to
> > do that. For example, the remote attr bits could be broken down into
> > a subfunction that processes the couple of states associated with remote
> > blocks. That said, ISTM it might be wiser to try and keep the state
> > processing in one place if possible. That would imply to break the
> > remote processing loop down into a couple functions. All in all, this
> > function might end up looking something like:
> > 
> > xfs_attr_node_removename()
> > {
> > 	/* switch statement and comment to document each state */
> > 
> > 	error = xfs_attr_node_hasname(args, &state);
> > 	...
> > 
> > 	if (remote) {
> > 		error = do_setflag();
> > 		if (error)
> > 			return error;
> > 
> > 		/* roll */
> > 		state = INVALIDATE;
> > 		return -EAGAIN;
> > 	}
> > 
> > rmt_invalidate:
> > 	state = INVALIDATE;
> > 	if (remote)
> > 		do_invalidate();
> > 	/* fallthru */
> > 
> > rmt_rm_blks:
> > 	state = RM_NODE_BLKS;
> > 	if (remote) {
> > 		/* loops and returns -EAGAIN until we fallthru */
> > 		error = rmt_remove_step();
> > 		if (error)
> > 			return error;
> > 
> > 		xfs_attr_refillstate();
> > 	}
> > 
> > /* maybe worth a new state here? */
> > removename:
> > 	state = REMOVENAME;
> > 	xfs_attr3_leaf_remove();
> > 	...
> > 	if (...) {
> > 		state = SHRINK;
> > 		return -EAGAIN;
> > 	}
> > 
> > shrink:
> > 	state = SHRINK;
> > 	error = do_shrink();
> > 
> > 	return 0;
> > }
> Ok, I had to go over this a few times, but I think I understand what you're
> describing.  Will update in the next version
> > 
> > I'm not totally sold on the idea of rolling the state forward explicitly
> > like this, but it seems like it could be a bit more maintainable.
> I think it is.  Having a dedicated struct just for this purpose alleviates a
> lot of struggle with trying to grab onto things like the fork or the
> incomplete flags to represent what we're trying to do here. Doing so also
> overloads their original intent in that if these structures ever change in
> the future, it may break something that the state machine depends on.  In
> this solution, they remain disjoint concepts dedicated to their purpose.
> And anyway, I couldn't completely escape the state machine in the previous
> set.  I still had to add the extra flag space which functioned more or less
> like "i was here" tick marks.  If we have to have it, we may as well
> leverage what it can do. For example I can drop patch 11 from this set
> because I don't need the extra isset helpers to see if it's already been
> done.
> 

Right.. I agree that the "bookmark" like approach in the current scheme
makes the state implementation (and not necessarily the operational
implementation) a little hard to follow and review. Note again that what
I wrote up here was just a quick example for that higher level feedback
of somehow or another trying to isolate state updates from state
implementation, so I'm not necessarily tied to that specific approach if
there are other ways to similarly simplify things.

I do think fixing up the code to avoid jumping into loops and whatnot is
more important. It could also be that just continuing to break things
down into as small functions as possible (i.e. with a goal of 1 function
per state) kind of forces a natural separation.

Brian

>  All in
> > all this is still fairly ugly, but this is mostly a mechanical attempt
> > to keep state management isolated and we can polish it up from there.
> > Thoughts?
> 
> Yes, at this point, I do kind of feel like it's the least of the ugly
> prototypes.  So I'm just kind of proceeding, with caution. :-)
> 
> Thanks for the in depths reviews!!  I know its a lot!  Much appreciated!!
> 
> Allison
> 
> > 
> > Brian
> > 
> > > +		/*
> > > +		 * Unmap value blocks for this attr.  This is similar to
> > > +		 * xfs_attr_rmtval_remove, but open coded here to return EAGAIN
> > > +		 * for new transactions
> > > +		 */
> > > +		while (!done && !error) {
> > > +			error = xfs_bunmapi(args->trans, args->dp,
> > > +				    args->rmtblkno, args->rmtblkcnt,
> > > +				    XFS_BMAPI_ATTRFORK, 1, &done);
> > > +			if (error)
> > > +				return error;
> > > -		error = xfs_attr_rmtval_remove(args);
> > > -		if (error)
> > > -			goto out;
> > > +			if (!done) {
> > > +				args->dc.dc_state = XFS_DC_RM_NODE_BLKS;
> > > +				return -EAGAIN;
> > > +			}
> > > +		}
> > >   		/*
> > >   		 * Refill the state structure with buffers, the prior calls
> > > @@ -1287,17 +1378,12 @@ xfs_attr_node_removename(
> > >   		error = xfs_da3_join(state);
> > >   		if (error)
> > >   			goto out;
> > > -		error = xfs_defer_finish(&args->trans);
> > > -		if (error)
> > > -			goto out;
> > > -		/*
> > > -		 * Commit the Btree join operation and start a new trans.
> > > -		 */
> > > -		error = xfs_trans_roll_inode(&args->trans, dp);
> > > -		if (error)
> > > -			goto out;
> > > +
> > > +		args->dc.dc_state = XFS_DC_RM_SHRINK;
> > > +		return -EAGAIN;
> > >   	}
> > > +rm_shrink:
> > >   	/*
> > >   	 * If the result is small enough, push it all into the inode.
> > >   	 */
> > > @@ -1319,9 +1405,6 @@ xfs_attr_node_removename(
> > >   			/* bp is gone due to xfs_da_shrink_inode */
> > >   			if (error)
> > >   				goto out;
> > > -			error = xfs_defer_finish(&args->trans);
> > > -			if (error)
> > > -				goto out;
> > >   		} else
> > >   			xfs_trans_brelse(args->trans, bp);
> > >   	}
> > > diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> > > index 3b5dad4..fb8bf5b 100644
> > > --- a/fs/xfs/libxfs/xfs_attr.h
> > > +++ b/fs/xfs/libxfs/xfs_attr.h
> > > @@ -152,6 +152,7 @@ int xfs_attr_set_args(struct xfs_da_args *args);
> > >   int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
> > >   int xfs_has_attr(struct xfs_da_args *args);
> > >   int xfs_attr_remove_args(struct xfs_da_args *args);
> > > +int xfs_attr_remove_later(struct xfs_da_args *args);
> > >   int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
> > >   		  int flags, struct attrlist_cursor_kern *cursor);
> > >   bool xfs_attr_namecheck(const void *name, size_t length);
> > > -- 
> > > 2.7.4
> > > 
> > 
> 


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

* Re: [PATCH v4 02/17] xfs: Replace attribute parameters with struct xfs_name
  2019-11-11 20:07     ` Allison Collins
@ 2019-11-13 15:12       ` Allison Collins
  2019-11-20 18:20         ` Christoph Hellwig
  0 siblings, 1 reply; 77+ messages in thread
From: Allison Collins @ 2019-11-13 15:12 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: linux-xfs, Dave Chinner



On 11/11/19 1:07 PM, Allison Collins wrote:
> 
> 
> On 11/11/19 10:49 AM, Christoph Hellwig wrote:
>> On Wed, Nov 06, 2019 at 06:27:46PM -0700, Allison Collins wrote:
>>> This patch replaces the attribute name and length parameters with a
>>> single struct xfs_name parameter.  This helps to clean up the numbers of
>>> parameters being passed around and pre-simplifies the code some.
>>
>> Does it?  As-is the patch doesn't look too bad, although it adds more
>> lines than it removes.  But together with the next patch that embedds
>> an xfs_name into the xfs_da_args structure and the now added memcpys
>> it doesn't really look very helpful to me.
>>
> It has evolved a bit since its initial proposition.  Maybe it would help 
> to raise the question of: is patch 2 or 3 alone more helpful than the 
> combination of them?  I think initially Dave had suggested the clean up 
> in one of the earlier reviews a while ago, so he may have an opinion here.
> 
> Personally I'm not super opinionated about it if people have strong 
> feelings toward keeping or pitching it.  I will say after having worked 
> with it as it is, I'm not sure I'm particularly fond of having a name 
> struct in the param, and another in the args.  I think eventually 
> someones going to forget that args supersedes the param after the init 
> routine.  People will probably figure it out pretty quick if they get 
> bit I suppose, but I do think it's a sort of wart to consider.
> 
> Allison

What if I added an xfs_name_init to reduce LOC. and then dropped patch 
3?  What would people think of that?

Allison

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

* Re: [PATCH v4 16/17] xfs: Add delay ready attr remove routines
  2019-11-13 11:54       ` Brian Foster
@ 2019-11-13 23:39         ` Allison Collins
  2019-11-14 12:48           ` Brian Foster
  0 siblings, 1 reply; 77+ messages in thread
From: Allison Collins @ 2019-11-13 23:39 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 11/13/19 4:54 AM, Brian Foster wrote:
> On Tue, Nov 12, 2019 at 05:43:04PM -0700, Allison Collins wrote:
>>
>>
>> On 11/12/19 6:37 AM, Brian Foster wrote:
>>> On Wed, Nov 06, 2019 at 06:28:00PM -0700, Allison Collins wrote:
>>>> This patch modifies the attr remove routines to be delay ready.
>>>> This means they no longer roll or commit transactions, but instead
>>>> return -EAGAIN to have the calling routine roll and refresh the
>>>> transaction.  In this series, xfs_attr_remove_args has become
>>>> xfs_attr_remove_later, which uses a state machine to keep track
>>>> of where it was when EAGAIN was returned.  xfs_attr_node_removename
>>>> has also been modified to use the state machine, and a  new version of
>>>> xfs_attr_remove_args consists of a simple loop to refresh the
>>>> transaction until the operation is completed.
>>>>
>>>> Signed-off-by: Allison Collins <allison.henderson@oracle.com>
>>>> ---
>>>
>>> On a cursory look, this is definitely more along the lines of what I was
>>> thinking on the previous revisions. I would like to see if we can get a
>>> bit more refactoring/cleanup before this point though. Further thoughts
>>> inline..
>>>
>>>>    fs/xfs/libxfs/xfs_attr.c | 123 +++++++++++++++++++++++++++++++++++++++--------
>>>>    fs/xfs/libxfs/xfs_attr.h |   1 +
>>>>    2 files changed, 104 insertions(+), 20 deletions(-)
>>>>
>>>> diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
>>>> index 626d4a98..38d5c5c 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr.c
>>>> +++ b/fs/xfs/libxfs/xfs_attr.c
>>>> @@ -369,10 +369,56 @@ xfs_has_attr(
>>>>     */
>>>>    int
>>>>    xfs_attr_remove_args(
>>>> +	struct xfs_da_args	*args)
>>>> +{
>>>> +	int			error = 0;
>>>> +	int			err2 = 0;
>>>> +
>>>> +	do {
>>>> +		error = xfs_attr_remove_later(args);
>>>> +		if (error && error != -EAGAIN)
>>>> +			goto out;
>>>
>>> xfs_attr_remove_later() strikes me as an odd name with respect to the
>>> functionality. Perhaps something like xfs_attr_remove_step() is
>>> (slightly) more accurate..?
>> Sure that's fine.  I think Darrick had proposed the *_later scheme in an
>> earlier review but that was when the code paths were split.  Darrick, does
>> the *_step scheme work for you?
>>
> 
> FWIW, xfs_attr_remove_iter() also came to mind after sending the
> previous mail.
Alrighty, I am fine with a *_iter scheme then

> 
>>>
>>>> +
>>>> +		xfs_trans_log_inode(args->trans, args->dp,
>>>> +			XFS_ILOG_CORE | XFS_ILOG_ADATA);
>>>> +
>>>> +		err2 = xfs_trans_roll(&args->trans);
>>>> +		if (err2) {
>>>> +			error = err2;
>>>
>>> Also do we really need two error codes in this function? It seems like
>>> we should be able to write this with one, but I haven't tried it..
>> No, because then we'll loose the xfs_attr_remove_later return code, which is
>> either 0 or EAGAIN at this point.  And we need that to drive the loop.  To
>> get rid of err2, we'd need another "not_done" variable or something.  Like:
>>
>> do {
>> 	...
>> 	not_done = (error == -EAGAIN);
>> 	...
>> } while (not_done)
>>
>>
>> Not sure if not_done is really preferable to err2?
>>
> 
> Eh, NBD. It just looked like potentially verbose logic on a quick scan.
> On a closer look, I see that we want to handle both error == 0 and error
> == -EAGAIN, so this seems fine as is to me.
> 
>>>
>>>> +			goto out;
>>>> +		}
>>>> +
>>>> +		/* Rejoin inode */
>>>> +		xfs_trans_ijoin(args->trans, args->dp, 0);
>>>> +
>>>> +	} while (error == -EAGAIN);
>>>> +out:
>>>> +	return error;
>>>> +}
>>>> +
>>>> +/*
>>>> + * Remove the attribute specified in @args.
>>>> + * This routine is meant to function as a delayed operation, and may return
>>>> + * -EGAIN when the transaction needs to be rolled.  Calling functions will need
>>>> + * to handle this, and recall the function until a successful error code is
>>>> + * returned.
>>>> + */
>>>> +int
>>>> +xfs_attr_remove_later(
>>>>    	struct xfs_da_args      *args)
>>>>    {
>>>>    	struct xfs_inode	*dp = args->dp;
>>>> -	int			error;
>>>> +	int			error = 0;
>>>> +
>>>> +	/* State machine switch */
>>>> +	switch (args->dc.dc_state) {
>>>> +	case XFS_DC_RM_INVALIDATE:
>>>> +	case XFS_DC_RM_SHRINK:
>>>> +	case XFS_DC_RM_NODE_BLKS:
>>>> +		goto node;
>>>> +	default:
>>>> +		break;
>>>> +	}
>>>>    	if (!xfs_inode_hasattr(dp)) {
>>>>    		error = -ENOATTR;
>>>> @@ -382,6 +428,7 @@ xfs_attr_remove_args(
>>>>    	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
>>>>    		error = xfs_attr_leaf_removename(args);
>>>>    	} else {
>>>> +node:
>>>>    		error = xfs_attr_node_removename(args);
>>>>    	}
>>>> @@ -892,9 +939,6 @@ xfs_attr_leaf_removename(
>>>>    		/* bp is gone due to xfs_da_shrink_inode */
>>>>    		if (error)
>>>>    			return error;
>>>> -		error = xfs_defer_finish(&args->trans);
>>>> -		if (error)
>>>> -			return error;
>>>>    	}
>>>>    	return 0;
>>>>    }
>>>> @@ -1212,6 +1256,11 @@ xfs_attr_node_addname(
>>>>     * This will involve walking down the Btree, and may involve joining
>>>>     * leaf nodes and even joining intermediate nodes up to and including
>>>>     * the root node (a special case of an intermediate node).
>>>> + *
>>>> + * This routine is meant to function as a delayed operation, and may return
>>>> + * -EAGAIN when the transaction needs to be rolled.  Calling functions
>>>> + * will need to handle this, and recall the function until a successful error
>>>> + * code is returned.
>>>>     */
>>>>    STATIC int
>>>>    xfs_attr_node_removename(
>>>> @@ -1222,12 +1271,29 @@ xfs_attr_node_removename(
>>>>    	struct xfs_buf		*bp;
>>>>    	int			retval, error, forkoff;
>>>>    	struct xfs_inode	*dp = args->dp;
>>>> +	int			done = 0;
>>>>    	trace_xfs_attr_node_removename(args);
>>>> +	state = args->dc.da_state;
>>>> +	blk = args->dc.blk;
>>>> +
>>>> +	/* State machine switch */
>>>> +	switch (args->dc.dc_state) {
>>>> +	case XFS_DC_RM_NODE_BLKS:
>>>> +		goto rm_node_blks;
>>>> +	case XFS_DC_RM_INVALIDATE:
>>>> +		goto rm_invalidate;
>>>> +	case XFS_DC_RM_SHRINK:
>>>> +		goto rm_shrink;
>>>> +	default:
>>>> +		break;
>>>
>>> I wonder if it's worth having an explicit state for the initial path.
>>> That could be useful for readability and debuggability in the future.
>> We could, it will just require to the calling function to set that before
>> state calling it.
>>
> 
> Looking back, I see we have XFS_DC_INIT in the enum, but it isn't used.
> What is that particular state for? Any reason the enum doesn't start
> with a value of 0?
Yes, sorry, it's used in the next patch series when we get into to the 
real delayed attr infrastructure.  I just forgot to take it out of the 
smaller subset here.

Basically all the use cases thus far already have args initialized, but 
in the log replay, we have to construct args from the log entry.  So we 
need the extra state to not re-initialize it every time and wipe out the 
state.  That use case is little more unique in that we have to set up 
the state machine after the ping pong has already started.

> 
>> Mechanically, I dont think it would hurt anything, but it may lead to
>> developer wonderments like... "Where's the EAGAIN for this state?" "Shouldnt
>> this state appear in the switch up top too?"  Or if it does "Why do we have
>> it here, if it never executes?"  "I wonder if i should sent a patch to take
>> it out..." :-)
>>
> 
> Perhaps, though some of those questions already exist with the current
> code. Not every function cares about every state from what I can tell.
> Also, not every state that can return -EAGAIN is guaranteed to do so.
> 
>> Puzzlement aside though, I cant quite think of what condition it would help
>> to debug?  It's not an error for the statemachine to hold a value outside of
>> the helpers scope.  It just means the caller was using it up to this point.
>> Helpers really shouldnt have enough context about their callers to know or
>> care what the caller states mean.  If we added a special init state, all the
>> default statement would really mean is: "The caller forgot to set the init
>> state".
>>
> 
> See my question above around the existing init state. However that is
> intended to be used is not really clear to me. BTW, it might be better
> to introduce the core structures in one patch and add the individual
> states as they are used by the subsequent patches that use them.
Ok, I will introduce the states progressively then, I think that caused 
the confusion

> 
> WRT to readability/debuggability, I suppose a simple example would be to
> consider if we had a tracepoint somewhere in the higher level code that
> printed state and error code and we wanted to use that to identify an
> unexpected error that occurs during an attr op. With the current code,
> if that printed something like:
> 
> 	state INVALIDATE error -EIO
> 
> ... that doesn't tell us a whole lot about what happened beyond
> something failed sometime after the setflag state. The attr itself might
> not even have remote blocks to invalidate, which is slightly confusing.
> This is handwavy/subjective, of course..
Yes, as it is, it doesn't really have any way of detecting a corrupt 
state.  Really though, if we want to do that what we need is another 
layer of modeling where we enforce the sequence of the states.  So for 
example, some sort of mapping or tree that defines: XFS_DC_LEAF_TO_NODE 
and XFS_DC_FOUND_LBLK as being children (or mappings) of 
XFS_DC_SF_TO_LEAF.

In other words, if the state is XFS_DC_SF_TO_LEAF, you can change it to 
XFS_DC_FOUND_LBLK or XFS_DC_LEAF_TO_NODE, but you can't go to say 
XFS_DC_RM_SHRINK, that would generate an error.  And then we have some 
sort of set_state() routine to enforce these rules.

That's a lot of extra overhead though, and could be more of a burden 
than a help.  But it's something we could explore if people think it's 
worth the pursuit.

Allison
> 
>> Thoughts?
>>
>>>
>>>> +	}
>>>>    	error = xfs_attr_node_hasname(args, &state);
>>>>    	if (error != -EEXIST)
>>>>    		goto out;
>>>> +	else
>>>> +		error = 0;
>>>>    	/*
>>>>    	 * If there is an out-of-line value, de-allocate the blocks.
>>>> @@ -1237,6 +1303,14 @@ xfs_attr_node_removename(
>>>>    	blk = &state->path.blk[ state->path.active-1 ];
>>>>    	ASSERT(blk->bp != NULL);
>>>>    	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>>>> +
>>>> +	/*
>>>> +	 * Store blk and state in the context incase we need to cycle out the
>>>> +	 * transaction
>>>> +	 */
>>>> +	args->dc.blk = blk;
>>>> +	args->dc.da_state = state;
>>>> +
>>>>    	if (args->rmtblkno > 0) {
>>>>    		/*
>>>>    		 * Fill in disk block numbers in the state structure
>>>> @@ -1255,13 +1329,30 @@ xfs_attr_node_removename(
>>>>    		if (error)
>>>>    			goto out;
>>>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>>>> +		args->dc.dc_state = XFS_DC_RM_INVALIDATE;
>>>> +		return -EAGAIN;
>>>> +rm_invalidate:
>>>> +		error = xfs_attr_rmtval_invalidate(args);
>>>>    		if (error)
>>>>    			goto out;
>>>> +rm_node_blks:
>>>
>>> While I think the design is the right idea, jumping down into a function
>>> like this is pretty hairy. I think we should try to further break this
>>> function down into smaller elements one way or another that model the
>>> steps defined by the state structure. There's probably multiple ways to
>>> do that. For example, the remote attr bits could be broken down into
>>> a subfunction that processes the couple of states associated with remote
>>> blocks. That said, ISTM it might be wiser to try and keep the state
>>> processing in one place if possible. That would imply to break the
>>> remote processing loop down into a couple functions. All in all, this
>>> function might end up looking something like:
>>>
>>> xfs_attr_node_removename()
>>> {
>>> 	/* switch statement and comment to document each state */
>>>
>>> 	error = xfs_attr_node_hasname(args, &state);
>>> 	...
>>>
>>> 	if (remote) {
>>> 		error = do_setflag();
>>> 		if (error)
>>> 			return error;
>>>
>>> 		/* roll */
>>> 		state = INVALIDATE;
>>> 		return -EAGAIN;
>>> 	}
>>>
>>> rmt_invalidate:
>>> 	state = INVALIDATE;
>>> 	if (remote)
>>> 		do_invalidate();
>>> 	/* fallthru */
>>>
>>> rmt_rm_blks:
>>> 	state = RM_NODE_BLKS;
>>> 	if (remote) {
>>> 		/* loops and returns -EAGAIN until we fallthru */
>>> 		error = rmt_remove_step();
>>> 		if (error)
>>> 			return error;
>>>
>>> 		xfs_attr_refillstate();
>>> 	}
>>>
>>> /* maybe worth a new state here? */
>>> removename:
>>> 	state = REMOVENAME;
>>> 	xfs_attr3_leaf_remove();
>>> 	...
>>> 	if (...) {
>>> 		state = SHRINK;
>>> 		return -EAGAIN;
>>> 	}
>>>
>>> shrink:
>>> 	state = SHRINK;
>>> 	error = do_shrink();
>>>
>>> 	return 0;
>>> }
>> Ok, I had to go over this a few times, but I think I understand what you're
>> describing.  Will update in the next version
>>>
>>> I'm not totally sold on the idea of rolling the state forward explicitly
>>> like this, but it seems like it could be a bit more maintainable.
>> I think it is.  Having a dedicated struct just for this purpose alleviates a
>> lot of struggle with trying to grab onto things like the fork or the
>> incomplete flags to represent what we're trying to do here. Doing so also
>> overloads their original intent in that if these structures ever change in
>> the future, it may break something that the state machine depends on.  In
>> this solution, they remain disjoint concepts dedicated to their purpose.
>> And anyway, I couldn't completely escape the state machine in the previous
>> set.  I still had to add the extra flag space which functioned more or less
>> like "i was here" tick marks.  If we have to have it, we may as well
>> leverage what it can do. For example I can drop patch 11 from this set
>> because I don't need the extra isset helpers to see if it's already been
>> done.
>>
> 
> Right.. I agree that the "bookmark" like approach in the current scheme
> makes the state implementation (and not necessarily the operational
> implementation) a little hard to follow and review. Note again that what
> I wrote up here was just a quick example for that higher level feedback
> of somehow or another trying to isolate state updates from state
> implementation, so I'm not necessarily tied to that specific approach if
> there are other ways to similarly simplify things.
> 
> I do think fixing up the code to avoid jumping into loops and whatnot is
> more important. It could also be that just continuing to break things
> down into as small functions as possible (i.e. with a goal of 1 function
> per state) kind of forces a natural separation.
> 
> Brian
> 
>>   All in
>>> all this is still fairly ugly, but this is mostly a mechanical attempt
>>> to keep state management isolated and we can polish it up from there.
>>> Thoughts?
>>
>> Yes, at this point, I do kind of feel like it's the least of the ugly
>> prototypes.  So I'm just kind of proceeding, with caution. :-)
>>
>> Thanks for the in depths reviews!!  I know its a lot!  Much appreciated!!
>>
>> Allison
>>
>>>
>>> Brian
>>>
>>>> +		/*
>>>> +		 * Unmap value blocks for this attr.  This is similar to
>>>> +		 * xfs_attr_rmtval_remove, but open coded here to return EAGAIN
>>>> +		 * for new transactions
>>>> +		 */
>>>> +		while (!done && !error) {
>>>> +			error = xfs_bunmapi(args->trans, args->dp,
>>>> +				    args->rmtblkno, args->rmtblkcnt,
>>>> +				    XFS_BMAPI_ATTRFORK, 1, &done);
>>>> +			if (error)
>>>> +				return error;
>>>> -		error = xfs_attr_rmtval_remove(args);
>>>> -		if (error)
>>>> -			goto out;
>>>> +			if (!done) {
>>>> +				args->dc.dc_state = XFS_DC_RM_NODE_BLKS;
>>>> +				return -EAGAIN;
>>>> +			}
>>>> +		}
>>>>    		/*
>>>>    		 * Refill the state structure with buffers, the prior calls
>>>> @@ -1287,17 +1378,12 @@ xfs_attr_node_removename(
>>>>    		error = xfs_da3_join(state);
>>>>    		if (error)
>>>>    			goto out;
>>>> -		error = xfs_defer_finish(&args->trans);
>>>> -		if (error)
>>>> -			goto out;
>>>> -		/*
>>>> -		 * Commit the Btree join operation and start a new trans.
>>>> -		 */
>>>> -		error = xfs_trans_roll_inode(&args->trans, dp);
>>>> -		if (error)
>>>> -			goto out;
>>>> +
>>>> +		args->dc.dc_state = XFS_DC_RM_SHRINK;
>>>> +		return -EAGAIN;
>>>>    	}
>>>> +rm_shrink:
>>>>    	/*
>>>>    	 * If the result is small enough, push it all into the inode.
>>>>    	 */
>>>> @@ -1319,9 +1405,6 @@ xfs_attr_node_removename(
>>>>    			/* bp is gone due to xfs_da_shrink_inode */
>>>>    			if (error)
>>>>    				goto out;
>>>> -			error = xfs_defer_finish(&args->trans);
>>>> -			if (error)
>>>> -				goto out;
>>>>    		} else
>>>>    			xfs_trans_brelse(args->trans, bp);
>>>>    	}
>>>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>>>> index 3b5dad4..fb8bf5b 100644
>>>> --- a/fs/xfs/libxfs/xfs_attr.h
>>>> +++ b/fs/xfs/libxfs/xfs_attr.h
>>>> @@ -152,6 +152,7 @@ int xfs_attr_set_args(struct xfs_da_args *args);
>>>>    int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
>>>>    int xfs_has_attr(struct xfs_da_args *args);
>>>>    int xfs_attr_remove_args(struct xfs_da_args *args);
>>>> +int xfs_attr_remove_later(struct xfs_da_args *args);
>>>>    int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>>>>    		  int flags, struct attrlist_cursor_kern *cursor);
>>>>    bool xfs_attr_namecheck(const void *name, size_t length);
>>>> -- 
>>>> 2.7.4
>>>>
>>>
>>
> 

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

* Re: [PATCH v4 16/17] xfs: Add delay ready attr remove routines
  2019-11-13 23:39         ` Allison Collins
@ 2019-11-14 12:48           ` Brian Foster
  2019-11-14 17:58             ` Allison Collins
  0 siblings, 1 reply; 77+ messages in thread
From: Brian Foster @ 2019-11-14 12:48 UTC (permalink / raw)
  To: Allison Collins; +Cc: linux-xfs

On Wed, Nov 13, 2019 at 04:39:18PM -0700, Allison Collins wrote:
> 
> 
> On 11/13/19 4:54 AM, Brian Foster wrote:
> > On Tue, Nov 12, 2019 at 05:43:04PM -0700, Allison Collins wrote:
> > > 
> > > 
> > > On 11/12/19 6:37 AM, Brian Foster wrote:
> > > > On Wed, Nov 06, 2019 at 06:28:00PM -0700, Allison Collins wrote:
> > > > > This patch modifies the attr remove routines to be delay ready.
> > > > > This means they no longer roll or commit transactions, but instead
> > > > > return -EAGAIN to have the calling routine roll and refresh the
> > > > > transaction.  In this series, xfs_attr_remove_args has become
> > > > > xfs_attr_remove_later, which uses a state machine to keep track
> > > > > of where it was when EAGAIN was returned.  xfs_attr_node_removename
> > > > > has also been modified to use the state machine, and a  new version of
> > > > > xfs_attr_remove_args consists of a simple loop to refresh the
> > > > > transaction until the operation is completed.
> > > > > 
> > > > > Signed-off-by: Allison Collins <allison.henderson@oracle.com>
> > > > > ---
> > > > 
> > > > On a cursory look, this is definitely more along the lines of what I was
> > > > thinking on the previous revisions. I would like to see if we can get a
> > > > bit more refactoring/cleanup before this point though. Further thoughts
> > > > inline..
> > > > 
> > > > >    fs/xfs/libxfs/xfs_attr.c | 123 +++++++++++++++++++++++++++++++++++++++--------
> > > > >    fs/xfs/libxfs/xfs_attr.h |   1 +
> > > > >    2 files changed, 104 insertions(+), 20 deletions(-)
> > > > > 
> > > > > diff --git a/fs/xfs/libxfs/xfs_attr.c b/fs/xfs/libxfs/xfs_attr.c
> > > > > index 626d4a98..38d5c5c 100644
> > > > > --- a/fs/xfs/libxfs/xfs_attr.c
> > > > > +++ b/fs/xfs/libxfs/xfs_attr.c
> > > > > @@ -369,10 +369,56 @@ xfs_has_attr(
> > > > >     */
> > > > >    int
> > > > >    xfs_attr_remove_args(
> > > > > +	struct xfs_da_args	*args)
> > > > > +{
> > > > > +	int			error = 0;
> > > > > +	int			err2 = 0;
> > > > > +
> > > > > +	do {
> > > > > +		error = xfs_attr_remove_later(args);
> > > > > +		if (error && error != -EAGAIN)
> > > > > +			goto out;
> > > > 
> > > > xfs_attr_remove_later() strikes me as an odd name with respect to the
> > > > functionality. Perhaps something like xfs_attr_remove_step() is
> > > > (slightly) more accurate..?
> > > Sure that's fine.  I think Darrick had proposed the *_later scheme in an
> > > earlier review but that was when the code paths were split.  Darrick, does
> > > the *_step scheme work for you?
> > > 
> > 
> > FWIW, xfs_attr_remove_iter() also came to mind after sending the
> > previous mail.
> Alrighty, I am fine with a *_iter scheme then
> 
> > 
> > > > 
> > > > > +
> > > > > +		xfs_trans_log_inode(args->trans, args->dp,
> > > > > +			XFS_ILOG_CORE | XFS_ILOG_ADATA);
> > > > > +
> > > > > +		err2 = xfs_trans_roll(&args->trans);
> > > > > +		if (err2) {
> > > > > +			error = err2;
> > > > 
> > > > Also do we really need two error codes in this function? It seems like
> > > > we should be able to write this with one, but I haven't tried it..
> > > No, because then we'll loose the xfs_attr_remove_later return code, which is
> > > either 0 or EAGAIN at this point.  And we need that to drive the loop.  To
> > > get rid of err2, we'd need another "not_done" variable or something.  Like:
> > > 
> > > do {
> > > 	...
> > > 	not_done = (error == -EAGAIN);
> > > 	...
> > > } while (not_done)
> > > 
> > > 
> > > Not sure if not_done is really preferable to err2?
> > > 
> > 
> > Eh, NBD. It just looked like potentially verbose logic on a quick scan.
> > On a closer look, I see that we want to handle both error == 0 and error
> > == -EAGAIN, so this seems fine as is to me.
> > 
> > > > 
> > > > > +			goto out;
> > > > > +		}
> > > > > +
> > > > > +		/* Rejoin inode */
> > > > > +		xfs_trans_ijoin(args->trans, args->dp, 0);
> > > > > +
> > > > > +	} while (error == -EAGAIN);
> > > > > +out:
> > > > > +	return error;
> > > > > +}
> > > > > +
> > > > > +/*
> > > > > + * Remove the attribute specified in @args.
> > > > > + * This routine is meant to function as a delayed operation, and may return
> > > > > + * -EGAIN when the transaction needs to be rolled.  Calling functions will need
> > > > > + * to handle this, and recall the function until a successful error code is
> > > > > + * returned.
> > > > > + */
> > > > > +int
> > > > > +xfs_attr_remove_later(
> > > > >    	struct xfs_da_args      *args)
> > > > >    {
> > > > >    	struct xfs_inode	*dp = args->dp;
> > > > > -	int			error;
> > > > > +	int			error = 0;
> > > > > +
> > > > > +	/* State machine switch */
> > > > > +	switch (args->dc.dc_state) {
> > > > > +	case XFS_DC_RM_INVALIDATE:
> > > > > +	case XFS_DC_RM_SHRINK:
> > > > > +	case XFS_DC_RM_NODE_BLKS:
> > > > > +		goto node;
> > > > > +	default:
> > > > > +		break;
> > > > > +	}
> > > > >    	if (!xfs_inode_hasattr(dp)) {
> > > > >    		error = -ENOATTR;
> > > > > @@ -382,6 +428,7 @@ xfs_attr_remove_args(
> > > > >    	} else if (xfs_bmap_one_block(dp, XFS_ATTR_FORK)) {
> > > > >    		error = xfs_attr_leaf_removename(args);
> > > > >    	} else {
> > > > > +node:
> > > > >    		error = xfs_attr_node_removename(args);
> > > > >    	}
> > > > > @@ -892,9 +939,6 @@ xfs_attr_leaf_removename(
> > > > >    		/* bp is gone due to xfs_da_shrink_inode */
> > > > >    		if (error)
> > > > >    			return error;
> > > > > -		error = xfs_defer_finish(&args->trans);
> > > > > -		if (error)
> > > > > -			return error;
> > > > >    	}
> > > > >    	return 0;
> > > > >    }
> > > > > @@ -1212,6 +1256,11 @@ xfs_attr_node_addname(
> > > > >     * This will involve walking down the Btree, and may involve joining
> > > > >     * leaf nodes and even joining intermediate nodes up to and including
> > > > >     * the root node (a special case of an intermediate node).
> > > > > + *
> > > > > + * This routine is meant to function as a delayed operation, and may return
> > > > > + * -EAGAIN when the transaction needs to be rolled.  Calling functions
> > > > > + * will need to handle this, and recall the function until a successful error
> > > > > + * code is returned.
> > > > >     */
> > > > >    STATIC int
> > > > >    xfs_attr_node_removename(
> > > > > @@ -1222,12 +1271,29 @@ xfs_attr_node_removename(
> > > > >    	struct xfs_buf		*bp;
> > > > >    	int			retval, error, forkoff;
> > > > >    	struct xfs_inode	*dp = args->dp;
> > > > > +	int			done = 0;
> > > > >    	trace_xfs_attr_node_removename(args);
> > > > > +	state = args->dc.da_state;
> > > > > +	blk = args->dc.blk;
> > > > > +
> > > > > +	/* State machine switch */
> > > > > +	switch (args->dc.dc_state) {
> > > > > +	case XFS_DC_RM_NODE_BLKS:
> > > > > +		goto rm_node_blks;
> > > > > +	case XFS_DC_RM_INVALIDATE:
> > > > > +		goto rm_invalidate;
> > > > > +	case XFS_DC_RM_SHRINK:
> > > > > +		goto rm_shrink;
> > > > > +	default:
> > > > > +		break;
> > > > 
> > > > I wonder if it's worth having an explicit state for the initial path.
> > > > That could be useful for readability and debuggability in the future.
> > > We could, it will just require to the calling function to set that before
> > > state calling it.
> > > 
> > 
> > Looking back, I see we have XFS_DC_INIT in the enum, but it isn't used.
> > What is that particular state for? Any reason the enum doesn't start
> > with a value of 0?
> Yes, sorry, it's used in the next patch series when we get into to the real
> delayed attr infrastructure.  I just forgot to take it out of the smaller
> subset here.
> 
> Basically all the use cases thus far already have args initialized, but in
> the log replay, we have to construct args from the log entry.  So we need
> the extra state to not re-initialize it every time and wipe out the state.
> That use case is little more unique in that we have to set up the state
> machine after the ping pong has already started.
> 
> > 
> > > Mechanically, I dont think it would hurt anything, but it may lead to
> > > developer wonderments like... "Where's the EAGAIN for this state?" "Shouldnt
> > > this state appear in the switch up top too?"  Or if it does "Why do we have
> > > it here, if it never executes?"  "I wonder if i should sent a patch to take
> > > it out..." :-)
> > > 
> > 
> > Perhaps, though some of those questions already exist with the current
> > code. Not every function cares about every state from what I can tell.
> > Also, not every state that can return -EAGAIN is guaranteed to do so.
> > 
> > > Puzzlement aside though, I cant quite think of what condition it would help
> > > to debug?  It's not an error for the statemachine to hold a value outside of
> > > the helpers scope.  It just means the caller was using it up to this point.
> > > Helpers really shouldnt have enough context about their callers to know or
> > > care what the caller states mean.  If we added a special init state, all the
> > > default statement would really mean is: "The caller forgot to set the init
> > > state".
> > > 
> > 
> > See my question above around the existing init state. However that is
> > intended to be used is not really clear to me. BTW, it might be better
> > to introduce the core structures in one patch and add the individual
> > states as they are used by the subsequent patches that use them.
> Ok, I will introduce the states progressively then, I think that caused the
> confusion
> 
> > 
> > WRT to readability/debuggability, I suppose a simple example would be to
> > consider if we had a tracepoint somewhere in the higher level code that
> > printed state and error code and we wanted to use that to identify an
> > unexpected error that occurs during an attr op. With the current code,
> > if that printed something like:
> > 
> > 	state INVALIDATE error -EIO
> > 
> > ... that doesn't tell us a whole lot about what happened beyond
> > something failed sometime after the setflag state. The attr itself might
> > not even have remote blocks to invalidate, which is slightly confusing.
> > This is handwavy/subjective, of course..
> Yes, as it is, it doesn't really have any way of detecting a corrupt state.
> Really though, if we want to do that what we need is another layer of
> modeling where we enforce the sequence of the states.  So for example, some
> sort of mapping or tree that defines: XFS_DC_LEAF_TO_NODE and
> XFS_DC_FOUND_LBLK as being children (or mappings) of XFS_DC_SF_TO_LEAF.
> 
> In other words, if the state is XFS_DC_SF_TO_LEAF, you can change it to
> XFS_DC_FOUND_LBLK or XFS_DC_LEAF_TO_NODE, but you can't go to say
> XFS_DC_RM_SHRINK, that would generate an error.  And then we have some sort
> of set_state() routine to enforce these rules.
> 
> That's a lot of extra overhead though, and could be more of a burden than a
> help.  But it's something we could explore if people think it's worth the
> pursuit.
> 

Yeah, I don't think it's necessary to go so far as to create a complex
set of rules and whatnot purely for the purpose of validating state
management. I'm just handwaving about potentially structuring the code
such that the state management is clear and easy to follow. :)

Brian

> Allison
> > 
> > > Thoughts?
> > > 
> > > > 
> > > > > +	}
> > > > >    	error = xfs_attr_node_hasname(args, &state);
> > > > >    	if (error != -EEXIST)
> > > > >    		goto out;
> > > > > +	else
> > > > > +		error = 0;
> > > > >    	/*
> > > > >    	 * If there is an out-of-line value, de-allocate the blocks.
> > > > > @@ -1237,6 +1303,14 @@ xfs_attr_node_removename(
> > > > >    	blk = &state->path.blk[ state->path.active-1 ];
> > > > >    	ASSERT(blk->bp != NULL);
> > > > >    	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
> > > > > +
> > > > > +	/*
> > > > > +	 * Store blk and state in the context incase we need to cycle out the
> > > > > +	 * transaction
> > > > > +	 */
> > > > > +	args->dc.blk = blk;
> > > > > +	args->dc.da_state = state;
> > > > > +
> > > > >    	if (args->rmtblkno > 0) {
> > > > >    		/*
> > > > >    		 * Fill in disk block numbers in the state structure
> > > > > @@ -1255,13 +1329,30 @@ xfs_attr_node_removename(
> > > > >    		if (error)
> > > > >    			goto out;
> > > > > -		error = xfs_trans_roll_inode(&args->trans, args->dp);
> > > > > +		args->dc.dc_state = XFS_DC_RM_INVALIDATE;
> > > > > +		return -EAGAIN;
> > > > > +rm_invalidate:
> > > > > +		error = xfs_attr_rmtval_invalidate(args);
> > > > >    		if (error)
> > > > >    			goto out;
> > > > > +rm_node_blks:
> > > > 
> > > > While I think the design is the right idea, jumping down into a function
> > > > like this is pretty hairy. I think we should try to further break this
> > > > function down into smaller elements one way or another that model the
> > > > steps defined by the state structure. There's probably multiple ways to
> > > > do that. For example, the remote attr bits could be broken down into
> > > > a subfunction that processes the couple of states associated with remote
> > > > blocks. That said, ISTM it might be wiser to try and keep the state
> > > > processing in one place if possible. That would imply to break the
> > > > remote processing loop down into a couple functions. All in all, this
> > > > function might end up looking something like:
> > > > 
> > > > xfs_attr_node_removename()
> > > > {
> > > > 	/* switch statement and comment to document each state */
> > > > 
> > > > 	error = xfs_attr_node_hasname(args, &state);
> > > > 	...
> > > > 
> > > > 	if (remote) {
> > > > 		error = do_setflag();
> > > > 		if (error)
> > > > 			return error;
> > > > 
> > > > 		/* roll */
> > > > 		state = INVALIDATE;
> > > > 		return -EAGAIN;
> > > > 	}
> > > > 
> > > > rmt_invalidate:
> > > > 	state = INVALIDATE;
> > > > 	if (remote)
> > > > 		do_invalidate();
> > > > 	/* fallthru */
> > > > 
> > > > rmt_rm_blks:
> > > > 	state = RM_NODE_BLKS;
> > > > 	if (remote) {
> > > > 		/* loops and returns -EAGAIN until we fallthru */
> > > > 		error = rmt_remove_step();
> > > > 		if (error)
> > > > 			return error;
> > > > 
> > > > 		xfs_attr_refillstate();
> > > > 	}
> > > > 
> > > > /* maybe worth a new state here? */
> > > > removename:
> > > > 	state = REMOVENAME;
> > > > 	xfs_attr3_leaf_remove();
> > > > 	...
> > > > 	if (...) {
> > > > 		state = SHRINK;
> > > > 		return -EAGAIN;
> > > > 	}
> > > > 
> > > > shrink:
> > > > 	state = SHRINK;
> > > > 	error = do_shrink();
> > > > 
> > > > 	return 0;
> > > > }
> > > Ok, I had to go over this a few times, but I think I understand what you're
> > > describing.  Will update in the next version
> > > > 
> > > > I'm not totally sold on the idea of rolling the state forward explicitly
> > > > like this, but it seems like it could be a bit more maintainable.
> > > I think it is.  Having a dedicated struct just for this purpose alleviates a
> > > lot of struggle with trying to grab onto things like the fork or the
> > > incomplete flags to represent what we're trying to do here. Doing so also
> > > overloads their original intent in that if these structures ever change in
> > > the future, it may break something that the state machine depends on.  In
> > > this solution, they remain disjoint concepts dedicated to their purpose.
> > > And anyway, I couldn't completely escape the state machine in the previous
> > > set.  I still had to add the extra flag space which functioned more or less
> > > like "i was here" tick marks.  If we have to have it, we may as well
> > > leverage what it can do. For example I can drop patch 11 from this set
> > > because I don't need the extra isset helpers to see if it's already been
> > > done.
> > > 
> > 
> > Right.. I agree that the "bookmark" like approach in the current scheme
> > makes the state implementation (and not necessarily the operational
> > implementation) a little hard to follow and review. Note again that what
> > I wrote up here was just a quick example for that higher level feedback
> > of somehow or another trying to isolate state updates from state
> > implementation, so I'm not necessarily tied to that specific approach if
> > there are other ways to similarly simplify things.
> > 
> > I do think fixing up the code to avoid jumping into loops and whatnot is
> > more important. It could also be that just continuing to break things
> > down into as small functions as possible (i.e. with a goal of 1 function
> > per state) kind of forces a natural separation.
> > 
> > Brian
> > 
> > >   All in
> > > > all this is still fairly ugly, but this is mostly a mechanical attempt
> > > > to keep state management isolated and we can polish it up from there.
> > > > Thoughts?
> > > 
> > > Yes, at this point, I do kind of feel like it's the least of the ugly
> > > prototypes.  So I'm just kind of proceeding, with caution. :-)
> > > 
> > > Thanks for the in depths reviews!!  I know its a lot!  Much appreciated!!
> > > 
> > > Allison
> > > 
> > > > 
> > > > Brian
> > > > 
> > > > > +		/*
> > > > > +		 * Unmap value blocks for this attr.  This is similar to
> > > > > +		 * xfs_attr_rmtval_remove, but open coded here to return EAGAIN
> > > > > +		 * for new transactions
> > > > > +		 */
> > > > > +		while (!done && !error) {
> > > > > +			error = xfs_bunmapi(args->trans, args->dp,
> > > > > +				    args->rmtblkno, args->rmtblkcnt,
> > > > > +				    XFS_BMAPI_ATTRFORK, 1, &done);
> > > > > +			if (error)
> > > > > +				return error;
> > > > > -		error = xfs_attr_rmtval_remove(args);
> > > > > -		if (error)
> > > > > -			goto out;
> > > > > +			if (!done) {
> > > > > +				args->dc.dc_state = XFS_DC_RM_NODE_BLKS;
> > > > > +				return -EAGAIN;
> > > > > +			}
> > > > > +		}
> > > > >    		/*
> > > > >    		 * Refill the state structure with buffers, the prior calls
> > > > > @@ -1287,17 +1378,12 @@ xfs_attr_node_removename(
> > > > >    		error = xfs_da3_join(state);
> > > > >    		if (error)
> > > > >    			goto out;
> > > > > -		error = xfs_defer_finish(&args->trans);
> > > > > -		if (error)
> > > > > -			goto out;
> > > > > -		/*
> > > > > -		 * Commit the Btree join operation and start a new trans.
> > > > > -		 */
> > > > > -		error = xfs_trans_roll_inode(&args->trans, dp);
> > > > > -		if (error)
> > > > > -			goto out;
> > > > > +
> > > > > +		args->dc.dc_state = XFS_DC_RM_SHRINK;
> > > > > +		return -EAGAIN;
> > > > >    	}
> > > > > +rm_shrink:
> > > > >    	/*
> > > > >    	 * If the result is small enough, push it all into the inode.
> > > > >    	 */
> > > > > @@ -1319,9 +1405,6 @@ xfs_attr_node_removename(
> > > > >    			/* bp is gone due to xfs_da_shrink_inode */
> > > > >    			if (error)
> > > > >    				goto out;
> > > > > -			error = xfs_defer_finish(&args->trans);
> > > > > -			if (error)
> > > > > -				goto out;
> > > > >    		} else
> > > > >    			xfs_trans_brelse(args->trans, bp);
> > > > >    	}
> > > > > diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
> > > > > index 3b5dad4..fb8bf5b 100644
> > > > > --- a/fs/xfs/libxfs/xfs_attr.h
> > > > > +++ b/fs/xfs/libxfs/xfs_attr.h
> > > > > @@ -152,6 +152,7 @@ int xfs_attr_set_args(struct xfs_da_args *args);
> > > > >    int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
> > > > >    int xfs_has_attr(struct xfs_da_args *args);
> > > > >    int xfs_attr_remove_args(struct xfs_da_args *args);
> > > > > +int xfs_attr_remove_later(struct xfs_da_args *args);
> > > > >    int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
> > > > >    		  int flags, struct attrlist_cursor_kern *cursor);
> > > > >    bool xfs_attr_namecheck(const void *name, size_t length);
> > > > > -- 
> > > > > 2.7.4
> > > > > 
> > > > 
> > > 
> > 
> 


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

* Re: [PATCH v4 16/17] xfs: Add delay ready attr remove routines
  2019-11-14 12:48           ` Brian Foster
@ 2019-11-14 17:58             ` Allison Collins
  0 siblings, 0 replies; 77+ messages in thread
From: Allison Collins @ 2019-11-14 17:58 UTC (permalink / raw)
  To: Brian Foster; +Cc: linux-xfs



On 11/14/19 5:48 AM, Brian Foster wrote:
> On Wed, Nov 13, 2019 at 04:39:18PM -0700, Allison Collins wrote:
>>
>>
>> On 11/13/19 4:54 AM, Brian Foster wrote:

<snip>

>> Yes, as it is, it doesn't really have any way of detecting a corrupt state.
>> Really though, if we want to do that what we need is another layer of
>> modeling where we enforce the sequence of the states.  So for example, some
>> sort of mapping or tree that defines: XFS_DC_LEAF_TO_NODE and
>> XFS_DC_FOUND_LBLK as being children (or mappings) of XFS_DC_SF_TO_LEAF.
>>
>> In other words, if the state is XFS_DC_SF_TO_LEAF, you can change it to
>> XFS_DC_FOUND_LBLK or XFS_DC_LEAF_TO_NODE, but you can't go to say
>> XFS_DC_RM_SHRINK, that would generate an error.  And then we have some sort
>> of set_state() routine to enforce these rules.
>>
>> That's a lot of extra overhead though, and could be more of a burden than a
>> help.  But it's something we could explore if people think it's worth the
>> pursuit.
>>
> 
> Yeah, I don't think it's necessary to go so far as to create a complex
> set of rules and whatnot purely for the purpose of validating state
> management. I'm just handwaving about potentially structuring the code
> such that the state management is clear and easy to follow. :)
> 
> Brian

Yeah, that's kinda how I felt too.  Maybe later we could come back and 
reconsider it depending on how the refactoring goes.  I've done a little 
research online around about state machine designs, and usually what I 
see is some sort of mapping of state codes to function pointers.  So if 
it's possible to modularize everything into helpers, then an extra layer 
of abstraction starts to make a lot more sense.  But what we wouldn't 
want is so much refactoring that we have a bunch of little helpers so 
small and fragmented that the code flow is a headache to follow.  So I 
figure maybe for now we could just stick to refactoring snippets under 
the switch approach, and if it starts to look like something that could 
really benefit from a fully formed state machine model, we can consider 
it then :-)

Allison

> 
>> Allison
>>>
>>>> Thoughts?
>>>>
>>>>>
>>>>>> +	}
>>>>>>     	error = xfs_attr_node_hasname(args, &state);
>>>>>>     	if (error != -EEXIST)
>>>>>>     		goto out;
>>>>>> +	else
>>>>>> +		error = 0;
>>>>>>     	/*
>>>>>>     	 * If there is an out-of-line value, de-allocate the blocks.
>>>>>> @@ -1237,6 +1303,14 @@ xfs_attr_node_removename(
>>>>>>     	blk = &state->path.blk[ state->path.active-1 ];
>>>>>>     	ASSERT(blk->bp != NULL);
>>>>>>     	ASSERT(blk->magic == XFS_ATTR_LEAF_MAGIC);
>>>>>> +
>>>>>> +	/*
>>>>>> +	 * Store blk and state in the context incase we need to cycle out the
>>>>>> +	 * transaction
>>>>>> +	 */
>>>>>> +	args->dc.blk = blk;
>>>>>> +	args->dc.da_state = state;
>>>>>> +
>>>>>>     	if (args->rmtblkno > 0) {
>>>>>>     		/*
>>>>>>     		 * Fill in disk block numbers in the state structure
>>>>>> @@ -1255,13 +1329,30 @@ xfs_attr_node_removename(
>>>>>>     		if (error)
>>>>>>     			goto out;
>>>>>> -		error = xfs_trans_roll_inode(&args->trans, args->dp);
>>>>>> +		args->dc.dc_state = XFS_DC_RM_INVALIDATE;
>>>>>> +		return -EAGAIN;
>>>>>> +rm_invalidate:
>>>>>> +		error = xfs_attr_rmtval_invalidate(args);
>>>>>>     		if (error)
>>>>>>     			goto out;
>>>>>> +rm_node_blks:
>>>>>
>>>>> While I think the design is the right idea, jumping down into a function
>>>>> like this is pretty hairy. I think we should try to further break this
>>>>> function down into smaller elements one way or another that model the
>>>>> steps defined by the state structure. There's probably multiple ways to
>>>>> do that. For example, the remote attr bits could be broken down into
>>>>> a subfunction that processes the couple of states associated with remote
>>>>> blocks. That said, ISTM it might be wiser to try and keep the state
>>>>> processing in one place if possible. That would imply to break the
>>>>> remote processing loop down into a couple functions. All in all, this
>>>>> function might end up looking something like:
>>>>>
>>>>> xfs_attr_node_removename()
>>>>> {
>>>>> 	/* switch statement and comment to document each state */
>>>>>
>>>>> 	error = xfs_attr_node_hasname(args, &state);
>>>>> 	...
>>>>>
>>>>> 	if (remote) {
>>>>> 		error = do_setflag();
>>>>> 		if (error)
>>>>> 			return error;
>>>>>
>>>>> 		/* roll */
>>>>> 		state = INVALIDATE;
>>>>> 		return -EAGAIN;
>>>>> 	}
>>>>>
>>>>> rmt_invalidate:
>>>>> 	state = INVALIDATE;
>>>>> 	if (remote)
>>>>> 		do_invalidate();
>>>>> 	/* fallthru */
>>>>>
>>>>> rmt_rm_blks:
>>>>> 	state = RM_NODE_BLKS;
>>>>> 	if (remote) {
>>>>> 		/* loops and returns -EAGAIN until we fallthru */
>>>>> 		error = rmt_remove_step();
>>>>> 		if (error)
>>>>> 			return error;
>>>>>
>>>>> 		xfs_attr_refillstate();
>>>>> 	}
>>>>>
>>>>> /* maybe worth a new state here? */
>>>>> removename:
>>>>> 	state = REMOVENAME;
>>>>> 	xfs_attr3_leaf_remove();
>>>>> 	...
>>>>> 	if (...) {
>>>>> 		state = SHRINK;
>>>>> 		return -EAGAIN;
>>>>> 	}
>>>>>
>>>>> shrink:
>>>>> 	state = SHRINK;
>>>>> 	error = do_shrink();
>>>>>
>>>>> 	return 0;
>>>>> }
>>>> Ok, I had to go over this a few times, but I think I understand what you're
>>>> describing.  Will update in the next version
>>>>>
>>>>> I'm not totally sold on the idea of rolling the state forward explicitly
>>>>> like this, but it seems like it could be a bit more maintainable.
>>>> I think it is.  Having a dedicated struct just for this purpose alleviates a
>>>> lot of struggle with trying to grab onto things like the fork or the
>>>> incomplete flags to represent what we're trying to do here. Doing so also
>>>> overloads their original intent in that if these structures ever change in
>>>> the future, it may break something that the state machine depends on.  In
>>>> this solution, they remain disjoint concepts dedicated to their purpose.
>>>> And anyway, I couldn't completely escape the state machine in the previous
>>>> set.  I still had to add the extra flag space which functioned more or less
>>>> like "i was here" tick marks.  If we have to have it, we may as well
>>>> leverage what it can do. For example I can drop patch 11 from this set
>>>> because I don't need the extra isset helpers to see if it's already been
>>>> done.
>>>>
>>>
>>> Right.. I agree that the "bookmark" like approach in the current scheme
>>> makes the state implementation (and not necessarily the operational
>>> implementation) a little hard to follow and review. Note again that what
>>> I wrote up here was just a quick example for that higher level feedback
>>> of somehow or another trying to isolate state updates from state
>>> implementation, so I'm not necessarily tied to that specific approach if
>>> there are other ways to similarly simplify things.
>>>
>>> I do think fixing up the code to avoid jumping into loops and whatnot is
>>> more important. It could also be that just continuing to break things
>>> down into as small functions as possible (i.e. with a goal of 1 function
>>> per state) kind of forces a natural separation.
>>>
>>> Brian
>>>
>>>>    All in
>>>>> all this is still fairly ugly, but this is mostly a mechanical attempt
>>>>> to keep state management isolated and we can polish it up from there.
>>>>> Thoughts?
>>>>
>>>> Yes, at this point, I do kind of feel like it's the least of the ugly
>>>> prototypes.  So I'm just kind of proceeding, with caution. :-)
>>>>
>>>> Thanks for the in depths reviews!!  I know its a lot!  Much appreciated!!
>>>>
>>>> Allison
>>>>
>>>>>
>>>>> Brian
>>>>>
>>>>>> +		/*
>>>>>> +		 * Unmap value blocks for this attr.  This is similar to
>>>>>> +		 * xfs_attr_rmtval_remove, but open coded here to return EAGAIN
>>>>>> +		 * for new transactions
>>>>>> +		 */
>>>>>> +		while (!done && !error) {
>>>>>> +			error = xfs_bunmapi(args->trans, args->dp,
>>>>>> +				    args->rmtblkno, args->rmtblkcnt,
>>>>>> +				    XFS_BMAPI_ATTRFORK, 1, &done);
>>>>>> +			if (error)
>>>>>> +				return error;
>>>>>> -		error = xfs_attr_rmtval_remove(args);
>>>>>> -		if (error)
>>>>>> -			goto out;
>>>>>> +			if (!done) {
>>>>>> +				args->dc.dc_state = XFS_DC_RM_NODE_BLKS;
>>>>>> +				return -EAGAIN;
>>>>>> +			}
>>>>>> +		}
>>>>>>     		/*
>>>>>>     		 * Refill the state structure with buffers, the prior calls
>>>>>> @@ -1287,17 +1378,12 @@ xfs_attr_node_removename(
>>>>>>     		error = xfs_da3_join(state);
>>>>>>     		if (error)
>>>>>>     			goto out;
>>>>>> -		error = xfs_defer_finish(&args->trans);
>>>>>> -		if (error)
>>>>>> -			goto out;
>>>>>> -		/*
>>>>>> -		 * Commit the Btree join operation and start a new trans.
>>>>>> -		 */
>>>>>> -		error = xfs_trans_roll_inode(&args->trans, dp);
>>>>>> -		if (error)
>>>>>> -			goto out;
>>>>>> +
>>>>>> +		args->dc.dc_state = XFS_DC_RM_SHRINK;
>>>>>> +		return -EAGAIN;
>>>>>>     	}
>>>>>> +rm_shrink:
>>>>>>     	/*
>>>>>>     	 * If the result is small enough, push it all into the inode.
>>>>>>     	 */
>>>>>> @@ -1319,9 +1405,6 @@ xfs_attr_node_removename(
>>>>>>     			/* bp is gone due to xfs_da_shrink_inode */
>>>>>>     			if (error)
>>>>>>     				goto out;
>>>>>> -			error = xfs_defer_finish(&args->trans);
>>>>>> -			if (error)
>>>>>> -				goto out;
>>>>>>     		} else
>>>>>>     			xfs_trans_brelse(args->trans, bp);
>>>>>>     	}
>>>>>> diff --git a/fs/xfs/libxfs/xfs_attr.h b/fs/xfs/libxfs/xfs_attr.h
>>>>>> index 3b5dad4..fb8bf5b 100644
>>>>>> --- a/fs/xfs/libxfs/xfs_attr.h
>>>>>> +++ b/fs/xfs/libxfs/xfs_attr.h
>>>>>> @@ -152,6 +152,7 @@ int xfs_attr_set_args(struct xfs_da_args *args);
>>>>>>     int xfs_attr_remove(struct xfs_inode *dp, struct xfs_name *name, int flags);
>>>>>>     int xfs_has_attr(struct xfs_da_args *args);
>>>>>>     int xfs_attr_remove_args(struct xfs_da_args *args);
>>>>>> +int xfs_attr_remove_later(struct xfs_da_args *args);
>>>>>>     int xfs_attr_list(struct xfs_inode *dp, char *buffer, int bufsize,
>>>>>>     		  int flags, struct attrlist_cursor_kern *cursor);
>>>>>>     bool xfs_attr_namecheck(const void *name, size_t length);
>>>>>> -- 
>>>>>> 2.7.4
>>>>>>
>>>>>
>>>>
>>>
>>
> 

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

* Re: [PATCH v4 02/17] xfs: Replace attribute parameters with struct xfs_name
  2019-11-13 15:12       ` Allison Collins
@ 2019-11-20 18:20         ` Christoph Hellwig
  0 siblings, 0 replies; 77+ messages in thread
From: Christoph Hellwig @ 2019-11-20 18:20 UTC (permalink / raw)
  To: Allison Collins; +Cc: Christoph Hellwig, linux-xfs, Dave Chinner

On Wed, Nov 13, 2019 at 08:12:50AM -0700, Allison Collins wrote:
> What if I added an xfs_name_init to reduce LOC. and then dropped patch 3?
> What would people think of that?

I think we should just pass the da_args to the attr ops from the highest
level and remove the churn of passing the xfs_name there.

I've pushed out a compile tested only series here to illustrate what
I mean:

http://git.infradead.org/users/hch/xfs.git/shortlog/refs/heads/xfs-attr-cleanup

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

end of thread, other threads:[~2019-11-20 18:20 UTC | newest]

Thread overview: 77+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-07  1:27 [PATCH v4 00/17] xfs: Delay Ready Attributes Allison Collins
2019-11-07  1:27 ` [PATCH v4 01/17] xfs: Remove all strlen in all xfs_attr_* functions for attr names Allison Collins
2019-11-11 17:47   ` Christoph Hellwig
2019-11-11 23:35     ` Allison Collins
2019-11-07  1:27 ` [PATCH v4 02/17] xfs: Replace attribute parameters with struct xfs_name Allison Collins
2019-11-08  1:13   ` Darrick J. Wong
2019-11-08 17:16     ` Allison Collins
2019-11-11 17:49   ` Christoph Hellwig
2019-11-11 20:07     ` Allison Collins
2019-11-13 15:12       ` Allison Collins
2019-11-20 18:20         ` Christoph Hellwig
2019-11-07  1:27 ` [PATCH v4 03/17] xfs: Embed struct xfs_name in xfs_da_args Allison Collins
2019-11-08  1:25   ` Darrick J. Wong
2019-11-08 16:11     ` Allison Collins
2019-11-08 21:47       ` Darrick J. Wong
2019-11-07  1:27 ` [PATCH v4 04/17] xfs: Add xfs_dabuf defines Allison Collins
2019-11-08 19:19   ` Darrick J. Wong
2019-11-09 17:32     ` Allison Collins
2019-11-09 20:11       ` Darrick J. Wong
2019-11-09 22:06         ` Allison Collins
2019-11-07  1:27 ` [PATCH v4 05/17] xfs: Add xfs_has_attr and subroutines Allison Collins
2019-11-08 19:32   ` Darrick J. Wong
2019-11-08 19:51     ` Allison Collins
2019-11-11 17:40   ` Brian Foster
2019-11-11 23:34     ` Allison Collins
2019-11-11 17:53   ` Christoph Hellwig
2019-11-11 23:36     ` Allison Collins
2019-11-07  1:27 ` [PATCH v4 06/17] xfs: Factor out new helper functions xfs_attr_rmtval_set Allison Collins
2019-11-08 19:34   ` Darrick J. Wong
2019-11-08 19:51     ` Allison Collins
2019-11-07  1:27 ` [PATCH v4 07/17] xfs: Factor up trans handling in xfs_attr3_leaf_flipflags Allison Collins
2019-11-08 19:35   ` Darrick J. Wong
2019-11-08 19:52     ` Allison Collins
2019-11-07  1:27 ` [PATCH v4 08/17] xfs: Factor out xfs_attr_leaf_addname helper Allison Collins
2019-11-08 20:57   ` Darrick J. Wong
2019-11-09 21:41     ` Allison Collins
2019-11-07  1:27 ` [PATCH v4 09/17] xfs: Factor up commit from xfs_attr_try_sf_addname Allison Collins
2019-11-08 21:04   ` Darrick J. Wong
2019-11-08 23:13     ` Allison Collins
2019-11-07  1:27 ` [PATCH v4 10/17] xfs: Factor up trans roll from xfs_attr3_leaf_setflag Allison Collins
2019-11-07  1:27 ` [PATCH v4 11/17] xfs: Add xfs_attr3_leaf helper functions Allison Collins
2019-11-08 21:17   ` Darrick J. Wong
2019-11-09  0:09     ` Allison Collins
2019-11-07  1:27 ` [PATCH v4 12/17] xfs: Factor out xfs_attr_rmtval_invalidate Allison Collins
2019-11-08 21:19   ` Darrick J. Wong
2019-11-09  0:10     ` Allison Collins
2019-11-07  1:27 ` [PATCH v4 13/17] xfs: Factor up trans roll in xfs_attr3_leaf_clearflag Allison Collins
2019-11-08 21:19   ` Darrick J. Wong
2019-11-09  0:11     ` Allison Collins
2019-11-11 18:23   ` Brian Foster
2019-11-11 23:37     ` Allison Collins
2019-11-07  1:27 ` [PATCH v4 14/17] xfs: Add delay context to xfs_da_args Allison Collins
2019-11-08 21:22   ` Darrick J. Wong
2019-11-09  0:23     ` Allison Collins
2019-11-11 18:23   ` Brian Foster
2019-11-11 23:42     ` Allison Collins
2019-11-07  1:27 ` [PATCH v4 15/17] xfs: Check for -ENOATTR or -EEXIST Allison Collins
2019-11-08 21:28   ` Darrick J. Wong
2019-11-08 21:42     ` Allison Collins
2019-11-08 21:51       ` Darrick J. Wong
2019-11-11 18:24   ` Brian Foster
2019-11-12  0:33     ` Allison Collins
2019-11-07  1:28 ` [PATCH v4 16/17] xfs: Add delay ready attr remove routines Allison Collins
2019-11-08 21:37   ` Darrick J. Wong
2019-11-09  0:25     ` Allison Collins
2019-11-12 13:37   ` Brian Foster
2019-11-13  0:43     ` Allison Collins
2019-11-13 11:54       ` Brian Foster
2019-11-13 23:39         ` Allison Collins
2019-11-14 12:48           ` Brian Foster
2019-11-14 17:58             ` Allison Collins
2019-11-07  1:28 ` [PATCH v4 17/17] xfs: Add delay ready attr set routines Allison Collins
2019-11-08 21:42   ` Darrick J. Wong
2019-11-08 21:52     ` Allison Collins
2019-11-09  4:07     ` Allison Collins
2019-11-12 13:37   ` Brian Foster
2019-11-13  4:57     ` Allison Collins

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.